Push version 2.5.6 to trunk.

Added support for VFP rounding modes to the ARM simulator.

Fixed multiplication overflow bug (issue 927).

Added a limit for the amount of executable memory (issue 925).


git-svn-id: http://v8.googlecode.com/svn/trunk@5804 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/AUTHORS b/AUTHORS
index 3749ceb..68f9b63 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -9,6 +9,7 @@
 Hewlett-Packard Development Company, LP
 
 Alexander Botero-Lowry <alexbl@FreeBSD.org>
+Alexandre Rames <alexandre.rames@arm.com>
 Alexandre Vassalotti <avassalotti@gmail.com>
 Andreas Anyuru <andreas.anyuru@gmail.com>
 Burcu Dogan <burcujdogan@gmail.com>
diff --git a/ChangeLog b/ChangeLog
index ea07009..573ebb3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2010-11-10: Version 2.5.6
+
+        Added support for VFP rounding modes to the ARM simulator.
+
+        Fixed multiplication overflow bug (issue 927).
+
+        Added a limit for the amount of executable memory (issue 925).
+
+
 2010-11-08: Version 2.5.5
 
         Added more aggressive GC of external objects in near out-of-memory
diff --git a/include/v8.h b/include/v8.h
index 8c730df..f6c3c8b 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -2348,12 +2348,15 @@
   void set_max_young_space_size(int value) { max_young_space_size_ = value; }
   int max_old_space_size() const { return max_old_space_size_; }
   void set_max_old_space_size(int value) { max_old_space_size_ = value; }
+  int max_executable_size() { return max_executable_size_; }
+  void set_max_executable_size(int value) { max_executable_size_ = value; }
   uint32_t* stack_limit() const { return stack_limit_; }
   // Sets an address beyond which the VM's stack may not grow.
   void set_stack_limit(uint32_t* value) { stack_limit_ = value; }
  private:
   int max_young_space_size_;
   int max_old_space_size_;
+  int max_executable_size_;
   uint32_t* stack_limit_;
 };
 
@@ -2485,13 +2488,18 @@
  public:
   HeapStatistics();
   size_t total_heap_size() { return total_heap_size_; }
+  size_t total_heap_size_executable() { return total_heap_size_executable_; }
   size_t used_heap_size() { return used_heap_size_; }
 
  private:
   void set_total_heap_size(size_t size) { total_heap_size_ = size; }
+  void set_total_heap_size_executable(size_t size) {
+    total_heap_size_executable_ = size;
+  }
   void set_used_heap_size(size_t size) { used_heap_size_ = size; }
 
   size_t total_heap_size_;
+  size_t total_heap_size_executable_;
   size_t used_heap_size_;
 
   friend class V8;
diff --git a/src/SConscript b/src/SConscript
index 596caf7..030c643 100755
--- a/src/SConscript
+++ b/src/SConscript
@@ -40,6 +40,7 @@
     api.cc
     assembler.cc
     ast.cc
+    bignum.cc
     bootstrapper.cc
     builtins.cc
     cached-powers.cc
diff --git a/src/api.cc b/src/api.cc
index ee7ad3a..9da3346 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -393,14 +393,18 @@
 ResourceConstraints::ResourceConstraints()
   : max_young_space_size_(0),
     max_old_space_size_(0),
+    max_executable_size_(0),
     stack_limit_(NULL) { }
 
 
 bool SetResourceConstraints(ResourceConstraints* constraints) {
   int young_space_size = constraints->max_young_space_size();
   int old_gen_size = constraints->max_old_space_size();
-  if (young_space_size != 0 || old_gen_size != 0) {
-    bool result = i::Heap::ConfigureHeap(young_space_size / 2, old_gen_size);
+  int max_executable_size = constraints->max_executable_size();
+  if (young_space_size != 0 || old_gen_size != 0 || max_executable_size != 0) {
+    bool result = i::Heap::ConfigureHeap(young_space_size / 2,
+                                         old_gen_size,
+                                         max_executable_size);
     if (!result) return false;
   }
   if (constraints->stack_limit() != NULL) {
@@ -3259,11 +3263,15 @@
 }
 
 
-HeapStatistics::HeapStatistics(): total_heap_size_(0), used_heap_size_(0) { }
+HeapStatistics::HeapStatistics(): total_heap_size_(0),
+                                  total_heap_size_executable_(0),
+                                  used_heap_size_(0) { }
 
 
 void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) {
   heap_statistics->set_total_heap_size(i::Heap::CommittedMemory());
+  heap_statistics->set_total_heap_size_executable(
+      i::Heap::CommittedMemoryExecutable());
   heap_statistics->set_used_heap_size(i::Heap::SizeOfObjects());
 }
 
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index 72835ba..4cb421c 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -2144,6 +2144,7 @@
                         const int dst_code,
                         const VFPType src_type,
                         const int src_code,
+                        Assembler::ConversionMode mode,
                         const Condition cond) {
   ASSERT(src_type != dst_type);
   int D, Vd, M, Vm;
@@ -2162,7 +2163,7 @@
     if (IsIntegerVFPType(dst_type)) {
       opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4;
       sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
-      op = 1;  // round towards zero
+      op = mode;
     } else {
       ASSERT(IsIntegerVFPType(src_type));
       opc2 = 0x0;
@@ -2186,57 +2187,64 @@
 
 void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
                              const SwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(F64, dst.code(), S32, src.code(), cond));
+  emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
 }
 
 
 void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
                              const SwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(F32, dst.code(), S32, src.code(), cond));
+  emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
 }
 
 
 void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
                              const SwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(F64, dst.code(), U32, src.code(), cond));
+  emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
 }
 
 
 void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
                              const DwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(S32, dst.code(), F64, src.code(), cond));
+  emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
 }
 
 
 void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
                              const DwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(U32, dst.code(), F64, src.code(), cond));
+  emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
 }
 
 
 void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
                              const SwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(F64, dst.code(), F32, src.code(), cond));
+  emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
 }
 
 
 void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
                              const DwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(F32, dst.code(), F64, src.code(), cond));
+  emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
 }
 
 
@@ -2329,6 +2337,16 @@
 }
 
 
+void Assembler::vmsr(Register dst, Condition cond) {
+  // Instruction details available in ARM DDI 0406A, A8-652.
+  // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
+  // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
+  ASSERT(CpuFeatures::IsEnabled(VFP3));
+  emit(cond | 0xE*B24 | 0xE*B20 |  B16 |
+       dst.code()*B12 | 0xA*B8 | B4);
+}
+
+
 void Assembler::vmrs(Register dst, Condition cond) {
   // Instruction details available in ARM DDI 0406A, A8-652.
   // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
@@ -2339,7 +2357,6 @@
 }
 
 
