| 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();
|
| 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());
|
| }
|
|
|