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(¬_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, ¬_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(¬_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, ¬_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