Index: runtime/lib/double.cc |
=================================================================== |
--- runtime/lib/double.cc (revision 40060) |
+++ runtime/lib/double.cc (working copy) |
@@ -6,9 +6,10 @@ |
#include "platform/math.h" |
-#include "vm/bigint_operations.h" |
#include "vm/code_generator.h" // DartModulo. |
+#include "vm/dart_entry.h" |
#include "vm/double_conversion.h" |
+#include "vm/double_internals.h" |
#include "vm/exceptions.h" |
#include "vm/native_entry.h" |
#include "vm/object.h" |
@@ -78,8 +79,63 @@ |
args.SetAt(0, String::Handle(String::New(error_msg))); |
Exceptions::ThrowByType(Exceptions::kUnsupported, args); |
} |
- const Bigint& big = Bigint::Handle(BigintOperations::NewFromDouble(val)); |
- return big.AsValidInteger(); |
+ // TODO(regis): Should we implement Bigint::NewFromDouble instead? |
+ if ((-1.0 < val) && (val < 1.0)) { |
+ return Smi::New(0); |
+ } |
+ DoubleInternals internals = DoubleInternals(val); |
+ if (internals.IsSpecial()) { |
+ const Array& exception_arguments = Array::Handle(Array::New(1)); |
+ exception_arguments.SetAt( |
+ 0, Object::Handle(String::New("BigintOperations::NewFromDouble"))); |
+ Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); |
+ } |
+ uint64_t significand = internals.Significand(); |
+ intptr_t exponent = internals.Exponent(); |
+ intptr_t sign = internals.Sign(); |
+ if (exponent <= 0) { |
+ significand >>= -exponent; |
+ exponent = 0; |
+ } else if (exponent <= 10) { |
+ // A double significand has at most 53 bits. The following shift will |
+ // hence not overflow, and yield an integer of at most 63 bits. |
+ significand <<= exponent; |
+ exponent = 0; |
+ } |
+ // A significand has at most 63 bits (after the shift above). |
+ // The cast to int64_t is hence safe. |
+ if (exponent == 0) { |
+ // The double fits in a Smi or Mint. |
+ int64_t ival = static_cast<int64_t>(significand); |
+ if (sign < 0) { |
+ ival = -ival; |
+ } |
+ return Integer::New(ival); |
+ } |
+ // Lookup the factory creating a Bigint from a double. |
+ const Class& bigint_class = |
+ Class::Handle(Library::LookupCoreClass(Symbols::_Bigint())); |
+ ASSERT(!bigint_class.IsNull()); |
+ const Function& factory_method = Function::Handle( |
+ bigint_class.LookupFactoryAllowPrivate( |
+ Symbols::_BigintFromDoubleFactory())); |
+ ASSERT(!factory_method.IsNull()); |
+ |
+ // Create the argument list. |
+ const intptr_t kNumArgs = 4; |
+ const Array& args = Array::Handle(Array::New(kNumArgs)); |
+ // Factories get type arguments. |
+ args.SetAt(0, Object::null_type_arguments()); |
+ args.SetAt(1, Smi::Handle(Smi::New(sign))); |
+ args.SetAt(2, |
+ Integer::Handle(Integer::New(static_cast<int64_t>(significand)))); |
+ args.SetAt(3, Integer::Handle(Integer::New(exponent))); |
+ |
+ // Invoke the constructor and return the new object. |
+ Integer& result = Integer::Handle(); |
+ result ^= DartEntry::InvokeFunction(factory_method, args); |
+ ASSERT(result.IsBigint()); |
+ return result.AsValidInteger(); |
} |