Create a common base class for Fixed-, FixedDouble- and ExternalArrays.

Also unify Crankshaft code to load array length.

BUG=v8:1493
TEST=external-arrays.js

Review URL: http://codereview.chromium.org/7600025

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8901 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
danno@chromium.org 2011-08-11 14:00:16 +00:00
parent 3c13926936
commit d5d7185578
18 changed files with 172 additions and 283 deletions

View File

@ -1509,16 +1509,10 @@ LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
}
LInstruction* LChunkBuilder::DoExternalArrayLength(
HExternalArrayLength* instr) {
LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LExternalArrayLength(array));
}
LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LFixedArrayLength(array));
return DefineAsRegister(new LFixedArrayBaseLength(array));
}

View File

@ -92,8 +92,7 @@ class LCodeGen;
V(DivI) \
V(DoubleToI) \
V(ElementsKind) \
V(ExternalArrayLength) \
V(FixedArrayLength) \
V(FixedArrayBaseLength) \
V(FunctionLiteral) \
V(GetCachedArrayIndex) \
V(GlobalObject) \
@ -915,25 +914,15 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> {
};
class LExternalArrayLength: public LTemplateInstruction<1, 1, 0> {
class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LExternalArrayLength(LOperand* value) {
explicit LFixedArrayBaseLength(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length")
DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength)
};
class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LFixedArrayLength(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length")
DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength)
DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength,
"fixed-array-base-length")
DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength)
};

View File

@ -1378,17 +1378,10 @@ void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
}
void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0));
__ ldr(result, FieldMemOperand(array, ExternalArray::kLengthOffset));
}
void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0));
__ ldr(result, FieldMemOperand(array, FixedArray::kLengthOffset));
__ ldr(result, FieldMemOperand(array, FixedArrayBase::kLengthOffset));
}

View File

