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

Unified Diff: runtime/vm/object.cc

Issue 203443012: Fix canonicalization of types. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 9 months 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/reusable_handles.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 34127)
+++ runtime/vm/object.cc (working copy)
@@ -3251,6 +3251,72 @@
}
+intptr_t Class::NumCanonicalTypes() const {
+ if (CanonicalType() != Type::null()) {
+ return 1;
+ }
+ const Object& types = Object::Handle(canonical_types());
+ if (types.IsNull()) {
+ return 0;
+ }
+ intptr_t num_types = Array::Cast(types).Length();
+ while ((num_types > 0) &&
+ (Array::Cast(types).At(num_types - 1) == Type::null())) {
+ num_types--;
+ }
+ return num_types;
+}
+
+
+intptr_t Class::FindCanonicalTypeIndex(const Type& needle) const {
+ Isolate* isolate = Isolate::Current();
+ if (EnsureIsFinalized(isolate) != Error::null()) {
+ return -1;
+ }
+ if (needle.raw() == CanonicalType()) {
+ return 0;
+ }
+ REUSABLE_OBJECT_HANDLESCOPE(isolate);
+ Object& types = isolate->ObjectHandle();
+ types = canonical_types();
+ if (types.IsNull()) {
+ return -1;
+ }
+ const intptr_t len = Array::Cast(types).Length();
+ REUSABLE_ABSTRACT_TYPE_HANDLESCOPE(isolate);
+ AbstractType& type = isolate->AbstractTypeHandle();
+ for (intptr_t i = 0; i < len; i++) {
+ type ^= Array::Cast(types).At(i);
+ if (needle.raw() == type.raw()) {
+ return i;
+ }
+ }
+ // No type found.
+ return -1;
+}
+
+
+RawType* Class::CanonicalTypeFromIndex(intptr_t idx) const {
+ Type& type = Type::Handle();
+ if (idx == 0) {
+ type = CanonicalType();
+ if (!type.IsNull()) {
+ return type.raw();
+ }
+ }
+ Object& types = Object::Handle(canonical_types());
+ if (types.IsNull()) {
+ return Type::null();
+ }
+ if ((idx < 0) || (idx >= Array::Cast(types).Length())) {
+ return Type::null();
+ }
+ type ^= Array::Cast(types).At(idx);
+ ASSERT(!type.IsNull());
+ return type.raw();
+}
+
+
void Class::set_allocation_stub(const Code& value) const {
ASSERT(!value.IsNull());
ASSERT(raw_ptr()->allocation_stub_ == Code::null());
@@ -3613,7 +3679,7 @@
Array& funcs = isolate->ArrayHandle();
funcs ^= functions();
ASSERT(!funcs.IsNull());
- intptr_t len = funcs.Length();
+ const intptr_t len = funcs.Length();
Function& function = isolate->FunctionHandle();
String& function_name = isolate->StringHandle();
for (intptr_t i = 0; i < len; i++) {
@@ -3956,8 +4022,9 @@
intptr_t TypeArguments::Hash() const {
if (IsNull()) return 0;
- uword result = 0;
const intptr_t num_types = Length();
+ if (IsRaw(0, num_types)) return 0;
+ intptr_t result = 0;
AbstractType& type = AbstractType::Handle();
for (intptr_t i = 0; i < num_types; i++) {
type = TypeAt(i);
@@ -4073,10 +4140,29 @@
}
+bool TypeArguments::HasInstantiations() const {
+ const Array& prior_instantiations = Array::Handle(instantiations());
+ ASSERT(prior_instantiations.Length() > 0); // Always at least a sentinel.
+ return prior_instantiations.Length() > 1;
+}
+
+
+intptr_t TypeArguments::NumInstantiations() const {
+ const Array& prior_instantiations = Array::Handle(instantiations());
+ ASSERT(prior_instantiations.Length() > 0); // Always at least a sentinel.
+ intptr_t i = 0;
+ while (prior_instantiations.At(i) != Smi::New(StubCode::kNoInstantiator)) {
+ i += 2;
+ }
+ return i/2;
+}
+
+
RawArray* TypeArguments::instantiations() const {
return raw_ptr()->instantiations_;
}
+
void TypeArguments::set_instantiations(const Array& value) const {
ASSERT(!value.IsNull());
StorePointer(&raw_ptr()->instantiations_, value.raw());
@@ -4316,7 +4402,7 @@
ASSERT(!prior_instantiations.IsNull() && prior_instantiations.IsArray());
// The instantiations cache is initialized with Object::zero_array() and is
// therefore guaranteed to contain kNoInstantiator. No length check needed.
- ASSERT(prior_instantiations.Length() > 0);
+ ASSERT(prior_instantiations.Length() > 0); // Always at least a sentinel.
intptr_t index = 0;
while (true) {
if (prior_instantiations.At(index) == instantiator_type_arguments.raw()) {
@@ -4335,6 +4421,9 @@
}
// Instantiation did not result in bound error. Canonicalize type arguments.
result = result.Canonicalize();
+ // InstantiateAndCanonicalizeFrom is not reentrant. It cannot have been called
+ // indirectly, so the prior_instantiations array cannot have grown.
+ ASSERT(prior_instantiations.raw() == instantiations());
// Add instantiator and result to instantiations array.
intptr_t length = prior_instantiations.Length();
if ((index + 2) >= length) {
@@ -4397,8 +4486,8 @@
static void GrowCanonicalTypeArguments(Isolate* isolate, const Array& table) {
// Last element of the array is the number of used elements.
- intptr_t table_size = table.Length() - 1;
- intptr_t new_table_size = table_size * 2;
+ const intptr_t table_size = table.Length() - 1;
+ const intptr_t new_table_size = table_size * 2;
Array& new_table = Array::Handle(isolate, Array::New(new_table_size + 1));
// Copy all elements from the original table to the newly allocated
// array.
@@ -4434,8 +4523,9 @@
table.SetAt(index, arguments); // Remember the new element.
// Update used count.
// Last element of the array is the number of used elements.
- intptr_t table_size = table.Length() - 1;
- intptr_t used_elements = Smi::Value(Smi::RawCast(table.At(table_size))) + 1;
+ const intptr_t table_size = table.Length() - 1;
+ const intptr_t used_elements =
+ Smi::Value(Smi::RawCast(table.At(table_size))) + 1;
const Smi& used = Smi::Handle(isolate, Smi::New(used_elements));
table.SetAt(table_size, used);
@@ -4452,7 +4542,7 @@
const TypeArguments& arguments,
intptr_t hash) {
// Last element of the array is the number of used elements.
- intptr_t table_size = table.Length() - 1;
+ const intptr_t table_size = table.Length() - 1;
ASSERT(Utils::IsPowerOfTwo(table_size));
intptr_t index = hash & (table_size - 1);
@@ -4491,34 +4581,53 @@
ASSERT(IsOld());
return this->raw();
}
+ const intptr_t num_types = Length();
+ if (IsRaw(0, num_types)) {
+ return TypeArguments::null();
+ }
Isolate* isolate = Isolate::Current();
ObjectStore* object_store = isolate->object_store();
- const Array& table = Array::Handle(isolate,
- object_store->canonical_type_arguments());
- ASSERT(table.Length() > 0);
- intptr_t index = FindIndexInCanonicalTypeArguments(isolate,
- table,
- *this,
- Hash());
+ Array& table = Array::Handle(isolate,
+ object_store->canonical_type_arguments());
+ // Last element of the array is the number of used elements.
+ const intptr_t used_elements =
+ Smi::Value(Smi::RawCast(table.At(table.Length() - 1)));
+ const intptr_t hash = Hash();
+ intptr_t index =
+ FindIndexInCanonicalTypeArguments(isolate, table, *this, hash);
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);
+ AbstractType& type_arg = AbstractType::Handle(isolate);
for (intptr_t i = 0; i < num_types; i++) {
- type = TypeAt(i);
- type = type.Canonicalize(trail);
- SetTypeAt(i, type);
+ type_arg = TypeAt(i);
+ type_arg = type_arg.Canonicalize(trail);
+ SetTypeAt(i, type_arg);
}
- // Make sure we have an old space object and add it to the table.
- if (this->IsNew()) {
- result ^= Object::Clone(*this, Heap::kOld);
- } else {
- result ^= this->raw();
+ // Canonicalization of a recursive type may change its hash.
+ const intptr_t new_hash = Hash();
+ // Canonicalization of the type argument's own type arguments may add an
+ // entry to the table, or even grow the table, and thereby change the
+ // previously calculated index.
+ table = object_store->canonical_type_arguments();
+ if ((new_hash != hash) ||
+ (Smi::Value(Smi::RawCast(table.At(table.Length() - 1)))
+ != used_elements)) {
+ index =
+ FindIndexInCanonicalTypeArguments(isolate, table, *this, new_hash);
+ result ^= table.At(index);
}
- ASSERT(result.IsOld());
- InsertIntoCanonicalTypeArguments(isolate, table, result, index);
+ if (result.IsNull()) {
+ // Make sure we have an old space object and add it to the table.
+ if (this->IsNew()) {
+ result ^= Object::Clone(*this, Heap::kOld);
+ } else {
+ result ^= this->raw();
+ }
+ ASSERT(result.IsOld());
+ InsertIntoCanonicalTypeArguments(isolate, table, result, index);
+ }
}
ASSERT(result.Equals(*this));
ASSERT(!result.IsNull());
@@ -8029,7 +8138,7 @@
if (!entry.IsNull()) {
entry_name = entry.DictionaryName();
ASSERT(!entry_name.IsNull());
- intptr_t hash = entry_name.Hash();
+ const intptr_t hash = entry_name.Hash();
intptr_t index = hash % new_dict_size;
new_entry = new_dict.At(index);
while (!new_entry.IsNull()) {
@@ -13135,7 +13244,7 @@
if (canonical_types.IsNull()) {
canonical_types = empty_array().raw();
}
- const intptr_t length = canonical_types.Length();
+ intptr_t length = canonical_types.Length();
// Linear search to see whether this type is already present in the
// list of canonicalized types.
// TODO(asiva): Try to re-factor this lookup code to make sharing
@@ -13152,6 +13261,8 @@
}
index++;
}
+ // The type was not found in the table. It is not canonical yet.
+
// Canonicalize the type arguments.
TypeArguments& type_args = TypeArguments::Handle(isolate, arguments());
// In case the type is first canonicalized at runtime, its type argument
@@ -13159,6 +13270,26 @@
ASSERT(type_args.IsNull() || (type_args.Length() >= cls.NumTypeArguments()));
type_args = type_args.Canonicalize(trail);
set_arguments(type_args);
+
+ // Canonicalizing the type arguments may have changed the index, may have
+ // grown the table, or may even have canonicalized this type.
+ canonical_types ^= cls.canonical_types();
+ if (canonical_types.IsNull()) {
+ canonical_types = empty_array().raw();
+ }
+ length = canonical_types.Length();
+ while (index < length) {
+ type ^= canonical_types.At(index);
+ if (type.IsNull()) {
+ break;
+ }
+ ASSERT(type.IsFinalized());
+ if (this->Equals(type)) {
+ return type.raw();
+ }
+ index++;
+ }
+
// The type needs to be added to the list. Grow the list if it is full.
if (index == length) {
const intptr_t new_length = (length > 64) ?
@@ -13270,7 +13401,7 @@
}
if (type_arguments.IsNull()) {
const char* format = "Type: class '%s'";
- intptr_t len = OS::SNPrint(NULL, 0, format, class_name) + 1;
+ const intptr_t len = OS::SNPrint(NULL, 0, format, class_name) + 1;
char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, class_name);
return chars;
@@ -13416,7 +13547,7 @@
void TypeRef::AddOnlyBuddyToTrail(GrowableObjectArray** trail,
- const Object& buddy) const {
+ const Object& buddy) const {
if (*trail == NULL) {
*trail = &GrowableObjectArray::ZoneHandle(GrowableObjectArray::New());
} else {
« no previous file with comments | « runtime/vm/object.h ('k') | runtime/vm/reusable_handles.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698