Implement Math.random() purely in JavaScript.
authorsvenpanne@chromium.org <svenpanne@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 21 Nov 2013 09:55:15 +0000 (09:55 +0000)
committersvenpanne@chromium.org <svenpanne@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 21 Nov 2013 09:55:15 +0000 (09:55 +0000)
This removes tons of architecture-specific code and makes it easy to
experiment with other pseudo-RNG algorithms. The crankshafted code is
extremely good, keeping all things unboxed and doing only minimal
checks, so it is basically equivalent to the handwritten code.

When benchmarks are run without parallel recompilation, we get a few
percent regression on SunSpider's string-validate-input and
string-base64, but these benchmarks run so fast that the overall
SunSpider score is hardly affected and within the usual jitter. Note
that these benchmarks actually run even faster when we don't
crankshaft at all on the main thread (the regression is not caused by
bad code, it is caused by Crankshaft needing a few hundred microsecond
for compilation of a trivial function). Luckily, when parallel
recompilation is enabled, i.e. in the browser, we see no regression at
all!

R=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/68723002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17955 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

31 files changed:
src/arm/full-codegen-arm.cc
src/arm/lithium-arm.cc
src/arm/lithium-arm.h
src/arm/lithium-codegen-arm.cc
src/assembler.cc
src/assembler.h
src/bootstrapper.cc
src/contexts.h
src/globals.h
src/heap.cc
src/hydrogen-instructions.h
src/hydrogen.cc
src/ia32/full-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h
src/math.js
src/mips/full-codegen-mips.cc
src/mips/lithium-codegen-mips.cc
src/mips/lithium-mips.cc
src/mips/lithium-mips.h
src/objects.h
src/runtime.h
src/serialize.cc
src/v8.cc
src/v8.h
src/x64/full-codegen-x64.cc
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc
src/x64/lithium-x64.h
test/cctest/test-weaktypedarrays.cc

index 64a9fdf..4a39970 100644 (file)
@@ -3347,50 +3347,6 @@ void FullCodeGenerator::EmitLog(CallRuntime* expr) {
 }
 
 
-void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
-  ASSERT(expr->arguments()->length() == 0);
-  Label slow_allocate_heapnumber;
-  Label heapnumber_allocated;
-
-  __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
-  __ AllocateHeapNumber(r4, r1, r2, r6, &slow_allocate_heapnumber);
-  __ jmp(&heapnumber_allocated);
-
-  __ bind(&slow_allocate_heapnumber);
-  // Allocate a heap number.
-  __ CallRuntime(Runtime::kNumberAlloc, 0);
-  __ mov(r4, Operand(r0));
-
-  __ bind(&heapnumber_allocated);
-
-  // Convert 32 random bits in r0 to 0.(32 random bits) in a double
-  // by computing:
-  // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
-  __ PrepareCallCFunction(1, r0);
-  __ ldr(r0,
-         ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX));
-  __ ldr(r0, FieldMemOperand(r0, GlobalObject::kNativeContextOffset));
-  __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
-
-  // 0x41300000 is the top half of 1.0 x 2^20 as a double.
-  // Create this constant using mov/orr to avoid PC relative load.
-  __ mov(r1, Operand(0x41000000));
-  __ orr(r1, r1, Operand(0x300000));
-  // Move 0x41300000xxxxxxxx (x = random bits) to VFP.
-  __ vmov(d7, r0, r1);
-  // Move 0x4130000000000000 to VFP.
-  __ mov(r0, Operand::Zero());
-  __ vmov(d8, r0, r1);
-  // Subtract and store the result in the heap number.
-  __ vsub(d7, d7, d8);
-  __ sub(r0, r4, Operand(kHeapObjectTag));
-  __ vstr(d7, r0, HeapNumber::kValueOffset);
-  __ mov(r0, r4);
-
-  context()->Plug(r0);
-}
-
-
 void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
   // Load the arguments on the stack and call the stub.
   SubStringStub stub;
index a1e892b..eeffc16 100644 (file)
@@ -1720,19 +1720,6 @@ LInstruction* LChunkBuilder::DoPower(HPower* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
-  ASSERT(instr->representation().IsDouble());
-  ASSERT(instr->global_object()->representation().IsTagged());
-  LOperand* global_object = UseTempRegister(instr->global_object());
-  LOperand* scratch = TempRegister();
-  LOperand* scratch2 = TempRegister();
-  LOperand* scratch3 = TempRegister();
-  LRandom* result = new(zone()) LRandom(
-      global_object, scratch, scratch2, scratch3);
-  return DefineFixedDouble(result, d7);
-}
-
-
 LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
   ASSERT(instr->left()->representation().IsTagged());
   ASSERT(instr->right()->representation().IsTagged());
index 5b9278b..72932de 100644 (file)
@@ -155,7 +155,6 @@ class LCodeGen;
   V(Parameter)                                  \
   V(Power)                                      \
   V(PushArgument)                               \
-  V(Random)                                     \
   V(RegExpLiteral)                              \
   V(Return)                                     \
   V(SeqStringGetChar)                           \
@@ -1481,28 +1480,6 @@ class LPower V8_FINAL : public LTemplateInstruction<1, 2, 0> {
 };
 
 
