Consolidated all the key store/load classes in the Hydrogen and Lithium
space into just two: HLoadKeyed/HLoadKeyedGeneric and HStoreKeyed/HStoreKeyedGeneric LLoadKeyed/LLoadKeyedGeneric and LStoreKeyed/LStoreKeyedGeneric BUG= Review URL: https://codereview.chromium.org/11238016 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12839 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
d2dc5ff546
commit
a85fd03caa
@ -372,16 +372,7 @@ void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintTo(stream);
|
||||
stream->Add("[");
|
||||
key()->PrintTo(stream);
|
||||
stream->Add("] <- ");
|
||||
value()->PrintTo(stream);
|
||||
}
|
||||
|
||||
|
||||
void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
|
||||
void LStoreKeyed::PrintDataTo(StringStream* stream) {
|
||||
elements()->PrintTo(stream);
|
||||
stream->Add("[");
|
||||
key()->PrintTo(stream);
|
||||
@ -1860,53 +1851,40 @@ LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
|
||||
HLoadKeyedFastElement* instr) {
|
||||
ASSERT(instr->representation().IsTagged());
|
||||
LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
LOperand* obj = UseRegisterAtStart(instr->object());
|
||||
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
|
||||
LLoadKeyedFastElement* result = new(zone()) LLoadKeyedFastElement(obj, key);
|
||||
if (instr->RequiresHoleCheck()) AssignEnvironment(result);
|
||||
return DefineAsRegister(result);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
|
||||
HLoadKeyedFastDoubleElement* instr) {
|
||||
ASSERT(instr->representation().IsDouble());
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
LOperand* elements = UseTempRegister(instr->elements());
|
||||
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
|
||||
LLoadKeyedFastDoubleElement* result =
|
||||
new(zone()) LLoadKeyedFastDoubleElement(elements, key);
|
||||
return AssignEnvironment(DefineAsRegister(result));
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
|
||||
HLoadKeyedSpecializedArrayElement* instr) {
|
||||
ElementsKind elements_kind = instr->elements_kind();
|
||||
ASSERT(
|
||||
(instr->representation().IsInteger32() &&
|
||||
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
|
||||
(elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
|
||||
(instr->representation().IsDouble() &&
|
||||
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
|
||||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
LOperand* external_pointer = UseRegister(instr->external_pointer());
|
||||
LOperand* key = UseRegisterOrConstant(instr->key());
|
||||
LLoadKeyedSpecializedArrayElement* result =
|
||||
new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer, key);
|
||||
LInstruction* load_instr = DefineAsRegister(result);
|
||||
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
|
||||
LLoadKeyed* result = NULL;
|
||||
|
||||
if (!instr->is_external()) {
|
||||
LOperand* obj = NULL;
|
||||
if (instr->representation().IsDouble()) {
|
||||
obj = UseTempRegister(instr->elements());
|
||||
} else {
|
||||
ASSERT(instr->representation().IsTagged());
|
||||
obj = UseRegisterAtStart(instr->elements());
|
||||
}
|
||||
result = new(zone()) LLoadKeyed(obj, key);
|
||||
} else {
|
||||
ASSERT(
|
||||
(instr->representation().IsInteger32() &&
|
||||
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
|
||||
(elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
|
||||
(instr->representation().IsDouble() &&
|
||||
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
|
||||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
|
||||
LOperand* external_pointer = UseRegister(instr->elements());
|
||||
result = new(zone()) LLoadKeyed(external_pointer, key);
|
||||
}
|
||||
|
||||
DefineAsRegister(result);
|
||||
// An unsigned int array load might overflow and cause a deopt, make sure it
|
||||
// has an environment.
|
||||
return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) ?
|
||||
AssignEnvironment(load_instr) : load_instr;
|
||||
bool can_deoptimize = instr->RequiresHoleCheck() ||
|
||||
(elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS);
|
||||
return can_deoptimize ? AssignEnvironment(result) : result;
|
||||
}
|
||||
|
||||
|
||||
@ -1920,66 +1898,48 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
|
||||
HStoreKeyedFastElement* instr) {
|
||||
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
|
||||
ElementsKind elements_kind = instr->elements_kind();
|
||||
bool needs_write_barrier = instr->NeedsWriteBarrier();
|
||||
ASSERT(instr->value()->representation().IsTagged());
|
||||
ASSERT(instr->object()->representation().IsTagged());
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
|
||||
LOperand* obj = UseTempRegister(instr->object());
|
||||
LOperand* val = needs_write_barrier
|
||||
? UseTempRegister(instr->value())
|
||||
: UseRegisterAtStart(instr->value());
|
||||
LOperand* key = needs_write_barrier
|
||||
? UseTempRegister(instr->key())
|
||||
: UseRegisterOrConstantAtStart(instr->key());
|
||||
return new(zone()) LStoreKeyedFastElement(obj, key, val);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement(
|
||||
HStoreKeyedFastDoubleElement* instr) {
|
||||
ASSERT(instr->value()->representation().IsDouble());
|
||||
ASSERT(instr->elements()->representation().IsTagged());
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
|
||||
LOperand* elements = UseRegisterAtStart(instr->elements());
|
||||
LOperand* val = UseTempRegister(instr->value());
|
||||
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
|
||||
|
||||
return new(zone()) LStoreKeyedFastDoubleElement(elements, key, val);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
|
||||
HStoreKeyedSpecializedArrayElement* instr) {
|
||||
ElementsKind elements_kind = instr->elements_kind();
|
||||
ASSERT(
|
||||
(instr->value()->representation().IsInteger32() &&
|
||||
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
|
||||
(elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
|
||||
(instr->value()->representation().IsDouble() &&
|
||||
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
|
||||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
|
||||
ASSERT(instr->external_pointer()->representation().IsExternal());
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
|
||||
LOperand* external_pointer = UseRegister(instr->external_pointer());
|
||||
bool val_is_temp_register =
|
||||
elements_kind == EXTERNAL_PIXEL_ELEMENTS ||
|
||||
elements_kind == EXTERNAL_FLOAT_ELEMENTS;
|
||||
LOperand* val = val_is_temp_register
|
||||
LOperand* val = val_is_temp_register || needs_write_barrier
|
||||
? UseTempRegister(instr->value())
|
||||
: UseRegister(instr->value());
|
||||
LOperand* key = UseRegisterOrConstant(instr->key());
|
||||
|
||||
return new(zone()) LStoreKeyedSpecializedArrayElement(external_pointer,
|
||||
key,
|
||||
val);
|
||||
LStoreKeyed* result = NULL;
|
||||
if (!instr->is_external()) {
|
||||
ASSERT(instr->elements()->representation().IsTagged());
|
||||
|
||||
LOperand* object = NULL;
|
||||
if (instr->value()->representation().IsDouble()) {
|
||||
object = UseRegisterAtStart(instr->elements());
|
||||
} else {
|
||||
ASSERT(instr->value()->representation().IsTagged());
|
||||
object = UseTempRegister(instr->elements());
|
||||
}
|
||||
|
||||
result = new(zone()) LStoreKeyed(object, key, val);
|
||||
} else {
|
||||
ASSERT(
|
||||
(instr->value()->representation().IsInteger32() &&
|
||||
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
|
||||
(elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
|
||||
(instr->value()->representation().IsDouble() &&
|
||||
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
|
||||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
|
||||
ASSERT(instr->elements()->representation().IsExternal());
|
||||
|
||||
LOperand* external_pointer = UseRegister(instr->elements());
|
||||
result = new(zone()) LStoreKeyed(external_pointer, key, val);
|
||||
}
|
||||
|
||||
ASSERT(result != NULL);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -125,10 +125,8 @@ class LCodeGen;
|
||||
V(LoadFunctionPrototype) \
|
||||
V(LoadGlobalCell) \
|
||||
V(LoadGlobalGeneric) \
|
||||
V(LoadKeyedFastDoubleElement) \
|
||||
V(LoadKeyedFastElement) \
|
||||
V(LoadKeyed) \
|
||||
V(LoadKeyedGeneric) \
|
||||
V(LoadKeyedSpecializedArrayElement) \
|
||||
V(LoadNamedField) \
|
||||
V(LoadNamedFieldPolymorphic) \
|
||||
V(LoadNamedGeneric) \
|
||||
@ -157,10 +155,8 @@ class LCodeGen;
|
||||
V(StoreContextSlot) \
|
||||
V(StoreGlobalCell) \
|
||||
V(StoreGlobalGeneric) \
|
||||
V(StoreKeyedFastDoubleElement) \
|
||||
V(StoreKeyedFastElement) \
|
||||
V(StoreKeyed) \
|
||||
V(StoreKeyedGeneric) \
|
||||
V(StoreKeyedSpecializedArrayElement) \
|
||||
V(StoreNamedField) \
|
||||
V(StoreNamedGeneric) \
|
||||
V(StringAdd) \
|
||||
@ -1357,58 +1353,25 @@ class LLoadExternalArrayPointer: public LTemplateInstruction<1, 1, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
|
||||
class LLoadKeyed: public LTemplateInstruction<1, 2, 0> {
|
||||
public:
|
||||
LLoadKeyedFastElement(LOperand* elements, LOperand* key) {
|
||||
LLoadKeyed(LOperand* elements, LOperand* key) {
|
||||
inputs_[0] = elements;
|
||||
inputs_[1] = key;
|
||||
}
|
||||
|
||||
LOperand* elements() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement, "load-keyed-fast-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastElement)
|
||||
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
};
|
||||
|
||||
|
||||
class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
|
||||
public:
|
||||
LLoadKeyedFastDoubleElement(LOperand* elements, LOperand* key) {
|
||||
inputs_[0] = elements;
|
||||
inputs_[1] = key;
|
||||
}
|
||||
|
||||
LOperand* elements() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement,
|
||||
"load-keyed-fast-double-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastDoubleElement)
|
||||
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
};
|
||||
|
||||
|
||||
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
|
||||
public:
|
||||
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LOperand* key) {
|
||||
inputs_[0] = external_pointer;
|
||||
inputs_[1] = key;
|
||||
}
|
||||
|
||||
LOperand* external_pointer() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement,
|
||||
"load-keyed-specialized-array-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedSpecializedArrayElement)
|
||||
|
||||
ElementsKind elements_kind() const {
|
||||
return hydrogen()->elements_kind();
|
||||
}
|
||||
bool is_external() const {
|
||||
return hydrogen()->is_external();
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
|
||||
DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
|
||||
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
};
|
||||
|
||||
@ -1922,51 +1885,28 @@ class LStoreNamedGeneric: public LTemplateInstruction<0, 2, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
|
||||
class LStoreKeyed: public LTemplateInstruction<0, 3, 0> {
|
||||
public:
|
||||
LStoreKeyedFastElement(LOperand* object, LOperand* key, LOperand* value) {
|
||||
LStoreKeyed(LOperand* object, LOperand* key, LOperand* value) {
|
||||
inputs_[0] = object;
|
||||
inputs_[1] = key;
|
||||
inputs_[2] = value;
|
||||
}
|
||||
|
||||
LOperand* object() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
LOperand* value() { return inputs_[2]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement,
|
||||
"store-keyed-fast-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastElement)
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
};
|
||||
|
||||
|
||||
class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> {
|
||||
public:
|
||||
LStoreKeyedFastDoubleElement(LOperand* elements,
|
||||
LOperand* key,
|
||||
LOperand* value) {
|
||||
inputs_[0] = elements;
|
||||
inputs_[1] = key;
|
||||
inputs_[2] = value;
|
||||
}
|
||||
|
||||
bool is_external() const { return hydrogen()->is_external(); }
|
||||
LOperand* elements() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
LOperand* value() { return inputs_[2]; }
|
||||
ElementsKind elements_kind() const {
|
||||
return hydrogen()->elements_kind();
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement,
|
||||
"store-keyed-fast-double-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastDoubleElement)
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed")
|
||||
DECLARE_HYDROGEN_ACCESSOR(StoreKeyed)
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
|
||||
bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
};
|
||||
|
||||
|
||||
@ -1990,28 +1930,6 @@ class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> {
|
||||
StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); }
|
||||
};
|
||||
|
||||
class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
|
||||
public:
|
||||
LStoreKeyedSpecializedArrayElement(LOperand* external_pointer,
|
||||
LOperand* key,
|
||||
LOperand* value) {
|
||||
inputs_[0] = external_pointer;
|
||||
inputs_[1] = key;
|
||||
inputs_[2] = value;
|
||||
}
|
||||
|
||||
LOperand* external_pointer() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
LOperand* value() { return inputs_[2]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement,
|
||||
"store-keyed-specialized-array-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedSpecializedArrayElement)
|
||||
|
||||
ElementsKind elements_kind() const { return hydrogen()->elements_kind(); }
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
};
|
||||
|
||||
|
||||
class LTransitionElementsKind: public LTemplateInstruction<1, 1, 2> {
|
||||
public:
|
||||
|
@ -2918,130 +2918,8 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
|
||||
Register elements = ToRegister(instr->elements());
|
||||
Register result = ToRegister(instr->result());
|
||||
Register scratch = scratch0();
|
||||
Register store_base = scratch;
|
||||
int offset = 0;
|
||||
|
||||
if (instr->key()->IsConstantOperand()) {
|
||||
LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
|
||||
offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) +
|
||||
instr->additional_index());
|
||||
store_base = elements;
|
||||
} else {
|
||||
Register key = EmitLoadRegister(instr->key(), scratch0());
|
||||
// Even though the HLoadKeyedFastElement instruction forces the input
|
||||
// representation for the key to be an integer, the input gets replaced
|
||||
// during bound check elimination with the index argument to the bounds
|
||||
// check, which can be tagged, so that case must be handled here, too.
|
||||
if (instr->hydrogen()->key()->representation().IsTagged()) {
|
||||
__ add(scratch, elements,
|
||||
Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
|
||||
} else {
|
||||
__ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
|
||||
}
|
||||
offset = FixedArray::OffsetOfElementAt(instr->additional_index());
|
||||
}
|
||||
__ ldr(result, FieldMemOperand(store_base, offset));
|
||||
|
||||
// Check for the hole value.
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
|
||||
__ tst(result, Operand(kSmiTagMask));
|
||||
DeoptimizeIf(ne, instr->environment());
|
||||
} else {
|
||||
__ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
|
||||
__ cmp(result, scratch);
|
||||
DeoptimizeIf(eq, instr->environment());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedFastDoubleElement(
|
||||
LLoadKeyedFastDoubleElement* instr) {
|
||||
Register elements = ToRegister(instr->elements());
|
||||
bool key_is_constant = instr->key()->IsConstantOperand();
|
||||
Register key = no_reg;
|
||||
DwVfpRegister result = ToDoubleRegister(instr->result());
|
||||
Register scratch = scratch0();
|
||||
|
||||
int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
|
||||
int shift_size = (instr->hydrogen()->key()->representation().IsTagged())
|
||||
? (element_size_shift - kSmiTagSize) : element_size_shift;
|
||||
int constant_key = 0;
|
||||
if (key_is_constant) {
|
||||
constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
|
||||
if (constant_key & 0xF0000000) {
|
||||
Abort("array index constant value too big.");
|
||||
}
|
||||
} else {
|
||||
key = ToRegister(instr->key());
|
||||
}
|
||||
|
||||
Operand operand = key_is_constant
|
||||
? Operand(((constant_key + instr->additional_index()) <<
|
||||
element_size_shift) +
|
||||
FixedDoubleArray::kHeaderSize - kHeapObjectTag)
|
||||
: Operand(key, LSL, shift_size);
|
||||
__ add(elements, elements, operand);
|
||||
if (!key_is_constant) {
|
||||
__ add(elements, elements,
|
||||
Operand((FixedDoubleArray::kHeaderSize - kHeapObjectTag) +
|
||||
(instr->additional_index() << element_size_shift)));
|
||||
}
|
||||
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
__ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
|
||||
__ cmp(scratch, Operand(kHoleNanUpper32));
|
||||
DeoptimizeIf(eq, instr->environment());
|
||||
}
|
||||
|
||||
__ vldr(result, elements, 0);
|
||||
}
|
||||
|
||||
|
||||
MemOperand LCodeGen::PrepareKeyedOperand(Register key,
|
||||
Register base,
|
||||
bool key_is_constant,
|
||||
int constant_key,
|
||||
int element_size,
|
||||
int shift_size,
|
||||
int additional_index,
|
||||
int additional_offset) {
|
||||
if (additional_index != 0 && !key_is_constant) {
|
||||
additional_index *= 1 << (element_size - shift_size);
|
||||
__ add(scratch0(), key, Operand(additional_index));
|
||||
}
|
||||
|
||||
if (key_is_constant) {
|
||||
return MemOperand(base,
|
||||
(constant_key << element_size) + additional_offset);
|
||||
}
|
||||
|
||||
if (additional_index == 0) {
|
||||
if (shift_size >= 0) {
|
||||
return MemOperand(base, key, LSL, shift_size);
|
||||
} else {
|
||||
ASSERT_EQ(-1, shift_size);
|
||||
return MemOperand(base, key, LSR, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (shift_size >= 0) {
|
||||
return MemOperand(base, scratch0(), LSL, shift_size);
|
||||
} else {
|
||||
ASSERT_EQ(-1, shift_size);
|
||||
return MemOperand(base, scratch0(), LSR, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
|
||||
LLoadKeyedSpecializedArrayElement* instr) {
|
||||
Register external_pointer = ToRegister(instr->external_pointer());
|
||||
void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
|
||||
Register external_pointer = ToRegister(instr->elements());
|
||||
Register key = no_reg;
|
||||
ElementsKind elements_kind = instr->elements_kind();
|
||||
bool key_is_constant = instr->key()->IsConstantOperand();
|
||||
@ -3120,6 +2998,137 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
|
||||
Register elements = ToRegister(instr->elements());
|
||||
bool key_is_constant = instr->key()->IsConstantOperand();
|
||||
Register key = no_reg;
|
||||
DwVfpRegister result = ToDoubleRegister(instr->result());
|
||||
Register scratch = scratch0();
|
||||
|
||||
int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
|
||||
int shift_size = (instr->hydrogen()->key()->representation().IsTagged())
|
||||
? (element_size_shift - kSmiTagSize) : element_size_shift;
|
||||
int constant_key = 0;
|
||||
if (key_is_constant) {
|
||||
constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
|
||||
if (constant_key & 0xF0000000) {
|
||||
Abort("array index constant value too big.");
|
||||
}
|
||||
} else {
|
||||
key = ToRegister(instr->key());
|
||||
}
|
||||
|
||||
Operand operand = key_is_constant
|
||||
? Operand(((constant_key + instr->additional_index()) <<
|
||||
element_size_shift) +
|
||||
FixedDoubleArray::kHeaderSize - kHeapObjectTag)
|
||||
: Operand(key, LSL, shift_size);
|
||||
__ add(elements, elements, operand);
|
||||
if (!key_is_constant) {
|
||||
__ add(elements, elements,
|
||||
Operand((FixedDoubleArray::kHeaderSize - kHeapObjectTag) +
|
||||
(instr->additional_index() << element_size_shift)));
|
||||
}
|
||||
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
__ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
|
||||
__ cmp(scratch, Operand(kHoleNanUpper32));
|
||||
DeoptimizeIf(eq, instr->environment());
|
||||
}
|
||||
|
||||
__ vldr(result, elements, 0);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
|
||||
Register elements = ToRegister(instr->elements());
|
||||
Register result = ToRegister(instr->result());
|
||||
Register scratch = scratch0();
|
||||
Register store_base = scratch;
|
||||
int offset = 0;
|
||||
|
||||
if (instr->key()->IsConstantOperand()) {
|
||||
LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
|
||||
offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) +
|
||||
instr->additional_index());
|
||||
store_base = elements;
|
||||
} else {
|
||||
Register key = EmitLoadRegister(instr->key(), scratch0());
|
||||
// Even though the HLoadKeyed instruction forces the input
|
||||
// representation for the key to be an integer, the input gets replaced
|
||||
// during bound check elimination with the index argument to the bounds
|
||||
// check, which can be tagged, so that case must be handled here, too.
|
||||
if (instr->hydrogen()->key()->representation().IsTagged()) {
|
||||
__ add(scratch, elements,
|
||||
Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
|
||||
} else {
|
||||
__ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
|
||||
}
|
||||
offset = FixedArray::OffsetOfElementAt(instr->additional_index());
|
||||
}
|
||||
__ ldr(result, FieldMemOperand(store_base, offset));
|
||||
|
||||
// Check for the hole value.
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
|
||||
__ tst(result, Operand(kSmiTagMask));
|
||||
DeoptimizeIf(ne, instr->environment());
|
||||
} else {
|
||||
__ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
|
||||
__ cmp(result, scratch);
|
||||
DeoptimizeIf(eq, instr->environment());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
|
||||
if (instr->is_external()) {
|
||||
DoLoadKeyedExternalArray(instr);
|
||||
} else if (instr->hydrogen()->representation().IsDouble()) {
|
||||
DoLoadKeyedFixedDoubleArray(instr);
|
||||
} else {
|
||||
DoLoadKeyedFixedArray(instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MemOperand LCodeGen::PrepareKeyedOperand(Register key,
|
||||
Register base,
|
||||
bool key_is_constant,
|
||||
int constant_key,
|
||||
int element_size,
|
||||
int shift_size,
|
||||
int additional_index,
|
||||
int additional_offset) {
|
||||
if (additional_index != 0 && !key_is_constant) {
|
||||
additional_index *= 1 << (element_size - shift_size);
|
||||
__ add(scratch0(), key, Operand(additional_index));
|
||||
}
|
||||
|
||||
if (key_is_constant) {
|
||||
return MemOperand(base,
|
||||
(constant_key << element_size) + additional_offset);
|
||||
}
|
||||
|
||||
if (additional_index == 0) {
|
||||
if (shift_size >= 0) {
|
||||
return MemOperand(base, key, LSL, shift_size);
|
||||
} else {
|
||||
ASSERT_EQ(-1, shift_size);
|
||||
return MemOperand(base, key, LSR, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (shift_size >= 0) {
|
||||
return MemOperand(base, scratch0(), LSL, shift_size);
|
||||
} else {
|
||||
ASSERT_EQ(-1, shift_size);
|
||||
return MemOperand(base, scratch0(), LSR, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
|
||||
ASSERT(ToRegister(instr->object()).is(r1));
|
||||
ASSERT(ToRegister(instr->key()).is(r0));
|
||||
@ -4000,102 +4009,8 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
|
||||
Register value = ToRegister(instr->value());
|
||||
Register elements = ToRegister(instr->object());
|
||||
Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
|
||||
Register scratch = scratch0();
|
||||
Register store_base = scratch;
|
||||
int offset = 0;
|
||||
|
||||
// Do the store.
|
||||
if (instr->key()->IsConstantOperand()) {
|
||||
ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
|
||||
LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
|
||||
offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) +
|
||||
instr->additional_index());
|
||||
store_base = elements;
|
||||
} else {
|
||||
// Even though the HLoadKeyedFastElement instruction forces the input
|
||||
// representation for the key to be an integer, the input gets replaced
|
||||
// during bound check elimination with the index argument to the bounds
|
||||
// check, which can be tagged, so that case must be handled here, too.
|
||||
if (instr->hydrogen()->key()->representation().IsTagged()) {
|
||||
__ add(scratch, elements,
|
||||
Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
|
||||
} else {
|
||||
__ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
|
||||
}
|
||||
offset = FixedArray::OffsetOfElementAt(instr->additional_index());
|
||||
}
|
||||
__ str(value, FieldMemOperand(store_base, offset));
|
||||
|
||||
if (instr->hydrogen()->NeedsWriteBarrier()) {
|
||||
HType type = instr->hydrogen()->value()->type();
|
||||
SmiCheck check_needed =
|
||||
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
|
||||
// Compute address of modified element and store it into key register.
|
||||
__ add(key, store_base, Operand(offset - kHeapObjectTag));
|
||||
__ RecordWrite(elements,
|
||||
key,
|
||||
value,
|
||||
kLRHasBeenSaved,
|
||||
kSaveFPRegs,
|
||||
EMIT_REMEMBERED_SET,
|
||||
check_needed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyedFastDoubleElement(
|
||||
LStoreKeyedFastDoubleElement* instr) {
|
||||
DwVfpRegister value = ToDoubleRegister(instr->value());
|
||||
Register elements = ToRegister(instr->elements());
|
||||
Register key = no_reg;
|
||||
Register scratch = scratch0();
|
||||
bool key_is_constant = instr->key()->IsConstantOperand();
|
||||
int constant_key = 0;
|
||||
|
||||
// Calculate the effective address of the slot in the array to store the
|
||||
// double value.
|
||||
if (key_is_constant) {
|
||||
constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
|
||||
if (constant_key & 0xF0000000) {
|
||||
Abort("array index constant value too big.");
|
||||
}
|
||||
} else {
|
||||
key = ToRegister(instr->key());
|
||||
}
|
||||
int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
|
||||
int shift_size = (instr->hydrogen()->key()->representation().IsTagged())
|
||||
? (element_size_shift - kSmiTagSize) : element_size_shift;
|
||||
Operand operand = key_is_constant
|
||||
? Operand((constant_key << element_size_shift) +
|
||||
FixedDoubleArray::kHeaderSize - kHeapObjectTag)
|
||||
: Operand(key, LSL, shift_size);
|
||||
__ add(scratch, elements, operand);
|
||||
if (!key_is_constant) {
|
||||
__ add(scratch, scratch,
|
||||
Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
|
||||
}
|
||||
|
||||
if (instr->NeedsCanonicalization()) {
|
||||
// Check for NaN. All NaNs must be canonicalized.
|
||||
__ VFPCompareAndSetFlags(value, value);
|
||||
// Only load canonical NaN if the comparison above set the overflow.
|
||||
__ Vmov(value,
|
||||
FixedDoubleArray::canonical_not_the_hole_nan_as_double(),
|
||||
no_reg, vs);
|
||||
}
|
||||
|
||||
__ vstr(value, scratch, instr->additional_index() << element_size_shift);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
|
||||
LStoreKeyedSpecializedArrayElement* instr) {
|
||||
|
||||
Register external_pointer = ToRegister(instr->external_pointer());
|
||||
void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
|
||||
Register external_pointer = ToRegister(instr->elements());
|
||||
Register key = no_reg;
|
||||
ElementsKind elements_kind = instr->elements_kind();
|
||||
bool key_is_constant = instr->key()->IsConstantOperand();
|
||||
@ -4164,6 +4079,110 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement(
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
|
||||
DwVfpRegister value = ToDoubleRegister(instr->value());
|
||||
Register elements = ToRegister(instr->elements());
|
||||
Register key = no_reg;
|
||||
Register scratch = scratch0();
|
||||
bool key_is_constant = instr->key()->IsConstantOperand();
|
||||
int constant_key = 0;
|
||||
|
||||
// Calculate the effective address of the slot in the array to store the
|
||||
// double value.
|
||||
if (key_is_constant) {
|
||||
constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
|
||||
if (constant_key & 0xF0000000) {
|
||||
Abort("array index constant value too big.");
|
||||
}
|
||||
} else {
|
||||
key = ToRegister(instr->key());
|
||||
}
|
||||
int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
|
||||
int shift_size = (instr->hydrogen()->key()->representation().IsTagged())
|
||||
? (element_size_shift - kSmiTagSize) : element_size_shift;
|
||||
Operand operand = key_is_constant
|
||||
? Operand((constant_key << element_size_shift) +
|
||||
FixedDoubleArray::kHeaderSize - kHeapObjectTag)
|
||||
: Operand(key, LSL, shift_size);
|
||||
__ add(scratch, elements, operand);
|
||||
if (!key_is_constant) {
|
||||
__ add(scratch, scratch,
|
||||
Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
|
||||
}
|
||||
|
||||
if (instr->NeedsCanonicalization()) {
|
||||
// Check for NaN. All NaNs must be canonicalized.
|
||||
__ VFPCompareAndSetFlags(value, value);
|
||||
// Only load canonical NaN if the comparison above set the overflow.
|
||||
__ Vmov(value,
|
||||
FixedDoubleArray::canonical_not_the_hole_nan_as_double(),
|
||||
no_reg, vs);
|
||||
}
|
||||
|
||||
__ vstr(value, scratch, instr->additional_index() << element_size_shift);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
|
||||
Register value = ToRegister(instr->value());
|
||||
Register elements = ToRegister(instr->elements());
|
||||
Register key = instr->key()->IsRegister() ? ToRegister(instr->key())
|
||||
: no_reg;
|
||||
Register scratch = scratch0();
|
||||
Register store_base = scratch;
|
||||
int offset = 0;
|
||||
|
||||
// Do the store.
|
||||
if (instr->key()->IsConstantOperand()) {
|
||||
ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
|
||||
LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
|
||||
offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) +
|
||||
instr->additional_index());
|
||||
store_base = elements;
|
||||
} else {
|
||||
// Even though the HLoadKeyed instruction forces the input
|
||||
// representation for the key to be an integer, the input gets replaced
|
||||
// during bound check elimination with the index argument to the bounds
|
||||
// check, which can be tagged, so that case must be handled here, too.
|
||||
if (instr->hydrogen()->key()->representation().IsTagged()) {
|
||||
__ add(scratch, elements,
|
||||
Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
|
||||
} else {
|
||||
__ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
|
||||
}
|
||||
offset = FixedArray::OffsetOfElementAt(instr->additional_index());
|
||||
}
|
||||
__ str(value, FieldMemOperand(store_base, offset));
|
||||
|
||||
if (instr->hydrogen()->NeedsWriteBarrier()) {
|
||||
HType type = instr->hydrogen()->value()->type();
|
||||
SmiCheck check_needed =
|
||||
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
|
||||
// Compute address of modified element and store it into key register.
|
||||
__ add(key, store_base, Operand(offset - kHeapObjectTag));
|
||||
__ RecordWrite(elements,
|
||||
key,
|
||||
value,
|
||||
kLRHasBeenSaved,
|
||||
kSaveFPRegs,
|
||||
EMIT_REMEMBERED_SET,
|
||||
check_needed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
|
||||
// By cases: external, fast double
|
||||
if (instr->is_external()) {
|
||||
DoStoreKeyedExternalArray(instr);
|
||||
} else if (instr->hydrogen()->value()->representation().IsDouble()) {
|
||||
DoStoreKeyedFixedDoubleArray(instr);
|
||||
} else {
|
||||
DoStoreKeyedFixedArray(instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
|
||||
ASSERT(ToRegister(instr->object()).is(r2));
|
||||
ASSERT(ToRegister(instr->key()).is(r1));
|
||||
|
@ -377,6 +377,12 @@ class LCodeGen BASE_EMBEDDED {
|
||||
};
|
||||
|
||||
void EnsureSpaceForLazyDeopt();
|
||||
void DoLoadKeyedExternalArray(LLoadKeyed* instr);
|
||||
void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr);
|
||||
void DoLoadKeyedFixedArray(LLoadKeyed* instr);
|
||||
void DoStoreKeyedExternalArray(LStoreKeyed* instr);
|
||||
void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr);
|
||||
void DoStoreKeyedFixedArray(LStoreKeyed* instr);
|
||||
|
||||
Zone* zone_;
|
||||
LPlatformChunk* const chunk_;
|
||||
|
@ -35,9 +35,14 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
void PrintElementsKind(FILE* out, ElementsKind kind) {
|
||||
const char* ElementsKindToString(ElementsKind kind) {
|
||||
ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
|
||||
PrintF(out, "%s", accessor->name());
|
||||
return accessor->name();
|
||||
}
|
||||
|
||||
|
||||
void PrintElementsKind(FILE* out, ElementsKind kind) {
|
||||
PrintF(out, "%s", ElementsKindToString(kind));
|
||||
}
|
||||
|
||||
|
||||
|
@ -77,6 +77,7 @@ const int kElementsKindCount = LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1;
|
||||
const int kFastElementsKindCount = LAST_FAST_ELEMENTS_KIND -
|
||||
FIRST_FAST_ELEMENTS_KIND + 1;
|
||||
|
||||
const char* ElementsKindToString(ElementsKind kind);
|
||||
void PrintElementsKind(FILE* out, ElementsKind kind);
|
||||
|
||||
ElementsKind GetInitialFastElementsKind();
|
||||
@ -109,6 +110,13 @@ inline bool IsFastDoubleElementsKind(ElementsKind kind) {
|
||||
}
|
||||
|
||||
|
||||
inline bool IsDoubleOrFloatElementsKind(ElementsKind kind) {
|
||||
return IsFastDoubleElementsKind(kind) ||
|
||||
kind == EXTERNAL_DOUBLE_ELEMENTS ||
|
||||
kind == EXTERNAL_FLOAT_ELEMENTS;
|
||||
}
|
||||
|
||||
|
||||
inline bool IsFastSmiOrObjectElementsKind(ElementsKind kind) {
|
||||
return kind == FAST_SMI_ELEMENTS ||
|
||||
kind == FAST_HOLEY_SMI_ELEMENTS ||
|
||||
|
@ -1622,7 +1622,7 @@ Range* HShl::InferRange(Zone* zone) {
|
||||
}
|
||||
|
||||
|
||||
Range* HLoadKeyedSpecializedArrayElement::InferRange(Zone* zone) {
|
||||
Range* HLoadKeyed::InferRange(Zone* zone) {
|
||||
switch (elements_kind()) {
|
||||
case EXTERNAL_PIXEL_ELEMENTS:
|
||||
return new(zone) Range(0, 255);
|
||||
@ -1849,8 +1849,17 @@ void HLoadNamedGeneric::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintNameTo(stream);
|
||||
void HLoadKeyed::PrintDataTo(StringStream* stream) {
|
||||
if (!is_external()) {
|
||||
elements()->PrintNameTo(stream);
|
||||
} else {
|
||||
ASSERT(elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND &&
|
||||
elements_kind() <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
|
||||
elements()->PrintNameTo(stream);
|
||||
stream->Add(".");
|
||||
stream->Add(ElementsKindToString(elements_kind()));
|
||||
}
|
||||
|
||||
stream->Add("[");
|
||||
key()->PrintNameTo(stream);
|
||||
stream->Add("] ");
|
||||
@ -1861,29 +1870,26 @@ void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
bool HLoadKeyedFastElement::RequiresHoleCheck() const {
|
||||
bool HLoadKeyed::RequiresHoleCheck() const {
|
||||
if (IsFastPackedElementsKind(elements_kind())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsFastDoubleElementsKind(elements_kind())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
|
||||
HValue* use = it.value();
|
||||
if (!use->IsChange()) return true;
|
||||
if (!use->IsChange()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void HLoadKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
|
||||
elements()->PrintNameTo(stream);
|
||||
stream->Add("[");
|
||||
key()->PrintNameTo(stream);
|
||||
stream->Add("] ");
|
||||
dependency()->PrintNameTo(stream);
|
||||
}
|
||||
|
||||
|
||||
void HLoadKeyedGeneric::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintNameTo(stream);
|
||||
stream->Add("[");
|
||||
@ -1896,21 +1902,22 @@ HValue* HLoadKeyedGeneric::Canonicalize() {
|
||||
// Recognize generic keyed loads that use property name generated
|
||||
// by for-in statement as a key and rewrite them into fast property load
|
||||
// by index.
|
||||
if (key()->IsLoadKeyedFastElement()) {
|
||||
HLoadKeyedFastElement* key_load = HLoadKeyedFastElement::cast(key());
|
||||
if (key_load->object()->IsForInCacheArray()) {
|
||||
if (key()->IsLoadKeyed()) {
|
||||
HLoadKeyed* key_load = HLoadKeyed::cast(key());
|
||||
if (key_load->elements()->IsForInCacheArray()) {
|
||||
HForInCacheArray* names_cache =
|
||||
HForInCacheArray::cast(key_load->object());
|
||||
HForInCacheArray::cast(key_load->elements());
|
||||
|
||||
if (names_cache->enumerable() == object()) {
|
||||
HForInCacheArray* index_cache =
|
||||
names_cache->index_cache();
|
||||
HCheckMapValue* map_check =
|
||||
new(block()->zone()) HCheckMapValue(object(), names_cache->map());
|
||||
HInstruction* index = new(block()->zone()) HLoadKeyedFastElement(
|
||||
HInstruction* index = new(block()->zone()) HLoadKeyed(
|
||||
index_cache,
|
||||
key_load->key(),
|
||||
key_load->key());
|
||||
key_load->key(),
|
||||
key_load->elements_kind());
|
||||
map_check->InsertBefore(this);
|
||||
index->InsertBefore(this);
|
||||
HLoadFieldByIndex* load = new(block()->zone()) HLoadFieldByIndex(
|
||||
@ -1925,56 +1932,6 @@ HValue* HLoadKeyedGeneric::Canonicalize() {
|
||||
}
|
||||
|
||||
|
||||
void HLoadKeyedSpecializedArrayElement::PrintDataTo(
|
||||
StringStream* stream) {
|
||||
external_pointer()->PrintNameTo(stream);
|
||||
stream->Add(".");
|
||||
switch (elements_kind()) {
|
||||
case EXTERNAL_BYTE_ELEMENTS:
|
||||
stream->Add("byte");
|
||||
break;
|
||||
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
|
||||
stream->Add("u_byte");
|
||||
break;
|
||||
case EXTERNAL_SHORT_ELEMENTS:
|
||||
stream->Add("short");
|
||||
break;
|
||||
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
|
||||
stream->Add("u_short");
|
||||
break;
|
||||
case EXTERNAL_INT_ELEMENTS:
|
||||
stream->Add("int");
|
||||
break;
|
||||
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
|
||||
stream->Add("u_int");
|
||||
break;
|
||||
case EXTERNAL_FLOAT_ELEMENTS:
|
||||
stream->Add("float");
|
||||
break;
|
||||
case EXTERNAL_DOUBLE_ELEMENTS:
|
||||
stream->Add("double");
|
||||
break;
|
||||
case EXTERNAL_PIXEL_ELEMENTS:
|
||||
stream->Add("pixel");
|
||||
break;
|
||||
case FAST_ELEMENTS:
|
||||
case FAST_SMI_ELEMENTS:
|
||||
case FAST_DOUBLE_ELEMENTS:
|
||||
case FAST_HOLEY_ELEMENTS:
|
||||
case FAST_HOLEY_SMI_ELEMENTS:
|
||||
case FAST_HOLEY_DOUBLE_ELEMENTS:
|
||||
case DICTIONARY_ELEMENTS:
|
||||
case NON_STRICT_ARGUMENTS_ELEMENTS:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
stream->Add("[");
|
||||
key()->PrintNameTo(stream);
|
||||
stream->Add("] ");
|
||||
dependency()->PrintNameTo(stream);
|
||||
}
|
||||
|
||||
|
||||
void HStoreNamedGeneric::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintNameTo(stream);
|
||||
stream->Add(".");
|
||||
@ -2001,17 +1958,17 @@ void HStoreNamedField::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
void HStoreKeyedFastElement::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintNameTo(stream);
|
||||
stream->Add("[");
|
||||
key()->PrintNameTo(stream);
|
||||
stream->Add("] = ");
|
||||
value()->PrintNameTo(stream);
|
||||
}
|
||||
void HStoreKeyed::PrintDataTo(StringStream* stream) {
|
||||
if (!is_external()) {
|
||||
elements()->PrintNameTo(stream);
|
||||
} else {
|
||||
elements()->PrintNameTo(stream);
|
||||
stream->Add(".");
|
||||
stream->Add(ElementsKindToString(elements_kind()));
|
||||
ASSERT(elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND &&
|
||||
elements_kind() <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
|
||||
}
|
||||
|
||||
|
||||
void HStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
|
||||
elements()->PrintNameTo(stream);
|
||||
stream->Add("[");
|
||||
key()->PrintNameTo(stream);
|
||||
stream->Add("] = ");
|
||||
@ -2028,56 +1985,6 @@ void HStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
void HStoreKeyedSpecializedArrayElement::PrintDataTo(
|
||||
StringStream* stream) {
|
||||
external_pointer()->PrintNameTo(stream);
|
||||
stream->Add(".");
|
||||
switch (elements_kind()) {
|
||||
case EXTERNAL_BYTE_ELEMENTS:
|
||||
stream->Add("byte");
|
||||
break;
|
||||
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
|
||||
stream->Add("u_byte");
|
||||
break;
|
||||
case EXTERNAL_SHORT_ELEMENTS:
|
||||
stream->Add("short");
|
||||
break;
|
||||
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
|
||||
stream->Add("u_short");
|
||||
break;
|
||||
case EXTERNAL_INT_ELEMENTS:
|
||||
stream->Add("int");
|
||||
break;
|
||||
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
|
||||
stream->Add("u_int");
|
||||
break;
|
||||
case EXTERNAL_FLOAT_ELEMENTS:
|
||||
stream->Add("float");
|
||||
break;
|
||||
case EXTERNAL_DOUBLE_ELEMENTS:
|
||||
stream->Add("double");
|
||||
break;
|
||||
case EXTERNAL_PIXEL_ELEMENTS:
|
||||
stream->Add("pixel");
|
||||
break;
|
||||
case FAST_SMI_ELEMENTS:
|
||||
case FAST_ELEMENTS:
|
||||
case FAST_DOUBLE_ELEMENTS:
|
||||
case FAST_HOLEY_SMI_ELEMENTS:
|
||||
case FAST_HOLEY_ELEMENTS:
|
||||
case FAST_HOLEY_DOUBLE_ELEMENTS:
|
||||
case DICTIONARY_ELEMENTS:
|
||||
case NON_STRICT_ARGUMENTS_ELEMENTS:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
stream->Add("[");
|
||||
key()->PrintNameTo(stream);
|
||||
stream->Add("] = ");
|
||||
value()->PrintNameTo(stream);
|
||||
}
|
||||
|
||||
|
||||
void HTransitionElementsKind::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintNameTo(stream);
|
||||
ElementsKind from_kind = original_map()->elements_kind();
|
||||
@ -2368,10 +2275,10 @@ HValue* HAdd::EnsureAndPropagateNotMinusZero(BitVector* visited) {
|
||||
}
|
||||
|
||||
|
||||
bool HStoreKeyedFastDoubleElement::NeedsCanonicalization() {
|
||||
// If value was loaded from unboxed double backing store or
|
||||
// converted from an integer then we don't have to canonicalize it.
|
||||
if (value()->IsLoadKeyedFastDoubleElement() ||
|
||||
bool HStoreKeyed::NeedsCanonicalization() {
|
||||
// If value is an integer or comes from the result of a keyed load
|
||||
// then it will be a non-hole value: no need for canonicalization.
|
||||
if (value()->IsLoadKeyed() ||
|
||||
(value()->IsChange() && HChange::cast(value())->from().IsInteger32())) {
|
||||
return false;
|
||||
}
|
||||
|
@ -133,10 +133,8 @@ class LChunkBuilder;
|
||||
V(LoadFunctionPrototype) \
|
||||
V(LoadGlobalCell) \
|
||||
V(LoadGlobalGeneric) \
|
||||
V(LoadKeyedFastDoubleElement) \
|
||||
V(LoadKeyedFastElement) \
|
||||
V(LoadKeyed) \
|
||||
V(LoadKeyedGeneric) \
|
||||
V(LoadKeyedSpecializedArrayElement) \
|
||||
V(LoadNamedField) \
|
||||
V(LoadNamedFieldPolymorphic) \
|
||||
V(LoadNamedGeneric) \
|
||||
@ -163,10 +161,8 @@ class LChunkBuilder;
|
||||
V(StoreContextSlot) \
|
||||
V(StoreGlobalCell) \
|
||||
V(StoreGlobalGeneric) \
|
||||
V(StoreKeyedFastDoubleElement) \
|
||||
V(StoreKeyedFastElement) \
|
||||
V(StoreKeyed) \
|
||||
V(StoreKeyedGeneric) \
|
||||
V(StoreKeyedSpecializedArrayElement) \
|
||||
V(StoreNamedField) \
|
||||
V(StoreNamedGeneric) \
|
||||
V(StringAdd) \
|
||||
@ -4244,29 +4240,59 @@ class ArrayInstructionInterface {
|
||||
virtual ~ArrayInstructionInterface() { };
|
||||
};
|
||||
|
||||
class HLoadKeyedFastElement
|
||||
|
||||
class HLoadKeyed
|
||||
: public HTemplateInstruction<3>, public ArrayInstructionInterface {
|
||||
public:
|
||||
HLoadKeyedFastElement(HValue* obj,
|
||||
HValue* key,
|
||||
HValue* dependency,
|
||||
ElementsKind elements_kind = FAST_ELEMENTS)
|
||||
HLoadKeyed(HValue* obj,
|
||||
HValue* key,
|
||||
HValue* dependency,
|
||||
ElementsKind elements_kind)
|
||||
: bit_field_(0) {
|
||||
ASSERT(IsFastSmiOrObjectElementsKind(elements_kind));
|
||||
bit_field_ = ElementsKindField::encode(elements_kind);
|
||||
if (IsFastSmiElementsKind(elements_kind) &&
|
||||
IsFastPackedElementsKind(elements_kind)) {
|
||||
set_type(HType::Smi());
|
||||
}
|
||||
|
||||
SetOperandAt(0, obj);
|
||||
SetOperandAt(1, key);
|
||||
SetOperandAt(2, dependency);
|
||||
set_representation(Representation::Tagged());
|
||||
SetGVNFlag(kDependsOnArrayElements);
|
||||
|
||||
if (!is_external()) {
|
||||
// I can detect the case between storing double (holey and fast) and
|
||||
// smi/object by looking at elements_kind_.
|
||||
ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) ||
|
||||
IsFastDoubleElementsKind(elements_kind));
|
||||
|
||||
if (IsFastSmiOrObjectElementsKind(elements_kind)) {
|
||||
if (IsFastSmiElementsKind(elements_kind) &&
|
||||
IsFastPackedElementsKind(elements_kind)) {
|
||||
set_type(HType::Smi());
|
||||
}
|
||||
|
||||
set_representation(Representation::Tagged());
|
||||
SetGVNFlag(kDependsOnArrayElements);
|
||||
} else {
|
||||
set_representation(Representation::Double());
|
||||
SetGVNFlag(kDependsOnDoubleArrayElements);
|
||||
}
|
||||
} else {
|
||||
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
|
||||
elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
|
||||
set_representation(Representation::Double());
|
||||
} else {
|
||||
set_representation(Representation::Integer32());
|
||||
}
|
||||
|
||||
SetGVNFlag(kDependsOnSpecializedArrayElements);
|
||||
// Native code could change the specialized array.
|
||||
SetGVNFlag(kDependsOnCalls);
|
||||
}
|
||||
|
||||
SetFlag(kUseGVN);
|
||||
}
|
||||
|
||||
HValue* object() { return OperandAt(0); }
|
||||
bool is_external() const {
|
||||
return IsExternalArrayElementsKind(elements_kind());
|
||||
}
|
||||
HValue* elements() { return OperandAt(0); }
|
||||
HValue* key() { return OperandAt(1); }
|
||||
HValue* dependency() { return OperandAt(2); }
|
||||
uint32_t index_offset() { return IndexOffsetField::decode(bit_field_); }
|
||||
@ -4284,8 +4310,13 @@ class HLoadKeyedFastElement
|
||||
}
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
// The key is supposed to be Integer32.
|
||||
if (index == 0) return Representation::Tagged();
|
||||
// kind_fast: tagged[int32] (none)
|
||||
// kind_double: tagged[int32] (none)
|
||||
// kind_external: external[int32] (none)
|
||||
if (index == 0) {
|
||||
return is_external() ? Representation::External()
|
||||
: Representation::Tagged();
|
||||
}
|
||||
if (index == 1) return Representation::Integer32();
|
||||
return Representation::None();
|
||||
}
|
||||
@ -4294,157 +4325,52 @@ class HLoadKeyedFastElement
|
||||
|
||||
bool RequiresHoleCheck() const;
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement)
|
||||
virtual Range* InferRange(Zone* zone);
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
|
||||
|
||||
protected:
|
||||
virtual bool DataEquals(HValue* other) {
|
||||
if (!other->IsLoadKeyedFastElement()) return false;
|
||||
HLoadKeyedFastElement* other_load = HLoadKeyedFastElement::cast(other);
|
||||
if (!other->IsLoadKeyed()) return false;
|
||||
HLoadKeyed* other_load = HLoadKeyed::cast(other);
|
||||
|
||||
if (IsDehoisted() && index_offset() != other_load->index_offset())
|
||||
return false;
|
||||
return elements_kind() == other_load->elements_kind();
|
||||
}
|
||||
|
||||
private:
|
||||
virtual bool IsDeletable() const { return !RequiresHoleCheck(); }
|
||||
virtual bool IsDeletable() const {
|
||||
return !RequiresHoleCheck();
|
||||
}
|
||||
|
||||
class ElementsKindField: public BitField<ElementsKind, 0, 4> {};
|
||||
class IndexOffsetField: public BitField<uint32_t, 4, 27> {};
|
||||
class IsDehoistedField: public BitField<bool, 31, 1> {};
|
||||
// Establish some checks around our packed fields
|
||||
enum LoadKeyedBits {
|
||||
kBitsForElementsKind = 5,
|
||||
kBitsForIndexOffset = 26,
|
||||
kBitsForIsDehoisted = 1,
|
||||
|
||||
kStartElementsKind = 0,
|
||||
kStartIndexOffset = kStartElementsKind + kBitsForElementsKind,
|
||||
kStartIsDehoisted = kStartIndexOffset + kBitsForIndexOffset
|
||||
};
|
||||
|
||||
STATIC_ASSERT((kBitsForElementsKind + kBitsForIndexOffset +
|
||||
kBitsForIsDehoisted) <= sizeof(uint32_t)*8);
|
||||
STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
|
||||
class ElementsKindField:
|
||||
public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
|
||||
{}; // NOLINT
|
||||
class IndexOffsetField:
|
||||
public BitField<uint32_t, kStartIndexOffset, kBitsForIndexOffset>
|
||||
{}; // NOLINT
|
||||
class IsDehoistedField:
|
||||
public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted>
|
||||
{}; // NOLINT
|
||||
uint32_t bit_field_;
|
||||
};
|
||||
|
||||
|
||||
enum HoleCheckMode { PERFORM_HOLE_CHECK, OMIT_HOLE_CHECK };
|
||||
|
||||
|
||||
class HLoadKeyedFastDoubleElement
|
||||
: public HTemplateInstruction<3>, public ArrayInstructionInterface {
|
||||
public:
|
||||
HLoadKeyedFastDoubleElement(
|
||||
HValue* elements,
|
||||
HValue* key,
|
||||
HValue* dependency,
|
||||
HoleCheckMode hole_check_mode = PERFORM_HOLE_CHECK)
|
||||
: index_offset_(0),
|
||||
is_dehoisted_(false),
|
||||
hole_check_mode_(hole_check_mode) {
|
||||
SetOperandAt(0, elements);
|
||||
SetOperandAt(1, key);
|
||||
SetOperandAt(2, dependency);
|
||||
set_representation(Representation::Double());
|
||||
SetGVNFlag(kDependsOnDoubleArrayElements);
|
||||
SetFlag(kUseGVN);
|
||||
}
|
||||
|
||||
HValue* elements() { return OperandAt(0); }
|
||||
HValue* key() { return OperandAt(1); }
|
||||
HValue* dependency() { return OperandAt(2); }
|
||||
uint32_t index_offset() { return index_offset_; }
|
||||
void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
|
||||
HValue* GetKey() { return key(); }
|
||||
void SetKey(HValue* key) { SetOperandAt(1, key); }
|
||||
bool IsDehoisted() { return is_dehoisted_; }
|
||||
void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
// The key is supposed to be Integer32.
|
||||
if (index == 0) return Representation::Tagged();
|
||||
if (index == 1) return Representation::Integer32();
|
||||
return Representation::None();
|
||||
}
|
||||
|
||||
bool RequiresHoleCheck() const {
|
||||
return hole_check_mode_ == PERFORM_HOLE_CHECK;
|
||||
}
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement)
|
||||
|
||||
protected:
|
||||
virtual bool DataEquals(HValue* other) {
|
||||
if (!other->IsLoadKeyedFastDoubleElement()) return false;
|
||||
HLoadKeyedFastDoubleElement* other_load =
|
||||
HLoadKeyedFastDoubleElement::cast(other);
|
||||
return hole_check_mode_ == other_load->hole_check_mode_;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual bool IsDeletable() const { return !RequiresHoleCheck(); }
|
||||
|
||||
uint32_t index_offset_;
|
||||
bool is_dehoisted_;
|
||||
HoleCheckMode hole_check_mode_;
|
||||
};
|
||||
|
||||
|
||||
class HLoadKeyedSpecializedArrayElement
|
||||
: public HTemplateInstruction<3>, public ArrayInstructionInterface {
|
||||
public:
|
||||
HLoadKeyedSpecializedArrayElement(HValue* external_elements,
|
||||
HValue* key,
|
||||
HValue* dependency,
|
||||
ElementsKind elements_kind)
|
||||
: elements_kind_(elements_kind),
|
||||
index_offset_(0),
|
||||
is_dehoisted_(false) {
|
||||
SetOperandAt(0, external_elements);
|
||||
SetOperandAt(1, key);
|
||||
SetOperandAt(2, dependency);
|
||||
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
|
||||
elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
|
||||
set_representation(Representation::Double());
|
||||
} else {
|
||||
set_representation(Representation::Integer32());
|
||||
}
|
||||
SetGVNFlag(kDependsOnSpecializedArrayElements);
|
||||
// Native code could change the specialized array.
|
||||
SetGVNFlag(kDependsOnCalls);
|
||||
SetFlag(kUseGVN);
|
||||
}
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
// The key is supposed to be Integer32.
|
||||
if (index == 0) return Representation::External();
|
||||
if (index == 1) return Representation::Integer32();
|
||||
return Representation::None();
|
||||
}
|
||||
|
||||
HValue* external_pointer() { return OperandAt(0); }
|
||||
HValue* key() { return OperandAt(1); }
|
||||
HValue* dependency() { return OperandAt(2); }
|
||||
ElementsKind elements_kind() const { return elements_kind_; }
|
||||
uint32_t index_offset() { return index_offset_; }
|
||||
void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
|
||||
HValue* GetKey() { return key(); }
|
||||
void SetKey(HValue* key) { SetOperandAt(1, key); }
|
||||
bool IsDehoisted() { return is_dehoisted_; }
|
||||
void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
|
||||
|
||||
virtual Range* InferRange(Zone* zone);
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement)
|
||||
|
||||
protected:
|
||||
virtual bool DataEquals(HValue* other) {
|
||||
if (!other->IsLoadKeyedSpecializedArrayElement()) return false;
|
||||
HLoadKeyedSpecializedArrayElement* cast_other =
|
||||
HLoadKeyedSpecializedArrayElement::cast(other);
|
||||
return elements_kind_ == cast_other->elements_kind();
|
||||
}
|
||||
|
||||
private:
|
||||
virtual bool IsDeletable() const { return true; }
|
||||
|
||||
ElementsKind elements_kind_;
|
||||
uint32_t index_offset_;
|
||||
bool is_dehoisted_;
|
||||
};
|
||||
|
||||
|
||||
class HLoadKeyedGeneric: public HTemplateInstruction<3> {
|
||||
public:
|
||||
HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key) {
|
||||
@ -4462,6 +4388,7 @@ class HLoadKeyedGeneric: public HTemplateInstruction<3> {
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
// tagged[tagged]
|
||||
return Representation::Tagged();
|
||||
}
|
||||
|
||||
@ -4567,31 +4494,56 @@ class HStoreNamedGeneric: public HTemplateInstruction<3> {
|
||||
};
|
||||
|
||||
|
||||
class HStoreKeyedFastElement
|
||||
class HStoreKeyed
|
||||
: public HTemplateInstruction<3>, public ArrayInstructionInterface {
|
||||
public:
|
||||
HStoreKeyedFastElement(HValue* obj, HValue* key, HValue* val,
|
||||
ElementsKind elements_kind = FAST_ELEMENTS)
|
||||
HStoreKeyed(HValue* obj, HValue* key, HValue* val,
|
||||
ElementsKind elements_kind)
|
||||
: elements_kind_(elements_kind), index_offset_(0), is_dehoisted_(false) {
|
||||
SetOperandAt(0, obj);
|
||||
SetOperandAt(1, key);
|
||||
SetOperandAt(2, val);
|
||||
SetGVNFlag(kChangesArrayElements);
|
||||
|
||||
if (is_external()) {
|
||||
SetGVNFlag(kChangesSpecializedArrayElements);
|
||||
} else if (IsFastDoubleElementsKind(elements_kind)) {
|
||||
SetGVNFlag(kChangesDoubleArrayElements);
|
||||
SetFlag(kDeoptimizeOnUndefined);
|
||||
} else {
|
||||
SetGVNFlag(kChangesArrayElements);
|
||||
}
|
||||
}
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
// The key is supposed to be Integer32.
|
||||
return index == 1
|
||||
? Representation::Integer32()
|
||||
: Representation::Tagged();
|
||||
// kind_fast: tagged[int32] = tagged
|
||||
// kind_double: tagged[int32] = double
|
||||
// kind_external: external[int32] = (double | int32)
|
||||
if (index == 0) {
|
||||
return is_external() ? Representation::External()
|
||||
: Representation::Tagged();
|
||||
} else if (index == 1) {
|
||||
return Representation::Integer32();
|
||||
}
|
||||
|
||||
ASSERT_EQ(index, 2);
|
||||
if (IsDoubleOrFloatElementsKind(elements_kind())) {
|
||||
return Representation::Double();
|
||||
}
|
||||
|
||||
return is_external() ? Representation::Integer32()
|
||||
: Representation::Tagged();
|
||||
}
|
||||
|
||||
HValue* object() { return OperandAt(0); }
|
||||
bool is_external() const {
|
||||
return IsExternalArrayElementsKind(elements_kind());
|
||||
}
|
||||
HValue* elements() { return OperandAt(0); }
|
||||
HValue* key() { return OperandAt(1); }
|
||||
HValue* value() { return OperandAt(2); }
|
||||
bool value_is_smi() {
|
||||
bool value_is_smi() const {
|
||||
return IsFastSmiElementsKind(elements_kind_);
|
||||
}
|
||||
ElementsKind elements_kind() const { return elements_kind_; }
|
||||
uint32_t index_offset() { return index_offset_; }
|
||||
void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
|
||||
HValue* GetKey() { return key(); }
|
||||
@ -4607,110 +4559,11 @@ class HStoreKeyedFastElement
|
||||
}
|
||||
}
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement)
|
||||
|
||||
private:
|
||||
ElementsKind elements_kind_;
|
||||
uint32_t index_offset_;
|
||||
bool is_dehoisted_;
|
||||
};
|
||||
|
||||
|
||||
class HStoreKeyedFastDoubleElement
|
||||
: public HTemplateInstruction<3>, public ArrayInstructionInterface {
|
||||
public:
|
||||
HStoreKeyedFastDoubleElement(HValue* elements,
|
||||
HValue* key,
|
||||
HValue* val)
|
||||
: index_offset_(0), is_dehoisted_(false) {
|
||||
SetOperandAt(0, elements);
|
||||
SetOperandAt(1, key);
|
||||
SetOperandAt(2, val);
|
||||
SetFlag(kDeoptimizeOnUndefined);
|
||||
SetGVNFlag(kChangesDoubleArrayElements);
|
||||
}
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
if (index == 1) {
|
||||
return Representation::Integer32();
|
||||
} else if (index == 2) {
|
||||
return Representation::Double();
|
||||
} else {
|
||||
return Representation::Tagged();
|
||||
}
|
||||
}
|
||||
|
||||
HValue* elements() { return OperandAt(0); }
|
||||
HValue* key() { return OperandAt(1); }
|
||||
HValue* value() { return OperandAt(2); }
|
||||
uint32_t index_offset() { return index_offset_; }
|
||||
void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
|
||||
HValue* GetKey() { return key(); }
|
||||
void SetKey(HValue* key) { SetOperandAt(1, key); }
|
||||
bool IsDehoisted() { return is_dehoisted_; }
|
||||
void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
|
||||
|
||||
bool NeedsWriteBarrier() {
|
||||
return StoringValueNeedsWriteBarrier(value());
|
||||
}
|
||||
|
||||
bool NeedsCanonicalization();
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement)
|
||||
|
||||
private:
|
||||
uint32_t index_offset_;
|
||||
bool is_dehoisted_;
|
||||
};
|
||||
|
||||
|
||||
class HStoreKeyedSpecializedArrayElement
|
||||
: public HTemplateInstruction<3>, public ArrayInstructionInterface {
|
||||
public:
|
||||
HStoreKeyedSpecializedArrayElement(HValue* external_elements,
|
||||
HValue* key,
|
||||
HValue* val,
|
||||
ElementsKind elements_kind)
|
||||
: elements_kind_(elements_kind), index_offset_(0), is_dehoisted_(false) {
|
||||
SetGVNFlag(kChangesSpecializedArrayElements);
|
||||
SetOperandAt(0, external_elements);
|
||||
SetOperandAt(1, key);
|
||||
SetOperandAt(2, val);
|
||||
}
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
if (index == 0) {
|
||||
return Representation::External();
|
||||
} else {
|
||||
bool float_or_double_elements =
|
||||
elements_kind() == EXTERNAL_FLOAT_ELEMENTS ||
|
||||
elements_kind() == EXTERNAL_DOUBLE_ELEMENTS;
|
||||
if (index == 2 && float_or_double_elements) {
|
||||
return Representation::Double();
|
||||
} else {
|
||||
return Representation::Integer32();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HValue* external_pointer() { return OperandAt(0); }
|
||||
HValue* key() { return OperandAt(1); }
|
||||
HValue* value() { return OperandAt(2); }
|
||||
ElementsKind elements_kind() const { return elements_kind_; }
|
||||
uint32_t index_offset() { return index_offset_; }
|
||||
void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
|
||||
HValue* GetKey() { return key(); }
|
||||
void SetKey(HValue* key) { SetOperandAt(1, key); }
|
||||
bool IsDehoisted() { return is_dehoisted_; }
|
||||
void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement)
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
|
||||
|
||||
private:
|
||||
ElementsKind elements_kind_;
|
||||
@ -4741,6 +4594,7 @@ class HStoreKeyedGeneric: public HTemplateInstruction<4> {
|
||||
StrictModeFlag strict_mode_flag() { return strict_mode_flag_; }
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
// tagged[tagged] = tagged
|
||||
return Representation::Tagged();
|
||||
}
|
||||
|
||||
|
@ -2715,17 +2715,18 @@ bool Uint32Analysis::IsSafeUint32Use(HValue* val, HValue* use) {
|
||||
} else if (use->IsChange() || use->IsSimulate()) {
|
||||
// Conversions and deoptimization have special support for unt32.
|
||||
return true;
|
||||
} else if (use->IsStoreKeyedSpecializedArrayElement()) {
|
||||
// Storing a value into an external integer array is a bit level operation.
|
||||
HStoreKeyedSpecializedArrayElement* store =
|
||||
HStoreKeyedSpecializedArrayElement::cast(use);
|
||||
|
||||
if (store->value() == val) {
|
||||
// Clamping or a conversion to double should have beed inserted.
|
||||
ASSERT(store->elements_kind() != EXTERNAL_PIXEL_ELEMENTS);
|
||||
ASSERT(store->elements_kind() != EXTERNAL_FLOAT_ELEMENTS);
|
||||
ASSERT(store->elements_kind() != EXTERNAL_DOUBLE_ELEMENTS);
|
||||
return true;
|
||||
} else if (use->IsStoreKeyed()) {
|
||||
HStoreKeyed* store = HStoreKeyed::cast(use);
|
||||
if (store->is_external()) {
|
||||
// Storing a value into an external integer array is a bit level
|
||||
// operation.
|
||||
if (store->value() == val) {
|
||||
// Clamping or a conversion to double should have beed inserted.
|
||||
ASSERT(store->elements_kind() != EXTERNAL_PIXEL_ELEMENTS);
|
||||
ASSERT(store->elements_kind() != EXTERNAL_FLOAT_ELEMENTS);
|
||||
ASSERT(store->elements_kind() != EXTERNAL_DOUBLE_ELEMENTS);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3757,27 +3758,11 @@ void HGraph::DehoistSimpleArrayIndexComputations() {
|
||||
instr != NULL;
|
||||
instr = instr->next()) {
|
||||
ArrayInstructionInterface* array_instruction = NULL;
|
||||
if (instr->IsLoadKeyedFastElement()) {
|
||||
HLoadKeyedFastElement* op = HLoadKeyedFastElement::cast(instr);
|
||||
if (instr->IsLoadKeyed()) {
|
||||
HLoadKeyed* op = HLoadKeyed::cast(instr);
|
||||
array_instruction = static_cast<ArrayInstructionInterface*>(op);
|
||||
} else if (instr->IsLoadKeyedFastDoubleElement()) {
|
||||
HLoadKeyedFastDoubleElement* op =
|
||||
HLoadKeyedFastDoubleElement::cast(instr);
|
||||
array_instruction = static_cast<ArrayInstructionInterface*>(op);
|
||||
} else if (instr->IsLoadKeyedSpecializedArrayElement()) {
|
||||
HLoadKeyedSpecializedArrayElement* op =
|
||||
HLoadKeyedSpecializedArrayElement::cast(instr);
|
||||
array_instruction = static_cast<ArrayInstructionInterface*>(op);
|
||||
} else if (instr->IsStoreKeyedFastElement()) {
|
||||
HStoreKeyedFastElement* op = HStoreKeyedFastElement::cast(instr);
|
||||
array_instruction = static_cast<ArrayInstructionInterface*>(op);
|
||||
} else if (instr->IsStoreKeyedFastDoubleElement()) {
|
||||
HStoreKeyedFastDoubleElement* op =
|
||||
HStoreKeyedFastDoubleElement::cast(instr);
|
||||
array_instruction = static_cast<ArrayInstructionInterface*>(op);
|
||||
} else if (instr->IsStoreKeyedSpecializedArrayElement()) {
|
||||
HStoreKeyedSpecializedArrayElement* op =
|
||||
HStoreKeyedSpecializedArrayElement::cast(instr);
|
||||
} else if (instr->IsStoreKeyed()) {
|
||||
HStoreKeyed* op = HStoreKeyed::cast(instr);
|
||||
array_instruction = static_cast<ArrayInstructionInterface*>(op);
|
||||
} else {
|
||||
continue;
|
||||
@ -4617,10 +4602,11 @@ void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
|
||||
set_current_block(loop_body);
|
||||
|
||||
HValue* key = AddInstruction(
|
||||
new(zone()) HLoadKeyedFastElement(
|
||||
new(zone()) HLoadKeyed(
|
||||
environment()->ExpressionStackAt(2), // Enum cache.
|
||||
environment()->ExpressionStackAt(0), // Iteration index.
|
||||
environment()->ExpressionStackAt(0)));
|
||||
environment()->ExpressionStackAt(0),
|
||||
FAST_ELEMENTS));
|
||||
|
||||
// Check if the expected map still matches that of the enumerable.
|
||||
// If not just deoptimize.
|
||||
@ -5225,18 +5211,14 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
// Fall through.
|
||||
case FAST_ELEMENTS:
|
||||
case FAST_HOLEY_ELEMENTS:
|
||||
AddInstruction(new(zone()) HStoreKeyedFastElement(
|
||||
case FAST_DOUBLE_ELEMENTS:
|
||||
case FAST_HOLEY_DOUBLE_ELEMENTS:
|
||||
AddInstruction(new(zone()) HStoreKeyed(
|
||||
elements,
|
||||
key,
|
||||
value,
|
||||
boilerplate_elements_kind));
|
||||
break;
|
||||
case FAST_DOUBLE_ELEMENTS:
|
||||
case FAST_HOLEY_DOUBLE_ELEMENTS:
|
||||
AddInstruction(new(zone()) HStoreKeyedFastDoubleElement(elements,
|
||||
key,
|
||||
value));
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
@ -6085,13 +6067,15 @@ HInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
return new(zone()) HStoreKeyedSpecializedArrayElement(
|
||||
external_elements, checked_key, val, elements_kind);
|
||||
return new(zone()) HStoreKeyed(external_elements,
|
||||
checked_key,
|
||||
val,
|
||||
elements_kind);
|
||||
} else {
|
||||
ASSERT(val == NULL);
|
||||
HLoadKeyedSpecializedArrayElement* load =
|
||||
new(zone()) HLoadKeyedSpecializedArrayElement(
|
||||
external_elements, checked_key, dependency, elements_kind);
|
||||
HLoadKeyed* load =
|
||||
new(zone()) HLoadKeyed(
|
||||
external_elements, checked_key, dependency, elements_kind);
|
||||
if (FLAG_opt_safe_uint32_operations &&
|
||||
elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
|
||||
graph()->RecordUint32Instruction(load);
|
||||
@ -6110,10 +6094,6 @@ HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
|
||||
if (is_store) {
|
||||
ASSERT(val != NULL);
|
||||
switch (elements_kind) {
|
||||
case FAST_DOUBLE_ELEMENTS:
|
||||
case FAST_HOLEY_DOUBLE_ELEMENTS:
|
||||
return new(zone()) HStoreKeyedFastDoubleElement(
|
||||
elements, checked_key, val);
|
||||
case FAST_SMI_ELEMENTS:
|
||||
case FAST_HOLEY_SMI_ELEMENTS:
|
||||
// Smi-only arrays need a smi check.
|
||||
@ -6121,7 +6101,9 @@ HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
|
||||
// Fall through.
|
||||
case FAST_ELEMENTS:
|
||||
case FAST_HOLEY_ELEMENTS:
|
||||
return new(zone()) HStoreKeyedFastElement(
|
||||
case FAST_DOUBLE_ELEMENTS:
|
||||
case FAST_HOLEY_DOUBLE_ELEMENTS:
|
||||
return new(zone()) HStoreKeyed(
|
||||
elements, checked_key, val, elements_kind);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -6129,16 +6111,10 @@ HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
|
||||
}
|
||||
}
|
||||
// It's an element load (!is_store).
|
||||
HoleCheckMode mode = IsFastPackedElementsKind(elements_kind) ?
|
||||
OMIT_HOLE_CHECK :
|
||||
PERFORM_HOLE_CHECK;
|
||||
if (IsFastDoubleElementsKind(elements_kind)) {
|
||||
return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key,
|
||||
load_dependency, mode);
|
||||
} else { // Smi or Object elements.
|
||||
return new(zone()) HLoadKeyedFastElement(elements, checked_key,
|
||||
load_dependency, elements_kind);
|
||||
}
|
||||
return new(zone()) HLoadKeyed(elements,
|
||||
checked_key,
|
||||
load_dependency,
|
||||
elements_kind);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2749,95 +2749,7 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
|
||||
Register result = ToRegister(instr->result());
|
||||
|
||||
// Load the result.
|
||||
__ mov(result,
|
||||
BuildFastArrayOperand(instr->elements(),
|
||||
instr->key(),
|
||||
instr->hydrogen()->key()->representation(),
|
||||
FAST_ELEMENTS,
|
||||
FixedArray::kHeaderSize - kHeapObjectTag,
|
||||
instr->additional_index()));
|
||||
|
||||
// Check for the hole value.
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
|
||||
__ test(result, Immediate(kSmiTagMask));
|
||||
DeoptimizeIf(not_equal, instr->environment());
|
||||
} else {
|
||||
__ cmp(result, factory()->the_hole_value());
|
||||
DeoptimizeIf(equal, instr->environment());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedFastDoubleElement(
|
||||
LLoadKeyedFastDoubleElement* instr) {
|
||||
XMMRegister result = ToDoubleRegister(instr->result());
|
||||
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
|
||||
sizeof(kHoleNanLower32);
|
||||
Operand hole_check_operand = BuildFastArrayOperand(
|
||||
instr->elements(), instr->key(),
|
||||
instr->hydrogen()->key()->representation(),
|
||||
FAST_DOUBLE_ELEMENTS,
|
||||
offset,
|
||||
instr->additional_index());
|
||||
__ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
|
||||
DeoptimizeIf(equal, instr->environment());
|
||||
}
|
||||
|
||||
Operand double_load_operand = BuildFastArrayOperand(
|
||||
instr->elements(),
|
||||
instr->key(),
|
||||
instr->hydrogen()->key()->representation(),
|
||||
FAST_DOUBLE_ELEMENTS,
|
||||
FixedDoubleArray::kHeaderSize - kHeapObjectTag,
|
||||
instr->additional_index());
|
||||
__ movdbl(result, double_load_operand);
|
||||
}
|
||||
|
||||
|
||||
Operand LCodeGen::BuildFastArrayOperand(
|
||||
LOperand* elements_pointer,
|
||||
LOperand* key,
|
||||
Representation key_representation,
|
||||
ElementsKind elements_kind,
|
||||
uint32_t offset,
|
||||
uint32_t additional_index) {
|
||||
Register elements_pointer_reg = ToRegister(elements_pointer);
|
||||
int shift_size = ElementsKindToShiftSize(elements_kind);
|
||||
// Even though the HLoad/StoreKeyedFastElement instructions force the input
|
||||
// representation for the key to be an integer, the input gets replaced during
|
||||
// bound check elimination with the index argument to the bounds check, which
|
||||
// can be tagged, so that case must be handled here, too.
|
||||
if (key_representation.IsTagged() && (shift_size >= 1)) {
|
||||
shift_size -= kSmiTagSize;
|
||||
}
|
||||
if (key->IsConstantOperand()) {
|
||||
int constant_value = ToInteger32(LConstantOperand::cast(key));
|
||||
if (constant_value & 0xF0000000) {
|
||||
Abort("array index constant value too big");
|
||||
}
|
||||
return Operand(elements_pointer_reg,
|
||||
((constant_value + additional_index) << shift_size)
|
||||
+ offset);
|
||||
} else {
|
||||
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
|
||||
return Operand(elements_pointer_reg,
|
||||
ToRegister(key),
|
||||
scale_factor,
|
||||
offset + (additional_index << shift_size));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
|
||||
LLoadKeyedSpecializedArrayElement* instr) {
|
||||
void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
|
||||
ElementsKind elements_kind = instr->elements_kind();
|
||||
LOperand* key = instr->key();
|
||||
if (!key->IsConstantOperand() &&
|
||||
@ -2846,7 +2758,7 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
|
||||
__ SmiUntag(ToRegister(key));
|
||||
}
|
||||
Operand operand(BuildFastArrayOperand(
|
||||
instr->external_pointer(),
|
||||
instr->elements(),
|
||||
key,
|
||||
instr->hydrogen()->key()->representation(),
|
||||
elements_kind,
|
||||
@ -2901,6 +2813,103 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
|
||||
XMMRegister result = ToDoubleRegister(instr->result());
|
||||
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
|
||||
sizeof(kHoleNanLower32);
|
||||
Operand hole_check_operand = BuildFastArrayOperand(
|
||||
instr->elements(), instr->key(),
|
||||
instr->hydrogen()->key()->representation(),
|
||||
FAST_DOUBLE_ELEMENTS,
|
||||
offset,
|
||||
instr->additional_index());
|
||||
__ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
|
||||
DeoptimizeIf(equal, instr->environment());
|
||||
}
|
||||
|
||||
Operand double_load_operand = BuildFastArrayOperand(
|
||||
instr->elements(),
|
||||
instr->key(),
|
||||
instr->hydrogen()->key()->representation(),
|
||||
FAST_DOUBLE_ELEMENTS,
|
||||
FixedDoubleArray::kHeaderSize - kHeapObjectTag,
|
||||
instr->additional_index());
|
||||
__ movdbl(result, double_load_operand);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
|
||||
Register result = ToRegister(instr->result());
|
||||
|
||||
// Load the result.
|
||||
__ mov(result,
|
||||
BuildFastArrayOperand(instr->elements(),
|
||||
instr->key(),
|
||||
instr->hydrogen()->key()->representation(),
|
||||
FAST_ELEMENTS,
|
||||
FixedArray::kHeaderSize - kHeapObjectTag,
|
||||
instr->additional_index()));
|
||||
|
||||
// Check for the hole value.
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
|
||||
__ test(result, Immediate(kSmiTagMask));
|
||||
DeoptimizeIf(not_equal, instr->environment());
|
||||
} else {
|
||||
__ cmp(result, factory()->the_hole_value());
|
||||
DeoptimizeIf(equal, instr->environment());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
|
||||
if (instr->is_external()) {
|
||||
DoLoadKeyedExternalArray(instr);
|
||||
} else if (instr->hydrogen()->representation().IsDouble()) {
|
||||
DoLoadKeyedFixedDoubleArray(instr);
|
||||
} else {
|
||||
DoLoadKeyedFixedArray(instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Operand LCodeGen::BuildFastArrayOperand(
|
||||
LOperand* elements_pointer,
|
||||
LOperand* key,
|
||||
Representation key_representation,
|
||||
ElementsKind elements_kind,
|
||||
uint32_t offset,
|
||||
uint32_t additional_index) {
|
||||
Register elements_pointer_reg = ToRegister(elements_pointer);
|
||||
int shift_size = ElementsKindToShiftSize(elements_kind);
|
||||
// Even though the HLoad/StoreKeyed instructions force the input
|
||||
// representation for the key to be an integer, the input gets replaced during
|
||||
// bound check elimination with the index argument to the bounds check, which
|
||||
// can be tagged, so that case must be handled here, too.
|
||||
if (key_representation.IsTagged() && (shift_size >= 1)) {
|
||||
shift_size -= kSmiTagSize;
|
||||
}
|
||||
if (key->IsConstantOperand()) {
|
||||
int constant_value = ToInteger32(LConstantOperand::cast(key));
|
||||
if (constant_value & 0xF0000000) {
|
||||
Abort("array index constant value too big");
|
||||
}
|
||||
return Operand(elements_pointer_reg,
|
||||
((constant_value + additional_index) << shift_size)
|
||||
+ offset);
|
||||
} else {
|
||||
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
|
||||
return Operand(elements_pointer_reg,
|
||||
ToRegister(key),
|
||||
scale_factor,
|
||||
offset + (additional_index << shift_size));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
|
||||
ASSERT(ToRegister(instr->context()).is(esi));
|
||||
ASSERT(ToRegister(instr->object()).is(edx));
|
||||
@ -3818,8 +3827,7 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
|
||||
LStoreKeyedSpecializedArrayElement* instr) {
|
||||
void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
|
||||
ElementsKind elements_kind = instr->elements_kind();
|
||||
LOperand* key = instr->key();
|
||||
if (!key->IsConstantOperand() &&
|
||||
@ -3828,7 +3836,7 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement(
|
||||
__ SmiUntag(ToRegister(key));
|
||||
}
|
||||
Operand operand(BuildFastArrayOperand(
|
||||
instr->external_pointer(),
|
||||
instr->elements(),
|
||||
key,
|
||||
instr->hydrogen()->key()->representation(),
|
||||
elements_kind,
|
||||
@ -3872,13 +3880,39 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement(
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
|
||||
void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
|
||||
XMMRegister value = ToDoubleRegister(instr->value());
|
||||
|
||||
if (instr->NeedsCanonicalization()) {
|
||||
Label have_value;
|
||||
|
||||
__ ucomisd(value, value);
|
||||
__ j(parity_odd, &have_value); // NaN.
|
||||
|
||||
ExternalReference canonical_nan_reference =
|
||||
ExternalReference::address_of_canonical_non_hole_nan();
|
||||
__ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
|
||||
__ bind(&have_value);
|
||||
}
|
||||
|
||||
Operand double_store_operand = BuildFastArrayOperand(
|
||||
instr->elements(),
|
||||
instr->key(),
|
||||
instr->hydrogen()->key()->representation(),
|
||||
FAST_DOUBLE_ELEMENTS,
|
||||
FixedDoubleArray::kHeaderSize - kHeapObjectTag,
|
||||
instr->additional_index());
|
||||
__ movdbl(double_store_operand, value);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
|
||||
Register value = ToRegister(instr->value());
|
||||
Register elements = ToRegister(instr->object());
|
||||
Register elements = ToRegister(instr->elements());
|
||||
Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
|
||||
|
||||
Operand operand = BuildFastArrayOperand(
|
||||
instr->object(),
|
||||
instr->elements(),
|
||||
instr->key(),
|
||||
instr->hydrogen()->key()->representation(),
|
||||
FAST_ELEMENTS,
|
||||
@ -3903,30 +3937,15 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyedFastDoubleElement(
|
||||
LStoreKeyedFastDoubleElement* instr) {
|
||||
XMMRegister value = ToDoubleRegister(instr->value());
|
||||
|
||||
if (instr->NeedsCanonicalization()) {
|
||||
Label have_value;
|
||||
|
||||
__ ucomisd(value, value);
|
||||
__ j(parity_odd, &have_value); // NaN.
|
||||
|
||||
ExternalReference canonical_nan_reference =
|
||||
ExternalReference::address_of_canonical_non_hole_nan();
|
||||
__ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
|
||||
__ bind(&have_value);
|
||||
void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
|
||||
// By cases...external, fast-double, fast
|
||||
if (instr->is_external()) {
|
||||
DoStoreKeyedExternalArray(instr);
|
||||
} else if (instr->hydrogen()->value()->representation().IsDouble()) {
|
||||
DoStoreKeyedFixedDoubleArray(instr);
|
||||
} else {
|
||||
DoStoreKeyedFixedArray(instr);
|
||||
}
|
||||
|
||||
Operand double_store_operand = BuildFastArrayOperand(
|
||||
instr->elements(),
|
||||
instr->key(),
|
||||
instr->hydrogen()->key()->representation(),
|
||||
FAST_DOUBLE_ELEMENTS,
|
||||
FixedDoubleArray::kHeaderSize - kHeapObjectTag,
|
||||
instr->additional_index());
|
||||
__ movdbl(double_store_operand, value);
|
||||
}
|
||||
|
||||
|
||||
|
@ -340,6 +340,12 @@ class LCodeGen BASE_EMBEDDED {
|
||||
int* offset);
|
||||
|
||||
void EnsureSpaceForLazyDeopt();
|
||||
void DoLoadKeyedExternalArray(LLoadKeyed* instr);
|
||||
void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr);
|
||||
void DoLoadKeyedFixedArray(LLoadKeyed* instr);
|
||||
void DoStoreKeyedExternalArray(LStoreKeyed* instr);
|
||||
void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr);
|
||||
void DoStoreKeyedFixedArray(LStoreKeyed* instr);
|
||||
|
||||
// Emits code for pushing either a tagged constant, a (non-double)
|
||||
// register, or a stack slot operand.
|
||||
|
@ -407,16 +407,7 @@ void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintTo(stream);
|
||||
stream->Add("[");
|
||||
key()->PrintTo(stream);
|
||||
stream->Add("] <- ");
|
||||
value()->PrintTo(stream);
|
||||
}
|
||||
|
||||
|
||||
void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
|
||||
void LStoreKeyed::PrintDataTo(StringStream* stream) {
|
||||
elements()->PrintTo(stream);
|
||||
stream->Add("[");
|
||||
key()->PrintTo(stream);
|
||||
@ -1932,59 +1923,38 @@ LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
|
||||
HLoadKeyedFastElement* instr) {
|
||||
ASSERT(instr->representation().IsTagged());
|
||||
LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
LOperand* obj = UseRegisterAtStart(instr->object());
|
||||
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
|
||||
LLoadKeyedFastElement* result = new(zone()) LLoadKeyedFastElement(obj, key);
|
||||
if (instr->RequiresHoleCheck()) AssignEnvironment(result);
|
||||
return DefineAsRegister(result);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
|
||||
HLoadKeyedFastDoubleElement* instr) {
|
||||
ASSERT(instr->representation().IsDouble());
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
LOperand* elements = UseRegisterAtStart(instr->elements());
|
||||
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
|
||||
LLoadKeyedFastDoubleElement* result =
|
||||
new(zone()) LLoadKeyedFastDoubleElement(elements, key);
|
||||
return AssignEnvironment(DefineAsRegister(result));
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
|
||||
HLoadKeyedSpecializedArrayElement* instr) {
|
||||
ElementsKind elements_kind = instr->elements_kind();
|
||||
ASSERT(
|
||||
(instr->representation().IsInteger32() &&
|
||||
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
|
||||
(elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
|
||||
(instr->representation().IsDouble() &&
|
||||
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
|
||||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
LOperand* external_pointer = UseRegister(instr->external_pointer());
|
||||
bool clobbers_key = ExternalArrayOpRequiresTemp(
|
||||
instr->key()->representation(), elements_kind);
|
||||
LOperand* key = clobbers_key
|
||||
? UseTempRegister(instr->key())
|
||||
: UseRegisterOrConstant(instr->key());
|
||||
: UseRegisterOrConstantAtStart(instr->key());
|
||||
LLoadKeyed* result = NULL;
|
||||
|
||||
LLoadKeyedSpecializedArrayElement* result =
|
||||
new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer, key);
|
||||
LInstruction* load_instr = DefineAsRegister(result);
|
||||
if (!instr->is_external()) {
|
||||
LOperand* obj = UseRegisterAtStart(instr->elements());
|
||||
result = new(zone()) LLoadKeyed(obj, key);
|
||||
} else {
|
||||
ASSERT(
|
||||
(instr->representation().IsInteger32() &&
|
||||
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
|
||||
(elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
|
||||
(instr->representation().IsDouble() &&
|
||||
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
|
||||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
|
||||
LOperand* external_pointer = UseRegister(instr->elements());
|
||||
result = new(zone()) LLoadKeyed(external_pointer, key);
|
||||
}
|
||||
|
||||
DefineAsRegister(result);
|
||||
bool can_deoptimize = instr->RequiresHoleCheck() ||
|
||||
(elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS);
|
||||
// An unsigned int array load might overflow and cause a deopt, make sure it
|
||||
// has an environment.
|
||||
return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS)
|
||||
? AssignEnvironment(load_instr)
|
||||
: load_instr;
|
||||
return can_deoptimize ? AssignEnvironment(result) : result;
|
||||
}
|
||||
|
||||
|
||||
@ -1999,72 +1969,66 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
|
||||
HStoreKeyedFastElement* instr) {
|
||||
bool needs_write_barrier = instr->NeedsWriteBarrier();
|
||||
ASSERT(instr->value()->representation().IsTagged());
|
||||
ASSERT(instr->object()->representation().IsTagged());
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
|
||||
LStoreKeyed* result = NULL;
|
||||
|
||||
LOperand* obj = UseRegister(instr->object());
|
||||
LOperand* val = needs_write_barrier
|
||||
? UseTempRegister(instr->value())
|
||||
: UseRegisterAtStart(instr->value());
|
||||
LOperand* key = needs_write_barrier
|
||||
? UseTempRegister(instr->key())
|
||||
: UseRegisterOrConstantAtStart(instr->key());
|
||||
return new(zone()) LStoreKeyedFastElement(obj, key, val);
|
||||
}
|
||||
if (!instr->is_external()) {
|
||||
ASSERT(instr->elements()->representation().IsTagged());
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
|
||||
if (instr->value()->representation().IsDouble()) {
|
||||
LOperand* object = UseRegisterAtStart(instr->elements());
|
||||
LOperand* val = UseTempRegister(instr->value());
|
||||
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
|
||||
|
||||
LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement(
|
||||
HStoreKeyedFastDoubleElement* instr) {
|
||||
ASSERT(instr->value()->representation().IsDouble());
|
||||
ASSERT(instr->elements()->representation().IsTagged());
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
result = new(zone()) LStoreKeyed(object, key, val);
|
||||
} else {
|
||||
ASSERT(instr->value()->representation().IsTagged());
|
||||
bool needs_write_barrier = instr->NeedsWriteBarrier();
|
||||
|
||||
LOperand* elements = UseRegisterAtStart(instr->elements());
|
||||
LOperand* val = UseTempRegister(instr->value());
|
||||
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
|
||||
|
||||
return new(zone()) LStoreKeyedFastDoubleElement(elements, key, val);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
|
||||
HStoreKeyedSpecializedArrayElement* instr) {
|
||||
ElementsKind elements_kind = instr->elements_kind();
|
||||
ASSERT(
|
||||
(instr->value()->representation().IsInteger32() &&
|
||||
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
|
||||
(elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
|
||||
(instr->value()->representation().IsDouble() &&
|
||||
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
|
||||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
|
||||
ASSERT(instr->external_pointer()->representation().IsExternal());
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
|
||||
LOperand* external_pointer = UseRegister(instr->external_pointer());
|
||||
LOperand* val = NULL;
|
||||
if (elements_kind == EXTERNAL_BYTE_ELEMENTS ||
|
||||
elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
|
||||
elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
|
||||
// We need a byte register in this case for the value.
|
||||
val = UseFixed(instr->value(), eax);
|
||||
LOperand* obj = UseRegister(instr->elements());
|
||||
LOperand* val = needs_write_barrier
|
||||
? UseTempRegister(instr->value())
|
||||
: UseRegisterAtStart(instr->value());
|
||||
LOperand* key = needs_write_barrier
|
||||
? UseTempRegister(instr->key())
|
||||
: UseRegisterOrConstantAtStart(instr->key());
|
||||
result = new(zone()) LStoreKeyed(obj, key, val);
|
||||
}
|
||||
} else {
|
||||
val = UseRegister(instr->value());
|
||||
ElementsKind elements_kind = instr->elements_kind();
|
||||
ASSERT(
|
||||
(instr->value()->representation().IsInteger32() &&
|
||||
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
|
||||
(elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
|
||||
(instr->value()->representation().IsDouble() &&
|
||||
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
|
||||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
|
||||
ASSERT(instr->elements()->representation().IsExternal());
|
||||
|
||||
LOperand* external_pointer = UseRegister(instr->elements());
|
||||
// Determine if we need a byte register in this case for the value.
|
||||
bool val_is_fixed_register =
|
||||
elements_kind == EXTERNAL_BYTE_ELEMENTS ||
|
||||
elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
|
||||
elements_kind == EXTERNAL_PIXEL_ELEMENTS;
|
||||
|
||||
LOperand* val = val_is_fixed_register
|
||||
? UseFixed(instr->value(), eax)
|
||||
: UseRegister(instr->value());
|
||||
bool clobbers_key = ExternalArrayOpRequiresTemp(
|
||||
instr->key()->representation(), elements_kind);
|
||||
LOperand* key = clobbers_key
|
||||
? UseTempRegister(instr->key())
|
||||
: UseRegisterOrConstantAtStart(instr->key());
|
||||
result = new(zone()) LStoreKeyed(external_pointer,
|
||||
key,
|
||||
val);
|
||||
}
|
||||
bool clobbers_key = ExternalArrayOpRequiresTemp(
|
||||
instr->key()->representation(), elements_kind);
|
||||
LOperand* key = clobbers_key
|
||||
? UseTempRegister(instr->key())
|
||||
: UseRegisterOrConstant(instr->key());
|
||||
return new(zone()) LStoreKeyedSpecializedArrayElement(external_pointer,
|
||||
key,
|
||||
val);
|
||||
|
||||
ASSERT(result != NULL);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -119,10 +119,8 @@ class LCodeGen;
|
||||
V(LoadFunctionPrototype) \
|
||||
V(LoadGlobalCell) \
|
||||
V(LoadGlobalGeneric) \
|
||||
V(LoadKeyedFastElement) \
|
||||
V(LoadKeyedFastDoubleElement) \
|
||||
V(LoadKeyed) \
|
||||
V(LoadKeyedGeneric) \
|
||||
V(LoadKeyedSpecializedArrayElement) \
|
||||
V(LoadNamedField) \
|
||||
V(LoadNamedFieldPolymorphic) \
|
||||
V(LoadNamedGeneric) \
|
||||
@ -152,10 +150,8 @@ class LCodeGen;
|
||||
V(StoreContextSlot) \
|
||||
V(StoreGlobalCell) \
|
||||
V(StoreGlobalGeneric) \
|
||||
V(StoreKeyedFastDoubleElement) \
|
||||
V(StoreKeyedFastElement) \
|
||||
V(StoreKeyed) \
|
||||
V(StoreKeyedGeneric) \
|
||||
V(StoreKeyedSpecializedArrayElement) \
|
||||
V(StoreNamedField) \
|
||||
V(StoreNamedGeneric) \
|
||||
V(StringAdd) \
|
||||
@ -1389,36 +1385,24 @@ class LLoadExternalArrayPointer: public LTemplateInstruction<1, 1, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
|
||||
class LLoadKeyed: public LTemplateInstruction<1, 2, 0> {
|
||||
public:
|
||||
LLoadKeyedFastElement(LOperand* elements, LOperand* key) {
|
||||
LLoadKeyed(LOperand* elements, LOperand* key) {
|
||||
inputs_[0] = elements;
|
||||
inputs_[1] = key;
|
||||
}
|
||||
|
||||
LOperand* elements() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement, "load-keyed-fast-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastElement)
|
||||
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
};
|
||||
|
||||
|
||||
class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
|
||||
public:
|
||||
LLoadKeyedFastDoubleElement(LOperand* elements, LOperand* key) {
|
||||
inputs_[0] = elements;
|
||||
inputs_[1] = key;
|
||||
ElementsKind elements_kind() const {
|
||||
return hydrogen()->elements_kind();
|
||||
}
|
||||
bool is_external() const {
|
||||
return hydrogen()->is_external();
|
||||
}
|
||||
|
||||
LOperand* elements() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement,
|
||||
"load-keyed-fast-double-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastDoubleElement)
|
||||
DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
|
||||
DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
|
||||
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
};
|
||||
@ -1437,27 +1421,6 @@ inline static bool ExternalArrayOpRequiresTemp(
|
||||
}
|
||||
|
||||
|
||||
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
|
||||
public:
|
||||
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LOperand* key) {
|
||||
inputs_[0] = external_pointer;
|
||||
inputs_[1] = key;
|
||||
}
|
||||
|
||||
LOperand* external_pointer() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement,
|
||||
"load-keyed-specialized-array-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedSpecializedArrayElement)
|
||||
|
||||
ElementsKind elements_kind() const {
|
||||
return hydrogen()->elements_kind();
|
||||
}
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
};
|
||||
|
||||
|
||||
class LLoadKeyedGeneric: public LTemplateInstruction<1, 3, 0> {
|
||||
public:
|
||||
LLoadKeyedGeneric(LOperand* context, LOperand* obj, LOperand* key) {
|
||||
@ -2006,75 +1969,28 @@ class LStoreNamedGeneric: public LTemplateInstruction<0, 3, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
|
||||
class LStoreKeyed: public LTemplateInstruction<0, 3, 0> {
|
||||
public:
|
||||
LStoreKeyedFastElement(LOperand* obj, LOperand* key, LOperand* val) {
|
||||
LStoreKeyed(LOperand* obj, LOperand* key, LOperand* val) {
|
||||
inputs_[0] = obj;
|
||||
inputs_[1] = key;
|
||||
inputs_[2] = val;
|
||||
}
|
||||
|
||||
LOperand* object() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
LOperand* value() { return inputs_[2]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement,
|
||||
"store-keyed-fast-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastElement)
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
};
|
||||
|
||||
|
||||
class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> {
|
||||
public:
|
||||
LStoreKeyedFastDoubleElement(LOperand* elements,
|
||||
LOperand* key,
|
||||
LOperand* val) {
|
||||
inputs_[0] = elements;
|
||||
inputs_[1] = key;
|
||||
inputs_[2] = val;
|
||||
}
|
||||
|
||||
bool is_external() const { return hydrogen()->is_external(); }
|
||||
LOperand* elements() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
LOperand* value() { return inputs_[2]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement,
|
||||
"store-keyed-fast-double-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastDoubleElement)
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
|
||||
bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
|
||||
};
|
||||
|
||||
|
||||
class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
|
||||
public:
|
||||
LStoreKeyedSpecializedArrayElement(LOperand* external_pointer,
|
||||
LOperand* key,
|
||||
LOperand* val) {
|
||||
inputs_[0] = external_pointer;
|
||||
inputs_[1] = key;
|
||||
inputs_[2] = val;
|
||||
}
|
||||
|
||||
LOperand* external_pointer() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
LOperand* value() { return inputs_[2]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement,
|
||||
"store-keyed-specialized-array-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedSpecializedArrayElement)
|
||||
|
||||
ElementsKind elements_kind() const {
|
||||
return hydrogen()->elements_kind();
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed")
|
||||
DECLARE_HYDROGEN_ACCESSOR(StoreKeyed)
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -2612,123 +2612,16 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
|
||||
Register result = ToRegister(instr->result());
|
||||
LOperand* key = instr->key();
|
||||
if (!key->IsConstantOperand()) {
|
||||
Register key_reg = ToRegister(key);
|
||||
// Even though the HLoad/StoreKeyedFastElement instructions force the input
|
||||
// representation for the key to be an integer, the input gets replaced
|
||||
// during bound check elimination with the index argument to the bounds
|
||||
// check, which can be tagged, so that case must be handled here, too.
|
||||
if (instr->hydrogen()->key()->representation().IsTagged()) {
|
||||
__ SmiToInteger64(key_reg, key_reg);
|
||||
} else if (instr->hydrogen()->IsDehoisted()) {
|
||||
// Sign extend key because it could be a 32 bit negative value
|
||||
// and the dehoisted address computation happens in 64 bits
|
||||
__ movsxlq(key_reg, key_reg);
|
||||
}
|
||||
}
|
||||
|
||||
// Load the result.
|
||||
__ movq(result,
|
||||
BuildFastArrayOperand(instr->elements(),
|
||||
key,
|
||||
FAST_ELEMENTS,
|
||||
FixedArray::kHeaderSize - kHeapObjectTag,
|
||||
instr->additional_index()));
|
||||
|
||||
// Check for the hole value.
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
|
||||
Condition smi = __ CheckSmi(result);
|
||||
DeoptimizeIf(NegateCondition(smi), instr->environment());
|
||||
} else {
|
||||
__ CompareRoot(result, Heap::kTheHoleValueRootIndex);
|
||||
DeoptimizeIf(equal, instr->environment());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedFastDoubleElement(
|
||||
LLoadKeyedFastDoubleElement* instr) {
|
||||
XMMRegister result(ToDoubleRegister(instr->result()));
|
||||
LOperand* key = instr->key();
|
||||
if (!key->IsConstantOperand()) {
|
||||
Register key_reg = ToRegister(key);
|
||||
// Even though the HLoad/StoreKeyedFastElement instructions force the input
|
||||
// representation for the key to be an integer, the input gets replaced
|
||||
// during bound check elimination with the index argument to the bounds
|
||||
// check, which can be tagged, so that case must be handled here, too.
|
||||
if (instr->hydrogen()->key()->representation().IsTagged()) {
|
||||
__ SmiToInteger64(key_reg, key_reg);
|
||||
} else if (instr->hydrogen()->IsDehoisted()) {
|
||||
// Sign extend key because it could be a 32 bit negative value
|
||||
// and the dehoisted address computation happens in 64 bits
|
||||
__ movsxlq(key_reg, key_reg);
|
||||
}
|
||||
}
|
||||
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
|
||||
sizeof(kHoleNanLower32);
|
||||
Operand hole_check_operand = BuildFastArrayOperand(
|
||||
instr->elements(),
|
||||
key,
|
||||
FAST_DOUBLE_ELEMENTS,
|
||||
offset,
|
||||
instr->additional_index());
|
||||
__ cmpl(hole_check_operand, Immediate(kHoleNanUpper32));
|
||||
DeoptimizeIf(equal, instr->environment());
|
||||
}
|
||||
|
||||
Operand double_load_operand = BuildFastArrayOperand(
|
||||
instr->elements(),
|
||||
key,
|
||||
FAST_DOUBLE_ELEMENTS,
|
||||
FixedDoubleArray::kHeaderSize - kHeapObjectTag,
|
||||
instr->additional_index());
|
||||
__ movsd(result, double_load_operand);
|
||||
}
|
||||
|
||||
|
||||
Operand LCodeGen::BuildFastArrayOperand(
|
||||
LOperand* elements_pointer,
|
||||
LOperand* key,
|
||||
ElementsKind elements_kind,
|
||||
uint32_t offset,
|
||||
uint32_t additional_index) {
|
||||
Register elements_pointer_reg = ToRegister(elements_pointer);
|
||||
int shift_size = ElementsKindToShiftSize(elements_kind);
|
||||
if (key->IsConstantOperand()) {
|
||||
int constant_value = ToInteger32(LConstantOperand::cast(key));
|
||||
if (constant_value & 0xF0000000) {
|
||||
Abort("array index constant value too big");
|
||||
}
|
||||
return Operand(elements_pointer_reg,
|
||||
((constant_value + additional_index) << shift_size)
|
||||
+ offset);
|
||||
} else {
|
||||
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
|
||||
return Operand(elements_pointer_reg,
|
||||
ToRegister(key),
|
||||
scale_factor,
|
||||
offset + (additional_index << shift_size));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
|
||||
LLoadKeyedSpecializedArrayElement* instr) {
|
||||
void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
|
||||
ElementsKind elements_kind = instr->elements_kind();
|
||||
LOperand* key = instr->key();
|
||||
if (!key->IsConstantOperand()) {
|
||||
Register key_reg = ToRegister(key);
|
||||
// Even though the HLoad/StoreKeyedFastElement instructions force the input
|
||||
// representation for the key to be an integer, the input gets replaced
|
||||
// during bound check elimination with the index argument to the bounds
|
||||
// check, which can be tagged, so that case must be handled here, too.
|
||||
// Even though the HLoad/StoreKeyed (in this case) instructions force
|
||||
// the input representation for the key to be an integer, the input
|
||||
// gets replaced during bound check elimination with the index argument
|
||||
// to the bounds check, which can be tagged, so that case must be
|
||||
// handled here, too.
|
||||
if (instr->hydrogen()->key()->representation().IsTagged()) {
|
||||
__ SmiToInteger64(key_reg, key_reg);
|
||||
} else if (instr->hydrogen()->IsDehoisted()) {
|
||||
@ -2738,7 +2631,7 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
|
||||
}
|
||||
}
|
||||
Operand operand(BuildFastArrayOperand(
|
||||
instr->external_pointer(),
|
||||
instr->elements(),
|
||||
key,
|
||||
elements_kind,
|
||||
0,
|
||||
@ -2793,6 +2686,124 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
|
||||
XMMRegister result(ToDoubleRegister(instr->result()));
|
||||
LOperand* key = instr->key();
|
||||
if (!key->IsConstantOperand()) {
|
||||
Register key_reg = ToRegister(key);
|
||||
// Even though the HLoad/StoreKeyed instructions force the input
|
||||
// representation for the key to be an integer, the input gets replaced
|
||||
// during bound check elimination with the index argument to the bounds
|
||||
// check, which can be tagged, so that case must be handled here, too.
|
||||
if (instr->hydrogen()->key()->representation().IsTagged()) {
|
||||
__ SmiToInteger64(key_reg, key_reg);
|
||||
} else if (instr->hydrogen()->IsDehoisted()) {
|
||||
// Sign extend key because it could be a 32 bit negative value
|
||||
// and the dehoisted address computation happens in 64 bits
|
||||
__ movsxlq(key_reg, key_reg);
|
||||
}
|
||||
}
|
||||
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
|
||||
sizeof(kHoleNanLower32);
|
||||
Operand hole_check_operand = BuildFastArrayOperand(
|
||||
instr->elements(),
|
||||
key,
|
||||
FAST_DOUBLE_ELEMENTS,
|
||||
offset,
|
||||
instr->additional_index());
|
||||
__ cmpl(hole_check_operand, Immediate(kHoleNanUpper32));
|
||||
DeoptimizeIf(equal, instr->environment());
|
||||
}
|
||||
|
||||
Operand double_load_operand = BuildFastArrayOperand(
|
||||
instr->elements(),
|
||||
key,
|
||||
FAST_DOUBLE_ELEMENTS,
|
||||
FixedDoubleArray::kHeaderSize - kHeapObjectTag,
|
||||
instr->additional_index());
|
||||
__ movsd(result, double_load_operand);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
|
||||
Register result = ToRegister(instr->result());
|
||||
LOperand* key = instr->key();
|
||||
if (!key->IsConstantOperand()) {
|
||||
Register key_reg = ToRegister(key);
|
||||
// Even though the HLoad/StoreKeyedFastElement instructions force
|
||||
// the input representation for the key to be an integer, the input
|
||||
// gets replaced during bound check elimination with the index
|
||||
// argument to the bounds check, which can be tagged, so that
|
||||
// case must be handled here, too.
|
||||
if (instr->hydrogen()->key()->representation().IsTagged()) {
|
||||
__ SmiToInteger64(key_reg, key_reg);
|
||||
} else if (instr->hydrogen()->IsDehoisted()) {
|
||||
// Sign extend key because it could be a 32 bit negative value
|
||||
// and the dehoisted address computation happens in 64 bits
|
||||
__ movsxlq(key_reg, key_reg);
|
||||
}
|
||||
}
|
||||
|
||||
// Load the result.
|
||||
__ movq(result,
|
||||
BuildFastArrayOperand(instr->elements(),
|
||||
key,
|
||||
FAST_ELEMENTS,
|
||||
FixedArray::kHeaderSize - kHeapObjectTag,
|
||||
instr->additional_index()));
|
||||
|
||||
// Check for the hole value.
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
|
||||
Condition smi = __ CheckSmi(result);
|
||||
DeoptimizeIf(NegateCondition(smi), instr->environment());
|
||||
} else {
|
||||
__ CompareRoot(result, Heap::kTheHoleValueRootIndex);
|
||||
DeoptimizeIf(equal, instr->environment());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
|
||||
if (instr->is_external()) {
|
||||
DoLoadKeyedExternalArray(instr);
|
||||
} else if (instr->hydrogen()->representation().IsDouble()) {
|
||||
DoLoadKeyedFixedDoubleArray(instr);
|
||||
} else {
|
||||
DoLoadKeyedFixedArray(instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Operand LCodeGen::BuildFastArrayOperand(
|
||||
LOperand* elements_pointer,
|
||||
LOperand* key,
|
||||
ElementsKind elements_kind,
|
||||
uint32_t offset,
|
||||
uint32_t additional_index) {
|
||||
Register elements_pointer_reg = ToRegister(elements_pointer);
|
||||
int shift_size = ElementsKindToShiftSize(elements_kind);
|
||||
if (key->IsConstantOperand()) {
|
||||
int constant_value = ToInteger32(LConstantOperand::cast(key));
|
||||
if (constant_value & 0xF0000000) {
|
||||
Abort("array index constant value too big");
|
||||
}
|
||||
return Operand(elements_pointer_reg,
|
||||
((constant_value + additional_index) << shift_size)
|
||||
+ offset);
|
||||
} else {
|
||||
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
|
||||
return Operand(elements_pointer_reg,
|
||||
ToRegister(key),
|
||||
scale_factor,
|
||||
offset + (additional_index << shift_size));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
|
||||
ASSERT(ToRegister(instr->object()).is(rdx));
|
||||
ASSERT(ToRegister(instr->key()).is(rax));
|
||||
@ -3665,70 +3676,6 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
|
||||
LStoreKeyedSpecializedArrayElement* instr) {
|
||||
ElementsKind elements_kind = instr->elements_kind();
|
||||
LOperand* key = instr->key();
|
||||
if (!key->IsConstantOperand()) {
|
||||
Register key_reg = ToRegister(key);
|
||||
// Even though the HLoad/StoreKeyedFastElement instructions force the input
|
||||
// representation for the key to be an integer, the input gets replaced
|
||||
// during bound check elimination with the index argument to the bounds
|
||||
// check, which can be tagged, so that case must be handled here, too.
|
||||
if (instr->hydrogen()->key()->representation().IsTagged()) {
|
||||
__ SmiToInteger64(key_reg, key_reg);
|
||||
} else if (instr->hydrogen()->IsDehoisted()) {
|
||||
// Sign extend key because it could be a 32 bit negative value
|
||||
// and the dehoisted address computation happens in 64 bits
|
||||
__ movsxlq(key_reg, key_reg);
|
||||
}
|
||||
}
|
||||
Operand operand(BuildFastArrayOperand(
|
||||
instr->external_pointer(),
|
||||
key,
|
||||
elements_kind,
|
||||
0,
|
||||
instr->additional_index()));
|
||||
|
||||
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
|
||||
XMMRegister value(ToDoubleRegister(instr->value()));
|
||||
__ cvtsd2ss(value, value);
|
||||
__ movss(operand, value);
|
||||
} else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
|
||||
__ movsd(operand, ToDoubleRegister(instr->value()));
|
||||
} else {
|
||||
Register value(ToRegister(instr->value()));
|
||||
switch (elements_kind) {
|
||||
case EXTERNAL_PIXEL_ELEMENTS:
|
||||
case EXTERNAL_BYTE_ELEMENTS:
|
||||
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
|
||||
__ movb(operand, value);
|
||||
break;
|
||||
case EXTERNAL_SHORT_ELEMENTS:
|
||||
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
|
||||
__ movw(operand, value);
|
||||
break;
|
||||
case EXTERNAL_INT_ELEMENTS:
|
||||
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
|
||||
__ movl(operand, value);
|
||||
break;
|
||||
case EXTERNAL_FLOAT_ELEMENTS:
|
||||
case EXTERNAL_DOUBLE_ELEMENTS:
|
||||
case FAST_ELEMENTS:
|
||||
case FAST_SMI_ELEMENTS:
|
||||
case FAST_DOUBLE_ELEMENTS:
|
||||
case FAST_HOLEY_ELEMENTS:
|
||||
case FAST_HOLEY_SMI_ELEMENTS:
|
||||
case FAST_HOLEY_DOUBLE_ELEMENTS:
|
||||
case DICTIONARY_ELEMENTS:
|
||||
case NON_STRICT_ARGUMENTS_ELEMENTS:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DeoptIfTaggedButNotSmi(LEnvironment* environment,
|
||||
HValue* value,
|
||||
LOperand* operand) {
|
||||
@ -3789,16 +3736,16 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
|
||||
Register value = ToRegister(instr->value());
|
||||
Register elements = ToRegister(instr->object());
|
||||
void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
|
||||
ElementsKind elements_kind = instr->elements_kind();
|
||||
LOperand* key = instr->key();
|
||||
if (!key->IsConstantOperand()) {
|
||||
Register key_reg = ToRegister(key);
|
||||
// Even though the HLoad/StoreKeyedFastElement instructions force the input
|
||||
// representation for the key to be an integer, the input gets replaced
|
||||
// during bound check elimination with the index argument to the bounds
|
||||
// check, which can be tagged, so that case must be handled here, too.
|
||||
// Even though the HLoad/StoreKeyedFastElement instructions force
|
||||
// the input representation for the key to be an integer, the input
|
||||
// gets replaced during bound check elimination with the index
|
||||
// argument to the bounds check, which can be tagged, so that case
|
||||
// must be handled here, too.
|
||||
if (instr->hydrogen()->key()->representation().IsTagged()) {
|
||||
__ SmiToInteger64(key_reg, key_reg);
|
||||
} else if (instr->hydrogen()->IsDehoisted()) {
|
||||
@ -3807,45 +3754,62 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
|
||||
__ movsxlq(key_reg, key_reg);
|
||||
}
|
||||
}
|
||||
Operand operand(BuildFastArrayOperand(
|
||||
instr->elements(),
|
||||
key,
|
||||
elements_kind,
|
||||
0,
|
||||
instr->additional_index()));
|
||||
|
||||
Operand operand =
|
||||
BuildFastArrayOperand(instr->object(),
|
||||
key,
|
||||
FAST_ELEMENTS,
|
||||
FixedArray::kHeaderSize - kHeapObjectTag,
|
||||
instr->additional_index());
|
||||
|
||||
if (instr->hydrogen()->NeedsWriteBarrier()) {
|
||||
ASSERT(!instr->key()->IsConstantOperand());
|
||||
HType type = instr->hydrogen()->value()->type();
|
||||
SmiCheck check_needed =
|
||||
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
|
||||
// Compute address of modified element and store it into key register.
|
||||
Register key_reg(ToRegister(key));
|
||||
__ lea(key_reg, operand);
|
||||
__ movq(Operand(key_reg, 0), value);
|
||||
__ RecordWrite(elements,
|
||||
key_reg,
|
||||
value,
|
||||
kSaveFPRegs,
|
||||
EMIT_REMEMBERED_SET,
|
||||
check_needed);
|
||||
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
|
||||
XMMRegister value(ToDoubleRegister(instr->value()));
|
||||
__ cvtsd2ss(value, value);
|
||||
__ movss(operand, value);
|
||||
} else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
|
||||
__ movsd(operand, ToDoubleRegister(instr->value()));
|
||||
} else {
|
||||
__ movq(operand, value);
|
||||
Register value(ToRegister(instr->value()));
|
||||
switch (elements_kind) {
|
||||
case EXTERNAL_PIXEL_ELEMENTS:
|
||||
case EXTERNAL_BYTE_ELEMENTS:
|
||||
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
|
||||
__ movb(operand, value);
|
||||
break;
|
||||
case EXTERNAL_SHORT_ELEMENTS:
|
||||
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
|
||||
__ movw(operand, value);
|
||||
break;
|
||||
case EXTERNAL_INT_ELEMENTS:
|
||||
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
|
||||
__ movl(operand, value);
|
||||
break;
|
||||
case EXTERNAL_FLOAT_ELEMENTS:
|
||||
case EXTERNAL_DOUBLE_ELEMENTS:
|
||||
case FAST_ELEMENTS:
|
||||
case FAST_SMI_ELEMENTS:
|
||||
case FAST_DOUBLE_ELEMENTS:
|
||||
case FAST_HOLEY_ELEMENTS:
|
||||
case FAST_HOLEY_SMI_ELEMENTS:
|
||||
case FAST_HOLEY_DOUBLE_ELEMENTS:
|
||||
case DICTIONARY_ELEMENTS:
|
||||
case NON_STRICT_ARGUMENTS_ELEMENTS:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyedFastDoubleElement(
|
||||
LStoreKeyedFastDoubleElement* instr) {
|
||||
void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
|
||||
XMMRegister value = ToDoubleRegister(instr->value());
|
||||
LOperand* key = instr->key();
|
||||
if (!key->IsConstantOperand()) {
|
||||
Register key_reg = ToRegister(key);
|
||||
// Even though the HLoad/StoreKeyedFastElement instructions force the input
|
||||
// representation for the key to be an integer, the input gets replaced
|
||||
// during bound check elimination with the index argument to the bounds
|
||||
// check, which can be tagged, so that case must be handled here, too.
|
||||
// Even though the HLoad/StoreKeyedFastElement instructions force
|
||||
// the input representation for the key to be an integer, the
|
||||
// input gets replaced during bound check elimination with the index
|
||||
// argument to the bounds check, which can be tagged, so that case
|
||||
// must be handled here, too.
|
||||
if (instr->hydrogen()->key()->representation().IsTagged()) {
|
||||
__ SmiToInteger64(key_reg, key_reg);
|
||||
} else if (instr->hydrogen()->IsDehoisted()) {
|
||||
@ -3878,6 +3842,66 @@ void LCodeGen::DoStoreKeyedFastDoubleElement(
|
||||
__ movsd(double_store_operand, value);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
|
||||
Register value = ToRegister(instr->value());
|
||||
Register elements = ToRegister(instr->elements());
|
||||
LOperand* key = instr->key();
|
||||
if (!key->IsConstantOperand()) {
|
||||
Register key_reg = ToRegister(key);
|
||||
// Even though the HLoad/StoreKeyedFastElement instructions force
|
||||
// the input representation for the key to be an integer, the
|
||||
// input gets replaced during bound check elimination with the index
|
||||
// argument to the bounds check, which can be tagged, so that case
|
||||
// must be handled here, too.
|
||||
if (instr->hydrogen()->key()->representation().IsTagged()) {
|
||||
__ SmiToInteger64(key_reg, key_reg);
|
||||
} else if (instr->hydrogen()->IsDehoisted()) {
|
||||
// Sign extend key because it could be a 32 bit negative value
|
||||
// and the dehoisted address computation happens in 64 bits
|
||||
__ movsxlq(key_reg, key_reg);
|
||||
}
|
||||
}
|
||||
|
||||
Operand operand =
|
||||
BuildFastArrayOperand(instr->elements(),
|
||||
key,
|
||||
FAST_ELEMENTS,
|
||||
FixedArray::kHeaderSize - kHeapObjectTag,
|
||||
instr->additional_index());
|
||||
|
||||
if (instr->hydrogen()->NeedsWriteBarrier()) {
|
||||
ASSERT(!instr->key()->IsConstantOperand());
|
||||
HType type = instr->hydrogen()->value()->type();
|
||||
SmiCheck check_needed =
|
||||
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
|
||||
// Compute address of modified element and store it into key register.
|
||||
Register key_reg(ToRegister(key));
|
||||
__ lea(key_reg, operand);
|
||||
__ movq(Operand(key_reg, 0), value);
|
||||
__ RecordWrite(elements,
|
||||
key_reg,
|
||||
value,
|
||||
kSaveFPRegs,
|
||||
EMIT_REMEMBERED_SET,
|
||||
check_needed);
|
||||
} else {
|
||||
__ movq(operand, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
|
||||
if (instr->is_external()) {
|
||||
DoStoreKeyedExternalArray(instr);
|
||||
} else if (instr->hydrogen()->value()->representation().IsDouble()) {
|
||||
DoStoreKeyedFixedDoubleArray(instr);
|
||||
} else {
|
||||
DoStoreKeyedFixedArray(instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
|
||||
ASSERT(ToRegister(instr->object()).is(rdx));
|
||||
ASSERT(ToRegister(instr->key()).is(rcx));
|
||||
|
@ -335,6 +335,12 @@ class LCodeGen BASE_EMBEDDED {
|
||||
};
|
||||
|
||||
void EnsureSpaceForLazyDeopt(int space_needed);
|
||||
void DoLoadKeyedExternalArray(LLoadKeyed* instr);
|
||||
void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr);
|
||||
void DoLoadKeyedFixedArray(LLoadKeyed* instr);
|
||||
void DoStoreKeyedExternalArray(LStoreKeyed* instr);
|
||||
void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr);
|
||||
void DoStoreKeyedFixedArray(LStoreKeyed* instr);
|
||||
|
||||
Zone* zone_;
|
||||
LPlatformChunk* const chunk_;
|
||||
|
@ -394,16 +394,7 @@ void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintTo(stream);
|
||||
stream->Add("[");
|
||||
key()->PrintTo(stream);
|
||||
stream->Add("] <- ");
|
||||
value()->PrintTo(stream);
|
||||
}
|
||||
|
||||
|
||||
void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
|
||||
void LStoreKeyed::PrintDataTo(StringStream* stream) {
|
||||
elements()->PrintTo(stream);
|
||||
stream->Add("[");
|
||||
key()->PrintTo(stream);
|
||||
@ -1843,63 +1834,37 @@ LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
|
||||
HLoadKeyedFastElement* instr) {
|
||||
ASSERT(instr->representation().IsTagged());
|
||||
LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
LOperand* obj = UseRegisterAtStart(instr->object());
|
||||
bool clobbers_key = instr->key()->representation().IsTagged();
|
||||
LOperand* key = clobbers_key
|
||||
? UseTempRegister(instr->key())
|
||||
: UseRegisterOrConstantAtStart(instr->key());
|
||||
LLoadKeyedFastElement* result =
|
||||
new(zone()) LLoadKeyedFastElement(obj, key);
|
||||
if (instr->RequiresHoleCheck()) AssignEnvironment(result);
|
||||
return DefineAsRegister(result);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
|
||||
HLoadKeyedFastDoubleElement* instr) {
|
||||
ASSERT(instr->representation().IsDouble());
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
LOperand* elements = UseRegisterAtStart(instr->elements());
|
||||
bool clobbers_key = instr->key()->representation().IsTagged();
|
||||
LOperand* key = clobbers_key
|
||||
? UseTempRegister(instr->key())
|
||||
: UseRegisterOrConstantAtStart(instr->key());
|
||||
LLoadKeyedFastDoubleElement* result =
|
||||
new(zone()) LLoadKeyedFastDoubleElement(elements, key);
|
||||
return AssignEnvironment(DefineAsRegister(result));
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
|
||||
HLoadKeyedSpecializedArrayElement* instr) {
|
||||
ElementsKind elements_kind = instr->elements_kind();
|
||||
ASSERT(
|
||||
(instr->representation().IsInteger32() &&
|
||||
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
|
||||
(elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
|
||||
(instr->representation().IsDouble() &&
|
||||
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
|
||||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
LOperand* external_pointer = UseRegister(instr->external_pointer());
|
||||
bool clobbers_key = instr->key()->representation().IsTagged();
|
||||
LOperand* key = clobbers_key
|
||||
? UseTempRegister(instr->key())
|
||||
: UseRegisterOrConstantAtStart(instr->key());
|
||||
LLoadKeyedSpecializedArrayElement* result =
|
||||
new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer, key);
|
||||
LInstruction* load_instr = DefineAsRegister(result);
|
||||
LLoadKeyed* result = NULL;
|
||||
|
||||
if (!instr->is_external()) {
|
||||
LOperand* obj = UseRegisterAtStart(instr->elements());
|
||||
result = new(zone()) LLoadKeyed(obj, key);
|
||||
} else {
|
||||
ASSERT(
|
||||
(instr->representation().IsInteger32() &&
|
||||
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
|
||||
(elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
|
||||
(instr->representation().IsDouble() &&
|
||||
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
|
||||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
|
||||
LOperand* external_pointer = UseRegister(instr->elements());
|
||||
result = new(zone()) LLoadKeyed(external_pointer, key);
|
||||
}
|
||||
|
||||
DefineAsRegister(result);
|
||||
bool can_deoptimize = instr->RequiresHoleCheck() ||
|
||||
(elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS);
|
||||
// An unsigned int array load might overflow and cause a deopt, make sure it
|
||||
// has an environment.
|
||||
return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) ?
|
||||
AssignEnvironment(load_instr) : load_instr;
|
||||
return can_deoptimize ? AssignEnvironment(result) : result;
|
||||
}
|
||||
|
||||
|
||||
@ -1912,71 +1877,49 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
|
||||
HStoreKeyedFastElement* instr) {
|
||||
bool needs_write_barrier = instr->NeedsWriteBarrier();
|
||||
ASSERT(instr->value()->representation().IsTagged());
|
||||
ASSERT(instr->object()->representation().IsTagged());
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
|
||||
LOperand* obj = UseTempRegister(instr->object());
|
||||
LOperand* val = needs_write_barrier
|
||||
? UseTempRegister(instr->value())
|
||||
: UseRegisterAtStart(instr->value());
|
||||
bool clobbers_key = needs_write_barrier ||
|
||||
instr->key()->representation().IsTagged();
|
||||
LOperand* key = clobbers_key
|
||||
? UseTempRegister(instr->key())
|
||||
: UseRegisterOrConstantAtStart(instr->key());
|
||||
return new(zone()) LStoreKeyedFastElement(obj, key, val);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement(
|
||||
HStoreKeyedFastDoubleElement* instr) {
|
||||
ASSERT(instr->value()->representation().IsDouble());
|
||||
ASSERT(instr->elements()->representation().IsTagged());
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
|
||||
LOperand* elements = UseRegisterAtStart(instr->elements());
|
||||
LOperand* val = UseTempRegister(instr->value());
|
||||
bool clobbers_key = instr->key()->representation().IsTagged();
|
||||
LOperand* key = clobbers_key
|
||||
? UseTempRegister(instr->key())
|
||||
: UseRegisterOrConstantAtStart(instr->key());
|
||||
return new(zone()) LStoreKeyedFastDoubleElement(elements, key, val);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
|
||||
HStoreKeyedSpecializedArrayElement* instr) {
|
||||
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
|
||||
ElementsKind elements_kind = instr->elements_kind();
|
||||
ASSERT(
|
||||
(instr->value()->representation().IsInteger32() &&
|
||||
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
|
||||
(elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
|
||||
(instr->value()->representation().IsDouble() &&
|
||||
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
|
||||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
|
||||
ASSERT(instr->external_pointer()->representation().IsExternal());
|
||||
ASSERT(instr->key()->representation().IsInteger32() ||
|
||||
instr->key()->representation().IsTagged());
|
||||
|
||||
LOperand* external_pointer = UseRegister(instr->external_pointer());
|
||||
bool needs_write_barrier = instr->NeedsWriteBarrier();
|
||||
bool clobbers_key = instr->key()->representation().IsTagged();
|
||||
LOperand* key = (clobbers_key || needs_write_barrier)
|
||||
? UseTempRegister(instr->key())
|
||||
: UseRegisterOrConstantAtStart(instr->key());
|
||||
bool val_is_temp_register =
|
||||
elements_kind == EXTERNAL_PIXEL_ELEMENTS ||
|
||||
elements_kind == EXTERNAL_FLOAT_ELEMENTS;
|
||||
LOperand* val = val_is_temp_register
|
||||
LOperand* val = (needs_write_barrier || val_is_temp_register)
|
||||
? UseTempRegister(instr->value())
|
||||
: UseRegister(instr->value());
|
||||
bool clobbers_key = instr->key()->representation().IsTagged();
|
||||
LOperand* key = clobbers_key
|
||||
? UseTempRegister(instr->key())
|
||||
: UseRegisterOrConstantAtStart(instr->key());
|
||||
return new(zone()) LStoreKeyedSpecializedArrayElement(external_pointer,
|
||||
key, val);
|
||||
: UseRegisterAtStart(instr->value());
|
||||
LStoreKeyed* result = NULL;
|
||||
|
||||
if (!instr->is_external()) {
|
||||
ASSERT(instr->elements()->representation().IsTagged());
|
||||
|
||||
LOperand* object = NULL;
|
||||
if (instr->value()->representation().IsDouble()) {
|
||||
object = UseRegisterAtStart(instr->elements());
|
||||
} else {
|
||||
ASSERT(instr->value()->representation().IsTagged());
|
||||
object = UseTempRegister(instr->elements());
|
||||
}
|
||||
|
||||
result = new(zone()) LStoreKeyed(object, key, val);
|
||||
} else {
|
||||
ASSERT(
|
||||
(instr->value()->representation().IsInteger32() &&
|
||||
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
|
||||
(elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
|
||||
(instr->value()->representation().IsDouble() &&
|
||||
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
|
||||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
|
||||
ASSERT(instr->elements()->representation().IsExternal());
|
||||
|
||||
LOperand* external_pointer = UseRegister(instr->elements());
|
||||
result = new(zone()) LStoreKeyed(external_pointer, key, val);
|
||||
}
|
||||
|
||||
ASSERT(result != NULL);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -126,10 +126,8 @@ class LCodeGen;
|
||||
V(LoadFunctionPrototype) \
|
||||
V(LoadGlobalCell) \
|
||||
V(LoadGlobalGeneric) \
|
||||
V(LoadKeyedFastDoubleElement) \
|
||||
V(LoadKeyedFastElement) \
|
||||
V(LoadKeyed) \
|
||||
V(LoadKeyedGeneric) \
|
||||
V(LoadKeyedSpecializedArrayElement) \
|
||||
V(LoadNamedField) \
|
||||
V(LoadNamedFieldPolymorphic) \
|
||||
V(LoadNamedGeneric) \
|
||||
@ -157,10 +155,8 @@ class LCodeGen;
|
||||
V(StoreContextSlot) \
|
||||
V(StoreGlobalCell) \
|
||||
V(StoreGlobalGeneric) \
|
||||
V(StoreKeyedFastDoubleElement) \
|
||||
V(StoreKeyedFastElement) \
|
||||
V(StoreKeyed) \
|
||||
V(StoreKeyedGeneric) \
|
||||
V(StoreKeyedSpecializedArrayElement) \
|
||||
V(StoreNamedField) \
|
||||
V(StoreNamedGeneric) \
|
||||
V(StringAdd) \
|
||||
@ -1353,56 +1349,25 @@ class LLoadExternalArrayPointer: public LTemplateInstruction<1, 1, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
|
||||
class LLoadKeyed: public LTemplateInstruction<1, 2, 0> {
|
||||
public:
|
||||
LLoadKeyedFastElement(LOperand* elements, LOperand* key) {
|
||||
LLoadKeyed(LOperand* elements, LOperand* key) {
|
||||
inputs_[0] = elements;
|
||||
inputs_[1] = key;
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement, "load-keyed-fast-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastElement)
|
||||
DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
|
||||
DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
|
||||
|
||||
bool is_external() const {
|
||||
return hydrogen()->is_external();
|
||||
}
|
||||
LOperand* elements() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
};
|
||||
|
||||
|
||||
class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
|
||||
public:
|
||||
LLoadKeyedFastDoubleElement(LOperand* elements, LOperand* key) {
|
||||
inputs_[0] = elements;
|
||||
inputs_[1] = key;
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement,
|
||||
"load-keyed-fast-double-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastDoubleElement)
|
||||
|
||||
LOperand* elements() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
};
|
||||
|
||||
|
||||
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
|
||||
public:
|
||||
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LOperand* key) {
|
||||
inputs_[0] = external_pointer;
|
||||
inputs_[1] = key;
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement,
|
||||
"load-keyed-specialized-array-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedSpecializedArrayElement)
|
||||
|
||||
LOperand* external_pointer() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
ElementsKind elements_kind() const {
|
||||
return hydrogen()->elements_kind();
|
||||
}
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
};
|
||||
|
||||
|
||||
@ -1899,76 +1864,29 @@ class LStoreNamedGeneric: public LTemplateInstruction<0, 2, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
|
||||
class LStoreKeyed: public LTemplateInstruction<0, 3, 0> {
|
||||
public:
|
||||
LStoreKeyedFastElement(LOperand* object, LOperand* key, LOperand* value) {
|
||||
LStoreKeyed(LOperand* object, LOperand* key, LOperand* value) {
|
||||
inputs_[0] = object;
|
||||
inputs_[1] = key;
|
||||
inputs_[2] = value;
|
||||
}
|
||||
|
||||
LOperand* object() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
LOperand* value() { return inputs_[2]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement,
|
||||
"store-keyed-fast-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastElement)
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
};
|
||||
|
||||
|
||||
class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> {
|
||||
public:
|
||||
LStoreKeyedFastDoubleElement(LOperand* elements,
|
||||
LOperand* key,
|
||||
LOperand* value) {
|
||||
inputs_[0] = elements;
|
||||
inputs_[1] = key;
|
||||
inputs_[2] = value;
|
||||
}
|
||||
|
||||
bool is_external() const { return hydrogen()->is_external(); }
|
||||
LOperand* elements() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
LOperand* value() { return inputs_[2]; }
|
||||
ElementsKind elements_kind() const { return hydrogen()->elements_kind(); }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement,
|
||||
"store-keyed-fast-double-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastDoubleElement)
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed")
|
||||
DECLARE_HYDROGEN_ACCESSOR(StoreKeyed)
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
|
||||
bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
};
|
||||
|
||||
|
||||
class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
|
||||
public:
|
||||
LStoreKeyedSpecializedArrayElement(LOperand* external_pointer,
|
||||
LOperand* key,
|
||||
LOperand* value) {
|
||||
inputs_[0] = external_pointer;
|
||||
inputs_[1] = key;
|
||||
inputs_[2] = value;
|
||||
}
|
||||
|
||||
LOperand* external_pointer() { return inputs_[0]; }
|
||||
LOperand* key() { return inputs_[1]; }
|
||||
LOperand* value() { return inputs_[2]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement,
|
||||
"store-keyed-specialized-array-element")
|
||||
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedSpecializedArrayElement)
|
||||
|
||||
ElementsKind elements_kind() const { return hydrogen()->elements_kind(); }
|
||||
uint32_t additional_index() const { return hydrogen()->index_offset(); }
|
||||
};
|
||||
|
||||
|
||||
class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> {
|
||||
public:
|
||||
LStoreKeyedGeneric(LOperand* object, LOperand* key, LOperand* value) {
|
||||
|
Loading…
Reference in New Issue
Block a user