| Index: runtime/vm/object.cc
|
| diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
|
| index 44e9d23312d593d64b356ef300bad1de9e43d571..63389b6a446460fbc94232abd70b83b507bb23a1 100644
|
| --- a/runtime/vm/object.cc
|
| +++ b/runtime/vm/object.cc
|
| @@ -4399,6 +4399,21 @@ void Class::InsertCanonicalConstant(intptr_t index,
|
| }
|
|
|
|
|
| +void Class::InsertCanonicalNumber(Zone* zone,
|
| + intptr_t index,
|
| + const Number& constant) const {
|
| + // The constant needs to be added to the list. Grow the list if it is full.
|
| + Array& canonical_list = Array::Handle(zone, constants());
|
| + const intptr_t list_len = canonical_list.Length();
|
| + if (index >= list_len) {
|
| + const intptr_t new_length = (list_len == 0) ? 4 : list_len + 4;
|
| + canonical_list ^= Array::Grow(canonical_list, new_length, Heap::kOld);
|
| + set_constants(canonical_list);
|
| + }
|
| + canonical_list.SetAt(index, constant);
|
| +}
|
| +
|
| +
|
| RawUnresolvedClass* UnresolvedClass::New(const LibraryPrefix& library_prefix,
|
| const String& ident,
|
| TokenPosition token_pos) {
|
| @@ -14654,12 +14669,13 @@ class CheckForPointers : public ObjectPointerVisitor {
|
| #endif // DEBUG
|
|
|
|
|
| -bool Instance::CheckAndCanonicalizeFields(const char** error_str) const {
|
| - const Class& cls = Class::Handle(this->clazz());
|
| +bool Instance::CheckAndCanonicalizeFields(Zone* zone,
|
| + const char** error_str) const {
|
| + const Class& cls = Class::Handle(zone, this->clazz());
|
| if (cls.id() >= kNumPredefinedCids) {
|
| // Iterate over all fields, canonicalize numbers and strings, expect all
|
| // other instances to be canonical otherwise report error (return false).
|
| - Object& obj = Object::Handle();
|
| + Object& obj = Object::Handle(zone);
|
| intptr_t end_field_offset = cls.instance_size() - kWordSize;
|
| for (intptr_t field_offset = 0;
|
| field_offset <= end_field_offset;
|
| @@ -14672,8 +14688,7 @@ bool Instance::CheckAndCanonicalizeFields(const char** error_str) const {
|
| this->SetFieldAtOffset(field_offset, obj);
|
| } else {
|
| ASSERT(error_str != NULL);
|
| - char* chars = OS::SCreate(Thread::Current()->zone(),
|
| - "field: %s\n", obj.ToCString());
|
| + char* chars = OS::SCreate(zone, "field: %s\n", obj.ToCString());
|
| *error_str = chars;
|
| return false;
|
| }
|
| @@ -14696,11 +14711,11 @@ RawInstance* Instance::CheckAndCanonicalize(const char** error_str) const {
|
| if (this->IsCanonical()) {
|
| return this->raw();
|
| }
|
| - if (!CheckAndCanonicalizeFields(error_str)) {
|
| - return Instance::null();
|
| - }
|
| Thread* thread = Thread::Current();
|
| Zone* zone = thread->zone();
|
| + if (!CheckAndCanonicalizeFields(zone, error_str)) {
|
| + return Instance::null();
|
| + }
|
| Isolate* isolate = thread->isolate();
|
| Instance& result = Instance::Handle(zone);
|
| const Class& cls = Class::Handle(zone, this->clazz());
|
| @@ -14713,38 +14728,21 @@ RawInstance* Instance::CheckAndCanonicalize(const char** error_str) const {
|
| SafepointMutexLocker ml(isolate->constant_canonicalization_mutex());
|
| // Retry lookup.
|
| {
|
| - Instance& temp_result = Instance::Handle(zone,
|
| - cls.LookupCanonicalInstance(zone, *this, &index));
|
| - if (!temp_result.IsNull()) {
|
| - return temp_result.raw();
|
| + result ^= cls.LookupCanonicalInstance(zone, *this, &index);
|
| + if (!result.IsNull()) {
|
| + return result.raw();
|
| }
|
| }
|
|
|
| // The value needs to be added to the list. Grow the list if
|
| // it is full.
|
| result ^= this->raw();
|
| - if (result.IsNew() ||
|
| - (result.InVMHeap() && (isolate != Dart::vm_isolate()))) {
|
| - /**
|
| - * When a snapshot is generated on a 64 bit architecture and then read
|
| - * into a 32 bit architecture, values which are Smi on the 64 bit
|
| - * architecture could potentially be converted to Mint objects, however
|
| - * since Smi values do not have any notion of canonical bits we lose
|
| - * that information when the object becomes a Mint.
|
| - * Some of these values could be literal values and end up in the
|
| - * VM isolate heap. Later when these values are referenced in a
|
| - * constant list we try to ensure that all the objects in the list
|
| - * are canonical and try to canonicalize them. When these Mint objects
|
| - * are encountered they do not have the canonical bit set and
|
| - * canonicalizing them won't work as the VM heap is read only now.
|
| - * In these cases we clone the object into the isolate and then
|
| - * canonicalize it.
|
| - */
|
| + ASSERT((isolate == Dart::vm_isolate()) || !result.InVMHeap());
|
| + if (result.IsNew()) {
|
| // Create a canonical object in old space.
|
| result ^= Object::Clone(result, Heap::kOld);
|
| }
|
| ASSERT(result.IsOld());
|
| -
|
| result.SetCanonical();
|
| cls.InsertCanonicalConstant(index, result);
|
| return result.raw();
|
| @@ -14956,7 +14954,8 @@ bool Instance::IsIdenticalTo(const Instance& other) const {
|
| return Integer::Cast(*this).Equals(other);
|
| }
|
| if (IsDouble() && other.IsDouble()) {
|
| - return Double::Cast(*this).CanonicalizeEquals(other);
|
| + double other_value = Double::Cast(other).value();
|
| + return Double::Cast(*this).BitwiseEqualsToDouble(other_value);
|
| }
|
| return false;
|
| }
|
| @@ -17360,6 +17359,61 @@ RawMixinAppType* MixinAppType::New(const AbstractType& super_type,
|
| }
|
|
|
|
|
| +RawInstance* Number::CheckAndCanonicalize(const char** error_str) const {
|
| + intptr_t cid = GetClassId();
|
| + switch (cid) {
|
| + case kSmiCid:
|
| + return reinterpret_cast<RawSmi*>(raw_value());
|
| + case kMintCid:
|
| + return Mint::NewCanonical(Mint::Cast(*this).value());
|
| + case kDoubleCid:
|
| + return Double::NewCanonical(Double::Cast(*this).value());
|
| + case kBigintCid: {
|
| + Thread* thread = Thread::Current();
|
| + Zone* zone = thread->zone();
|
| + Isolate* isolate = thread->isolate();
|
| + if (!CheckAndCanonicalizeFields(zone, error_str)) {
|
| + return Instance::null();
|
| + }
|
| + Bigint& result = Bigint::Handle(zone);
|
| + const Class& cls = Class::Handle(zone, this->clazz());
|
| + intptr_t index = 0;
|
| + result ^= cls.LookupCanonicalBigint(zone, Bigint::Cast(*this), &index);
|
| + if (!result.IsNull()) {
|
| + return result.raw();
|
| + }
|
| + {
|
| + SafepointMutexLocker ml(isolate->constant_canonicalization_mutex());
|
| + // Retry lookup.
|
| + {
|
| + result ^= cls.LookupCanonicalBigint(
|
| + zone, Bigint::Cast(*this), &index);
|
| + if (!result.IsNull()) {
|
| + return result.raw();
|
| + }
|
| + }
|
| +
|
| + // The value needs to be added to the list. Grow the list if
|
| + // it is full.
|
| + result ^= this->raw();
|
| + ASSERT((isolate == Dart::vm_isolate()) || !result.InVMHeap());
|
| + if (result.IsNew()) {
|
| + // Create a canonical object in old space.
|
| + result ^= Object::Clone(result, Heap::kOld);
|
| + }
|
| + ASSERT(result.IsOld());
|
| + result.SetCanonical();
|
| + cls.InsertCanonicalNumber(zone, index, result);
|
| + return result.raw();
|
| + }
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + return Instance::null();
|
| +}
|
| +
|
| +
|
| const char* Number::ToCString() const {
|
| // Number is an interface. No instances of Number should exist.
|
| UNREACHABLE();
|
| @@ -17783,17 +17837,16 @@ RawMint* Mint::NewCanonical(int64_t value) {
|
| SafepointMutexLocker ml(isolate->constant_canonicalization_mutex());
|
| // Retry lookup.
|
| {
|
| - const Mint& result =
|
| - Mint::Handle(zone, cls.LookupCanonicalMint(zone, value, &index));
|
| - if (!result.IsNull()) {
|
| - return result.raw();
|
| + canonical_value ^= cls.LookupCanonicalMint(zone, value, &index);
|
| + if (!canonical_value.IsNull()) {
|
| + return canonical_value.raw();
|
| }
|
| }
|
| canonical_value = Mint::New(value, Heap::kOld);
|
| canonical_value.SetCanonical();
|
| // The value needs to be added to the constants list. Grow the list if
|
| // it is full.
|
| - cls.InsertCanonicalConstant(index, canonical_value);
|
| + cls.InsertCanonicalNumber(zone, index, canonical_value);
|
| return canonical_value.raw();
|
| }
|
| }
|
| @@ -17936,17 +17989,16 @@ RawDouble* Double::NewCanonical(double value) {
|
| SafepointMutexLocker ml(isolate->constant_canonicalization_mutex());
|
| // Retry lookup.
|
| {
|
| - const Double& result =
|
| - Double::Handle(zone, cls.LookupCanonicalDouble(zone, value, &index));
|
| - if (!result.IsNull()) {
|
| - return result.raw();
|
| + canonical_value ^= cls.LookupCanonicalDouble(zone, value, &index);
|
| + if (!canonical_value.IsNull()) {
|
| + return canonical_value.raw();
|
| }
|
| }
|
| canonical_value = Double::New(value, Heap::kOld);
|
| canonical_value.SetCanonical();
|
| // The value needs to be added to the constants list. Grow the list if
|
| // it is full.
|
| - cls.InsertCanonicalConstant(index, canonical_value);
|
| + cls.InsertCanonicalNumber(zone, index, canonical_value);
|
| return canonical_value.raw();
|
| }
|
| }
|
| @@ -18073,13 +18125,14 @@ bool Bigint::Equals(const Instance& other) const {
|
| }
|
|
|
|
|
| -bool Bigint::CheckAndCanonicalizeFields(const char** error_str) const {
|
| +bool Bigint::CheckAndCanonicalizeFields(Zone* zone,
|
| + const char** error_str) const {
|
| // Bool field neg should always be canonical.
|
| - ASSERT(Bool::Handle(neg()).IsCanonical());
|
| + ASSERT(Bool::Handle(zone, neg()).IsCanonical());
|
| // Smi field used is canonical by definition.
|
| if (Used() > 0) {
|
| // Canonicalize TypedData field digits.
|
| - TypedData& digits_ = TypedData::Handle(digits());
|
| + TypedData& digits_ = TypedData::Handle(zone, digits());
|
| digits_ ^= digits_.CheckAndCanonicalize(NULL);
|
| ASSERT(!digits_.IsNull());
|
| set_digits(digits_);
|
| @@ -18237,8 +18290,8 @@ RawBigint* Bigint::NewCanonical(const String& str) {
|
| const Class& cls =
|
| Class::Handle(zone, isolate->object_store()->bigint_class());
|
| intptr_t index = 0;
|
| - const Bigint& canonical_value =
|
| - Bigint::Handle(zone, cls.LookupCanonicalBigint(zone, value, &index));
|
| + Bigint& canonical_value = Bigint::Handle(zone);
|
| + canonical_value ^= cls.LookupCanonicalBigint(zone, value, &index);
|
| if (!canonical_value.IsNull()) {
|
| return canonical_value.raw();
|
| }
|
| @@ -18246,16 +18299,15 @@ RawBigint* Bigint::NewCanonical(const String& str) {
|
| SafepointMutexLocker ml(isolate->constant_canonicalization_mutex());
|
| // Retry lookup.
|
| {
|
| - const Bigint& result =
|
| - Bigint::Handle(zone, cls.LookupCanonicalBigint(zone, value, &index));
|
| - if (!result.IsNull()) {
|
| - return result.raw();
|
| + canonical_value ^= cls.LookupCanonicalBigint(zone, value, &index);
|
| + if (!canonical_value.IsNull()) {
|
| + return canonical_value.raw();
|
| }
|
| }
|
| value.SetCanonical();
|
| // The value needs to be added to the constants list. Grow the list if
|
| // it is full.
|
| - cls.InsertCanonicalConstant(index, value);
|
| + cls.InsertCanonicalNumber(zone, index, value);
|
| return value.raw();
|
| }
|
| }
|
| @@ -20494,14 +20546,7 @@ bool Array::CanonicalizeEquals(const Instance& other) const {
|
| return false;
|
| }
|
|
|
| - // Both arrays must have the same type arguments.
|
| - const TypeArguments& type_args = TypeArguments::Handle(GetTypeArguments());
|
| - const TypeArguments& other_type_args = TypeArguments::Handle(
|
| - other.GetTypeArguments());
|
| - if (!type_args.Equals(other_type_args)) {
|
| - return false;
|
| - }
|
| -
|
| + // First check if both arrays have the same length and elements.
|
| const Array& other_arr = Array::Cast(other);
|
|
|
| intptr_t len = this->Length();
|
| @@ -20514,6 +20559,14 @@ bool Array::CanonicalizeEquals(const Instance& other) const {
|
| return false;
|
| }
|
| }
|
| +
|
| + // Now check if both arrays have the same type arguments.
|
| + const TypeArguments& type_args = TypeArguments::Handle(GetTypeArguments());
|
| + const TypeArguments& other_type_args = TypeArguments::Handle(
|
| + other.GetTypeArguments());
|
| + if (!type_args.Equals(other_type_args)) {
|
| + return false;
|
| + }
|
| return true;
|
| }
|
|
|
| @@ -20659,8 +20712,9 @@ RawArray* Array::MakeArray(const GrowableObjectArray& growable_array) {
|
| }
|
|
|
|
|
| -bool Array::CheckAndCanonicalizeFields(const char** error_str) const {
|
| - Object& obj = Object::Handle();
|
| +bool Array::CheckAndCanonicalizeFields(Zone* zone,
|
| + const char** error_str) const {
|
| + Object& obj = Object::Handle(zone);
|
| // Iterate over all elements, canonicalize numbers and strings, expect all
|
| // other instances to be canonical otherwise report error (return false).
|
| for (intptr_t i = 0; i < Length(); i++) {
|
| @@ -20730,44 +20784,6 @@ RawObject* GrowableObjectArray::RemoveLast() const {
|
| }
|
|
|
|
|
| -bool GrowableObjectArray::CanonicalizeEquals(const Instance& other) const {
|
| - // If both handles point to the same raw instance they are equal.
|
| - if (this->raw() == other.raw()) {
|
| - return true;
|
| - }
|
| -
|
| - // Other instance must be non null and a GrowableObjectArray.
|
| - if (!other.IsGrowableObjectArray() || other.IsNull()) {
|
| - return false;
|
| - }
|
| -
|
| - const GrowableObjectArray& other_arr = GrowableObjectArray::Cast(other);
|
| -
|
| - // The capacity and length of both objects must be equal.
|
| - if (Capacity() != other_arr.Capacity() || Length() != other_arr.Length()) {
|
| - return false;
|
| - }
|
| -
|
| - // Both arrays must have the same type arguments.
|
| - const TypeArguments& type_args = TypeArguments::Handle(GetTypeArguments());
|
| - const TypeArguments& other_type_args = TypeArguments::Handle(
|
| - other.GetTypeArguments());
|
| - if (!type_args.Equals(other_type_args)) {
|
| - return false;
|
| - }
|
| -
|
| - // The data part in both arrays must be identical.
|
| - const Array& contents = Array::Handle(data());
|
| - const Array& other_contents = Array::Handle(other_arr.data());
|
| - for (intptr_t i = 0; i < Length(); i++) {
|
| - if (contents.At(i) != other_contents.At(i)) {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -
|
| RawGrowableObjectArray* GrowableObjectArray::New(intptr_t capacity,
|
| Heap::Space space) {
|
| const Array& data = Array::Handle(Array::New(capacity, space));
|
|
|