Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(430)

Unified Diff: runtime/vm/class_finalizer.cc

Issue 8491055: Second attempt at finalizing all classes in the VM (fix issue 364). (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: '' Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/class_finalizer.h ('k') | runtime/vm/code_generator.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/class_finalizer.cc
===================================================================
--- runtime/vm/class_finalizer.cc (revision 1474)
+++ runtime/vm/class_finalizer.cc (working copy)
@@ -14,6 +14,7 @@
DEFINE_FLAG(bool, print_classes, false, "Prints details about loaded classes.");
DEFINE_FLAG(bool, trace_class_finalization, false, "Trace class finalization.");
+DEFINE_FLAG(bool, trace_type_finalization, false, "Trace type finalization.");
DEFINE_FLAG(bool, verify_implements, false,
"Verify that all classes implement their interface.");
DECLARE_FLAG(bool, enable_type_checks);
@@ -242,6 +243,39 @@
}
+// Resolve unresolved_class in the library of cls.
+RawClass* ClassFinalizer::ResolveClass(
+ const Class& cls, const UnresolvedClass& unresolved_class) {
+ Library& lib = Library::Handle();
+ if (unresolved_class.qualifier() == String::null()) {
+ lib = cls.library();
+ } else {
+ const String& qualifier = String::Handle(unresolved_class.qualifier());
+ LibraryPrefix& lib_prefix = LibraryPrefix::Handle();
+ lib_prefix = cls.LookupLibraryPrefix(qualifier);
+ if (lib_prefix.IsNull()) {
+ const Script& script = Script::Handle(cls.script());
+ ReportError(script, unresolved_class.token_index(),
+ "cannot resolve library prefix '%s' from '%s'.\n",
+ String::Handle(unresolved_class.Name()).ToCString(),
+ String::Handle(cls.Name()).ToCString());
+ }
+ lib = lib_prefix.library();
+ }
+ ASSERT(!lib.IsNull());
+ const String& class_name = String::Handle(unresolved_class.ident());
+ const Class& resolved_class = Class::Handle(lib.LookupClass(class_name));
+ if (resolved_class.IsNull()) {
+ const Script& script = Script::Handle(cls.script());
+ ReportError(script, unresolved_class.token_index(),
+ "cannot resolve class name '%s' from '%s'.\n",
+ String::Handle(unresolved_class.Name()).ToCString(),
+ String::Handle(cls.Name()).ToCString());
+ }
+ return resolved_class.raw();
+}
+
+
// Resolve unresolved superclasses (String -> Class).
void ClassFinalizer::ResolveSuperClass(const Class& cls) {
if (cls.is_finalized()) {
@@ -253,6 +287,13 @@
}
// Resolve failures lead to a longjmp.
super_type = ResolveType(cls, super_type);
+ if (super_type.IsTypeParameter()) {
+ String& class_name = String::Handle(cls.Name());
+ String& type_parameter_name = String::Handle(super_type.Name());
+ ReportError("'%s' cannot extend or implement type parameter '%s'.\n",
+ class_name.ToCString(),
+ type_parameter_name.ToCString());
+ }
cls.set_super_type(super_type);
const Class& super_class = Class::Handle(super_type.type_class());
if (cls.is_interface() != super_class.is_interface()) {
@@ -326,6 +367,9 @@
if (type.IsResolved()) {
return type.raw();
}
+ if (FLAG_trace_type_finalization) {
+ OS::Print("Resolve type '%s'\n", String::Handle(type.Name()).ToCString());
+ }
// Resolve the type class.
if (!type.HasResolvedTypeClass()) {
@@ -354,31 +398,9 @@
}
// Lookup the type class.
- Class& type_class = Class::Handle();
- Library& lib = Library::Handle();
- if (unresolved_class.qualifier() == String::null()) {
- lib = cls.library();
- } else {
- const String& qualifier = String::Handle(unresolved_class.qualifier());
- LibraryPrefix& lib_prefix = LibraryPrefix::Handle();
- lib_prefix = cls.LookupLibraryPrefix(qualifier);
- if (lib_prefix.IsNull()) {
- const Script& script = Script::Handle(cls.script());
- ReportError(script, unresolved_class.token_index(),
- "cannot resolve name '%s'\n",
- String::Handle(unresolved_class.Name()).ToCString());
- }
- lib = lib_prefix.library();
- }
- ASSERT(!lib.IsNull());
- type_class = lib.LookupClass(type_class_name);
- if (type_class.IsNull()) {
- const Script& script = Script::Handle(cls.script());
- ReportError(script, unresolved_class.token_index(),
- "cannot resolve class name '%s' from '%s'\n",
- String::Handle(unresolved_class.Name()).ToCString(),
- String::Handle(cls.Name()).ToCString());
- }
+ const Class& type_class =
+ Class::Handle(ResolveClass(cls, unresolved_class));
+
// Replace unresolved class with resolved type class.
ASSERT(type.IsParameterizedType());
ParameterizedType& parameterized_type = ParameterizedType::Handle();
@@ -418,37 +440,6 @@
void ClassFinalizer::FinalizeTypeArguments(const Class& cls,
const TypeArguments& arguments) {
ASSERT(arguments.Length() >= cls.NumTypeArguments());
- // If type checks are enabled, verify the subtyping constraints.
- if (FLAG_enable_type_checks) {
- const intptr_t num_type_params = cls.NumTypeParameters();
- const intptr_t offset = cls.NumTypeArguments() - num_type_params;
- Type& type = Type::Handle();
- Type& type_extends = Type::Handle();
- const TypeArguments& extends_array =
- TypeArguments::Handle(cls.type_parameter_extends());
- ASSERT((extends_array.IsNull() && (num_type_params == 0)) ||
- (extends_array.Length() == num_type_params));
- for (intptr_t i = 0; i < num_type_params; i++) {
- type_extends = extends_array.TypeAt(i);
- if (!type_extends.IsDynamicType()) {
- type = arguments.TypeAt(offset + i);
- if (type.IsInstantiated()) {
- if (!type_extends.IsInstantiated()) {
- type_extends = type_extends.InstantiateFrom(arguments, offset);
- }
- // TODO(regis): Where do we check the constraints when the type is
- // generic?
- if (!type.IsSubtypeOf(type_extends)) {
- const String& type_name = String::Handle(type.Name());
- const String& extends_name = String::Handle(type_extends.Name());
- ReportError("type argument '%s' does not extend type '%s'\n",
- type_name.ToCString(),
- extends_name.ToCString());
- }
- }
- }
- }
- }
Type& super_type = Type::Handle(cls.super_type());
if (!super_type.IsNull()) {
super_type = FinalizeType(super_type);
@@ -474,11 +465,57 @@
}
+// Verify the upper bounds of the type arguments of class cls.
+void ClassFinalizer::VerifyUpperBounds(const Class& cls,
+ const TypeArguments& arguments) {
+ ASSERT(FLAG_enable_type_checks);
+ ASSERT(arguments.Length() >= cls.NumTypeArguments());
+ const intptr_t num_type_params = cls.NumTypeParameters();
+ const intptr_t offset = cls.NumTypeArguments() - num_type_params;
+ Type& type = Type::Handle();
+ Type& type_extends = Type::Handle();
+ const TypeArguments& extends_array =
+ TypeArguments::Handle(cls.type_parameter_extends());
+ ASSERT((extends_array.IsNull() && (num_type_params == 0)) ||
+ (extends_array.Length() == num_type_params));
+ for (intptr_t i = 0; i < num_type_params; i++) {
+ type_extends = extends_array.TypeAt(i);
+ if (!type_extends.IsDynamicType()) {
+ type = arguments.TypeAt(offset + i);
+ if (type.IsInstantiated()) {
+ if (!type_extends.IsInstantiated()) {
+ type_extends = type_extends.InstantiateFrom(arguments, offset);
+ }
+ // TODO(regis): Where do we check the constraints when the type is
+ // generic?
+ if (!type.IsSubtypeOf(type_extends)) {
+ const String& type_name = String::Handle(type.Name());
+ const String& extends_name = String::Handle(type_extends.Name());
+ ReportError("type argument '%s' of class '%s' "
+ "does not extend type '%s'\n",
+ type_name.ToCString(),
+ extends_name.ToCString());
+ }
+ }
+ }
+ }
+ Type& super_type = Type::Handle(cls.super_type());
+ if (!super_type.IsNull()) {
+ ASSERT(super_type.IsFinalized());
+ const Class& super_class = Class::Handle(super_type.type_class());
+ VerifyUpperBounds(super_class, arguments);
+ }
+}
+
+
RawType* ClassFinalizer::FinalizeType(const Type& type) {
ASSERT(type.IsResolved());
if (type.IsFinalized()) {
return type.raw();
}
+ if (FLAG_trace_type_finalization) {
+ OS::Print("Finalize type '%s'\n", String::Handle(type.Name()).ToCString());
+ }
// At this point, we can only have a parameterized_type.
ParameterizedType& parameterized_type = ParameterizedType::Handle();
@@ -506,10 +543,24 @@
}
// The type class does not need to be finalized in order to finalize the type,
- // however, it must at least be resolved. This was done as part of resolving
- // the type itself.
+ // however, it must at least be resolved (this was done as part of resolving
+ // the type itself, a precondition to calling FinalizeType) and the upper
+ // bounds of its type parameters must be finalized (done here).
Class& type_class = Class::Handle(parameterized_type.type_class());
+ // If the type class is a signature class, we are finalizing its signature
+ // type, thereby finalizing the result type and parameter types of its
+ // signature function.
+ // Do this before marking this type as finalized in order to detect cycles.
+ if (type_class.IsSignatureClass()) {
+ // Signature classes are finalized upon creation.
+ ASSERT(type_class.is_finalized());
+ // Resolve and finalize the result and parameter types of the signature
+ // function of this signature class.
+ ResolveAndFinalizeSignature(
+ type_class, Function::Handle(type_class.signature_function()));
+ }
+
// The finalized type argument vector needs num_type_arguments types.
const intptr_t num_type_arguments = type_class.NumTypeArguments();
// The type class has num_type_parameters type parameters.
@@ -542,17 +593,28 @@
}
full_arguments.SetTypeAt(offset + i, type);
}
- FinalizeTypeArguments(type_class, full_arguments);
+ if (type_class.IsSignatureClass()) {
+ const Function& signature_fun =
+ Function::Handle(type_class.signature_function());
+ ASSERT(!signature_fun.is_static());
+ const Class& signature_fun_owner = Class::Handle(signature_fun.owner());
+ FinalizeTypeArguments(signature_fun_owner, full_arguments);
+ } else {
+ FinalizeTypeArguments(type_class, full_arguments);
+ }
parameterized_type.set_arguments(full_arguments);
- }
- // If the type is a function type, finalize the result and parameter types.
- if (type_class.IsSignatureClass()) {
- ResolveAndFinalizeSignature(
- type_class, Function::Handle(type_class.signature_function()));
+ // Mark the type as finalized before finalizing the upper bounds, because
+ // cycles via upper bounds are legal at compile time.
+ parameterized_type.set_is_finalized();
+
+ ResolveAndFinalizeUpperBounds(type_class);
+ if (FLAG_enable_type_checks) {
+ VerifyUpperBounds(type_class, full_arguments);
+ }
+ } else {
+ parameterized_type.set_is_finalized();
}
-
- parameterized_type.set_is_finalized();
return parameterized_type.Canonicalize();
}
@@ -580,11 +642,6 @@
}
-// Top level function signatures are canonicalized, added to the library class
-// dictionary, and finalized with other library classes and interfaces.
-// Function signatures used as type of a local variable or of a local function
-// are canonicalized and finalized upon creation, since all the types they
-// reference are already resolved.
void ClassFinalizer::ResolveAndFinalizeSignature(const Class& cls,
const Function& function) {
// Resolve result type.
@@ -644,6 +701,24 @@
}
+// Resolve and finalize the upper bounds of the type parameters of class cls.
+void ClassFinalizer::ResolveAndFinalizeUpperBounds(const Class& cls) {
+ const intptr_t num_type_params = cls.NumTypeParameters();
+ Type& type_extends = Type::Handle();
+ const TypeArguments& extends_array =
+ TypeArguments::Handle(cls.type_parameter_extends());
+ ASSERT((extends_array.IsNull() && (num_type_params == 0)) ||
+ (extends_array.Length() == num_type_params));
+ for (intptr_t i = 0; i < num_type_params; i++) {
+ type_extends = extends_array.TypeAt(i);
+ type_extends = ResolveType(cls, type_extends);
+ extends_array.SetTypeAt(i, type_extends);
+ type_extends = FinalizeType(type_extends);
+ extends_array.SetTypeAt(i, type_extends);
+ }
+}
+
+
void ClassFinalizer::ResolveAndFinalizeMemberTypes(const Class& cls) {
// Note that getters and setters are explicitly listed as such in the list of
// functions of a class, so we do not need to consider fields as implicitly
@@ -777,13 +852,6 @@
}
}
}
- // Resolve the signature type if this class is a signature class.
- if (cls.IsSignatureClass()) {
- Type& signature_type = Type::Handle(cls.SignatureType());
- signature_type = FinalizeType(signature_type);
- // Signature types are canonicalized by default.
- ASSERT(signature_type.raw() == cls.SignatureType());
- }
}
@@ -794,6 +862,8 @@
if (FLAG_trace_class_finalization) {
OS::Print("Finalize %s\n", cls.ToCString());
}
+ // Signature classes are finalized upon creation.
+ ASSERT(!cls.IsSignatureClass());
if (!IsSuperCycleFree(cls)) {
const String& name = String::Handle(cls.Name());
ReportError("class '%s' has a cycle in its superclass relationship.\n",
@@ -833,8 +903,10 @@
interface_type = FinalizeType(interface_type);
interface_types.SetAt(i, interface_type);
}
- // Mark as finalized before resolving member types in order to break cycles.
+ // Mark as finalized before resolving type parameter upper bounds and member
+ // types in order to break cycles.
cls.Finalize();
+ ResolveAndFinalizeUpperBounds(cls);
ResolveAndFinalizeMemberTypes(cls);
// Run additional checks after all types are finalized.
if (cls.is_const()) {
@@ -964,8 +1036,6 @@
String::Handle(cls.Name()).ToCString(),
String::Handle(interface_class.Name()).ToCString());
}
- // TODO(regis): We also need to prevent extending classes Smi, Mint,
- // BigInt, Double, OneByteString, TwoByteString, FourByteString.
}
// Now resolve the super interfaces.
ResolveInterfaces(interface_class, visited);
« no previous file with comments | « runtime/vm/class_finalizer.h ('k') | runtime/vm/code_generator.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698