Revision: 8637
Author:   [email protected]
Date:     Wed Jul 13 06:50:27 2011
Log:      Implement ICs for FastDoubleArray loads and stores

Implemented on ia32, x64, ARM. Stubbed out with UNIMPLEMENTED on MIPS.

BUG=none
TEST=unbox-double-arrays.js

Review URL: http://codereview.chromium.org/7307030
http://code.google.com/p/v8/source/detail?r=8637

Modified:
 /branches/bleeding_edge/src/arm/macro-assembler-arm.cc
 /branches/bleeding_edge/src/arm/stub-cache-arm.cc
 /branches/bleeding_edge/src/assembler.cc
 /branches/bleeding_edge/src/assembler.h
 /branches/bleeding_edge/src/code-stubs.cc
 /branches/bleeding_edge/src/globals.h
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
 /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
 /branches/bleeding_edge/src/mips/stub-cache-mips.cc
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/stub-cache.h
 /branches/bleeding_edge/src/v8globals.h
 /branches/bleeding_edge/src/x64/macro-assembler-x64.cc
 /branches/bleeding_edge/src/x64/stub-cache-x64.cc
 /branches/bleeding_edge/test/mjsunit/unbox-double-arrays.js

=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Fri Jul 8 03:46:10 2011 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Wed Jul 13 06:50:27 2011
@@ -2548,6 +2548,9 @@
     LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
     cmp(elements, ip);
     b(eq, &ok);
+    LoadRoot(ip, Heap::kFixedDoubleArrayMapRootIndex);
+    cmp(elements, ip);
+    b(eq, &ok);
     LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
     cmp(elements, ip);
     b(eq, &ok);
=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Fri Jul 8 03:46:10 2011 +++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Wed Jul 13 06:50:27 2011
@@ -4166,6 +4166,77 @@
       Builtins::kKeyedLoadIC_MissForceGeneric);
   __ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET);
 }
+
+
+void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
+    MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- lr    : return address
+  //  -- r0    : key
+  //  -- r1    : receiver
+  // -----------------------------------
+  Label miss_force_generic, slow_allocate_heapnumber;
+
+  Register key_reg = r0;
+  Register receiver_reg = r1;
+  Register elements_reg = r2;
+  Register heap_number_reg = r2;
+  Register indexed_double_offset = r3;
+  Register scratch = r4;
+  Register scratch2 = r5;
+  Register scratch3 = r6;
+  Register heap_number_map = r7;
+
+  // This stub is meant to be tail-jumped to, the receiver must already
+  // have been verified by the caller to not be a smi.
+
+  // Check that the key is a smi.
+  __ JumpIfNotSmi(key_reg, &miss_force_generic);
+
+  // Get the elements array.
+  __ ldr(elements_reg,
+         FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
+
+  // Check that the key is within bounds.
+ __ ldr(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
+  __ cmp(key_reg, Operand(scratch));
+  __ b(hs, &miss_force_generic);
+
+  // Load the upper word of the double in the fixed array and test for NaN.
+  __ add(indexed_double_offset, elements_reg,
+         Operand(key_reg, LSL, kDoubleSizeLog2 - kSmiTagSize));
+ uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
+  __ ldr(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
+  __ cmp(scratch, Operand(kHoleNanUpper32));
+  __ b(&miss_force_generic, eq);
+
+  // Non-NaN. Allocate a new heap number and copy the double value into it.
+  __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
+  __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
+                        heap_number_map, &slow_allocate_heapnumber);
+
+  // Don't need to reload the upper 32 bits of the double, it's already in
+  // scratch.
+  __ str(scratch, FieldMemOperand(heap_number_reg,
+                                  HeapNumber::kExponentOffset));
+  __ ldr(scratch, FieldMemOperand(indexed_double_offset,
+                                  FixedArray::kHeaderSize));
+  __ str(scratch, FieldMemOperand(heap_number_reg,
+                                  HeapNumber::kMantissaOffset));
+
+  __ mov(r0, heap_number_reg);
+  __ Ret();
+
+  __ bind(&slow_allocate_heapnumber);
+  Handle<Code> slow_ic =
+      masm->isolate()->builtins()->KeyedLoadIC_Slow();
+  __ Jump(slow_ic, RelocInfo::CODE_TARGET);
+
+  __ bind(&miss_force_generic);
+  Handle<Code> miss_ic =
+      masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
+  __ Jump(miss_ic, RelocInfo::CODE_TARGET);
+}


 void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
@@ -4229,6 +4300,123 @@
       masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
   __ Jump(ic, RelocInfo::CODE_TARGET);
 }