-
 void Assembler::vsqrt(const DwVfpRegister dst,
                       const DwVfpRegister src,
                       const Condition cond) {
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index 0579235..de3931c 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -1008,26 +1008,37 @@
   void vmov(const Register dst,
             const SwVfpRegister src,
             const Condition cond = al);
+  enum ConversionMode {
+    FPSCRRounding = 0,
+    RoundToZero = 1
+  };
   void vcvt_f64_s32(const DwVfpRegister dst,
                     const SwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_f32_s32(const SwVfpRegister dst,
                     const SwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_f64_u32(const DwVfpRegister dst,
                     const SwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_s32_f64(const SwVfpRegister dst,
                     const DwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_u32_f64(const SwVfpRegister dst,
                     const DwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_f64_f32(const DwVfpRegister dst,
                     const SwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_f32_f64(const SwVfpRegister dst,
                     const DwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
 
   void vadd(const DwVfpRegister dst,
@@ -1056,6 +1067,8 @@
             const Condition cond = al);
   void vmrs(const Register dst,
             const Condition cond = al);
+  void vmsr(const Register dst,
+            const Condition cond = al);
   void vsqrt(const DwVfpRegister dst,
              const DwVfpRegister src,
              const Condition cond = al);
diff --git a/src/arm/constants-arm.h b/src/arm/constants-arm.h
index 123c5e7..36f6283 100644
--- a/src/arm/constants-arm.h
+++ b/src/arm/constants-arm.h
@@ -206,6 +206,13 @@
   kDoublePrecision = 1
 };
 
+// VFP rounding modes. See ARM DDI 0406B Page A2-29.
+enum FPSCRRoundingModes {
+  RN,   // Round to Nearest.
+  RP,   // Round towards Plus Infinity.
+  RM,   // Round towards Minus Infinity.
+  RZ    // Round towards zero.
+};
 
 typedef int32_t instr_t;
 
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index a09afdf..4c1f983 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -1988,9 +1988,9 @@
 
       // Not infinity or NaN simply convert to int.
       if (IsElementTypeSigned(array_type)) {
-        __ vcvt_s32_f64(s0, d0, ne);
+        __ vcvt_s32_f64(s0, d0, Assembler::RoundToZero, ne);
       } else {
-        __ vcvt_u32_f64(s0, d0, ne);
+        __ vcvt_u32_f64(s0, d0, Assembler::RoundToZero, ne);
       }
       __ vmov(r5, s0, ne);
 
diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
index cb91520..3ec5f44 100644
--- a/src/arm/simulator-arm.cc
+++ b/src/arm/simulator-arm.cc
@@ -705,6 +705,7 @@
   z_flag_FPSCR_ = false;
   c_flag_FPSCR_ = false;
   v_flag_FPSCR_ = false;
+  FPSCR_rounding_mode_ = RZ;
 
   inv_op_vfp_flag_ = false;
   div_zero_vfp_flag_ = false;
@@ -2501,10 +2502,45 @@
                (instr->VAField() == 0x7) &&
                (instr->Bits(19, 16) == 0x1)) {
       // vmrs
-      if (instr->RtField() == 0xF)
+      uint32_t rt = instr->RtField();
+      if (rt == 0xF) {
         Copy_FPSCR_to_APSR();
-      else
-        UNIMPLEMENTED();  // Not used by V8.
+      } else {
+        // Emulate FPSCR from the Simulator flags.
+        uint32_t fpscr = (n_flag_FPSCR_ << 31) |
+                         (z_flag_FPSCR_ << 30) |
+                         (c_flag_FPSCR_ << 29) |
+                         (v_flag_FPSCR_ << 28) |
+                         (inexact_vfp_flag_ << 4) |
+                         (underflow_vfp_flag_ << 3) |
+                         (overflow_vfp_flag_ << 2) |
+                         (div_zero_vfp_flag_ << 1) |
+                         (inv_op_vfp_flag_ << 0) |
+                         (FPSCR_rounding_mode_ << 22);
+        set_register(rt, fpscr);
+      }
+    } else if ((instr->VLField() == 0x0) &&
+               (instr->VCField() == 0x0) &&
+               (instr->VAField() == 0x7) &&
+               (instr->Bits(19, 16) == 0x1)) {
+      // vmsr
+      uint32_t rt = instr->RtField();
+      if (rt == pc) {
+        UNREACHABLE();
+      } else {
+        uint32_t rt_value = get_register(rt);
+        n_flag_FPSCR_ = (rt_value >> 31) & 1;
+        z_flag_FPSCR_ = (rt_value >> 30) & 1;
+        c_flag_FPSCR_ = (rt_value >> 29) & 1;
+        v_flag_FPSCR_ = (rt_value >> 28) & 1;
+        inexact_vfp_flag_ = (rt_value >> 4) & 1;
+        underflow_vfp_flag_ = (rt_value >> 3) & 1;
+        overflow_vfp_flag_ = (rt_value >> 2) & 1;
+        div_zero_vfp_flag_ = (rt_value >> 1) & 1;
+        inv_op_vfp_flag_ = (rt_value >> 0) & 1;
+        FPSCR_rounding_mode_ =
+          static_cast<FPSCRRoundingModes>((rt_value >> 22) & 3);
+      }
     } else {
       UNIMPLEMENTED();  // Not used by V8.
     }
@@ -2605,29 +2641,71 @@
 
   if (to_integer) {
     bool unsigned_integer = (instr->Bit(16) == 0);
+    FPSCRRoundingModes mode;
     if (instr->Bit(7) != 1) {
-      // Only rounding towards zero supported.
-      UNIMPLEMENTED();  // Not used by V8.
+      // Use FPSCR defined rounding mode.
+      mode = FPSCR_rounding_mode_;
+      // Only RZ and RM modes are supported.
+      ASSERT((mode == RM) || (mode == RZ));
+    } else {
+      // VFP uses round towards zero by default.
+      mode = RZ;
     }
 
     int dst = instr->VFPDRegCode(kSinglePrecision);
     int src = instr->VFPMRegCode(src_precision);
+    int32_t kMaxInt = v8::internal::kMaxInt;
+    int32_t kMinInt = v8::internal::kMinInt;
+    switch (mode) {
+      case RM:
+        if (src_precision == kDoublePrecision) {
+          double val = get_double_from_d_register(src);
 
-    if (src_precision == kDoublePrecision) {
-      double val = get_double_from_d_register(src);
+          inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
 
-      int sint = unsigned_integer ? static_cast<uint32_t>(val) :
-                                    static_cast<int32_t>(val);
+          int sint = unsigned_integer ? static_cast<uint32_t>(val) :
+                                        static_cast<int32_t>(val);
+          sint = sint > val ? sint - 1 : sint;
 
-      set_s_register_from_sinteger(dst, sint);
-    } else {
-      float val = get_float_from_s_register(src);
+          set_s_register_from_sinteger(dst, sint);
+        } else {
+          float val = get_float_from_s_register(src);
 
-      int sint = unsigned_integer ? static_cast<uint32_t>(val) :
-                                      static_cast<int32_t>(val);
+          inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
 
-      set_s_register_from_sinteger(dst, sint);
+          int sint = unsigned_integer ? static_cast<uint32_t>(val) :
+                                        static_cast<int32_t>(val);
+          sint = sint > val ? sint - 1 : sint;
+
+          set_s_register_from_sinteger(dst, sint);
+        }
+        break;
+      case RZ:
+        if (src_precision == kDoublePrecision) {
+          double val = get_double_from_d_register(src);
+
+          inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
+
+          int sint = unsigned_integer ? static_cast<uint32_t>(val) :
+                                        static_cast<int32_t>(val);
+
+          set_s_register_from_sinteger(dst, sint);
+        } else {
+          float val = get_float_from_s_register(src);
+
+          inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
+
+          int sint = unsigned_integer ? static_cast<uint32_t>(val) :
+                                        static_cast<int32_t>(val);
+
+          set_s_register_from_sinteger(dst, sint);
+        }
+        break;
+
+      default:
+        UNREACHABLE();
     }
+
   } else {
     bool unsigned_integer = (instr->Bit(7) == 0);
 
diff --git a/src/arm/simulator-arm.h b/src/arm/simulator-arm.h
index 3e02348..c37b3f7 100644
--- a/src/arm/simulator-arm.h
+++ b/src/arm/simulator-arm.h
@@ -306,6 +306,9 @@
   bool c_flag_FPSCR_;
   bool v_flag_FPSCR_;
 
+  // VFP rounding mode. See ARM DDI 0406B Page A2-29.
+  FPSCRRoundingModes FPSCR_rounding_mode_;
+
   // VFP FP exception flags architecture state.
   bool inv_op_vfp_flag_;
   bool div_zero_vfp_flag_;
diff --git a/src/bignum.cc b/src/bignum.cc
new file mode 100644
index 0000000..dd1537a
--- /dev/null
+++ b/src/bignum.cc
@@ -0,0 +1,767 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "bignum.h"
+#include "utils.h"
+
+namespace v8 {
+namespace internal {
+
+Bignum::Bignum()
+    : bigits_(bigits_buffer_, kBigitCapacity), used_digits_(0), exponent_(0) {
+  for (int i = 0; i < kBigitCapacity; ++i) {
+    bigits_[i] = 0;
+  }
+}
+
+
+template<typename S>
+static int BitSize(S value) {
+  return 8 * sizeof(value);
+}
+
+// Guaranteed to lie in one Bigit.
+void Bignum::AssignUInt16(uint16_t value) {
+  ASSERT(kBigitSize >= BitSize(value));
+  Zero();
+  if (value == 0) return;
+
+  EnsureCapacity(1);
+  bigits_[0] = value;
+  used_digits_ = 1;
+}
+
+
+void Bignum::AssignUInt64(uint64_t value) {
+  const int kUInt64Size = 64;
+
+  Zero();
+  if (value == 0) return;
+
+  int needed_bigits = kUInt64Size / kBigitSize + 1;
+  EnsureCapacity(needed_bigits);
+  for (int i = 0; i < needed_bigits; ++i) {
+    bigits_[i] = value & kBigitMask;
+    value = value >> kBigitSize;
+  }
+  used_digits_ = needed_bigits;
+  Clamp();
+}
+
+
+void Bignum::AssignBignum(const Bignum& other) {
+  exponent_ = other.exponent_;
+  for (int i = 0; i < other.used_digits_; ++i) {
+    bigits_[i] = other.bigits_[i];
+  }
+  // Clear the excess digits (if there were any).
+  for (int i = other.used_digits_; i < used_digits_; ++i) {
+    bigits_[i] = 0;
+  }
+  used_digits_ = other.used_digits_;
+}
+
+
+static uint64_t ReadUInt64(Vector<const char> buffer,
+                           int from,
+                           int digits_to_read) {
+  uint64_t result = 0;
+  for (int i = from; i < from + digits_to_read; ++i) {
+    int digit = buffer[i] - '0';
+    ASSERT(0 <= digit && digit <= 9);
+    result = result * 10 + digit;
+  }
+  return result;
+}
+
+
+void Bignum::AssignDecimalString(Vector<const char> value) {
+  // 2^64 = 18446744073709551616 > 10^19
+  const int kMaxUint64DecimalDigits = 19;
+  Zero();
+  int length = value.length();
+  int pos = 0;
+  // Let's just say that each digit needs 4 bits.
+  while (length >= kMaxUint64DecimalDigits) {
+    uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits);
+    pos += kMaxUint64DecimalDigits;
+    length -= kMaxUint64DecimalDigits;
+    MultiplyByPowerOfTen(kMaxUint64DecimalDigits);
+    AddUInt64(digits);
+  }
+  uint64_t digits = ReadUInt64(value, pos, length);
+  MultiplyByPowerOfTen(length);
+  AddUInt64(digits);
+  Clamp();
+}
+
+
+static int HexCharValue(char c) {
+  if ('0' <= c && c <= '9') return c - '0';
+  if ('a' <= c && c <= 'f') return 10 + c - 'a';
+  if ('A' <= c && c <= 'F') return 10 + c - 'A';
+  UNREACHABLE();
+  return 0;  // To make compiler happy.
+}
+
+
+void Bignum::AssignHexString(Vector<const char> value) {
+  Zero();
+  int length = value.length();
+
+  int needed_bigits = length * 4 / kBigitSize + 1;
+  EnsureCapacity(needed_bigits);
+  int string_index = length - 1;
+  for (int i = 0; i < needed_bigits - 1; ++i) {
+    // These bigits are guaranteed to be "full".
+    Chunk current_bigit = 0;
+    for (int j = 0; j < kBigitSize / 4; j++) {
+      current_bigit += HexCharValue(value[string_index--]) << (j * 4);
+    }
+    bigits_[i] = current_bigit;
+  }
+  used_digits_ = needed_bigits - 1;
+
+  Chunk most_significant_bigit = 0;  // Could be = 0;
+  for (int j = 0; j <= string_index; ++j) {
+    most_significant_bigit <<= 4;
+    most_significant_bigit += HexCharValue(value[j]);
+  }
+  if (most_significant_bigit != 0) {
+    bigits_[used_digits_] = most_significant_bigit;
+    used_digits_++;
+  }
+  Clamp();
+}
+
+
+void Bignum::AddUInt64(uint64_t operand) {
+  if (operand == 0) return;
+  Bignum other;
+  other.AssignUInt64(operand);
+  AddBignum(other);
+}
+
+
+void Bignum::AddBignum(const Bignum& other) {
+  ASSERT(IsClamped());
+  ASSERT(other.IsClamped());
+
+  // If this has a greater exponent than other append zero-bigits to this.
+  // After this call exponent_ <= other.exponent_.
+  Align(other);
+
+  // There are two possibilities:
+  //   aaaaaaaaaaa 0000  (where the 0s represent a's exponent)
+  //     bbbbb 00000000
+  //   ----------------
+  //   ccccccccccc 0000
+  // or
+  //    aaaaaaaaaa 0000
+  //  bbbbbbbbb 0000000
+  //  -----------------
+  //  cccccccccccc 0000
+  // In both cases we might need a carry bigit.
+
+  EnsureCapacity(1 + Max(BigitLength(), other.BigitLength()) - exponent_);
+  Chunk carry = 0;
+  int bigit_pos = other.exponent_ - exponent_;
+  ASSERT(bigit_pos >= 0);
+  for (int i = 0; i < other.used_digits_; ++i) {
+    Chunk sum = bigits_[bigit_pos] + other.bigits_[i] + carry;
+    bigits_[bigit_pos] = sum & kBigitMask;
+    carry = sum >> kBigitSize;
+    bigit_pos++;
+  }
+
+  while (carry != 0) {
+    Chunk sum = bigits_[bigit_pos] + carry;
+    bigits_[bigit_pos] = sum & kBigitMask;
+    carry = sum >> kBigitSize;
+    bigit_pos++;
+  }
+  used_digits_ = Max(bigit_pos, used_digits_);
+  ASSERT(IsClamped());
+}
+
+
+void Bignum::SubtractBignum(const Bignum& other) {
+  ASSERT(IsClamped());
+  ASSERT(other.IsClamped());
+  // We require this to be bigger than other.
+  ASSERT(LessEqual(other, *this));
+
+  Align(other);
+
+  int offset = other.exponent_ - exponent_;
+  Chunk borrow = 0;
+  int i;
+  for (i = 0; i < other.used_digits_; ++i) {
+    ASSERT((borrow == 0) || (borrow == 1));
+    Chunk difference = bigits_[i + offset] - other.bigits_[i] - borrow;
+    bigits_[i + offset] = difference & kBigitMask;
+    borrow = difference >> (kChunkSize - 1);
+  }
+  while (borrow != 0) {
+    Chunk difference = bigits_[i + offset] - borrow;
+    bigits_[i + offset] = difference & kBigitMask;
+    borrow = difference >> (kChunkSize - 1);
+    ++i;
+  }
+  Clamp();
+}
+
+
+void Bignum::ShiftLeft(int shift_amount) {
+  if (used_digits_ == 0) return;
+  exponent_ += shift_amount / kBigitSize;
+  int local_shift = shift_amount % kBigitSize;
+  EnsureCapacity(used_digits_ + 1);
+  BigitsShiftLeft(local_shift);
+}
+
+
+void Bignum::MultiplyByUInt32(uint32_t factor) {
+  if (factor == 1) return;
+  if (factor == 0) {
+    Zero();
+    return;
+  }
+  if (used_digits_ == 0) return;
+
+  // The product of a bigit with the factor is of size kBigitSize + 32.
+  // Assert that this number + 1 (for the carry) fits into double chunk.
+  ASSERT(kDoubleChunkSize >= kBigitSize + 32 + 1);
+  DoubleChunk carry = 0;
+  for (int i = 0; i < used_digits_; ++i) {
+    DoubleChunk product = static_cast<DoubleChunk>(factor) * bigits_[i] + carry;
+    bigits_[i] = static_cast<Chunk>(product & kBigitMask);
+    carry = (product >> kBigitSize);
+  }
+  while (carry != 0) {
+    EnsureCapacity(used_digits_ + 1);
+    bigits_[used_digits_] = carry & kBigitMask;
+    used_digits_++;
+    carry >>= kBigitSize;
+  }
+}
+
+
+void Bignum::MultiplyByUInt64(uint64_t factor) {
+  if (factor == 1) return;
+  if (factor == 0) {
+    Zero();
+    return;
+  }
+  ASSERT(kBigitSize < 32);
+  uint64_t carry = 0;
+  uint64_t low = factor & 0xFFFFFFFF;
+  uint64_t high = factor >> 32;
+  for (int i = 0; i < used_digits_; ++i) {
+    uint64_t product_low = low * bigits_[i];
+    uint64_t product_high = high * bigits_[i];
+    uint64_t tmp = (carry & kBigitMask) + product_low;
+    bigits_[i] = tmp & kBigitMask;
+    carry = (carry >> kBigitSize) + (tmp >> kBigitSize) +
+        (product_high << (32 - kBigitSize));
+  }
+  while (carry != 0) {
+    EnsureCapacity(used_digits_ + 1);
+    bigits_[used_digits_] = carry & kBigitMask;
+    used_digits_++;
+    carry >>= kBigitSize;
+  }
+}
+
+
+void Bignum::MultiplyByPowerOfTen(int exponent) {
+  const uint64_t kFive27 = V8_2PART_UINT64_C(0x6765c793, fa10079d);
+  const uint16_t kFive1 = 5;
+  const uint16_t kFive2 = kFive1 * 5;
+  const uint16_t kFive3 = kFive2 * 5;
+  const uint16_t kFive4 = kFive3 * 5;
+  const uint16_t kFive5 = kFive4 * 5;
+  const uint16_t kFive6 = kFive5 * 5;
+  const uint32_t kFive7 = kFive6 * 5;
+  const uint32_t kFive8 = kFive7 * 5;
+  const uint32_t kFive9 = kFive8 * 5;
+  const uint32_t kFive10 = kFive9 * 5;
+  const uint32_t kFive11 = kFive10 * 5;
+  const uint32_t kFive12 = kFive11 * 5;
+  const uint32_t kFive13 = kFive12 * 5;
+  const uint32_t kFive1_to_12[] =
+      { kFive1, kFive2, kFive3, kFive4, kFive5, kFive6,
+        kFive7, kFive8, kFive9, kFive10, kFive11, kFive12 };
+
+  ASSERT(exponent >= 0);
+  if (exponent == 0) return;
+  if (used_digits_ == 0) return;
+
+  // We shift by exponent at the end just before returning.
+  int remaining_exponent = exponent;
+  while (remaining_exponent >= 27) {
+    MultiplyByUInt64(kFive27);
+    remaining_exponent -= 27;
+  }
+  while (remaining_exponent >= 13) {
+    MultiplyByUInt32(kFive13);
+    remaining_exponent -= 13;
+  }
+  if (remaining_exponent > 0) {
+    MultiplyByUInt32(kFive1_to_12[remaining_exponent - 1]);
+  }
+  ShiftLeft(exponent);
+}
+
+
+void Bignum::Square() {
+  ASSERT(IsClamped());
+  int product_length = 2 * used_digits_;
+  EnsureCapacity(product_length);
+
+  // Comba multiplication: compute each column separately.
+  // Example: r = a2a1a0 * b2b1b0.
+  //    r =  1    * a0b0 +
+  //        10    * (a1b0 + a0b1) +
+  //        100   * (a2b0 + a1b1 + a0b2) +
+  //        1000  * (a2b1 + a1b2) +
+  //        10000 * a2b2
+  //
+  // In the worst case we have to accumulate nb-digits products of digit*digit.
+  //
+  // Assert that the additional number of bits in a DoubleChunk are enough to
+  // sum up used_digits of Bigit*Bigit.
+  if ((1 << (2 * (kChunkSize - kBigitSize))) <= used_digits_) {
+    UNIMPLEMENTED();
+  }
+  DoubleChunk accumulator = 0;
+  // First shift the digits so we don't overwrite them.
+  int copy_offset = used_digits_;
+  for (int i = 0; i < used_digits_; ++i) {
+    bigits_[copy_offset + i] = bigits_[i];
+  }
+  // We have two loops to avoid some 'if's in the loop.
+  for (int i = 0; i < used_digits_; ++i) {
+    // Process temporary digit i with power i.
+    // The sum of the two indices must be equal to i.
+    int bigit_index1 = i;
+    int bigit_index2 = 0;
+    // Sum all of the sub-products.
+    while (bigit_index1 >= 0) {
+      Chunk chunk1 = bigits_[copy_offset + bigit_index1];
+      Chunk chunk2 = bigits_[copy_offset + bigit_index2];
+      accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
+      bigit_index1--;
+      bigit_index2++;
+    }
+    bigits_[i] = static_cast<Chunk>(accumulator) & kBigitMask;
+    accumulator >>= kBigitSize;
+  }
+  for (int i = used_digits_; i < product_length; ++i) {
+    int bigit_index1 = used_digits_ - 1;
+    int bigit_index2 = i - bigit_index1;
+    // Invariant: sum of both indices is again equal to i.
+    // Inner loop runs 0 times on last iteration, emptying accumulator.
+    while (bigit_index2 < used_digits_) {
+      Chunk chunk1 = bigits_[copy_offset + bigit_index1];
+      Chunk chunk2 = bigits_[copy_offset + bigit_index2];
+      accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
+      bigit_index1--;
+      bigit_index2++;
+    }
+    // The overwritten bigits_[i] will never be read in further loop iterations,
+    // because bigit_index1 and bigit_index2 are always greater
+    // than i - used_digits_.
+    bigits_[i] = static_cast<Chunk>(accumulator) & kBigitMask;
+    accumulator >>= kBigitSize;
+  }
+  // Since the result was guaranteed to lie inside the number the
+  // accumulator must be 0 now.
+  ASSERT(accumulator == 0);
+
+  // Don't forget to update the used_digits and the exponent.
+  used_digits_ = product_length;
+  exponent_ *= 2;
+  Clamp();
+}
+
+
+void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) {
+  ASSERT(base != 0);
+  ASSERT(power_exponent >= 0);
+  if (power_exponent == 0) {
+    AssignUInt16(1);
+    return;
+  }
+  Zero();
+  int shifts = 0;
+  // We expect base to be in range 2-32, and most often to be 10.
+  // It does not make much sense to implement different algorithms for counting
+  // the bits.
+  while ((base & 1) == 0) {
+    base >>= 1;
+    shifts++;
+  }
+  int bit_size = 0;
+  int tmp_base = base;
+  while (tmp_base != 0) {
+    tmp_base >>= 1;
+    bit_size++;
+  }
+  int final_size = bit_size * power_exponent;
+  // 1 extra bigit for the shifting, and one for rounded final_size.
+  EnsureCapacity(final_size / kBigitSize + 2);
+
+  // Left to Right exponentiation.
+  int mask = 1;
+  while (power_exponent >= mask) mask <<= 1;
+
+  // The mask is now pointing to the bit above the most significant 1-bit of
+  // power_exponent.
+  // Get rid of first 1-bit;
+  mask >>= 2;
+  uint64_t this_value = base;
+
+  bool delayed_multipliciation = false;
+  const uint64_t max_32bits = 0xFFFFFFFF;
+  while (mask != 0 && this_value <= max_32bits) {
+    this_value = this_value * this_value;
+    // Verify that there is enough space in this_value to perform the
+    // multiplication.  The first bit_size bits must be 0.
+    if ((power_exponent & mask) != 0) {
+      uint64_t base_bits_mask =
+          ~((static_cast<uint64_t>(1) << (64 - bit_size)) - 1);
+      bool high_bits_zero = (this_value & base_bits_mask) == 0;
+      if (high_bits_zero) {
+        this_value *= base;
+      } else {
+        delayed_multipliciation = true;
+      }
+    }
+    mask >>= 1;
+  }
+  AssignUInt64(this_value);
+  if (delayed_multipliciation) {
+    MultiplyByUInt32(base);
+  }
+
+  // Now do the same thing as a bignum.
+  while (mask != 0) {
+    Square();
+    if ((power_exponent & mask) != 0) {
+      MultiplyByUInt32(base);
+    }
+    mask >>= 1;
+  }
+
+  // And finally add the saved shifts.
+  ShiftLeft(shifts * power_exponent);
+}
+
+
+// Precondition: this/other < 16bit.
+uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) {
+  ASSERT(IsClamped());
+  ASSERT(other.IsClamped());
+  ASSERT(other.used_digits_ > 0);
+
+  // Easy case: if we have less digits than the divisor than the result is 0.
+  // Note: this handles the case where this == 0, too.
+  if (BigitLength() < other.BigitLength()) {
+    return 0;
+  }
+
+  Align(other);
+
+  uint16_t result = 0;
+
+  // Start by removing multiples of 'other' until both numbers have the same
+  // number of digits.
+  while (BigitLength() > other.BigitLength()) {
+    // This naive approach is extremely inefficient if the this divided other
+    // might be big. This function is implemented for doubleToString where
+    // the result should be small (less than 10).
+    ASSERT(other.bigits_[other.used_digits_ - 1] >= ((1 << kBigitSize) / 16));
+    // Remove the multiples of the first digit.
+    // Example this = 23 and other equals 9. -> Remove 2 multiples.
+    result += bigits_[used_digits_ - 1];
+    SubtractTimes(other, bigits_[used_digits_ - 1]);
+  }
+
+  ASSERT(BigitLength() == other.BigitLength());
+
+  // Both bignums are at the same length now.
+  // Since other has more than 0 digits we know that the access to
+  // bigits_[used_digits_ - 1] is safe.
+  Chunk this_bigit = bigits_[used_digits_ - 1];
+  Chunk other_bigit = other.bigits_[other.used_digits_ - 1];
+
+  if (other.used_digits_ == 1) {
+    // Shortcut for easy (and common) case.
+    int quotient = this_bigit / other_bigit;
+    bigits_[used_digits_ - 1] = this_bigit - other_bigit * quotient;
+    result += quotient;
+    Clamp();
+    return result;
+  }
+
+  int division_estimate = this_bigit / (other_bigit + 1);
+  result += division_estimate;
+  SubtractTimes(other, division_estimate);
+
+  if (other_bigit * (division_estimate + 1) > this_bigit) {
+    // No need to even try to subtract. Even if other's remaining digits were 0
+    // another subtraction would be too much.
+    return result;
+  }
+
+  while (LessEqual(other, *this)) {
+    SubtractBignum(other);
+    result++;
+  }
+  return result;
+}
+
+
+template<typename S>
+static int SizeInHexChars(S number) {
+  ASSERT(number > 0);
+  int result = 0;
+  while (number != 0) {
+    number >>= 4;
+    result++;
+  }
+  return result;
+}
+
+
+static char HexCharOfValue(int value) {
+  ASSERT(0 <= value && value <= 16);
+  if (value < 10) return value + '0';
+  return value - 10 + 'A';
+}
+
+
+bool Bignum::ToHexString(char* buffer, int buffer_size) const {
+  ASSERT(IsClamped());
+  // Each bigit must be printable as separate hex-character.
+  ASSERT(kBigitSize % 4 == 0);
+  const int kHexCharsPerBigit = kBigitSize / 4;
+
+  if (used_digits_ == 0) {
+    if (buffer_size < 2) return false;
+    buffer[0] = '0';
+    buffer[1] = '\0';
+    return true;
+  }
+  // We add 1 for the terminating '\0' character.
+  int needed_chars = (BigitLength() - 1) * kHexCharsPerBigit +
+      SizeInHexChars(bigits_[used_digits_ - 1]) + 1;
+  if (needed_chars > buffer_size) return false;
+  int string_index = needed_chars - 1;
+  buffer[string_index--] = '\0';
+  for (int i = 0; i < exponent_; ++i) {
+    for (int j = 0; j < kHexCharsPerBigit; ++j) {
+      buffer[string_index--] = '0';
+    }
+  }
+  for (int i = 0; i < used_digits_ - 1; ++i) {
+    Chunk current_bigit = bigits_[i];
+    for (int j = 0; j < kHexCharsPerBigit; ++j) {
+      buffer[string_index--] = HexCharOfValue(current_bigit & 0xF);
+      current_bigit >>= 4;
+    }
+  }
+  // And finally the last bigit.
+  Chunk most_significant_bigit = bigits_[used_digits_ - 1];
+  while (most_significant_bigit != 0) {
+    buffer[string_index--] = HexCharOfValue(most_significant_bigit & 0xF);
+    most_significant_bigit >>= 4;
+  }
+  return true;
+}
+
+
+Bignum::Chunk Bignum::BigitAt(int index) const {
+  if (index >= BigitLength()) return 0;
+  if (index < exponent_) return 0;
+  return bigits_[index - exponent_];
+}
+
+
+int Bignum::Compare(const Bignum& a, const Bignum& b) {
+  ASSERT(a.IsClamped());
+  ASSERT(b.IsClamped());
+  int bigit_length_a = a.BigitLength();
+  int bigit_length_b = b.BigitLength();
+  if (bigit_length_a < bigit_length_b) return -1;
+  if (bigit_length_a > bigit_length_b) return +1;
+  for (int i = bigit_length_a - 1; i >= Min(a.exponent_, b.exponent_); --i) {
+    Chunk bigit_a = a.BigitAt(i);
+    Chunk bigit_b = b.BigitAt(i);
+    if (bigit_a < bigit_b) return -1;
+    if (bigit_a > bigit_b) return +1;
+    // Otherwise they are equal up to this digit. Try the next digit.
+  }
+  return 0;
+}
+
+
+int Bignum::PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c) {
+  ASSERT(a.IsClamped());
+  ASSERT(b.IsClamped());
+  ASSERT(c.IsClamped());
+  if (a.BigitLength() < b.BigitLength()) {
+    return PlusCompare(b, a, c);
+  }
+  if (a.BigitLength() + 1 < c.BigitLength()) return -1;
+  if (a.BigitLength() > c.BigitLength()) return +1;
+  // The exponent encodes 0-bigits. So if there are more 0-digits in 'a' than
+  // 'b' has digits, then the bigit-length of 'a'+'b' must be equal to the one
+  // of 'a'.
+  if (a.exponent_ >= b.BigitLength() && a.BigitLength() < c.BigitLength()) {
+    return -1;
+  }
+
+  Chunk borrow = 0;
+  // Starting at min_exponent all digits are == 0. So no need to compare them.
+  int min_exponent = Min(Min(a.exponent_, b.exponent_), c.exponent_);
+  for (int i = c.BigitLength() - 1; i >= min_exponent; --i) {
+    Chunk chunk_a = a.BigitAt(i);
+    Chunk chunk_b = b.BigitAt(i);
+    Chunk chunk_c = c.BigitAt(i);
+    Chunk sum = chunk_a + chunk_b;
+    if (sum > chunk_c + borrow) {
+      return +1;
+    } else {
+      borrow = chunk_c + borrow - sum;
+      if (borrow > 1) return -1;
+      borrow <<= kBigitSize;
+    }
+  }
+  if (borrow == 0) return 0;
+  return -1;
+}
+
+
+void Bignum::Clamp() {
+  while (used_digits_ > 0 && bigits_[used_digits_ - 1] == 0) {
+    used_digits_--;
+  }
+  if (used_digits_ == 0) {
+    // Zero.
+    exponent_ = 0;
+  }
+}
+
+
+bool Bignum::IsClamped() const {
+  return used_digits_ == 0 || bigits_[used_digits_ - 1] != 0;
+}
+
+
+void Bignum::Zero() {
+  for (int i = 0; i < used_digits_; ++i) {
+    bigits_[i] = 0;
+  }
+  used_digits_ = 0;
+  exponent_ = 0;
+}
+
+
+void Bignum::Align(const Bignum& other) {
+  if (exponent_ > other.exponent_) {
+    // If "X" represents a "hidden" digit (by the exponent) then we are in the
+    // following case (a == this, b == other):
+    // a:  aaaaaaXXXX   or a:   aaaaaXXX
+    // b:     bbbbbbX      b: bbbbbbbbXX
+    // We replace some of the hidden digits (X) of a with 0 digits.
+    // a:  aaaaaa000X   or a:   aaaaa0XX
+    int zero_digits = exponent_ - other.exponent_;
+    EnsureCapacity(used_digits_ + zero_digits);
+    for (int i = used_digits_ - 1; i >= 0; --i) {
+      bigits_[i + zero_digits] = bigits_[i];
+    }
+    for (int i = 0; i < zero_digits; ++i) {
+      bigits_[i] = 0;
+    }
+    used_digits_ += zero_digits;
+    exponent_ -= zero_digits;
+    ASSERT(used_digits_ >= 0);
+    ASSERT(exponent_ >= 0);
+  }
+}
+
+
+void Bignum::BigitsShiftLeft(int shift_amount) {
+  ASSERT(shift_amount < kBigitSize);
+  ASSERT(shift_amount >= 0);
+  Chunk carry = 0;
+  for (int i = 0; i < used_digits_; ++i) {
+    Chunk new_carry = bigits_[i] >> (kBigitSize - shift_amount);
+    bigits_[i] = ((bigits_[i] << shift_amount) + carry) & kBigitMask;
+    carry = new_carry;
+  }
+  if (carry != 0) {
+    bigits_[used_digits_] = carry;
+    used_digits_++;
+  }
+}
+
+
+void Bignum::SubtractTimes(const Bignum& other, int factor) {
+  ASSERT(exponent_ <= other.exponent_);
+  if (factor < 3) {
+    for (int i = 0; i < factor; ++i) {
+      SubtractBignum(other);
+    }
+    return;
+  }
+  Chunk borrow = 0;
+  int exponent_diff = other.exponent_ - exponent_;
+  for (int i = 0; i < other.used_digits_; ++i) {
+    DoubleChunk product = static_cast<DoubleChunk>(factor) * other.bigits_[i];
+    DoubleChunk remove = borrow + product;
+    Chunk difference = bigits_[i + exponent_diff] - (remove & kBigitMask);
+    bigits_[i + exponent_diff] = difference & kBigitMask;
+    borrow = static_cast<Chunk>((difference >> (kChunkSize - 1)) +
+                                (remove >> kBigitSize));
+  }
+  for (int i = other.used_digits_ + exponent_diff; i < used_digits_; ++i) {
+    if (borrow == 0) return;
+    Chunk difference = bigits_[i] - borrow;
+    bigits_[i] = difference & kBigitMask;
+    borrow = difference >> (kChunkSize - 1);
+    ++i;
+  }
+  Clamp();
+}
+
+
+} }  // namespace v8::internal
diff --git a/src/bignum.h b/src/bignum.h
new file mode 100644
index 0000000..1d2bff6
--- /dev/null
+++ b/src/bignum.h
@@ -0,0 +1,140 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_BIGNUM_H_
+#define V8_BIGNUM_H_
+
+namespace v8 {
+namespace internal {
+
+class Bignum {
+ public:
+  // 3584 = 128 * 28. We can represent 2^3584 > 10^1000 accurately.
+  // This bignum can encode much bigger numbers, since it contains an
+  // exponent.
+  static const int kMaxSignificantBits = 3584;
+
+  Bignum();
+  void AssignUInt16(uint16_t value);
+  void AssignUInt64(uint64_t value);
+  void AssignBignum(const Bignum& other);
+
+  void AssignDecimalString(Vector<const char> value);
+  void AssignHexString(Vector<const char> value);
+
+  void AssignPowerUInt16(uint16_t base, int exponent);
+
+  void AddUInt16(uint16_t operand);
+  void AddUInt64(uint64_t operand);
+  void AddBignum(const Bignum& other);
+  // Precondition: this >= other.
+  void SubtractBignum(const Bignum& other);
+
+  void Square();
+  void ShiftLeft(int shift_amount);
+  void MultiplyByUInt32(uint32_t factor);
+  void MultiplyByUInt64(uint64_t factor);
+  void MultiplyByPowerOfTen(int exponent);
+  void Times10() { return MultiplyByUInt32(10); }
+  // Pseudocode:
+  //  int result = this / other;
+  //  this = this % other;
+  // In the worst case this function is in O(this/other).
+  uint16_t DivideModuloIntBignum(const Bignum& other);
+
+  bool ToHexString(char* buffer, int buffer_size) const;
+
+  static int Compare(const Bignum& a, const Bignum& b);
+  static bool Equal(const Bignum& a, const Bignum& b) {
+    return Compare(a, b) == 0;
+  }
+  static bool LessEqual(const Bignum& a, const Bignum& b) {
+    return Compare(a, b) <= 0;
+  }
+  static bool Less(const Bignum& a, const Bignum& b) {
+    return Compare(a, b) < 0;
+  }
+  // Returns Compare(a + b, c);
+  static int PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c);
+  // Returns a + b == c
+  static bool PlusEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
+    return PlusCompare(a, b, c) == 0;
+  }
+  // Returns a + b <= c
+  static bool PlusLessEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
+    return PlusCompare(a, b, c) <= 0;
+  }
+  // Returns a + b < c
+  static bool PlusLess(const Bignum& a, const Bignum& b, const Bignum& c) {
+    return PlusCompare(a, b, c) < 0;
+  }
+ private:
+  typedef uint32_t Chunk;
+  typedef uint64_t DoubleChunk;
+
+  static const int kChunkSize = sizeof(Chunk) * 8;
+  static const int kDoubleChunkSize = sizeof(DoubleChunk) * 8;
+  // With bigit size of 28 we loose some bits, but a double still fits easily
+  // into two chunks, and more importantly we can use the Comba multiplication.
+  static const int kBigitSize = 28;
+  static const Chunk kBigitMask = (1 << kBigitSize) - 1;
+  // Every instance allocates kBigitLength chunks on the stack. Bignums cannot
+  // grow. There are no checks if the stack-allocated space is sufficient.
+  static const int kBigitCapacity = kMaxSignificantBits / kBigitSize;
+
+  void EnsureCapacity(int size) {
+    if (size > kBigitCapacity) {
+      UNREACHABLE();
+    }
+  }
+  void Align(const Bignum& other);
+  void Clamp();
+  bool IsClamped() const;
+  void Zero();
+  // Requires this to have enough capacity (no tests done).
+  // Updates used_digits_ if necessary.
+  // by must be < kBigitSize.
+  void BigitsShiftLeft(int shift_amount);
+  // BigitLength includes the "hidden" digits encoded in the exponent.
+  int BigitLength() const { return used_digits_ + exponent_; }
+  Chunk BigitAt(int index) const;
+  void SubtractTimes(const Bignum& other, int factor);
+
+  Chunk bigits_buffer_[kBigitCapacity];
+  // A vector backed by bigits_buffer_. This way accesses to the array are
+  // checked for out-of-bounds errors.
+  Vector<Chunk> bigits_;
+  int used_digits_;
+  // The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize).
+  int exponent_;
+
+  DISALLOW_COPY_AND_ASSIGN(Bignum);
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_BIGNUM_H_
diff --git a/src/code-stubs.h b/src/code-stubs.h
index c0a8d30..ec64353 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -542,7 +542,7 @@
   ApiFunction* fun() { return fun_; }
   Major MajorKey() { return NoCache; }
   int MinorKey() { return 0; }
-  const char* GetName() { return "ApiEntryStub"; }
+  const char* GetName() { return "ApiGetterEntryStub"; }
   // The accessor info associated with the function.
   Handle<AccessorInfo> info_;
   // The function to be called.
@@ -550,6 +550,32 @@
 };
 
 
+class ApiCallEntryStub : public CodeStub {
+ public:
+  ApiCallEntryStub(Handle<CallHandlerInfo> info,
+                   ApiFunction* fun)
+      : info_(info),
+        fun_(fun) { }
+  void Generate(MacroAssembler* masm);
+  virtual bool has_custom_cache() { return true; }
+  virtual bool GetCustomCache(Code** code_out);
+  virtual void SetCustomCache(Code* value);
+
+  static const int kStackSpace = 0;
+  static const int kArgc = 5;
+ private:
+  Handle<CallHandlerInfo> info() { return info_; }
+  ApiFunction* fun() { return fun_; }
+  Major MajorKey() { return NoCache; }
+  int MinorKey() { return 0; }
+  const char* GetName() { return "ApiCallEntryStub"; }
+  // The call handler info associated with the function.
+  Handle<CallHandlerInfo> info_;
+  // The function to be called.
+  ApiFunction* fun_;
+};
+
+
 class JSEntryStub : public CodeStub {
  public:
   JSEntryStub() { }
diff --git a/src/codegen.cc b/src/codegen.cc
index 2e32418..e954dd6 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -482,8 +482,8 @@
 }
 
 
-bool ApiGetterEntryStub::GetCustomCache(Code** code_out) {
-  Object* cache = info()->load_stub_cache();
+// Implementation of CodeStub::GetCustomCache.
+static bool GetCustomCacheHelper(Object* cache, Code** code_out) {
   if (cache->IsUndefined()) {
     return false;
   } else {
@@ -493,9 +493,24 @@
 }
 
 
+bool ApiGetterEntryStub::GetCustomCache(Code** code_out) {
+  return GetCustomCacheHelper(info()->load_stub_cache(), code_out);
+}
+
+
 void ApiGetterEntryStub::SetCustomCache(Code* value) {
   info()->set_load_stub_cache(value);
 }
 
 
+bool ApiCallEntryStub::GetCustomCache(Code** code_out) {
+  return GetCustomCacheHelper(info()->call_stub_cache(), code_out);
+}
+
+
+void ApiCallEntryStub::SetCustomCache(Code* value) {
+  info()->set_call_stub_cache(value);
+}
+
+
 } }  // namespace v8::internal
diff --git a/src/double.h b/src/double.h
index e805173..65eded9 100644
--- a/src/double.h
+++ b/src/double.h
@@ -54,18 +54,20 @@
   explicit Double(DiyFp diy_fp)
     : d64_(DiyFpToUint64(diy_fp)) {}
 
+  // The value encoded by this Double must be greater or equal to +0.0.
+  // It must not be special (infinity, or NaN).
   DiyFp AsDiyFp() const {
+    ASSERT(Sign() > 0);
     ASSERT(!IsSpecial());
     return DiyFp(Significand(), Exponent());
   }
 
-  // this->Significand() must not be 0.
+  // The value encoded by this Double must be strictly greater than 0.
   DiyFp AsNormalizedDiyFp() const {
+    ASSERT(value() > 0.0);
     uint64_t f = Significand();
     int e = Exponent();
 
-    ASSERT(f != 0);
-
     // The current double could be a denormal.
     while ((f & kHiddenBit) == 0) {
       f <<= 1;
@@ -82,6 +84,20 @@
     return d64_;
   }
 
+  // Returns the next greater double. Returns +infinity on input +infinity.
+  double NextDouble() const {
+    if (d64_ == kInfinity) return Double(kInfinity).value();
+    if (Sign() < 0 && Significand() == 0) {
+      // -0.0
+      return 0.0;
+    }
+    if (Sign() < 0) {
+      return Double(d64_ - 1).value();
+    } else {
+      return Double(d64_ + 1).value();
+    }
+  }
+
   int Exponent() const {
     if (IsDenormal()) return kDenormalExponent;
 
@@ -120,24 +136,30 @@
         ((d64 & kSignificandMask) != 0);
   }
 
-
   bool IsInfinite() const {
     uint64_t d64 = AsUint64();
     return ((d64 & kExponentMask) == kExponentMask) &&
         ((d64 & kSignificandMask) == 0);
   }
 
-
   int Sign() const {
     uint64_t d64 = AsUint64();
     return (d64 & kSignMask) == 0? 1: -1;
   }
 
+  // Precondition: the value encoded by this Double must be greater or equal
+  // than +0.0.
+  DiyFp UpperBoundary() const {
+    ASSERT(Sign() > 0);
+    return DiyFp(Significand() * 2 + 1, Exponent() - 1);
+  }
 
   // Returns the two boundaries of this.
   // The bigger boundary (m_plus) is normalized. The lower boundary has the same
   // exponent as m_plus.
+  // Precondition: the value encoded by this Double must be greater than 0.
   void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
+    ASSERT(value() > 0.0);
     DiyFp v = this->AsDiyFp();
     bool significand_is_zero = (v.f() == kHiddenBit);
     DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 54501ec..46feea7 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -186,6 +186,7 @@
 // heap.cc
 DEFINE_int(max_new_space_size, 0, "max size of the new generation (in kBytes)")
 DEFINE_int(max_old_space_size, 0, "max size of the old generation (in Mbytes)")
+DEFINE_int(max_executable_size, 0, "max size of executable memory (in Mbytes)")
 DEFINE_bool(gc_global, false, "always perform global GCs")
 DEFINE_int(gc_interval, -1, "garbage collect after <n> allocations")
 DEFINE_bool(trace_gc, false,
diff --git a/src/heap.cc b/src/heap.cc
index 226a202..134f40e 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -83,16 +83,19 @@
 intptr_t Heap::max_old_generation_size_ = 192*MB;
 int Heap::initial_semispace_size_ = 128*KB;
 intptr_t Heap::code_range_size_ = 0;
+intptr_t Heap::max_executable_size_ = max_old_generation_size_;
 #elif defined(V8_TARGET_ARCH_X64)
 int Heap::max_semispace_size_  = 16*MB;
 intptr_t Heap::max_old_generation_size_ = 1*GB;
 int Heap::initial_semispace_size_ = 1*MB;
 intptr_t Heap::code_range_size_ = 512*MB;
+intptr_t Heap::max_executable_size_ = 256*MB;
 #else
 int Heap::max_semispace_size_  = 8*MB;
 intptr_t Heap::max_old_generation_size_ = 512*MB;
 int Heap::initial_semispace_size_ = 512*KB;
 intptr_t Heap::code_range_size_ = 0;
+intptr_t Heap::max_executable_size_ = 128*MB;
 #endif
 
 // The snapshot semispace size will be the default semispace size if
@@ -172,6 +175,12 @@
       lo_space_->Size();
 }
 
+intptr_t Heap::CommittedMemoryExecutable() {
+  if (!HasBeenSetup()) return 0;
+
+  return MemoryAllocator::SizeExecutable();
+}
+
 
 intptr_t Heap::Available() {
   if (!HasBeenSetup()) return 0;
@@ -4313,7 +4322,9 @@
 // TODO(1236194): Since the heap size is configurable on the command line
 // and through the API, we should gracefully handle the case that the heap
 // size is not big enough to fit all the initial objects.
-bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) {
+bool Heap::ConfigureHeap(int max_semispace_size,
+                         int max_old_gen_size,
+                         int max_executable_size) {
   if (HasBeenSetup()) return false;
 
   if (max_semispace_size > 0) max_semispace_size_ = max_semispace_size;
@@ -4334,6 +4345,15 @@
   }
 
   if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size;
+  if (max_executable_size > 0) {
+    max_executable_size_ = RoundUp(max_executable_size, Page::kPageSize);
+  }
+
+  // The max executable size must be less than or equal to the max old
+  // generation size.
+  if (max_executable_size_ > max_old_generation_size_) {
+    max_executable_size_ = max_old_generation_size_;
+  }
 
   // The new space size must be a power of two to support single-bit testing
   // for containment.
@@ -4351,8 +4371,9 @@
 
 
 bool Heap::ConfigureHeapDefault() {
-  return ConfigureHeap(
-      FLAG_max_new_space_size * (KB / 2), FLAG_max_old_space_size * MB);
+  return ConfigureHeap(FLAG_max_new_space_size / 2 * KB,
+                       FLAG_max_old_space_size * MB,
+                       FLAG_max_executable_size * MB);
 }
 
 
@@ -4435,7 +4456,7 @@
   // space.  The chunk is double the size of the requested reserved
   // new space size to ensure that we can find a pair of semispaces that
   // are contiguous and aligned to their size.
-  if (!MemoryAllocator::Setup(MaxReserved())) return false;
+  if (!MemoryAllocator::Setup(MaxReserved(), MaxExecutableSize())) return false;
   void* chunk =
       MemoryAllocator::ReserveInitialChunk(4 * reserved_semispace_size_);
   if (chunk == NULL) return false;
diff --git a/src/heap.h b/src/heap.h
index 714bf0d..c37ced3 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -222,7 +222,9 @@
  public:
   // Configure heap size before setup. Return false if the heap has been
   // setup already.
-  static bool ConfigureHeap(int max_semispace_size, int max_old_gen_size);
+  static bool ConfigureHeap(int max_semispace_size,
+                            int max_old_gen_size,
+                            int max_executable_size);
   static bool ConfigureHeapDefault();
 
   // Initializes the global object heap. If create_heap_objects is true,
@@ -253,6 +255,7 @@
   static int ReservedSemiSpaceSize() { return reserved_semispace_size_; }
   static int InitialSemiSpaceSize() { return initial_semispace_size_; }
   static intptr_t MaxOldGenerationSize() { return max_old_generation_size_; }
+  static intptr_t MaxExecutableSize() { return max_executable_size_; }
 
   // Returns the capacity of the heap in bytes w/o growing. Heap grows when
   // more spaces are needed until it reaches the limit.
@@ -261,6 +264,9 @@
   // Returns the amount of memory currently committed for the heap.
   static intptr_t CommittedMemory();
 
+  // Returns the amount of executable memory currently committed for the heap.
+  static intptr_t CommittedMemoryExecutable();
+
   // Returns the available bytes in space w/o growing.
   // Heap doesn't guarantee that it can allocate an object that requires
   // all available bytes. Check MaxHeapObjectSize() instead.
@@ -1096,6 +1102,7 @@
   static int max_semispace_size_;
   static int initial_semispace_size_;
   static intptr_t max_old_generation_size_;
+  static intptr_t max_executable_size_;
   static intptr_t code_range_size_;
 
   // For keeping track of how much data has survived
diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h
index 624be0c..79637a1 100644
--- a/src/ia32/assembler-ia32.h
+++ b/src/ia32/assembler-ia32.h
@@ -521,7 +521,6 @@
   void push(const Immediate& x);
   void push(Register src);
   void push(const Operand& src);
-  void push(Label* label, RelocInfo::Mode relocation_mode);
 
   void pop(Register dst);
   void pop(const Operand& dst);
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index b2b7392..a7d658b 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -3067,6 +3067,26 @@
 }
 
 
+void ApiCallEntryStub::Generate(MacroAssembler* masm) {
+  __ PrepareCallApiFunction(kStackSpace, kArgc);
+  STATIC_ASSERT(kArgc == 5);
+
+  // Allocate the v8::Arguments structure in the arguments' space since
+  // it's not controlled by GC.
+  __ mov(ApiParameterOperand(1), eax);  // v8::Arguments::implicit_args_.
+  __ mov(ApiParameterOperand(2), ebx);  // v8::Arguments::values_.
+  __ mov(ApiParameterOperand(3), edx);  // v8::Arguments::length_.
+  // v8::Arguments::is_construct_call_.
+  __ mov(ApiParameterOperand(4), Immediate(0));
+
+  // v8::InvocationCallback's argument.
+  __ lea(eax, ApiParameterOperand(1));
+  __ mov(ApiParameterOperand(0), eax);
+
+  __ CallApiFunctionAndReturn(fun(), kArgc);
+}
+
+
 void CEntryStub::GenerateCore(MacroAssembler* masm,
                               Label* throw_normal_exception,
                               Label* throw_termination_exception,
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index 7295340..6f4ef87 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -8578,9 +8578,11 @@
       }
       right.Unuse();
       frame_->Push(&left);
-      if (!node->to_int32()) {
-        // If ToInt32 is called on the result of ADD, SUB, or MUL, we don't
+      if (!node->to_int32() || op == Token::MUL) {
+        // If ToInt32 is called on the result of ADD, SUB, we don't
         // care about overflows.
+        // Result of MUL can be non-representable precisely in double so
+        // we have to check for overflow.
         unsafe_bailout_->Branch(overflow);
       }
       break;
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index 7b9b843..d65eebb 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -488,7 +488,7 @@
   // stored in ApiParameterOperand(0), ApiParameterOperand(1) etc.
   void PrepareCallApiFunction(int stack_space, int argc);
 
-  // Tail call an API function (jump). Allocates HandleScope, extracts
+  // Calls an API function. Allocates HandleScope, extracts
   // returned value from handle and propagates exceptions.
   // Clobbers ebx, esi, edi and caller-save registers.
   void CallApiFunctionAndReturn(ApiFunction* function, int argc);
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index 042335a..f59928f 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -413,6 +413,10 @@
 }
 
 
+// Number of pointers to be reserved on stack for fast API call.
+static const int kFastApiCallArguments = 3;
+
+
 // Reserves space for the extra arguments to FastHandleApiCall in the
 // caller's frame.
 //
@@ -423,10 +427,9 @@
   //  -- esp[4] : last argument in the internal frame of the caller
   // -----------------------------------
   __ pop(scratch);
-  __ push(Immediate(Smi::FromInt(0)));
-  __ push(Immediate(Smi::FromInt(0)));
-  __ push(Immediate(Smi::FromInt(0)));
-  __ push(Immediate(Smi::FromInt(0)));
+  for (int i = 0; i < kFastApiCallArguments; i++) {
+    __ push(Immediate(Smi::FromInt(0)));
+  }
   __ push(scratch);
 }
 
@@ -434,75 +437,81 @@
 // Undoes the effects of ReserveSpaceForFastApiCall.
 static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
   // ----------- S t a t e -------------
-  //  -- esp[0]  : return address
-  //  -- esp[4]  : last fast api call extra argument
+  //  -- esp[0]  : return address.
+  //  -- esp[4]  : last fast api call extra argument.
   //  -- ...
-  //  -- esp[16] : first fast api call extra argument
-  //  -- esp[20] : last argument in the internal frame
+  //  -- esp[kFastApiCallArguments * 4] : first fast api call extra argument.
+  //  -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal
+  //                                          frame.
   // -----------------------------------
   __ pop(scratch);
-  __ add(Operand(esp), Immediate(kPointerSize * 4));
+  __ add(Operand(esp), Immediate(kPointerSize * kFastApiCallArguments));
   __ push(scratch);
 }
 
 
 // Generates call to FastHandleApiCall builtin.
-static void GenerateFastApiCall(MacroAssembler* masm,
+static bool GenerateFastApiCall(MacroAssembler* masm,
                                 const CallOptimization& optimization,
-                                int argc) {
+                                int argc,
+                                Failure** failure) {
   // ----------- S t a t e -------------
   //  -- esp[0]              : return address
   //  -- esp[4]              : object passing the type check
   //                           (last fast api call extra argument,
   //                            set by CheckPrototypes)
-  //  -- esp[8]              : api call data
-  //  -- esp[12]             : api callback
-  //  -- esp[16]             : api function
+  //  -- esp[8]              : api function
   //                           (first fast api call extra argument)
-  //  -- esp[20]             : last argument
+  //  -- esp[12]             : api call data
+  //  -- esp[16]             : last argument
   //  -- ...
-  //  -- esp[(argc + 5) * 4] : first argument
-  //  -- esp[(argc + 6) * 4] : receiver
+  //  -- esp[(argc + 3) * 4] : first argument
+  //  -- esp[(argc + 4) * 4] : receiver
   // -----------------------------------
-
   // Get the function and setup the context.
   JSFunction* function = optimization.constant_function();
   __ mov(edi, Immediate(Handle<JSFunction>(function)));
   __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
 
   // Pass the additional arguments FastHandleApiCall expects.
-  __ mov(Operand(esp, 4 * kPointerSize), edi);
-  bool info_loaded = false;
-  Object* callback = optimization.api_call_info()->callback();
-  if (Heap::InNewSpace(callback)) {
-    info_loaded = true;
-    __ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info()));
-    __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kCallbackOffset));
+  __ mov(Operand(esp, 2 * kPointerSize), edi);
+  Object* call_data = optimization.api_call_info()->data();
+  Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
+  if (Heap::InNewSpace(call_data)) {
+    __ mov(ecx, api_call_info_handle);
+    __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
     __ mov(Operand(esp, 3 * kPointerSize), ebx);
   } else {
-    __ mov(Operand(esp, 3 * kPointerSize), Immediate(Handle<Object>(callback)));
-  }
-  Object* call_data = optimization.api_call_info()->data();
-  if (Heap::InNewSpace(call_data)) {
-    if (!info_loaded) {
-      __ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info()));
-    }
-    __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
-    __ mov(Operand(esp, 2 * kPointerSize), ebx);
-  } else {
-    __ mov(Operand(esp, 2 * kPointerSize),
+    __ mov(Operand(esp, 3 * kPointerSize),
            Immediate(Handle<Object>(call_data)));
   }
 
-  // Set the number of arguments.
-  __ mov(eax, Immediate(argc + 4));
+  // Prepare arguments for ApiCallEntryStub.
+  __ lea(eax, Operand(esp, 3 * kPointerSize));
+  __ lea(ebx, Operand(esp, (argc + 3) * kPointerSize));
+  __ Set(edx, Immediate(argc));
 
-  // Jump to the fast api call builtin (tail call).
-  Handle<Code> code = Handle<Code>(
-      Builtins::builtin(Builtins::FastHandleApiCall));
-  ParameterCount expected(0);
-  __ InvokeCode(code, expected, expected,
-                RelocInfo::CODE_TARGET, JUMP_FUNCTION);
+  Object* callback = optimization.api_call_info()->callback();
+  Address api_function_address = v8::ToCData<Address>(callback);
+  ApiFunction fun(api_function_address);
+
+  ApiCallEntryStub stub(api_call_info_handle, &fun);
+
+  __ EnterInternalFrame();
+
+  // Emitting a stub call may try to allocate (if the code is not
+  // already generated).  Do not allow the assembler to perform a
+  // garbage collection but instead return the allocation failure
+  // object.
+  MaybeObject* result = masm->TryCallStub(&stub);
+  if (result->IsFailure()) {
+    *failure = Failure::cast(result);
+    return false;
+  }
+
+  __ LeaveInternalFrame();
+  __ ret((argc + 4) * kPointerSize);
+  return true;
 }
 
 