@ -3489,9 +3489,9 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// Check that the index is in range.
__ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
__ cmp(ip, Operand(key, ASR, kSmiTagSize));
__ cmp(key, ip);
// Unsigned comparison catches both negative and too-large values.
__ b(lo, &miss_force_generic);
__ b(hs, &miss_force_generic);
__ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
// r3: base pointer of external storage
@ -3811,22 +3811,20 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
__ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
// Check that the key is a smi.
__ JumpIfNotSmi(key, &miss_force_generic);
__ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
// Check that the index is in range
__ SmiUntag(r4, key);
__ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
__ cmp(r4, ip);
__ cmp(key, ip);
// Unsigned comparison catches both negative and too-large values.
__ b(hs, &miss_force_generic);
// Handle both smis and HeapNumbers in the fast path. Go to the
// runtime for all other kinds of values.
// r3: external array.
// r4: key (integer).
if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
// Double to pixel conversion is only implemented in the runtime for now.
__ JumpIfNotSmi(value, &slow);
@ -3837,32 +3835,32 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
// r3: base pointer of external storage.
// r4: key (integer).
// r5: value (integer).
switch (elements_kind) {
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
// Clamp the value to [0..255].
__ Usat(r5, 8, Operand(r5));
__ strb(r5, MemOperand(r3, r4, LSL, 0));
__ strb(r5, MemOperand(r3, key, LSR, 1));
break;
case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ strb(r5, MemOperand(r3, r4, LSL, 0));
__ strb(r5, MemOperand(r3, key, LSR, 1));
break;
case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ strh(r5, MemOperand(r3, r4, LSL, 1));
__ strh(r5, MemOperand(r3, key, LSL, 0));
break;
case JSObject::EXTERNAL_INT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ str(r5, MemOperand(r3, r4, LSL, 2));
__ str(r5, MemOperand(r3, key, LSL, 1));
break;
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
// Perform int-to-float conversion and store to memory.
__ SmiUntag(r4, key);
StoreIntAsFloat(masm, r3, r4, r5, r6, r7, r9);
break;
case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
__ add(r3, r3, Operand(r4, LSL, 3));
__ add(r3, r3, Operand(key, LSL, 2));
// r3: effective address of the double element
FloatingPointHelper::Destination destination;
if (CpuFeatures::IsSupported(VFP3)) {
@ -3895,7 +3893,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
if (elements_kind != JSObject::EXTERNAL_PIXEL_ELEMENTS) {
// r3: external array.
// r4: index (integer).
__ bind(&check_heap_number);
__ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE);
__ b(ne, &slow);
@ -3903,7 +3900,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
// r3: base pointer of external storage.
// r4: key (integer).
// The WebGL specification leaves the behavior of storing NaN and
// +/-Infinity into integer arrays basically undefined. For more
@ -3916,13 +3912,13 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// include -kHeapObjectTag into it.
__ sub(r5, r0, Operand(kHeapObjectTag));
__ vldr(d0, r5, HeapNumber::kValueOffset);
__ add(r5, r3, Operand(r4, LSL, 2));
__ add(r5, r3, Operand(key, LSL, 1));
__ vcvt_f32_f64(s0, d0);
__ vstr(s0, r5, 0);
} else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
__ sub(r5, r0, Operand(kHeapObjectTag));
__ vldr(d0, r5, HeapNumber::kValueOffset);
__ add(r5, r3, Operand(r4, LSL, 3));
__ add(r5, r3, Operand(key, LSL, 2));
__ vstr(d0, r5, 0);
} else {
// Hoisted load. vldr requires offset to be a multiple of 4 so we can
@ -3934,15 +3930,15 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
switch (elements_kind) {
case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ strb(r5, MemOperand(r3, r4, LSL, 0));
__ strb(r5, MemOperand(r3, key, LSR, 1));
break;
case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ strh(r5, MemOperand(r3, r4, LSL, 1));
__ strh(r5, MemOperand(r3, key, LSL, 0));
break;
case JSObject::EXTERNAL_INT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ str(r5, MemOperand(r3, r4, LSL, 2));
__ str(r5, MemOperand(r3, key, LSL, 1));
break;
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
@ -4004,7 +4000,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift));
__ bind(&done);
__ str(r5, MemOperand(r3, r4, LSL, 2));
__ str(r5, MemOperand(r3, key, LSL, 1));
// Entry registers are intact, r0 holds the value which is the return
// value.
__ Ret();
@ -4017,7 +4013,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift));
__ b(&done);
} else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
__ add(r7, r3, Operand(r4, LSL, 3));
__ add(r7, r3, Operand(key, LSL, 2));
// r7: effective address of destination element.
__ str(r6, MemOperand(r7, 0));
__ str(r5, MemOperand(r7, Register::kSizeInBytes));
@ -4073,15 +4069,15 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
switch (elements_kind) {
case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ strb(r5, MemOperand(r3, r4, LSL, 0));
__ strb(r5, MemOperand(r3, key, LSR, 1));
break;
case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ strh(r5, MemOperand(r3, r4, LSL, 1));
__ strh(r5, MemOperand(r3, key, LSL, 0));
break;
case JSObject::EXTERNAL_INT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ str(r5, MemOperand(r3, r4, LSL, 2));
__ str(r5, MemOperand(r3, key, LSL, 1));
break;
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
case JSObject::EXTERNAL_FLOAT_ELEMENTS:

View File

@ -104,8 +104,7 @@ class LChunkBuilder;
V(Div) \
V(ElementsKind) \
V(EnterInlined) \
V(ExternalArrayLength) \
V(FixedArrayLength) \
V(FixedArrayBaseLength) \
V(ForceRepresentation) \
V(FunctionLiteral) \
V(GetCachedArrayIndex) \
@ -1702,9 +1701,9 @@ class HJSArrayLength: public HTemplateInstruction<2> {
};
class HFixedArrayLength: public HUnaryOperation {
class HFixedArrayBaseLength: public HUnaryOperation {
public:
explicit HFixedArrayLength(HValue* value) : HUnaryOperation(value) {
explicit HFixedArrayBaseLength(HValue* value) : HUnaryOperation(value) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetFlag(kDependsOnArrayLengths);
@ -1714,28 +1713,7 @@ class HFixedArrayLength: public HUnaryOperation {
return Representation::Tagged();
}
DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength)
protected:
virtual bool DataEquals(HValue* other) { return true; }
};
class HExternalArrayLength: public HUnaryOperation {
public:
explicit HExternalArrayLength(HValue* value) : HUnaryOperation(value) {
set_representation(Representation::Integer32());
// The result of this instruction is idempotent as long as its inputs don't
// change. The length of a pixel array cannot change once set, so it's not
// necessary to introduce a kDependsOnArrayLengths or any other dependency.
SetFlag(kUseGVN);
}
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength)
DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength)
protected:
virtual bool DataEquals(HValue* other) { return true; }

View File

@ -3940,7 +3940,7 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
HInstruction* length = NULL;
HInstruction* checked_key = NULL;
if (map->has_external_array_elements()) {
length = AddInstruction(new(zone()) HExternalArrayLength(elements));
length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
HLoadExternalArrayPointer* external_elements =
new(zone()) HLoadExternalArrayPointer(elements);
@ -3952,7 +3952,7 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
if (map->instance_type() == JS_ARRAY_TYPE) {
length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck));
} else {
length = AddInstruction(new(zone()) HFixedArrayLength(elements));
length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
}
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
if (is_store) {
@ -4024,7 +4024,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
if (elements_kind == JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND
&& todo_external_array) {
HInstruction* length =
AddInstruction(new(zone()) HExternalArrayLength(elements));
AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
external_elements = new(zone()) HLoadExternalArrayPointer(elements);
AddInstruction(external_elements);
@ -4088,7 +4088,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
if_jsarray->Goto(join);
set_current_block(if_fastobject);
length = AddInstruction(new(zone()) HFixedArrayLength(elements));
length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
if (is_store) {
if (fast_double_elements) {

View File

@ -1211,17 +1211,11 @@ void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
}
void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
void LCodeGen::DoFixedArrayBaseLength(
LFixedArrayBaseLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0));
__ mov(result, FieldOperand(array, FixedArray::kLengthOffset));
}
void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0));
__ mov(result, FieldOperand(array, ExternalArray::kLengthOffset));
__ mov(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
}