+
+
+void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
+    MacroAssembler* masm,
+    bool is_js_array) {
+  // ----------- S t a t e -------------
+  //  -- r0    : value
+  //  -- r1    : key
+  //  -- r2    : receiver
+  //  -- lr    : return address
+  //  -- r3    : scratch
+  //  -- r4    : scratch
+  //  -- r5    : scratch
+  // -----------------------------------
+ Label miss_force_generic, smi_value, is_nan, maybe_nan, have_double_value;
+
+  Register value_reg = r0;
+  Register key_reg = r1;
+  Register receiver_reg = r2;
+  Register scratch = r3;
+  Register elements_reg = r4;
+  Register mantissa_reg = r5;
+  Register exponent_reg = r6;
+  Register scratch4 = r7;
+
+  // This stub is meant to be tail-jumped to, the receiver must already
+  // have been verified by the caller to not be a smi.
+  __ JumpIfNotSmi(key_reg, &miss_force_generic);
+
+  __ ldr(elements_reg,
+         FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
+
+  // Check that the key is within bounds.
+  if (is_js_array) {
+    __ ldr(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
+  } else {
+    __ ldr(scratch,
+           FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
+  }
+  // Compare smis, unsigned compare catches both negative and out-of-bound
+  // indexes.
+  __ cmp(key_reg, scratch);
+  __ b(hs, &miss_force_generic);
+
+  // Handle smi values specially.
+  __ JumpIfSmi(value_reg, &smi_value);
+
+  // Ensure that the object is a heap number
+  __ CheckMap(value_reg,
+              scratch,
+              masm->isolate()->factory()->heap_number_map(),
+              &miss_force_generic,
+              DONT_DO_SMI_CHECK);
+
+ // Check for nan: all NaN values have a value greater (signed) than 0x7ff00000
+  // in the exponent.
+  __ mov(scratch, Operand(kNaNOrInfinityLowerBoundUpper32));
+ __ ldr(exponent_reg, FieldMemOperand(value_reg, HeapNumber::kExponentOffset));
+  __ cmp(exponent_reg, scratch);
+  __ b(ge, &maybe_nan);
+
+ __ ldr(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
+
+  __ bind(&have_double_value);
+  __ add(scratch, elements_reg,
+         Operand(key_reg, LSL, kDoubleSizeLog2 - kSmiTagSize));
+ __ str(mantissa_reg, FieldMemOperand(scratch, FixedDoubleArray::kHeaderSize)); + uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
+  __ str(exponent_reg, FieldMemOperand(scratch, offset));
+  __ Ret();
+
+  __ bind(&maybe_nan);
+  // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise
+  // it's an Infinity, and the non-NaN code path applies.
+  __ b(gt, &is_nan);
+ __ ldr(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
+  __ cmp(mantissa_reg, Operand(0));
+  __ b(eq, &have_double_value);
+  __ bind(&is_nan);
+  // Load canonical NaN for storing into the double array.
+  __ mov(mantissa_reg, Operand(kCanonicalNonHoleNanLower32));
+  __ mov(exponent_reg, Operand(kCanonicalNonHoleNanUpper32));
+  __ jmp(&have_double_value);
+
+  __ bind(&smi_value);
+  __ add(scratch, elements_reg,
+         Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
+  __ add(scratch, scratch,
+         Operand(key_reg, LSL, kDoubleSizeLog2 - kSmiTagSize));
+  // scratch is now effective address of the double element
+
+  FloatingPointHelper::Destination destination;
+  if (CpuFeatures::IsSupported(VFP3)) {
+    destination = FloatingPointHelper::kVFPRegisters;
+  } else {
+    destination = FloatingPointHelper::kCoreRegisters;
+  }
+  __ SmiUntag(value_reg, value_reg);
+  FloatingPointHelper::ConvertIntToDouble(
+      masm, value_reg, destination,
+ d0, mantissa_reg, exponent_reg, // These are: double_dst, dst1, dst2.
+      scratch4, s2);  // These are: scratch2, single_scratch.
+  if (destination == FloatingPointHelper::kVFPRegisters) {
+    CpuFeatures::Scope scope(VFP3);
+    __ vstr(d0, scratch, 0);
+  } else {
+    __ str(mantissa_reg, MemOperand(scratch, 0));
+    __ str(exponent_reg, MemOperand(scratch, Register::kSizeInBytes));
+  }
+  __ Ret();
+
+  // Handle store cache miss, replacing the ic with the generic stub.
+  __ bind(&miss_force_generic);
+  Handle<Code> ic =
+      masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
+  __ Jump(ic, RelocInfo::CODE_TARGET);
+}


 #undef __
=======================================
--- /branches/bleeding_edge/src/assembler.cc    Mon May 16 07:10:56 2011
+++ /branches/bleeding_edge/src/assembler.cc    Wed Jul 13 06:50:27 2011
@@ -1,4 +1,4 @@
-// Copyright (c) 1994-2006 Sun Microsystems Inc.
+// Copyright (c) 2011 Sun Microsystems Inc.
 // All Rights Reserved.
 //
 // Redistribution and use in source and binary forms, with or without
@@ -71,7 +71,9 @@
 const double DoubleConstant::minus_zero = -0.0;
 const double DoubleConstant::uint8_max_value = 255;
 const double DoubleConstant::zero = 0.0;
-const double DoubleConstant::nan = OS::nan_value();
+const double DoubleConstant::canonical_non_hole_nan =
+    BitCast<double>(kCanonicalNonHoleNanInt64);
+const double DoubleConstant::the_hole_nan = BitCast<double>(kHoleNanInt64);
 const double DoubleConstant::negative_infinity = -V8_INFINITY;
 const char* RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING";

@@ -921,9 +923,15 @@
 }


-ExternalReference ExternalReference::address_of_nan() {
+ExternalReference ExternalReference::address_of_canonical_non_hole_nan() {
   return ExternalReference(reinterpret_cast<void*>(
-      const_cast<double*>(&DoubleConstant::nan)));
+      const_cast<double*>(&DoubleConstant::canonical_non_hole_nan)));
+}
+
+
+ExternalReference ExternalReference::address_of_the_hole_nan() {
+  return ExternalReference(reinterpret_cast<void*>(
+      const_cast<double*>(&DoubleConstant::the_hole_nan)));
 }


=======================================
--- /branches/bleeding_edge/src/assembler.h     Thu Jun 16 08:18:48 2011
+++ /branches/bleeding_edge/src/assembler.h     Wed Jul 13 06:50:27 2011
@@ -70,7 +70,8 @@
   static const double zero;
   static const double uint8_max_value;
   static const double negative_infinity;
-  static const double nan;
+  static const double canonical_non_hole_nan;
+  static const double the_hole_nan;
 };


@@ -629,7 +630,8 @@
   static ExternalReference address_of_zero();
   static ExternalReference address_of_uint8_max_value();
   static ExternalReference address_of_negative_infinity();
-  static ExternalReference address_of_nan();
+  static ExternalReference address_of_canonical_non_hole_nan();
+  static ExternalReference address_of_the_hole_nan();

   static ExternalReference math_sin_double_function(Isolate* isolate);
   static ExternalReference math_cos_double_function(Isolate* isolate);
=======================================
--- /branches/bleeding_edge/src/code-stubs.cc   Wed Jul 13 04:08:25 2011
+++ /branches/bleeding_edge/src/code-stubs.cc   Wed Jul 13 06:50:27 2011
@@ -250,7 +250,7 @@
       KeyedLoadStubCompiler::GenerateLoadFastElement(masm);
       break;
     case JSObject::FAST_DOUBLE_ELEMENTS:
-      UNIMPLEMENTED();
+      KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(masm);
       break;
     case JSObject::EXTERNAL_BYTE_ELEMENTS:
     case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
@@ -279,7 +279,8 @@
       KeyedStoreStubCompiler::GenerateStoreFastElement(masm, is_js_array_);
       break;
     case JSObject::FAST_DOUBLE_ELEMENTS:
-      UNIMPLEMENTED();
+      KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
+                                                             is_js_array_);
       break;
     case JSObject::EXTERNAL_BYTE_ELEMENTS:
     case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
=======================================
--- /branches/bleeding_edge/src/globals.h       Mon Mar 28 06:05:36 2011
+++ /branches/bleeding_edge/src/globals.h       Wed Jul 13 06:50:27 2011
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
@@ -199,6 +199,8 @@
 const int kIntptrSize   = sizeof(intptr_t);  // NOLINT
 const int kPointerSize  = sizeof(void*);     // NOLINT

+const int kDoubleSizeLog2 = 3;
+
 #if V8_HOST_ARCH_64_BIT
 const int kPointerSizeLog2 = 3;
 const intptr_t kIntptrSignBit = V8_INT64_C(0x8000000000000000);
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Wed Jul 13 02:31:17 2011 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Wed Jul 13 06:50:27 2011
@@ -2790,7 +2790,8 @@
   __ ucomisd(input_reg, xmm0);
   __ j(above, &positive, Label::kNear);
   __ j(equal, &zero, Label::kNear);
-  ExternalReference nan = ExternalReference::address_of_nan();
+  ExternalReference nan =
+      ExternalReference::address_of_canonical_non_hole_nan();
   __ movdbl(input_reg, Operand::StaticVariable(nan));
   __ jmp(&done, Label::kNear);
   __ bind(&zero);
@@ -3451,7 +3452,8 @@
     DeoptimizeIf(not_equal, env);

     // Convert undefined to NaN.
-    ExternalReference nan = ExternalReference::address_of_nan();
+    ExternalReference nan =
+        ExternalReference::address_of_canonical_non_hole_nan();
     __ movdbl(result_reg, Operand::StaticVariable(nan));
     __ jmp(&done, Label::kNear);

=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Fri Jul 8 03:46:10 2011 +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Wed Jul 13 06:50:27 2011
@@ -2043,6 +2043,9 @@
     cmp(FieldOperand(elements, HeapObject::kMapOffset),
         Immediate(factory->fixed_array_map()));
     j(equal, &ok);
+    cmp(FieldOperand(elements, HeapObject::kMapOffset),
+        Immediate(factory->fixed_double_array_map()));
+    j(equal, &ok);
     cmp(FieldOperand(elements, HeapObject::kMapOffset),
         Immediate(factory->fixed_cow_array_map()));
     j(equal, &ok);
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Fri Jul 8 03:46:10 2011 +++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Wed Jul 13 06:50:27 2011
@@ -3788,6 +3788,71 @@
       masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
   __ jmp(miss_ic, RelocInfo::CODE_TARGET);
 }
+
+
+void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
+    MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- eax    : key
+  //  -- edx    : receiver
+  //  -- esp[0] : return address
+  // -----------------------------------
+  Label miss_force_generic, slow_allocate_heapnumber;
+
+  // This stub is meant to be tail-jumped to, the receiver must already
+  // have been verified by the caller to not be a smi.
+
+  // Check that the key is a smi.
+  __ JumpIfNotSmi(eax, &miss_force_generic);
+
+  // Get the elements array.
+  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
+  __ AssertFastElements(ecx);
+
+  // Check that the key is within bounds.
+  __ cmp(eax, FieldOperand(ecx, FixedDoubleArray::kLengthOffset));
+  __ j(above_equal, &miss_force_generic);
+
+  // Check for the hole
+ uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32); + __ cmp(FieldOperand(ecx, eax, times_4, offset), Immediate(kHoleNanUpper32));
+  __ j(equal, &miss_force_generic);
+
+  // Always allocate a heap number for the result.
+  if (CpuFeatures::IsSupported(SSE2)) {
+    CpuFeatures::Scope use_sse2(SSE2);
+    __ movdbl(xmm0, FieldOperand(ecx, eax, times_4,
+                                 FixedDoubleArray::kHeaderSize));
+  } else {
+ __ fld_d(FieldOperand(ecx, eax, times_4, FixedDoubleArray::kHeaderSize));
+  }
+  __ AllocateHeapNumber(ecx, ebx, edi, &slow_allocate_heapnumber);
+  // Set the value.
+  if (CpuFeatures::IsSupported(SSE2)) {
+    CpuFeatures::Scope use_sse2(SSE2);
+    __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0);
+  } else {
+    __ fstp_d(FieldOperand(ecx, HeapNumber::kValueOffset));
+  }
+  __ mov(eax, ecx);
+  __ ret(0);
+
+  __ bind(&slow_allocate_heapnumber);
+ // A value was pushed on the floating point stack before the allocation, if
+  // the allocation fails it needs to be removed.
+  if (!CpuFeatures::IsSupported(SSE2)) {
+    __ ffree();
+    __ fincstp();
+  }
+  Handle<Code> slow_ic =
+      masm->isolate()->builtins()->KeyedLoadIC_Slow();
+  __ jmp(slow_ic, RelocInfo::CODE_TARGET);
+
+  __ bind(&miss_force_generic);
+  Handle<Code> miss_ic =
+      masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
+  __ jmp(miss_ic, RelocInfo::CODE_TARGET);
+}


 void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
