Index: runtime/vm/object.cc |
=================================================================== |
--- runtime/vm/object.cc (revision 23933) |
+++ runtime/vm/object.cc (working copy) |
@@ -9209,13 +9209,43 @@ |
} |
-RawInstance* Instance::Canonicalize() const { |
+RawInstance* Instance::CheckAndCanonicalize(const char** error_str) const { |
ASSERT(!IsNull()); |
if (this->IsCanonical()) { |
return this->raw(); |
} |
Instance& result = Instance::Handle(); |
const Class& cls = Class::Handle(this->clazz()); |
+ // TODO(srdjan): Check that predefined classes do not have fields that need |
+ // to be checked/canonicalized as well. |
+ if ((cls.id() >= kNumPredefinedCids) || cls.IsArray()) { |
+ // Iterate over all fields, canonicalize numbers and strings, expect all |
+ // other instances to be canonical otherwise report error (return |
+ // Instance::null()). |
+ Object& obj = Object::Handle(); |
+ const intptr_t end_field_offset = cls.instance_size() - kWordSize; |
+ for (intptr_t field_offset = 0; |
+ field_offset <= end_field_offset; |
+ field_offset += kWordSize) { |
+ obj = *this->FieldAddrAtOffset(field_offset); |
+ if (obj.IsInstance() && !obj.IsSmi() && !obj.IsCanonical()) { |
+ if (obj.IsNumber() || obj.IsString()) { |
+ obj = Instance::Cast(obj).CheckAndCanonicalize(NULL); |
+ ASSERT(!obj.IsNull()); |
+ this->SetFieldAtOffset(field_offset, obj); |
+ } else { |
+ ASSERT(error_str != NULL); |
+ const char* kFormat = "field: %s\n"; |
+ const intptr_t len = |
+ OS::SNPrint(NULL, 0, kFormat, obj.ToCString()) + 1; |
+ char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
+ OS::SNPrint(chars, len, kFormat, obj.ToCString()); |
+ *error_str = chars; |
+ return Instance::null(); |
+ } |
+ } |
+ } |
+ } |
Array& constants = Array::Handle(cls.constants()); |
const intptr_t constants_len = constants.Length(); |
// Linear search to see whether this value is already present in the |
@@ -11563,7 +11593,7 @@ |
} |
-RawInstance* String::Canonicalize() const { |
+RawInstance* String::CheckAndCanonicalize(const char** error_str) const { |
if (IsCanonical()) { |
return this->raw(); |
} |