-class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 3> {
- public:
-  LRandom(LOperand* global_object,
-          LOperand* scratch,
-          LOperand* scratch2,
-          LOperand* scratch3) {
-    inputs_[0] = global_object;
-    temps_[0] = scratch;
-    temps_[1] = scratch2;
-    temps_[2] = scratch3;
-  }
-
-  LOperand* global_object() const { return inputs_[0]; }
-  LOperand* scratch() const { return temps_[0]; }
-  LOperand* scratch2() const { return temps_[1]; }
-  LOperand* scratch3() const { return temps_[2]; }
-
-  DECLARE_CONCRETE_INSTRUCTION(Random, "random")
-  DECLARE_HYDROGEN_ACCESSOR(Random)
-};
-
-
 class LArithmeticD V8_FINAL : public LTemplateInstruction<1, 2, 0> {
  public:
   LArithmeticD(Token::Value op, LOperand* left, LOperand* right)
index 0aa8197..cd9c712 100644 (file)
@@ -3934,68 +3934,6 @@ void LCodeGen::DoPower(LPower* instr) {
 }
 
 
-void LCodeGen::DoRandom(LRandom* instr) {
-  // Assert that the register size is indeed the size of each seed.
-  static const int kSeedSize = sizeof(uint32_t);
-  STATIC_ASSERT(kPointerSize == kSeedSize);
-
-  // Load native context
-  Register global_object = ToRegister(instr->global_object());
-  Register native_context = global_object;
-  __ ldr(native_context, FieldMemOperand(
-          global_object, GlobalObject::kNativeContextOffset));
-
-  // Load state (FixedArray of the native context's random seeds)
-  static const int kRandomSeedOffset =
-      FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
-  Register state = native_context;
-  __ ldr(state, FieldMemOperand(native_context, kRandomSeedOffset));
-
-  // Load state[0].
-  Register state0 = ToRegister(instr->scratch());
-  __ ldr(state0, FieldMemOperand(state, ByteArray::kHeaderSize));
-  // Load state[1].
-  Register state1 = ToRegister(instr->scratch2());
-  __ ldr(state1, FieldMemOperand(state, ByteArray::kHeaderSize + kSeedSize));
-
-  // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
-  Register scratch3 = ToRegister(instr->scratch3());
-  Register scratch4 = scratch0();
-  __ and_(scratch3, state0, Operand(0xFFFF));
-  __ mov(scratch4, Operand(18273));
-  __ mul(scratch3, scratch3, scratch4);
-  __ add(state0, scratch3, Operand(state0, LSR, 16));
-  // Save state[0].
-  __ str(state0, FieldMemOperand(state, ByteArray::kHeaderSize));
-
-  // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
-  __ and_(scratch3, state1, Operand(0xFFFF));
-  __ mov(scratch4, Operand(36969));
-  __ mul(scratch3, scratch3, scratch4);
-  __ add(state1, scratch3, Operand(state1, LSR, 16));
-  // Save state[1].
-  __ str(state1, FieldMemOperand(state, ByteArray::kHeaderSize + kSeedSize));
-
-  // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
-  Register random = scratch4;
-  __ and_(random, state1, Operand(0x3FFFF));
-  __ add(random, random, Operand(state0, LSL, 14));
-
-  // 0x41300000 is the top half of 1.0 x 2^20 as a double.
-  // Create this constant using mov/orr to avoid PC relative load.
-  __ mov(scratch3, Operand(0x41000000));
-  __ orr(scratch3, scratch3, Operand(0x300000));
-  // Move 0x41300000xxxxxxxx (x = random bits) to VFP.
-  DwVfpRegister result = ToDoubleRegister(instr->result());
-  __ vmov(result, random, scratch3);
-  // Move 0x4130000000000000 to VFP.
-  __ mov(scratch4, Operand::Zero());
-  DwVfpRegister scratch5 = double_scratch0();
-  __ vmov(scratch5, scratch4, scratch3);
-  __ vsub(result, result, scratch5);
-}
-
-
 void LCodeGen::DoMathExp(LMathExp* instr) {
   DwVfpRegister input = ToDoubleRegister(instr->value());
   DwVfpRegister result = ToDoubleRegister(instr->result());
index fa0b4c3..febae63 100644 (file)
@@ -1061,12 +1061,6 @@ ExternalReference ExternalReference::delete_handle_scope_extensions(
 }
 
 
-ExternalReference ExternalReference::random_uint32_function(
-    Isolate* isolate) {
-  return ExternalReference(Redirect(isolate, FUNCTION_ADDR(V8::Random)));
-}
-
-
 ExternalReference ExternalReference::get_date_field_function(
     Isolate* isolate) {
   return ExternalReference(Redirect(isolate, FUNCTION_ADDR(JSDate::GetField)));
index 049fa8c..0c706c4 100644 (file)
@@ -718,7 +718,6 @@ class ExternalReference BASE_EMBEDDED {
       Isolate* isolate);
   static ExternalReference flush_icache_function(Isolate* isolate);
   static ExternalReference perform_gc_function(Isolate* isolate);
-  static ExternalReference random_uint32_function(Isolate* isolate);
   static ExternalReference transcendental_cache_array_address(Isolate* isolate);
   static ExternalReference delete_handle_scope_extensions(Isolate* isolate);
 
index bc52fa8..a2d13d1 100644 (file)
@@ -1308,10 +1308,6 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
   // Initialize the embedder data slot.
   Handle<FixedArray> embedder_data = factory->NewFixedArray(2);
   native_context()->set_embedder_data(*embedder_data);
-
-  // Allocate the random seed slot.
-  Handle<ByteArray> random_seed = factory->NewByteArray(kRandomStateSize);
-  native_context()->set_random_seed(*random_seed);
 }
 
 
@@ -2635,13 +2631,36 @@ Genesis::Genesis(Isolate* isolate,
   InitializeExperimentalGlobal();
   if (!InstallExperimentalNatives()) return;
 
-  // Initially seed the per-context random number generator
-  // using the per-isolate random number generator.
-  uint32_t* state = reinterpret_cast<uint32_t*>(
-      native_context()->random_seed()->GetDataStartAddress());
-  do {
-    isolate->random_number_generator()->NextBytes(state, kRandomStateSize);
-  } while (state[0] == 0 || state[1] == 0);
+  // We can't (de-)serialize typed arrays currently, but we are lucky: The state
+  // of the random number generator needs no initialization during snapshot
+  // creation time.
+  if (!Serializer::enabled()) {
+    // Initially seed the per-context random number generator using the
+    // per-isolate random number generator.
+    const int num_elems = 2;
+    uint32_t* state = new uint32_t[num_elems];
+    const int num_bytes = num_elems * sizeof(*state);
+    // We have to delete the state when the context dies, so we remember it in
+    // the context (encoded as a Smi, our usual technique for aligned pointers)
+    // and do the cleanup in WeakListVisitor<Context>::VisitPhantomObject().
+    // This hack can go away when we have a way to allocate the backing store of
+    // typed arrays on the heap.
+    native_context()->set_random_state(reinterpret_cast<Smi*>(state));
+    ASSERT(native_context()->random_state()->IsSmi());
+
+    do {
+      isolate->random_number_generator()->NextBytes(state, num_bytes);
+    } while (state[0] == 0 || state[1] == 0);
+
+    v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(state, num_bytes);
+    v8::Local<v8::Uint32Array> ta = v8::Uint32Array::New(buffer, 0, num_elems);
+    Handle<JSBuiltinsObject> builtins(native_context()->builtins());
+    ForceSetProperty(builtins,
+                     factory()->InternalizeOneByteString(
+                         STATIC_ASCII_VECTOR("rngstate")),
+                     Utils::OpenHandle(*ta),
+                     NONE);
+  }
 
   result_ = native_context();
 }
index 189c215..3817de1 100644 (file)
@@ -185,7 +185,7 @@ enum BindingFlags {
   V(GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX, Map, \
     generator_object_prototype_map) \
   V(GENERATOR_RESULT_MAP_INDEX, Map, generator_result_map) \
-  V(RANDOM_SEED_INDEX, ByteArray, random_seed)
+  V(RANDOM_STATE_INDEX, Smi, random_state)
 
 // JSFunctions are pairs (context, function code), sometimes also called
 // closures. A Context object is used to represent function contexts and
@@ -332,7 +332,7 @@ class Context: public FixedArray {
     STRICT_MODE_GENERATOR_FUNCTION_MAP_INDEX,
     GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX,
     GENERATOR_RESULT_MAP_INDEX,
-    RANDOM_SEED_INDEX,
+    RANDOM_STATE_INDEX,
 
     // Properties from here are treated as weak references by the full GC.
     // Scavenge treats them as strong references.
index 1db48a1..db80a7e 100644 (file)
@@ -251,9 +251,6 @@ const int kFPOnStackSize = kRegisterSize;
 
 const int kDoubleSizeLog2 = 3;
 
-// Size of the state of a the random number generator.
-const int kRandomStateSize = 2 * kIntSize;
-
 #if V8_HOST_ARCH_64_BIT
 const int kPointerSizeLog2 = 3;
 const intptr_t kIntptrSignBit = V8_INT64_C(0x8000000000000000);
index b5fe184..dcab156 100644 (file)
@@ -1765,7 +1765,9 @@ struct WeakListVisitor<Context> {
     }
   }
 
-  static void VisitPhantomObject(Heap*, Context*) {
+  static void VisitPhantomObject(Heap*, Context* context) {
+    // A bit of a hack, see the comment at the end of Genesis::Genesis().
+    delete[] reinterpret_cast<uint32_t*>(context->random_state());
   }
 
   static int WeakNextOffset() {
index 73c1d7d..f9524bc 100644 (file)
@@ -155,7 +155,6 @@ class LChunkBuilder;
   V(Parameter)                                 \
   V(Power)                                     \
   V(PushArgument)                              \
-  V(Random)                                    \
   V(RegExpLiteral)                             \
   V(Return)                                    \
   V(Ror)                                       \
@@ -4724,28 +4723,6 @@ class HPower V8_FINAL : public HTemplateInstruction<2> {
 };
 
 
-class HRandom V8_FINAL : public HTemplateInstruction<1> {
- public:
-  DECLARE_INSTRUCTION_FACTORY_P1(HRandom, HValue*);
-
-  HValue* global_object() { return OperandAt(0); }
-
-  virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
-    return Representation::Tagged();
-  }
-
-  DECLARE_CONCRETE_INSTRUCTION(Random)
-
- private:
-  explicit HRandom(HValue* global_object) {
-    SetOperandAt(0, global_object);
-    set_representation(Representation::Double());
-  }
-
-  virtual bool IsDeletable() const V8_OVERRIDE { return true; }
-};
-
-
 class HAdd V8_FINAL : public HArithmeticBinaryOperation {
  public:
   static HInstruction* New(Zone* zone,
index f7b3100..9215d0f 100644 (file)
@@ -7489,16 +7489,6 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
         return true;
       }
       break;
-    case kMathRandom:
-      if (argument_count == 1 && check_type == RECEIVER_MAP_CHECK) {
-        AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
-        Drop(1);  // Receiver.
-        HGlobalObject* global_object = Add<HGlobalObject>();
-        HRandom* result = New<HRandom>(global_object);
-        ast_context()->ReturnInstruction(result, expr->id());
-        return true;
-      }
-      break;
     case kMathMax:
     case kMathMin:
       if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
@@ -9873,14 +9863,6 @@ void HOptimizedGraphBuilder::GenerateLog(CallRuntime* call) {
 }
 
 
-// Fast support for Math.random().
-void HOptimizedGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) {
-  HGlobalObject* global_object = Add<HGlobalObject>();
-  HRandom* result = New<HRandom>(global_object);
-  return ast_context()->ReturnInstruction(result, call->id());
-}
-
-
 // Fast support for StringAdd.
 void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) {
   ASSERT_EQ(2, call->arguments()->length());
index 86c525d..e067c90 100644 (file)
@@ -3296,57 +3296,6 @@ void FullCodeGenerator::EmitLog(CallRuntime* expr) {
 }
 
 
-void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
-  ASSERT(expr->arguments()->length() == 0);
-
-  Label slow_allocate_heapnumber;
-  Label heapnumber_allocated;
-
-  __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber);
-  __ jmp(&heapnumber_allocated);
-
-  __ bind(&slow_allocate_heapnumber);
-  // Allocate a heap number.
-  __ CallRuntime(Runtime::kNumberAlloc, 0);
-  __ mov(edi, eax);
-
-  __ bind(&heapnumber_allocated);
-
-  __ PrepareCallCFunction(1, ebx);
-  __ mov(eax, ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX));
-  __ mov(eax, FieldOperand(eax, GlobalObject::kNativeContextOffset));
-  __ mov(Operand(esp, 0), eax);
-  __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
-
-  // Convert 32 random bits in eax to 0.(32 random bits) in a double
-  // by computing:
-  // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
-  // This is implemented on both SSE2 and FPU.
-  if (CpuFeatures::IsSupported(SSE2)) {
-    CpuFeatureScope fscope(masm(), SSE2);
-    __ mov(ebx, Immediate(0x49800000));  // 1.0 x 2^20 as single.
-    __ movd(xmm1, ebx);
-    __ movd(xmm0, eax);
-    __ cvtss2sd(xmm1, xmm1);
-    __ xorps(xmm0, xmm1);
-    __ subsd(xmm0, xmm1);
-    __ movsd(FieldOperand(edi, HeapNumber::kValueOffset), xmm0);
-  } else {
-    // 0x4130000000000000 is 1.0 x 2^20 as a double.
-    __ mov(FieldOperand(edi, HeapNumber::kExponentOffset),
-           Immediate(0x41300000));
-    __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax);
-    __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
-    __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), Immediate(0));
-    __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
-    __ fsubp(1);
-    __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
-  }
-  __ mov(eax, edi);
-  context()->Plug(eax);
-}
-
-
 void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
   // Load the arguments on the stack and call the stub.
   SubStringStub stub;
