diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index d82136f54b0..8029030c28b 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -98,6 +98,7 @@ TypeArguments* Object::null_type_arguments_ = NULL; Array* Object::empty_array_ = NULL; Array* Object::zero_array_ = NULL; PcDescriptors* Object::empty_descriptors_ = NULL; +LocalVarDescriptors* Object::empty_var_descriptors_ = NULL; Instance* Object::sentinel_ = NULL; Instance* Object::transition_sentinel_ = NULL; Instance* Object::unknown_constant_ = NULL; @@ -435,6 +436,7 @@ void Object::InitOnce() { empty_array_ = Array::ReadOnlyHandle(); zero_array_ = Array::ReadOnlyHandle(); empty_descriptors_ = PcDescriptors::ReadOnlyHandle(); + empty_var_descriptors_ = LocalVarDescriptors::ReadOnlyHandle(); sentinel_ = Instance::ReadOnlyHandle(); transition_sentinel_ = Instance::ReadOnlyHandle(); unknown_constant_ = Instance::ReadOnlyHandle(); @@ -665,6 +667,20 @@ void Object::InitOnce() { empty_descriptors_->raw_ptr()->length_ = 0; } + // Allocate and initialize the canonical empty variable descriptor object. + { + uword address = heap->Allocate( + LocalVarDescriptors::InstanceSize(0), Heap::kOld); + InitializeObject(address, kLocalVarDescriptorsCid, + LocalVarDescriptors::InstanceSize(0)); + LocalVarDescriptors::initializeHandle( + empty_var_descriptors_, + reinterpret_cast(address + kHeapObjectTag)); + empty_var_descriptors_->raw_ptr()->length_ = 0; + // Can't use instance mentod StorePointer() here, but this pointer + // assignment is safe (from old space to old space). + empty_var_descriptors_->raw_ptr()->names_ = empty_array_->raw_ptr(); + } cls = Class::New(kDynamicCid); cls.set_is_abstract(); diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 7fcebdb0f57..1edfaedcdce 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -393,6 +393,11 @@ class Object { return *empty_descriptors_; } + static const LocalVarDescriptors& empty_var_descriptors() { + ASSERT(empty_var_descriptors_ != NULL); + return *empty_var_descriptors_; + } + // The sentinel is a value that cannot be produced by Dart code. // It can be used to mark special values, for example to distinguish // "uninitialized" fields. @@ -670,6 +675,7 @@ class Object { static Array* empty_array_; static Array* zero_array_; static PcDescriptors* empty_descriptors_; + static LocalVarDescriptors* empty_var_descriptors_; static Instance* sentinel_; static Instance* transition_sentinel_; static Instance* unknown_constant_; @@ -3099,6 +3105,7 @@ class LocalVarDescriptors : public Object { private: FINAL_HEAP_OBJECT_IMPLEMENTATION(LocalVarDescriptors, Object); friend class Class; + friend class Object; }; diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index c6ac4b5d663..0643ba42118 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -1102,6 +1102,8 @@ class RawLocalVarDescriptors : public RawObject { // Variable info with [length_] entries. VarInfo* data() { OPEN_ARRAY_START(VarInfo, int32_t); } + + friend class Object; }; diff --git a/runtime/vm/scopes.cc b/runtime/vm/scopes.cc index be699cf3d83..01a138654f6 100644 --- a/runtime/vm/scopes.cc +++ b/runtime/vm/scopes.cc @@ -266,6 +266,9 @@ RawLocalVarDescriptors* LocalScope::GetVarDescriptors(const Function& func) { int16_t scope_id = 0; CollectLocalVariables(&vars, &scope_id); + if (vars.length() == 0) { + return Object::empty_var_descriptors().raw(); + } const LocalVarDescriptors& var_desc = LocalVarDescriptors::Handle(LocalVarDescriptors::New(vars.length())); for (int i = 0; i < vars.length(); i++) { @@ -294,7 +297,7 @@ void LocalScope::CollectLocalVariables(GrowableArray* vars, // This is the outermost scope with a context level or this scope's // context level differs from its parent's level. VarDesc desc; - desc.name = &String::Handle(); // No name. + desc.name = &Object::null_string(); // No name. desc.info.set_kind(RawLocalVarDescriptors::kContextLevel); desc.info.scope_id = *scope_id; desc.info.begin_pos = begin_token_pos();