View File

@ -1538,16 +1538,10 @@ LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
}
LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LFixedArrayLength(array));
}
LInstruction* LChunkBuilder::DoExternalArrayLength(
HExternalArrayLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LExternalArrayLength(array));
return DefineAsRegister(new LFixedArrayBaseLength(array));
}

View File

@ -86,8 +86,7 @@ class LCodeGen;
V(DivI) \
V(DoubleToI) \
V(ElementsKind) \
V(ExternalArrayLength) \
V(FixedArrayLength) \
V(FixedArrayBaseLength) \
V(FunctionLiteral) \
V(GetCachedArrayIndex) \
V(GlobalObject) \
@ -922,25 +921,15 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> {
};
class LExternalArrayLength: public LTemplateInstruction<1, 1, 0> {
class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LExternalArrayLength(LOperand* value) {
explicit LFixedArrayBaseLength(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length")
DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength)
};
class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LFixedArrayLength(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length")
DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength)
DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength,
"fixed-array-base-length")
DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength)
};

View File

@ -3400,37 +3400,37 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ JumpIfNotSmi(eax, &miss_force_generic);
// Check that the index is in range.
__ mov(ecx, eax);
__ SmiUntag(ecx); // Untag the index.
__ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
__ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
__ cmp(eax, FieldOperand(ebx, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values.
__ j(above_equal, &miss_force_generic);
__ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
// ebx: base pointer of external storage
switch (elements_kind) {
case JSObject::EXTERNAL_BYTE_ELEMENTS:
__ movsx_b(eax, Operand(ebx, ecx, times_1, 0));
__ SmiUntag(eax); // Untag the index.
__ movsx_b(eax, Operand(ebx, eax, times_1, 0));
break;
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
__ movzx_b(eax, Operand(ebx, ecx, times_1, 0));
__ SmiUntag(eax); // Untag the index.
__ movzx_b(eax, Operand(ebx, eax, times_1, 0));
break;
case JSObject::EXTERNAL_SHORT_ELEMENTS:
__ movsx_w(eax, Operand(ebx, ecx, times_2, 0));
__ movsx_w(eax, Operand(ebx, eax, times_1, 0));
break;
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ movzx_w(eax, Operand(ebx, ecx, times_2, 0));
__ movzx_w(eax, Operand(ebx, eax, times_1, 0));
break;
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
case JSObject::EXTERNAL_INT_ELEMENTS:
__ mov(ecx, Operand(ebx, ecx, times_4, 0));
__ mov(ecx, Operand(ebx, eax, times_2, 0));
break;
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
__ fld_s(Operand(ebx, ecx, times_4, 0));
__ fld_s(Operand(ebx, eax, times_2, 0));
break;
case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
__ fld_d(Operand(ebx, ecx, times_8, 0));
__ fld_d(Operand(ebx, eax, times_4, 0));
break;
default:
UNREACHABLE();
@ -3556,9 +3556,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// Check that the index is in range.
__ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
__ mov(ebx, ecx);
__ SmiUntag(ebx);
__ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset));
__ cmp(ecx, FieldOperand(edi, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values.
__ j(above_equal, &slow);
@ -3568,7 +3566,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// edx: receiver
// ecx: key
// edi: elements array
// ebx: untagged index
if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
__ JumpIfNotSmi(eax, &slow);
} else {
@ -3576,44 +3573,39 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
}
// smi case
__ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed.
__ SmiUntag(ecx);
__ mov(ebx, eax); // Preserve the value in eax as the return value.
__ SmiUntag(ebx);
__ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
// ecx: base pointer of external storage
// edi: base pointer of external storage
switch (elements_kind) {
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
{ // Clamp the value to [0..255].
Label done;
__ test(ecx, Immediate(0xFFFFFF00));
__ j(zero, &done, Label::kNear);
__ setcc(negative, ecx); // 1 if negative, 0 if positive.
__ dec_b(ecx); // 0 if negative, 255 if positive.
__ bind(&done);
}
__ mov_b(Operand(edi, ebx, times_1, 0), ecx);
__ ClampUint8(ebx);
__ SmiUntag(ecx);
__ mov_b(Operand(edi, ecx, times_1, 0), ebx);
break;
case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ mov_b(Operand(edi, ebx, times_1, 0), ecx);
__ SmiUntag(ecx);
__ mov_b(Operand(edi, ecx, times_1, 0), ebx);
break;
case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ mov_w(Operand(edi, ebx, times_2, 0), ecx);
__ mov_w(Operand(edi, ecx, times_1, 0), ebx);
break;
case JSObject::EXTERNAL_INT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ mov(Operand(edi, ebx, times_4, 0), ecx);
__ mov(Operand(edi, ecx, times_2, 0), ebx);
break;
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
// Need to perform int-to-float conversion.
__ push(ecx);
__ push(ebx);
__ fild_s(Operand(esp, 0));
__ pop(ecx);
__ pop(ebx);
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
__ fstp_s(Operand(edi, ebx, times_4, 0));
__ fstp_s(Operand(edi, ecx, times_2, 0));
} else { // elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS.
__ fstp_d(Operand(edi, ebx, times_8, 0));
__ fstp_d(Operand(edi, ecx, times_4, 0));
}
break;
default:
@ -3629,7 +3621,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// edx: receiver
// ecx: key
// edi: elements array
// ebx: untagged index
__ cmp(FieldOperand(eax, HeapObject::kMapOffset),
Immediate(masm->isolate()->factory()->heap_number_map()));
__ j(not_equal, &slow);
@ -3638,15 +3629,14 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// +/-Infinity into integer arrays basically undefined. For more
// reproducible behavior, convert these to zero.
__ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
// ebx: untagged index
// edi: base pointer of external storage
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ fstp_s(Operand(edi, ebx, times_4, 0));
__ fstp_s(Operand(edi, ecx, times_2, 0));
__ ret(0);
} else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ fstp_d(Operand(edi, ebx, times_8, 0));
__ fstp_d(Operand(edi, ecx, times_4, 0));
__ ret(0);
} else {
// Perform float-to-int conversion with truncation (round-to-zero)
@ -3661,27 +3651,20 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
elements_kind != JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) {
ASSERT(CpuFeatures::IsSupported(SSE2));
CpuFeatures::Scope scope(SSE2);
__ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset));
__ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset));
// ecx: untagged integer value
switch (elements_kind) {
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
{ // Clamp the value to [0..255].
Label done;
__ test(ecx, Immediate(0xFFFFFF00));
__ j(zero, &done, Label::kNear);
__ setcc(negative, ecx); // 1 if negative, 0 if positive.
__ dec_b(ecx); // 0 if negative, 255 if positive.
__ bind(&done);
}
__ mov_b(Operand(edi, ebx, times_1, 0), ecx);
break;
__ ClampUint8(ebx);
// Fall through.
case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ mov_b(Operand(edi, ebx, times_1, 0), ecx);
__ SmiUntag(ecx);
__ mov_b(Operand(edi, ecx, times_1, 0), ebx);
break;
case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ mov_w(Operand(edi, ebx, times_2, 0), ecx);
__ mov_w(Operand(edi, ecx, times_1, 0), ebx);
break;
default:
UNREACHABLE();
@ -3698,7 +3681,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ sub(Operand(esp), Immediate(2 * kPointerSize));
__ fisttp_d(Operand(esp, 0));
__ pop(ecx);
__ pop(ebx);
__ add(Operand(esp), Immediate(kPointerSize));
} else {
ASSERT(CpuFeatures::IsSupported(SSE2));
@ -3709,15 +3692,15 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// Note: we could do better for signed int arrays.
__ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
// We will need the key if we have to make the slow runtime call.
__ push(ecx);
__ LoadPowerOf2(xmm1, ecx, 31);
__ pop(ecx);
__ push(ebx);
__ LoadPowerOf2(xmm1, ebx, 31);
__ pop(ebx);
__ ucomisd(xmm1, xmm0);
__ j(above_equal, &slow);
__ cvttsd2si(ecx, Operand(xmm0));
__ cvttsd2si(ebx, Operand(xmm0));
}
// ecx: untagged integer value
__ mov(Operand(edi, ebx, times_4, 0), ecx);
// ebx: untagged integer value
__ mov(Operand(edi, ecx, times_2, 0), ebx);
}
__ ret(0); // Return original value.
}

