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