index f316e85..1797d2e 100644 (file)
@@ -4167,69 +4167,6 @@ void LCodeGen::DoPower(LPower* instr) {
 }
 
 
-void LCodeGen::DoRandom(LRandom* instr) {
-  CpuFeatureScope scope(masm(), SSE2);
-
-  // Assert that the register size is indeed the size of each seed.
-  static const int kSeedSize = sizeof(uint32_t);
-  STATIC_ASSERT(kPointerSize == kSeedSize);
-
-  // Load native context
-  Register global_object = ToRegister(instr->global_object());
-  Register native_context = global_object;
-  __ mov(native_context, FieldOperand(
-          global_object, GlobalObject::kNativeContextOffset));
-
-  // Load state (FixedArray of the native context's random seeds)
-  static const int kRandomSeedOffset =
-      FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
-  Register state = native_context;
-  __ mov(state, FieldOperand(native_context, kRandomSeedOffset));
-
-  // Load state[0].
-  Register state0 = ToRegister(instr->scratch());
-  __ mov(state0, FieldOperand(state, ByteArray::kHeaderSize));
-  // Load state[1].
-  Register state1 = ToRegister(instr->scratch2());
-  __ mov(state1, FieldOperand(state, ByteArray::kHeaderSize + kSeedSize));
-
-  // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
-  Register scratch3 = ToRegister(instr->scratch3());
-  __ movzx_w(scratch3, state0);
-  __ imul(scratch3, scratch3, 18273);
-  __ shr(state0, 16);
-  __ add(state0, scratch3);
-  // Save state[0].
-  __ mov(FieldOperand(state, ByteArray::kHeaderSize), state0);
-
-  // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
-  __ movzx_w(scratch3, state1);
-  __ imul(scratch3, scratch3, 36969);
-  __ shr(state1, 16);
-  __ add(state1, scratch3);
-  // Save state[1].
-  __ mov(FieldOperand(state, ByteArray::kHeaderSize + kSeedSize), state1);
-
-  // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
-  Register random = state0;
-  __ shl(random, 14);
-  __ and_(state1, Immediate(0x3FFFF));
-  __ add(random, state1);
-
-  // Convert 32 random bits in random to 0.(32 random bits) in a double
-  // by computing:
-  // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
-  XMMRegister result = ToDoubleRegister(instr->result());
-  XMMRegister scratch4 = double_scratch0();
-  __ mov(scratch3, Immediate(0x49800000));  // 1.0 x 2^20 as single.
-  __ movd(scratch4, scratch3);
-  __ movd(result, random);
-  __ cvtss2sd(scratch4, scratch4);
-  __ xorps(result, scratch4);
-  __ subsd(result, scratch4);
-}
-
-
 void LCodeGen::DoMathLog(LMathLog* instr) {
   CpuFeatureScope scope(masm(), SSE2);
   ASSERT(instr->value()->Equals(instr->result()));
index d4c17ab..5343773 100644 (file)
@@ -1695,19 +1695,6 @@ LInstruction* LChunkBuilder::DoPower(HPower* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
-  ASSERT(instr->representation().IsDouble());
-  ASSERT(instr->global_object()->representation().IsTagged());
-  LOperand* global_object = UseTempRegister(instr->global_object());
-  LOperand* scratch = TempRegister();
-  LOperand* scratch2 = TempRegister();
-  LOperand* scratch3 = TempRegister();
-  LRandom* result = new(zone()) LRandom(
-      global_object, scratch, scratch2, scratch3);
-  return DefineFixedDouble(result, xmm1);
-}
-
-
 LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
   ASSERT(instr->left()->representation().IsSmiOrTagged());
   ASSERT(instr->right()->representation().IsSmiOrTagged());
index bc2b71b..b429120 100644 (file)
@@ -154,7 +154,6 @@ class LCodeGen;
   V(OuterContext)                               \
   V(Parameter)                                  \
   V(Power)                                      \
-  V(Random)                                     \
   V(PushArgument)                               \
   V(RegExpLiteral)                              \
   V(Return)                                     \
@@ -1462,28 +1461,6 @@ class LPower V8_FINAL : public LTemplateInstruction<1, 2, 0> {
 };
 
 
-class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 3> {
- public:
-  LRandom(LOperand* global_object,
-          LOperand* scratch,
-          LOperand* scratch2,
-          LOperand* scratch3) {
-    inputs_[0] = global_object;
-    temps_[0] = scratch;
-    temps_[1] = scratch2;
-    temps_[2] = scratch3;
-  }
-
-  LOperand* global_object() const { return inputs_[0]; }
-  LOperand* scratch() const { return temps_[0]; }
-  LOperand* scratch2() const { return temps_[1]; }
-  LOperand* scratch3() const { return temps_[2]; }
-
-  DECLARE_CONCRETE_INSTRUCTION(Random, "random")
-  DECLARE_HYDROGEN_ACCESSOR(Random)
-};
-
-
 class LArithmeticD V8_FINAL : public LTemplateInstruction<1, 2, 0> {
  public:
   LArithmeticD(Token::Value op, LOperand* left, LOperand* right)
index 2df0ec2..7366072 100644 (file)
@@ -168,8 +168,15 @@ function MathPow(x, y) {
 }
 
 // ECMA 262 - 15.8.2.14
+var rngstate;  // Initialized to a Uint32Array during genesis.
 function MathRandom() {
-  return %_RandomHeapNumber();
+  var r0 = (MathImul(18273, rngstate[0] & 0xFFFF) + (rngstate[0] >>> 16)) | 0;
+  rngstate[0] = r0;
+  var r1 = (MathImul(36969, rngstate[1] & 0xFFFF) + (rngstate[1] >>> 16)) | 0;
+  rngstate[1] = r1;
+  var x = ((r0 << 14) + (r1 & 0x3FFFF)) | 0;
+  // Division by 0x100000000 through multiplication by reciprocal.
+  return (x < 0 ? (x + 0x100000000) : x) * 2.3283064365386962890625e-10;
 }
 
 // ECMA 262 - 15.8.2.15
index 6ef871f..486eb9d 100644 (file)
@@ -3378,48 +3378,6 @@ void FullCodeGenerator::EmitLog(CallRuntime* expr) {
 }
 
 
-void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
-  ASSERT(expr->arguments()->length() == 0);
-  Label slow_allocate_heapnumber;
-  Label heapnumber_allocated;
-
-  // Save the new heap number in callee-saved register s0, since
-  // we call out to external C code below.
-  __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
-  __ AllocateHeapNumber(s0, a1, a2, t6, &slow_allocate_heapnumber);
-  __ jmp(&heapnumber_allocated);
-
-  __ bind(&slow_allocate_heapnumber);
-
-  // Allocate a heap number.
-  __ CallRuntime(Runtime::kNumberAlloc, 0);
-  __ mov(s0, v0);   // Save result in s0, so it is saved thru CFunc call.
-
-  __ bind(&heapnumber_allocated);
-
-  // Convert 32 random bits in v0 to 0.(32 random bits) in a double
-  // by computing:
-  // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
-  __ PrepareCallCFunction(1, a0);
-  __ lw(a0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
-  __ lw(a0, FieldMemOperand(a0, GlobalObject::kNativeContextOffset));
-  __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
-
-  // 0x41300000 is the top half of 1.0 x 2^20 as a double.
-  __ li(a1, Operand(0x41300000));
-  // Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU.
-  __ Move(f12, v0, a1);
-  // Move 0x4130000000000000 to FPU.
-  __ Move(f14, zero_reg, a1);
-  // Subtract and store the result in the heap number.
-  __ sub_d(f0, f12, f14);
-  __ sdc1(f0, FieldMemOperand(s0, HeapNumber::kValueOffset));
-  __ mov(v0, s0);
-
-  context()->Plug(v0);
-}
-
-
 void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
   // Load the arguments on the stack and call the stub.
   SubStringStub stub;
index bc5d62a..e40021d 100644 (file)
@@ -3829,68 +3829,6 @@ void LCodeGen::DoPower(LPower* instr) {
 }
 
 
-void LCodeGen::DoRandom(LRandom* instr) {
-  // Assert that the register size is indeed the size of each seed.
-  static const int kSeedSize = sizeof(uint32_t);
-  STATIC_ASSERT(kPointerSize == kSeedSize);
-
-  // Load native context.
-  Register global_object = ToRegister(instr->global_object());
-  Register native_context = global_object;
-  __ lw(native_context, FieldMemOperand(
-          global_object, GlobalObject::kNativeContextOffset));
-
-  // Load state (FixedArray of the native context's random seeds).
-  static const int kRandomSeedOffset =
-      FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
-  Register state = native_context;
-  __ lw(state, FieldMemOperand(native_context, kRandomSeedOffset));
-
-  // Load state[0].
-  Register state0 = ToRegister(instr->scratch());
-  __ lw(state0, FieldMemOperand(state, ByteArray::kHeaderSize));
-  // Load state[1].
-  Register state1 = ToRegister(instr->scratch2());
-  __ lw(state1, FieldMemOperand(state, ByteArray::kHeaderSize + kSeedSize));
-
-  // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
-  Register scratch3 = ToRegister(instr->scratch3());
-  Register scratch4 = scratch0();
-  __ And(scratch3, state0, Operand(0xFFFF));
-  __ li(scratch4, Operand(18273));
-  __ Mul(scratch3, scratch3, scratch4);
-  __ srl(state0, state0, 16);
-  __ Addu(state0, scratch3, state0);
-  // Save state[0].
-  __ sw(state0, FieldMemOperand(state, ByteArray::kHeaderSize));
-
-  // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
-  __ And(scratch3, state1, Operand(0xFFFF));
-  __ li(scratch4, Operand(36969));
-  __ Mul(scratch3, scratch3, scratch4);
-  __ srl(state1, state1, 16),
-  __ Addu(state1, scratch3, state1);
-  // Save state[1].
-  __ sw(state1, FieldMemOperand(state, ByteArray::kHeaderSize + kSeedSize));
-
-  // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
-  Register random = scratch4;
-  __ And(random, state1, Operand(0x3FFFF));
-  __ sll(state0, state0, 14);
-  __ Addu(random, random, state0);
-
-  // 0x41300000 is the top half of 1.0 x 2^20 as a double.
-  __ li(scratch3, Operand(0x41300000));
-  // Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU.
-  DoubleRegister result = ToDoubleRegister(instr->result());
-  __ Move(result, random, scratch3);
-  // Move 0x4130000000000000 to FPU.
-  DoubleRegister scratch5 = double_scratch0();
-  __ Move(scratch5, zero_reg, scratch3);
-  __ sub_d(result, result, scratch5);
-}
-
-
 void LCodeGen::DoMathExp(LMathExp* instr) {
   DoubleRegister input = ToDoubleRegister(instr->value());
   DoubleRegister result = ToDoubleRegister(instr->result());
index abdc3e6..fa653c6 100644 (file)
@@ -1640,19 +1640,6 @@ LInstruction* LChunkBuilder::DoPower(HPower* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
-  ASSERT(instr->representation().IsDouble());
-  ASSERT(instr->global_object()->representation().IsTagged());
-  LOperand* global_object = UseTempRegister(instr->global_object());
-  LOperand* scratch = TempRegister();
-  LOperand* scratch2 = TempRegister();
-  LOperand* scratch3 = TempRegister();
-  LRandom* result = new(zone()) LRandom(
-      global_object, scratch, scratch2, scratch3);
-  return DefineFixedDouble(result, f0);
-}
-
-
 LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
   ASSERT(instr->left()->representation().IsTagged());
   ASSERT(instr->right()->representation().IsTagged());
index 452963b..2996c78 100644 (file)
@@ -154,7 +154,6 @@ class LCodeGen;
   V(Parameter)                                  \
   V(Power)                                      \
   V(PushArgument)                               \
-  V(Random)                                     \
   V(RegExpLiteral)                              \
   V(Return)                                     \
   V(SeqStringGetChar)                           \
@@ -1461,28 +1460,6 @@ class LPower V8_FINAL : public LTemplateInstruction<1, 2, 0> {
 };
 
 
-class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 3> {
- public:
-  LRandom(LOperand* global_object,
-          LOperand* scratch,
-          LOperand* scratch2,
-          LOperand* scratch3) {
-    inputs_[0] = global_object;
-    temps_[0] = scratch;
-    temps_[1] = scratch2;
-    temps_[2] = scratch3;
-  }
-
-  LOperand* global_object() const { return inputs_[0]; }
-  LOperand* scratch() const { return temps_[0]; }
-  LOperand* scratch2() const { return temps_[1]; }
-  LOperand* scratch3() const { return temps_[2]; }
-
-  DECLARE_CONCRETE_INSTRUCTION(Random, "random")
-  DECLARE_HYDROGEN_ACCESSOR(Random)
-};
-
-
 class LArithmeticD V8_FINAL : public LTemplateInstruction<1, 2, 0> {
  public:
   LArithmeticD(Token::Value op, LOperand* left, LOperand* right)
index 352edaa..ffde816 100644 (file)
@@ -6506,7 +6506,6 @@ class Script: public Struct {
   V(Math, exp, MathExp)                             \
   V(Math, sqrt, MathSqrt)                           \
   V(Math, pow, MathPow)                             \
-  V(Math, random, MathRandom)                       \
   V(Math, max, MathMax)                             \
   V(Math, min, MathMin)                             \
   V(Math, imul, MathImul)
index 4872ab5..6ae39ac 100644 (file)
@@ -623,7 +623,6 @@ namespace internal {
   F(OneByteSeqStringSetChar, 3, 1)                                           \
   F(TwoByteSeqStringSetChar, 3, 1)                                           \
   F(ObjectEquals, 2, 1)                                                      \
-  F(RandomHeapNumber, 0, 1)                                                  \
   F(IsObject, 1, 1)                                                          \
   F(IsFunction, 1, 1)                                                        \
   F(IsUndetectableObject, 1, 1)                                              \
index 36e19c1..a8df238 100644 (file)
@@ -297,10 +297,6 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
       RUNTIME_ENTRY,
       1,
       "Runtime::PerformGC");
-  Add(ExternalReference::random_uint32_function(isolate).address(),
-      RUNTIME_ENTRY,
-      3,
-      "V8::Random");
   Add(ExternalReference::delete_handle_scope_extensions(isolate).address(),
       RUNTIME_ENTRY,
       4,
index 17007a2..611a615 100644 (file)
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -109,25 +109,6 @@ void V8::SetReturnAddressLocationResolver(
 }
 
 
-// Used by JavaScript APIs
-uint32_t V8::Random(Context* context) {
-  ASSERT(context->IsNativeContext());
-  ByteArray* seed = context->random_seed();
-  uint32_t* state = reinterpret_cast<uint32_t*>(seed->GetDataStartAddress());
-
-  // When we get here, the RNG must have been initialized,
-  // see the Genesis constructor in file bootstrapper.cc.
-  ASSERT_NE(0, state[0]);
-  ASSERT_NE(0, state[1]);
-
-  // Mix the bits.  Never replaces state[i] with 0 if it is nonzero.
-  state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16);
-  state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16);
-
-  return (state[0] << 14) + (state[1] & 0x3FFFF);
-}
-
-
 void V8::AddCallCompletedCallback(CallCompletedCallback callback) {
   if (call_completed_callbacks_ == NULL) {  // Lazy init.
     call_completed_callbacks_ = new List<CallCompletedCallback>();
index 01362ab..21f7d59 100644 (file)
--- a/src/v8.h
+++ b/src/v8.h
@@ -95,8 +95,6 @@ class V8 : public AllStatic {
       ReturnAddressLocationResolver resolver);
   // Support for entry hooking JITed code.
   static void SetFunctionEntryHook(FunctionEntryHook entry_hook);
-  // Random number generation support. Not cryptographically safe.
-  static uint32_t Random(Context* context);
 
   static void AddCallCompletedCallback(CallCompletedCallback callback);
   static void RemoveCallCompletedCallback(CallCompletedCallback callback);
index 71b5468..a62fde0 100644 (file)
@@ -3271,47 +3271,6 @@ void FullCodeGenerator::EmitLog(CallRuntime* expr) {
 }
 
 
-void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
-  ASSERT(expr->arguments()->length() == 0);
-
-  Label slow_allocate_heapnumber;
-  Label heapnumber_allocated;
-
-  __ AllocateHeapNumber(rbx, rcx, &slow_allocate_heapnumber);
-  __ jmp(&heapnumber_allocated);
-
-  __ bind(&slow_allocate_heapnumber);
-  // Allocate a heap number.
-  __ CallRuntime(Runtime::kNumberAlloc, 0);
-  __ movq(rbx, rax);
-
-  __ bind(&heapnumber_allocated);
-
-  // Return a random uint32 number in rax.
-  // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs.
-  __ PrepareCallCFunction(1);
-  __ movq(arg_reg_1,
-          ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX));
-  __ movq(arg_reg_1,
-          FieldOperand(arg_reg_1, GlobalObject::kNativeContextOffset));
-  __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
-
-  // Convert 32 random bits in rax to 0.(32 random bits) in a double
-  // by computing:
-  // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
-  __ movl(rcx, Immediate(0x49800000));  // 1.0 x 2^20 as single.
-  __ movd(xmm1, rcx);
-  __ movd(xmm0, rax);
-  __ cvtss2sd(xmm1, xmm1);
-  __ xorps(xmm0, xmm1);
-  __ subsd(xmm0, xmm1);
-  __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0);
-
-  __ movq(rax, rbx);
-  context()->Plug(rax);
-}
-
-
 void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
   // Load the arguments on the stack and call the stub.
   SubStringStub stub;
index 0c95745..241963b 100644 (file)
@@ -3698,66 +3698,6 @@ void LCodeGen::DoPower(LPower* instr) {
 }
 
 
-void LCodeGen::DoRandom(LRandom* instr) {
-  // Assert that register size is twice the size of each seed.
-  static const int kSeedSize = sizeof(uint32_t);
-  STATIC_ASSERT(kPointerSize == 2 * kSeedSize);
-
-  // Load native context
-  Register global_object = ToRegister(instr->global_object());
-  Register native_context = global_object;
-  __ movq(native_context, FieldOperand(
-          global_object, GlobalObject::kNativeContextOffset));
-
-  // Load state (FixedArray of the native context's random seeds)
-  static const int kRandomSeedOffset =
-      FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
-  Register state = native_context;
-  __ movq(state, FieldOperand(native_context, kRandomSeedOffset));
-
-  // Load state[0].
-  Register state0 = ToRegister(instr->scratch());
-  __ movl(state0, FieldOperand(state, ByteArray::kHeaderSize));
-  // Load state[1].
-  Register state1 = ToRegister(instr->scratch2());
-  __ movl(state1, FieldOperand(state, ByteArray::kHeaderSize + kSeedSize));
-
-  // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
-  Register scratch3 = ToRegister(instr->scratch3());
-  __ movzxwl(scratch3, state0);
-  __ imull(scratch3, scratch3, Immediate(18273));
-  __ shrl(state0, Immediate(16));
-  __ addl(state0, scratch3);
-  // Save state[0].
-  __ movl(FieldOperand(state, ByteArray::kHeaderSize), state0);
-
-  // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
-  __ movzxwl(scratch3, state1);
-  __ imull(scratch3, scratch3, Immediate(36969));
-  __ shrl(state1, Immediate(16));
-  __ addl(state1, scratch3);
-  // Save state[1].
-  __ movl(FieldOperand(state, ByteArray::kHeaderSize + kSeedSize), state1);
-
-  // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
-  Register random = state0;
-  __ shll(random, Immediate(14));
-  __ andl(state1, Immediate(0x3FFFF));
-  __ addl(random, state1);
-
-  // Convert 32 random bits in rax to 0.(32 random bits) in a double
-  // by computing:
-  // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
-  XMMRegister result = ToDoubleRegister(instr->result());
-  XMMRegister scratch4 = double_scratch0();
-  __ movq(scratch3, V8_INT64_C(0x4130000000000000));  // 1.0 x 2^20 as double
-  __ movq(scratch4, scratch3);
-  __ movd(result, random);
-  __ xorps(result, scratch4);
-  __ subsd(result, scratch4);
-}
-
-
 void LCodeGen::DoMathExp(LMathExp* instr) {
   XMMRegister input = ToDoubleRegister(instr->value());
   XMMRegister result = ToDoubleRegister(instr->result());
index 2a73472..fa1bdaa 100644 (file)
@@ -1601,19 +1601,6 @@ LInstruction* LChunkBuilder::DoPower(HPower* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
-  ASSERT(instr->representation().IsDouble());
-  ASSERT(instr->global_object()->representation().IsTagged());
-  LOperand* global_object = UseTempRegister(instr->global_object());
-  LOperand* scratch = TempRegister();
-  LOperand* scratch2 = TempRegister();
-  LOperand* scratch3 = TempRegister();
-  LRandom* result = new(zone()) LRandom(
-      global_object, scratch, scratch2, scratch3);
-  return DefineFixedDouble(result, xmm1);
-}
-
-
 LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
   ASSERT(instr->left()->representation().IsTagged());
   ASSERT(instr->right()->representation().IsTagged());
index a475d8c..ca7831c 100644 (file)
@@ -153,7 +153,6 @@ class LCodeGen;
   V(Parameter)                                  \
   V(Power)                                      \
   V(PushArgument)                               \
-  V(Random)                                     \
   V(RegExpLiteral)                              \
   V(Return)                                     \
   V(SeqStringGetChar)                           \
@@ -1424,28 +1423,6 @@ class LPower V8_FINAL : public LTemplateInstruction<1, 2, 0> {
 };
 
 
-class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 3> {
- public:
-  LRandom(LOperand* global_object,
-          LOperand* scratch,
-          LOperand* scratch2,
-          LOperand* scratch3) {
-    inputs_[0] = global_object;
-    temps_[0] = scratch;
-    temps_[1] = scratch2;
-    temps_[2] = scratch3;
-  }
-
-  LOperand* global_object() { return inputs_[0]; }
-  LOperand* scratch() const { return temps_[0]; }
-  LOperand* scratch2() const { return temps_[1]; }
-  LOperand* scratch3() const { return temps_[2]; }
-
-  DECLARE_CONCRETE_INSTRUCTION(Random, "random")
-  DECLARE_HYDROGEN_ACCESSOR(Random)
-};
-
-
 class LArithmeticD V8_FINAL : public LTemplateInstruction<1, 2, 0> {
  public:
   LArithmeticD(Token::Value op, LOperand* left, LOperand* right)
index fe1ef04..edfc375 100644 (file)
@@ -89,7 +89,7 @@ TEST(WeakArrayBuffersFromApi) {
   LocalContext context;
   Isolate* isolate = GetIsolateFrom(&context);
 
-  CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
+  int start = CountArrayBuffersInWeakList(isolate->heap());
   {
     v8::HandleScope s1(context->GetIsolate());
     v8::Handle<v8::ArrayBuffer> ab1 = v8::ArrayBuffer::New(256);
@@ -99,12 +99,12 @@ TEST(WeakArrayBuffersFromApi) {
 
       Handle<JSArrayBuffer> iab1 = v8::Utils::OpenHandle(*ab1);
       Handle<JSArrayBuffer> iab2 = v8::Utils::OpenHandle(*ab2);
-      CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()));
+      CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()) - start);
       CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab1));
       CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab2));
     }
     isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
