Index: runtime/vm/object.cc |
=================================================================== |
--- runtime/vm/object.cc (revision 33387) |
+++ runtime/vm/object.cc (working copy) |
@@ -3234,6 +3234,70 @@ |
} |
+intptr_t Class::NumCanonicalTypes() const { |
+ if (CanonicalType() != Type::null()) { |
+ return 1; |
+ } |
+ const Object& types = Object::Handle(canonical_types()); |
+ if (types.IsNull() || !types.IsArray()) { |
+ return 0; |
+ } |
+ intptr_t num_types = Array::Cast(types).Length(); |
+ while (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; |
+ } |
+ ReusableHandleScope reused_handles(isolate); |
+ Object& types = reused_handles.ObjectHandle(); |
+ types = canonical_types(); |
+ if (types.IsNull() || !types.IsArray()) { |
+ return -1; |
+ } |
+ const intptr_t len = Array::Cast(types).Length(); |
+ AbstractType& type = reused_handles.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() || !types.IsArray()) { |
+ types = empty_array().raw(); |
+ } |
+ 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()); |
@@ -3594,7 +3658,7 @@ |
ASSERT(!funcs.IsNull()); |
Function& function = reused_handles.FunctionHandle(); |
String& function_name = reused_handles.StringHandle(); |
- intptr_t len = funcs.Length(); |
+ const intptr_t len = funcs.Length(); |
for (intptr_t i = 0; i < len; i++) { |
function ^= funcs.At(i); |
function_name ^= function.name(); |
@@ -3789,6 +3853,7 @@ |
} |
} |
} |
+ jsobj.AddPropertyF("canonicalTypes", "classes/%" Pd "/types", id()); |
} |
} |
@@ -4001,13 +4066,80 @@ |
void TypeArguments::PrintToJSONStream(JSONStream* stream, bool ref) const { |
JSONObject jsobj(stream); |
+ if (IsNull()) { |
+ jsobj.AddProperty("type", ref ? "@Null" : "Null"); |
+ jsobj.AddProperty("id", "objects/null"); |
+ return; |
+ } |
+ // The index in the canonical_type_arguments table cannot be used as part of |
+ // the object id (as in typearguments/id), because the indices are not |
+ // preserved when the table grows and the entries get rehashed. Use the ring. |
+ Isolate* isolate = Isolate::Current(); |
+ ObjectStore* object_store = isolate->object_store(); |
+ const Array& table = Array::Handle(object_store->canonical_type_arguments()); |
+ ASSERT(table.Length() > 0); |
+ ObjectIdRing* ring = Isolate::Current()->object_id_ring(); |
+ const intptr_t id = ring->GetIdForObject(raw()); |
+ jsobj.AddProperty("type", JSONType(ref)); |
+ jsobj.AddPropertyF("id", "objects/%" Pd "", id); |
+ jsobj.AddProperty("name", String::Handle(UserVisibleName()).ToCString()); |
+ jsobj.AddProperty("length", Length()); |
+ jsobj.AddProperty("num_instantiations", NumInstantiations()); |
+ if (ref) { |
+ return; |
+ } |
+ { |
+ JSONArray jsarr(&jsobj, "types"); |
+ AbstractType& type_arg = AbstractType::Handle(); |
+ for (intptr_t i = 0; i < Length(); i++) { |
+ type_arg = TypeAt(i); |
+ jsarr.AddValue(type_arg); |
+ } |
+ } |
+ if (!IsInstantiated()) { |
+ JSONArray jsarr(&jsobj, "instantiations"); |
+ Array& prior_instantiations = Array::Handle(instantiations()); |
+ ASSERT(prior_instantiations.Length() > 0); // Always at least a sentinel. |
+ TypeArguments& type_args = TypeArguments::Handle(); |
+ intptr_t i = 0; |
+ while (true) { |
+ if (prior_instantiations.At(i) == Smi::New(StubCode::kNoInstantiator)) { |
+ break; |
+ } |
+ JSONObject instantiation(&jsarr); |
+ type_args ^= prior_instantiations.At(i); |
+ instantiation.AddProperty("instantiator", type_args, true); |
+ type_args ^= prior_instantiations.At(i + 1); |
+ instantiation.AddProperty("instantiated", type_args, true); |
+ i += 2; |
+ } |
+ } |
} |
+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()); |
@@ -4247,7 +4379,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()) { |
@@ -4370,6 +4502,21 @@ |
const Smi& used = Smi::Handle(isolate, Smi::New(used_elements)); |
table.SetAt(table_size, used); |
+ // TODO(regis): Use a trail to compute hashes of TypeRef, or duplicates will |
+ // show up in the table (different hashes but equal). |
+#if 0 // #ifdef DEBUG |
+ // Verify that there are no duplicates. |
+ // Duplicates could appear if hash values are not kept constant across |
+ // snapshots, e.g. if class ids are not preserved by the snapshots. |
+ TypeArguments& other = TypeArguments::Handle(); |
+ for (intptr_t i = 0; i < table_size; i++) { |
+ if ((i != index) && (table.At(i) != TypeArguments::null())) { |
+ other ^= table.At(i); |
+ ASSERT(!arguments.Equals(other)); |
+ } |
+ } |
+#endif |
+ |
// Rehash if table is 75% full. |
if (used_elements > ((table_size / 4) * 3)) { |
GrowCanonicalTypeArguments(isolate, table); |
@@ -12132,7 +12279,7 @@ |
return; |
} else { |
ObjectIdRing* ring = Isolate::Current()->object_id_ring(); |
- intptr_t id = ring->GetIdForObject(raw()); |
+ const intptr_t id = ring->GetIdForObject(raw()); |
if (IsClosure()) { |
const Function& closureFunc = Function::Handle(Closure::function(*this)); |
jsobj.AddProperty("closureFunc", closureFunc); |
@@ -12569,7 +12716,7 @@ |
void AbstractType::PrintToJSONStream(JSONStream* stream, bool ref) const { |
- JSONObject jsobj(stream); |
+ UNREACHABLE(); |
} |
@@ -13088,7 +13235,26 @@ |
void Type::PrintToJSONStream(JSONStream* stream, bool ref) const { |
+ ASSERT(IsCanonical()); |
JSONObject jsobj(stream); |
+ jsobj.AddProperty("type", JSONType(ref)); |
+ const Class& type_cls = Class::Handle(type_class()); |
+ intptr_t id = type_cls.FindCanonicalTypeIndex(*this); |
+ if (id >= 0) { |
+ intptr_t cid = type_cls.id(); |
+ jsobj.AddPropertyF("id", "classes/%" Pd "/types/%" Pd "", cid, id); |
+ } else { |
+ ObjectIdRing* ring = Isolate::Current()->object_id_ring(); |
+ id = ring->GetIdForObject(raw()); |
Cutch
2014/03/11 13:50:01
How frequently does this path happen?
regis
2014/03/14 23:52:07
If I call PrintToJSON on all canonicalized type ar
|
+ jsobj.AddPropertyF("id", "objects/%" Pd "", id); |
+ } |
+ const char* type_name = String::Handle(UserVisibleName()).ToCString(); |
+ jsobj.AddProperty("name", type_name); |
+ if (ref) { |
+ return; |
+ } |
+ jsobj.AddProperty("type_class", type_cls); |
+ jsobj.AddProperty("type_arguments", TypeArguments::Handle(arguments())); |
} |
@@ -13257,6 +13423,16 @@ |
void TypeRef::PrintToJSONStream(JSONStream* stream, bool ref) const { |
JSONObject jsobj(stream); |
+ ObjectIdRing* ring = Isolate::Current()->object_id_ring(); |
+ const intptr_t id = ring->GetIdForObject(raw()); |
+ jsobj.AddProperty("type", JSONType(ref)); |
+ jsobj.AddPropertyF("id", "objects/%" Pd "", id); |
+ const char* type_name = String::Handle(UserVisibleName()).ToCString(); |
+ jsobj.AddProperty("name", type_name); |
+ if (ref) { |
+ return; |
+ } |
+ jsobj.AddProperty("ref_type", AbstractType::Handle(type())); |
} |
@@ -13461,6 +13637,19 @@ |
void TypeParameter::PrintToJSONStream(JSONStream* stream, bool ref) const { |
JSONObject jsobj(stream); |
+ ObjectIdRing* ring = Isolate::Current()->object_id_ring(); |
+ const intptr_t id = ring->GetIdForObject(raw()); |
+ jsobj.AddProperty("type", JSONType(ref)); |
+ jsobj.AddPropertyF("id", "objects/%" Pd "", id); |
+ jsobj.AddProperty("name", String::Handle(name()).ToCString()); |
+ const Class& cls = Class::Handle(parameterized_class()); |
+ jsobj.AddProperty("parameterized_class", cls); |
+ if (ref) { |
+ return; |
+ } |
+ jsobj.AddProperty("index", index()); |
+ const AbstractType& upper_bound = AbstractType::Handle(bound()); |
+ jsobj.AddProperty("upper_bound", upper_bound); |
} |
@@ -13642,6 +13831,17 @@ |
void BoundedType::PrintToJSONStream(JSONStream* stream, bool ref) const { |
JSONObject jsobj(stream); |
+ ObjectIdRing* ring = Isolate::Current()->object_id_ring(); |
+ const intptr_t id = ring->GetIdForObject(raw()); |
+ jsobj.AddProperty("type", JSONType(ref)); |
+ jsobj.AddPropertyF("id", "objects/%" Pd "", id); |
+ const char* type_name = String::Handle(UserVisibleName()).ToCString(); |
+ jsobj.AddProperty("name", type_name); |
+ if (ref) { |
+ return; |
+ } |
+ jsobj.AddProperty("bounded_type", AbstractType::Handle(type())); |
+ jsobj.AddProperty("upper_bound", AbstractType::Handle(bound())); |
} |
@@ -13675,7 +13875,7 @@ |
void MixinAppType::PrintToJSONStream(JSONStream* stream, bool ref) const { |
- JSONObject jsobj(stream); |
+ UNREACHABLE(); |
} |
@@ -16296,7 +16496,7 @@ |
JSONObject jsobj(stream); |
Class& cls = Class::Handle(this->clazz()); |
ObjectIdRing* ring = Isolate::Current()->object_id_ring(); |
- intptr_t id = ring->GetIdForObject(raw()); |
+ const intptr_t id = ring->GetIdForObject(raw()); |
jsobj.AddProperty("type", JSONType(ref)); |
jsobj.AddPropertyF("id", "objects/%" Pd "", id); |
jsobj.AddProperty("class", cls); |
@@ -16636,7 +16836,7 @@ |
JSONObject jsobj(stream); |
Class& cls = Class::Handle(this->clazz()); |
ObjectIdRing* ring = Isolate::Current()->object_id_ring(); |
- intptr_t id = ring->GetIdForObject(raw()); |
+ const intptr_t id = ring->GetIdForObject(raw()); |
jsobj.AddProperty("type", JSONType(ref)); |
jsobj.AddPropertyF("id", "objects/%" Pd "", id); |
jsobj.AddProperty("class", cls); |