| Index: runtime/vm/object.cc
|
| diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
|
| index 98d7b238584f2c48a85d7ce384475d7cf4e99e58..349dc25956fd78659aee6aae97efd35cecc3c34e 100644
|
| --- a/runtime/vm/object.cc
|
| +++ b/runtime/vm/object.cc
|
| @@ -703,6 +703,10 @@ void Object::InitOnce(Isolate* isolate) {
|
| isolate->object_store()->set_bigint_class(cls);
|
| cls = Class::New<Double>();
|
| isolate->object_store()->set_double_class(cls);
|
| + cls = Class::New<Fraction>();
|
| + // TODO(regis): Remove once native getters are implemented for _Fraction.
|
| + cls.SetRefinalizeAfterPatch(); // Fields are defined both in C++ and in Dart.
|
| + isolate->object_store()->set_fraction_class(cls);
|
|
|
| // Ensure that class kExternalTypedDataUint8ArrayCid is registered as we
|
| // need it when reading in the token stream of bootstrap classes in the VM
|
| @@ -1378,6 +1382,13 @@ NOT_IN_PRODUCT(
|
| RegisterPrivateClass(cls, Symbols::_Double(), core_lib);
|
| pending_classes.Add(cls);
|
|
|
| + cls = Class::New<Fraction>();
|
| + object_store->set_fraction_class(cls);
|
| + // TODO(regis): Remove once native getters are implemented for _Fraction.
|
| + cls.SetRefinalizeAfterPatch(); // Fields are defined both in C++ and in Dart.
|
| + RegisterPrivateClass(cls, Symbols::_Fraction(), core_lib);
|
| + pending_classes.Add(cls);
|
| +
|
| // Class that represents the Dart class _Closure and C++ class Closure.
|
| cls = Class::New<Closure>();
|
| cls.set_type_arguments_field_offset(Closure::type_arguments_offset());
|
| @@ -1698,6 +1709,7 @@ NOT_IN_PRODUCT(
|
| #undef REGISTER_EXT_TYPED_DATA_CLASS
|
|
|
| cls = Class::New<Instance>(kByteBufferCid);
|
| + object_store->set_byte_buffer_class(cls);
|
|
|
| cls = Class::New<Integer>();
|
| object_store->set_integer_implementation_class(cls);
|
| @@ -1711,6 +1723,11 @@ NOT_IN_PRODUCT(
|
| cls = Class::New<Double>();
|
| object_store->set_double_class(cls);
|
|
|
| + cls = Class::New<Fraction>();
|
| + // TODO(regis): Remove once native getters are implemented for _Fraction.
|
| + cls.SetRefinalizeAfterPatch(); // Fields are defined both in C++ and in Dart.
|
| + object_store->set_fraction_class(cls);
|
| +
|
| cls = Class::New<Closure>();
|
| object_store->set_closure_class(cls);
|
|
|
| @@ -3572,7 +3589,7 @@ void Class::set_is_finalized() const {
|
|
|
|
|
| void Class::SetRefinalizeAfterPatch() const {
|
| - ASSERT(!IsTopLevel());
|
| + ASSERT((raw_ptr()->name_ == String::null()) || !IsTopLevel());
|
| set_state_bits(ClassFinalizedBits::update(RawClass::kRefinalizeAfterPatch,
|
| raw_ptr()->state_bits_));
|
| set_state_bits(TypeFinalizedBit::update(false, raw_ptr()->state_bits_));
|
| @@ -4338,6 +4355,30 @@ RawBigint* Class::LookupCanonicalBigint(Zone* zone,
|
| }
|
|
|
|
|
| +RawFraction* Class::LookupCanonicalFraction(Zone* zone,
|
| + const Fraction& value,
|
| + intptr_t* index) const {
|
| + ASSERT(this->raw() == Isolate::Current()->object_store()->fraction_class());
|
| + const Array& constants = Array::Handle(zone, this->constants());
|
| + const intptr_t constants_len = constants.Length();
|
| + // Linear search to see whether this value is already present in the
|
| + // list of canonicalized constants.
|
| + Fraction& canonical_value = Fraction::Handle(zone);
|
| + while (*index < constants_len) {
|
| + canonical_value ^= constants.At(*index);
|
| + if (canonical_value.IsNull()) {
|
| + break;
|
| + }
|
| + if (canonical_value.CanonicalizeEquals(value)) {
|
| + ASSERT(canonical_value.IsCanonical());
|
| + return canonical_value.raw();
|
| + }
|
| + *index = *index + 1;
|
| + }
|
| + return Fraction::null();
|
| +}
|
| +
|
| +
|
| class CanonicalInstanceKey {
|
| public:
|
| explicit CanonicalInstanceKey(const Instance& key) : key_(key) {
|
| @@ -8017,6 +8058,9 @@ RawLiteralToken* LiteralToken::New(Token::Kind kind, const String& literal) {
|
| const Integer& value = Integer::Handle(Integer::NewCanonical(literal));
|
| ASSERT(value.IsSmi() || value.IsOld());
|
| result.set_value(value);
|
| + } else if (kind == Token::kRATIONAL) {
|
| + const Fraction& value = Fraction::Handle(Fraction::NewCanonical(literal));
|
| + result.set_value(value);
|
| } else if (kind == Token::kDOUBLE) {
|
| const Double& value = Double::Handle(Double::NewCanonical(literal));
|
| result.set_value(value);
|
| @@ -18061,6 +18105,9 @@ RawInstance* Number::CheckAndCanonicalize(Thread* thread,
|
| return result.raw();
|
| }
|
| }
|
| + case kFractionCid: {
|
| + return Fraction::NewCanonical(Fraction::Cast(*this));
|
| + }
|
| default:
|
| UNREACHABLE();
|
| }
|
| @@ -18959,6 +19006,7 @@ RawBigint* Bigint::NewCanonical(const String& str) {
|
| return canonical_value.raw();
|
| }
|
| }
|
| + ASSERT(value.IsOld());
|
| value.SetCanonical();
|
| // The value needs to be added to the constants list. Grow the list if
|
| // it is full.
|
| @@ -19451,6 +19499,170 @@ const char* Bigint::ToCString() const {
|
| }
|
|
|
|
|
| +bool Fraction::CanonicalizeEquals(const Instance& other) const {
|
| + if (this->raw() == other.raw()) {
|
| + return true; // "===".
|
| + }
|
| + if (other.IsNull() || !other.IsFraction()) {
|
| + return false;
|
| + }
|
| + return (numerator() == Fraction::Cast(other).numerator()) &&
|
| + (denominator() == Fraction::Cast(other).denominator());
|
| +}
|
| +
|
| +
|
| +RawFraction* Fraction::New(Heap::Space space) {
|
| + return Fraction::New(0, 0, space);
|
| +}
|
| +
|
| +
|
| +RawFraction* Fraction::New(uint64_t numerator,
|
| + uint64_t denominator,
|
| + Heap::Space space) {
|
| + Thread* thread = Thread::Current();
|
| + Zone* zone = thread->zone();
|
| + Isolate* isolate = thread->isolate();
|
| + ASSERT(isolate->object_store()->fraction_class() != Class::null());
|
| + Fraction& result = Fraction::Handle(zone);
|
| + {
|
| + RawObject* raw = Object::Allocate(Fraction::kClassId,
|
| + Fraction::InstanceSize(),
|
| + space);
|
| + NoSafepointScope no_safepoint;
|
| + result ^= raw;
|
| + }
|
| + result.set_numerator(Integer::Handle(
|
| + Integer::NewFromUint64(numerator, space)));
|
| + result.set_denominator(Integer::Handle(
|
| + Integer::NewFromUint64(denominator, space)));
|
| + return result.raw();
|
| +}
|
| +
|
| +
|
| +void Fraction::set_numerator(const Integer& value) const {
|
| + StorePointer(&raw_ptr()->numerator_, value.raw());
|
| +}
|
| +
|
| +
|
| +static bool CStringToFraction(const char* str,
|
| + intptr_t length,
|
| + uint64_t* numerator,
|
| + uint64_t* denominator) {
|
| + ASSERT(str != NULL);
|
| + ASSERT(length > 0);
|
| + const uint64_t max_accum = (1ULL << 63) / 10;
|
| + uint64_t num = 0ULL;
|
| + uint64_t denom = 1ULL;
|
| + bool seen_decimal_point = false;
|
| + for (intptr_t i = 0; i < length; i++) {
|
| + char c = str[i];
|
| + if (!seen_decimal_point && (c == '.')) {
|
| + seen_decimal_point = true;
|
| + } else if (('0' <= c) && (c <= '9')) {
|
| + // Bail if numerator or denominator get close to Bigint.
|
| + if ((num > max_accum) || (denom > max_accum)) {
|
| + return false;
|
| + }
|
| + num = num*10 + (c - '0');
|
| + if (seen_decimal_point) denom *= 10;
|
| + } else {
|
| + if ((str[i] != 'r') && (str[i] != 'R')) {
|
| + return false;
|
| + }
|
| + break;
|
| + }
|
| + }
|
| + // Reduce somewhat. Do not reduce if denominator is 100.
|
| + while ((denom != 100ULL) && ((num & 1) == 0) && ((denom & 1) == 0)) {
|
| + num >>= 1;
|
| + denom >>= 1;
|
| + }
|
| + // TODO(regis): Reduce further using gcd.
|
| + *numerator = num;
|
| + *denominator = denom;
|
| + return true;
|
| +}
|
| +
|
| +
|
| +RawFraction* Fraction::NewCanonical(const String& str) {
|
| + uint64_t nominator;
|
| + uint64_t denominator;
|
| + if (!CStringToFraction(str.ToCString(), str.Length(),
|
| + &nominator, &denominator)) {
|
| + // Call the Dart version, which supports Bigint.
|
| + // Not supported when called early from core lib itself.
|
| + const Library& core_lib = Library::Handle(Library::CoreLibrary());
|
| + ASSERT(!core_lib.IsNull());
|
| + const String& fraction_class_name = Symbols::_Fraction();
|
| + const String& constructor_name = Symbols::DotFromRationalLiteral();
|
| + const Array& constructor_args = Array::Handle(Array::New(1));
|
| + constructor_args.SetAt(0, str);
|
| + Object& value = Object::Handle(
|
| + DartLibraryCalls::InstanceCreate(core_lib,
|
| + fraction_class_name,
|
| + constructor_name,
|
| + true, // A factory.
|
| + constructor_args));
|
| + ASSERT(!value.IsError());
|
| + return Fraction::NewCanonical(Fraction::Cast(value));
|
| + }
|
| + return Fraction::NewCanonical(Fraction::Handle(
|
| + Fraction::New(nominator, denominator, Heap::kOld)));
|
| +}
|
| +
|
| +
|
| +RawFraction* Fraction::NewCanonical(const Fraction& value) {
|
| + // TODO(regis): Canonicalize fields.
|
| + Thread* thread = Thread::Current();
|
| + Zone* zone = thread->zone();
|
| + Isolate* isolate = thread->isolate();
|
| + const Class& cls =
|
| + Class::Handle(zone, isolate->object_store()->fraction_class());
|
| + intptr_t index = 0;
|
| + Fraction& canonical_value = Fraction::Handle(zone);
|
| + canonical_value ^= cls.LookupCanonicalFraction(zone, value, &index);
|
| + if (!canonical_value.IsNull()) {
|
| + return canonical_value.raw();
|
| + }
|
| + {
|
| + SafepointMutexLocker ml(isolate->constant_canonicalization_mutex());
|
| + // Retry lookup.
|
| + {
|
| + canonical_value ^= cls.LookupCanonicalFraction(zone, value, &index);
|
| + if (!canonical_value.IsNull()) {
|
| + return canonical_value.raw();
|
| + }
|
| + }
|
| + Fraction& result = Fraction::Handle(zone, value.raw());
|
| + if (result.IsNew()) {
|
| + // Create a canonical object in old space.
|
| + result ^= Object::Clone(result, Heap::kOld);
|
| + }
|
| + ASSERT(result.IsOld());
|
| + result.SetCanonical();
|
| + // The value needs to be added to the constants list. Grow the list if
|
| + // it is full.
|
| + cls.InsertCanonicalNumber(zone, index, result);
|
| + return result.raw();
|
| + }
|
| +}
|
| +
|
| +
|
| +void Fraction::set_denominator(const Integer& value) const {
|
| + StorePointer(&raw_ptr()->denominator_, value.raw());
|
| +}
|
| +
|
| +
|
| +const char* Fraction::ToCString() const {
|
| + if (IsNull()) {
|
| + return "_Fraction NULL";
|
| + }
|
| + return OS::SCreate(Thread::Current()->zone(), "_Fraction %s/%s",
|
| + Integer::Handle(numerator()).ToCString(),
|
| + Integer::Handle(denominator()).ToCString());
|
| +}
|
| +
|
| +
|
| // Synchronize with implementation in compiler (intrinsifier).
|
| class StringHasher : ValueObject {
|
| public:
|
|
|