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

Unified Diff: runtime/vm/object.cc

Issue 103913005: Introduce class TypeRef in the VM to fully support recursive types. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years 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/object.h ('k') | runtime/vm/object_store.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/object.cc
===================================================================
--- runtime/vm/object.cc (revision 31085)
+++ runtime/vm/object.cc (working copy)
@@ -902,6 +902,9 @@
cls = Class::New<Type>();
object_store->set_type_class(cls);
+ cls = Class::New<TypeRef>();
+ object_store->set_type_ref_class(cls);
+
cls = Class::New<TypeParameter>();
object_store->set_type_parameter_class(cls);
@@ -1033,6 +1036,10 @@
RegisterPrivateClass(cls, Symbols::Type(), core_lib);
pending_classes.Add(cls);
+ cls = object_store->type_ref_class();
+ RegisterPrivateClass(cls, Symbols::TypeRef(), core_lib);
+ pending_classes.Add(cls);
+
cls = object_store->type_parameter_class();
RegisterPrivateClass(cls, Symbols::TypeParameter(), core_lib);
pending_classes.Add(cls);
@@ -1290,6 +1297,9 @@
cls = Class::New<Type>();
object_store->set_type_class(cls);
+ cls = Class::New<TypeRef>();
+ object_store->set_type_ref_class(cls);
+
cls = Class::New<TypeParameter>();
object_store->set_type_parameter_class(cls);
@@ -1991,6 +2001,7 @@
void Class::set_super_type(const AbstractType& value) const {
ASSERT(value.IsNull() ||
(value.IsType() && !value.IsDynamicType()) ||
+ value.IsTypeRef() ||
value.IsBoundedType() ||
value.IsMixinAppType());
StorePointer(&raw_ptr()->super_type_, value.raw());
@@ -3513,9 +3524,6 @@
// the presence of a malformed bound in checked mode).
continue;
}
- ASSERT((!raw_instantiated && type.IsTypeParameter()) ||
- type.IsBoundedType() ||
- type.IsMalformed());
return false;
}
type_class = type.type_class();
@@ -3579,8 +3587,14 @@
void TypeArguments::SetTypeAt(intptr_t index, const AbstractType& value) const {
- ASSERT(!IsCanonical());
- StorePointer(TypeAddr(index), value.raw());
+ const AbstractType& type_arg = AbstractType::Handle(TypeAt(index));
+ if (type_arg.IsTypeRef()) {
+ if (value.raw() != type_arg.raw()) {
+ TypeRef::Cast(type_arg).set_type(value);
+ }
+ } else {
+ StorePointer(TypeAddr(index), value.raw());
+ }
}
@@ -3915,6 +3929,14 @@
TypeArguments& result = TypeArguments::Handle(isolate);
result ^= table.At(index);
if (result.IsNull()) {
+ // Canonicalize each type argument.
+ const intptr_t num_types = Length();
+ AbstractType& type = AbstractType::Handle(isolate);
+ for (intptr_t i = 0; i < num_types; i++) {
+ type = TypeAt(i);
+ type = type.Canonicalize();
+ SetTypeAt(i, type);
+ }
// Make sure we have an old space object and add it to the table.
if (this->IsNew()) {
result ^= Object::Clone(*this, Heap::kOld);
@@ -11563,8 +11585,8 @@
bool AbstractType::Equals(const Instance& other) const {
// AbstractType is an abstract class.
- ASSERT(raw() == AbstractType::null());
- return other.IsNull();
+ UNREACHABLE();
+ return false;
}
@@ -11685,7 +11707,8 @@
first_type_param_index = 0;
}
String& type_name = String::Handle();
- if (num_type_params == 0) {
+ if ((num_type_params == 0) ||
+ args.IsRaw(first_type_param_index, num_type_params)) {
type_name = class_name.raw();
} else {
const String& args_name = String::Handle(
@@ -12054,17 +12077,6 @@
}
-RawString* Type::TypeClassName() const {
- if (HasResolvedTypeClass()) {
- const Class& cls = Class::Handle(type_class());
- return cls.Name();
- } else {
- const UnresolvedClass& cls = UnresolvedClass::Handle(unresolved_class());
- return cls.Name();
- }
-}
-
-
RawAbstractTypeArguments* Type::arguments() const {
return raw_ptr()->arguments_;
}
@@ -12086,7 +12098,7 @@
RawAbstractType* Type::InstantiateFrom(
const AbstractTypeArguments& instantiator_type_arguments,
Error* bound_error) const {
- ASSERT(IsResolved());
+ ASSERT(IsFinalized() || IsBeingFinalized());
ASSERT(!IsInstantiated());
// Return the uninstantiated type unchanged if malformed. No copy needed.
if (IsMalformed()) {
@@ -12115,6 +12127,10 @@
if (raw() == other.raw()) {
return true;
}
+ if (other.IsTypeRef()) {
+ // TODO(regis): Use trail. For now, we "unfold" the right hand type.
+ return Equals(AbstractType::Handle(TypeRef::Cast(other).type()));
+ }
if (!other.IsType()) {
return false;
}
@@ -12133,13 +12149,17 @@
return true;
}
const Class& cls = Class::Handle(type_class());
+ const intptr_t num_type_params = cls.NumTypeParameters();
+ if (num_type_params == 0) {
+ // Shortcut unnecessary handle allocation below.
+ return true;
+ }
+ const intptr_t num_type_args = cls.NumTypeArguments();
+ const intptr_t from_index = num_type_args - num_type_params;
const AbstractTypeArguments& type_args = AbstractTypeArguments::Handle(
arguments());
const AbstractTypeArguments& other_type_args = AbstractTypeArguments::Handle(
other_type.arguments());
- const intptr_t num_type_args = cls.NumTypeArguments();
- const intptr_t num_type_params = cls.NumTypeParameters();
- const intptr_t from_index = num_type_args - num_type_params;
if (type_args.IsNull()) {
return other_type_args.IsRaw(from_index, num_type_params);
}
@@ -12346,6 +12366,135 @@
}
+bool TypeRef::IsInstantiated() const {
+ if (is_being_checked()) {
+ return true;
+ }
+ set_is_being_checked(true);
+ const bool result = AbstractType::Handle(type()).IsInstantiated();
+ set_is_being_checked(false);
+ return result;
+}
+
+
+bool TypeRef::Equals(const Instance& other) const {
+ // TODO(regis): Use trail instead of mark bit.
+ if (raw() == other.raw()) {
+ return true;
+ }
+ if (is_being_checked()) {
+ return true;
+ }
+ set_is_being_checked(true);
+ const bool result = AbstractType::Handle(type()).Equals(other);
+ set_is_being_checked(false);
+ return result;
+}
+
+
+RawAbstractType* TypeRef::InstantiateFrom(
+ const AbstractTypeArguments& instantiator_type_arguments,
+ Error* bound_error) const {
+ const AbstractType& ref_type = AbstractType::Handle(type());
+ // TODO(regis): Use trail instead of mark bit plus temporary redirection,
+ // because it could be marked for another reason.
+ if (is_being_checked()) {
+ ASSERT(ref_type.IsTypeRef());
+ return ref_type.raw();
+ }
+ set_is_being_checked(true);
+ ASSERT(!ref_type.IsTypeRef());
+ const TypeRef& instantiated_type_ref = TypeRef::Handle(
+ TypeRef::New(ref_type));
+ // TODO(regis): instantiated_type_ref should be stored in the trail instead.
+ set_type(instantiated_type_ref);
+ const AbstractType& instantiated_ref_type = AbstractType::Handle(
+ ref_type.InstantiateFrom(instantiator_type_arguments, bound_error));
+ instantiated_type_ref.set_type(instantiated_ref_type);
+ set_type(ref_type);
+ set_is_being_checked(false);
+ return instantiated_type_ref.raw();
+}
+
+
+void TypeRef::set_type(const AbstractType& value) const {
+ ASSERT(value.HasResolvedTypeClass());
+ StorePointer(&raw_ptr()->type_, value.raw());
+}
+
+
+void TypeRef::set_is_being_checked(bool value) const {
+ raw_ptr()->is_being_checked_ = value;
+}
+
+
+// This function only canonicalizes the referenced type, but not the TypeRef
+// itself, since it cannot be canonical by definition.
+// Consider the type Derived, where class Derived extends Base<Derived>.
+// The first type argument of its flattened type argument vector is Derived,
+// i.e. itself, but pointer equality is not possible.
+RawAbstractType* TypeRef::Canonicalize() const {
+ // TODO(regis): Use trail, not mark bit.
+ if (is_being_checked()) {
+ return raw();
+ }
+ set_is_being_checked(true);
+ AbstractType& ref_type = AbstractType::Handle(type());
+ ASSERT(!ref_type.IsTypeRef());
+ ref_type = ref_type.Canonicalize();
+ set_type(ref_type);
+ // No need to call SetCanonical(), since a TypeRef cannot be canonical by
+ // definition.
+ set_is_being_checked(false);
+ // We return the referenced type instead of the TypeRef in order to provide
+ // pointer equality in simple cases, e.g. in language/f_bounded_equality_test.
+ return ref_type.raw();
+}
+
+
+intptr_t TypeRef::Hash() const {
+ // TODO(regis): Use trail and hash of referenced type.
+ // Do not calculate the hash of the referenced type to avoid cycles.
+ uword result = Class::Handle(AbstractType::Handle(type()).type_class()).id();
+ return FinalizeHash(result);
+}
+
+
+RawTypeRef* TypeRef::New() {
+ ASSERT(Isolate::Current()->object_store()->type_ref_class() != Class::null());
+ RawObject* raw = Object::Allocate(TypeRef::kClassId,
+ TypeRef::InstanceSize(),
+ Heap::kOld);
+ return reinterpret_cast<RawTypeRef*>(raw);
+}
+
+
+RawTypeRef* TypeRef::New(const AbstractType& type) {
+ const TypeRef& result = TypeRef::Handle(TypeRef::New());
+ result.set_type(type);
+ result.set_is_being_checked(false);
+ return result.raw();
+}
+
+
+const char* TypeRef::ToCString() const {
+ const char* format = "TypeRef: %s%s";
+ const char* type_cstr = String::Handle(Class::Handle(AbstractType::Handle(
+ type()).type_class()).Name()).ToCString();
+ const char* args_cstr = (AbstractType::Handle(
+ type()).arguments() == AbstractTypeArguments::null()) ? "" : "<...>";
+ intptr_t len = OS::SNPrint(NULL, 0, format, type_cstr, args_cstr) + 1;
+ char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ OS::SNPrint(chars, len, format, type_cstr, args_cstr);
+ return chars;
+}
+
+
+void TypeRef::PrintToJSONStream(JSONStream* stream, bool ref) const {
+ JSONObject jsobj(stream);
+}
+
+
void TypeParameter::set_is_finalized() const {
ASSERT(!IsFinalized());
set_type_state(RawTypeParameter::kFinalizedUninstantiated);
@@ -12356,6 +12505,10 @@
if (raw() == other.raw()) {
return true;
}
+ if (other.IsTypeRef()) {
+ // TODO(regis): Use trail. For now, we "unfold" the right hand type.
+ return Equals(AbstractType::Handle(TypeRef::Cast(other).type()));
+ }
if (!other.IsTypeParameter()) {
return false;
}
@@ -12400,7 +12553,24 @@
if (instantiator_type_arguments.IsNull()) {
return Type::DynamicType();
}
- return instantiator_type_arguments.TypeAt(index());
+ const AbstractType& type_arg = AbstractType::Handle(
+ instantiator_type_arguments.TypeAt(index()));
+ // There is no need to canonicalize the instantiated type parameter, since all
+ // type arguments are canonicalized at type finalization time. It would be too
+ // early to canonicalize the returned type argument here, since instantiation
+ // not only happens at run time, but also during type finalization.
+ // However, if the type argument is a reference to a canonical type, we
+ // return the referenced canonical type instead of the type reference to
+ // provide pointer equality in some simple cases, e.g. in
+ // language/f_bounded_equality_test.
+ if (type_arg.IsTypeRef()) {
+ const AbstractType& ref_type = AbstractType::Handle(
+ TypeRef::Cast(type_arg).type());
+ if (ref_type.IsCanonical()) {
+ return ref_type.raw();
+ }
+ }
+ return type_arg.raw();
}
@@ -12465,8 +12635,7 @@
intptr_t TypeParameter::Hash() const {
ASSERT(IsFinalized());
- uword result = 0;
- result += Class::Handle(parameterized_class()).id();
+ uword result = Class::Handle(parameterized_class()).id();
// Do not include the hash of the bound, which could lead to cycles.
result <<= index();
return FinalizeHash(result);
@@ -12557,6 +12726,10 @@
if (raw() == other.raw()) {
return true;
}
+ if (other.IsTypeRef()) {
+ // TODO(regis): Use trail. For now, we "unfold" the right hand type.
+ return Equals(AbstractType::Handle(TypeRef::Cast(other).type()));
+ }
if (!other.IsBoundedType()) {
return false;
}
@@ -12580,7 +12753,7 @@
void BoundedType::set_type(const AbstractType& value) const {
- ASSERT(value.IsFinalized());
+ ASSERT(value.IsFinalized() || value.IsBeingFinalized());
ASSERT(!value.IsMalformed());
StorePointer(&raw_ptr()->type_, value.raw());
}
@@ -12660,13 +12833,9 @@
intptr_t BoundedType::Hash() const {
- uword result = 0;
- result += AbstractType::Handle(type()).Hash();
+ uword result = AbstractType::Handle(type()).Hash();
// Do not include the hash of the bound, which could lead to cycles.
- TypeParameter& type_param = TypeParameter::Handle(type_parameter());
- if (!type_param.IsNull()) {
- result += type_param.Hash();
- }
+ result += TypeParameter::Handle(type_parameter()).Hash();
return FinalizeHash(result);
}
« no previous file with comments | « runtime/vm/object.h ('k') | runtime/vm/object_store.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698