View File

@ -3494,7 +3494,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
__ sra(t2, key, kSmiTagSize);
// Unsigned comparison catches both negative and too-large values.
__ Branch(&miss_force_generic, Uless, t1, Operand(t2));
__ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
__ lw(a3, FieldMemOperand(a3, ExternalArray::kExternalPointerOffset));
// a3: base pointer of external storage
@ -3822,16 +3822,16 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
__ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
// Check that the key is a smi.
// Check that the key is a smi.
__ JumpIfNotSmi(key, &miss_force_generic);
__ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
// Check that the index is in range.
__ SmiUntag(t0, key);
__ lw(t1, FieldMemOperand(a3, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values.
__ Branch(&miss_force_generic, Ugreater_equal, t0, Operand(t1));
__ Branch(&miss_force_generic, Ugreater_equal, key, Operand(t1));
// Handle both smis and HeapNumbers in the fast path. Go to the
// runtime for all other kinds of values.

View File

@ -2114,12 +2114,6 @@ HashTable<Shape, Key>* HashTable<Shape, Key>::cast(Object* obj) {
SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset)
SMI_ACCESSORS(ByteArray, length, kLengthOffset)
// TODO(1493): Investigate if it's possible to s/INT/SMI/ here (and
// subsequently unify H{Fixed,External}ArrayLength).
INT_ACCESSORS(ExternalArray, length, kLengthOffset)
SMI_ACCESSORS(String, length, kLengthOffset)

View File

@ -62,17 +62,8 @@
// - JSMessageObject
// - JSProxy
// - JSFunctionProxy
// - ByteArray
// - ExternalArray
// - ExternalPixelArray
// - ExternalByteArray
// - ExternalUnsignedByteArray
// - ExternalShortArray
// - ExternalUnsignedShortArray
// - ExternalIntArray
// - ExternalUnsignedIntArray
// - ExternalFloatArray
// - FixedArrayBase
// - ByteArray
// - FixedArray
// - DescriptorArray
// - HashTable
@ -85,6 +76,15 @@
// - JSFunctionResultCache
// - SerializedScopeInfo
// - FixedDoubleArray
// - ExternalArray
// - ExternalPixelArray
// - ExternalByteArray
// - ExternalUnsignedByteArray
// - ExternalShortArray
// - ExternalUnsignedShortArray
// - ExternalIntArray
// - ExternalUnsignedIntArray
// - ExternalFloatArray
// - String
// - SeqString
// - SeqAsciiString
@ -2084,6 +2084,7 @@ class FixedArrayBase: public HeapObject {
static const int kHeaderSize = kLengthOffset + kPointerSize;
};
class FixedDoubleArray;
// FixedArray describes fixed-sized arrays with element type Object*.
@ -3053,12 +3054,8 @@ class NormalizedMapCache: public FixedArray {
// ByteArray represents fixed sized byte arrays. Used by the outside world,
// such as PCRE, and also by the memory allocator and garbage collector to
// fill in free blocks in the heap.
class ByteArray: public HeapObject {
class ByteArray: public FixedArrayBase {
public:
// [length]: length of the array.
inline int length();
inline void set_length(int value);
// Setter and getter.
inline byte get(int index);
inline void set(int index, byte value);
@ -3103,10 +3100,6 @@ class ByteArray: public HeapObject {
#endif
// Layout description.
// Length is smi tagged when it is stored.
static const int kLengthOffset = HeapObject::kHeaderSize;
static const int kHeaderSize = kLengthOffset + kPointerSize;
static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize);
// Maximal memory consumption for a single ByteArray.
@ -3130,11 +3123,8 @@ class ByteArray: public HeapObject {
// Out-of-range values passed to the setter are converted via a C
// cast, not clamping. Out-of-range indices cause exceptions to be
// raised rather than being silently ignored.
class ExternalArray: public HeapObject {
class ExternalArray: public FixedArrayBase {
public:
// [length]: length of the array.
inline int length();
inline void set_length(int value);
inline bool is_the_hole(int index) { return false; }
@ -3149,9 +3139,8 @@ class ExternalArray: public HeapObject {
static const int kMaxLength = 0x3fffffff;
// ExternalArray headers are not quadword aligned.
static const int kLengthOffset = HeapObject::kHeaderSize;
static const int kExternalPointerOffset =
POINTER_SIZE_ALIGN(kLengthOffset + kIntSize);
POINTER_SIZE_ALIGN(FixedArrayBase::kLengthOffset + kPointerSize);
static const int kHeaderSize = kExternalPointerOffset + kPointerSize;
static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize);

View File

@ -1216,17 +1216,10 @@ void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
}
void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0));
__ movq(result, FieldOperand(array, FixedArray::kLengthOffset));
}
void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
Register result = ToRegister(instr->result());
Register array = ToRegister(instr->InputAt(0));
__ movl(result, FieldOperand(array, ExternalPixelArray::kLengthOffset));
__ movq(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
}

View File

@ -1498,16 +1498,10 @@ LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
}
LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
HFixedArrayBaseLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LFixedArrayLength(array));
}
LInstruction* LChunkBuilder::DoExternalArrayLength(
HExternalArrayLength* instr) {
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LExternalArrayLength(array));
return DefineAsRegister(new LFixedArrayBaseLength(array));
}