@@ -515,7 +524,7 @@
         arguments_(arguments),
         name_(name) {}
 
-  void Compile(MacroAssembler* masm,
+  bool Compile(MacroAssembler* masm,
                JSObject* object,
                JSObject* holder,
                String* name,
@@ -524,7 +533,8 @@
                Register scratch1,
                Register scratch2,
                Register scratch3,
-               Label* miss) {
+               Label* miss,
+               Failure** failure) {
     ASSERT(holder->HasNamedInterceptor());
     ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
 
@@ -535,17 +545,18 @@
     CallOptimization optimization(lookup);
 
     if (optimization.is_constant_call()) {
-      CompileCacheable(masm,
-                       object,
-                       receiver,
-                       scratch1,
-                       scratch2,
-                       scratch3,
-                       holder,
-                       lookup,
-                       name,
-                       optimization,
-                       miss);
+      return CompileCacheable(masm,
+                              object,
+                              receiver,
+                              scratch1,
+                              scratch2,
+                              scratch3,
+                              holder,
+                              lookup,
+                              name,
+                              optimization,
+                              miss,
+                              failure);
     } else {
       CompileRegular(masm,
                      object,
@@ -556,11 +567,12 @@
                      name,
                      holder,
                      miss);
+      return true;
     }
   }
 
  private:
-  void CompileCacheable(MacroAssembler* masm,
+  bool CompileCacheable(MacroAssembler* masm,
                         JSObject* object,
                         Register receiver,
                         Register scratch1,
@@ -570,7 +582,8 @@
                         LookupResult* lookup,
                         String* name,
                         const CallOptimization& optimization,
-                        Label* miss_label) {
+                        Label* miss_label,
+                        Failure** failure) {
     ASSERT(optimization.is_constant_call());
     ASSERT(!lookup->holder()->IsGlobalObject());
 
@@ -632,7 +645,11 @@
 
     // Invoke function.
     if (can_do_fast_api_call) {
-      GenerateFastApiCall(masm, optimization, arguments_.immediate());
+      bool success = GenerateFastApiCall(masm, optimization,
+                                         arguments_.immediate(), failure);
+      if (!success) {
+        return false;
+      }
     } else {
       __ InvokeFunction(optimization.constant_function(), arguments_,
                         JUMP_FUNCTION);
@@ -650,6 +667,8 @@
     if (can_do_fast_api_call) {
       FreeSpaceForFastApiCall(masm, scratch1);
     }
+
+    return true;
   }
 
   void CompileRegular(MacroAssembler* masm,
@@ -1046,8 +1065,7 @@
 
   __ EnterInternalFrame();
   // Push the stack address where the list of arguments ends.
-  __ mov(scratch2, esp);
-  __ sub(Operand(scratch2), Immediate(2 * kPointerSize));
+  __ lea(scratch2, Operand(esp, -2 * kPointerSize));
   __ push(scratch2);
   __ push(receiver);  // receiver
   __ push(reg);  // holder
@@ -1061,12 +1079,11 @@
   __ push(name_reg);  // name
   // Save a pointer to where we pushed the arguments pointer.
   // This will be passed as the const AccessorInfo& to the C++ callback.
-  __ mov(eax, esp);
-  __ add(Operand(eax), Immediate(4 * kPointerSize));
+  STATIC_ASSERT(ApiGetterEntryStub::kStackSpace == 5);
+  __ lea(eax, Operand(esp, 4 * kPointerSize));
   __ mov(ebx, esp);
 
   // Do call through the api.
-  ASSERT_EQ(5, ApiGetterEntryStub::kStackSpace);
   Address getter_address = v8::ToCData<Address>(callback->getter());
   ApiFunction fun(getter_address);
   ApiGetterEntryStub stub(callback_handle, &fun);
@@ -2208,7 +2225,11 @@
   }
 
   if (depth != kInvalidProtoDepth) {
-    GenerateFastApiCall(masm(), optimization, argc);
+    Failure* failure;
+    bool success = GenerateFastApiCall(masm(), optimization, argc, &failure);
+    if (!success) {
+      return failure;
+    }
   } else {
     __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
   }
@@ -2253,16 +2274,21 @@
   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
 
   CallInterceptorCompiler compiler(this, arguments(), ecx);
-  compiler.Compile(masm(),
-                   object,
-                   holder,
-                   name,
-                   &lookup,
-                   edx,
-                   ebx,
-                   edi,
-                   eax,
-                   &miss);
+  Failure* failure;
+  bool success = compiler.Compile(masm(),
+                                  object,
+                                  holder,
+                                  name,
+                                  &lookup,
+                                  edx,
+                                  ebx,
+                                  edi,
+                                  eax,
+                                  &miss,
+                                  &failure);
+  if (!success) {
+    return false;
+  }
 
   // Restore receiver.
   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index c0e5610..2b79016 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -997,6 +997,8 @@
   data()->ShortPrint();
   PrintF("\n - flag: ");
   flag()->ShortPrint();
+  PrintF("\n - load_stub_cache: ");
+  load_stub_cache()->ShortPrint();
 }
 
 void AccessCheckInfo::AccessCheckInfoVerify() {
@@ -1046,6 +1048,7 @@
   CHECK(IsCallHandlerInfo());
   VerifyPointer(callback());
   VerifyPointer(data());
+  VerifyPointer(call_stub_cache());
 }
 
 void CallHandlerInfo::CallHandlerInfoPrint() {
@@ -1054,6 +1057,8 @@
   callback()->ShortPrint();
   PrintF("\n - data: ");
   data()->ShortPrint();
+  PrintF("\n - call_stub_cache: ");
+  call_stub_cache()->ShortPrint();
 }
 
 void TemplateInfo::TemplateInfoVerify() {
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 399ef35..79d70e1 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2557,6 +2557,7 @@
 
 ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset)
 ACCESSORS(CallHandlerInfo, data, Object, kDataOffset)
+ACCESSORS(CallHandlerInfo, call_stub_cache, Object, kCallStubCacheOffset)
 
 ACCESSORS(TemplateInfo, tag, Object, kTagOffset)
 ACCESSORS(TemplateInfo, property_list, Object, kPropertyListOffset)
diff --git a/src/objects.h b/src/objects.h
index 6029ad5..9d975ec 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -5423,6 +5423,7 @@
  public:
   DECL_ACCESSORS(callback, Object)
   DECL_ACCESSORS(data, Object)
+  DECL_ACCESSORS(call_stub_cache, Object)
 
   static inline CallHandlerInfo* cast(Object* obj);
 
@@ -5433,7 +5434,8 @@
 
   static const int kCallbackOffset = HeapObject::kHeaderSize;
   static const int kDataOffset = kCallbackOffset + kPointerSize;
-  static const int kSize = kDataOffset + kPointerSize;
+  static const int kCallStubCacheOffset = kDataOffset + kPointerSize;
+  static const int kSize = kCallStubCacheOffset + kPointerSize;
 
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(CallHandlerInfo);
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index a4d9a82..29f9ab4 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -1848,22 +1848,6 @@
 }
 
 
-int HeapSnapshotGenerator::GetGlobalSecurityToken() {
-  return collection_->token_enumerator()->GetTokenId(
-      Top::context()->global()->global_context()->security_token());
-}
-
-
-int HeapSnapshotGenerator::GetObjectSecurityToken(HeapObject* obj) {
-  if (obj->IsGlobalContext()) {
-    return collection_->token_enumerator()->GetTokenId(
-        Context::cast(obj)->security_token());
-  } else {
-    return TokenEnumerator::kNoSecurityToken;
-  }
-}
-
-
 class IndexedReferencesExtractor : public ObjectVisitor {
  public:
   IndexedReferencesExtractor(HeapSnapshotGenerator* generator,
@@ -1893,19 +1877,11 @@
 
 void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) {
   // We need to reference JS global objects from snapshot's root.
-  // We also need to only include global objects from the current
-  // security context. And we don't want to add the global proxy,
-  // as we don't have a special type for it.
+  // We use JSGlobalProxy because this is what embedder (e.g. browser)
+  // uses for the global object.
   if (obj->IsJSGlobalProxy()) {
-    int global_security_token = GetGlobalSecurityToken();
     JSGlobalProxy* proxy = JSGlobalProxy::cast(obj);
-    int object_security_token =
-        collection_->token_enumerator()->GetTokenId(
-            Context::cast(proxy->context())->security_token());
-    if (object_security_token == TokenEnumerator::kNoSecurityToken
-        || object_security_token == global_security_token) {
-      SetRootReference(proxy->map()->prototype());
-    }
+    SetRootReference(proxy->map()->prototype());
     return;
   }
 
diff --git a/src/profile-generator.h b/src/profile-generator.h
index 6f63f6a..b691a05 100644
--- a/src/profile-generator.h
+++ b/src/profile-generator.h
@@ -948,8 +948,6 @@
 
  private:
   HeapEntry* GetEntry(Object* obj);
-  int GetGlobalSecurityToken();
-  int GetObjectSecurityToken(HeapObject* obj);
   void ExtractReferences(HeapObject* obj);
   void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry);
   void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry);
diff --git a/src/spaces.cc b/src/spaces.cc
index e3fb923..2f3e41a 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -270,8 +270,9 @@
 // -----------------------------------------------------------------------------
 // MemoryAllocator
 //
-intptr_t MemoryAllocator::capacity_   = 0;
-intptr_t MemoryAllocator::size_       = 0;
+intptr_t MemoryAllocator::capacity_ = 0;
+intptr_t MemoryAllocator::capacity_executable_ = 0;
+intptr_t MemoryAllocator::size_ = 0;
 intptr_t MemoryAllocator::size_executable_ = 0;
 
 List<MemoryAllocator::MemoryAllocationCallbackRegistration>
@@ -302,8 +303,10 @@
 }
 
 