@@ -3837,6 +3902,98 @@
       masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
   __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
 }
+
+
+void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
+    MacroAssembler* masm,
+    bool is_js_array) {
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  //  -- ecx    : key
+  //  -- edx    : receiver
+  //  -- esp[0] : return address
+  // -----------------------------------
+  Label miss_force_generic, smi_value, is_nan, maybe_nan;
+  Label have_double_value, not_nan;
+
+  // This stub is meant to be tail-jumped to, the receiver must already
+  // have been verified by the caller to not be a smi.
+
+  // Check that the key is a smi.
+  __ JumpIfNotSmi(ecx, &miss_force_generic);
+
+  // Get the elements array.
+  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
+  __ AssertFastElements(edi);
+
+  if (is_js_array) {
+    // Check that the key is within bounds.
+    __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset));  // smis.
+  } else {
+    // Check that the key is within bounds.
+    __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));  // smis.
+  }
+  __ j(above_equal, &miss_force_generic);
+
+  __ JumpIfSmi(eax, &smi_value, Label::kNear);
+
+  __ CheckMap(eax,
+              masm->isolate()->factory()->heap_number_map(),
+              &miss_force_generic,
+              DONT_DO_SMI_CHECK);
+
+  // Double value, canonicalize NaN.
+  uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32);
+ __ cmp(FieldOperand(eax, offset), Immediate(kNaNOrInfinityLowerBoundUpper32));
+  __ j(greater_equal, &maybe_nan, Label::kNear);
+
+  __ bind(&not_nan);
+  ExternalReference canonical_nan_reference =
+      ExternalReference::address_of_canonical_non_hole_nan();
+  if (CpuFeatures::IsSupported(SSE2)) {
+    CpuFeatures::Scope use_sse2(SSE2);
+    __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
+    __ bind(&have_double_value);
+ __ movdbl(FieldOperand(edi, ecx, times_4, FixedDoubleArray::kHeaderSize),
+              xmm0);
+    __ ret(0);
+  } else {
+    __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
+    __ bind(&have_double_value);
+ __ fstp_d(FieldOperand(edi, ecx, times_4, FixedDoubleArray::kHeaderSize));
+    __ ret(0);
+  }
+
+  __ bind(&maybe_nan);
+  // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise
+  // it's an Infinity, and the non-NaN code path applies.
+  __ j(greater, &is_nan, Label::kNear);
+  __ cmp(FieldOperand(eax, HeapNumber::kValueOffset), Immediate(0));
+  __ j(zero, &not_nan);
+  __ bind(&is_nan);
+  if (CpuFeatures::IsSupported(SSE2)) {
+    CpuFeatures::Scope use_sse2(SSE2);
+    __ movdbl(xmm0, Operand::StaticVariable(canonical_nan_reference));
+  } else {
+    __ fld_d(Operand::StaticVariable(canonical_nan_reference));
+  }
+  __ jmp(&have_double_value, Label::kNear);
+
+  __ bind(&smi_value);
+  // Value is a smi. convert to a double and store.
+  __ SmiUntag(eax);
+  __ push(eax);
+  __ fild_s(Operand(esp, 0));
+  __ pop(eax);
+ __ fstp_d(FieldOperand(edi, ecx, times_4, FixedDoubleArray::kHeaderSize));
+  __ ret(0);
+
+  // Handle store cache miss, replacing the ic with the generic stub.
+  __ bind(&miss_force_generic);
+  Handle<Code> ic_force_generic =
+      masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
+  __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
+}


 #undef __
