1. Register canonical names for internal VM classes and get rid of the method GetSingletonClassName
2. Create the empty_array object as a singleton in the VM isolate and remove it from the object store
3. Remove eager population of the functions_cache entry in the class. This results in a pretty impressive reduction of the initial isolate heap size:
- on IA32 it goes from 1331k to 1071k
- on X64 it goes from 2431k to 1911k
- snapshot size also is reduced from 859219 bytes to 789147 bytes.
(as a follow up change I will consider completely removing functions cache)
Review URL: https://chromiumcodereview.appspot.com//10827249
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@10535 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
@@ -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 =
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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_));
|
||||
}
|
||||
|
||||
|
||||
|
||||
+83
-95
@@ -59,6 +59,7 @@ cpp_vtable Smi::handle_vtable_ = 0;
|
||||
#endif
|
||||
#define RAW_NULL kHeapObjectTag
|
||||
RawObject* Object::null_ = reinterpret_cast<RawInstance*>(RAW_NULL);
|
||||
RawArray* Object::empty_array_ = reinterpret_cast<RawArray*>(RAW_NULL);
|
||||
RawInstance* Object::sentinel_ = reinterpret_cast<RawInstance*>(RAW_NULL);
|
||||
RawInstance* Object::transition_sentinel_ =
|
||||
reinterpret_cast<RawInstance*>(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<Instance>(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<OneByteString>();
|
||||
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<RawArray*>(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<GrowableObjectArray>();
|
||||
@@ -835,10 +830,6 @@ void Object::InitFromSnapshot(Isolate* isolate) {
|
||||
cls = Class::New<Array>();
|
||||
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<ImmutableArray>();
|
||||
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<Closure>(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<Instance>(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;
|
||||
|
||||
+6
-5
@@ -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 <class FakeObject> 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
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -1149,6 +1149,7 @@ class RawArray : public RawInstance {
|
||||
friend class RawImmutableArray;
|
||||
friend class SnapshotReader;
|
||||
friend class GrowableObjectArray;
|
||||
friend class Object;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace dart {
|
||||
enum {
|
||||
kNullObject = 0,
|
||||
kSentinelObject,
|
||||
kEmptyArrayObject,
|
||||
kTrueValue,
|
||||
kFalseValue,
|
||||
kClassIdsOffset = kFalseValue,
|
||||
|
||||
@@ -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()));
|
||||
|
||||
|
||||
@@ -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()));
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ void Symbols::InitOnce(Isolate* isolate) {
|
||||
Add(symbol_table, str);
|
||||
predefined_[i] = str.raw();
|
||||
}
|
||||
Object::RegisterSingletonClassNames();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user