-bool MemoryAllocator::Setup(intptr_t capacity) {
+bool MemoryAllocator::Setup(intptr_t capacity, intptr_t capacity_executable) {
   capacity_ = RoundUp(capacity, Page::kPageSize);
+  capacity_executable_ = RoundUp(capacity_executable, Page::kPageSize);
+  ASSERT_GE(capacity_, capacity_executable_);
 
   // Over-estimate the size of chunks_ array.  It assumes the expansion of old
   // space is always in the unit of a chunk (kChunkSize) except the last
@@ -346,6 +349,7 @@
   ASSERT(top_ == max_nof_chunks_);  // all chunks are free
   top_ = 0;
   capacity_ = 0;
+  capacity_executable_ = 0;
   size_ = 0;
   max_nof_chunks_ = 0;
 }
@@ -357,16 +361,31 @@
   if (size_ + static_cast<size_t>(requested) > static_cast<size_t>(capacity_)) {
     return NULL;
   }
+
   void* mem;
-  if (executable == EXECUTABLE  && CodeRange::exists()) {
-    mem = CodeRange::AllocateRawMemory(requested, allocated);
+  if (executable == EXECUTABLE) {
+    // Check executable memory limit.
+    if (size_executable_ + requested >
+        static_cast<size_t>(capacity_executable_)) {
+      LOG(StringEvent("MemoryAllocator::AllocateRawMemory",
+                      "V8 Executable Allocation capacity exceeded"));
+      return NULL;
+    }
+    // Allocate executable memory either from code range or from the
+    // OS.
+    if (CodeRange::exists()) {
+      mem = CodeRange::AllocateRawMemory(requested, allocated);
+    } else {
+      mem = OS::Allocate(requested, allocated, true);
+    }
+    // Update executable memory size.
+    size_executable_ += static_cast<int>(*allocated);
   } else {
-    mem = OS::Allocate(requested, allocated, (executable == EXECUTABLE));
+    mem = OS::Allocate(requested, allocated, false);
   }
   int alloced = static_cast<int>(*allocated);
   size_ += alloced;
 
-  if (executable == EXECUTABLE) size_executable_ += alloced;
 #ifdef DEBUG
   ZapBlock(reinterpret_cast<Address>(mem), alloced);
 #endif
@@ -391,6 +410,7 @@
   if (executable == EXECUTABLE) size_executable_ -= static_cast<int>(length);
 
   ASSERT(size_ >= 0);
+  ASSERT(size_executable_ >= 0);
 }
 
 
diff --git a/src/spaces.h b/src/spaces.h
index 3ed2fe8..0c10d2c 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -491,8 +491,8 @@
 class MemoryAllocator : public AllStatic {
  public:
   // Initializes its internal bookkeeping structures.
-  // Max capacity of the total space.
-  static bool Setup(intptr_t max_capacity);
+  // Max capacity of the total space and executable memory limit.
+  static bool Setup(intptr_t max_capacity, intptr_t capacity_executable);
 
   // Deletes valid chunks.
   static void TearDown();
@@ -590,6 +590,12 @@
   // Returns allocated spaces in bytes.
   static intptr_t Size() { return size_; }
 
+  // Returns the maximum available executable bytes of heaps.
+  static int AvailableExecutable() {
+    if (capacity_executable_ < size_executable_) return 0;
+    return capacity_executable_ - size_executable_;
+  }
+
   // Returns allocated executable spaces in bytes.
   static intptr_t SizeExecutable() { return size_executable_; }
 
@@ -653,6 +659,8 @@
  private:
   // Maximum space size in bytes.
   static intptr_t capacity_;
+  // Maximum subset of capacity_ that can be executable
+  static intptr_t capacity_executable_;
 
   // Allocated space size in bytes.
   static intptr_t size_;
diff --git a/src/strtod.cc b/src/strtod.cc
index 0ed1b0d..0523d88 100644
--- a/src/strtod.cc
+++ b/src/strtod.cc
@@ -31,6 +31,7 @@
 #include "v8.h"
 
 #include "strtod.h"
+#include "bignum.h"
 #include "cached-powers.h"
 #include "double.h"
 
@@ -83,44 +84,12 @@
   // 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22
   10000000000000000000000.0
 };
-
 static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten);
 