=======================================
--- /branches/bleeding_edge/src/mips/stub-cache-mips.cc Fri Jul 8 03:46:10 2011 +++ /branches/bleeding_edge/src/mips/stub-cache-mips.cc Wed Jul 13 06:50:27 2011
@@ -4227,6 +4227,12 @@
       Builtins::kKeyedLoadIC_MissForceGeneric);
   __ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET);
 }
+
+
+void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
+    MacroAssembler* masm) {
+  UNIMPLEMENTED();
+}


 void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
@@ -4290,6 +4296,13 @@
       masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
   __ Jump(ic, RelocInfo::CODE_TARGET);
 }
+
+
+void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
+    MacroAssembler* masm,
+    bool is_js_array) {
+  UNIMPLEMENTED();
+}


 #undef __
=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Wed Jul 13 04:13:40 2011
+++ /branches/bleeding_edge/src/objects-inl.h   Wed Jul 13 06:50:27 2011
@@ -1608,6 +1608,21 @@
   WRITE_FIELD(this, offset, value);
   WRITE_BARRIER(this, offset);
 }
+
+
+inline bool FixedDoubleArray::is_the_hole_nan(double value) {
+  return BitCast<uint64_t, double>(value) == kHoleNanInt64;
+}
+
+
+inline double FixedDoubleArray::hole_nan_as_double() {
+  return BitCast<double, uint64_t>(kHoleNanInt64);
+}
+
+
+inline double FixedDoubleArray::canonical_not_the_hole_nan_as_double() {
+  return BitCast<double, uint64_t>(kCanonicalNonHoleNanInt64);
+}


 double FixedDoubleArray::get(int index) {
=======================================
--- /branches/bleeding_edge/src/objects.cc      Wed Jul 13 04:13:40 2011
+++ /branches/bleeding_edge/src/objects.cc      Wed Jul 13 06:50:27 2011
@@ -58,11 +58,6 @@
 const int kGetterIndex = 0;
 const int kSetterIndex = 1;

-uint64_t FixedDoubleArray::kHoleNanInt64 = -1;
-uint64_t FixedDoubleArray::kCanonicalNonHoleNanLower32 = 0x7FF00000;
-uint64_t FixedDoubleArray::kCanonicalNonHoleNanInt64 =
-    kCanonicalNonHoleNanLower32 << 32;
-
 MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
                                                   Object* value) {
   Object* result;
@@ -2811,16 +2806,18 @@
   ASSERT(!HasExternalArrayElements());

   // Find the backing store.
-  FixedArray* array = FixedArray::cast(elements());
+  FixedArrayBase* array = FixedArrayBase::cast(elements());
   Map* old_map = array->map();
   bool is_arguments =
       (old_map == old_map->heap()->non_strict_arguments_elements_map());
   if (is_arguments) {
-    array = FixedArray::cast(array->get(1));
+    array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
   }
   if (array->IsDictionary()) return array;

-  ASSERT(HasFastElements() || HasFastArgumentsElements());
+  ASSERT(HasFastElements() ||
+         HasFastDoubleElements() ||
+         HasFastArgumentsElements());
   // Compute the effective length and allocate a new backing store.
   int length = IsJSArray()
       ? Smi::cast(JSArray::cast(this)->length())->value()
@@ -2833,7 +2830,7 @@
   }

   // Copy the elements to the new backing store.
