Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(865)

Unified Diff: runtime/vm/object.cc

Issue 2005723004: Fraction class prototype and test (not to be committed). (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: work in progress Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/object.h ('k') | runtime/vm/object_service.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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:
« no previous file with comments | « runtime/vm/object.h ('k') | runtime/vm/object_service.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698