-    CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
+    CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
     {
       HandleScope scope2(isolate);
       Handle<JSArrayBuffer> iab1 = v8::Utils::OpenHandle(*ab1);
@@ -114,7 +114,7 @@ TEST(WeakArrayBuffersFromApi) {
   }
 
   isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
-  CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
+  CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()) - start);
 }
 
 
@@ -122,11 +122,12 @@ TEST(WeakArrayBuffersFromScript) {
   v8::V8::Initialize();
   LocalContext context;
   Isolate* isolate = GetIsolateFrom(&context);
+  int start = CountArrayBuffersInWeakList(isolate->heap());
 
   for (int i = 1; i <= 3; i++) {
     // Create 3 array buffers, make i-th of them garbage,
     // validate correct state of array buffer weak list.
-    CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
+    CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()) - start);
     {
       v8::HandleScope scope(context->GetIsolate());
 
@@ -142,7 +143,7 @@ TEST(WeakArrayBuffersFromScript) {
         v8::Handle<v8::ArrayBuffer> ab3 =
             v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab3"));
 
-        CHECK_EQ(3, CountArrayBuffersInWeakList(isolate->heap()));
+        CHECK_EQ(3, CountArrayBuffersInWeakList(isolate->heap()) - start);
         CHECK(HasArrayBufferInWeakList(isolate->heap(),
               *v8::Utils::OpenHandle(*ab1)));
         CHECK(HasArrayBufferInWeakList(isolate->heap(),
@@ -156,7 +157,7 @@ TEST(WeakArrayBuffersFromScript) {
       CompileRun(source.start());
       isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
 
-      CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()));
+      CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()) - start);
 
       {
         v8::HandleScope s2(context->GetIsolate());
@@ -174,7 +175,7 @@ TEST(WeakArrayBuffersFromScript) {
     }
 
     isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
-    CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
+    CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()) - start);
   }
 }
 