-  bool has_double_elements = old_map->has_fast_double_elements();
+  bool has_double_elements = array->IsFixedDoubleArray();
   for (int i = 0; i < length; i++) {
     Object* value = NULL;
     if (has_double_elements) {
@@ -2851,7 +2848,7 @@
       }
     } else {
       ASSERT(old_map->has_fast_elements());
-      value = array->get(i);
+      value = FixedArray::cast(array)->get(i);
     }
     PropertyDetails details = PropertyDetails(NONE, NORMAL);
     if (!value->IsTheHole()) {
@@ -7317,22 +7314,28 @@
     new_map = Map::cast(object);
   }

-  AssertNoAllocation no_gc;
-  WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
   switch (GetElementsKind()) {
-    case FAST_ELEMENTS:
+    case FAST_ELEMENTS: {
+      AssertNoAllocation no_gc;
+      WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode);
       set_map(new_map);
       set_elements(new_elements);
       break;
-    case DICTIONARY_ELEMENTS:
+    }
+    case DICTIONARY_ELEMENTS: {
+      AssertNoAllocation no_gc;
+      WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
       CopySlowElementsToFast(NumberDictionary::cast(elements()),
                              new_elements,
                              mode);
       set_map(new_map);
       set_elements(new_elements);
       break;
+    }
     case NON_STRICT_ARGUMENTS_ELEMENTS: {
+      AssertNoAllocation no_gc;
+      WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
// The object's map and the parameter map are unchanged, the unaliased
       // arguments are copied to the new backing store.
       FixedArray* parameter_map = FixedArray::cast(elements());
@@ -7368,6 +7371,8 @@
           new_elements->set(i, obj, UPDATE_WRITE_BARRIER);
         }
       }
+      set_map(new_map);
+      set_elements(new_elements);
       break;
     }
     case EXTERNAL_BYTE_ELEMENTS:
@@ -7430,7 +7435,9 @@
       break;
   }

+  ASSERT(new_map->has_fast_double_elements());
   set_map(new_map);
+  ASSERT(elems->IsFixedDoubleArray());
   set_elements(elems);

   if (IsJSArray()) {
@@ -8407,8 +8414,9 @@
     } else {
       new_length = dictionary->max_number_key() + 1;
     }
-    MaybeObject* result =
-        SetFastElementsCapacityAndLength(new_length, new_length);
+    MaybeObject* result = ShouldConvertToFastDoubleElements()
+        ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
+        : SetFastElementsCapacityAndLength(new_length, new_length);
     if (result->IsFailure()) return result;
 #ifdef DEBUG
     if (FLAG_trace_normalization) {
@@ -8495,6 +8503,9 @@
   }

   // Otherwise default to slow case.
+  ASSERT(HasFastDoubleElements());
+  ASSERT(map()->has_fast_double_elements());
+  ASSERT(elements()->IsFixedDoubleArray());
   Object* obj;
   { MaybeObject* maybe_obj = NormalizeElements();
     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
@@ -8948,10 +8959,13 @@
   int capacity = 0;
   int number_of_elements = 0;

-  FixedArray* backing_store = FixedArray::cast(elements());
+  FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
+  FixedArray* backing_store = NULL;
   switch (GetElementsKind()) {
     case NON_STRICT_ARGUMENTS_ELEMENTS:
-      backing_store = FixedArray::cast(backing_store->get(1));
+      backing_store_base =
+          FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
+      backing_store = FixedArray::cast(backing_store_base);
       if (backing_store->IsDictionary()) {
NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
         capacity = dictionary->Capacity();
@@ -8960,13 +8974,15 @@
       }
       // Fall through.
     case FAST_ELEMENTS:
+      backing_store = FixedArray::cast(backing_store_base);
       capacity = backing_store->length();
       for (int i = 0; i < capacity; ++i) {
         if (!backing_store->get(i)->IsTheHole()) ++number_of_elements;
       }
       break;
     case DICTIONARY_ELEMENTS: {
-      NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
+      NumberDictionary* dictionary =
+          NumberDictionary::cast(FixedArray::cast(elements()));
       capacity = dictionary->Capacity();
       number_of_elements = dictionary->NumberOfElements();
       break;
=======================================
--- /branches/bleeding_edge/src/objects.h       Wed Jul 13 04:13:40 2011
+++ /branches/bleeding_edge/src/objects.h       Wed Jul 13 06:50:27 2011
@@ -2173,23 +2173,9 @@
     return kHeaderSize + length * kDoubleSize;
   }

-  // The following can't be declared inline as const static
-  // because they're 64-bit.
-  static uint64_t kCanonicalNonHoleNanLower32;
-  static uint64_t kCanonicalNonHoleNanInt64;
-  static uint64_t kHoleNanInt64;
-
-  inline static bool is_the_hole_nan(double value) {
-    return BitCast<uint64_t, double>(value) == kHoleNanInt64;
-  }
-
-  inline static double hole_nan_as_double() {
-    return BitCast<double, uint64_t>(kHoleNanInt64);
-  }
-
-  inline static double canonical_not_the_hole_nan_as_double() {
-    return BitCast<double, uint64_t>(kCanonicalNonHoleNanInt64);
-  }
+  inline static bool is_the_hole_nan(double value);
+  inline static double hole_nan_as_double();
+  inline static double canonical_not_the_hole_nan_as_double();

   // Casting.
   static inline FixedDoubleArray* cast(Object* obj);
=======================================
--- /branches/bleeding_edge/src/stub-cache.h    Fri Jul  8 03:46:10 2011
+++ /branches/bleeding_edge/src/stub-cache.h    Wed Jul 13 06:50:27 2011
@@ -662,6 +662,8 @@

   static void GenerateLoadFastElement(MacroAssembler* masm);

+  static void GenerateLoadFastDoubleElement(MacroAssembler* masm);
+
   static void GenerateLoadDictionaryElement(MacroAssembler* masm);

  private:
@@ -717,6 +719,9 @@
   static void GenerateStoreFastElement(MacroAssembler* masm,
                                        bool is_js_array);

+  static void GenerateStoreFastDoubleElement(MacroAssembler* masm,
+                                             bool is_js_array);
+
   static void GenerateStoreExternalArray(MacroAssembler* masm,
JSObject::ElementsKind elements_kind);

=======================================
--- /branches/bleeding_edge/src/v8globals.h     Wed Jul 13 02:09:04 2011
+++ /branches/bleeding_edge/src/v8globals.h     Wed Jul 13 06:50:27 2011
@@ -506,6 +506,21 @@
   CALL_AS_FUNCTION
 };

+
+static const uint32_t kHoleNanUpper32 = 0x7FFFFFFF;
+static const uint32_t kHoleNanLower32 = 0xFFFFFFFF;
+static const uint32_t kCanonicalNonHoleNanUpper32 = 0x7FF10000;
+static const uint32_t kCanonicalNonHoleNanLower32 = 0xFFFFFFFF;
+static const uint32_t kNaNOrInfinityLowerBoundUpper32 = 0x7FF00000;
+
+const uint64_t kHoleNanInt64 =
+    (static_cast<uint64_t>(kHoleNanUpper32) << 32) | kHoleNanLower32;
+const uint64_t kCanonicalNonHoleNanInt64 =
+    (static_cast<uint64_t>(kCanonicalNonHoleNanUpper32) << 32) |
+        kCanonicalNonHoleNanLower32;
+const uint64_t kLastNonNaNInt64 =
+    (static_cast<uint64_t>(kNaNOrInfinityLowerBoundUpper32) << 32);
+
 } }  // namespace v8::internal

 #endif  // V8_V8GLOBALS_H_
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Fri Jul 8 03:46:10 2011 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Wed Jul 13 06:50:27 2011
@@ -384,6 +384,9 @@
     CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
                 Heap::kFixedArrayMapRootIndex);
     j(equal, &ok, Label::kNear);
