| Index: runtime/vm/object.cc
|
| diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
|
| index 7bf95a0dbd29193a2ecf3dd639ef4eb369029d49..9744fb8c5cb6fb49c9e258d446a06cf29a88fb09 100644
|
| --- a/runtime/vm/object.cc
|
| +++ b/runtime/vm/object.cc
|
| @@ -15307,6 +15307,19 @@ RawInstance* Instance::CheckAndCanonicalize(Thread* thread,
|
| }
|
|
|
|
|
| +#if defined(DEBUG)
|
| +bool Instance::CheckIsCanonical(Thread* thread) const {
|
| + Zone* zone = thread->zone();
|
| + Isolate* isolate = thread->isolate();
|
| + Instance& result = Instance::Handle(zone);
|
| + const Class& cls = Class::Handle(zone, this->clazz());
|
| + SafepointMutexLocker ml(isolate->constant_canonicalization_mutex());
|
| + result ^= cls.LookupCanonicalInstance(zone, *this);
|
| + return (result.raw() == this->raw());
|
| +}
|
| +#endif // DEBUG
|
| +
|
| +
|
| RawAbstractType* Instance::GetType() const {
|
| if (IsNull()) {
|
| return Type::NullType();
|
| @@ -17115,6 +17128,38 @@ RawAbstractType* Type::Canonicalize(TrailPtr trail) const {
|
| }
|
|
|
|
|
| +#if defined(DEBUG)
|
| +bool Type::CheckIsCanonical(Thread* thread) const {
|
| + if (IsMalformed()) {
|
| + return true;
|
| + }
|
| + if (type_class() == Object::dynamic_class()) {
|
| + return (raw() == Object::dynamic_type().raw());
|
| + }
|
| + Zone* zone = thread->zone();
|
| + Isolate* isolate = thread->isolate();
|
| + AbstractType& type = Type::Handle(zone);
|
| + const Class& cls = Class::Handle(zone, type_class());
|
| +
|
| + // Fast canonical lookup/registry for simple types.
|
| + if (!cls.IsGeneric() && !cls.IsClosureClass() && !cls.IsTypedefClass()) {
|
| + ASSERT(!IsFunctionType());
|
| + type = cls.CanonicalType();
|
| + return (raw() == type.raw());
|
| + }
|
| +
|
| + ObjectStore* object_store = isolate->object_store();
|
| + {
|
| + SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
|
| + CanonicalTypeSet table(zone, object_store->canonical_types());
|
| + type ^= table.GetOrNull(CanonicalTypeKey(*this));
|
| + object_store->set_canonical_types(table.Release());
|
| + }
|
| + return (raw() == type.raw());
|
| +}
|
| +#endif // DEBUG
|
| +
|
| +
|
| RawString* Type::EnumerateURIs() const {
|
| if (IsDynamicType() || IsVoidType()) {
|
| return Symbols::Empty().raw();
|
| @@ -17377,6 +17422,14 @@ RawAbstractType* TypeRef::Canonicalize(TrailPtr trail) const {
|
| }
|
|
|
|
|
| +#if defined(DEBUG)
|
| +bool TypeRef::CheckIsCanonical(Thread* thread) const {
|
| + AbstractType& ref_type = AbstractType::Handle(type());
|
| + return ref_type.CheckIsCanonical(thread);
|
| +}
|
| +#endif // DEBUG
|
| +
|
| +
|
| RawString* TypeRef::EnumerateURIs() const {
|
| Thread* thread = Thread::Current();
|
| Zone* zone = thread->zone();
|
| @@ -18040,11 +18093,11 @@ RawInstance* Number::CheckAndCanonicalize(Thread* thread,
|
| case kDoubleCid:
|
| return Double::NewCanonical(Double::Cast(*this).value());
|
| case kBigintCid: {
|
| + if (this->IsCanonical()) {
|
| + return this->raw();
|
| + }
|
| Zone* zone = thread->zone();
|
| Isolate* isolate = thread->isolate();
|
| - if (!CheckAndCanonicalizeFields(thread, error_str)) {
|
| - return Instance::null();
|
| - }
|
| Bigint& result = Bigint::Handle(zone);
|
| const Class& cls = Class::Handle(zone, this->clazz());
|
| intptr_t index = 0;
|
| @@ -18084,6 +18137,38 @@ RawInstance* Number::CheckAndCanonicalize(Thread* thread,
|
| }
|
|
|
|
|
| +#if defined(DEBUG)
|
| +bool Number::CheckIsCanonical(Thread* thread) const {
|
| + intptr_t cid = GetClassId();
|
| + intptr_t idx = 0;
|
| + Zone* zone = thread->zone();
|
| + const Class& cls = Class::Handle(zone, this->clazz());
|
| + switch (cid) {
|
| + case kSmiCid:
|
| + return true;
|
| + case kMintCid: {
|
| + Mint& result = Mint::Handle(zone);
|
| + result ^= cls.LookupCanonicalMint(zone, Mint::Cast(*this).value(), &idx);
|
| + return (result.raw() == this->raw());
|
| + }
|
| + case kDoubleCid: {
|
| + Double& dbl = Double::Handle(zone);
|
| + dbl ^= cls.LookupCanonicalDouble(zone, Double::Cast(*this).value(), &idx);
|
| + return (dbl.raw() == this->raw());
|
| + }
|
| + case kBigintCid: {
|
| + Bigint& result = Bigint::Handle(zone);
|
| + result ^= cls.LookupCanonicalBigint(zone, Bigint::Cast(*this), &idx);
|
| + return (result.raw() == this->raw());
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + return false;
|
| +}
|
| +#endif // DEBUG
|
| +
|
| +
|
| const char* Number::ToCString() const {
|
| // Number is an interface. No instances of Number should exist.
|
| UNREACHABLE();
|
| @@ -19784,6 +19869,15 @@ RawInstance* String::CheckAndCanonicalize(Thread* thread,
|
| }
|
|
|
|
|
| +#if defined(DEBUG)
|
| +bool String::CheckIsCanonical(Thread* thread) const {
|
| + Zone* zone = thread->zone();
|
| + const String& str = String::Handle(zone, Symbols::Lookup(thread, *this));
|
| + return (str.raw() == this->raw());
|
| +}
|
| +#endif // DEBUG
|
| +
|
| +
|
| RawString* String::New(const char* cstr, Heap::Space space) {
|
| ASSERT(cstr != NULL);
|
| intptr_t array_len = strlen(cstr);
|
| @@ -21304,6 +21398,7 @@ RawArray* Array::Slice(intptr_t start,
|
|
|
| void Array::MakeImmutable() const {
|
| if (IsImmutable()) return;
|
| + ASSERT(!IsCanonical());
|
| NoSafepointScope no_safepoint;
|
| uword tags = raw_ptr()->tags_;
|
| uword old_tags;
|
|
|