@@ -266,6 +267,7 @@ static void TestTypedArrayFromScript(const char* constructor) {
   LocalContext context;
   Isolate* isolate = GetIsolateFrom(&context);
   v8::HandleScope scope(context->GetIsolate());
+  int start = CountArrayBuffersInWeakList(isolate->heap());
   CompileRun("var ab = new ArrayBuffer(2048);");
   for (int i = 1; i <= 3; i++) {
     // Create 3 typed arrays, make i-th of them garbage,
@@ -273,7 +275,7 @@ static void TestTypedArrayFromScript(const char* constructor) {
     v8::HandleScope s0(context->GetIsolate());
     i::ScopedVector<char> source(2048);
 
-    CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
+    CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
 
     {
       v8::HandleScope s1(context->GetIsolate());
@@ -292,7 +294,7 @@ static void TestTypedArrayFromScript(const char* constructor) {
           v8::Handle<TypedArray>::Cast(CompileRun("ta2"));
       v8::Handle<TypedArray> ta3 =
           v8::Handle<TypedArray>::Cast(CompileRun("ta3"));
-      CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
+      CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
       Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab);
       CHECK_EQ(3, CountViews(*iab));
       CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta1)));
@@ -304,7 +306,7 @@ static void TestTypedArrayFromScript(const char* constructor) {
     CompileRun(source.start());
     isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
 
-    CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
+    CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
 
     {
       v8::HandleScope s2(context->GetIsolate());
@@ -324,7 +326,7 @@ static void TestTypedArrayFromScript(const char* constructor) {
     CompileRun("ta1 = null; ta2 = null; ta3 = null;");
     isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
 
-    CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
+    CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
 
     {
       v8::HandleScope s3(context->GetIsolate());