+    CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
+                Heap::kFixedDoubleArrayMapRootIndex);
+    j(equal, &ok, Label::kNear);
     CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
                 Heap::kFixedCOWArrayMapRootIndex);
     j(equal, &ok, Label::kNear);
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Fri Jul 8 03:46:10 2011 +++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Wed Jul 13 06:50:27 2011
@@ -3582,6 +3582,57 @@
   Handle<Code> ic(code);
   __ jmp(ic, RelocInfo::CODE_TARGET);
 }
+
+
+void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
+    MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- rax    : key
+  //  -- rdx    : receiver
+  //  -- rsp[0] : return address
+  // -----------------------------------
+  Label miss_force_generic, slow_allocate_heapnumber;
+
+  // This stub is meant to be tail-jumped to, the receiver must already
+  // have been verified by the caller to not be a smi.
+
+  // Check that the key is a smi.
+  __ JumpIfNotSmi(rax, &miss_force_generic);
+
+  // Get the elements array.
+  __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
+  __ AssertFastElements(rcx);
+
+  // Check that the key is within bounds.
+  __ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset));
+  __ j(above_equal, &miss_force_generic);
+
+  // Check for the hole
+  __ SmiToInteger32(kScratchRegister, rax);
+ uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
+  __ cmpl(FieldOperand(rcx, kScratchRegister, times_8, offset),
+          Immediate(kHoleNanUpper32));
+  __ j(equal, &miss_force_generic);
+
+  // Always allocate a heap number for the result.
+  __ movsd(xmm0, FieldOperand(rcx, kScratchRegister, times_8,
+                              FixedDoubleArray::kHeaderSize));
+  __ AllocateHeapNumber(rcx, rbx, &slow_allocate_heapnumber);
+  // Set the value.
+  __ movq(rax, rcx);
+  __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
+  __ ret(0);
+
+  __ bind(&slow_allocate_heapnumber);
+  Handle<Code> slow_ic =
+      masm->isolate()->builtins()->KeyedLoadIC_Slow();
+  __ jmp(slow_ic, RelocInfo::CODE_TARGET);
+
+  __ bind(&miss_force_generic);
+  Handle<Code> miss_ic =
+      masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
+  __ jmp(miss_ic, RelocInfo::CODE_TARGET);
+}


 void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
@@ -3632,6 +3683,91 @@
       masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
   __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
 }