-
-extern "C" double gay_strtod(const char* s00, const char** se);
-
-static double old_strtod(Vector<const char> buffer, int exponent) {
-  // gay_strtod is broken on Linux,x86. For numbers with few decimal digits
-  // the computation is done using floating-point operations which (on Linux)
-  // are prone to double-rounding errors.
-  // By adding several zeroes to the buffer gay_strtod falls back to a slower
-  // (but correct) algorithm.
-  const int kInsertedZeroesCount = 20;
-  char gay_buffer[1024];
-  Vector<char> gay_buffer_vector(gay_buffer, sizeof(gay_buffer));
-  int pos = 0;
-  for (int i = 0; i < buffer.length(); ++i) {
-    gay_buffer_vector[pos++] = buffer[i];
-  }
-  for (int i = 0; i < kInsertedZeroesCount; ++i) {
-    gay_buffer_vector[pos++] = '0';
-  }
-  exponent -= kInsertedZeroesCount;
-  gay_buffer_vector[pos++] = 'e';
-  if (exponent < 0) {
-    gay_buffer_vector[pos++] = '-';
-    exponent = -exponent;
-  }
-  const int kNumberOfExponentDigits = 5;
-  for (int i = kNumberOfExponentDigits - 1; i >= 0; i--) {
-    gay_buffer_vector[pos + i] = exponent % 10 + '0';
-    exponent /= 10;
-  }
-  pos += kNumberOfExponentDigits;
-  gay_buffer_vector[pos] = '\0';
-  return gay_strtod(gay_buffer, NULL);
-}
-
+// Maximum number of significant digits in the decimal representation.
+// In fact the value is 772 (see conversions.cc), but to give us some margin
+// we round up to 780.
+static const int kMaxSignificantDecimalDigits = 780;
 
 static Vector<const char> TrimLeadingZeros(Vector<const char> buffer) {
   for (int i = 0; i < buffer.length(); i++) {
@@ -142,6 +111,23 @@
 }
 
 
+static void TrimToMaxSignificantDigits(Vector<const char> buffer,
+                                       int exponent,
+                                       char* significant_buffer,
+                                       int* significant_exponent) {
+  for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) {
+    significant_buffer[i] = buffer[i];
+  }
+  // The input buffer has been trimmed. Therefore the last digit must be
+  // different from '0'.
+  ASSERT(buffer[buffer.length() - 1] != '0');
+  // Set the last digit to be non-zero. This is sufficient to guarantee
+  // correct rounding.
+  significant_buffer[kMaxSignificantDecimalDigits - 1] = '1';
+  *significant_exponent =
+      exponent + (buffer.length() - kMaxSignificantDecimalDigits);
+}
+
 // Reads digits from the buffer and converts them to a uint64.
 // Reads in as many digits as fit into a uint64.
 // When the string starts with "1844674407370955161" no further digit is read.
@@ -374,20 +360,81 @@
 }
 
 
+// Returns the correct double for the buffer*10^exponent.
+// The variable guess should be a close guess that is either the correct double
+// or its lower neighbor (the nearest double less than the correct one).
+// Preconditions:
+//   buffer.length() + exponent <= kMaxDecimalPower + 1
+//   buffer.length() + exponent > kMinDecimalPower
+//   buffer.length() <= kMaxDecimalSignificantDigits
+static double BignumStrtod(Vector<const char> buffer,
+                           int exponent,
+                           double guess) {
+  if (guess == V8_INFINITY) {
+    return guess;
+  }
+
+  DiyFp upper_boundary = Double(guess).UpperBoundary();
+
+  ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1);
+  ASSERT(buffer.length() + exponent > kMinDecimalPower);
+  ASSERT(buffer.length() <= kMaxSignificantDecimalDigits);
+  // Make sure that the Bignum will be able to hold all our numbers.
+  // Our Bignum implementation has a separate field for exponents. Shifts will
+  // consume at most one bigit (< 64 bits).
+  // ln(10) == 3.3219...
+  ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits);
+  Bignum input;
+  Bignum boundary;
+  input.AssignDecimalString(buffer);
+  boundary.AssignUInt64(upper_boundary.f());
+  if (exponent >= 0) {
+    input.MultiplyByPowerOfTen(exponent);
+  } else {
+    boundary.MultiplyByPowerOfTen(-exponent);
+  }
+  if (upper_boundary.e() > 0) {
+    boundary.ShiftLeft(upper_boundary.e());
+  } else {
+    input.ShiftLeft(-upper_boundary.e());
+  }
+  int comparison = Bignum::Compare(input, boundary);
+  if (comparison < 0) {
+    return guess;
+  } else if (comparison > 0) {
+    return Double(guess).NextDouble();
+  } else if ((Double(guess).Significand() & 1) == 0) {
+    // Round towards even.
+    return guess;
+  } else {
+    return Double(guess).NextDouble();
+  }
+}
+
+
 double Strtod(Vector<const char> buffer, int exponent) {
   Vector<const char> left_trimmed = TrimLeadingZeros(buffer);
   Vector<const char> trimmed = TrimTrailingZeros(left_trimmed);
   exponent += left_trimmed.length() - trimmed.length();
   if (trimmed.length() == 0) return 0.0;
+  if (trimmed.length() > kMaxSignificantDecimalDigits) {
+    char significant_buffer[kMaxSignificantDecimalDigits];
+    int significant_exponent;
+    TrimToMaxSignificantDigits(trimmed, exponent,
+                               significant_buffer, &significant_exponent);
+    trimmed =
+        Vector<const char>(significant_buffer, kMaxSignificantDecimalDigits);
+    exponent = significant_exponent;
+  }
   if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) return V8_INFINITY;
   if (exponent + trimmed.length() <= kMinDecimalPower) return 0.0;
 
-  double result;
-  if (DoubleStrtod(trimmed, exponent, &result) ||
-      DiyFpStrtod(trimmed, exponent, &result)) {
-    return result;
+  double guess;
+  if (DoubleStrtod(trimmed, exponent, &guess) ||
+      DiyFpStrtod(trimmed, exponent, &guess)) {
+    return guess;
   }
-  return old_strtod(trimmed, exponent);
+  return BignumStrtod(trimmed, exponent, guess);
 }
 
 } }  // namespace v8::internal
diff --git a/src/version.cc b/src/version.cc
index 5ef2a65..b45510c 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
 // cannot be changed without changing the SCons build script.
 #define MAJOR_VERSION     2
 #define MINOR_VERSION     5
-#define BUILD_NUMBER      5
+#define BUILD_NUMBER      6
 #define PATCH_LEVEL       0
 #define CANDIDATE_VERSION false
 
diff --git a/test/cctest/SConscript b/test/cctest/SConscript
index 006653c..620cd82 100644
--- a/test/cctest/SConscript
+++ b/test/cctest/SConscript
@@ -41,6 +41,7 @@
     'test-alloc.cc',
     'test-api.cc',
     'test-ast.cc',
+    'test-bignum.cc',
     'test-circular-queue.cc',
     'test-compiler.cc',
     'test-conversions.cc',
diff --git a/test/cctest/test-assembler-arm.cc b/test/cctest/test-assembler-arm.cc
index 4f90b61..0f12f98 100644
--- a/test/cctest/test-assembler-arm.cc
+++ b/test/cctest/test-assembler-arm.cc
@@ -397,4 +397,72 @@
   }
 }
 
