Chromium Code Reviews| Index: runtime/vm/object.cc |
| diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc |
| index b012e5a80fe6bba680491c37853f7619fb627382..eb563e30ad530f193de7565062449f58dba4455e 100644 |
| --- a/runtime/vm/object.cc |
| +++ b/runtime/vm/object.cc |
| @@ -111,6 +111,7 @@ Array* Object::null_array_ = NULL; |
| String* Object::null_string_ = NULL; |
| Instance* Object::null_instance_ = NULL; |
| TypeArguments* Object::null_type_arguments_ = NULL; |
| +TypeArguments* Object::empty_type_arguments_ = NULL; |
| Array* Object::empty_array_ = NULL; |
| Array* Object::zero_array_ = NULL; |
| Context* Object::empty_context_ = NULL; |
| @@ -515,6 +516,7 @@ void Object::InitOnce(Isolate* isolate) { |
| null_string_ = String::ReadOnlyHandle(); |
| null_instance_ = Instance::ReadOnlyHandle(); |
| null_type_arguments_ = TypeArguments::ReadOnlyHandle(); |
| + empty_type_arguments_ = TypeArguments::ReadOnlyHandle(); |
|
rmacnak
2017/04/15 01:00:50
Also add this to the two functions called AddVMIso
regis
2017/04/17 15:49:38
Done.
|
| empty_array_ = Array::ReadOnlyHandle(); |
| zero_array_ = Array::ReadOnlyHandle(); |
| empty_context_ = Context::ReadOnlyHandle(); |
| @@ -756,6 +758,22 @@ void Object::InitOnce(Isolate* isolate) { |
| // Needed for object pools of VM isolate stubs. |
| Class::NewTypedDataClass(kTypedDataInt8ArrayCid); |
| + // Allocate and initialize the empty_type_arguments instance. |
| + { |
| + uword address = heap->Allocate(TypeArguments::InstanceSize(0), Heap::kOld); |
| + InitializeObject(address, TypeArguments::kClassId, |
| + TypeArguments::InstanceSize(0), true); |
| + TypeArguments::initializeHandle( |
| + empty_type_arguments_, |
| + reinterpret_cast<RawTypeArguments*>(address + kHeapObjectTag)); |
| + empty_type_arguments_->StoreSmi(&empty_type_arguments_->raw_ptr()->length_, |
| + Smi::New(0)); |
| + empty_type_arguments_->StoreSmi(&empty_type_arguments_->raw_ptr()->hash_, |
| + Smi::New(0)); |
| + // instantiations_ field is initialized to null and should not be used. |
| + empty_type_arguments_->SetCanonical(); |
| + } |
| + |
| // Allocate and initialize the empty_array instance. |
| { |
| uword address = heap->Allocate(Array::InstanceSize(0), Heap::kOld); |
| @@ -931,6 +949,8 @@ void Object::InitOnce(Isolate* isolate) { |
| ASSERT(null_instance_->IsInstance()); |
| ASSERT(!null_type_arguments_->IsSmi()); |
| ASSERT(null_type_arguments_->IsTypeArguments()); |
| + ASSERT(!empty_type_arguments_->IsSmi()); |
| + ASSERT(empty_type_arguments_->IsTypeArguments()); |
| ASSERT(!empty_array_->IsSmi()); |
| ASSERT(empty_array_->IsArray()); |
| ASSERT(!zero_array_->IsSmi()); |
| @@ -4717,14 +4737,9 @@ bool TypeArguments::IsDynamicTypes(bool raw_instantiated, |
| type = TypeAt(from_index + i); |
| if (!type.HasResolvedTypeClass()) { |
| if (raw_instantiated && type.IsTypeParameter()) { |
| - const TypeParameter& type_param = TypeParameter::Cast(type); |
| - if (type_param.IsClassTypeParameter() || |
| - (type_param.IsFunctionTypeParameter() && |
| - type_param.parent_level() == 0)) { |
| - // An uninstantiated type parameter is equivalent to dynamic (even in |
| - // the presence of a malformed bound in checked mode). |
| - continue; |
| - } |
| + // An uninstantiated type parameter is equivalent to dynamic (even in |
| + // the presence of a malformed bound in checked mode). |
| + continue; |
| } |
| return false; |
| } |
| @@ -5028,6 +5043,9 @@ RawTypeArguments* TypeArguments::InstantiateAndCanonicalizeFrom( |
| ASSERT(!IsInstantiated()); |
| ASSERT(instantiator_type_arguments.IsNull() || |
| instantiator_type_arguments.IsCanonical()); |
| + // TODO(regis): It is not clear yet whether we will canonicalize the result |
| + // of the concatenation of function_type_arguments in a nested generic |
| + // function. Leave the assert for now to be safe, but plan on revisiting. |
| ASSERT(function_type_arguments.IsNull() || |
| function_type_arguments.IsCanonical()); |
| // Lookup instantiator and, if found, return paired instantiated result. |
| @@ -5059,11 +5077,6 @@ RawTypeArguments* TypeArguments::InstantiateAndCanonicalizeFrom( |
| // InstantiateAndCanonicalizeFrom is not reentrant. It cannot have been called |
| // indirectly, so the prior_instantiations array cannot have grown. |
| ASSERT(prior_instantiations.raw() == instantiations()); |
| - // Do not cache result if the context is required to instantiate the |
| - // type arguments, i.e. they refer to the type parameters of parent functions. |
| - if (!IsInstantiated(kParentFunctions)) { |
| - return result.raw(); |
| - } |
| // Add instantiator and function type args and result to instantiations array. |
| intptr_t length = prior_instantiations.Length(); |
| if ((index + StubCode::kInstantiationSizeInWords) >= length) { |
| @@ -5989,6 +6002,18 @@ intptr_t Function::NumTypeParameters(Thread* thread) const { |
| } |
| +intptr_t Function::NumParentTypeParameters() const { |
| + Thread* thread = Thread::Current(); |
| + Function& parent = Function::Handle(parent_function()); |
| + intptr_t num_parent_type_params = 0; |
| + while (!parent.IsNull()) { |
| + num_parent_type_params += parent.NumTypeParameters(thread); |
| + parent ^= parent.parent_function(); |
| + } |
| + return num_parent_type_params; |
| +} |
| + |
| + |
| RawTypeParameter* Function::LookupTypeParameter( |
| const String& type_name, |
| intptr_t* function_level) const { |
| @@ -6004,7 +6029,6 @@ RawTypeParameter* Function::LookupTypeParameter( |
| Function& function = thread->FunctionHandle(); |
| function ^= this->raw(); |
| - intptr_t parent_level = 0; |
| while (!function.IsNull()) { |
| type_params ^= function.type_parameters(); |
| if (!type_params.IsNull()) { |
| @@ -6013,20 +6037,11 @@ RawTypeParameter* Function::LookupTypeParameter( |
| type_param ^= type_params.TypeAt(i); |
| type_param_name = type_param.name(); |
| if (type_param_name.Equals(type_name)) { |
| - if (parent_level > 0) { |
| - // Clone type parameter and set parent_level. |
| - type_param = TypeParameter::New( |
| - Class::Handle(), function, type_param.index(), parent_level, |
| - type_param_name, AbstractType::Handle(type_param.bound()), |
| - TokenPosition::kNoSource); |
| - type_param.SetIsFinalized(); |
| - } |
| return type_param.raw(); |
| } |
| } |
| } |
| function ^= function.parent_function(); |
| - parent_level++; |
| if (function_level != NULL) { |
| (*function_level)--; |
| } |
| @@ -6550,6 +6565,9 @@ bool Function::TypeTest(TypeTestKind test_kind, |
| (num_opt_named_params < other_num_opt_named_params)) { |
| return false; |
| } |
| + |
| + // TODO(regis): Check the type parameters and bounds of a generic function. |
| + |
| // Check the result type. |
| const AbstractType& other_res_type = |
| AbstractType::Handle(other.result_type()); |
| @@ -6969,9 +6987,14 @@ RawInstance* Function::ImplicitStaticClosure() const { |
| if (implicit_static_closure() == Instance::null()) { |
| Zone* zone = Thread::Current()->zone(); |
| const Context& context = Object::empty_context(); |
| - const TypeArguments& instantiator = TypeArguments::Handle(zone); |
| - Instance& closure = Instance::Handle( |
| - zone, Closure::New(instantiator, *this, context, Heap::kOld)); |
| + TypeArguments& function_type_arguments = TypeArguments::Handle(zone); |
| + if (!HasInstantiatedSignature(kFunctions)) { |
| + function_type_arguments = Object::empty_type_arguments().raw(); |
| + } |
| + Instance& closure = |
| + Instance::Handle(zone, Closure::New(Object::null_type_arguments(), |
| + function_type_arguments, *this, |
| + context, Heap::kOld)); |
| set_implicit_static_closure(closure); |
| } |
| return implicit_static_closure(); |
| @@ -6983,11 +7006,16 @@ RawInstance* Function::ImplicitInstanceClosure(const Instance& receiver) const { |
| Zone* zone = Thread::Current()->zone(); |
| const Context& context = Context::Handle(zone, Context::New(1)); |
| context.SetAt(0, receiver); |
| - TypeArguments& instantiator = TypeArguments::Handle(zone); |
| + TypeArguments& instantiator_type_arguments = TypeArguments::Handle(zone); |
| + TypeArguments& function_type_arguments = TypeArguments::Handle(zone); |
| if (!HasInstantiatedSignature(kCurrentClass)) { |
| - instantiator = receiver.GetTypeArguments(); |
| + instantiator_type_arguments = receiver.GetTypeArguments(); |
| + } |
| + if (!HasInstantiatedSignature(kFunctions)) { |
| + function_type_arguments = Object::empty_type_arguments().raw(); |
| } |
| - return Closure::New(instantiator, *this, context); |
| + return Closure::New(instantiator_type_arguments, function_type_arguments, |
| + *this, context); |
| } |
| @@ -15655,11 +15683,10 @@ RawAbstractType* Instance::GetType(Heap::Space space) const { |
| Function::Handle(Closure::Cast(*this).function()); |
| Type& type = Type::Handle(signature.SignatureType()); |
| if (!type.IsInstantiated()) { |
| - TypeArguments& instantiator_type_arguments = |
| - TypeArguments::Handle(Closure::Cast(*this).instantiator()); |
| + const TypeArguments& instantiator_type_arguments = TypeArguments::Handle( |
| + Closure::Cast(*this).instantiator_type_arguments()); |
| const TypeArguments& function_type_arguments = |
| - TypeArguments::Handle(signature.type_parameters()); |
| - // TODO(regis): Pass the closure context to InstantiateSignatureFrom(). |
| + TypeArguments::Handle(Closure::Cast(*this).function_type_arguments()); |
| // No bound error possible, since the instance exists. |
| type ^= type.InstantiateFrom(instantiator_type_arguments, |
| function_type_arguments, NULL, NULL, NULL, |
| @@ -15750,11 +15777,10 @@ bool Instance::IsInstanceOf( |
| Function::Handle(zone, Type::Cast(instantiated_other).signature()); |
| Function& sig_fun = Function::Handle(zone, Closure::Cast(*this).function()); |
| if (!sig_fun.HasInstantiatedSignature()) { |
| - const TypeArguments& instantiator_type_arguments = |
| - TypeArguments::Handle(zone, Closure::Cast(*this).instantiator()); |
| - const TypeArguments& function_type_arguments = |
| - TypeArguments::Handle(zone, sig_fun.type_parameters()); |
| - // TODO(regis): Pass the closure context to InstantiateSignatureFrom(). |
| + const TypeArguments& instantiator_type_arguments = TypeArguments::Handle( |
| + zone, Closure::Cast(*this).instantiator_type_arguments()); |
| + const TypeArguments& function_type_arguments = TypeArguments::Handle( |
| + zone, Closure::Cast(*this).function_type_arguments()); |
| sig_fun = sig_fun.InstantiateSignatureFrom( |
| instantiator_type_arguments, function_type_arguments, Heap::kOld); |
| } |
| @@ -16585,6 +16611,13 @@ bool AbstractType::TypeTest(TypeTestKind test_kind, |
| if (type_param.Equals(other_type_param)) { |
| return true; |
| } |
| + // TODO(regis): Should we update TypeParameter::IsEquivalent() instead? |
| + if (type_param.IsFunctionTypeParameter() && |
| + other_type_param.IsFunctionTypeParameter() && |
| + type_param.IsFinalized() && other_type_param.IsFinalized() && |
| + (type_param.index() == other_type_param.index())) { |
| + return true; |
| + } |
| } |
| const AbstractType& bound = AbstractType::Handle(zone, type_param.bound()); |
| // We may be checking bounds at finalization time and can encounter |
| @@ -17796,10 +17829,6 @@ bool TypeParameter::IsInstantiated(Genericity genericity, |
| return IsFunctionTypeParameter(); |
| case kFunctions: |
| return IsClassTypeParameter(); |
| - case kCurrentFunction: |
| - return IsClassTypeParameter() || (parent_level() > 0); |
| - case kParentFunctions: |
| - return IsClassTypeParameter() || (parent_level() == 0); |
| default: |
| UNREACHABLE(); |
| } |
| @@ -17825,12 +17854,12 @@ bool TypeParameter::IsEquivalent(const Instance& other, TrailPtr trail) const { |
| if (parameterized_class_id() != other_type_param.parameterized_class_id()) { |
| return false; |
| } |
| + // The function doesn't matter in type tests, but it does in canonicalization. |
| if (parameterized_function() != other_type_param.parameterized_function()) { |
| return false; |
| } |
| if (IsFinalized() == other_type_param.IsFinalized()) { |
| - return (index() == other_type_param.index()) && |
| - (parent_level() == other_type_param.parent_level()); |
| + return (index() == other_type_param.index()); |
| } |
| return name() == other_type_param.name(); |
| } |
| @@ -17892,15 +17921,17 @@ RawAbstractType* TypeParameter::InstantiateFrom( |
| Heap::Space space) const { |
| ASSERT(IsFinalized()); |
| if (IsFunctionTypeParameter()) { |
| - if (parent_level() == 0) { |
| - if (function_type_arguments.IsNull()) { |
| - return Type::DynamicType(); |
| - } |
| - return function_type_arguments.TypeAt(index()); |
| + // We make the distinction between a null function_type_arguments vector, |
| + // which instantiates every function type parameter to dynamic, and a |
| + // (possibly empty) function_type_arguments vector of length N, which only |
| + // instantiates function type parameters with indices below N. |
| + if (function_type_arguments.IsNull()) { |
| + return Type::DynamicType(); |
| + } |
| + if (index() >= function_type_arguments.Length()) { |
| + // Return uninstantiated type parameter unchanged. |
| + return raw(); |
| } |
| - // We need to find the type argument vector of the parent function at |
| - // parent_level() in the context. |
| - UNIMPLEMENTED(); |
| return function_type_arguments.TypeAt(index()); |
| } |
| ASSERT(IsClassTypeParameter()); |
| @@ -17918,6 +17949,10 @@ RawAbstractType* TypeParameter::InstantiateFrom( |
| // time (i.e. compile time). |
| // Indeed, the instantiator (type arguments of an instance) is always |
| // instantiated at run time and any bounds were checked during allocation. |
| + // Similarly, function type arguments are always instantiated before being |
| + // passed to a function at run time and bounds are checked as part of the |
| + // signature compatibility check (during call resolution or in the function |
| + // prolog). |
| } |
| @@ -17991,7 +18026,7 @@ RawAbstractType* TypeParameter::CloneUnfinalized() const { |
| // No need to clone bound, as it is not part of the finalization state. |
| return TypeParameter::New(Class::Handle(parameterized_class()), |
| Function::Handle(parameterized_function()), index(), |
| - parent_level(), String::Handle(name()), |
| + String::Handle(name()), |
| AbstractType::Handle(bound()), token_pos()); |
| } |
| @@ -18014,7 +18049,7 @@ RawAbstractType* TypeParameter::CloneUninstantiated(const Class& new_owner, |
| index() + new_owner.NumTypeArguments() - old_owner.NumTypeArguments(); |
| AbstractType& upper_bound = AbstractType::Handle(bound()); |
| ASSERT(parameterized_function() == Function::null()); |
| - clone = TypeParameter::New(new_owner, Function::Handle(), new_index, 0, |
| + clone = TypeParameter::New(new_owner, Function::Handle(), new_index, |
| String::Handle(name()), |
| upper_bound, // Not cloned yet. |
| token_pos()); |
| @@ -18032,12 +18067,21 @@ RawString* TypeParameter::EnumerateURIs() const { |
| GrowableHandlePtrArray<const String> pieces(zone, 4); |
| pieces.Add(Symbols::TwoSpaces()); |
| pieces.Add(String::Handle(zone, name())); |
| - pieces.Add(Symbols::SpaceOfSpace()); |
| - const Class& cls = Class::Handle(zone, parameterized_class()); |
| - pieces.Add(String::Handle(zone, cls.UserVisibleName())); |
| - pieces.Add(Symbols::SpaceIsFromSpace()); |
| - const Library& library = Library::Handle(zone, cls.library()); |
| - pieces.Add(String::Handle(zone, library.url())); |
| + Class& cls = Class::Handle(zone, parameterized_class()); |
| + if (cls.IsNull()) { |
| + const Function& fun = Function::Handle(zone, parameterized_function()); |
| + pieces.Add(Symbols::SpaceOfSpace()); |
| + pieces.Add(String::Handle(zone, fun.UserVisibleName())); |
| + cls = fun.Owner(); // May be null. |
| + // TODO(regis): Should we keep the function owner for better error messages? |
| + } |
| + if (!cls.IsNull()) { |
| + pieces.Add(Symbols::SpaceOfSpace()); |
| + pieces.Add(String::Handle(zone, cls.UserVisibleName())); |
| + pieces.Add(Symbols::SpaceIsFromSpace()); |
| + const Library& library = Library::Handle(zone, cls.library()); |
| + pieces.Add(String::Handle(zone, library.url())); |
| + } |
| pieces.Add(Symbols::NewLine()); |
| return Symbols::FromConcatAll(thread, pieces); |
| } |
| @@ -18050,7 +18094,6 @@ intptr_t TypeParameter::ComputeHash() const { |
| result = parameterized_class_id(); |
| } else { |
| result = Function::Handle(parameterized_function()).Hash(); |
| - result = CombineHashes(result, parent_level()); |
| } |
| // No need to include the hash of the bound, since the type parameter is fully |
| // identified by its class and index. |
| @@ -18071,7 +18114,6 @@ RawTypeParameter* TypeParameter::New() { |
| RawTypeParameter* TypeParameter::New(const Class& parameterized_class, |
| const Function& parameterized_function, |
| intptr_t index, |
| - intptr_t parent_level, |
| const String& name, |
| const AbstractType& bound, |
| TokenPosition token_pos) { |
| @@ -18080,7 +18122,6 @@ RawTypeParameter* TypeParameter::New(const Class& parameterized_class, |
| result.set_parameterized_class(parameterized_class); |
| result.set_parameterized_function(parameterized_function); |
| result.set_index(index); |
| - result.set_parent_level(parent_level); |
| result.set_name(name); |
| result.set_bound(bound); |
| result.SetHash(0); |
| @@ -18097,13 +18138,6 @@ void TypeParameter::set_token_pos(TokenPosition token_pos) const { |
| } |
| -void TypeParameter::set_parent_level(intptr_t value) const { |
| - // TODO(regis): Report error in caller if not uint8. |
| - ASSERT(Utils::IsUint(8, value)); |
| - StoreNonPointer(&raw_ptr()->parent_level_, value); |
| -} |
| - |
| - |
| void TypeParameter::set_type_state(int8_t state) const { |
| ASSERT((state == RawTypeParameter::kAllocated) || |
| (state == RawTypeParameter::kBeingFinalized) || |
| @@ -18118,16 +18152,14 @@ const char* TypeParameter::ToCString() const { |
| const char* bound_cstr = String::Handle(upper_bound.Name()).ToCString(); |
| if (IsFunctionTypeParameter()) { |
| const char* format = |
| - "TypeParameter: name %s; index: %d; parent_level: %d, " |
| - "function: %s; bound: %s"; |
| + "TypeParameter: name %s; index: %d; function: %s; bound: %s"; |
| const Function& function = Function::Handle(parameterized_function()); |
| const char* fun_cstr = String::Handle(function.name()).ToCString(); |
| - intptr_t len = OS::SNPrint(NULL, 0, format, name_cstr, index(), |
| - parent_level(), fun_cstr, bound_cstr) + |
| - 1; |
| + intptr_t len = |
| + OS::SNPrint(NULL, 0, format, name_cstr, index(), fun_cstr, bound_cstr) + |
| + 1; |
| char* chars = Thread::Current()->zone()->Alloc<char>(len); |
| - OS::SNPrint(chars, len, format, name_cstr, index(), parent_level(), |
| - fun_cstr, bound_cstr); |
| + OS::SNPrint(chars, len, format, name_cstr, index(), fun_cstr, bound_cstr); |
| return chars; |
| } else { |
| const char* format = |
| @@ -22528,7 +22560,8 @@ const char* Closure::ToCString() const { |
| } |
| -RawClosure* Closure::New(const TypeArguments& instantiator, |
| +RawClosure* Closure::New(const TypeArguments& instantiator_type_arguments, |
| + const TypeArguments& function_type_arguments, |
| const Function& function, |
| const Context& context, |
| Heap::Space space) { |
| @@ -22538,7 +22571,10 @@ RawClosure* Closure::New(const TypeArguments& instantiator, |
| Object::Allocate(Closure::kClassId, Closure::InstanceSize(), space); |
| NoSafepointScope no_safepoint; |
| result ^= raw; |
| - result.StorePointer(&result.raw_ptr()->instantiator_, instantiator.raw()); |
| + result.StorePointer(&result.raw_ptr()->instantiator_type_arguments_, |
| + instantiator_type_arguments.raw()); |
| + result.StorePointer(&result.raw_ptr()->function_type_arguments_, |
| + function_type_arguments.raw()); |
| result.StorePointer(&result.raw_ptr()->function_, function.raw()); |
| result.StorePointer(&result.raw_ptr()->context_, context.raw()); |
| } |