+
+
+void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
+    MacroAssembler* masm,
+    bool is_js_array) {
+  // ----------- S t a t e -------------
+  //  -- rax    : value
+  //  -- rcx    : key
+  //  -- rdx    : receiver
+  //  -- rsp[0] : return address
+  // -----------------------------------
+  Label miss_force_generic, smi_value, is_nan, maybe_nan;
+  Label have_double_value, not_nan;
+
+  // This stub is meant to be tail-jumped to, the receiver must already
+  // have been verified by the caller to not be a smi.
+
+  // Check that the key is a smi.
+  __ JumpIfNotSmi(rcx, &miss_force_generic);
+
+  // Get the elements array.
+  __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
+  __ AssertFastElements(rdi);
+
+  // Check that the key is within bounds.
+  if (is_js_array) {
+    __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
+  } else {
+    __ SmiCompare(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset));
+  }
+  __ j(above_equal, &miss_force_generic);
+
+  // Handle smi values specially
+  __ JumpIfSmi(rax, &smi_value, Label::kNear);
+
+  __ CheckMap(rax,
+              masm->isolate()->factory()->heap_number_map(),
+              &miss_force_generic,
+              DONT_DO_SMI_CHECK);
+
+  // Double value, canonicalize NaN.
+  uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32);
+  __ cmpl(FieldOperand(rax, offset),
+          Immediate(kNaNOrInfinityLowerBoundUpper32));
+  __ j(greater_equal, &maybe_nan, Label::kNear);
+
+  __ bind(&not_nan);
+  __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
+  __ bind(&have_double_value);
+  __ SmiToInteger32(rcx, rcx);
+  __ movsd(FieldOperand(rdi, rcx, times_8, FixedDoubleArray::kHeaderSize),
+           xmm0);
+  __ ret(0);
+
+  __ bind(&maybe_nan);
+  // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise
+  // it's an Infinity, and the non-NaN code path applies.
+  __ j(greater, &is_nan, Label::kNear);
+  __ cmpl(FieldOperand(rax, HeapNumber::kValueOffset), Immediate(0));
+  __ j(zero, &not_nan);
+  __ bind(&is_nan);
+ // Convert all NaNs to the same canonical NaN value when they are stored in
+  // the double array.
+  ExternalReference canonical_nan_reference =
+      ExternalReference::address_of_canonical_non_hole_nan();
+  __ Set(kScratchRegister, kCanonicalNonHoleNanInt64);
+  __ movq(xmm0, kScratchRegister);
+  __ jmp(&have_double_value, Label::kNear);
+
+  __ bind(&smi_value);
+  // Value is a smi. convert to a double and store.
+  __ SmiToInteger32(rax, rax);
+  __ push(rax);
+  __ fild_s(Operand(rsp, 0));
+  __ pop(rax);
+  __ SmiToInteger32(rcx, rcx);
+ __ fstp_d(FieldOperand(rdi, rcx, times_8, FixedDoubleArray::kHeaderSize));
+  __ ret(0);
+
+  // Handle store cache miss, replacing the ic with the generic stub.
+  __ bind(&miss_force_generic);
+  Handle<Code> ic_force_generic =
+      masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
+  __ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
+}


 #undef __
=======================================
--- /branches/bleeding_edge/test/mjsunit/unbox-double-arrays.js Thu Jun 9 03:03:35 2011 +++ /branches/bleeding_edge/test/mjsunit/unbox-double-arrays.js Wed Jul 13 06:50:27 2011
@@ -27,52 +27,255 @@

 // Test dictionary -> double elements -> dictionary elements round trip

