diff --git a/runtime/vm/class_finalizer_test.cc b/runtime/vm/class_finalizer_test.cc index 49d10201520..20009b573b7 100644 --- a/runtime/vm/class_finalizer_test.cc +++ b/runtime/vm/class_finalizer_test.cc @@ -11,7 +11,7 @@ namespace dart { static RawClass* CreateTestClass(const char* name) { - const Array& empty_array = Array::Handle(Array::Empty()); + const Array& empty_array = Array::Handle(Object::empty_array()); const String& class_name = String::Handle(Symbols::New(name)); const Script& script = Script::Handle(); const Class& cls = diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc index 29c2ee7a4c3..bf55c14ecbf 100644 --- a/runtime/vm/code_descriptors.cc +++ b/runtime/vm/code_descriptors.cc @@ -80,7 +80,7 @@ RawArray* StackmapTableBuilder::FinalizeStackmaps(const Code& code) { intptr_t num_entries = Length(); uword entry_point = code.EntryPoint(); if (num_entries == 0) { - return Array::Empty(); + return Object::empty_array(); } for (intptr_t i = 0; i < num_entries; i++) { stack_map_ = Map(i); diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc index 69bad4974ac..8dcdb46c5f0 100644 --- a/runtime/vm/code_generator.cc +++ b/runtime/vm/code_generator.cc @@ -1663,6 +1663,10 @@ void FunctionsCache::AddCompiledFunction(const Function& function, #if 0 ASSERT(function.HasCode()); Array& cache = Array::Handle(class_.functions_cache()); + if (cache.IsNull()) { + class_.InitFunctionsCache(); + cache = class_.functions_cache(); + } // Search for first free slot. Last entry is always NULL object. for (intptr_t i = 0; i < (cache.Length() - kNumEntries); i += kNumEntries) { if (Object::Handle(cache.At(i)).IsNull()) { @@ -1692,6 +1696,9 @@ RawCode* FunctionsCache::LookupCode(const String& function_name, int num_arguments, int num_named_arguments) { const Array& cache = Array::Handle(class_.functions_cache()); + if (cache.IsNull()) { + return Code::null(); // Functions cache has not been populated yet. + } String& test_name = String::Handle(); for (intptr_t i = 0; i < cache.Length(); i += kNumEntries) { test_name ^= cache.At(i + FunctionsCache::kFunctionName); diff --git a/runtime/vm/heap_profiler.cc b/runtime/vm/heap_profiler.cc index d83d48b57d9..9de32081dbc 100644 --- a/runtime/vm/heap_profiler.cc +++ b/runtime/vm/heap_profiler.cc @@ -412,13 +412,8 @@ void HeapProfiler::WriteLoadClass(const RawClass* raw_class) { record.WritePointer(raw_class); // stack trace serial number record.Write32(0); - if (raw_class->ptr()->name_ == String::null()) { - intptr_t class_id = raw_class->ptr()->id_; - const char* name = Object::GetSingletonClassName(class_id); - record.WritePointer(StringId(name)); - } else { - record.WritePointer(StringId(raw_class->ptr()->name_)); - } + ASSERT(raw_class->ptr()->name_ != String::null()); + record.WritePointer(StringId(raw_class->ptr()->name_)); } diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 0c1c06d384d..409d96cd23c 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -59,6 +59,7 @@ cpp_vtable Smi::handle_vtable_ = 0; #endif #define RAW_NULL kHeapObjectTag RawObject* Object::null_ = reinterpret_cast(RAW_NULL); +RawArray* Object::empty_array_ = reinterpret_cast(RAW_NULL); RawInstance* Object::sentinel_ = reinterpret_cast(RAW_NULL); RawInstance* Object::transition_sentinel_ = reinterpret_cast(RAW_NULL); @@ -185,47 +186,6 @@ static RawString* IdentifierPrettyName(const String& name) { } -// TODO(asiva): Get rid of this function once we have predefined names for -// the shared classes and set that up in the name field. -const char* Object::GetSingletonClassName(intptr_t class_id) { - switch (class_id) { - case kClassCid: return "Class"; - case kNullCid: return "Null"; - case kDynamicCid: return "Dynamic"; - case kVoidCid: return "void"; - case kUnresolvedClassCid: return "UnresolvedClass"; - case kTypeCid: return "Type"; - case kTypeParameterCid: return "TypeParameter"; - case kTypeArgumentsCid: return "TypeArguments"; - case kInstantiatedTypeArgumentsCid: return "InstantiatedTypeArguments"; - case kFunctionCid: return "Function"; - case kFieldCid: return "Field"; - case kLiteralTokenCid: return "LiteralToken"; - case kTokenStreamCid: return "TokenStream"; - case kScriptCid: return "Script"; - case kLibraryCid: return "Library"; - case kLibraryPrefixCid: return "LibraryPrefix"; - case kCodeCid: return "Code"; - case kInstructionsCid: return "Instructions"; - case kPcDescriptorsCid: return "PcDescriptors"; - case kStackmapCid: return "Stackmap"; - case kLocalVarDescriptorsCid: return "LocalVarDescriptors"; - case kExceptionHandlersCid: return "ExceptionHandlers"; - case kContextCid: return "Context"; - case kContextScopeCid: return "ContextScope"; - case kICDataCid: return "ICData"; - case kSubtypeTestCacheCid: return "SubtypeTestCache"; - case kApiErrorCid: return "ApiError"; - case kLanguageErrorCid: return "LanguageError"; - case kUnhandledExceptionCid: return "UnhandledException"; - case kUnwindErrorCid: return "UnwindError"; - default: break; - } - UNREACHABLE(); - return NULL; -} - - void Object::InitOnce() { // TODO(iposva): NoGCScope needs to be added here. ASSERT(class_class() == null_); @@ -239,7 +199,7 @@ void Object::InitOnce() { Isolate* isolate = Isolate::Current(); Heap* heap = isolate->heap(); - // Allocate and initialize the null instance, except its class_ field. + // Allocate and initialize the null instance. // 'null_' must be the first object allocated as it is used in allocation to // clear the object. { @@ -251,7 +211,7 @@ void Object::InitOnce() { // Initialize object_store empty array to null_ in order to be able to check // if the empty array was allocated (RAW_NULL is not available). - isolate->object_store()->set_empty_array(Array::Handle()); + empty_array_ = Array::null(); Class& cls = Class::Handle(); @@ -303,14 +263,6 @@ void Object::InitOnce() { transition_sentinel_ = transition_sentinel.raw(); } - // The interface "Dynamic" is not a VM internal class. It is the type class of - // the "unknown type". For efficiency, we allocate it in the VM isolate. - // Therefore, it cannot have a heap allocated name (the name is hard coded, - // see GetSingletonClassName) and its array fields cannot be set to the empty - // array, but remain null. - // - // TODO(turnidge): Once the empty array is allocated in the vm - // isolate, use it here. cls = Class::New(kDynamicCid); cls.set_is_finalized(); cls.set_is_interface(); @@ -411,6 +363,57 @@ void Object::InitOnce() { isolate->object_store()->set_array_class(cls); cls = Class::New(); isolate->object_store()->set_one_byte_string_class(cls); + + // Allocate and initialize the empty_array instance. + { + uword address = heap->Allocate(Array::InstanceSize(0), Heap::kOld); + empty_array_ = reinterpret_cast(address + kHeapObjectTag); + InitializeObject(address, kArrayCid, Array::InstanceSize(0)); + empty_array_->ptr()->length_ = Smi::New(0); + } +} + + +#define SET_CLASS_NAME(class_name, name) \ + cls = class_name##_class(); \ + str = Symbols::name(); \ + cls.set_name(str); \ + +void Object::RegisterSingletonClassNames() { + Class& cls = Class::Handle(); + String& str = String::Handle(); + + SET_CLASS_NAME(class, Class); + SET_CLASS_NAME(null, Null); + SET_CLASS_NAME(dynamic, Dynamic); + SET_CLASS_NAME(void, Void); + SET_CLASS_NAME(unresolved_class, UnresolvedClass); + SET_CLASS_NAME(type, Type); + SET_CLASS_NAME(type_parameter, TypeParameter); + SET_CLASS_NAME(type_arguments, TypeArguments); + SET_CLASS_NAME(instantiated_type_arguments, InstantiatedTypeArguments); + SET_CLASS_NAME(function, Function); + SET_CLASS_NAME(field, Field); + SET_CLASS_NAME(literal_token, LiteralToken); + SET_CLASS_NAME(token_stream, TokenStream); + SET_CLASS_NAME(script, Script); + SET_CLASS_NAME(library, LibraryClass); + SET_CLASS_NAME(library_prefix, LibraryPrefix); + SET_CLASS_NAME(code, Code); + SET_CLASS_NAME(instructions, Instructions); + SET_CLASS_NAME(pc_descriptors, PcDescriptors); + SET_CLASS_NAME(stackmap, Stackmap); + SET_CLASS_NAME(var_descriptors, LocalVarDescriptors); + SET_CLASS_NAME(exception_handlers, ExceptionHandlers); + SET_CLASS_NAME(deopt_info, DeoptInfo); + SET_CLASS_NAME(context, Context); + SET_CLASS_NAME(context_scope, ContextScope); + SET_CLASS_NAME(icdata, ICData); + SET_CLASS_NAME(subtypetestcache, SubtypeTestCache); + SET_CLASS_NAME(api_error, ApiError); + SET_CLASS_NAME(language_error, LanguageError); + SET_CLASS_NAME(unhandled_exception, UnhandledException); + SET_CLASS_NAME(unwind_error, UnwindError); } @@ -468,14 +471,6 @@ RawError* Object::Init(Isolate* isolate) { // declared in RawArray. cls.set_type_arguments_instance_field_offset(Array::type_arguments_offset()); - Array& empty_array = Array::Handle(); - empty_array = Array::New(0, Heap::kOld); - object_store->set_empty_array(empty_array); - - // Re-initialize fields of the array class now that the empty array - // has been created. - cls.InitEmptyFields(); - // Set up the growable object array class (Has to be done after the array // class is setup as one of its field is an array object). cls = Class::New(); @@ -835,10 +830,6 @@ void Object::InitFromSnapshot(Isolate* isolate) { cls = Class::New(); object_store->set_array_class(cls); - Array& empty_array = Array::Handle(); - empty_array = Array::New(0); - object_store->set_empty_array(empty_array); - cls = Class::New(); object_store->set_immutable_array_class(cls); @@ -1037,11 +1028,8 @@ RawObject* Object::Clone(const Object& src, Heap::Space space) { RawString* Class::Name() const { - if (raw_ptr()->name_ != String::null()) { - return raw_ptr()->name_; - } - ASSERT(class_class() != Class::null()); // class_class_ should be set up. - return Symbols::New(GetSingletonClassName(raw_ptr()->id_)); + ASSERT(raw_ptr()->name_ != String::null()); + return raw_ptr()->name_; } @@ -1186,20 +1174,22 @@ RawClass* Class::New() { // Initialize class fields of type Array with empty array. void Class::InitEmptyFields() { - const Array& empty_array = Array::Handle(Array::Empty()); - if (empty_array.IsNull()) { + if (Object::empty_array() == Array::null()) { // The empty array has not been initialized yet. return; } - StorePointer(&raw_ptr()->interfaces_, empty_array.raw()); - // TODO(srdjan): Make functions_cache growable and start with a smaller size. - Array& fcache = - Array::Handle(Array::New(FunctionsCache::kNumEntries * 32, Heap::kOld)); - StorePointer(&raw_ptr()->functions_cache_, fcache.raw()); - StorePointer(&raw_ptr()->constants_, empty_array.raw()); - StorePointer(&raw_ptr()->canonical_types_, empty_array.raw()); - StorePointer(&raw_ptr()->functions_, empty_array.raw()); - StorePointer(&raw_ptr()->fields_, empty_array.raw()); + StorePointer(&raw_ptr()->interfaces_, Object::empty_array()); + StorePointer(&raw_ptr()->constants_, Object::empty_array()); + StorePointer(&raw_ptr()->canonical_types_, Object::empty_array()); + StorePointer(&raw_ptr()->functions_, Object::empty_array()); + StorePointer(&raw_ptr()->fields_, Object::empty_array()); +} + + +void Class::InitFunctionsCache() const { + // TODO(srdjan): Make functions_cache growable and start with smaller size. + StorePointer(&raw_ptr()->functions_cache_, + Array::New(FunctionsCache::kNumEntries * 32, Heap::kOld)); } @@ -1564,12 +1554,13 @@ RawClass* Class::NewSignatureClass(const String& name, const intptr_t token_pos = signature_function.token_pos(); Class& result = Class::Handle(New(name, script, token_pos)); const Type& super_type = Type::Handle(Type::ObjectType()); + const Array& empty_array = Array::Handle(Object::empty_array()); ASSERT(!super_type.IsNull()); result.set_super_type(super_type); result.set_signature_function(signature_function); result.set_type_parameters(type_parameters); - result.SetFields(Array::Handle(Array::Empty())); - result.SetFunctions(Array::Handle(Array::Empty())); + result.SetFields(empty_array); + result.SetFunctions(empty_array); result.set_type_arguments_instance_field_offset( Closure::type_arguments_offset()); // Implements interface "Function". @@ -1623,9 +1614,10 @@ RawClass* Class::NewNativeWrapper(Library* library, int field_count) { Class& cls = Class::Handle(library->LookupClass(name)); if (cls.IsNull()) { + const Array& empty_array = Array::Handle(Object::empty_array()); cls = New(name, Script::Handle(), Scanner::kDummyTokenIndex); - cls.SetFields(Array::Handle(Array::Empty())); - cls.SetFunctions(Array::Handle(Array::Empty())); + cls.SetFields(empty_array); + cls.SetFunctions(empty_array); // Set super class to Object. cls.set_super_type(Type::Handle(Type::ObjectType())); // Compute instance size. @@ -4022,8 +4014,9 @@ RawFunction* Function::New(const String& name, ASSERT(name.IsOneByteString()); ASSERT(!owner.IsNull()); const Function& result = Function::Handle(Function::New()); - result.set_parameter_types(Array::Handle(Array::Empty())); - result.set_parameter_names(Array::Handle(Array::Empty())); + const Array& empty_array = Array::Handle(Object::empty_array()); + result.set_parameter_types(empty_array); + result.set_parameter_names(empty_array); result.set_name(name); result.set_kind(kind); result.set_is_static(is_static); @@ -6044,10 +6037,10 @@ RawLibrary* Library::NewLibraryHelper(const String& url, result.StorePointer(&result.raw_ptr()->name_, url.raw()); result.StorePointer(&result.raw_ptr()->url_, url.raw()); result.raw_ptr()->private_key_ = Scanner::AllocatePrivateKey(result); - result.raw_ptr()->dictionary_ = Array::Empty(); - result.raw_ptr()->anonymous_classes_ = Array::Empty(); + result.raw_ptr()->dictionary_ = Object::empty_array(); + result.raw_ptr()->anonymous_classes_ = Object::empty_array(); result.raw_ptr()->num_anonymous_ = 0; - result.raw_ptr()->imports_ = Array::Empty(); + result.raw_ptr()->imports_ = Object::empty_array(); result.raw_ptr()->loaded_scripts_ = Array::null(); result.set_native_entry_resolver(NULL); result.raw_ptr()->corelib_imported_ = true; @@ -7014,7 +7007,7 @@ Code::Comments& Code::Comments::New(intptr_t count) { FATAL1("Fatal error in Code::Comments::New: invalid count %ld\n", count); } if (count == 0) { - comments = new Comments(Array::Empty()); + comments = new Comments(Object::empty_array()); } else { comments = new Comments(Array::New(count * kNumberOfEntries)); } @@ -9980,17 +9973,12 @@ RawArray* Array::Grow(const Array& source, int new_length, Heap::Space space) { } -RawArray* Array::Empty() { - return Isolate::Current()->object_store()->empty_array(); -} - - RawArray* Array::MakeArray(const GrowableObjectArray& growable_array) { intptr_t used_len = growable_array.Length(); intptr_t capacity_len = growable_array.Capacity(); Isolate* isolate = Isolate::Current(); const Array& array = Array::Handle(isolate, growable_array.data()); - const Array& new_array = Array::Handle(isolate, Array::Empty()); + const Array& new_array = Array::Handle(isolate, Object::empty_array()); intptr_t capacity_size = Array::InstanceSize(capacity_len); intptr_t used_size = Array::InstanceSize(used_len); NoGCScope no_gc; diff --git a/runtime/vm/object.h b/runtime/vm/object.h index dbcc16e209f..80744f98c75 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -235,6 +235,7 @@ CLASS_LIST_NO_OBJECT(DEFINE_CLASS_TESTER); } static RawObject* null() { return null_; } + static RawArray* empty_array() { return empty_array_; } // The sentinel is a value that cannot be produced by Dart code. // It can be used to mark special values, for example to distinguish @@ -284,8 +285,6 @@ CLASS_LIST_NO_OBJECT(DEFINE_CLASS_TESTER); static RawClass* icdata_class() { return icdata_class_; } static RawClass* subtypetestcache_class() { return subtypetestcache_class_; } - static const char* GetSingletonClassName(intptr_t class_id); - static RawClass* CreateAndRegisterInterface(const char* cname, const Script& script, const Library& lib); @@ -302,6 +301,7 @@ CLASS_LIST_NO_OBJECT(DEFINE_CLASS_TESTER); static RawError* Init(Isolate* isolate); static void InitFromSnapshot(Isolate* isolate); static void InitOnce(); + static void RegisterSingletonClassNames(); static intptr_t InstanceSize() { return RoundedAllocationSize(sizeof(RawObject)); @@ -376,6 +376,7 @@ CLASS_LIST_NO_OBJECT(DEFINE_CLASS_TESTER); // The static values below are singletons shared between the different // isolates. They are all allocated in the non-GC'd Dart::vm_isolate_. static RawObject* null_; + static RawArray* empty_array_; static RawInstance* sentinel_; static RawInstance* transition_sentinel_; @@ -687,6 +688,9 @@ class Class : public Object { void Finalize() const; + // Initialize the functions cache array. + void InitFunctionsCache() const; + // Allocate a class used for VM internal objects. template static RawClass* New(); @@ -3928,9 +3932,6 @@ class Array : public Instance { int new_length, Heap::Space space = Heap::kNew); - // Returns the preallocated empty array, used to initialize array fields. - static RawArray* Empty(); - // Return an Array object that contains all the elements currently present // in the specified Growable Object Array. This is done by first truncating // the Growable Object Array's backing array to the currently used size and diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc index 6284e0547dd..1100cfa2772 100644 --- a/runtime/vm/object_store.cc +++ b/runtime/vm/object_store.cc @@ -61,7 +61,6 @@ ObjectStore::ObjectStore() jsregexp_class_(Class::null()), true_value_(Bool::null()), false_value_(Bool::null()), - empty_array_(Array::null()), symbol_table_(Array::null()), canonical_type_arguments_(Array::null()), core_library_(Library::null()), diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h index 6a081a895d5..cacf7a47b44 100644 --- a/runtime/vm/object_store.h +++ b/runtime/vm/object_store.h @@ -421,9 +421,6 @@ class ObjectStore { RawBool* false_value() const { return false_value_; } void set_false_value(const Bool& value) { false_value_ = value.raw(); } - RawArray* empty_array() const { return empty_array_; } - void set_empty_array(const Array& value) { empty_array_ = value.raw(); } - RawContext* empty_context() const { return empty_context_; } void set_empty_context(const Context& value) { empty_context_ = value.raw(); @@ -514,7 +511,6 @@ class ObjectStore { RawClass* jsregexp_class_; RawBool* true_value_; RawBool* false_value_; - RawArray* empty_array_; RawArray* symbol_table_; RawArray* canonical_type_arguments_; RawLibrary* core_library_; diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc index 1a64fbaa34d..e050512e820 100644 --- a/runtime/vm/object_test.cc +++ b/runtime/vm/object_test.cc @@ -21,7 +21,7 @@ TEST_CASE(Class) { Class::New(class_name, script, Scanner::kDummyTokenIndex)); // Class has no fields. - const Array& no_fields = Array::Handle(Array::Empty()); + const Array& no_fields = Array::Handle(Object::empty_array()); cls.SetFields(no_fields); // Create and populate the function arrays. @@ -111,6 +111,8 @@ TEST_CASE(Class) { cls.set_interfaces(interfaces); cls.Finalize(); + ASSERT(cls.functions_cache() == Array::null()); + cls.InitFunctionsCache(); const Array& array = Array::Handle(cls.functions_cache()); array.SetAt(0, function_name); cls.set_functions_cache(array); @@ -172,7 +174,7 @@ TEST_CASE(InstanceClass) { Class::Handle(Class::New(class_name, script, Scanner::kDummyTokenIndex)); // No functions and no super class for the EmptyClass. - const Array& no_fields = Array::Handle(Array::Empty()); + const Array& no_fields = Array::Handle(Object::empty_array()); empty_class.SetFields(no_fields); empty_class.Finalize(); EXPECT_EQ(kObjectAlignment, empty_class.instance_size()); @@ -203,7 +205,7 @@ TEST_CASE(Interface) { Script& script = Script::Handle(); const Class& factory_class = Class::Handle(Class::New(class_name, script, Scanner::kDummyTokenIndex)); - const Array& no_fields = Array::Handle(Array::Empty()); + const Array& no_fields = Array::Handle(Object::empty_array()); // Finalizes the class. factory_class.SetFields(no_fields); @@ -1765,7 +1767,7 @@ TEST_CASE(Array) { other_array.SetAt(2, array); EXPECT(!array.Equals(other_array)); - EXPECT_EQ(0, Array::Handle(Array::Empty()).Length()); + EXPECT_EQ(0, Array::Handle(Object::empty_array()).Length()); } diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc index b71e03b2277..db0606df4c3 100644 --- a/runtime/vm/parser.cc +++ b/runtime/vm/parser.cc @@ -2930,13 +2930,13 @@ void Parser::ParseClassDefinition(const GrowableObjectArray& pending_classes) { if (cls.is_interface()) { ErrorMsg(classname_pos, "'%s' is already defined as interface", class_name.ToCString()); - } else if (cls.functions() != Array::Empty()) { + } else if (cls.functions() != Object::empty_array()) { ErrorMsg(classname_pos, "class '%s' is already defined", class_name.ToCString()); } } ASSERT(!cls.IsNull()); - ASSERT(cls.functions() == Array::Empty()); + ASSERT(cls.functions() == Object::empty_array()); set_current_class(cls); ParseTypeParameters(cls); Type& super_type = Type::Handle(); @@ -3208,14 +3208,14 @@ void Parser::ParseInterfaceDefinition( ErrorMsg(interfacename_pos, "'%s' is already defined as class", interface_name.ToCString()); - } else if (interface.functions() != Array::Empty()) { + } else if (interface.functions() != Object::empty_array()) { ErrorMsg(interfacename_pos, "interface '%s' is already defined", interface_name.ToCString()); } } ASSERT(!interface.IsNull()); - ASSERT(interface.functions() == Array::Empty()); + ASSERT(interface.functions() == Object::empty_array()); set_current_class(interface); ParseTypeParameters(interface); diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index 69368a92cf6..59ae73d5ad2 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -1149,6 +1149,7 @@ class RawArray : public RawInstance { friend class RawImmutableArray; friend class SnapshotReader; friend class GrowableObjectArray; + friend class Object; }; diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc index c292a95f622..5dcba7a71ae 100644 --- a/runtime/vm/snapshot.cc +++ b/runtime/vm/snapshot.cc @@ -581,6 +581,9 @@ RawObject* SnapshotReader::ReadVMIsolateObject(intptr_t header_value) { if (object_id == kSentinelObject) { return Object::sentinel(); } + if (object_id == kEmptyArrayObject) { + return Object::empty_array(); + } intptr_t class_id = ClassIdFromObjectId(object_id); if (IsSingletonClassId(class_id)) { return isolate()->class_table()->At(class_id); // get singleton class. @@ -709,6 +712,12 @@ void SnapshotWriter::HandleVMIsolateObject(RawObject* rawobj) { return; } + // Check if it is a singleton empty array object. + if (rawobj == Object::empty_array()) { + WriteVMIsolateObject(kEmptyArrayObject); + return; + } + // Check if it is a singleton class object which is shared by // all isolates. intptr_t id = rawobj->GetClassId(); diff --git a/runtime/vm/snapshot_ids.h b/runtime/vm/snapshot_ids.h index 20593c21ee1..a0134839dfc 100644 --- a/runtime/vm/snapshot_ids.h +++ b/runtime/vm/snapshot_ids.h @@ -13,6 +13,7 @@ namespace dart { enum { kNullObject = 0, kSentinelObject, + kEmptyArrayObject, kTrueValue, kFalseValue, kClassIdsOffset = kFalseValue, diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc index 646d68393c9..60aa8a97a99 100644 --- a/runtime/vm/stub_code_ia32.cc +++ b/runtime/vm/stub_code_ia32.cc @@ -293,6 +293,9 @@ static void MegamorphicLookup(Assembler* assembler) { Label loop, next_iteration; // Get functions_cache, since it is allocated lazily it maybe null. __ movl(EAX, FieldAddress(EAX, Class::functions_cache_offset())); + __ cmpl(EAX, raw_null); + __ j(EQUAL, ¬_found, Assembler::kNearJump); + // Iterate and search for identical name. __ leal(EBX, FieldAddress(EAX, Array::data_offset())); diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc index 31c99c59b4d..f2350e8be8b 100644 --- a/runtime/vm/stub_code_x64.cc +++ b/runtime/vm/stub_code_x64.cc @@ -288,6 +288,9 @@ static void MegamorphicLookup(Assembler* assembler) { Label loop, next_iteration; // Get functions_cache, since it is allocated lazily it maybe null. __ movq(RAX, FieldAddress(RAX, Class::functions_cache_offset())); + __ cmpq(RAX, raw_null); + __ j(EQUAL, ¬_found, Assembler::kNearJump); + // Iterate and search for identical name. __ leaq(R12, FieldAddress(RAX, Array::data_offset())); diff --git a/runtime/vm/symbols.cc b/runtime/vm/symbols.cc index 5b631020d33..5bd18b28305 100644 --- a/runtime/vm/symbols.cc +++ b/runtime/vm/symbols.cc @@ -48,6 +48,7 @@ void Symbols::InitOnce(Isolate* isolate) { Add(symbol_table, str); predefined_[i] = str.raw(); } + Object::RegisterSingletonClassNames(); } diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h index 5515d1b4d77..9751977e611 100644 --- a/runtime/vm/symbols.h +++ b/runtime/vm/symbols.h @@ -53,6 +53,37 @@ class ObjectPointerVisitor; V(Import, "import") \ V(Source, "source") \ V(Resource, "resource") \ + V(Class, "Class") \ + V(Null, "Null") \ + V(Dynamic, "Dynamic") \ + V(Void, "void") \ + V(UnresolvedClass, "UnresolvedClass") \ + V(Type, "Type") \ + V(TypeParameter, "TypeParameter") \ + V(TypeArguments, "TypeArguments") \ + V(InstantiatedTypeArguments, "InstantiatedTypeArguments") \ + V(Function, "Function") \ + V(Field, "Field") \ + V(LiteralToken, "LiteralToken") \ + V(TokenStream, "TokenStream") \ + V(Script, "Script") \ + V(LibraryClass, "Library") \ + V(LibraryPrefix, "LibraryPrefix") \ + V(Code, "Code") \ + V(Instructions, "Instructions") \ + V(PcDescriptors, "PcDescriptors") \ + V(Stackmap, "Stackmap") \ + V(LocalVarDescriptors, "LocalVarDescriptors") \ + V(ExceptionHandlers, "ExceptionHandlers") \ + V(DeoptInfo, "DeoptInfo") \ + V(Context, "Context") \ + V(ContextScope, "ContextScope") \ + V(ICData, "ICData") \ + V(SubtypeTestCache, "SubtypeTestCache") \ + V(ApiError, "ApiError") \ + V(LanguageError, "LanguageError") \ + V(UnhandledException, "UnhandledException") \ + V(UnwindError, "UnwindError") \ // Contains a list of frequently used strings in a canonicalized form. This // list is kept in the vm_isolate in order to share the copy across isolates