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:
parent
3c13926936
commit
d5d7185578
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
};
|
||||
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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; }
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
};
|
||||
|
||||
|
||||
|
@ -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.
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
};
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user