kExternalIntArray,
kExternalUnsignedIntArray,
kExternalFloatArray,
+ kExternalDoubleArray,
kExternalPixelArray
};
static const int kFullStringRepresentationMask = 0x07;
static const int kExternalTwoByteRepresentationTag = 0x02;
- static const int kJSObjectType = 0xa0;
+ static const int kJSObjectType = 0xa1;
static const int kFirstNonstringType = 0x80;
static const int kProxyType = 0x85;
v8::Handle<v8::Value> Int32Array(const v8::Arguments& args);
v8::Handle<v8::Value> Uint32Array(const v8::Arguments& args);
v8::Handle<v8::Value> Float32Array(const v8::Arguments& args);
+v8::Handle<v8::Value> Float64Array(const v8::Arguments& args);
v8::Handle<v8::Value> PixelArray(const v8::Arguments& args);
v8::Handle<v8::String> ReadFile(const char* name);
void ReportException(v8::TryCatch* handler);
v8::FunctionTemplate::New(Uint32Array));
global->Set(v8::String::New("Float32Array"),
v8::FunctionTemplate::New(Float32Array));
+ global->Set(v8::String::New("Float64Array"),
+ v8::FunctionTemplate::New(Float64Array));
global->Set(v8::String::New("PixelArray"),
v8::FunctionTemplate::New(PixelArray));
}
+v8::Handle<v8::Value> Float64Array(const v8::Arguments& args) {
+ return CreateExternalArray(args, v8::kExternalDoubleArray,
+ sizeof(double)); // NOLINT
+}
+
+
v8::Handle<v8::Value> PixelArray(const v8::Arguments& args) {
return CreateExternalArray(args, v8::kExternalPixelArray, sizeof(uint8_t));
}
return kExternalUnsignedIntArray;
case i::EXTERNAL_FLOAT_ARRAY_TYPE:
return kExternalFloatArray;
+ case i::EXTERNAL_DOUBLE_ARRAY_TYPE:
+ return kExternalDoubleArray;
case i::EXTERNAL_PIXEL_ARRAY_TYPE:
return kExternalPixelArray;
default:
struct Register {
static const int kNumRegisters = 16;
static const int kNumAllocatableRegisters = 8;
+ static const int kSizeInBytes = 4;
static int ToAllocationIndex(Register reg) {
ASSERT(reg.code() < kNumAllocatableRegisters);
}
-class FloatingPointHelper : public AllStatic {
- public:
-
- enum Destination {
- kVFPRegisters,
- kCoreRegisters
- };
-
-
- // Loads smis from r0 and r1 (right and left in binary operations) into
- // floating point registers. Depending on the destination the values ends up
- // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the destination is
- // floating point registers VFP3 must be supported. If core registers are
- // requested when VFP3 is supported d6 and d7 will be scratched.
- static void LoadSmis(MacroAssembler* masm,
- Destination destination,
- Register scratch1,
- Register scratch2);
-
- // Loads objects from r0 and r1 (right and left in binary operations) into
- // floating point registers. Depending on the destination the values ends up
- // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the destination is
- // floating point registers VFP3 must be supported. If core registers are
- // requested when VFP3 is supported d6 and d7 will still be scratched. If
- // either r0 or r1 is not a number (not smi and not heap number object) the
- // not_number label is jumped to with r0 and r1 intact.
- static void LoadOperands(MacroAssembler* masm,
- FloatingPointHelper::Destination destination,
- Register heap_number_map,
- Register scratch1,
- Register scratch2,
- Label* not_number);
-
- // Convert the smi or heap number in object to an int32 using the rules
- // for ToInt32 as described in ECMAScript 9.5.: the value is truncated
- // and brought into the range -2^31 .. +2^31 - 1.
- static void ConvertNumberToInt32(MacroAssembler* masm,
- Register object,
- Register dst,
- Register heap_number_map,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- DwVfpRegister double_scratch,
- Label* not_int32);
-
- // Load the number from object into double_dst in the double format.
- // Control will jump to not_int32 if the value cannot be exactly represented
- // by a 32-bit integer.
- // Floating point value in the 32-bit integer range that are not exact integer
- // won't be loaded.
- static void LoadNumberAsInt32Double(MacroAssembler* masm,
- Register object,
- Destination destination,
- DwVfpRegister double_dst,
- Register dst1,
- Register dst2,
- Register heap_number_map,
- Register scratch1,
- Register scratch2,
- SwVfpRegister single_scratch,
- Label* not_int32);
-
- // Loads the number from object into dst as a 32-bit integer.
- // Control will jump to not_int32 if the object cannot be exactly represented
- // by a 32-bit integer.
- // Floating point value in the 32-bit integer range that are not exact integer
- // won't be converted.
- // scratch3 is not used when VFP3 is supported.
- static void LoadNumberAsInt32(MacroAssembler* masm,
- Register object,
- Register dst,
- Register heap_number_map,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- DwVfpRegister double_scratch,
- Label* not_int32);
-
- // Generate non VFP3 code to check if a double can be exactly represented by a
- // 32-bit integer. This does not check for 0 or -0, which need
- // to be checked for separately.
- // Control jumps to not_int32 if the value is not a 32-bit integer, and falls
- // through otherwise.
- // src1 and src2 will be cloberred.
- //
- // Expected input:
- // - src1: higher (exponent) part of the double value.
- // - src2: lower (mantissa) part of the double value.
- // Output status:
- // - dst: 32 higher bits of the mantissa. (mantissa[51:20])
- // - src2: contains 1.
- // - other registers are clobbered.
- static void DoubleIs32BitInteger(MacroAssembler* masm,
- Register src1,
- Register src2,
- Register dst,
- Register scratch,
- Label* not_int32);
-
- // Generates code to call a C function to do a double operation using core
- // registers. (Used when VFP3 is not supported.)
- // This code never falls through, but returns with a heap number containing
- // the result in r0.
- // Register heapnumber_result must be a heap number in which the
- // result of the operation will be stored.
- // Requires the following layout on entry:
- // r0: Left value (least significant part of mantissa).
- // r1: Left value (sign, exponent, top of mantissa).
- // r2: Right value (least significant part of mantissa).
- // r3: Right value (sign, exponent, top of mantissa).
- static void CallCCodeForDoubleOperation(MacroAssembler* masm,
- Token::Value op,
- Register heap_number_result,
- Register scratch);
-
- private:
- static void LoadNumber(MacroAssembler* masm,
- FloatingPointHelper::Destination destination,
- Register object,
- DwVfpRegister dst,
- Register dst1,
- Register dst2,
- Register heap_number_map,
- Register scratch1,
- Register scratch2,
- Label* not_number);
-};
-
-
void FloatingPointHelper::LoadSmis(MacroAssembler* masm,
FloatingPointHelper::Destination destination,
Register scratch1,
}
-void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm,
- Register object,
- Destination destination,
- DwVfpRegister double_dst,
- Register dst1,
- Register dst2,
- Register heap_number_map,
- Register scratch1,
- Register scratch2,
- SwVfpRegister single_scratch,
- Label* not_int32) {
- ASSERT(!scratch1.is(object) && !scratch2.is(object));
- ASSERT(!scratch1.is(scratch2));
- ASSERT(!heap_number_map.is(object) &&
- !heap_number_map.is(scratch1) &&
- !heap_number_map.is(scratch2));
+void FloatingPointHelper::ConvertIntToDouble(MacroAssembler* masm,
+ Register int_scratch,
+ Destination destination,
+ DwVfpRegister double_dst,
+ Register dst1,
+ Register dst2,
+ Register scratch2,
+ SwVfpRegister single_scratch) {
+ ASSERT(!smi_scratch.is(scratch2));
- Label done, obj_is_not_smi;
+ Label done;
- __ JumpIfNotSmi(object, &obj_is_not_smi);
- __ SmiUntag(scratch1, object);
if (CpuFeatures::IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
- __ vmov(single_scratch, scratch1);
+ __ vmov(single_scratch, int_scratch);
__ vcvt_f64_s32(double_dst, single_scratch);
if (destination == kCoreRegisters) {
__ vmov(dst1, dst2, double_dst);
// | s | exp | mantissa |
// Check for zero.
- __ cmp(scratch1, Operand(0));
- __ mov(dst2, scratch1);
- __ mov(dst1, scratch1);
+ __ cmp(int_scratch, Operand(0));
+ __ mov(dst2, int_scratch);
+ __ mov(dst1, int_scratch);
__ b(eq, &done);
// Preload the sign of the value.
- __ and_(dst2, scratch1, Operand(HeapNumber::kSignMask), SetCC);
+ __ and_(dst2, int_scratch, Operand(HeapNumber::kSignMask), SetCC);
// Get the absolute value of the object (as an unsigned integer).
- __ rsb(scratch1, scratch1, Operand(0), SetCC, mi);
+ __ rsb(int_scratch, int_scratch, Operand(0), SetCC, mi);
// Get mantisssa[51:20].
// Get the position of the first set bit.
- __ CountLeadingZeros(dst1, scratch1, scratch2);
+ __ CountLeadingZeros(dst1, int_scratch, scratch2);
__ rsb(dst1, dst1, Operand(31));
// Set the exponent.
// Clear the first non null bit.
__ mov(scratch2, Operand(1));
- __ bic(scratch1, scratch1, Operand(scratch2, LSL, dst1));
+ __ bic(int_scratch, int_scratch, Operand(scratch2, LSL, dst1));
__ cmp(dst1, Operand(HeapNumber::kMantissaBitsInTopWord));
// Get the number of bits to set in the lower part of the mantissa.
__ sub(scratch2, dst1, Operand(HeapNumber::kMantissaBitsInTopWord), SetCC);
__ b(mi, &fewer_than_20_useful_bits);
// Set the higher 20 bits of the mantissa.
- __ orr(dst2, dst2, Operand(scratch1, LSR, scratch2));
+ __ orr(dst2, dst2, Operand(int_scratch, LSR, scratch2));
__ rsb(scratch2, scratch2, Operand(32));
- __ mov(dst1, Operand(scratch1, LSL, scratch2));
+ __ mov(dst1, Operand(int_scratch, LSL, scratch2));
__ b(&done);
__ bind(&fewer_than_20_useful_bits);
__ rsb(scratch2, dst1, Operand(HeapNumber::kMantissaBitsInTopWord));
- __ mov(scratch2, Operand(scratch1, LSL, scratch2));
+ __ mov(scratch2, Operand(int_scratch, LSL, scratch2));
__ orr(dst2, dst2, scratch2);
// Set dst1 to 0.
__ mov(dst1, Operand(0));
}
+ __ bind(&done);
+}
+
+void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm,
+ Register object,
+ Destination destination,
+ DwVfpRegister double_dst,
+ Register dst1,
+ Register dst2,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ SwVfpRegister single_scratch,
+ Label* not_int32) {
+ ASSERT(!scratch1.is(object) && !scratch2.is(object));
+ ASSERT(!scratch1.is(scratch2));
+ ASSERT(!heap_number_map.is(object) &&
+ !heap_number_map.is(scratch1) &&
+ !heap_number_map.is(scratch2));
+
+ Label done, obj_is_not_smi;
+
+ __ JumpIfNotSmi(object, &obj_is_not_smi);
+ __ SmiUntag(scratch1, object);
+ ConvertIntToDouble(masm, scratch1, destination, double_dst, dst1, dst2,
+ scratch2, single_scratch);
__ b(&done);
__ bind(&obj_is_not_smi);
};
+class FloatingPointHelper : public AllStatic {
+ public:
+
+ enum Destination {
+ kVFPRegisters,
+ kCoreRegisters
+ };
+
+
+ // Loads smis from r0 and r1 (right and left in binary operations) into
+ // floating point registers. Depending on the destination the values ends up
+ // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the destination is
+ // floating point registers VFP3 must be supported. If core registers are
+ // requested when VFP3 is supported d6 and d7 will be scratched.
+ static void LoadSmis(MacroAssembler* masm,
+ Destination destination,
+ Register scratch1,
+ Register scratch2);
+
+ // Loads objects from r0 and r1 (right and left in binary operations) into
+ // floating point registers. Depending on the destination the values ends up
+ // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the destination is
+ // floating point registers VFP3 must be supported. If core registers are
+ // requested when VFP3 is supported d6 and d7 will still be scratched. If
+ // either r0 or r1 is not a number (not smi and not heap number object) the
+ // not_number label is jumped to with r0 and r1 intact.
+ static void LoadOperands(MacroAssembler* masm,
+ FloatingPointHelper::Destination destination,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ Label* not_number);
+
+ // Convert the smi or heap number in object to an int32 using the rules
+ // for ToInt32 as described in ECMAScript 9.5.: the value is truncated
+ // and brought into the range -2^31 .. +2^31 - 1.
+ static void ConvertNumberToInt32(MacroAssembler* masm,
+ Register object,
+ Register dst,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ DwVfpRegister double_scratch,
+ Label* not_int32);
+
+ // Converts the integer (untagged smi) in |int_scratch| to a double, storing
+ // the result either in |double_dst| or |dst2:dst1|, depending on
+ // |destination|.
+ // Warning: The value in |int_scratch| will be changed in the process!
+ static void ConvertIntToDouble(MacroAssembler* masm,
+ Register int_scratch,
+ Destination destination,
+ DwVfpRegister double_dst,
+ Register dst1,
+ Register dst2,
+ Register scratch2,
+ SwVfpRegister single_scratch);
+
+ // Load the number from object into double_dst in the double format.
+ // Control will jump to not_int32 if the value cannot be exactly represented
+ // by a 32-bit integer.
+ // Floating point value in the 32-bit integer range that are not exact integer
+ // won't be loaded.
+ static void LoadNumberAsInt32Double(MacroAssembler* masm,
+ Register object,
+ Destination destination,
+ DwVfpRegister double_dst,
+ Register dst1,
+ Register dst2,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ SwVfpRegister single_scratch,
+ Label* not_int32);
+
+ // Loads the number from object into dst as a 32-bit integer.
+ // Control will jump to not_int32 if the object cannot be exactly represented
+ // by a 32-bit integer.
+ // Floating point value in the 32-bit integer range that are not exact integer
+ // won't be converted.
+ // scratch3 is not used when VFP3 is supported.
+ static void LoadNumberAsInt32(MacroAssembler* masm,
+ Register object,
+ Register dst,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ DwVfpRegister double_scratch,
+ Label* not_int32);
+
+ // Generate non VFP3 code to check if a double can be exactly represented by a
+ // 32-bit integer. This does not check for 0 or -0, which need
+ // to be checked for separately.
+ // Control jumps to not_int32 if the value is not a 32-bit integer, and falls
+ // through otherwise.
+ // src1 and src2 will be cloberred.
+ //
+ // Expected input:
+ // - src1: higher (exponent) part of the double value.
+ // - src2: lower (mantissa) part of the double value.
+ // Output status:
+ // - dst: 32 higher bits of the mantissa. (mantissa[51:20])
+ // - src2: contains 1.
+ // - other registers are clobbered.
+ static void DoubleIs32BitInteger(MacroAssembler* masm,
+ Register src1,
+ Register src2,
+ Register dst,
+ Register scratch,
+ Label* not_int32);
+
+ // Generates code to call a C function to do a double operation using core
+ // registers. (Used when VFP3 is not supported.)
+ // This code never falls through, but returns with a heap number containing
+ // the result in r0.
+ // Register heapnumber_result must be a heap number in which the
+ // result of the operation will be stored.
+ // Requires the following layout on entry:
+ // r0: Left value (least significant part of mantissa).
+ // r1: Left value (sign, exponent, top of mantissa).
+ // r2: Right value (least significant part of mantissa).
+ // r3: Right value (sign, exponent, top of mantissa).
+ static void CallCCodeForDoubleOperation(MacroAssembler* masm,
+ Token::Value op,
+ Register heap_number_result,
+ Register scratch);
+
+ private:
+ static void LoadNumber(MacroAssembler* masm,
+ FloatingPointHelper::Destination destination,
+ Register object,
+ DwVfpRegister dst,
+ Register dst1,
+ Register dst2,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ Label* not_number);
+};
+
+
} } // namespace v8::internal
#endif // V8_ARM_CODE_STUBS_ARM_H_
HLoadKeyedSpecializedArrayElement* instr) {
ExternalArrayType array_type = instr->array_type();
Representation representation(instr->representation());
- ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
- (representation.IsDouble() && array_type == kExternalFloatArray));
+ ASSERT(
+ (representation.IsInteger32() && (array_type != kExternalFloatArray &&
+ array_type != kExternalDoubleArray)) ||
+ (representation.IsDouble() && (array_type == kExternalFloatArray ||
+ array_type == kExternalDoubleArray)));
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegister(instr->key());
HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation());
ExternalArrayType array_type = instr->array_type();
- ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
- (representation.IsDouble() && array_type == kExternalFloatArray));
+ ASSERT(
+ (representation.IsInteger32() && (array_type != kExternalFloatArray &&
+ array_type != kExternalDoubleArray)) ||
+ (representation.IsDouble() && (array_type == kExternalFloatArray ||
+ array_type == kExternalDoubleArray)));
ASSERT(instr->external_pointer()->representation().IsExternal());
ASSERT(instr->key()->representation().IsInteger32());
__ add(scratch0(), external_pointer, Operand(key, LSL, 2));
__ vldr(result.low(), scratch0(), 0);
__ vcvt_f64_f32(result, result.low());
+ } else if (array_type == kExternalDoubleArray) {
+ CpuFeatures::Scope scope(VFP3);
+ DwVfpRegister result(ToDoubleRegister(instr->result()));
+ __ add(scratch0(), external_pointer, Operand(key, LSL, 3));
+ __ vldr(result, scratch0(), 0);
} else {
Register result(ToRegister(instr->result()));
switch (array_type) {
DeoptimizeIf(cs, instr->environment());
break;
case kExternalFloatArray:
+ case kExternalDoubleArray:
UNREACHABLE();
break;
}
Register external_pointer = ToRegister(instr->external_pointer());
Register key = ToRegister(instr->key());
ExternalArrayType array_type = instr->array_type();
+
if (array_type == kExternalFloatArray) {
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);
} else {
Register value(ToRegister(instr->value()));
switch (array_type) {
__ str(value, MemOperand(external_pointer, key, LSL, 2));
break;
case kExternalFloatArray:
+ case kExternalDoubleArray:
UNREACHABLE();
break;
}
__ ldr(value, MemOperand(r3, key, LSL, 1));
}
break;
+ case kExternalDoubleArray:
+ if (CpuFeatures::IsSupported(VFP3)) {
+ CpuFeatures::Scope scope(VFP3);
+ __ add(r2, r3, Operand(key, LSL, 2));
+ __ vldr(d0, r2, 0);
+ } else {
+ __ add(r4, r3, Operand(key, LSL, 2));
+ // r4: pointer to the beginning of the double we want to load.
+ __ ldr(r2, MemOperand(r4, 0));
+ __ ldr(r3, MemOperand(r4, Register::kSizeInBytes));
+ }
+ break;
default:
UNREACHABLE();
break;
// For integer array types:
// r2: value
- // For floating-point array type
+ // For float array type:
// s0: value (if VFP3 is supported)
// r2: value (if VFP3 is not supported)
+ // For double array type:
+ // d0: value (if VFP3 is supported)
+ // r2/r3: value (if VFP3 is not supported)
if (array_type == kExternalIntArray) {
// For the Int and UnsignedInt array types, we need to see whether
__ mov(r0, r3);
__ Ret();
}
+ } else if (array_type == kExternalDoubleArray) {
+ if (CpuFeatures::IsSupported(VFP3)) {
+ CpuFeatures::Scope scope(VFP3);
+ // Allocate a HeapNumber for the result. Don't use r0 and r1 as
+ // AllocateHeapNumber clobbers all registers - also when jumping due to
+ // exhausted young space.
+ __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
+ __ AllocateHeapNumber(r2, r3, r4, r6, &slow);
+ __ sub(r1, r2, Operand(kHeapObjectTag));
+ __ vstr(d0, r1, HeapNumber::kValueOffset);
+
+ __ mov(r0, r2);
+ __ Ret();
+ } else {
+ // Allocate a HeapNumber for the result. Don't use r0 and r1 as
+ // AllocateHeapNumber clobbers all registers - also when jumping due to
+ // exhausted young space.
+ __ LoadRoot(r7, Heap::kHeapNumberMapRootIndex);
+ __ AllocateHeapNumber(r4, r5, r6, r7, &slow);
+
+ __ str(r2, FieldMemOperand(r4, HeapNumber::kMantissaOffset));
+ __ str(r3, FieldMemOperand(r4, HeapNumber::kExponentOffset));
+ __ mov(r0, r4);
+ __ Ret();
+ }
} else {
// Tag integer as smi and return it.
// Perform int-to-float conversion and store to memory.
StoreIntAsFloat(masm(), r3, r4, r5, r6, r7, r9);
break;
+ case kExternalDoubleArray:
+ __ add(r3, r3, Operand(r4, LSL, 3));
+ // r3: effective address of the double element
+ FloatingPointHelper::Destination destination;
+ if (CpuFeatures::IsSupported(VFP3)) {
+ destination = FloatingPointHelper::kVFPRegisters;
+ } else {
+ destination = FloatingPointHelper::kCoreRegisters;
+ }
+ FloatingPointHelper::ConvertIntToDouble(
+ masm(), r5, destination,
+ d0, r6, r7, // These are: double_dst, dst1, dst2.
+ r4, s2); // These are: scratch2, single_scratch.
+ if (destination == FloatingPointHelper::kVFPRegisters) {
+ CpuFeatures::Scope scope(VFP3);
+ __ vstr(d0, r3, 0);
+ } else {
+ __ str(r6, MemOperand(r3, 0));
+ __ str(r7, MemOperand(r3, Register::kSizeInBytes));
+ }
+ break;
default:
UNREACHABLE();
break;
__ add(r5, r3, Operand(r4, LSL, 2));
__ vcvt_f32_f64(s0, d0);
__ vstr(s0, r5, 0);
+ } else if (array_type == kExternalDoubleArray) {
+ __ sub(r5, r0, Operand(kHeapObjectTag));
+ __ vldr(d0, r5, HeapNumber::kValueOffset);
+ __ add(r5, r3, Operand(r4, LSL, 3));
+ __ vstr(d0, r5, 0);
} else {
// Need to perform float-to-int conversion.
// Test for NaN or infinity (both give zero).
__ orr(r9, r9, Operand(r5, LSL, kMantissaInHiWordShift));
__ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift));
__ b(&done);
+ } else if (array_type == kExternalDoubleArray) {
+ __ add(r7, r3, Operand(r4, LSL, 3));
+ // r7: effective address of destination element.
+ __ str(r6, MemOperand(r7, 0));
+ __ str(r5, MemOperand(r7, Register::kSizeInBytes));
+ __ Ret();
} else {
bool is_signed_type = IsElementTypeSigned(array_type);
int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
}
set_external_float_array_map(Map::cast(obj));
+ { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_DOUBLE_ARRAY_TYPE,
+ ExternalArray::kAlignedSize);
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_external_double_array_map(Map::cast(obj));
+
{ MaybeObject* maybe_obj = AllocateMap(CODE_TYPE, kVariableSizeSentinel);
if (!maybe_obj->ToObject(&obj)) return false;
}
return kExternalUnsignedIntArrayMapRootIndex;
case kExternalFloatArray:
return kExternalFloatArrayMapRootIndex;
+ case kExternalDoubleArray:
+ return kExternalDoubleArrayMapRootIndex;
case kExternalPixelArray:
return kExternalPixelArrayMapRootIndex;
default:
V(Map, external_int_array_map, ExternalIntArrayMap) \
V(Map, external_unsigned_int_array_map, ExternalUnsignedIntArrayMap) \
V(Map, external_float_array_map, ExternalFloatArrayMap) \
+ V(Map, external_double_array_map, ExternalDoubleArrayMap) \
V(Map, context_map, ContextMap) \
V(Map, catch_context_map, CatchContextMap) \
V(Map, code_map, CodeMap) \
V(KeyedLoadExternalUnsignedIntArray_symbol, \
"KeyedLoadExternalUnsignedIntArray") \
V(KeyedLoadExternalFloatArray_symbol, "KeyedLoadExternalFloatArray") \
+ V(KeyedLoadExternalDoubleArray_symbol, "KeyedLoadExternalDoubleArray") \
V(KeyedLoadExternalPixelArray_symbol, "KeyedLoadExternalPixelArray") \
V(KeyedStoreExternalByteArray_symbol, "KeyedStoreExternalByteArray") \
V(KeyedStoreExternalUnsignedByteArray_symbol, \
V(KeyedStoreExternalUnsignedIntArray_symbol, \
"KeyedStoreExternalUnsignedIntArray") \
V(KeyedStoreExternalFloatArray_symbol, "KeyedStoreExternalFloatArray") \
+ V(KeyedStoreExternalDoubleArray_symbol, "KeyedStoreExternalDoubleArray") \
V(KeyedStoreExternalPixelArray_symbol, "KeyedStoreExternalPixelArray")
// Forward declarations.
case kExternalFloatArray:
stream->Add("float");
break;
+ case kExternalDoubleArray:
+ stream->Add("double");
+ break;
case kExternalPixelArray:
stream->Add("pixel");
break;
case kExternalFloatArray:
stream->Add("float");
break;
+ case kExternalDoubleArray:
+ stream->Add("double");
+ break;
case kExternalPixelArray:
stream->Add("pixel");
break;
ExternalArrayType array_type)
: HBinaryOperation(external_elements, key),
array_type_(array_type) {
- if (array_type == kExternalFloatArray) {
+ if (array_type == kExternalFloatArray ||
+ array_type == kExternalDoubleArray) {
set_representation(Representation::Double());
} else {
set_representation(Representation::Integer32());
if (index == 0) {
return Representation::External();
} else {
- if (index == 2 && array_type() == kExternalFloatArray) {
+ if (index == 2 && (array_type() == kExternalFloatArray ||
+ array_type() == kExternalDoubleArray)) {
return Representation::Double();
} else {
return Representation::Integer32();
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, Operand(external_pointer, key, times_4, 0));
__ cvtss2sd(result, result);
+ } else if (array_type == kExternalDoubleArray) {
+ __ movdbl(ToDoubleRegister(instr->result()),
+ Operand(external_pointer, key, times_8, 0));
} else {
Register result(ToRegister(instr->result()));
switch (array_type) {
DeoptimizeIf(negative, instr->environment());
break;
case kExternalFloatArray:
+ case kExternalDoubleArray:
UNREACHABLE();
break;
}
if (array_type == kExternalFloatArray) {
__ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
__ movss(Operand(external_pointer, key, times_4, 0), xmm0);
+ } else if (array_type == kExternalDoubleArray) {
+ __ movdbl(Operand(external_pointer, key, times_8, 0),
+ ToDoubleRegister(instr->value()));
} else {
Register value = ToRegister(instr->value());
switch (array_type) {
__ mov(Operand(external_pointer, key, times_4, 0), value);
break;
case kExternalFloatArray:
+ case kExternalDoubleArray:
UNREACHABLE();
break;
}
HLoadKeyedSpecializedArrayElement* instr) {
ExternalArrayType array_type = instr->array_type();
Representation representation(instr->representation());
- ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
- (representation.IsDouble() && array_type == kExternalFloatArray));
+ ASSERT(
+ (representation.IsInteger32() && (array_type != kExternalFloatArray &&
+ array_type != kExternalDoubleArray)) ||
+ (representation.IsDouble() && (array_type == kExternalFloatArray ||
+ array_type == kExternalDoubleArray)));
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegister(instr->key());
HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation());
ExternalArrayType array_type = instr->array_type();
- ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
- (representation.IsDouble() && array_type == kExternalFloatArray));
+ ASSERT(
+ (representation.IsInteger32() && (array_type != kExternalFloatArray &&
+ array_type != kExternalDoubleArray)) ||
+ (representation.IsDouble() && (array_type == kExternalFloatArray ||
+ array_type == kExternalDoubleArray)));
ASSERT(instr->external_pointer()->representation().IsExternal());
ASSERT(instr->key()->representation().IsInteger32());
case kExternalFloatArray:
__ fld_s(Operand(ebx, ecx, times_4, 0));
break;
+ case kExternalDoubleArray:
+ __ fld_d(Operand(ebx, ecx, times_8, 0));
+ break;
default:
UNREACHABLE();
break;
__ mov(eax, ecx);
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ ret(0);
- } else if (array_type == kExternalFloatArray) {
+ } else if (array_type == kExternalFloatArray ||
+ array_type == kExternalDoubleArray) {
// For the floating-point array type, we need to always allocate a
// HeapNumber.
__ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
__ mov(Operand(edi, ebx, times_4, 0), ecx);
break;
case kExternalFloatArray:
+ case kExternalDoubleArray:
// Need to perform int-to-float conversion.
__ push(ecx);
__ fild_s(Operand(esp, 0));
__ pop(ecx);
- __ fstp_s(Operand(edi, ebx, times_4, 0));
+ if (array_type == kExternalFloatArray) {
+ __ fstp_s(Operand(edi, ebx, times_4, 0));
+ } else { // array_type == kExternalDoubleArray.
+ __ fstp_d(Operand(edi, ebx, times_8, 0));
+ }
break;
default:
UNREACHABLE();
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ fstp_s(Operand(edi, ebx, times_4, 0));
__ ret(0);
+ } else if (array_type == kExternalDoubleArray) {
+ __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
+ __ fstp_d(Operand(edi, ebx, times_8, 0));
+ __ ret(0);
} else {
// Perform float-to-int conversion with truncation (round-to-zero)
// behavior.
case EXTERNAL_FLOAT_ARRAY_TYPE:
ExternalFloatArray::cast(this)->ExternalFloatArrayVerify();
break;
+ case EXTERNAL_DOUBLE_ARRAY_TYPE:
+ ExternalDoubleArray::cast(this)->ExternalDoubleArrayVerify();
+ break;
case CODE_TYPE:
Code::cast(this)->CodeVerify();
break;
}
+void ExternalDoubleArray::ExternalDoubleArrayVerify() {
+ ASSERT(IsExternalDoubleArray());
+}
+
+
void JSObject::JSObjectVerify() {
VerifyHeapPointer(properties());
VerifyHeapPointer(elements());
}
+bool Object::IsExternalDoubleArray() {
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map()->instance_type() ==
+ EXTERNAL_DOUBLE_ARRAY_TYPE;
+}
+
+
bool MaybeObject::IsFailure() {
return HAS_FAILURE_TAG(this);
}
CAST_ACCESSOR(ExternalIntArray)
CAST_ACCESSOR(ExternalUnsignedIntArray)
CAST_ACCESSOR(ExternalFloatArray)
+CAST_ACCESSOR(ExternalDoubleArray)
CAST_ACCESSOR(ExternalPixelArray)
CAST_ACCESSOR(Struct)
}
+double ExternalDoubleArray::get(int index) {
+ ASSERT((index >= 0) && (index < this->length()));
+ double* ptr = static_cast<double*>(external_pointer());
+ return ptr[index];
+}
+
+
+void ExternalDoubleArray::set(int index, double value) {
+ ASSERT((index >= 0) && (index < this->length()));
+ double* ptr = static_cast<double*>(external_pointer());
+ ptr[index] = value;
+}
+
+
int Map::visitor_id() {
return READ_BYTE_FIELD(this, kVisitorIdOffset);
}
return EXTERNAL_INT_ELEMENTS;
case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
return EXTERNAL_UNSIGNED_INT_ELEMENTS;
+ case EXTERNAL_FLOAT_ARRAY_TYPE:
+ return EXTERNAL_FLOAT_ELEMENTS;
+ case EXTERNAL_DOUBLE_ARRAY_TYPE:
+ return EXTERNAL_DOUBLE_ELEMENTS;
case EXTERNAL_PIXEL_ARRAY_TYPE:
return EXTERNAL_PIXEL_ELEMENTS;
default:
break;
}
}
- ASSERT(array->map()->instance_type() == EXTERNAL_FLOAT_ARRAY_TYPE);
- return EXTERNAL_FLOAT_ELEMENTS;
+ UNREACHABLE();
+ return DICTIONARY_ELEMENTS;
}
EXTERNAL_UNSIGNED_INT_ARRAY_TYPE)
EXTERNAL_ELEMENTS_CHECK(Float,
EXTERNAL_FLOAT_ARRAY_TYPE)
+EXTERNAL_ELEMENTS_CHECK(Double,
+ EXTERNAL_DOUBLE_ARRAY_TYPE)
EXTERNAL_ELEMENTS_CHECK(Pixel, EXTERNAL_PIXEL_ARRAY_TYPE)
case EXTERNAL_FLOAT_ARRAY_TYPE:
ExternalFloatArray::cast(this)->ExternalFloatArrayPrint(out);
break;
+ case EXTERNAL_DOUBLE_ARRAY_TYPE:
+ ExternalDoubleArray::cast(this)->ExternalDoubleArrayPrint(out);
+ break;
case FILLER_TYPE:
PrintF(out, "filler");
break;
}
+void ExternalDoubleArray::ExternalDoubleArrayPrint(FILE* out) {
+ PrintF(out, "external double array");
+}
+
+
void JSObject::PrintProperties(FILE* out) {
if (HasFastProperties()) {
DescriptorArray* descs = map()->instance_descriptors();
}
break;
}
+ case EXTERNAL_DOUBLE_ELEMENTS: {
+ ExternalDoubleArray* p = ExternalDoubleArray::cast(elements());
+ for (int i = 0; i < p->length(); i++) {
+ PrintF(out, " %d: %f\n", i, p->get(i));
+ }
+ break;
+ }
case DICTIONARY_ELEMENTS:
elements()->Print(out);
break;
case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
return "EXTERNAL_UNSIGNED_INT_ARRAY";
case EXTERNAL_FLOAT_ARRAY_TYPE: return "EXTERNAL_FLOAT_ARRAY";
+ case EXTERNAL_DOUBLE_ARRAY_TYPE: return "EXTERNAL_DOUBLE_ARRAY";
case FILLER_TYPE: return "FILLER";
case JS_OBJECT_TYPE: return "JS_OBJECT";
case JS_CONTEXT_EXTENSION_OBJECT_TYPE: return "JS_CONTEXT_EXTENSION_OBJECT";
case EXTERNAL_INT_ARRAY_TYPE:
case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
case EXTERNAL_FLOAT_ARRAY_TYPE:
+ case EXTERNAL_DOUBLE_ARRAY_TYPE:
return GetVisitorIdForSize(kVisitDataObject,
kVisitDataObjectGeneric,
instance_size);
accumulator->Add("<ExternalFloatArray[%u]>",
ExternalFloatArray::cast(this)->length());
break;
+ case EXTERNAL_DOUBLE_ARRAY_TYPE:
+ accumulator->Add("<ExternalDoubleArray[%u]>",
+ ExternalDoubleArray::cast(this)->length());
+ break;
case SHARED_FUNCTION_INFO_TYPE:
accumulator->Add("<SharedFunctionInfo>");
break;
case EXTERNAL_INT_ARRAY_TYPE:
case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
case EXTERNAL_FLOAT_ARRAY_TYPE:
+ case EXTERNAL_DOUBLE_ARRAY_TYPE:
break;
case SHARED_FUNCTION_INFO_TYPE:
SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
// Pixel and external array elements cannot be deleted. Just
// silently ignore here.
break;
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
// Raw pixels and external arrays do not reference other
// objects.
break;
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
// Ignore getters and setters on pixel and external array
// elements.
return heap->undefined_value();
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
// Ignore getters and setters on pixel and external array
// elements.
return isolate->heap()->undefined_value();
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS: {
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS: {
ExternalArray* array = ExternalArray::cast(elements());
if (index < static_cast<uint32_t>(array->length())) {
return true;
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS: {
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS: {
ExternalArray* array = ExternalArray::cast(elements());
if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
break;
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS: {
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS: {
ExternalArray* array = ExternalArray::cast(elements());
if (index < static_cast<uint32_t>(array->length())) {
return true;
ExternalFloatArray* array = ExternalFloatArray::cast(elements());
return array->SetValue(index, value);
}
+ case EXTERNAL_DOUBLE_ELEMENTS: {
+ ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
+ return array->SetValue(index, value);
+ }
case DICTIONARY_ELEMENTS: {
// Insert element in the dictionary.
FixedArray* elms = FixedArray::cast(elements());
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS: {
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS: {
MaybeObject* maybe_value = GetExternalElement(index);
Object* value;
if (!maybe_value->ToObject(&value)) return maybe_value;
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS: {
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS: {
MaybeObject* maybe_value = GetExternalElement(index);
Object* value;
if (!maybe_value->ToObject(&value)) return maybe_value;
}
break;
}
+ case EXTERNAL_DOUBLE_ELEMENTS: {
+ ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
+ if (index < static_cast<uint32_t>(array->length())) {
+ double value = array->get(index);
+ return GetHeap()->AllocateHeapNumber(value);
+ }
+ break;
+ }
case FAST_ELEMENTS:
case DICTIONARY_ELEMENTS:
UNREACHABLE();
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS: {
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS: {
return true;
}
case DICTIONARY_ELEMENTS: {
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS: {
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS: {
ExternalArray* array = ExternalArray::cast(elements());
return index < static_cast<uint32_t>(array->length());
}
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS: {
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS: {
int length = ExternalArray::cast(elements())->length();
while (counter < length) {
if (storage != NULL) {
}
+MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
+ double double_value = 0;
+ Heap* heap = GetHeap();
+ if (index < static_cast<uint32_t>(length())) {
+ if (value->IsSmi()) {
+ int int_value = Smi::cast(value)->value();
+ double_value = static_cast<double>(int_value);
+ } else if (value->IsHeapNumber()) {
+ double_value = HeapNumber::cast(value)->value();
+ } else {
+ // Clamp undefined to zero (default). All other types have been
+ // converted to a number type further up in the call chain.
+ ASSERT(value->IsUndefined());
+ }
+ set(index, double_value);
+ }
+ return heap->AllocateHeapNumber(double_value);
+}
+
+
JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
ASSERT(!HasFastProperties());
Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
EXTERNAL_INT_ARRAY_TYPE,
EXTERNAL_UNSIGNED_INT_ARRAY_TYPE,
EXTERNAL_FLOAT_ARRAY_TYPE,
+ EXTERNAL_DOUBLE_ARRAY_TYPE,
EXTERNAL_PIXEL_ARRAY_TYPE, // LAST_EXTERNAL_ARRAY_TYPE
FILLER_TYPE, // LAST_DATA_TYPE
V(ExternalIntArray) \
V(ExternalUnsignedIntArray) \
V(ExternalFloatArray) \
+ V(ExternalDoubleArray) \
V(ExternalPixelArray) \
V(ByteArray) \
V(JSObject) \
EXTERNAL_INT_ELEMENTS,
EXTERNAL_UNSIGNED_INT_ELEMENTS,
EXTERNAL_FLOAT_ELEMENTS,
+ EXTERNAL_DOUBLE_ELEMENTS,
EXTERNAL_PIXEL_ELEMENTS
};
inline bool HasExternalIntElements();
inline bool HasExternalUnsignedIntElements();
inline bool HasExternalFloatElements();
+ inline bool HasExternalDoubleElements();
inline bool AllowsSetElementsLength();
inline NumberDictionary* element_dictionary(); // Gets slow elements.
// Requires: this->HasFastElements().
};
+class ExternalDoubleArray: public ExternalArray {
+ public:
+ // Setter and getter.
+ inline double get(int index);
+ inline void set(int index, double value);
+
+ // This accessor applies the correct conversion from Smi, HeapNumber
+ // and undefined.
+ MaybeObject* SetValue(uint32_t index, Object* value);
+
+ // Casting.
+ static inline ExternalDoubleArray* cast(Object* obj);
+
+#ifdef OBJECT_PRINT
+ inline void ExternalDoubleArrayPrint() {
+ ExternalDoubleArrayPrint(stdout);
+ }
+ void ExternalDoubleArrayPrint(FILE* out);
+#endif // OBJECT_PRINT
+#ifdef DEBUG
+ void ExternalDoubleArrayVerify();
+#endif // DEBUG
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalDoubleArray);
+};
+
+
// DeoptimizationInputData is a fixed array used to hold the deoptimization
// data for code generated by the Hydrogen/Lithium compiler. It also
// contains information about functions that were inlined. If N different
int dense_elements_length;
switch (kind) {
case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
- dense_elements_length =
- ExternalPixelArray::cast(object->elements())->length();
+ dense_elements_length =
+ ExternalPixelArray::cast(object->elements())->length();
break;
}
case JSObject::EXTERNAL_BYTE_ELEMENTS: {
- dense_elements_length =
- ExternalByteArray::cast(object->elements())->length();
+ dense_elements_length =
+ ExternalByteArray::cast(object->elements())->length();
break;
}
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
- dense_elements_length =
- ExternalUnsignedByteArray::cast(object->elements())->length();
+ dense_elements_length =
+ ExternalUnsignedByteArray::cast(object->elements())->length();
break;
}
case JSObject::EXTERNAL_SHORT_ELEMENTS: {
- dense_elements_length =
- ExternalShortArray::cast(object->elements())->length();
+ dense_elements_length =
+ ExternalShortArray::cast(object->elements())->length();
break;
}
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
- dense_elements_length =
- ExternalUnsignedShortArray::cast(object->elements())->length();
+ dense_elements_length =
+ ExternalUnsignedShortArray::cast(object->elements())->length();
break;
}
case JSObject::EXTERNAL_INT_ELEMENTS: {
- dense_elements_length =
- ExternalIntArray::cast(object->elements())->length();
+ dense_elements_length =
+ ExternalIntArray::cast(object->elements())->length();
break;
}
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
- dense_elements_length =
- ExternalUnsignedIntArray::cast(object->elements())->length();
+ dense_elements_length =
+ ExternalUnsignedIntArray::cast(object->elements())->length();
break;
}
case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
- dense_elements_length =
- ExternalFloatArray::cast(object->elements())->length();
+ dense_elements_length =
+ ExternalFloatArray::cast(object->elements())->length();
+ break;
+ }
+ case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
+ dense_elements_length =
+ ExternalDoubleArray::cast(object->elements())->length();
break;
}
default:
isolate, receiver, false, false, visitor);
break;
}
+ case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
+ IterateExternalArrayElements<ExternalDoubleArray, double>(
+ isolate, receiver, false, false, visitor);
+ break;
+ }
default:
UNREACHABLE();
break;
return kExternalUnsignedIntArray;
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
return kExternalFloatArray;
+ case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ return kExternalDoubleArray;
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
return kExternalPixelArray;
default:
return heap->KeyedStoreExternalUnsignedIntArray_symbol();
case kExternalFloatArray:
return heap->KeyedStoreExternalFloatArray_symbol();
+ case kExternalDoubleArray:
+ return heap->KeyedStoreExternalDoubleArray_symbol();
case kExternalPixelArray:
return heap->KeyedStoreExternalPixelArray_symbol();
default:
return heap->KeyedLoadExternalUnsignedIntArray_symbol();
case kExternalFloatArray:
return heap->KeyedLoadExternalFloatArray_symbol();
+ case kExternalDoubleArray:
+ return heap->KeyedLoadExternalDoubleArray_symbol();
case kExternalPixelArray:
return heap->KeyedLoadExternalPixelArray_symbol();
default:
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, Operand(external_pointer, key, times_4, 0));
__ cvtss2sd(result, result);
+ } else if (array_type == kExternalDoubleArray) {
+ __ movsd(ToDoubleRegister(instr->result()),
+ Operand(external_pointer, key, times_8, 0));
} else {
Register result(ToRegister(instr->result()));
switch (array_type) {
DeoptimizeIf(negative, instr->environment());
break;
case kExternalFloatArray:
+ case kExternalDoubleArray:
UNREACHABLE();
break;
}
XMMRegister value(ToDoubleRegister(instr->value()));
__ cvtsd2ss(value, value);
__ movss(Operand(external_pointer, key, times_4, 0), value);
+ } else if (array_type == kExternalDoubleArray) {
+ __ movsd(Operand(external_pointer, key, times_8, 0),
+ ToDoubleRegister(instr->value()));
} else {
Register value(ToRegister(instr->value()));
switch (array_type) {
__ movl(Operand(external_pointer, key, times_4, 0), value);
break;
case kExternalFloatArray:
+ case kExternalDoubleArray:
UNREACHABLE();
break;
}
HLoadKeyedSpecializedArrayElement* instr) {
ExternalArrayType array_type = instr->array_type();
Representation representation(instr->representation());
- ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
- (representation.IsDouble() && array_type == kExternalFloatArray));
+ ASSERT(
+ (representation.IsInteger32() && (array_type != kExternalFloatArray &&
+ array_type != kExternalDoubleArray)) ||
+ (representation.IsDouble() && (array_type == kExternalFloatArray ||
+ array_type == kExternalDoubleArray)));
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegister(instr->key());
HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation());
ExternalArrayType array_type = instr->array_type();
- ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
- (representation.IsDouble() && array_type == kExternalFloatArray));
+ ASSERT(
+ (representation.IsInteger32() && (array_type != kExternalFloatArray &&
+ array_type != kExternalDoubleArray)) ||
+ (representation.IsDouble() && (array_type == kExternalFloatArray ||
+ array_type == kExternalDoubleArray)));
ASSERT(instr->external_pointer()->representation().IsExternal());
ASSERT(instr->key()->representation().IsInteger32());
case kExternalFloatArray:
__ cvtss2sd(xmm0, Operand(rbx, rcx, times_4, 0));
break;
+ case kExternalDoubleArray:
+ __ movsd(xmm0, Operand(rbx, rcx, times_8, 0));
+ break;
default:
UNREACHABLE();
break;
__ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
__ movq(rax, rcx);
__ ret(0);
- } else if (array_type == kExternalFloatArray) {
+ } else if (array_type == kExternalFloatArray ||
+ array_type == kExternalDoubleArray) {
// For the floating-point array type, we need to always allocate a
// HeapNumber.
__ AllocateHeapNumber(rcx, rbx, &slow);
__ cvtlsi2ss(xmm0, rdx);
__ movss(Operand(rbx, rdi, times_4, 0), xmm0);
break;
+ case kExternalDoubleArray:
+ // Need to perform int-to-float conversion.
+ __ cvtlsi2sd(xmm0, rdx);
+ __ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
+ break;
default:
UNREACHABLE();
break;
__ cvtsd2ss(xmm0, xmm0);
__ movss(Operand(rbx, rdi, times_4, 0), xmm0);
__ ret(0);
+ } else if (array_type == kExternalDoubleArray) {
+ __ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
+ __ ret(0);
} else {
// Perform float-to-int conversion with truncation (round-to-zero)
// behavior.
case v8::kExternalFloatArray:
return 4;
break;
+ case v8::kExternalDoubleArray:
+ return 8;
+ break;
default:
UNREACHABLE();
return -1;
CHECK_EQ(
2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
- if (array_type != v8::kExternalFloatArray) {
+ if (array_type != v8::kExternalFloatArray &&
+ array_type != v8::kExternalDoubleArray) {
// Though the specification doesn't state it, be explicit about
// converting NaNs and +/-Infinity to zero.
result = CompileRun("for (var i = 0; i < 8; i++) {"
}
+THREADED_TEST(ExternalDoubleArray) {
+ ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
+ v8::kExternalDoubleArray,
+ -500,
+ 500);
+}
+
+
THREADED_TEST(ExternalArrays) {
TestExternalByteArray();
TestExternalUnsignedByteArray();
ExternalArrayInfoTestHelper(v8::kExternalIntArray);
ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
+ ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
}
a = new Int16Array(2);
assertEquals(2, a.BYTES_PER_ELEMENT);
+// Test Float64Arrays.
+function get(a, index) {
+ return a[index];
+}
+function set(a, index, value) {
+ a[index] = value;
+}
+
+var array = new Float64Array(2);
+for (var i = 0; i < 5; i++) {
+ set(array, 0, 2.5);
+ assertEquals(2.5, array[0]);
+}
+%OptimizeFunctionOnNextCall(set);
+set(array, 0, 2.5);
+assertEquals(2.5, array[0]);
+set(array, 1, 3.5);
+assertEquals(3.5, array[1]);
+for (var i = 0; i < 5; i++) {
+ assertEquals(2.5, get(array, 0));
+ assertEquals(3.5, array[1]);
+}
+%OptimizeFunctionOnNextCall(get);
+assertEquals(2.5, get(array, 0));
+assertEquals(3.5, get(array, 1));