+
+static void TestRoundingMode(int32_t mode, double value, int expected) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  Assembler assm(NULL, 0);
+
+  __ vmrs(r1);
+  // Set custom FPSCR.
+  __ bic(r2, r1, Operand(((mode ^ 3) << 22) | 0xf));
+  __ orr(r2, r2, Operand(mode << 22));
+  __ vmsr(r2);
+
+  // Load value, convert, and move back result to r0.
+  __ vmov(d1, value);
+  __ vcvt_s32_f64(s0, d1, Assembler::FPSCRRounding, al);
+  __ vmov(r0, s0);
+
+  __ mov(pc, Operand(lr));
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = Heap::CreateCode(
+      desc,
+      Code::ComputeFlags(Code::STUB),
+      Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
+  CHECK(code->IsCode());
+#ifdef DEBUG
+  Code::cast(code)->Print();
+#endif
+  F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
+  int res = reinterpret_cast<int>(
+              CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+  ::printf("res = %d\n", res);
+  CHECK_EQ(expected, res);
+}
+
+
+TEST(7) {
+  // Test vfp rounding modes.
+
+  // See ARM DDI 0406B Page A2-29.
+  enum FPSCRRoungingMode {
+    RN,   // Round to Nearest.
+    RP,   // Round towards Plus Infinity.
+    RM,   // Round towards Minus Infinity.
+    RZ    // Round towards zero.
+  };
+
+  if (CpuFeatures::IsSupported(VFP3)) {
+    CpuFeatures::Scope scope(VFP3);
+
+    TestRoundingMode(RZ,  0.5, 0);
+    TestRoundingMode(RZ, -0.5, 0);
+    TestRoundingMode(RZ,  123.7,  123);
+    TestRoundingMode(RZ, -123.7, -123);
+    TestRoundingMode(RZ,  123456.2,  123456);
+    TestRoundingMode(RZ, -123456.2, -123456);
+
+    TestRoundingMode(RM,  0.5, 0);
+    TestRoundingMode(RM, -0.5, -1);
+    TestRoundingMode(RM,  123.7, 123);
+    TestRoundingMode(RM, -123.7, -124);
+    TestRoundingMode(RM,  123456.2,  123456);
+    TestRoundingMode(RM, -123456.2, -123457);
+  }
+}
+
 #undef __
diff --git a/test/cctest/test-bignum.cc b/test/cctest/test-bignum.cc
new file mode 100644
index 0000000..9aa5ef3
--- /dev/null
+++ b/test/cctest/test-bignum.cc
@@ -0,0 +1,1502 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "platform.h"
+#include "cctest.h"
+#include "bignum.h"
+
+using namespace v8::internal;
+
+
+static const int kBufferSize = 1024;
+
+static void AssignHexString(Bignum* bignum, const char* str) {
+  bignum->AssignHexString(Vector<const char>(str, StrLength(str)));
+}
+
+
+static void AssignDecimalString(Bignum* bignum, const char* str) {
+  bignum->AssignDecimalString(Vector<const char>(str, StrLength(str)));
+}
+
+
+TEST(Assign) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+  Bignum bignum2;
+  bignum.AssignUInt16(0);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("0", buffer);
+  bignum.AssignUInt16(0xA);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A", buffer);
+  bignum.AssignUInt16(0x20);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("20", buffer);
+
+
+  bignum.AssignUInt64(0);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("0", buffer);
+  bignum.AssignUInt64(0xA);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A", buffer);
+  bignum.AssignUInt64(0x20);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("20", buffer);
+  bignum.AssignUInt64(0x100);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100", buffer);
+
+  // The first real test, since this will not fit into one bigit.
+  bignum.AssignUInt64(0x12345678);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("12345678", buffer);
+
+  uint64_t big = V8_2PART_UINT64_C(0xFFFFFFFF, FFFFFFFF);
+  bignum.AssignUInt64(big);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFFFFF", buffer);
+
+  big = V8_2PART_UINT64_C(0x12345678, 9ABCDEF0);
+  bignum.AssignUInt64(big);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("123456789ABCDEF0", buffer);
+
+  bignum2.AssignBignum(bignum);
+  CHECK(bignum2.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("123456789ABCDEF0", buffer);
+
+  AssignDecimalString(&bignum, "0");
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("0", buffer);
+
+  AssignDecimalString(&bignum, "1");
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  AssignDecimalString(&bignum, "1234567890");
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("499602D2", buffer);
+
+  AssignHexString(&bignum, "0");
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("0", buffer);
+
+  AssignHexString(&bignum, "123456789ABCDEF0");
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("123456789ABCDEF0", buffer);
+}
+
+
+TEST(ShiftLeft) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+  AssignHexString(&bignum, "0");
+  bignum.ShiftLeft(100);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("0", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.ShiftLeft(1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.ShiftLeft(4);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.ShiftLeft(32);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100000000", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.ShiftLeft(64);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000", buffer);
+
+  AssignHexString(&bignum, "123456789ABCDEF");
+  bignum.ShiftLeft(64);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("123456789ABCDEF0000000000000000", buffer);
+  bignum.ShiftLeft(1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2468ACF13579BDE0000000000000000", buffer);
+}
+
+
+TEST(AddUInt64) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+  AssignHexString(&bignum, "0");
+  bignum.AddUInt64(0xA);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.AddUInt64(0xA);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("B", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.AddUInt64(0x100);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("101", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.AddUInt64(0xFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000", buffer);
+
+  AssignHexString(&bignum, "FFFFFFF");
+  bignum.AddUInt64(0x1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000", buffer);
+
+  AssignHexString(&bignum, "10000000000000000000000000000000000000000000");
+  bignum.AddUInt64(0xFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1000000000000000000000000000000000000000FFFF", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+  bignum.AddUInt64(0x1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100000000000000000000000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  bignum.AddUInt64(1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000000000001", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  bignum.AddUInt64(0xFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1000000000000000000000FFFF", buffer);
+
+  AssignHexString(&bignum, "0");
+  bignum.AddUInt64(V8_2PART_UINT64_C(0xA, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A00000000", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.AddUInt64(V8_2PART_UINT64_C(0xA, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A00000001", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.AddUInt64(V8_2PART_UINT64_C(0x100, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000001", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.AddUInt64(V8_2PART_UINT64_C(0xFFFF, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFF00000001", buffer);
+
+  AssignHexString(&bignum, "FFFFFFF");
+  bignum.AddUInt64(V8_2PART_UINT64_C(0x1, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10FFFFFFF", buffer);
+
+  AssignHexString(&bignum, "10000000000000000000000000000000000000000000");
+  bignum.AddUInt64(V8_2PART_UINT64_C(0xFFFF, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000000000000000000FFFF00000000", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+  bignum.AddUInt64(V8_2PART_UINT64_C(0x1, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1000000000000000000000000000000000000FFFFFFFF", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  bignum.AddUInt64(V8_2PART_UINT64_C(0x1, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000100000000", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  bignum.AddUInt64(V8_2PART_UINT64_C(0xFFFF, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000FFFF00000000", buffer);
+}
+
+
+TEST(AddBignum) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+  Bignum other;
+
+  AssignHexString(&other, "1");
+  AssignHexString(&bignum, "0");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2", buffer);
+
+  AssignHexString(&bignum, "FFFFFFF");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFF");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100000000000000", buffer);
+
+  AssignHexString(&bignum, "10000000000000000000000000000000000000000000");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000000000000000000000000000001", buffer);
+
+  AssignHexString(&other, "1000000000000");
+
+  AssignHexString(&bignum, "1");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1000000000001", buffer);
+
+  AssignHexString(&bignum, "FFFFFFF");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100000FFFFFFF", buffer);
+
+  AssignHexString(&bignum, "10000000000000000000000000000000000000000000");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000000000000000001000000000000", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1000000000000000000000000000000FFFFFFFFFFFF", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000001000000000000", buffer);
+
+  other.ShiftLeft(64);
+  // other == "10000000000000000000000000000"
+
+  bignum.AssignUInt16(0x1);
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000000000000001", buffer);
+
+  AssignHexString(&bignum, "FFFFFFF");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1000000000000000000000FFFFFFF", buffer);
+
+  AssignHexString(&bignum, "10000000000000000000000000000000000000000000");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000010000000000000000000000000000", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFF", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10010000000000000000000000000", buffer);
+}
+
+
+TEST(SubtractBignum) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+  Bignum other;
+
+  AssignHexString(&bignum, "1");
+  AssignHexString(&other, "0");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  AssignHexString(&bignum, "2");
+  AssignHexString(&other, "0");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2", buffer);
+
+  AssignHexString(&bignum, "10000000");
+  AssignHexString(&other, "1");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFF", buffer);
+
+  AssignHexString(&bignum, "100000000000000");
+  AssignHexString(&other, "1");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFFF", buffer);
+
+  AssignHexString(&bignum, "10000000000000000000000000000000000000000001");
+  AssignHexString(&other, "1");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000000000000000000000000000000", buffer);
+
+  AssignHexString(&bignum, "1000000000001");
+  AssignHexString(&other, "1000000000000");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  AssignHexString(&bignum, "100000FFFFFFF");
+  AssignHexString(&other, "1000000000000");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFF", buffer);
+
+  AssignHexString(&bignum, "10000000000000000000000000000001000000000000");
+  AssignHexString(&other, "1000000000000");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000000000000000000000000000000", buffer);
+
+  AssignHexString(&bignum, "1000000000000000000000000000000FFFFFFFFFFFF");
+  AssignHexString(&other, "1000000000000");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  // "10 0000 0000 0000 0000 0000 0000"
+  AssignHexString(&other, "1000000000000");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFF000000000000", buffer);
+
+  AssignHexString(&other, "1000000000000");
+  other.ShiftLeft(48);
+  // other == "1000000000000000000000000"
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  // bignum == "10000000000000000000000000"
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("F000000000000000000000000", buffer);
+
+  other.AssignUInt16(0x1);
+  other.ShiftLeft(35);
+  // other == "800000000"
+  AssignHexString(&bignum, "FFFFFFF");
+  bignum.ShiftLeft(60);
+  // bignum = FFFFFFF000000000000000
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFEFFFFFF800000000", buffer);
+
+  AssignHexString(&bignum, "10000000000000000000000000000000000000000000");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF800000000", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFF", buffer);
+}
+
+
+TEST(MultiplyUInt32) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+
+  AssignHexString(&bignum, "0");
+  bignum.MultiplyByUInt32(0x25);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("0", buffer);
+
+  AssignHexString(&bignum, "2");
+  bignum.MultiplyByUInt32(0x5);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A", buffer);
+
+  AssignHexString(&bignum, "10000000");
+  bignum.MultiplyByUInt32(0x9);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("90000000", buffer);
+
+  AssignHexString(&bignum, "100000000000000");
+  bignum.MultiplyByUInt32(0xFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFF00000000000000", buffer);
+
+  AssignHexString(&bignum, "100000000000000");
+  bignum.MultiplyByUInt32(0xFFFFFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFF00000000000000", buffer);
+
+  AssignHexString(&bignum, "1234567ABCD");
+  bignum.MultiplyByUInt32(0xFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("12333335552433", buffer);
+
+  AssignHexString(&bignum, "1234567ABCD");
+  bignum.MultiplyByUInt32(0xFFFFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("12345679998A985433", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");
+  bignum.MultiplyByUInt32(0x2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1FFFFFFFFFFFFFFFE", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");
+  bignum.MultiplyByUInt32(0x4);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("3FFFFFFFFFFFFFFFC", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");
+  bignum.MultiplyByUInt32(0xF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("EFFFFFFFFFFFFFFF1", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");
+  bignum.MultiplyByUInt32(0xFFFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFEFFFFFFFFFF000001", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  // "10 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt32(2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("20000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  // "10 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt32(0xF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("F0000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0xFFFF);
+  bignum.ShiftLeft(100);
+  // "FFFF0 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt32(0xFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFE00010000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0xFFFF);
+  bignum.ShiftLeft(100);
+  // "FFFF0 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt32(0xFFFFFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFEFFFF00010000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0xFFFF);
+  bignum.ShiftLeft(100);
+  // "FFFF0 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt32(0xFFFFFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFEFFFF00010000000000000000000000000", buffer);
+
+  AssignDecimalString(&bignum, "15611230384529777");
+  bignum.MultiplyByUInt32(10000000);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("210EDD6D4CDD2580EE80", buffer);
+}
+
+
+TEST(MultiplyUInt64) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+
+  AssignHexString(&bignum, "0");
+  bignum.MultiplyByUInt64(0x25);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("0", buffer);
+
+  AssignHexString(&bignum, "2");
+  bignum.MultiplyByUInt64(0x5);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A", buffer);
+
+  AssignHexString(&bignum, "10000000");
+  bignum.MultiplyByUInt64(0x9);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("90000000", buffer);
+
+  AssignHexString(&bignum, "100000000000000");
+  bignum.MultiplyByUInt64(0xFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFF00000000000000", buffer);
+
+  AssignHexString(&bignum, "100000000000000");
+  bignum.MultiplyByUInt64(V8_2PART_UINT64_C(0xFFFFFFFF, FFFFFFFF));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFFFFF00000000000000", buffer);
+
+  AssignHexString(&bignum, "1234567ABCD");
+  bignum.MultiplyByUInt64(0xFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("12333335552433", buffer);
+
+  AssignHexString(&bignum, "1234567ABCD");
+  bignum.MultiplyByUInt64(V8_2PART_UINT64_C(0xFF, FFFFFFFF));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1234567ABCBDCBA985433", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");
+  bignum.MultiplyByUInt64(0x2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1FFFFFFFFFFFFFFFE", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");
+  bignum.MultiplyByUInt64(0x4);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("3FFFFFFFFFFFFFFFC", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");
+  bignum.MultiplyByUInt64(0xF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("EFFFFFFFFFFFFFFF1", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");
+  bignum.MultiplyByUInt64(V8_2PART_UINT64_C(0xFFFFFFFF, FFFFFFFF));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFFFFE0000000000000001", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  // "10 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt64(2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("20000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  // "10 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt64(0xF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("F0000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0xFFFF);
+  bignum.ShiftLeft(100);
+  // "FFFF0 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt64(0xFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFE00010000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0xFFFF);
+  bignum.ShiftLeft(100);
+  // "FFFF0 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt64(0xFFFFFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFEFFFF00010000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0xFFFF);
+  bignum.ShiftLeft(100);
+  // "FFFF0 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt64(V8_2PART_UINT64_C(0xFFFFFFFF, FFFFFFFF));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFEFFFFFFFFFFFF00010000000000000000000000000", buffer);
+
+  AssignDecimalString(&bignum, "15611230384529777");
+  bignum.MultiplyByUInt64(V8_2PART_UINT64_C(0x8ac72304, 89e80000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1E10EE4B11D15A7F3DE7F3C7680000", buffer);
+}
+
+
+TEST(MultiplyPowerOfTen) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("3034", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1E208", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(3);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("12D450", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(4);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("BC4B20", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(5);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("75AEF40", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(6);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("498D5880", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(7);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2DF857500", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(8);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1CBB369200", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(9);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("11F5021B400", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(10);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("B3921510800", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(11);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("703B4D2A5000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(12);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("4625103A72000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(13);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2BD72A24874000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(14);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1B667A56D488000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(15);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("11200C7644D50000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(16);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("AB407C9EB0520000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(17);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("6B084DE32E3340000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(18);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("42E530ADFCE0080000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(19);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("29CF3E6CBE0C0500000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(20);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1A218703F6C783200000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(21);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1054F4627A3CB1F400000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(22);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A3518BD8C65EF38800000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(23);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("6612F7677BFB5835000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(24);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("3FCBDAA0AD7D17212000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(25);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("27DF68A46C6E2E74B4000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(26);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("18EBA166C3C4DD08F08000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(27);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("F9344E03A5B0A259650000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(28);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("9BC0B0C2478E6577DF20000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(29);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("61586E796CB8FF6AEB740000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(30);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("3CD7450BE3F39FA2D32880000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(31);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("26068B276E7843C5C3F9500000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(50);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("149D1B4CFED03B23AB5F4E1196EF45C08000000000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(100);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("5827249F27165024FBC47DFCA9359BF316332D1B91ACEECF471FBAB06D9B2"
+           "0000000000000000000000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(200);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("64C1F5C06C3816AFBF8DAFD5A3D756365BB0FD020E6F084E759C1F7C99E4F"
+           "55B9ACC667CEC477EB958C2AEEB3C6C19BA35A1AD30B35C51EB72040920000"
+           "0000000000000000000000000000000000000000000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(500);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("96741A625EB5D7C91039FEB5C5ACD6D9831EDA5B083D800E6019442C8C8223"
+           "3EAFB3501FE2058062221E15121334928880827DEE1EC337A8B26489F3A40A"
+           "CB440A2423734472D10BFCE886F41B3AF9F9503013D86D088929CA86EEB4D8"
+           "B9C831D0BD53327B994A0326227CFD0ECBF2EB48B02387AAE2D4CCCDF1F1A1"
+           "B8CC4F1FA2C56AD40D0E4DAA9C28CDBF0A549098EA13200000000000000000"
+           "00000000000000000000000000000000000000000000000000000000000000"
+           "0000000000000000000000000000000000000000000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(1000);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1258040F99B1CD1CC9819C676D413EA50E4A6A8F114BB0C65418C62D399B81"
+           "6361466CA8E095193E1EE97173553597C96673AF67FAFE27A66E7EF2E5EF2E"
+           "E3F5F5070CC17FE83BA53D40A66A666A02F9E00B0E11328D2224B8694C7372"
+           "F3D536A0AD1985911BD361496F268E8B23112500EAF9B88A9BC67B2AB04D38"
+           "7FEFACD00F5AF4F764F9ABC3ABCDE54612DE38CD90CB6647CA389EA0E86B16"
+           "BF7A1F34086E05ADBE00BD1673BE00FAC4B34AF1091E8AD50BA675E0381440"
+           "EA8E9D93E75D816BAB37C9844B1441C38FC65CF30ABB71B36433AF26DD97BD"
+           "ABBA96C03B4919B8F3515B92826B85462833380DC193D79F69D20DD6038C99"
+           "6114EF6C446F0BA28CC772ACBA58B81C04F8FFDE7B18C4E5A3ABC51E637FDF"
+           "6E37FDFF04C940919390F4FF92000000000000000000000000000000000000"
+           "00000000000000000000000000000000000000000000000000000000000000"
+           "00000000000000000000000000000000000000000000000000000000000000"
+           "00000000000000000000000000000000000000000000000000000000000000"
+           "0000000000000000000000000000", buffer);
+
+  Bignum bignum2;
+  AssignHexString(&bignum2, "3DA774C07FB5DF54284D09C675A492165B830D5DAAEB2A7501"
+                            "DA17CF9DFA1CA2282269F92A25A97314296B717E3DCBB9FE17"
+                            "41A842FE2913F540F40796F2381155763502C58B15AF7A7F88"
+                            "6F744C9164FF409A28F7FA0C41F89ED79C1BE9F322C8578B97"
+                            "841F1CBAA17D901BE1230E3C00E1C643AF32638B5674E01FEA"
+                            "96FC90864E621B856A9E1CE56E6EB545B9C2F8F0CC10DDA88D"
+                            "CC6D282605F8DB67044F2DFD3695E7BA63877AE16701536AE6"
+                            "567C794D0BFE338DFBB42D92D4215AF3BB22BF0A8B283FDDC2"
+                            "C667A10958EA6D2");
+  CHECK(bignum2.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("3DA774C07FB5DF54284D09C675A492165B830D5DAAEB2A7501"
+           "DA17CF9DFA1CA2282269F92A25A97314296B717E3DCBB9FE17"
+           "41A842FE2913F540F40796F2381155763502C58B15AF7A7F88"
+           "6F744C9164FF409A28F7FA0C41F89ED79C1BE9F322C8578B97"
+           "841F1CBAA17D901BE1230E3C00E1C643AF32638B5674E01FEA"
+           "96FC90864E621B856A9E1CE56E6EB545B9C2F8F0CC10DDA88D"
+           "CC6D282605F8DB67044F2DFD3695E7BA63877AE16701536AE6"
+           "567C794D0BFE338DFBB42D92D4215AF3BB22BF0A8B283FDDC2"
+           "C667A10958EA6D2", buffer);
+
+  bignum.AssignBignum(bignum2);
+  bignum.MultiplyByPowerOfTen(1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2688A8F84FD1AB949930261C0986DB4DF931E85A8AD2FA8921284EE1C2BC51"
+           "E55915823BBA5789E7EC99E326EEE69F543ECE890929DED9AC79489884BE57"
+           "630AD569E121BB76ED8DAC8FB545A8AFDADF1F8860599AFC47A93B6346C191"
+           "7237F5BD36B73EB29371F4A4EE7A116CB5E8E5808D1BEA4D7F7E3716090C13"
+           "F29E5DDA53F0FD513362A2D20F6505314B9419DB967F8A8A89589FC43917C3"
+           "BB892062B17CBE421DB0D47E34ACCCE060D422CFF60DCBD0277EE038BD509C"
+           "7BC494D8D854F5B76696F927EA99BC00C4A5D7928434", buffer);
+
+  bignum.AssignBignum(bignum2);
+  bignum.MultiplyByPowerOfTen(2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1815699B31E30B3CDFBE17D185F44910BBBF313896C3DC95B4B9314D19B5B32"
+           "F57AD71655476B630F3E02DF855502394A74115A5BA2B480BCBCD5F52F6F69D"
+           "E6C5622CB5152A54788BD9D14B896DE8CB73B53C3800DDACC9C51E0C38FAE76"
+           "2F9964232872F9C2738E7150C4AE3F1B18F70583172706FAEE26DC5A78C77A2"
+           "FAA874769E52C01DA5C3499F233ECF3C90293E0FB69695D763DAA3AEDA5535B"
+           "43DAEEDF6E9528E84CEE0EC000C3C8495C1F9C89F6218AF4C23765261CD5ADD"
+           "0787351992A01E5BB8F2A015807AE7A6BB92A08", buffer);
+
+  bignum.AssignBignum(bignum2);
+  bignum.MultiplyByPowerOfTen(5);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("5E13A4863ADEE3E5C9FE8D0A73423D695D62D8450CED15A8C9F368952C6DC3"
+           "F0EE7D82F3D1EFB7AF38A3B3920D410AFCAD563C8F5F39116E141A3C5C14B3"
+           "58CD73077EA35AAD59F6E24AD98F10D5555ABBFBF33AC361EAF429FD5FBE94"
+           "17DA9EF2F2956011F9F93646AA38048A681D984ED88127073443247CCC167C"
+           "B354A32206EF5A733E73CF82D795A1AD598493211A6D613C39515E0E0F6304"
+           "DCD9C810F3518C7F6A7CB6C81E99E02FCC65E8FDB7B7AE97306CC16A8631CE"
+           "0A2AEF6568276BE4C176964A73C153FDE018E34CB4C2F40", buffer);
+
+  bignum.AssignBignum(bignum2);
+  bignum.MultiplyByPowerOfTen(10);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("8F8CB8EB51945A7E815809F6121EF2F4E61EF3405CD9432CAD2709749EEAFD"
+           "1B81E843F14A3667A7BDCCC9E0BB795F63CDFDB62844AC7438976C885A0116"
+           "29607DA54F9C023CC366570B7637ED0F855D931752038A614922D0923E382C"
+           "B8E5F6C975672DB76E0DE471937BB9EDB11E28874F1C122D5E1EF38CECE9D0"
+           "0723056BCBD4F964192B76830634B1D322B7EB0062F3267E84F5C824343A77"
+           "4B7DCEE6DD464F01EBDC8C671BB18BB4EF4300A42474A6C77243F2A12B03BF"
+           "0443C38A1C0D2701EDB393135AE0DEC94211F9D4EB51F990800", buffer);
+
+  bignum.AssignBignum(bignum2);
+  bignum.MultiplyByPowerOfTen(50);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("107A8BE345E24407372FC1DE442CBA696BC23C4FFD5B4BDFD9E5C39559815"
+           "86628CF8472D2D589F2FC2BAD6E0816EC72CBF85CCA663D8A1EC6C51076D8"
+           "2D247E6C26811B7EC4D4300FB1F91028DCB7B2C4E7A60C151161AA7E65E79"
+           "B40917B12B2B5FBE7745984D4E8EFA31F9AE6062427B068B144A9CB155873"
+           "E7C0C9F0115E5AC72DC5A73C4796DB970BF9205AB8C77A6996EB1B417F9D1"
+           "6232431E6313C392203601B9C22CC10DDA88DCC6D282605F8DB67044F2DFD"
+           "3695E7BA63877AE16701536AE6567C794D0BFE338DFBB42D924CF964BD2C0"
+           "F586E03A2FCD35A408000000000000", buffer);
+
+  bignum.AssignBignum(bignum2);
+  bignum.MultiplyByPowerOfTen(100);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("46784A90ACD0ED3E7759CC585FB32D36EB6034A6F78D92604E3BAA5ED3D8B"
+           "6E60E854439BE448897FB4B7EA5A3D873AA0FCB3CFFD80D0530880E45F511"
+           "722A50CE7E058B5A6F5464DB7500E34984EE3202A9441F44FA1554C0CEA96"
+           "B438A36F25E7C9D56D71AE2CD313EC37534DA299AC0854FC48591A7CF3171"
+           "31265AA4AE62DE32344CE7BEEEF894AE686A2DAAFE5D6D9A10971FFD9C064"
+           "5079B209E1048F58B5192D41D84336AC4C8C489EEF00939CFC9D55C122036"
+           "01B9C22CC10DDA88DCC6D282605F8DB67044F2DFD3695E7BA3F67B96D3A32"
+           "E11FB5561B68744C4035B0800DC166D49D98E3FD1D5BB2000000000000000"
+           "0000000000", buffer);
+
+  bignum.AssignBignum(bignum2);
+  bignum.MultiplyByPowerOfTen(200);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("508BD351221DF139D72D88CDC0416845A53EE2D0E6B98352509A9AC312F8C"
+           "6CB1A144889416201E0B6CE66EA3EBE259B5FD79ECFC1FD77963CE516CC7E"
+           "2FE73D4B5B710C19F6BCB092C7A2FD76286543B8DBD2C596DFF2C896720BA"
+           "DFF7BC9C366ACEA3A880AEC287C5E6207DF2739B5326FC19D773BD830B109"
+           "ED36C7086544BF8FDB9D4B73719C2B5BC2F571A5937EC46876CD428281F6B"
+           "F287E1E07F25C1B1D46BC37324FF657A8B2E0071DB83B86123CA34004F406"
+           "001082D7945E90C6E8C9A9FEC2B44BE0DDA46E9F52B152E4D1336D2FCFBC9"
+           "96E30CA0082256737365158FE36482AA7EB9DAF2AB128F10E7551A3CD5BE6"
+           "0A922F3A7D5EED38B634A7EC95BCF7021BA6820A292000000000000000000"
+           "00000000000000000000000000000000", buffer);
+
+  bignum.AssignBignum(bignum2);
+  bignum.MultiplyByPowerOfTen(500);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("7845F900E475B5086885BAAAE67C8E85185ACFE4633727F82A4B06B5582AC"
+           "BE933C53357DA0C98C20C5AC900C4D76A97247DF52B79F48F9E35840FB715"
+           "D392CE303E22622B0CF82D9471B398457DD3196F639CEE8BBD2C146873841"
+           "F0699E6C41F04FC7A54B48CEB995BEB6F50FE81DE9D87A8D7F849CC523553"
+           "7B7BBBC1C7CAAFF6E9650BE03B308C6D31012AEF9580F70D3EE2083ADE126"
+           "8940FA7D6308E239775DFD2F8C97FF7EBD525DAFA6512216F7047A62A93DC"
+           "38A0165BDC67E250DCC96A0181DE935A70B38704DC71819F02FC5261FF7E1"
+           "E5F11907678B0A3E519FF4C10A867B0C26CE02BE6960BA8621A87303C101C"
+           "3F88798BB9F7739655946F8B5744E6B1EAF10B0C5621330F0079209033C69"
+           "20DE2E2C8D324F0624463735D482BF291926C22A910F5B80FA25170B6B57D"
+           "8D5928C7BCA3FE87461275F69BD5A1B83181DAAF43E05FC3C72C4E93111B6"
+           "6205EBF49B28FEDFB7E7526CBDA658A332000000000000000000000000000"
+           "0000000000000000000000000000000000000000000000000000000000000"
+           "0000000000000000000000000000000000000", buffer);
+}
+
+
+TEST(DivideModuloIntBignum) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+  Bignum other;
+  Bignum third;
+
+  bignum.AssignUInt16(10);
+  other.AssignUInt16(2);
+  CHECK_EQ(5, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("0", buffer);
+
+  bignum.AssignUInt16(10);
+  bignum.ShiftLeft(500);
+  other.AssignUInt16(2);
+  other.ShiftLeft(500);
+  CHECK_EQ(5, bignum.DivideModuloIntBignum(other));
+  CHECK_EQ("0", buffer);
+
+  bignum.AssignUInt16(11);
+  other.AssignUInt16(2);
+  CHECK_EQ(5, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignUInt16(10);
+  bignum.ShiftLeft(500);
+  other.AssignUInt16(1);
+  bignum.AddBignum(other);
+  other.AssignUInt16(2);
+  other.ShiftLeft(500);
+  CHECK_EQ(5, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignUInt16(10);
+  bignum.ShiftLeft(500);
+  other.AssignBignum(bignum);
+  bignum.MultiplyByUInt32(0x1234);
+  third.AssignUInt16(0xFFF);
+  bignum.AddBignum(third);
+  CHECK_EQ(0x1234, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFF", buffer);
+
+  bignum.AssignUInt16(10);
+  AssignHexString(&other, "1234567890");
+  CHECK_EQ(0, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A", buffer);
+
+  AssignHexString(&bignum, "12345678");
+  AssignHexString(&other, "3789012");
+  CHECK_EQ(5, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("D9861E", buffer);
+
+  AssignHexString(&bignum, "70000001");
+  AssignHexString(&other, "1FFFFFFF");
+  CHECK_EQ(3, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000004", buffer);
+
+  AssignHexString(&bignum, "28000000");
+  AssignHexString(&other, "12A05F20");
+  CHECK_EQ(2, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2BF41C0", buffer);
+
+  bignum.AssignUInt16(10);
+  bignum.ShiftLeft(500);
+  other.AssignBignum(bignum);
+  bignum.MultiplyByUInt32(0x1234);
+  third.AssignUInt16(0xFFF);
+  other.SubtractBignum(third);
+  CHECK_EQ(0x1234, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1232DCC", buffer);
+  CHECK_EQ(0, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1232DCC", buffer);
+}
+
+
+TEST(Compare) {
+  Bignum bignum1;
+  Bignum bignum2;
+  bignum1.AssignUInt16(1);
+  bignum2.AssignUInt16(1);
+  CHECK_EQ(0, Bignum::Compare(bignum1, bignum2));
+  CHECK(Bignum::Equal(bignum1, bignum2));
+  CHECK(Bignum::LessEqual(bignum1, bignum2));
+  CHECK(!Bignum::Less(bignum1, bignum2));
+
+  bignum1.AssignUInt16(0);
+  bignum2.AssignUInt16(1);
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+  CHECK(!Bignum::Equal(bignum1, bignum2));
+  CHECK(!Bignum::Equal(bignum2, bignum1));
+  CHECK(Bignum::LessEqual(bignum1, bignum2));
+  CHECK(!Bignum::LessEqual(bignum2, bignum1));
+  CHECK(Bignum::Less(bignum1, bignum2));
+  CHECK(!Bignum::Less(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "1234567890ABCDEF12345");
+  AssignHexString(&bignum2, "1234567890ABCDEF12345");
+  CHECK_EQ(0, Bignum::Compare(bignum1, bignum2));
+
+  AssignHexString(&bignum1, "1234567890ABCDEF12345");
+  AssignHexString(&bignum2, "1234567890ABCDEF12346");
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "1234567890ABCDEF12345");
+  bignum1.ShiftLeft(500);
+  AssignHexString(&bignum2, "1234567890ABCDEF12345");
+  bignum2.ShiftLeft(500);
+  CHECK_EQ(0, Bignum::Compare(bignum1, bignum2));
+
+  AssignHexString(&bignum1, "1234567890ABCDEF12345");
+  bignum1.ShiftLeft(500);
+  AssignHexString(&bignum2, "1234567890ABCDEF12346");
+  bignum2.ShiftLeft(500);
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+
+  bignum1.AssignUInt16(1);
+  bignum1.ShiftLeft(64);
+  AssignHexString(&bignum2, "10000000000000000");
+  CHECK_EQ(0, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(0, Bignum::Compare(bignum2, bignum1));
+
+  bignum1.AssignUInt16(1);
+  bignum1.ShiftLeft(64);
+  AssignHexString(&bignum2, "10000000000000001");
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+
+  bignum1.AssignUInt16(1);
+  bignum1.ShiftLeft(96);
+  AssignHexString(&bignum2, "10000000000000001");
+  bignum2.ShiftLeft(32);
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "FFFFFFFFFFFFFFFF");
+  bignum2.AssignUInt16(1);
+  bignum2.ShiftLeft(64);
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "FFFFFFFFFFFFFFFF");
+  bignum1.ShiftLeft(32);
+  bignum2.AssignUInt16(1);
+  bignum2.ShiftLeft(96);
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "FFFFFFFFFFFFFFFF");
+  bignum1.ShiftLeft(32);
+  bignum2.AssignUInt16(1);
+  bignum2.ShiftLeft(95);
+  CHECK_EQ(+1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(-1, Bignum::Compare(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "FFFFFFFFFFFFFFFF");
+  bignum1.ShiftLeft(32);
+  bignum2.AssignUInt16(1);
+  bignum2.ShiftLeft(100);
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "100000000000000");
+  bignum2.AssignUInt16(1);
+  bignum2.ShiftLeft(14*4);
+  CHECK_EQ(0, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(0, Bignum::Compare(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "100000000000001");
+  bignum2.AssignUInt16(1);
+  bignum2.ShiftLeft(14*4);
+  CHECK_EQ(+1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(-1, Bignum::Compare(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "200000000000000");
+  bignum2.AssignUInt16(3);
+  bignum2.ShiftLeft(14*4);
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+}
+
+
+TEST(PlusCompare) {
+  Bignum a;
+  Bignum b;
+  Bignum c;
+  a.AssignUInt16(1);
+  b.AssignUInt16(0);
+  c.AssignUInt16(1);
+  CHECK_EQ(0, Bignum::PlusCompare(a, b, c));
+  CHECK(Bignum::PlusEqual(a, b, c));
+  CHECK(Bignum::PlusLessEqual(a, b, c));
+  CHECK(!Bignum::PlusLess(a, b, c));
+
+  a.AssignUInt16(0);
+  b.AssignUInt16(0);
+  c.AssignUInt16(1);
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+  CHECK_EQ(+1, Bignum::PlusCompare(c, b, a));
+  CHECK(!Bignum::PlusEqual(a, b, c));
+  CHECK(!Bignum::PlusEqual(c, b, a));
+  CHECK(Bignum::PlusLessEqual(a, b, c));
+  CHECK(!Bignum::PlusLessEqual(c, b, a));
+  CHECK(Bignum::PlusLess(a, b, c));
+  CHECK(!Bignum::PlusLess(c, b, a));
+
+  AssignHexString(&a, "1234567890ABCDEF12345");
+  b.AssignUInt16(1);
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  CHECK_EQ(+1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890ABCDEF12344");
+  b.AssignUInt16(1);
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  CHECK_EQ(0, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4);
+  AssignHexString(&b, "ABCDEF12345");
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  CHECK_EQ(0, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4);
+  AssignHexString(&b, "ABCDEF12344");
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4);
+  AssignHexString(&b, "ABCDEF12346");
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  CHECK_EQ(1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567891");
+  a.ShiftLeft(11*4);
+  AssignHexString(&b, "ABCDEF12345");
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  CHECK_EQ(1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567889");
+  a.ShiftLeft(11*4);
+  AssignHexString(&b, "ABCDEF12345");
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  c.ShiftLeft(32);
+  CHECK_EQ(0, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12344");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  c.ShiftLeft(32);
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12346");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  c.ShiftLeft(32);
+  CHECK_EQ(1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567891");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  c.ShiftLeft(32);
+  CHECK_EQ(1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567889");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  c.ShiftLeft(32);
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF1234500000000");
+  CHECK_EQ(0, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12344");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF1234500000000");
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12346");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF1234500000000");
+  CHECK_EQ(1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567891");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF1234500000000");
+  CHECK_EQ(1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567889");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF1234500000000");
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  AssignHexString(&c, "123456789000000000ABCDEF12345");
+  CHECK_EQ(0, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12346");
+  AssignHexString(&c, "123456789000000000ABCDEF12345");
+  CHECK_EQ(1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12344");
+  AssignHexString(&c, "123456789000000000ABCDEF12345");
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  b.ShiftLeft(16);
+  AssignHexString(&c, "12345678900000ABCDEF123450000");
+  CHECK_EQ(0, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12344");
+  b.ShiftLeft(16);
+  AssignHexString(&c, "12345678900000ABCDEF123450000");
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  b.ShiftLeft(16);
+  AssignHexString(&c, "12345678900000ABCDEF123450001");
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12346");
+  b.ShiftLeft(16);
+  AssignHexString(&c, "12345678900000ABCDEF123450000");
+  CHECK_EQ(+1, Bignum::PlusCompare(a, b, c));
+}
+
+
+TEST(Square) {
+  Bignum bignum;
+  char buffer[kBufferSize];
+
+  bignum.AssignUInt16(1);
+  bignum.Square();
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignUInt16(2);
+  bignum.Square();
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("4", buffer);
+
+  bignum.AssignUInt16(10);
+  bignum.Square();
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("64", buffer);
+
+  AssignHexString(&bignum, "FFFFFFF");
+  bignum.Square();
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFE0000001", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFF");
+  bignum.Square();
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFFE00000000000001", buffer);
+}
+
+
+TEST(AssignPowerUInt16) {
+  Bignum bignum;
+  char buffer[kBufferSize];
+
+  bignum.AssignPowerUInt16(1, 0);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignPowerUInt16(1, 1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignPowerUInt16(1, 2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignPowerUInt16(2, 0);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignPowerUInt16(2, 1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2", buffer);
+
+  bignum.AssignPowerUInt16(2, 2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("4", buffer);
+
+  bignum.AssignPowerUInt16(16, 1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10", buffer);
+
+  bignum.AssignPowerUInt16(16, 2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100", buffer);
+
+  bignum.AssignPowerUInt16(16, 5);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100000", buffer);
+
+  bignum.AssignPowerUInt16(16, 8);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100000000", buffer);
+
+  bignum.AssignPowerUInt16(16, 16);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000", buffer);
+
+  bignum.AssignPowerUInt16(16, 30);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1000000000000000000000000000000", buffer);
+
+  bignum.AssignPowerUInt16(10, 0);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignPowerUInt16(10, 1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A", buffer);
+
+  bignum.AssignPowerUInt16(10, 2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("64", buffer);
+
+  bignum.AssignPowerUInt16(10, 5);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("186A0", buffer);
+
+  bignum.AssignPowerUInt16(10, 8);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("5F5E100", buffer);
+
+  bignum.AssignPowerUInt16(10, 16);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2386F26FC10000", buffer);
+
+  bignum.AssignPowerUInt16(10, 30);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("C9F2C9CD04674EDEA40000000", buffer);
+
+  bignum.AssignPowerUInt16(10, 31);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("7E37BE2022C0914B2680000000", buffer);
+
+  bignum.AssignPowerUInt16(2, 0);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignPowerUInt16(2, 100);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000000000000", buffer);
+
+  bignum.AssignPowerUInt16(17, 0);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignPowerUInt16(17, 99);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1942BB9853FAD924A3D4DD92B89B940E0207BEF05DB9C26BC1B757"
+           "80BE0C5A2C2990E02A681224F34ED68558CE4C6E33760931",
+           buffer);
+
+  bignum.AssignPowerUInt16(0xFFFF, 99);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FF9D12F09B886C54E77E7439C7D2DED2D34F669654C0C2B6B8C288250"
+           "5A2211D0E3DC9A61831349EAE674B11D56E3049D7BD79DAAD6C9FA2BA"
+           "528E3A794299F2EE9146A324DAFE3E88967A0358233B543E233E575B9"
+           "DD4E3AA7942146426C328FF55BFD5C45E0901B1629260AF9AE2F310C5"
+           "50959FAF305C30116D537D80CF6EBDBC15C5694062AF1AC3D956D0A41"
+           "B7E1B79FF11E21D83387A1CE1F5882B31E4B5D8DE415BDBE6854466DF"
+           "343362267A7E8833119D31D02E18DB5B0E8F6A64B0ED0D0062FFFF",
+           buffer);
+}
diff --git a/test/cctest/test-double.cc b/test/cctest/test-double.cc
index a7a604e..3594a4f 100644
--- a/test/cctest/test-double.cc
+++ b/test/cctest/test-double.cc
@@ -202,3 +202,19 @@
   CHECK(diy_fp.f() - boundary_minus.f() == boundary_plus.f() - diy_fp.f());
   CHECK((1 << 10) == diy_fp.f() - boundary_minus.f());  // NOLINT
 }
+
+
+TEST(NextDouble) {
+  CHECK_EQ(4e-324, Double(0.0).NextDouble());
+  CHECK_EQ(0.0, Double(-0.0).NextDouble());
+  CHECK_EQ(-0.0, Double(-4e-324).NextDouble());
+  Double d0(-4e-324);
+  Double d1(d0.NextDouble());
+  Double d2(d1.NextDouble());
+  CHECK_EQ(-0.0, d1.value());
+  CHECK_EQ(0.0, d2.value());
+  CHECK_EQ(4e-324, d2.NextDouble());
+  CHECK_EQ(-1.7976931348623157e308, Double(-V8_INFINITY).NextDouble());
+  CHECK_EQ(V8_INFINITY,
+           Double(V8_2PART_UINT64_C(0x7fefffff, ffffffff)).NextDouble());
+}
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
index b86a336..b165190 100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -388,14 +388,10 @@
 class NamedEntriesDetector {
  public:
   NamedEntriesDetector()
-      : has_A1(false), has_B1(false), has_C1(false),
-        has_A2(false), has_B2(false), has_C2(false) {
+      : has_A2(false), has_B2(false), has_C2(false) {
   }
 
   void Apply(i::HeapEntry** entry_ptr) {
-    if (IsReachableNodeWithName(*entry_ptr, "A1")) has_A1 = true;
-    if (IsReachableNodeWithName(*entry_ptr, "B1")) has_B1 = true;
-    if (IsReachableNodeWithName(*entry_ptr, "C1")) has_C1 = true;
     if (IsReachableNodeWithName(*entry_ptr, "A2")) has_A2 = true;
     if (IsReachableNodeWithName(*entry_ptr, "B2")) has_B2 = true;
     if (IsReachableNodeWithName(*entry_ptr, "C2")) has_C2 = true;
@@ -405,9 +401,6 @@
     return strcmp(name, entry->name()) == 0 && entry->painted_reachable();
   }
 
-  bool has_A1;
-  bool has_B1;
-  bool has_C1;
   bool has_A2;
   bool has_B2;
   bool has_C2;
@@ -464,21 +457,7 @@
 
 TEST(HeapSnapshot) {
   v8::HandleScope scope;
-  v8::Handle<v8::String> token1 = v8::String::New("token1");
-  LocalContext env1;
-  env1->SetSecurityToken(token1);
-
-  CompileRun(
-      "function A1() {}\n"
-      "function B1(x) { this.x = x; }\n"
-      "function C1(x) { this.x1 = x; this.x2 = x; }\n"
-      "var a1 = new A1();\n"
-      "var b1_1 = new B1(a1), b1_2 = new B1(a1);\n"
-      "var c1 = new C1(a1);");
-
-  v8::Handle<v8::String> token2 = v8::String::New("token2");
   LocalContext env2;
-  env2->SetSecurityToken(token2);
 
   CompileRun(
       "function A2() {}\n"
@@ -498,14 +477,7 @@
   const_cast<i::HeapEntry*>(
       reinterpret_cast<const i::HeapEntry*>(global_env2))->PaintAllReachable();
 
-  // Verify, that JS global object of env2 doesn't have '..1'
-  // properties, but has '..2' properties.
-  CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "a1"));
-  CHECK_EQ(
-      NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b1_1"));
-  CHECK_EQ(
-      NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b1_2"));
-  CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "c1"));
+  // Verify, that JS global object of env2 has '..2' properties.
   const v8::HeapGraphNode* a2_node =
       GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "a2");
   CHECK_NE(NULL, a2_node);
@@ -518,9 +490,6 @@
   // Verify that anything related to '[ABC]1' is not reachable.
   NamedEntriesDetector det;
   i_snapshot_env2->IterateEntries(&det);
-  CHECK(!det.has_A1);
-  CHECK(!det.has_B1);
-  CHECK(!det.has_C1);
   CHECK(det.has_A2);
   CHECK(det.has_B2);
   CHECK(det.has_C2);
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index ea5afec..9942567 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -75,7 +75,7 @@
   // from new space.
   FLAG_gc_global = true;
   FLAG_always_compact = true;
-  Heap::ConfigureHeap(2*256*KB, 4*MB);
+  Heap::ConfigureHeap(2*256*KB, 4*MB, 4*MB);
 
   InitializeVM();
 
@@ -101,7 +101,7 @@
 
 
 TEST(NoPromotion) {
-  Heap::ConfigureHeap(2*256*KB, 4*MB);
+  Heap::ConfigureHeap(2*256*KB, 4*MB, 4*MB);
 
   // Test the situation that some objects in new space are promoted to
   // the old space
diff --git a/test/cctest/test-spaces.cc b/test/cctest/test-spaces.cc
index 06f1bfa..b399a4e 100644
--- a/test/cctest/test-spaces.cc
+++ b/test/cctest/test-spaces.cc
@@ -91,7 +91,7 @@
 
 TEST(MemoryAllocator) {
   CHECK(Heap::ConfigureHeapDefault());
-  CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
+  CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
 
   OldSpace faked_space(Heap::MaxReserved(), OLD_POINTER_SPACE, NOT_EXECUTABLE);
   int total_pages = 0;
@@ -147,7 +147,7 @@
 
 TEST(NewSpace) {
   CHECK(Heap::ConfigureHeapDefault());
-  CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
+  CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
 
   NewSpace new_space;
 
@@ -172,7 +172,7 @@
 
 TEST(OldSpace) {
   CHECK(Heap::ConfigureHeapDefault());
-  CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
+  CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
 
   OldSpace* s = new OldSpace(Heap::MaxOldGenerationSize(),
                              OLD_POINTER_SPACE,
diff --git a/test/cctest/test-strtod.cc b/test/cctest/test-strtod.cc
index 56b26ea..d71d126 100644
--- a/test/cctest/test-strtod.cc
+++ b/test/cctest/test-strtod.cc
@@ -4,7 +4,10 @@
 
 #include "v8.h"
 
+#include "bignum.h"
 #include "cctest.h"
+#include "diy-fp.h"
+#include "double.h"
 #include "strtod.h"
 
 using namespace v8::internal;
@@ -202,11 +205,14 @@
   CHECK_EQ(1.7976931348623158E+308, StrtodChar("17976931348623158", 292));
   CHECK_EQ(V8_INFINITY, StrtodChar("17976931348623159", 292));
 
-  // The following number is the result of 89255.0/1e-22. Both floating-point
+  // The following number is the result of 89255.0/1e22. Both floating-point
   // numbers can be accurately represented with doubles. However on Linux,x86
   // the floating-point stack is set to 80bits and the double-rounding
   // introduces an error.
   CHECK_EQ(89255e-22, StrtodChar("89255", -22));
+
+  // Some random values.
+  CHECK_EQ(358416272e-33, StrtodChar("358416272", -33));
   CHECK_EQ(104110013277974872254e-225,
            StrtodChar("104110013277974872254", -225));
 
@@ -252,4 +258,160 @@
            StrtodChar("1234567890123456789052345", 114));
   CHECK_EQ(1234567890123456789052345e115,
            StrtodChar("1234567890123456789052345", 115));
+
+  // Boundary cases. Boundaries themselves should round to even.
+  //
+  // 0x1FFFFFFFFFFFF * 2^3 = 72057594037927928
+  //                   next: 72057594037927936
+  //               boundary: 72057594037927932  should round up.
+  CHECK_EQ(72057594037927928.0, StrtodChar("72057594037927928", 0));
+  CHECK_EQ(72057594037927936.0, StrtodChar("72057594037927936", 0));
+  CHECK_EQ(72057594037927936.0, StrtodChar("72057594037927932", 0));
+  CHECK_EQ(72057594037927928.0, StrtodChar("7205759403792793199999", -5));
+  CHECK_EQ(72057594037927936.0, StrtodChar("7205759403792793200001", -5));
+
+  // 0x1FFFFFFFFFFFF * 2^10 = 9223372036854774784
+  //                    next: 9223372036854775808
+  //                boundary: 9223372036854775296 should round up.
+  CHECK_EQ(9223372036854774784.0, StrtodChar("9223372036854774784", 0));
+  CHECK_EQ(9223372036854775808.0, StrtodChar("9223372036854775808", 0));
+  CHECK_EQ(9223372036854775808.0, StrtodChar("9223372036854775296", 0));
+  CHECK_EQ(9223372036854774784.0, StrtodChar("922337203685477529599999", -5));
+  CHECK_EQ(9223372036854775808.0, StrtodChar("922337203685477529600001", -5));
+
+  // 0x1FFFFFFFFFFFF * 2^50 = 10141204801825834086073718800384
+  //                    next: 10141204801825835211973625643008
+  //                boundary: 10141204801825834649023672221696 should round up.
+  CHECK_EQ(10141204801825834086073718800384.0,
+           StrtodChar("10141204801825834086073718800384", 0));
+  CHECK_EQ(10141204801825835211973625643008.0,
+           StrtodChar("10141204801825835211973625643008", 0));
+  CHECK_EQ(10141204801825835211973625643008.0,
+           StrtodChar("10141204801825834649023672221696", 0));
+  CHECK_EQ(10141204801825834086073718800384.0,
+           StrtodChar("1014120480182583464902367222169599999", -5));
+  CHECK_EQ(10141204801825835211973625643008.0,
+           StrtodChar("1014120480182583464902367222169600001", -5));
+
+  // 0x1FFFFFFFFFFFF * 2^99 = 5708990770823838890407843763683279797179383808
+  //                    next: 5708990770823839524233143877797980545530986496
+  //                boundary: 5708990770823839207320493820740630171355185152
+  // The boundary should round up.
+  CHECK_EQ(5708990770823838890407843763683279797179383808.0,
+           StrtodChar("5708990770823838890407843763683279797179383808", 0));
+  CHECK_EQ(5708990770823839524233143877797980545530986496.0,
+           StrtodChar("5708990770823839524233143877797980545530986496", 0));
+  CHECK_EQ(5708990770823839524233143877797980545530986496.0,
+           StrtodChar("5708990770823839207320493820740630171355185152", 0));
+  CHECK_EQ(5708990770823838890407843763683279797179383808.0,
+           StrtodChar("5708990770823839207320493820740630171355185151999", -3));
+  CHECK_EQ(5708990770823839524233143877797980545530986496.0,
+           StrtodChar("5708990770823839207320493820740630171355185152001", -3));
+}
+
+
+static int CompareBignumToDiyFp(const Bignum& bignum_digits,
+                                int bignum_exponent,
+                                DiyFp diy_fp) {
+  Bignum bignum;
+  bignum.AssignBignum(bignum_digits);
+  Bignum other;
+  other.AssignUInt64(diy_fp.f());
+  if (bignum_exponent >= 0) {
+    bignum.MultiplyByPowerOfTen(bignum_exponent);
+  } else {
+    other.MultiplyByPowerOfTen(-bignum_exponent);
+  }
+  if (diy_fp.e() >= 0) {
+    other.ShiftLeft(diy_fp.e());
+  } else {
+    bignum.ShiftLeft(-diy_fp.e());
+  }
+  return Bignum::Compare(bignum, other);
+}
+
+
+static bool CheckDouble(Vector<const char> buffer,
+                        int exponent,
+                        double to_check) {
+  DiyFp lower_boundary;
+  DiyFp upper_boundary;
+  Bignum input_digits;
+  input_digits.AssignDecimalString(buffer);
+  if (to_check == 0.0) {
+    const double kMinDouble = 4e-324;
+    // Check that the buffer*10^exponent < (0 + kMinDouble)/2.
+    Double d(kMinDouble);
+    d.NormalizedBoundaries(&lower_boundary, &upper_boundary);
+    return CompareBignumToDiyFp(input_digits, exponent, lower_boundary) <= 0;
+  }
+  if (to_check == V8_INFINITY) {
+    const double kMaxDouble = 1.7976931348623157e308;
+    // Check that the buffer*10^exponent >= boundary between kMaxDouble and inf.
+    Double d(kMaxDouble);
+    d.NormalizedBoundaries(&lower_boundary, &upper_boundary);
+    return CompareBignumToDiyFp(input_digits, exponent, upper_boundary) >= 0;
+  }
+  Double d(to_check);
+  d.NormalizedBoundaries(&lower_boundary, &upper_boundary);
+  if ((d.Significand() & 1) == 0) {
+    return CompareBignumToDiyFp(input_digits, exponent, lower_boundary) >= 0 &&
+        CompareBignumToDiyFp(input_digits, exponent, upper_boundary) <= 0;
+  } else {
+    return CompareBignumToDiyFp(input_digits, exponent, lower_boundary) > 0 &&
+        CompareBignumToDiyFp(input_digits, exponent, upper_boundary) < 0;
+  }
+}
+
+
+// Copied from v8.cc and adapted to make the function deterministic.
+static uint32_t DeterministicRandom() {
+  // Random number generator using George Marsaglia's MWC algorithm.
+  static uint32_t hi = 0;
+  static uint32_t lo = 0;
+
+  // Initialization values don't have any special meaning. (They are the result
+  // of two calls to random().)
+  if (hi == 0) hi = 0xbfe166e7;
+  if (lo == 0) lo = 0x64d1c3c9;
+
+  // Mix the bits.
+  hi = 36969 * (hi & 0xFFFF) + (hi >> 16);
+  lo = 18273 * (lo & 0xFFFF) + (lo >> 16);
+  return (hi << 16) + (lo & 0xFFFF);
+}
+
+
+static const int kBufferSize = 1024;
+static const int kShortStrtodRandomCount = 2;
+static const int kLargeStrtodRandomCount = 2;
+
+TEST(RandomStrtod) {
+  char buffer[kBufferSize];
+  for (int length = 1; length < 15; length++) {
+    for (int i = 0; i < kShortStrtodRandomCount; ++i) {
+      int pos = 0;
+      for (int j = 0; j < length; ++j) {
+        buffer[pos++] = random() % 10 + '0';
+      }
+      int exponent = DeterministicRandom() % (25*2 + 1) - 25 - length;
+      buffer[pos] = '\0';
+      Vector<const char> vector(buffer, pos);
+      double strtod_result = Strtod(vector, exponent);
+      CHECK(CheckDouble(vector, exponent, strtod_result));
+    }
+  }
+  for (int length = 15; length < 800; length += 2) {
+    for (int i = 0; i < kLargeStrtodRandomCount; ++i) {
+      int pos = 0;
+      for (int j = 0; j < length; ++j) {
+        buffer[pos++] = random() % 10 + '0';
+      }
+      int exponent = DeterministicRandom() % (308*2 + 1) - 308 - length;
+      buffer[pos] = '\0';
+      Vector<const char> vector(buffer, pos);
+      double strtod_result = Strtod(vector, exponent);
+      CHECK(CheckDouble(vector, exponent, strtod_result));
+    }
+  }
 }
diff --git a/test/mjsunit/regress/regress-927.js b/test/mjsunit/regress/regress-927.js
new file mode 100644
index 0000000..c671f7d
--- /dev/null
+++ b/test/mjsunit/regress/regress-927.js
@@ -0,0 +1,33 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function a1() {
+    var a2 = -1756315459;
+    return ((((a2 & a2) ^ 1) * a2) << -10);
+}
+
+assertEquals(a1(), -2147483648);
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index 3e40fcc..65b8620 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -280,6 +280,8 @@
         '../../src/ast.cc',
         '../../src/ast-inl.h',
         '../../src/ast.h',
+        '../../src/bignum.cc',
+        '../../src/bignum.h',
         '../../src/bootstrapper.cc',
         '../../src/bootstrapper.h',
         '../../src/builtins.cc',
diff --git a/tools/visual_studio/v8_base.vcproj b/tools/visual_studio/v8_base.vcproj
index bddf38e..d1ee48d 100644
--- a/tools/visual_studio/v8_base.vcproj
+++ b/tools/visual_studio/v8_base.vcproj
@@ -145,6 +145,22 @@
 				</FileConfiguration>
 			</File>
     		<File
+				RelativePath="..\..\src\bignum.cc"
+				>
+			</File>
+    		<File
+				RelativePath="..\..\src\bignum.h"
+				>
+			</File>
+    		<File
+				RelativePath="..\..\src\bignum-dtoa.cc"
+				>
+			</File>
+    		<File
+				RelativePath="..\..\src\bignum-dtoa.h"
+				>
+			</File>
+    		<File
 				RelativePath="..\..\src\dtoa.cc"
 				>
 			</File>
@@ -241,6 +257,22 @@
 				>
 			</File>
 			<File
+				RelativePath="..\..\src\bignum.cc"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\bignum.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\bignum-dtoa.cc"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\bignum-dtoa.h"
+				>
+			</File>
+			<File
 				RelativePath="..\..\src\bootstrapper.cc"
 				>
 			</File>