array_type == kExternalDoubleArray)));
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
- LOperand* key = UseRegister(instr->key());
+ LOperand* key = UseRegisterOrConstant(instr->key());
LLoadKeyedSpecializedArrayElement* result =
new LLoadKeyedSpecializedArrayElement(external_pointer, key);
LInstruction* load_instr = DefineAsRegister(result);
LOperand* val = val_is_temp_register
? UseTempRegister(instr->value())
: UseRegister(instr->value());
- LOperand* key = UseRegister(instr->key());
+ LOperand* key = UseRegisterOrConstant(instr->key());
return new LStoreKeyedSpecializedArrayElement(external_pointer,
key,
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
Register external_pointer = ToRegister(instr->external_pointer());
- Register key = ToRegister(instr->key());
+ Register key = no_reg;
ExternalArrayType array_type = instr->array_type();
- if (array_type == kExternalFloatArray) {
- CpuFeatures::Scope scope(VFP3);
- DwVfpRegister result(ToDoubleRegister(instr->result()));
- __ add(scratch0(), external_pointer, Operand(key, LSL, 2));
- __ vldr(result.low(), scratch0(), 0);
- __ vcvt_f64_f32(result, result.low());
- } else if (array_type == kExternalDoubleArray) {
+ 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 shift_size = ExternalArrayTypeToShiftSize(array_type);
+
+ if (array_type == kExternalFloatArray || array_type == kExternalDoubleArray) {
CpuFeatures::Scope scope(VFP3);
DwVfpRegister result(ToDoubleRegister(instr->result()));
- __ add(scratch0(), external_pointer, Operand(key, LSL, 3));
- __ vldr(result, scratch0(), 0);
+ Operand operand(key_is_constant ? Operand(constant_key * (1 << shift_size))
+ : Operand(key, LSL, shift_size));
+ __ add(scratch0(), external_pointer, operand);
+ if (array_type == kExternalFloatArray) {
+ __ vldr(result.low(), scratch0(), 0);
+ __ vcvt_f64_f32(result, result.low());
+ } else { // i.e. array_type == kExternalDoubleArray
+ __ vldr(result, scratch0(), 0);
+ }
} else {
Register result(ToRegister(instr->result()));
+ MemOperand mem_operand(key_is_constant
+ ? MemOperand(external_pointer, constant_key * (1 << shift_size))
+ : MemOperand(external_pointer, key, LSL, shift_size));
switch (array_type) {
case kExternalByteArray:
- __ ldrsb(result, MemOperand(external_pointer, key));
+ __ ldrsb(result, mem_operand);
break;
case kExternalUnsignedByteArray:
case kExternalPixelArray:
- __ ldrb(result, MemOperand(external_pointer, key));
+ __ ldrb(result, mem_operand);
break;
case kExternalShortArray:
- __ ldrsh(result, MemOperand(external_pointer, key, LSL, 1));
+ __ ldrsh(result, mem_operand);
break;
case kExternalUnsignedShortArray:
- __ ldrh(result, MemOperand(external_pointer, key, LSL, 1));
+ __ ldrh(result, mem_operand);
break;
case kExternalIntArray:
- __ ldr(result, MemOperand(external_pointer, key, LSL, 2));
+ __ ldr(result, mem_operand);
break;
case kExternalUnsignedIntArray:
- __ ldr(result, MemOperand(external_pointer, key, LSL, 2));
+ __ ldr(result, mem_operand);
__ cmp(result, Operand(0x80000000));
// TODO(danno): we could be more clever here, perhaps having a special
// version of the stub that detects if the overflow case actually
LStoreKeyedSpecializedArrayElement* instr) {
Register external_pointer = ToRegister(instr->external_pointer());
- Register key = ToRegister(instr->key());
+ Register key = no_reg;
ExternalArrayType array_type = instr->array_type();
+ 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 shift_size = ExternalArrayTypeToShiftSize(array_type);
- if (array_type == kExternalFloatArray) {
+ if (array_type == kExternalFloatArray || array_type == kExternalDoubleArray) {
CpuFeatures::Scope scope(VFP3);
DwVfpRegister value(ToDoubleRegister(instr->value()));
- __ add(scratch0(), external_pointer, Operand(key, LSL, 2));
- __ vcvt_f32_f64(double_scratch0().low(), value);
- __ vstr(double_scratch0().low(), scratch0(), 0);
- } else if (array_type == kExternalDoubleArray) {
- CpuFeatures::Scope scope(VFP3);
- DwVfpRegister value(ToDoubleRegister(instr->value()));
- __ add(scratch0(), external_pointer, Operand(key, LSL, 3));
- __ vstr(value, scratch0(), 0);
+ Operand operand(key_is_constant ? Operand(constant_key * (1 << shift_size))
+ : Operand(key, LSL, shift_size));
+ __ add(scratch0(), external_pointer, operand);
+ if (array_type == kExternalFloatArray) {
+ __ vcvt_f32_f64(double_scratch0().low(), value);
+ __ vstr(double_scratch0().low(), scratch0(), 0);
+ } else { // i.e. array_type == kExternalDoubleArray
+ __ vstr(value, scratch0(), 0);
+ }
} else {
Register value(ToRegister(instr->value()));
+ MemOperand mem_operand(key_is_constant
+ ? MemOperand(external_pointer, constant_key * (1 << shift_size))
+ : MemOperand(external_pointer, key, LSL, shift_size));
switch (array_type) {
case kExternalPixelArray:
// Clamp the value to [0..255].
__ Usat(value, 8, Operand(value));
- __ strb(value, MemOperand(external_pointer, key));
- break;
+ // Fall through to the next case for the store instruction:
case kExternalByteArray:
case kExternalUnsignedByteArray:
- __ strb(value, MemOperand(external_pointer, key));
+ __ strb(value, mem_operand);
break;
case kExternalShortArray:
case kExternalUnsignedShortArray:
- __ strh(value, MemOperand(external_pointer, key, LSL, 1));
+ __ strh(value, mem_operand);
break;
case kExternalIntArray:
case kExternalUnsignedIntArray:
- __ str(value, MemOperand(external_pointer, key, LSL, 2));
+ __ str(value, mem_operand);
break;
case kExternalFloatArray:
case kExternalDoubleArray:
}
+Operand LCodeGen::BuildExternalArrayOperand(LOperand* external_pointer,
+ LOperand* key,
+ ExternalArrayType array_type) {
+ Register external_pointer_reg = ToRegister(external_pointer);
+ int shift_size = ExternalArrayTypeToShiftSize(array_type);
+ if (key->IsConstantOperand()) {
+ int constant_value = ToInteger32(LConstantOperand::cast(key));
+ if (constant_value & 0xF0000000) {
+ Abort("array index constant value too big");
+ }
+ return Operand(external_pointer_reg, constant_value * (1 << shift_size));
+ } else {
+ ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
+ return Operand(external_pointer_reg, ToRegister(key), scale_factor, 0);
+ }
+}
+
+
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
- Register external_pointer = ToRegister(instr->external_pointer());
- Register key = ToRegister(instr->key());
ExternalArrayType array_type = instr->array_type();
+ Operand operand(BuildExternalArrayOperand(instr->external_pointer(),
+ instr->key(), array_type));
if (array_type == kExternalFloatArray) {
XMMRegister result(ToDoubleRegister(instr->result()));
- __ movss(result, Operand(external_pointer, key, times_4, 0));
+ __ movss(result, operand);
__ cvtss2sd(result, result);
} else if (array_type == kExternalDoubleArray) {
- __ movdbl(ToDoubleRegister(instr->result()),
- Operand(external_pointer, key, times_8, 0));
+ __ movdbl(ToDoubleRegister(instr->result()), operand);
} else {
Register result(ToRegister(instr->result()));
switch (array_type) {
case kExternalByteArray:
- __ movsx_b(result, Operand(external_pointer, key, times_1, 0));
+ __ movsx_b(result, operand);
break;
case kExternalUnsignedByteArray:
case kExternalPixelArray:
- __ movzx_b(result, Operand(external_pointer, key, times_1, 0));
+ __ movzx_b(result, operand);
break;
case kExternalShortArray:
- __ movsx_w(result, Operand(external_pointer, key, times_2, 0));
+ __ movsx_w(result, operand);
break;
case kExternalUnsignedShortArray:
- __ movzx_w(result, Operand(external_pointer, key, times_2, 0));
+ __ movzx_w(result, operand);
break;
case kExternalIntArray:
- __ mov(result, Operand(external_pointer, key, times_4, 0));
+ __ mov(result, operand);
break;
case kExternalUnsignedIntArray:
- __ mov(result, Operand(external_pointer, key, times_4, 0));
+ __ mov(result, operand);
__ test(result, Operand(result));
// TODO(danno): we could be more clever here, perhaps having a special
// version of the stub that detects if the overflow case actually
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
- Register external_pointer = ToRegister(instr->external_pointer());
- Register key = ToRegister(instr->key());
ExternalArrayType array_type = instr->array_type();
+ Operand operand(BuildExternalArrayOperand(instr->external_pointer(),
+ instr->key(), array_type));
if (array_type == kExternalFloatArray) {
__ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
- __ movss(Operand(external_pointer, key, times_4, 0), xmm0);
+ __ movss(operand, xmm0);
} else if (array_type == kExternalDoubleArray) {
- __ movdbl(Operand(external_pointer, key, times_8, 0),
- ToDoubleRegister(instr->value()));
+ __ movdbl(operand, ToDoubleRegister(instr->value()));
} else {
Register value = ToRegister(instr->value());
switch (array_type) {
__ setcc(negative, temp); // 1 if negative, 0 if positive.
__ dec_b(temp); // 0 if negative, 255 if positive.
__ bind(&done);
- __ mov_b(Operand(external_pointer, key, times_1, 0), temp);
+ __ mov_b(operand, temp);
break;
}
case kExternalByteArray:
case kExternalUnsignedByteArray:
- __ mov_b(Operand(external_pointer, key, times_1, 0), value);
+ __ mov_b(operand, value);
break;
case kExternalShortArray:
case kExternalUnsignedShortArray:
- __ mov_w(Operand(external_pointer, key, times_2, 0), value);
+ __ mov_w(operand, value);
break;
case kExternalIntArray:
case kExternalUnsignedIntArray:
- __ mov(Operand(external_pointer, key, times_4, 0), value);
+ __ mov(operand, value);
break;
case kExternalFloatArray:
case kExternalDoubleArray:
Register ToRegister(int index) const;
XMMRegister ToDoubleRegister(int index) const;
int ToInteger32(LConstantOperand* op) const;
+ Operand BuildExternalArrayOperand(LOperand* external_pointer,
+ LOperand* key,
+ ExternalArrayType array_type);
// Specific math operations - used from DoUnaryMathOperation.
void EmitIntegerMathAbs(LUnaryMathOperation* instr);
array_type == kExternalDoubleArray)));
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
- LOperand* key = UseRegister(instr->key());
+ LOperand* key = UseRegisterOrConstant(instr->key());
LLoadKeyedSpecializedArrayElement* result =
new LLoadKeyedSpecializedArrayElement(external_pointer,
key);
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
- LOperand* key = UseRegister(instr->key());
+ LOperand* key = UseRegisterOrConstant(instr->key());
LOperand* temp = NULL;
if (array_type == kExternalPixelArray) {
}
+int ExternalArrayTypeToShiftSize(ExternalArrayType type) {
+ switch (type) {
+ case kExternalByteArray:
+ case kExternalUnsignedByteArray:
+ case kExternalPixelArray:
+ return 0;
+ case kExternalShortArray:
+ case kExternalUnsignedShortArray:
+ return 1;
+ case kExternalIntArray:
+ case kExternalUnsignedIntArray:
+ case kExternalFloatArray:
+ return 2;
+ case kExternalDoubleArray:
+ return 3;
+ }
+ UNREACHABLE();
+ return 0;
+}
+
+
} } // namespace v8::internal
ShallowIterator current_iterator_;
};
+
+int ExternalArrayTypeToShiftSize(ExternalArrayType type);
+
+
} } // namespace v8::internal
#endif // V8_LITHIUM_H_
}
+Operand LCodeGen::BuildExternalArrayOperand(LOperand* external_pointer,
+ LOperand* key,
+ ExternalArrayType array_type) {
+ Register external_pointer_reg = ToRegister(external_pointer);
+ int shift_size = ExternalArrayTypeToShiftSize(array_type);
+ if (key->IsConstantOperand()) {
+ int constant_value = ToInteger32(LConstantOperand::cast(key));
+ if (constant_value & 0xF0000000) {
+ Abort("array index constant value too big");
+ }
+ return Operand(external_pointer_reg, constant_value * (1 << shift_size));
+ } else {
+ ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
+ return Operand(external_pointer_reg, ToRegister(key), scale_factor, 0);
+ }
+}
+
+
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
- Register external_pointer = ToRegister(instr->external_pointer());
- Register key = ToRegister(instr->key());
ExternalArrayType array_type = instr->array_type();
+ Operand operand(BuildExternalArrayOperand(instr->external_pointer(),
+ instr->key(), array_type));
if (array_type == kExternalFloatArray) {
XMMRegister result(ToDoubleRegister(instr->result()));
- __ movss(result, Operand(external_pointer, key, times_4, 0));
+ __ movss(result, operand);
__ cvtss2sd(result, result);
} else if (array_type == kExternalDoubleArray) {
- __ movsd(ToDoubleRegister(instr->result()),
- Operand(external_pointer, key, times_8, 0));
+ __ movsd(ToDoubleRegister(instr->result()), operand);
} else {
Register result(ToRegister(instr->result()));
switch (array_type) {
case kExternalByteArray:
- __ movsxbq(result, Operand(external_pointer, key, times_1, 0));
+ __ movsxbq(result, operand);
break;
case kExternalUnsignedByteArray:
case kExternalPixelArray:
- __ movzxbq(result, Operand(external_pointer, key, times_1, 0));
+ __ movzxbq(result, operand);
break;
case kExternalShortArray:
- __ movsxwq(result, Operand(external_pointer, key, times_2, 0));
+ __ movsxwq(result, operand);
break;
case kExternalUnsignedShortArray:
- __ movzxwq(result, Operand(external_pointer, key, times_2, 0));
+ __ movzxwq(result, operand);
break;
case kExternalIntArray:
- __ movsxlq(result, Operand(external_pointer, key, times_4, 0));
+ __ movsxlq(result, operand);
break;
case kExternalUnsignedIntArray:
- __ movl(result, Operand(external_pointer, key, times_4, 0));
+ __ movl(result, operand);
__ testl(result, result);
// TODO(danno): we could be more clever here, perhaps having a special
// version of the stub that detects if the overflow case actually
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
- Register external_pointer = ToRegister(instr->external_pointer());
- Register key = ToRegister(instr->key());
ExternalArrayType array_type = instr->array_type();
+ Operand operand(BuildExternalArrayOperand(instr->external_pointer(),
+ instr->key(), array_type));
if (array_type == kExternalFloatArray) {
XMMRegister value(ToDoubleRegister(instr->value()));
__ cvtsd2ss(value, value);
- __ movss(Operand(external_pointer, key, times_4, 0), value);
+ __ movss(operand, value);
} else if (array_type == kExternalDoubleArray) {
- __ movsd(Operand(external_pointer, key, times_8, 0),
- ToDoubleRegister(instr->value()));
+ __ movsd(operand, ToDoubleRegister(instr->value()));
} else {
Register value(ToRegister(instr->value()));
switch (array_type) {
__ setcc(negative, value); // 1 if negative, 0 if positive.
__ decb(value); // 0 if negative, 255 if positive.
__ bind(&done);
- __ movb(Operand(external_pointer, key, times_1, 0), value);
+ __ movb(operand, value);
}
break;
case kExternalByteArray:
case kExternalUnsignedByteArray:
- __ movb(Operand(external_pointer, key, times_1, 0), value);
+ __ movb(operand, value);
break;
case kExternalShortArray:
case kExternalUnsignedShortArray:
- __ movw(Operand(external_pointer, key, times_2, 0), value);
+ __ movw(operand, value);
break;
case kExternalIntArray:
case kExternalUnsignedIntArray:
- __ movl(Operand(external_pointer, key, times_4, 0), value);
+ __ movl(operand, value);
break;
case kExternalFloatArray:
case kExternalDoubleArray:
Register ToRegister(int index) const;
XMMRegister ToDoubleRegister(int index) const;
+ Operand BuildExternalArrayOperand(LOperand* external_pointer,
+ LOperand* key,
+ ExternalArrayType array_type);
// Specific math operations - used from DoUnaryMathOperation.
void EmitIntegerMathAbs(LUnaryMathOperation* instr);
array_type == kExternalDoubleArray)));
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
- LOperand* key = UseRegister(instr->key());
+ LOperand* key = UseRegisterOrConstant(instr->key());
LLoadKeyedSpecializedArrayElement* result =
new LLoadKeyedSpecializedArrayElement(external_pointer, key);
LInstruction* load_instr = DefineAsRegister(result);
LOperand* val = val_is_temp_register
? UseTempRegister(instr->value())
: UseRegister(instr->value());
- LOperand* key = UseRegister(instr->key());
+ LOperand* key = UseRegisterOrConstant(instr->key());
return new LStoreKeyedSpecializedArrayElement(external_pointer,
key,
CHECK_EQ(true, result->BooleanValue());
}
- // Test crankshaft external array loads
- for (int i = 0; i < kElementCount; i++) {
- array->set(i, static_cast<ElementType>(i));
- }
- result = CompileRun("function ee_load_test_func(sum) {"
- " for (var i = 0; i < 40; ++i)"
- " sum += ext_array[i];"
- " return sum;"
- "}"
- "sum=0;"
- "for (var i=0;i<10000;++i) {"
- " sum=ee_load_test_func(sum);"
- "}"
- "sum;");
- CHECK_EQ(7800000, result->Int32Value());
-
- // Test crankshaft external array stores
- result = CompileRun("function ee_store_test_func(sum) {"
- " for (var i = 0; i < 40; ++i)"
- " sum += ext_array[i] = i;"
- " return sum;"
- "}"
- "sum=0;"
- "for (var i=0;i<10000;++i) {"
- " sum=ee_store_test_func(sum);"
- "}"
- "sum;");
- CHECK_EQ(7800000, result->Int32Value());
-
for (int i = 0; i < kElementCount; i++) {
array->set(i, static_cast<ElementType>(i));
}
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --allow-natives-syntax
+// Flags: --allow-natives-syntax --expose-gc
// This is a regression test for overlapping key and value registers.
function f(a) {
assertEquals(0, a[0]);
assertEquals(0, a[1]);
-// Test the correct behavior of the |length| property (which is read-only).
-a = new Int32Array(42);
-assertEquals(42, a.length);
-a.length = 2;
-assertEquals(42, a.length);
-assertTrue(delete a.length);
-a.length = 2
-assertEquals(2, a.length);
-
// Test the correct behavior of the |BYTES_PER_ELEMENT| property (which is
// "constant", but not read-only).
a = new Int32Array(2);
%OptimizeFunctionOnNextCall(get);
assertEquals(2.5, get(array, 0));
assertEquals(3.5, get(array, 1));
+
+// Test loads and stores.
+types = [Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array,
+ Uint32Array, PixelArray, Float32Array, Float64Array];
+
+const kElementCount = 40;
+
+function test_load(array, sum) {
+ for (var i = 0; i < kElementCount; i++) {
+ sum += array[i];
+ }
+ return sum;
+}
+
+function test_load_const_key(array, sum) {
+ sum += array[0];
+ sum += array[1];
+ sum += array[2];
+ return sum;
+}
+
+function test_store(array, sum) {
+ for (var i = 0; i < kElementCount; i++) {
+ sum += array[i] = i+1;
+ }
+ return sum;
+}
+
+function test_store_const_key(array, sum) {
+ sum += array[0] = 1;
+ sum += array[1] = 2;
+ sum += array[2] = 3;
+ return sum;
+}
+
+function run_test(test_func, array, expected_sum_per_run) {
+ for (var i = 0; i < 5; i++) test_func(array, 0);
+ %OptimizeFunctionOnNextCall(test_func);
+ const kRuns = 10;
+ var sum = 0;
+ for (var i = 0; i < kRuns; i++) {
+ sum = test_func(array, sum);
+ }
+ assertEquals(sum, expected_sum_per_run * kRuns);
+ %DeoptimizeFunction(test_func);
+ gc(); // Makes V8 forget about type information for test_func.
+}
+
+for (var t = 0; t < types.length; t++) {
+ var type = types[t];
+ var a = new type(kElementCount);
+ for (var i = 0; i < kElementCount; i++) {
+ a[i] = i;
+ }
+
+ // Run test functions defined above.
+ run_test(test_load, a, 780);
+ run_test(test_load_const_key, a, 3);
+ run_test(test_store, a, 820);
+ run_test(test_store_const_key, a, 6);
+
+ // Test the correct behavior of the |length| property (which is read-only).
+ assertEquals(kElementCount, a.length);
+ a.length = 2;
+ assertEquals(kElementCount, a.length);
+ assertTrue(delete a.length);
+ a.length = 2
+ assertEquals(2, a.length);
+}