| Index: runtime/vm/class_finalizer.cc
|
| ===================================================================
|
| --- runtime/vm/class_finalizer.cc (revision 22914)
|
| +++ runtime/vm/class_finalizer.cc (working copy)
|
| @@ -147,7 +147,7 @@
|
| // Finalize all classes.
|
| for (intptr_t i = 0; i < class_array.Length(); i++) {
|
| cls ^= class_array.At(i);
|
| - FinalizeClass(cls);
|
| + FinalizeTypesInClass(cls);
|
| }
|
| if (FLAG_print_classes) {
|
| for (intptr_t i = 0; i < class_array.Length(); i++) {
|
| @@ -504,7 +504,7 @@
|
| FinalizationKind finalization,
|
| Error* bound_error) {
|
| ASSERT(arguments.Length() >= cls.NumTypeArguments());
|
| - if (!cls.is_finalized()) {
|
| + if (!cls.is_type_finalized()) {
|
| FinalizeTypeParameters(cls);
|
| ResolveUpperBounds(cls);
|
| }
|
| @@ -573,7 +573,7 @@
|
| const Class& cls,
|
| const AbstractTypeArguments& arguments,
|
| Error* bound_error) {
|
| - if (!cls.is_finalized()) {
|
| + if (!cls.is_type_finalized()) {
|
| FinalizeUpperBounds(cls);
|
| }
|
| // Note that when finalizing a type, we need to verify the bounds in both
|
| @@ -683,7 +683,9 @@
|
| ASSERT(finalization >= kFinalize);
|
|
|
| if (FLAG_trace_type_finalization) {
|
| - OS::Print("Finalize type '%s'\n", String::Handle(type.Name()).ToCString());
|
| + OS::Print("Finalize type '%s' for class %s\n",
|
| + String::Handle(type.Name()).ToCString(),
|
| + cls.ToCString());
|
| }
|
|
|
| if (type.IsTypeParameter()) {
|
| @@ -726,7 +728,7 @@
|
| // Also, the interfaces of the type class must be resolved and the type
|
| // parameters of the type class must be finalized.
|
| Class& type_class = Class::Handle(parameterized_type.type_class());
|
| - if (!type_class.is_finalized()) {
|
| + if (!type_class.is_type_finalized()) {
|
| FinalizeTypeParameters(type_class);
|
| ResolveUpperBounds(type_class);
|
| }
|
| @@ -859,7 +861,7 @@
|
| if (type_class.IsSignatureClass()) {
|
| // The class may be created while parsing a function body, after all
|
| // pending classes have already been finalized.
|
| - FinalizeClass(type_class);
|
| + FinalizeTypesInClass(type_class);
|
| }
|
|
|
| // If a bound error occurred, return a BoundedType with a malformed bound.
|
| @@ -1253,14 +1255,14 @@
|
| }
|
|
|
|
|
| -void ClassFinalizer::ApplyMixin(const Class& cls) {
|
| +void ClassFinalizer::ApplyMixinTypes(const Class& cls) {
|
| const Type& mixin_type = Type::Handle(cls.mixin());
|
| ASSERT(!mixin_type.IsNull());
|
| ASSERT(mixin_type.HasResolvedTypeClass());
|
| const Class& mixin_cls = Class::Handle(mixin_type.type_class());
|
|
|
| if (FLAG_trace_class_finalization) {
|
| - OS::Print("Applying mixin '%s' to '%s' at pos %"Pd"\n",
|
| + OS::Print("Applying mixin type '%s' to '%s' at pos %"Pd"\n",
|
| String::Handle(mixin_cls.Name()).ToCString(),
|
| cls.ToCString(),
|
| cls.token_pos());
|
| @@ -1281,10 +1283,34 @@
|
| // Copy type parameters to mixin application class.
|
| CloneTypeParameters(cls);
|
|
|
| + if (FLAG_trace_class_finalization) {
|
| + OS::Print("done mixin type appl %s %s extending %s\n",
|
| + String::Handle(cls.Name()).ToCString(),
|
| + TypeArguments::Handle(cls.type_parameters()).ToCString(),
|
| + AbstractType::Handle(cls.super_type()).ToCString());
|
| + }
|
| +}
|
| +
|
| +
|
| +void ClassFinalizer::ApplyMixin(const Class& cls) {
|
| + Isolate* isolate = Isolate::Current();
|
| + const Type& mixin_type = Type::Handle(isolate, cls.mixin());
|
| + ASSERT(!mixin_type.IsNull());
|
| + ASSERT(mixin_type.HasResolvedTypeClass());
|
| + const Class& mixin_cls = Class::Handle(isolate, mixin_type.type_class());
|
| + mixin_cls.EnsureIsParsed(isolate);
|
| +
|
| + if (FLAG_trace_class_finalization) {
|
| + OS::Print("Applying mixin '%s' to '%s' at pos %"Pd"\n",
|
| + String::Handle(mixin_cls.Name()).ToCString(),
|
| + cls.ToCString(),
|
| + cls.token_pos());
|
| + }
|
| +
|
| const GrowableObjectArray& cloned_funcs =
|
| - GrowableObjectArray::Handle(GrowableObjectArray::New());
|
| - Array& functions = Array::Handle();
|
| - Function& func = Function::Handle();
|
| + GrowableObjectArray::Handle(isolate, GrowableObjectArray::New());
|
| + Array& functions = Array::Handle(isolate);
|
| + Function& func = Function::Handle(isolate);
|
| // The parser creates the mixin application class and adds just
|
| // one function, the implicit constructor.
|
| functions = cls.functions();
|
| @@ -1300,10 +1326,10 @@
|
| if (func.IsConstructor()) {
|
| // A mixin class must not have explicit constructors.
|
| if (!func.IsImplicitConstructor()) {
|
| - const Script& script = Script::Handle(cls.script());
|
| + const Script& script = Script::Handle(isolate, cls.script());
|
| ReportError(script, cls.token_pos(),
|
| "mixin class %s must not have constructors\n",
|
| - String::Handle(mixin_cls.Name()).ToCString());
|
| + String::Handle(isolate, mixin_cls.Name()).ToCString());
|
| }
|
| continue; // Skip the implicit constructor.
|
| }
|
| @@ -1318,10 +1344,10 @@
|
| // Now clone the fields from the mixin class. There should be no
|
| // existing fields in the mixin application class.
|
| ASSERT(Array::Handle(cls.fields()).Length() == 0);
|
| - Array& fields = Array::Handle(mixin_cls.fields());
|
| - Field& field = Field::Handle();
|
| + Array& fields = Array::Handle(isolate, mixin_cls.fields());
|
| + Field& field = Field::Handle(isolate);
|
| const GrowableObjectArray& cloned_fields =
|
| - GrowableObjectArray::Handle(GrowableObjectArray::New());
|
| + GrowableObjectArray::Handle(isolate, GrowableObjectArray::New());
|
| const intptr_t num_fields = fields.Length();
|
| for (int i = 0; i < num_fields; i++) {
|
| field ^= fields.At(i);
|
| @@ -1342,9 +1368,9 @@
|
| }
|
|
|
|
|
| -void ClassFinalizer::FinalizeClass(const Class& cls) {
|
| +void ClassFinalizer::FinalizeTypesInClass(const Class& cls) {
|
| HANDLESCOPE(Isolate::Current());
|
| - if (cls.is_finalized()) {
|
| + if (cls.is_type_finalized()) {
|
| return;
|
| }
|
| if (FLAG_trace_class_finalization) {
|
| @@ -1360,13 +1386,11 @@
|
| // Finalize super class.
|
| const Class& super_class = Class::Handle(cls.SuperClass());
|
| if (!super_class.IsNull()) {
|
| - FinalizeClass(super_class);
|
| + FinalizeTypesInClass(super_class);
|
| }
|
| if (cls.mixin() != Type::null()) {
|
| - // Copy instance methods and fields from the mixin class.
|
| - // This has to happen before the check whether the methods of
|
| - // the class conflict with inherited methods.
|
| - ApplyMixin(cls);
|
| + // Copy the type parameters to the mixin application.
|
| + ApplyMixinTypes(cls);
|
| }
|
| // Finalize type parameters before finalizing the super type.
|
| FinalizeTypeParameters(cls);
|
| @@ -1393,7 +1417,7 @@
|
| "typedef '%s' illegally refers to itself",
|
| name.ToCString());
|
| }
|
| - cls.Finalize();
|
| + cls.set_is_type_finalized();
|
| // Signature classes extend Object. No need to add this class to the direct
|
| // subclasses of Object.
|
| ASSERT(super_type.IsNull() || super_type.IsObjectType());
|
| @@ -1445,33 +1469,53 @@
|
| }
|
| }
|
| }
|
| - // Mark as finalized before resolving type parameter upper bounds and member
|
| - // types in order to break cycles.
|
| - cls.Finalize();
|
| + // Mark as type finalized before resolving type parameter upper bounds and
|
| + // member types in order to break cycles.
|
| + cls.set_is_type_finalized();
|
| // Finalize bounds even if running in production mode, so that a snapshot
|
| // contains them.
|
| FinalizeUpperBounds(cls);
|
| - ResolveAndFinalizeMemberTypes(cls);
|
| - // Run additional checks after all types are finalized.
|
| - if (cls.is_const()) {
|
| - CheckForLegalConstClass(cls);
|
| - }
|
| // Add this class to the direct subclasses of the superclass, unless the
|
| // superclass is Object.
|
| if (!super_type.IsNull() && !super_type.IsObjectType()) {
|
| ASSERT(!super_class.IsNull());
|
| super_class.AddDirectSubclass(cls);
|
| }
|
| + if (cls.is_parsed()) {
|
| + ClassFinalizer::FinalizeClass(cls);
|
| + }
|
| }
|
|
|
|
|
| +void ClassFinalizer::FinalizeClass(const Class& cls) {
|
| + HANDLESCOPE(Isolate::Current());
|
| + if (cls.is_finalized()) {
|
| + return;
|
| + }
|
| + if (cls.mixin() != Type::null()) {
|
| + // Copy instance methods and fields from the mixin class.
|
| + // This has to happen before the check whether the methods of
|
| + // the class conflict with inherited methods.
|
| + ApplyMixin(cls);
|
| + }
|
| + // Mark as parsed and finalized.
|
| + cls.Finalize();
|
| + // Resolve and finalize all member types.
|
| + ResolveAndFinalizeMemberTypes(cls);
|
| + // Run additional checks after all types are finalized.
|
| + if (cls.is_const()) {
|
| + CheckForLegalConstClass(cls);
|
| + }
|
| +}
|
| +
|
| +
|
| bool ClassFinalizer::IsSuperCycleFree(const Class& cls) {
|
| Class& test1 = Class::Handle(cls.raw());
|
| Class& test2 = Class::Handle(cls.SuperClass());
|
| // A finalized class has been checked for cycles.
|
| // Using the hare and tortoise algorithm for locating cycles.
|
| - while (!test1.is_finalized() &&
|
| - !test2.IsNull() && !test2.is_finalized()) {
|
| + while (!test1.is_type_finalized() &&
|
| + !test2.IsNull() && !test2.is_type_finalized()) {
|
| if (test1.raw() == test2.raw()) {
|
| // Found a cycle.
|
| return false;
|
| @@ -1491,7 +1535,7 @@
|
| bool ClassFinalizer::IsAliasCycleFree(const Class& cls,
|
| GrowableArray<intptr_t>* visited) {
|
| ASSERT(cls.IsSignatureClass());
|
| - ASSERT(!cls.is_finalized());
|
| + ASSERT(!cls.is_type_finalized());
|
| ASSERT(visited != NULL);
|
| const intptr_t cls_index = cls.id();
|
| for (int i = 0; i < visited->length(); i++) {
|
| @@ -1509,7 +1553,7 @@
|
| ResolveType(cls, type, kCanonicalize);
|
| if (type.IsType() && !type.IsMalformed()) {
|
| const Class& type_class = Class::Handle(type.type_class());
|
| - if (!type_class.is_finalized() &&
|
| + if (!type_class.is_type_finalized() &&
|
| type_class.IsSignatureClass() &&
|
| !IsAliasCycleFree(type_class, visited)) {
|
| return false;
|
| @@ -1522,7 +1566,7 @@
|
| ResolveType(cls, type, kCanonicalize);
|
| if (type.IsType() && !type.IsMalformed()) {
|
| const Class& type_class = Class::Handle(type.type_class());
|
| - if (!type_class.is_finalized() &&
|
| + if (!type_class.is_type_finalized() &&
|
| type_class.IsSignatureClass() &&
|
| !IsAliasCycleFree(type_class, visited)) {
|
| return false;
|
| @@ -1946,18 +1990,22 @@
|
|
|
| void ClassFinalizer::VerifyImplicitFieldOffsets() {
|
| #ifdef DEBUG
|
| - const ClassTable& class_table = *(Isolate::Current()->class_table());
|
| - Class& cls = Class::Handle();
|
| - Array& fields_array = Array::Handle();
|
| - Field& field = Field::Handle();
|
| - String& name = String::Handle();
|
| - String& expected_name = String::Handle();
|
| + Isolate* isolate = Isolate::Current();
|
| + const ClassTable& class_table = *(isolate->class_table());
|
| + Class& cls = Class::Handle(isolate);
|
| + Array& fields_array = Array::Handle(isolate);
|
| + Field& field = Field::Handle(isolate);
|
| + String& name = String::Handle(isolate);
|
| + String& expected_name = String::Handle(isolate);
|
| + Error& error = Error::Handle(isolate);
|
|
|
| // First verify field offsets of all the TypedDataView classes.
|
| for (intptr_t cid = kTypedDataInt8ArrayViewCid;
|
| cid <= kTypedDataFloat32x4ArrayViewCid;
|
| cid++) {
|
| cls = class_table.At(cid); // Get the TypedDataView class.
|
| + error = cls.EnsureIsParsed(isolate);
|
| + ASSERT(error.IsNull());
|
| cls = cls.SuperClass(); // Get it's super class '_TypedListView'.
|
| fields_array ^= cls.fields();
|
| ASSERT(fields_array.Length() == TypedDataView::NumberOfFields());
|
| @@ -1978,6 +2026,8 @@
|
|
|
| // Now verify field offsets of '_ByteDataView' class.
|
| cls = class_table.At(kByteDataViewCid);
|
| + error = cls.EnsureIsParsed(isolate);
|
| + ASSERT(error.IsNull());
|
| fields_array ^= cls.fields();
|
| ASSERT(fields_array.Length() == TypedDataView::NumberOfFields());
|
| field ^= fields_array.At(0);
|
|
|