View File

@ -92,8 +92,7 @@ class LCodeGen;
V(DivI) \
V(DoubleToI) \
V(ElementsKind) \
V(ExternalArrayLength) \
V(FixedArrayLength) \
V(FixedArrayBaseLength) \
V(FunctionLiteral) \
V(GetCachedArrayIndex) \
V(GlobalObject) \
@ -913,25 +912,15 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> {
};
class LExternalArrayLength: public LTemplateInstruction<1, 1, 0> {
class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LExternalArrayLength(LOperand* value) {
explicit LFixedArrayBaseLength(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(ExternalArrayLength, "external-array-length")
DECLARE_HYDROGEN_ACCESSOR(ExternalArrayLength)
};
class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LFixedArrayLength(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length")
DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength)
DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength,
"fixed-array-base-length")
DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength)
};

View File

@ -3243,8 +3243,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// Check that the index is in range.
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
__ SmiToInteger32(rcx, rax);
__ cmpl(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset));
__ cmpl(rax, FieldOperand(rbx, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values.
__ j(above_equal, &miss_force_generic);
@ -3256,29 +3255,31 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// rbx: base pointer of external storage
switch (elements_kind) {
case JSObject::EXTERNAL_BYTE_ELEMENTS:
__ SmiToInteger32(rcx, rax);
__ movsxbq(rcx, Operand(rbx, rcx, times_1, 0));
break;
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ SmiToInteger32(rcx, rax);
__ movzxbq(rcx, Operand(rbx, rcx, times_1, 0));
break;
case JSObject::EXTERNAL_SHORT_ELEMENTS:
__ movsxwq(rcx, Operand(rbx, rcx, times_2, 0));
__ movsxwq(rcx, Operand(rbx, rax, times_1, 0));
break;
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ movzxwq(rcx, Operand(rbx, rcx, times_2, 0));
__ movzxwq(rcx, Operand(rbx, rax, times_1, 0));
break;
case JSObject::EXTERNAL_INT_ELEMENTS:
__ movsxlq(rcx, Operand(rbx, rcx, times_4, 0));
__ movsxlq(rcx, Operand(rbx, rax, times_2, 0));
break;
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ movl(rcx, Operand(rbx, rcx, times_4, 0));
__ movl(rcx, Operand(rbx, rax, times_2, 0));
break;
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
__ cvtss2sd(xmm0, Operand(rbx, rcx, times_4, 0));
__ cvtss2sd(xmm0, Operand(rbx, rax, times_2, 0));
break;
case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
__ movsd(xmm0, Operand(rbx, rcx, times_8, 0));
__ movsd(xmm0, Operand(rbx, rax, times_4, 0));
break;
default:
UNREACHABLE();
@ -3378,8 +3379,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// Check that the index is in range.
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
__ SmiToInteger32(rdi, rcx); // Untag the index.
__ cmpl(rdi, FieldOperand(rbx, ExternalArray::kLengthOffset));
__ cmpl(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset));
// Unsigned comparison catches both negative and too-large values.
__ j(above_equal, &miss_force_generic);
@ -3389,7 +3389,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// rcx: key (a smi)
// rdx: receiver (a JSObject)
// rbx: elements array
// rdi: untagged key
Label check_heap_number;
if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
// Float to pixel conversion is only implemented in the runtime for now.
@ -3403,37 +3402,32 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// rbx: base pointer of external storage
switch (elements_kind) {
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
{ // Clamp the value to [0..255].
Label done;
__ testl(rdx, Immediate(0xFFFFFF00));
__ j(zero, &done, Label::kNear);
__ setcc(negative, rdx); // 1 if negative, 0 if positive.
__ decb(rdx); // 0 if negative, 255 if positive.
__ bind(&done);
}
__ ClampUint8(rdx);
__ SmiToInteger32(rdi, rcx);
__ movb(Operand(rbx, rdi, times_1, 0), rdx);
break;
case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ SmiToInteger32(rdi, rcx);
__ movb(Operand(rbx, rdi, times_1, 0), rdx);
break;
case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ movw(Operand(rbx, rdi, times_2, 0), rdx);
__ movw(Operand(rbx, rcx, times_1, 0), rdx);
break;
case JSObject::EXTERNAL_INT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ movl(Operand(rbx, rdi, times_4, 0), rdx);
__ movl(Operand(rbx, rcx, times_2, 0), rdx);
break;
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
// Need to perform int-to-float conversion.
__ cvtlsi2ss(xmm0, rdx);
__ movss(Operand(rbx, rdi, times_4, 0), xmm0);
__ movss(Operand(rbx, rcx, times_2, 0), xmm0);
break;
case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
// Need to perform int-to-float conversion.
__ cvtlsi2sd(xmm0, rdx);
__ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
__ movsd(Operand(rbx, rcx, times_4, 0), xmm0);
break;
case JSObject::FAST_ELEMENTS:
case JSObject::FAST_DOUBLE_ELEMENTS:
@ -3451,7 +3445,6 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// rcx: key (a smi)
// rdx: receiver (a JSObject)
// rbx: elements array
// rdi: untagged key
__ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister);
__ j(not_equal, &slow);
// No more branches to slow case on this path.
@ -3461,15 +3454,15 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// reproducible behavior, convert these to zero.
__ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
__ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
// rdi: untagged index
// rbx: base pointer of external storage
// rcx: key
// top of FPU stack: value
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
__ cvtsd2ss(xmm0, xmm0);
__ movss(Operand(rbx, rdi, times_4, 0), xmm0);
__ movss(Operand(rbx, rcx, times_2, 0), xmm0);
__ ret(0);
} else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
__ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
__ movsd(Operand(rbx, rcx, times_4, 0), xmm0);
__ ret(0);
} else {
// Perform float-to-int conversion with truncation (round-to-zero)
@ -3482,24 +3475,31 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
// rdi: untagged index
// rbx: base pointer of external storage
switch (elements_kind) {
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
__ ClampUint8(rdx);
__ cvttsd2si(rdx, xmm0);
__ SmiToInteger32(rdi, rcx);
__ movb(Operand(rbx, rdi, times_1, 0), rdx);
break;
case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ cvttsd2si(rdx, xmm0);
__ SmiToInteger32(rdi, rcx);
__ movb(Operand(rbx, rdi, times_1, 0), rdx);
break;
case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ cvttsd2si(rdx, xmm0);
__ movw(Operand(rbx, rdi, times_2, 0), rdx);
__ SmiToInteger32(rdi, rcx);
__ movw(Operand(rbx, rcx, times_1, 0), rdx);
break;
case JSObject::EXTERNAL_INT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
// Convert to int64, so that NaN and infinities become
// 0x8000000000000000, which is zero mod 2^32.
__ cvttsd2siq(rdx, xmm0);
__ movl(Operand(rbx, rdi, times_4, 0), rdx);
__ movl(Operand(rbx, rcx, times_2, 0), rdx);
break;
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
case JSObject::FAST_ELEMENTS:

View File

@ -190,9 +190,19 @@ function run_test(test_func, array, expected_result) {
gc(); // Makes V8 forget about type information for test_func.
}
function run_bounds_test(test_func, array, expected_result) {
assertEquals(undefined, a[kElementCount]);
a[kElementCount] = 456;
assertEquals(undefined, a[kElementCount]);
assertEquals(undefined, a[kElementCount+1]);
a[kElementCount+1] = 456;
assertEquals(undefined, a[kElementCount+1]);
}
for (var t = 0; t < types.length; t++) {
var type = types[t];
var a = new type(kElementCount);
for (var i = 0; i < kElementCount; i++) {
a[i] = i;
}
@ -220,6 +230,16 @@ for (var t = 0; t < types.length; t++) {
assertTrue(delete a.length);
a.length = 2;
assertEquals(2, a.length);
// Make sure bounds checks are handled correctly for external arrays.
run_bounds_test(a);
run_bounds_test(a);
run_bounds_test(a);
%OptimizeFunctionOnNextCall(run_bounds_test);
run_bounds_test(a);
%DeoptimizeFunction(run_bounds_test);
gc(); // Makes V8 forget about type information for test_func.
}
function array_load_set_smi_check(a) {