Index: src/arm/lithium-codegen-arm.cc |
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc |
index 6f5aa436a85b49913e437b78ffdc31c8d2c0c07a..53a07c94ff3065c2012e1f9e8699a13efc130333 100644 |
--- a/src/arm/lithium-codegen-arm.cc |
+++ b/src/arm/lithium-codegen-arm.cc |
@@ -2918,50 +2918,87 @@ 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)); |
+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(); |
+ 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."); |
} |
- offset = FixedArray::OffsetOfElementAt(instr->additional_index()); |
+ } else { |
+ key = ToRegister(instr->key()); |
} |
- __ ldr(result, FieldMemOperand(store_base, offset)); |
+ int element_size_shift = ElementsKindToShiftSize(elements_kind); |
+ int shift_size = (instr->hydrogen()->key()->representation().IsTagged()) |
+ ? (element_size_shift - kSmiTagSize) : element_size_shift; |
+ int additional_offset = instr->additional_index() << element_size_shift; |
- // 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()); |
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || |
+ elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { |
+ CpuFeatures::Scope scope(VFP3); |
+ DwVfpRegister result = ToDoubleRegister(instr->result()); |
+ Operand operand = key_is_constant |
+ ? Operand(constant_key << element_size_shift) |
+ : Operand(key, LSL, shift_size); |
+ __ add(scratch0(), external_pointer, operand); |
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { |
+ __ vldr(result.low(), scratch0(), additional_offset); |
+ __ vcvt_f64_f32(result, result.low()); |
+ } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS |
+ __ vldr(result, scratch0(), additional_offset); |
+ } |
+ } else { |
+ Register result = ToRegister(instr->result()); |
+ MemOperand mem_operand = PrepareKeyedOperand( |
+ key, external_pointer, key_is_constant, constant_key, |
+ element_size_shift, shift_size, |
+ instr->additional_index(), additional_offset); |
+ switch (elements_kind) { |
+ case EXTERNAL_BYTE_ELEMENTS: |
+ __ ldrsb(result, mem_operand); |
+ break; |
+ case EXTERNAL_PIXEL_ELEMENTS: |
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
+ __ ldrb(result, mem_operand); |
+ break; |
+ case EXTERNAL_SHORT_ELEMENTS: |
+ __ ldrsh(result, mem_operand); |
+ break; |
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
+ __ ldrh(result, mem_operand); |
+ break; |
+ case EXTERNAL_INT_ELEMENTS: |
+ __ ldr(result, mem_operand); |
+ break; |
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
+ __ ldr(result, mem_operand); |
+ if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { |
+ __ cmp(result, Operand(0x80000000)); |
+ DeoptimizeIf(cs, instr->environment()); |
+ } |
+ break; |
+ case EXTERNAL_FLOAT_ELEMENTS: |
+ case EXTERNAL_DOUBLE_ELEMENTS: |
+ case FAST_HOLEY_DOUBLE_ELEMENTS: |
+ case FAST_HOLEY_ELEMENTS: |
+ case FAST_HOLEY_SMI_ELEMENTS: |
+ case FAST_DOUBLE_ELEMENTS: |
+ case FAST_ELEMENTS: |
+ case FAST_SMI_ELEMENTS: |
+ case DICTIONARY_ELEMENTS: |
+ case NON_STRICT_ARGUMENTS_ELEMENTS: |
+ UNREACHABLE(); |
+ break; |
} |
} |
} |
-void LCodeGen::DoLoadKeyedFastDoubleElement( |
- LLoadKeyedFastDoubleElement* instr) { |
+void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { |
Register elements = ToRegister(instr->elements()); |
bool key_is_constant = instr->key()->IsConstantOperand(); |
Register key = no_reg; |
@@ -3003,6 +3040,59 @@ void LCodeGen::DoLoadKeyedFastDoubleElement( |
} |
+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, |
@@ -3039,87 +3129,6 @@ MemOperand LCodeGen::PrepareKeyedOperand(Register key, |
} |
-void LCodeGen::DoLoadKeyedSpecializedArrayElement( |
- LLoadKeyedSpecializedArrayElement* instr) { |
- Register external_pointer = ToRegister(instr->external_pointer()); |
- Register key = no_reg; |
- ElementsKind elements_kind = instr->elements_kind(); |
- bool key_is_constant = instr->key()->IsConstantOperand(); |
- 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()); |
- } |
- int element_size_shift = ElementsKindToShiftSize(elements_kind); |
- int shift_size = (instr->hydrogen()->key()->representation().IsTagged()) |
- ? (element_size_shift - kSmiTagSize) : element_size_shift; |
- int additional_offset = instr->additional_index() << element_size_shift; |
- |
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || |
- elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { |
- CpuFeatures::Scope scope(VFP3); |
- DwVfpRegister result = ToDoubleRegister(instr->result()); |
- Operand operand = key_is_constant |
- ? Operand(constant_key << element_size_shift) |
- : Operand(key, LSL, shift_size); |
- __ add(scratch0(), external_pointer, operand); |
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { |
- __ vldr(result.low(), scratch0(), additional_offset); |
- __ vcvt_f64_f32(result, result.low()); |
- } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS |
- __ vldr(result, scratch0(), additional_offset); |
- } |
- } else { |
- Register result = ToRegister(instr->result()); |
- MemOperand mem_operand = PrepareKeyedOperand( |
- key, external_pointer, key_is_constant, constant_key, |
- element_size_shift, shift_size, |
- instr->additional_index(), additional_offset); |
- switch (elements_kind) { |
- case EXTERNAL_BYTE_ELEMENTS: |
- __ ldrsb(result, mem_operand); |
- break; |
- case EXTERNAL_PIXEL_ELEMENTS: |
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
- __ ldrb(result, mem_operand); |
- break; |
- case EXTERNAL_SHORT_ELEMENTS: |
- __ ldrsh(result, mem_operand); |
- break; |
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
- __ ldrh(result, mem_operand); |
- break; |
- case EXTERNAL_INT_ELEMENTS: |
- __ ldr(result, mem_operand); |
- break; |
- case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
- __ ldr(result, mem_operand); |
- if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { |
- __ cmp(result, Operand(0x80000000)); |
- DeoptimizeIf(cs, instr->environment()); |
- } |
- break; |
- case EXTERNAL_FLOAT_ELEMENTS: |
- case EXTERNAL_DOUBLE_ELEMENTS: |
- case FAST_HOLEY_DOUBLE_ELEMENTS: |
- case FAST_HOLEY_ELEMENTS: |
- case FAST_HOLEY_SMI_ELEMENTS: |
- case FAST_DOUBLE_ELEMENTS: |
- case FAST_ELEMENTS: |
- case FAST_SMI_ELEMENTS: |
- case DICTIONARY_ELEMENTS: |
- case NON_STRICT_ARGUMENTS_ELEMENTS: |
- UNREACHABLE(); |
- break; |
- } |
- } |
-} |
- |
- |
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)); |