-var foo = new Array(500000);
-
-function func(a) {
-  for (var i= 0; i < 100000; ++i ) {
-    a[i] = i+0.5;
+// Flags: --allow-natives-syntax --unbox-double-arrays
+var large_array_size = 500000;
+var approx_dict_to_elements_threshold = 69000;
+
+function expected_array_value(i) {
+  if ((i % 2) == 0) {
+    return i;
+  } else {
+    return i + 0.5;
   }
 }

-func(foo);
-
-for (var i= 0; i < 100000; i += 500 ) {
-  assertEquals(i+0.5, foo[i]);
+function force_to_fast_double_array(a) {
+  for (var i= 0; i < approx_dict_to_elements_threshold; ++i ) {
+    a[i] = expected_array_value(i);
+  }
+  assertTrue(%HasFastDoubleElements(a));
 }

-delete foo[5];
-// Don't use assertEquals for comparison to undefined due to
-assertTrue(undefined === foo[5]);
-assertTrue(undefined === foo[500000-1]);
-assertTrue(undefined === foo[-1]);
-assertEquals(500000, foo.length);
-
-// Cause the array to grow beyond it's JSArray length. This will double the
-// size of the capacity and force the array into "slow" dictionary case.
-foo[500001] = 50;
-assertEquals(50, foo[500001]);
-assertEquals(500002, foo.length);
-assertTrue(undefined === foo[5])
-assertTrue(undefined === foo[500000-1])
-assertTrue(undefined === foo[-1])
-assertEquals(500002, foo.length);
-
-// Test dictionary -> double elements -> fast elements.
-
-var foo2 = new Array(500000);
-func(foo2);
-delete foo2[5];
-
-// Convert back to fast elements and make sure the contents of the array are
-// unchanged.
-foo2[25] = new Object();
-for (var i= 0; i < 100000; i += 500 ) {
-  if (i != 25 && i != 5) {
-    assertEquals(i+0.5, foo2[i]);
-  }
-}
-assertTrue(undefined === foo2[5])
-assertTrue(undefined === foo2[500000-1])
-assertTrue(undefined === foo2[-1])
-assertEquals(500000, foo2.length);
+function testOneArrayType(allocator) {
+  var large_array = new allocator(500000);
+  force_to_fast_double_array(large_array);
+
+  for (var i= 0; i < approx_dict_to_elements_threshold; i += 501 ) {
+    assertEquals(expected_array_value(i), large_array[i]);
+  }
+
+  function get_test_various_loads() {
+    return function test_various_loads(a, value_5, value_6, value_7) {
+      assertTrue(%HasFastDoubleElements(a));
+      assertEquals(value_5, a[5]);
+      assertEquals(value_6, a[6]);
+      assertEquals(value_7, a[7]);
+      assertEquals(undefined, a[large_array_size-1]);
+      assertEquals(undefined, a[-1]);
+      assertEquals(large_array_size, a.length);
+      assertTrue(%HasFastDoubleElements(a));
+    }
+  }
+
+  function get_test_various_stores() {
+    return function test_various_stores(a, value_5, value_6, value_7) {
+      assertTrue(%HasFastDoubleElements(a));
+      a[5] = value_5;
+      a[6] = value_6;
+      a[7] = value_7;
+      assertTrue(%HasFastDoubleElements(a));
+    }
+  }
+
+ // Run tests up to three times to make sure both runtime and IC implementation
+  // (premonomorphic and monomorphic) of KeyedLoad access works in various
+  // cases.
+
+  // Test double and integer values
+  test_various_loads = get_test_various_loads();
+  test_various_loads(large_array,
+                     expected_array_value(5),
+                     expected_array_value(6),
+                     expected_array_value(7));
+  test_various_loads(large_array,
+                     expected_array_value(5),
+                     expected_array_value(6),
+                     expected_array_value(7));
+  test_various_loads(large_array,
+                     expected_array_value(5),
+                     expected_array_value(6),
+                     expected_array_value(7));
+
+  // Test NaN values
+  test_various_stores = get_test_various_stores();
+  test_various_stores(large_array, NaN, -NaN, expected_array_value(7));
+
+  test_various_loads(large_array,
+                     NaN,
+                     -NaN,
+                     expected_array_value(7));
+  test_various_loads(large_array,
+                     NaN,
+                     -NaN,
+                     expected_array_value(7));
+  test_various_loads(large_array,
+                     NaN,
+                     -NaN,
+                     expected_array_value(7));
+
+  // Test Infinity values
+  test_various_stores = get_test_various_stores();
+  test_various_stores(large_array,
+                      Infinity,
+                      -Infinity,
+                      expected_array_value(7));
+
+  test_various_loads(large_array,
+                     Infinity,
+                     -Infinity,
+                     expected_array_value(7));
+  test_various_loads(large_array,
+                     Infinity,
+                     -Infinity,
+                     expected_array_value(7));
+  test_various_loads(large_array,
+                     Infinity,
+                     -Infinity,
+                     expected_array_value(7));
+
+  // Test the hole for the default runtime implementation.
+  delete large_array[5];
+  delete large_array[6];
+  test_various_loads = get_test_various_loads();
+  test_various_loads(large_array,
+                     undefined,
+                     undefined,
+                     expected_array_value(7));
+
+  // Test the keyed load IC implementation when the value is the hole.
+  test_various_loads = get_test_various_loads();
+  test_various_stores(large_array,
+                      expected_array_value(5),
+                      expected_array_value(6),
+                      expected_array_value(7));
+  test_various_loads(large_array,
+                     expected_array_value(5),
+                     expected_array_value(6),
+                     expected_array_value(7));
+  test_various_loads(large_array,
+                     expected_array_value(5),
+                     expected_array_value(6),
+                     expected_array_value(7));
+  delete large_array[5];
+  delete large_array[6];
+  test_various_loads(large_array,
+                     undefined,
+                     undefined,
+                     expected_array_value(7));
+  test_various_loads(large_array,
+                     undefined,
+                     undefined,
+                     expected_array_value(7));
+
+  // Test both runtime and IC variants of double array stores for normal
+  // values (double and integer).
+  test_various_stores = get_test_various_stores();
+  test_various_stores(large_array,
+                      expected_array_value(4),
+                      expected_array_value(5),
+                      expected_array_value(6));
+  test_various_loads(large_array,
+                     expected_array_value(4),
+                     expected_array_value(5),
+                     expected_array_value(6));
+  test_various_stores(large_array,
+                      expected_array_value(5),
+                      expected_array_value(6),
+                      expected_array_value(7));
+  test_various_loads(large_array,
+                     expected_array_value(5),
+                     expected_array_value(6),
+                     expected_array_value(7));
+
+  // Test stores of NaN to make sure they don't get mistaken for the
+  // hole. Test both runtime and IC implementation.
+  test_various_stores = get_test_various_stores();
+  test_various_stores(large_array,
+                      NaN,
+                      -NaN,
+                      expected_array_value(6));
+  test_various_loads(large_array,
+                      NaN,
+                      -NaN,
+                     expected_array_value(6));
+  test_various_stores(large_array,
+                      expected_array_value(5),
+                      expected_array_value(6),
+                      expected_array_value(7));
+  test_various_loads(large_array,
+                     expected_array_value(5),
+                     expected_array_value(6),
+                     expected_array_value(7));
+  test_various_stores(large_array,
+                      NaN,
+                      -NaN,
+                      expected_array_value(7));
+  test_various_loads(large_array,
+                      NaN,
+                      -NaN,
+                     expected_array_value(7));
+
+  // Test stores of Infinity to make sure they don't get mistaken for the
+  // hole. Test both runtime and IC implementation.
+  test_various_stores = get_test_various_stores();
+  test_various_stores(large_array,
+                      Infinity,
+                      -Infinity,
+                      expected_array_value(6));
+  test_various_loads(large_array,
+                      Infinity,
+                      -Infinity,
+                     expected_array_value(6));
+  test_various_stores(large_array,
+                      expected_array_value(5),
+                      expected_array_value(6),
+                      expected_array_value(7));
+  test_various_loads(large_array,
+                     expected_array_value(5),
+                     expected_array_value(6),
+                     expected_array_value(7));
+  test_various_stores(large_array,
+                      Infinity,
+                      -Infinity,
+                      expected_array_value(7));
+  test_various_loads(large_array,
+                      Infinity,
+                      -Infinity,
+                     expected_array_value(7));
+
+  delete large_array[5];
+
+  // Make sure that we haven't converted from fast double.
+  assertTrue(%HasFastDoubleElements(large_array));
+ // Cause the array to grow beyond it's JSArray length. This will double the
+  // size of the capacity and force the array into "slow" dictionary case.
+  large_array[large_array_size+1] = 50;
+  assertTrue(%HasDictionaryElements(large_array));
+  assertEquals(50, large_array[large_array_size+1]);
+  assertEquals(large_array_size+2, large_array.length);
+  assertEquals(undefined, large_array[5]);
+  assertEquals(undefined, large_array[large_array_size-1]);
+  assertEquals(undefined, large_array[-1]);
+  assertEquals(large_array_size+2, large_array.length);
+
+  // Test dictionary -> double elements -> fast elements.
+  var large_array2 = new allocator(large_array_size);
+  force_to_fast_double_array(large_array2);
+  delete large_array2[5];
+
+ // Convert back to fast elements and make sure the contents of the array are
+  // unchanged.
+  large_array2[25] = new Object();
+  assertTrue(%HasFastElements(large_array2));
+  for (var i= 0; i < approx_dict_to_elements_threshold; i += 500 ) {
+    if (i != 25 && i != 5) {
+      assertEquals(expected_array_value(i), large_array2[i]);
+    }
+  }
+  assertEquals(undefined, large_array2[5])
+      assertEquals(undefined, large_array2[large_array_size-1])
+      assertEquals(undefined, large_array2[-1])
+      assertEquals(large_array_size, large_array2.length);
+}
+
+testOneArrayType(Array);

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to