Version 3.3.2.
Fixed crash bug on ARM with no VFP3 hardware.
Fixed compilation of V8 without debugger support.
Improved performance on JSLint.
Added support Float64 WebGL arrays.
Fixed crash bug in regexp replace.
Review URL: http://codereview.chromium.org/6903060
git-svn-id: http://v8.googlecode.com/svn/trunk@7688 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/api.cc b/src/api.cc
index 1a52174..aa36641 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -3161,6 +3161,8 @@
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:
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index 9050c2c..27350fe 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -72,6 +72,7 @@
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);
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index d66daea..4cc5ef3 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -364,136 +364,6 @@
}
-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,
@@ -651,6 +521,78 @@
}
+void FloatingPointHelper::ConvertIntToDouble(MacroAssembler* masm,
+ Register int_scratch,
+ Destination destination,
+ DwVfpRegister double_dst,
+ Register dst1,
+ Register dst2,
+ Register scratch2,
+ SwVfpRegister single_scratch) {
+ ASSERT(!int_scratch.is(scratch2));
+
+ Label done;
+
+ if (CpuFeatures::IsSupported(VFP3)) {
+ CpuFeatures::Scope scope(VFP3);
+ __ vmov(single_scratch, int_scratch);
+ __ vcvt_f64_s32(double_dst, single_scratch);
+ if (destination == kCoreRegisters) {
+ __ vmov(dst1, dst2, double_dst);
+ }
+ } else {
+ Label fewer_than_20_useful_bits;
+ // Expected output:
+ // | dst2 | dst1 |
+ // | s | exp | mantissa |
+
+ // Check for zero.
+ __ cmp(int_scratch, Operand(0));
+ __ mov(dst2, int_scratch);
+ __ mov(dst1, int_scratch);
+ __ b(eq, &done);
+
+ // Preload the sign of the value.
+ __ and_(dst2, int_scratch, Operand(HeapNumber::kSignMask), SetCC);
+ // Get the absolute value of the object (as an unsigned integer).
+ __ rsb(int_scratch, int_scratch, Operand(0), SetCC, mi);
+
+ // Get mantisssa[51:20].
+
+ // Get the position of the first set bit.
+ __ CountLeadingZeros(dst1, int_scratch, scratch2);
+ __ rsb(dst1, dst1, Operand(31));
+
+ // Set the exponent.
+ __ add(scratch2, dst1, Operand(HeapNumber::kExponentBias));
+ __ Bfi(dst2, scratch2, scratch2,
+ HeapNumber::kExponentShift, HeapNumber::kExponentBits);
+
+ // Clear the first non null bit.
+ __ mov(scratch2, Operand(1));
+ __ 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(int_scratch, LSR, scratch2));
+ __ rsb(scratch2, scratch2, Operand(32));
+ __ mov(dst1, Operand(int_scratch, LSL, scratch2));
+ __ b(&done);
+
+ __ bind(&fewer_than_20_useful_bits);
+ __ rsb(scratch2, dst1, Operand(HeapNumber::kMantissaBitsInTopWord));
+ __ 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,
@@ -672,63 +614,8 @@
__ JumpIfNotSmi(object, &obj_is_not_smi);
__ SmiUntag(scratch1, object);
- if (CpuFeatures::IsSupported(VFP3)) {
- CpuFeatures::Scope scope(VFP3);
- __ vmov(single_scratch, scratch1);
- __ vcvt_f64_s32(double_dst, single_scratch);
- if (destination == kCoreRegisters) {
- __ vmov(dst1, dst2, double_dst);
- }
- } else {
- Label fewer_than_20_useful_bits;
- // Expected output:
- // | dst2 | dst1 |
- // | s | exp | mantissa |
-
- // Check for zero.
- __ cmp(scratch1, Operand(0));
- __ mov(dst2, scratch1);
- __ mov(dst1, scratch1);
- __ b(eq, &done);
-
- // Preload the sign of the value.
- __ and_(dst2, scratch1, Operand(HeapNumber::kSignMask), SetCC);
- // Get the absolute value of the object (as an unsigned integer).
- __ rsb(scratch1, scratch1, Operand(0), SetCC, mi);
-
- // Get mantisssa[51:20].
-
- // Get the position of the first set bit.
- __ CountLeadingZeros(dst1, scratch1, scratch2);
- __ rsb(dst1, dst1, Operand(31));
-
- // Set the exponent.
- __ add(scratch2, dst1, Operand(HeapNumber::kExponentBias));
- __ Bfi(dst2, scratch2, scratch2,
- HeapNumber::kExponentShift, HeapNumber::kExponentBits);
-
- // Clear the first non null bit.
- __ mov(scratch2, Operand(1));
- __ bic(scratch1, scratch1, 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));
- __ rsb(scratch2, scratch2, Operand(32));
- __ mov(dst1, Operand(scratch1, LSL, scratch2));
- __ b(&done);
-
- __ bind(&fewer_than_20_useful_bits);
- __ rsb(scratch2, dst1, Operand(HeapNumber::kMantissaBitsInTopWord));
- __ mov(scratch2, Operand(scratch1, LSL, scratch2));
- __ orr(dst2, dst2, scratch2);
- // Set dst1 to 0.
- __ mov(dst1, Operand(0));
- }
-
+ ConvertIntToDouble(masm, scratch1, destination, double_dst, dst1, dst2,
+ scratch2, single_scratch);
__ b(&done);
__ bind(&obj_is_not_smi);
@@ -2440,6 +2327,8 @@
// Save the left value on the stack.
__ Push(r5, r4);
+ Label pop_and_call_runtime;
+
// Allocate a heap number to store the result.
heap_number_result = r5;
GenerateHeapResultAllocation(masm,
@@ -2447,7 +2336,7 @@
heap_number_map,
scratch1,
scratch2,
- &call_runtime);
+ &pop_and_call_runtime);
// Load the left value from the value saved on the stack.
__ Pop(r1, r0);
@@ -2458,6 +2347,10 @@
if (FLAG_debug_code) {
__ stop("Unreachable code.");
}
+
+ __ bind(&pop_and_call_runtime);
+ __ Drop(2);
+ __ b(&call_runtime);
}
break;
diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h
index 0bb0025..b4d8f84 100644
--- a/src/arm/code-stubs-arm.h
+++ b/src/arm/code-stubs-arm.h
@@ -368,6 +368,149 @@
};
+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_
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index faf6404..5a425a6 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -858,22 +858,20 @@
// Shift operations can only deoptimize if we do a logical shift
// by 0 and the result cannot be truncated to int32.
- bool can_deopt = (op == Token::SHR && constant_value == 0);
- if (can_deopt) {
- bool can_truncate = true;
- for (int i = 0; i < instr->uses()->length(); i++) {
- if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) {
- can_truncate = false;
+ bool may_deopt = (op == Token::SHR && constant_value == 0);
+ bool does_deopt = false;
+ if (may_deopt) {
+ for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
+ if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
+ does_deopt = true;
break;
}
}
- can_deopt = !can_truncate;
}
LInstruction* result =
- DefineSameAsFirst(new LShiftI(op, left, right, can_deopt));
- if (can_deopt) AssignEnvironment(result);
- return result;
+ DefineSameAsFirst(new LShiftI(op, left, right, does_deopt));
+ return does_deopt ? AssignEnvironment(result) : result;
}
@@ -1856,8 +1854,11 @@
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());
@@ -1904,8 +1905,11 @@
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());
@@ -2138,4 +2142,12 @@
}
+LInstruction* LChunkBuilder::DoIn(HIn* instr) {
+ LOperand* key = UseRegisterAtStart(instr->key());
+ LOperand* object = UseRegisterAtStart(instr->object());
+ LIn* result = new LIn(key, object);
+ return MarkAsCall(DefineFixed(result, r0), instr);
+}
+
+
} } // namespace v8::internal
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index 4add6bf..fbabb4b 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -102,6 +102,7 @@
V(HasCachedArrayIndexAndBranch) \
V(HasInstanceType) \
V(HasInstanceTypeAndBranch) \
+ V(In) \
V(InstanceOf) \
V(InstanceOfAndBranch) \
V(InstanceOfKnownGlobal) \
@@ -1992,6 +1993,20 @@
};
+class LIn: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LIn(LOperand* key, LOperand* object) {
+ inputs_[0] = key;
+ inputs_[1] = object;
+ }
+
+ LOperand* key() { return inputs_[0]; }
+ LOperand* object() { return inputs_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(In, "in")
+};
+
+
class LChunkBuilder;
class LChunk: public ZoneObject {
public:
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index c820e2e..32411e4 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -2479,6 +2479,11 @@
__ 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) {
@@ -2507,6 +2512,7 @@
DeoptimizeIf(cs, instr->environment());
break;
case kExternalFloatArray:
+ case kExternalDoubleArray:
UNREACHABLE();
break;
}
@@ -3232,12 +3238,18 @@
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) {
@@ -3259,6 +3271,7 @@
__ str(value, MemOperand(external_pointer, key, LSL, 2));
break;
case kExternalFloatArray:
+ case kExternalDoubleArray:
UNREACHABLE();
break;
}
@@ -4244,6 +4257,22 @@
}
+void LCodeGen::DoIn(LIn* instr) {
+ Register obj = ToRegister(instr->object());
+ Register key = ToRegister(instr->key());
+ __ Push(key, obj);
+ ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+ LPointerMap* pointers = instr->pointer_map();
+ LEnvironment* env = instr->deoptimization_environment();
+ RecordPosition(pointers->position());
+ RegisterEnvironmentForDeoptimization(env);
+ SafepointGenerator safepoint_generator(this,
+ pointers,
+ env->deoptimization_index());
+ __ InvokeBuiltin(Builtins::IN, CALL_JS, &safepoint_generator);
+}
+
+
void LCodeGen::DoStackCheck(LStackCheck* instr) {
// Perform stack overflow check.
Label ok;
@@ -4273,6 +4302,8 @@
}
+
+
#undef __
} } // namespace v8::internal
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 47d675b..97097c8 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -3517,6 +3517,18 @@
__ 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;
@@ -3524,9 +3536,12 @@
// 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
@@ -3694,6 +3709,31 @@
__ 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.
@@ -3797,6 +3837,27 @@
// 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;
@@ -3831,6 +3892,11 @@
__ 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).
@@ -3933,6 +3999,12 @@
__ 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;
diff --git a/src/codegen.cc b/src/codegen.cc
index 4bbe6ae..6abd0e3 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -176,7 +176,10 @@
bool CodeGenerator::ShouldGenerateLog(Expression* type) {
ASSERT(type != NULL);
- if (!LOGGER->is_logging() && !CpuProfiler::is_profiling()) return false;
+ Isolate* isolate = Isolate::Current();
+ if (!isolate->logger()->is_logging() && !CpuProfiler::is_profiling(isolate)) {
+ return false;
+ }
Handle<String> name = Handle<String>::cast(type->AsLiteral()->handle());
if (FLAG_log_regexp) {
if (name->IsEqualTo(kRegexp))
diff --git a/src/compiler.cc b/src/compiler.cc
index 86d5de3..16250af 100755
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -664,7 +664,7 @@
// version of the function right away - unless the debugger is
// active as it makes no sense to compile optimized code then.
if (FLAG_always_opt &&
- !Isolate::Current()->debug()->has_break_points()) {
+ !Isolate::Current()->DebuggerHasBreakPoints()) {
CompilationInfo optimized(function);
optimized.SetOptimizing(AstNode::kNoNumber);
return CompileLazy(&optimized);
@@ -767,7 +767,8 @@
// Log the code generation. If source information is available include
// script name and line number. Check explicitly whether logging is
// enabled as finding the line number is not free.
- if (info->isolate()->logger()->is_logging() || CpuProfiler::is_profiling()) {
+ if (info->isolate()->logger()->is_logging() ||
+ CpuProfiler::is_profiling(info->isolate())) {
Handle<Script> script = info->script();
Handle<Code> code = info->code();
if (*code == info->isolate()->builtins()->builtin(Builtins::kLazyCompile))
diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc
index 3894748..8d11e7a 100644
--- a/src/cpu-profiler.cc
+++ b/src/cpu-profiler.cc
@@ -288,14 +288,16 @@
CpuProfile* CpuProfiler::StopProfiling(const char* title) {
- return is_profiling() ?
- Isolate::Current()->cpu_profiler()->StopCollectingProfile(title) : NULL;
+ Isolate* isolate = Isolate::Current();
+ return is_profiling(isolate) ?
+ isolate->cpu_profiler()->StopCollectingProfile(title) : NULL;
}
CpuProfile* CpuProfiler::StopProfiling(Object* security_token, String* title) {
- return is_profiling() ?
- Isolate::Current()->cpu_profiler()->StopCollectingProfile(
+ Isolate* isolate = Isolate::Current();
+ return is_profiling(isolate) ?
+ isolate->cpu_profiler()->StopCollectingProfile(
security_token, title) : NULL;
}
@@ -336,8 +338,9 @@
void CpuProfiler::DeleteAllProfiles() {
Isolate* isolate = Isolate::Current();
ASSERT(isolate->cpu_profiler() != NULL);
- if (is_profiling())
+ if (is_profiling(isolate)) {
isolate->cpu_profiler()->StopProcessor();
+ }
isolate->cpu_profiler()->ResetProfiles();
}
diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h
index e04cf85..4e39527 100644
--- a/src/cpu-profiler.h
+++ b/src/cpu-profiler.h
@@ -197,12 +197,12 @@
} } // namespace v8::internal
-#define PROFILE(isolate, Call) \
- LOG(isolate, Call); \
- do { \
- if (v8::internal::CpuProfiler::is_profiling()) { \
- v8::internal::CpuProfiler::Call; \
- } \
+#define PROFILE(isolate, Call) \
+ LOG(isolate, Call); \
+ do { \
+ if (v8::internal::CpuProfiler::is_profiling(isolate)) { \
+ v8::internal::CpuProfiler::Call; \
+ } \
} while (false)
#else
#define PROFILE(isolate, Call) LOG(isolate, Call)
@@ -261,10 +261,6 @@
// TODO(isolates): this doesn't have to use atomics anymore.
- static INLINE(bool is_profiling()) {
- return is_profiling(Isolate::Current());
- }
-
static INLINE(bool is_profiling(Isolate* isolate)) {
CpuProfiler* profiler = isolate->cpu_profiler();
return profiler != NULL && NoBarrier_Load(&profiler->is_profiling_);
@@ -292,7 +288,7 @@
Atomic32 is_profiling_;
#else
- static INLINE(bool is_profiling()) { return false; }
+ static INLINE(bool is_profiling(Isolate* isolate)) { return false; }
#endif // ENABLE_LOGGING_AND_PROFILING
private:
diff --git a/src/d8-readline.cc b/src/d8-readline.cc
index 67fc9ef..08395e5 100644
--- a/src/d8-readline.cc
+++ b/src/d8-readline.cc
@@ -30,6 +30,8 @@
#include <readline/readline.h> // NOLINT
#include <readline/history.h> // NOLINT
+// The readline includes leaves RETURN defined which breaks V8 compilation.
+#undef RETURN
#include "d8.h"
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 69139bb..3b5c087 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -223,6 +223,8 @@
// compilation-cache.cc
DEFINE_bool(compilation_cache, true, "enable compilation cache")
+DEFINE_bool(cache_prototype_transitions, true, "cache prototype transitions")
+
// data-flow.cc
DEFINE_bool(loop_peeling, false, "Peel off the first iteration of loops.")
diff --git a/src/frames.cc b/src/frames.cc
index e0517c8..1103fc8 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -938,6 +938,10 @@
accumulator->Add("\n");
return;
}
+ if (is_optimized()) {
+ accumulator->Add(" {\n// optimized frame\n}\n");
+ return;
+ }
accumulator->Add(" {\n");
// Compute the number of locals and expression stack elements.
diff --git a/src/heap.cc b/src/heap.cc
index 9a3cfe4..ac00c01 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -1347,7 +1347,7 @@
#if defined(ENABLE_LOGGING_AND_PROFILING)
Isolate* isolate = heap->isolate();
if (isolate->logger()->is_logging() ||
- isolate->cpu_profiler()->is_profiling()) {
+ CpuProfiler::is_profiling(isolate)) {
if (target->IsSharedFunctionInfo()) {
PROFILE(isolate, SharedFunctionInfoMoveEvent(
source->address(), target->address()));
@@ -1522,8 +1522,8 @@
return;
}
- if (isolate()->logger()->is_logging() ||
- isolate()->cpu_profiler()->is_profiling() ||
+ if (isolate()->logger()->is_logging() |
+ CpuProfiler::is_profiling(isolate()) ||
(isolate()->heap_profiler() != NULL &&
isolate()->heap_profiler()->is_profiling())) {
// If one of the isolates is doing scavenge at this moment of time
@@ -1594,6 +1594,7 @@
map->set_pre_allocated_property_fields(0);
map->set_instance_descriptors(empty_descriptor_array());
map->set_code_cache(empty_fixed_array());
+ map->set_prototype_transitions(empty_fixed_array());
map->set_unused_property_fields(0);
map->set_bit_field(0);
map->set_bit_field2((1 << Map::kIsExtensible) | (1 << Map::kHasFastElements));
@@ -1686,12 +1687,15 @@
// Fix the instance_descriptors for the existing maps.
meta_map()->set_instance_descriptors(empty_descriptor_array());
meta_map()->set_code_cache(empty_fixed_array());
+ meta_map()->set_prototype_transitions(empty_fixed_array());
fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
fixed_array_map()->set_code_cache(empty_fixed_array());
+ fixed_array_map()->set_prototype_transitions(empty_fixed_array());
oddball_map()->set_instance_descriptors(empty_descriptor_array());
oddball_map()->set_code_cache(empty_fixed_array());
+ oddball_map()->set_prototype_transitions(empty_fixed_array());
// Fix prototype object for existing maps.
meta_map()->set_prototype(null_value());
@@ -1800,6 +1804,12 @@
}
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;
}
@@ -2288,6 +2298,8 @@
return kExternalUnsignedIntArrayMapRootIndex;
case kExternalFloatArray:
return kExternalFloatArrayMapRootIndex;
+ case kExternalDoubleArray:
+ return kExternalDoubleArrayMapRootIndex;
case kExternalPixelArray:
return kExternalPixelArrayMapRootIndex;
default:
diff --git a/src/heap.h b/src/heap.h
index 7a1bed3..d0c1551 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -103,6 +103,7 @@
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) \
@@ -217,6 +218,7 @@
V(KeyedLoadExternalUnsignedIntArray_symbol, \
"KeyedLoadExternalUnsignedIntArray") \
V(KeyedLoadExternalFloatArray_symbol, "KeyedLoadExternalFloatArray") \
+ V(KeyedLoadExternalDoubleArray_symbol, "KeyedLoadExternalDoubleArray") \
V(KeyedLoadExternalPixelArray_symbol, "KeyedLoadExternalPixelArray") \
V(KeyedStoreExternalByteArray_symbol, "KeyedStoreExternalByteArray") \
V(KeyedStoreExternalUnsignedByteArray_symbol, \
@@ -228,6 +230,7 @@
V(KeyedStoreExternalUnsignedIntArray_symbol, \
"KeyedStoreExternalUnsignedIntArray") \
V(KeyedStoreExternalFloatArray_symbol, "KeyedStoreExternalFloatArray") \
+ V(KeyedStoreExternalDoubleArray_symbol, "KeyedStoreExternalDoubleArray") \
V(KeyedStoreExternalPixelArray_symbol, "KeyedStoreExternalPixelArray")
// Forward declarations.
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 58e6ff0..ac509a7 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -264,31 +264,60 @@
}
-int HValue::LookupOperandIndex(int occurrence_index, HValue* op) {
- for (int i = 0; i < OperandCount(); ++i) {
- if (OperandAt(i) == op) {
- if (occurrence_index == 0) return i;
- --occurrence_index;
- }
- }
- return -1;
-}
-
-
bool HValue::IsDefinedAfter(HBasicBlock* other) const {
return block()->block_id() > other->block_id();
}
-bool HValue::UsesMultipleTimes(HValue* op) {
- bool seen = false;
- for (int i = 0; i < OperandCount(); ++i) {
- if (OperandAt(i) == op) {
- if (seen) return true;
- seen = true;
- }
+HUseIterator::HUseIterator(HUseListNode* head) : next_(head) {
+ Advance();
+}
+
+
+void HUseIterator::Advance() {
+ current_ = next_;
+ if (current_ != NULL) {
+ next_ = current_->tail();
+ value_ = current_->value();
+ index_ = current_->index();
}
- return false;
+}
+
+
+int HValue::UseCount() const {
+ int count = 0;
+ for (HUseIterator it(uses()); !it.Done(); it.Advance()) ++count;
+ return count;
+}
+
+
+HUseListNode* HValue::RemoveUse(HValue* value, int index) {
+ HUseListNode* previous = NULL;
+ HUseListNode* current = use_list_;
+ while (current != NULL) {
+ if (current->value() == value && current->index() == index) {
+ if (previous == NULL) {
+ use_list_ = current->tail();
+ } else {
+ previous->set_tail(current->tail());
+ }
+ break;
+ }
+
+ previous = current;
+ current = current->tail();
+ }
+
+#ifdef DEBUG
+ // Do not reuse use list nodes in debug mode, zap them.
+ if (current != NULL) {
+ HUseListNode* temp =
+ new HUseListNode(current->value(), current->index(), NULL);
+ current->Zap();
+ current = temp;
+ }
+#endif
+ return current;
}
@@ -335,64 +364,31 @@
}
-void HValue::ReplaceAndDelete(HValue* other) {
- if (other != NULL) ReplaceValue(other);
- Delete();
-}
-
-
-void HValue::ReplaceValue(HValue* other) {
- for (int i = 0; i < uses_.length(); ++i) {
- HValue* use = uses_[i];
- ASSERT(!use->block()->IsStartBlock());
- InternalReplaceAtUse(use, other);
- other->uses_.Add(use);
- }
- uses_.Rewind(0);
-}
-
-
-void HValue::ClearOperands() {
- for (int i = 0; i < OperandCount(); ++i) {
- SetOperandAt(i, NULL);
- }
-}
-
-
-void HValue::Delete() {
+void HValue::DeleteAndReplaceWith(HValue* other) {
+ // We replace all uses first, so Delete can assert that there are none.
+ if (other != NULL) ReplaceAllUsesWith(other);
ASSERT(HasNoUses());
ClearOperands();
DeleteFromGraph();
}
-void HValue::ReplaceAtUse(HValue* use, HValue* other) {
- for (int i = 0; i < use->OperandCount(); ++i) {
- if (use->OperandAt(i) == this) {
- use->SetOperandAt(i, other);
- }
+void HValue::ReplaceAllUsesWith(HValue* other) {
+ while (use_list_ != NULL) {
+ HUseListNode* list_node = use_list_;
+ HValue* value = list_node->value();
+ ASSERT(!value->block()->IsStartBlock());
+ value->InternalSetOperandAt(list_node->index(), other);
+ use_list_ = list_node->tail();
+ list_node->set_tail(other->use_list_);
+ other->use_list_ = list_node;
}
}
-void HValue::ReplaceFirstAtUse(HValue* use, HValue* other, Representation r) {
- for (int i = 0; i < use->OperandCount(); ++i) {
- if (use->RequiredInputRepresentation(i).Equals(r) &&
- use->OperandAt(i) == this) {
- use->SetOperandAt(i, other);
- return;
- }
- }
-}
-
-
-void HValue::InternalReplaceAtUse(HValue* use, HValue* other) {
- for (int i = 0; i < use->OperandCount(); ++i) {
- if (use->OperandAt(i) == this) {
- // Call internal method that does not update use lists. The caller is
- // responsible for doing so.
- use->InternalSetOperandAt(i, other);
- }
+void HValue::ClearOperands() {
+ for (int i = 0; i < OperandCount(); ++i) {
+ SetOperandAt(i, NULL);
}
}
@@ -427,9 +423,20 @@
void HValue::RegisterUse(int index, HValue* new_value) {
HValue* old_value = OperandAt(index);
if (old_value == new_value) return;
- if (old_value != NULL) old_value->uses_.RemoveElement(this);
+
+ HUseListNode* removed = NULL;
+ if (old_value != NULL) {
+ removed = old_value->RemoveUse(this, index);
+ }
+
if (new_value != NULL) {
- new_value->uses_.Add(this);
+ if (removed == NULL) {
+ new_value->use_list_ =
+ new HUseListNode(this, index, new_value->use_list_);
+ } else {
+ removed->set_tail(new_value->use_list_);
+ new_value->use_list_ = removed;
+ }
}
}
@@ -926,7 +933,7 @@
stream->Add(" ");
}
stream->Add(" uses%d_%di_%dd_%dt]",
- uses()->length(),
+ UseCount(),
int32_non_phi_uses() + int32_indirect_uses(),
double_non_phi_uses() + double_indirect_uses(),
tagged_non_phi_uses() + tagged_indirect_uses());
@@ -944,8 +951,8 @@
bool HPhi::HasRealUses() {
- for (int i = 0; i < uses()->length(); i++) {
- if (!uses()->at(i)->IsPhi()) return true;
+ for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
+ if (!it.value()->IsPhi()) return true;
}
return false;
}
@@ -978,12 +985,11 @@
void HPhi::InitRealUses(int phi_id) {
// Initialize real uses.
phi_id_ = phi_id;
- for (int j = 0; j < uses()->length(); j++) {
- HValue* use = uses()->at(j);
- if (!use->IsPhi()) {
- int index = use->LookupOperandIndex(0, this);
- Representation req_rep = use->RequiredInputRepresentation(index);
- non_phi_uses_[req_rep.kind()]++;
+ for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
+ HValue* value = it.value();
+ if (!value->IsPhi()) {
+ Representation rep = value->RequiredInputRepresentation(it.index());
+ ++non_phi_uses_[rep.kind()];
}
}
}
@@ -1281,6 +1287,9 @@
case kExternalFloatArray:
stream->Add("float");
break;
+ case kExternalDoubleArray:
+ stream->Add("double");
+ break;
case kExternalPixelArray:
stream->Add("pixel");
break;
@@ -1358,6 +1367,9 @@
case kExternalFloatArray:
stream->Add("float");
break;
+ case kExternalDoubleArray:
+ stream->Add("double");
+ break;
case kExternalPixelArray:
stream->Add("pixel");
break;
@@ -1599,6 +1611,13 @@
}
+void HIn::PrintDataTo(StringStream* stream) {
+ key()->PrintNameTo(stream);
+ stream->Add(" ");
+ object()->PrintNameTo(stream);
+}
+
+
// Node-specific verification code is only included in debug mode.
#ifdef DEBUG
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 561dbc1..4fb7fec 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -104,6 +104,7 @@
V(Goto) \
V(HasInstanceType) \
V(HasCachedArrayIndex) \
+ V(In) \
V(InstanceOf) \
V(InstanceOfKnownGlobal) \
V(InvokeFunction) \
@@ -403,6 +404,62 @@
};
+class HUseListNode: public ZoneObject {
+ public:
+ HUseListNode(HValue* value, int index, HUseListNode* tail)
+ : tail_(tail), value_(value), index_(index) {
+ }
+
+ HUseListNode* tail() const { return tail_; }
+ HValue* value() const { return value_; }
+ int index() const { return index_; }
+
+ void set_tail(HUseListNode* list) { tail_ = list; }
+
+#ifdef DEBUG
+ void Zap() {
+ tail_ = reinterpret_cast<HUseListNode*>(1);
+ value_ = NULL;
+ index_ = -1;
+ }
+#endif
+
+ private:
+ HUseListNode* tail_;
+ HValue* value_;
+ int index_;
+};
+
+
+// We reuse use list nodes behind the scenes as uses are added and deleted.
+// This class is the safe way to iterate uses while deleting them.
+class HUseIterator BASE_EMBEDDED {
+ public:
+ bool Done() { return current_ == NULL; }
+ void Advance();
+
+ HValue* value() {
+ ASSERT(!Done());
+ return value_;
+ }
+
+ int index() {
+ ASSERT(!Done());
+ return index_;
+ }
+
+ private:
+ explicit HUseIterator(HUseListNode* head);
+
+ HUseListNode* current_;
+ HUseListNode* next_;
+ HValue* value_;
+ int index_;
+
+ friend class HValue;
+};
+
+
class HValue: public ZoneObject {
public:
static const int kNoNumber = -1;
@@ -473,6 +530,7 @@
HValue() : block_(NULL),
id_(kNoNumber),
type_(HType::Tagged()),
+ use_list_(NULL),
range_(NULL),
flags_(0) {}
virtual ~HValue() {}
@@ -483,7 +541,7 @@
int id() const { return id_; }
void set_id(int id) { id_ = id; }
- SmallPointerList<HValue>* uses() { return &uses_; }
+ HUseIterator uses() const { return HUseIterator(use_list_); }
virtual bool EmitAtUses() { return false; }
Representation representation() const { return representation_; }
@@ -498,7 +556,7 @@
HType type() const { return type_; }
void set_type(HType type) {
- ASSERT(uses_.length() == 0);
+ ASSERT(HasNoUses());
type_ = type;
}
@@ -524,16 +582,13 @@
virtual HValue* OperandAt(int index) = 0;
void SetOperandAt(int index, HValue* value);
- int LookupOperandIndex(int occurrence_index, HValue* op);
- bool UsesMultipleTimes(HValue* op);
-
- void ReplaceAndDelete(HValue* other);
- void ReplaceValue(HValue* other);
- void ReplaceAtUse(HValue* use, HValue* other);
- void ReplaceFirstAtUse(HValue* use, HValue* other, Representation r);
- bool HasNoUses() const { return uses_.is_empty(); }
+ void DeleteAndReplaceWith(HValue* other);
+ bool HasNoUses() const { return use_list_ == NULL; }
+ bool HasMultipleUses() const {
+ return use_list_ != NULL && use_list_->tail() != NULL;
+ }
+ int UseCount() const;
void ClearOperands();
- void Delete();
int flags() const { return flags_; }
void SetFlag(Flag f) { flags_ |= (1 << f); }
@@ -611,7 +666,12 @@
return ChangesFlagsMask() & ~(1 << kChangesOsrEntries);
}
- void InternalReplaceAtUse(HValue* use, HValue* other);
+ // Remove the matching use from the use list if present. Returns the
+ // removed list node or NULL.
+ HUseListNode* RemoveUse(HValue* value, int index);
+
+ void ReplaceAllUsesWith(HValue* other);
+
void RegisterUse(int index, HValue* new_value);
HBasicBlock* block_;
@@ -622,7 +682,7 @@
Representation representation_;
HType type_;
- SmallPointerList<HValue> uses_;
+ HUseListNode* use_list_;
Range* range_;
int flags_;
@@ -2257,7 +2317,7 @@
void SetInputRepresentation(Representation r);
virtual bool EmitAtUses() {
- return !HasSideEffects() && (uses()->length() <= 1);
+ return !HasSideEffects() && !HasMultipleUses();
}
virtual Representation RequiredInputRepresentation(int index) const {
@@ -2299,7 +2359,7 @@
}
virtual bool EmitAtUses() {
- return !HasSideEffects() && (uses()->length() <= 1);
+ return !HasSideEffects() && !HasMultipleUses();
}
virtual Representation RequiredInputRepresentation(int index) const {
@@ -2322,7 +2382,7 @@
}
virtual bool EmitAtUses() {
- return !HasSideEffects() && (uses()->length() <= 1);
+ return !HasSideEffects() && !HasMultipleUses();
}
virtual Representation RequiredInputRepresentation(int index) const {
@@ -2382,7 +2442,7 @@
}
virtual bool EmitAtUses() {
- return !HasSideEffects() && (uses()->length() <= 1);
+ return !HasSideEffects() && !HasMultipleUses();
}
virtual Representation RequiredInputRepresentation(int index) const {
@@ -2504,7 +2564,7 @@
HValue* right() { return OperandAt(2); }
virtual bool EmitAtUses() {
- return !HasSideEffects() && (uses()->length() <= 1);
+ return !HasSideEffects() && !HasMultipleUses();
}
virtual Representation RequiredInputRepresentation(int index) const {
@@ -3187,7 +3247,8 @@
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());
@@ -3379,7 +3440,8 @@
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();
@@ -3719,6 +3781,32 @@
HValue* key() { return right(); }
};
+
+class HIn: public HTemplateInstruction<2> {
+ public:
+ HIn(HValue* key, HValue* object) {
+ SetOperandAt(0, key);
+ SetOperandAt(1, object);
+ set_representation(Representation::Tagged());
+ SetAllSideEffects();
+ }
+
+ HValue* key() { return OperandAt(0); }
+ HValue* object() { return OperandAt(1); }
+
+ virtual Representation RequiredInputRepresentation(int index) const {
+ return Representation::Tagged();
+ }
+
+ virtual HType CalculateInferredType() {
+ return HType::Boolean();
+ }
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ DECLARE_CONCRETE_INSTRUCTION(In)
+};
+
#undef DECLARE_INSTRUCTION
#undef DECLARE_CONCRETE_INSTRUCTION
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index f6c47f3..27b8a26 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -644,7 +644,7 @@
HInstruction* instr = blocks()->at(i)->first();
while (instr != NULL) {
HValue* value = instr->Canonicalize();
- if (value != instr) instr->ReplaceAndDelete(value);
+ if (value != instr) instr->DeleteAndReplaceWith(value);
instr = instr->next();
}
}
@@ -726,9 +726,9 @@
void HGraph::EliminateRedundantPhis() {
HPhase phase("Redundant phi elimination", this);
- // Worklist of phis that can potentially be eliminated. Initialized
- // with all phi nodes. When elimination of a phi node modifies
- // another phi node the modified phi node is added to the worklist.
+ // Worklist of phis that can potentially be eliminated. Initialized with
+ // all phi nodes. When elimination of a phi node modifies another phi node
+ // the modified phi node is added to the worklist.
ZoneList<HPhi*> worklist(blocks_.length());
for (int i = 0; i < blocks_.length(); ++i) {
worklist.AddAll(*blocks_[i]->phis());
@@ -742,18 +742,14 @@
if (block == NULL) continue;
// Get replacement value if phi is redundant.
- HValue* value = phi->GetRedundantReplacement();
+ HValue* replacement = phi->GetRedundantReplacement();
- if (value != NULL) {
- // Iterate through uses finding the ones that should be
- // replaced.
- SmallPointerList<HValue>* uses = phi->uses();
- while (!uses->is_empty()) {
- HValue* use = uses->RemoveLast();
- if (use != NULL) {
- phi->ReplaceAtUse(use, value);
- if (use->IsPhi()) worklist.Add(HPhi::cast(use));
- }
+ if (replacement != NULL) {
+ // Iterate through the uses and replace them all.
+ for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
+ HValue* value = it.value();
+ value->SetOperandAt(it.index(), replacement);
+ if (value->IsPhi()) worklist.Add(HPhi::cast(value));
}
block->RemovePhi(phi);
}
@@ -831,8 +827,8 @@
HValue* current = worklist->RemoveLast();
in_worklist.Remove(current->id());
if (current->UpdateInferredType()) {
- for (int j = 0; j < current->uses()->length(); j++) {
- HValue* use = current->uses()->at(j);
+ for (HUseIterator it(current->uses()); !it.Done(); it.Advance()) {
+ HValue* use = it.value();
if (!in_worklist.Contains(use->id())) {
in_worklist.Add(use->id());
worklist->Add(use);
@@ -1445,7 +1441,7 @@
instr->Mnemonic(),
other->id(),
other->Mnemonic());
- instr->ReplaceAndDelete(other);
+ instr->DeleteAndReplaceWith(other);
} else {
map->Add(instr);
}
@@ -1529,12 +1525,12 @@
}
-void HInferRepresentation::AddDependantsToWorklist(HValue* current) {
- for (int i = 0; i < current->uses()->length(); ++i) {
- AddToWorklist(current->uses()->at(i));
+void HInferRepresentation::AddDependantsToWorklist(HValue* value) {
+ for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
+ AddToWorklist(it.value());
}
- for (int i = 0; i < current->OperandCount(); ++i) {
- AddToWorklist(current->OperandAt(i));
+ for (int i = 0; i < value->OperandCount(); ++i) {
+ AddToWorklist(value->OperandAt(i));
}
}
@@ -1543,37 +1539,30 @@
// given as the parameter has a benefit in terms of less necessary type
// conversions. If there is a benefit, then the representation of the value is
// specialized.
-void HInferRepresentation::InferBasedOnUses(HValue* current) {
- Representation r = current->representation();
- if (r.IsSpecialization() || current->HasNoUses()) return;
- ASSERT(current->CheckFlag(HValue::kFlexibleRepresentation));
- Representation new_rep = TryChange(current);
+void HInferRepresentation::InferBasedOnUses(HValue* value) {
+ Representation r = value->representation();
+ if (r.IsSpecialization() || value->HasNoUses()) return;
+ ASSERT(value->CheckFlag(HValue::kFlexibleRepresentation));
+ Representation new_rep = TryChange(value);
if (!new_rep.IsNone()) {
- if (!current->representation().Equals(new_rep)) {
- current->ChangeRepresentation(new_rep);
- AddDependantsToWorklist(current);
+ if (!value->representation().Equals(new_rep)) {
+ value->ChangeRepresentation(new_rep);
+ AddDependantsToWorklist(value);
}
}
}
-Representation HInferRepresentation::TryChange(HValue* current) {
+Representation HInferRepresentation::TryChange(HValue* value) {
// Array of use counts for each representation.
- int use_count[Representation::kNumRepresentations];
- for (int i = 0; i < Representation::kNumRepresentations; i++) {
- use_count[i] = 0;
- }
+ int use_count[Representation::kNumRepresentations] = { 0 };
- for (int i = 0; i < current->uses()->length(); ++i) {
- HValue* use = current->uses()->at(i);
- int index = use->LookupOperandIndex(0, current);
- Representation req_rep = use->RequiredInputRepresentation(index);
- if (req_rep.IsNone()) continue;
- if (use->IsPhi()) {
- HPhi* phi = HPhi::cast(use);
- phi->AddIndirectUsesTo(&use_count[0]);
- }
- use_count[req_rep.kind()]++;
+ for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
+ HValue* use = it.value();
+ Representation rep = use->RequiredInputRepresentation(it.index());
+ if (rep.IsNone()) continue;
+ if (use->IsPhi()) HPhi::cast(use)->AddIndirectUsesTo(&use_count[0]);
+ ++use_count[rep.kind()];
}
int tagged_count = use_count[Representation::kTagged];
int double_count = use_count[Representation::kDouble];
@@ -1581,7 +1570,7 @@
int non_tagged_count = double_count + int32_count;
// If a non-loop phi has tagged uses, don't convert it to untagged.
- if (current->IsPhi() && !current->block()->IsLoopHeader()) {
+ if (value->IsPhi() && !value->block()->IsLoopHeader()) {
if (tagged_count > 0) return Representation::None();
}
@@ -1602,41 +1591,39 @@
void HInferRepresentation::Analyze() {
HPhase phase("Infer representations", graph_);
- // (1) Initialize bit vectors and count real uses. Each phi
- // gets a bit-vector of length <number of phis>.
+ // (1) Initialize bit vectors and count real uses. Each phi gets a
+ // bit-vector of length <number of phis>.
const ZoneList<HPhi*>* phi_list = graph_->phi_list();
- int num_phis = phi_list->length();
- ScopedVector<BitVector*> connected_phis(num_phis);
- for (int i = 0; i < num_phis; i++) {
+ int phi_count = phi_list->length();
+ ScopedVector<BitVector*> connected_phis(phi_count);
+ for (int i = 0; i < phi_count; ++i) {
phi_list->at(i)->InitRealUses(i);
- connected_phis[i] = new(zone()) BitVector(num_phis);
+ connected_phis[i] = new(zone()) BitVector(phi_count);
connected_phis[i]->Add(i);
}
- // (2) Do a fixed point iteration to find the set of connected phis.
- // A phi is connected to another phi if its value is used either
- // directly or indirectly through a transitive closure of the def-use
- // relation.
+ // (2) Do a fixed point iteration to find the set of connected phis. A
+ // phi is connected to another phi if its value is used either directly or
+ // indirectly through a transitive closure of the def-use relation.
bool change = true;
while (change) {
change = false;
- for (int i = 0; i < num_phis; i++) {
+ for (int i = 0; i < phi_count; ++i) {
HPhi* phi = phi_list->at(i);
- for (int j = 0; j < phi->uses()->length(); j++) {
- HValue* use = phi->uses()->at(j);
+ for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
+ HValue* use = it.value();
if (use->IsPhi()) {
- int phi_use = HPhi::cast(use)->phi_id();
- if (connected_phis[i]->UnionIsChanged(*connected_phis[phi_use])) {
- change = true;
- }
+ int id = HPhi::cast(use)->phi_id();
+ change = change ||
+ connected_phis[i]->UnionIsChanged(*connected_phis[id]);
}
}
}
}
- // (3) Sum up the non-phi use counts of all connected phis.
- // Don't include the non-phi uses of the phi itself.
- for (int i = 0; i < num_phis; i++) {
+ // (3) Sum up the non-phi use counts of all connected phis. Don't include
+ // the non-phi uses of the phi itself.
+ for (int i = 0; i < phi_count; ++i) {
HPhi* phi = phi_list->at(i);
for (BitVector::Iterator it(connected_phis.at(i));
!it.Done();
@@ -1746,17 +1733,16 @@
void HGraph::InsertRepresentationChangeForUse(HValue* value,
- HValue* use,
+ HValue* use_value,
+ int use_index,
Representation to) {
// Insert the representation change right before its use. For phi-uses we
// insert at the end of the corresponding predecessor.
HInstruction* next = NULL;
- if (use->IsPhi()) {
- int index = 0;
- while (use->OperandAt(index) != value) ++index;
- next = use->block()->predecessors()->at(index)->end();
+ if (use_value->IsPhi()) {
+ next = use_value->block()->predecessors()->at(use_index)->end();
} else {
- next = HInstruction::cast(use);
+ next = HInstruction::cast(use_value);
}
// For constants we try to make the representation change at compile
@@ -1764,7 +1750,7 @@
// information we treat constants like normal instructions and insert the
// change instructions for them.
HInstruction* new_value = NULL;
- bool is_truncating = use->CheckFlag(HValue::kTruncatingToInt32);
+ bool is_truncating = use_value->CheckFlag(HValue::kTruncatingToInt32);
if (value->IsConstant()) {
HConstant* constant = HConstant::cast(value);
// Try to create a new copy of the constant with the new representation.
@@ -1779,89 +1765,26 @@
}
new_value->InsertBefore(next);
- value->ReplaceFirstAtUse(use, new_value, to);
+ use_value->SetOperandAt(use_index, new_value);
}
-int CompareConversionUses(HValue* a,
- HValue* b,
- Representation a_rep,
- Representation b_rep) {
- if (a_rep.kind() > b_rep.kind()) {
- // Make sure specializations are separated in the result array.
- return 1;
- }
- // Put truncating conversions before non-truncating conversions.
- bool a_truncate = a->CheckFlag(HValue::kTruncatingToInt32);
- bool b_truncate = b->CheckFlag(HValue::kTruncatingToInt32);
- if (a_truncate != b_truncate) {
- return a_truncate ? -1 : 1;
- }
- // Sort by increasing block ID.
- return a->block()->block_id() - b->block()->block_id();
-}
-
-
-void HGraph::InsertRepresentationChangesForValue(
- HValue* current,
- ZoneList<HValue*>* to_convert,
- ZoneList<Representation>* to_convert_reps) {
- Representation r = current->representation();
+void HGraph::InsertRepresentationChangesForValue(HValue* value) {
+ Representation r = value->representation();
if (r.IsNone()) return;
- if (current->uses()->is_empty()) return;
+ if (value->HasNoUses()) return;
- // Collect the representation changes in a sorted list. This allows
- // us to avoid duplicate changes without searching the list.
- ASSERT(to_convert->is_empty());
- ASSERT(to_convert_reps->is_empty());
- for (int i = 0; i < current->uses()->length(); ++i) {
- HValue* use = current->uses()->at(i);
- // The occurrences index means the index within the operand array of "use"
- // at which "current" is used. While iterating through the use array we
- // also have to iterate over the different occurrence indices.
- int occurrence_index = 0;
- if (use->UsesMultipleTimes(current)) {
- occurrence_index = current->uses()->CountOccurrences(use, 0, i - 1);
- if (FLAG_trace_representation) {
- PrintF("Instruction %d is used multiple times at %d; occurrence=%d\n",
- current->id(),
- use->id(),
- occurrence_index);
- }
- }
- int operand_index = use->LookupOperandIndex(occurrence_index, current);
- Representation req = use->RequiredInputRepresentation(operand_index);
+ for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
+ HValue* use_value = it.value();
+ int use_index = it.index();
+ Representation req = use_value->RequiredInputRepresentation(use_index);
if (req.IsNone() || req.Equals(r)) continue;
- int index = 0;
- while (index < to_convert->length() &&
- CompareConversionUses(to_convert->at(index),
- use,
- to_convert_reps->at(index),
- req) < 0) {
- ++index;
- }
- if (FLAG_trace_representation) {
- PrintF("Inserting a representation change to %s of %d for use at %d\n",
- req.Mnemonic(),
- current->id(),
- use->id());
- }
- to_convert->InsertAt(index, use);
- to_convert_reps->InsertAt(index, req);
+ InsertRepresentationChangeForUse(value, use_value, use_index, req);
}
-
- for (int i = 0; i < to_convert->length(); ++i) {
- HValue* use = to_convert->at(i);
- Representation r_to = to_convert_reps->at(i);
- InsertRepresentationChangeForUse(current, use, r_to);
+ if (value->HasNoUses()) {
+ ASSERT(value->IsConstant());
+ value->DeleteAndReplaceWith(NULL);
}
-
- if (current->uses()->is_empty()) {
- ASSERT(current->IsConstant());
- current->Delete();
- }
- to_convert->Rewind(0);
- to_convert_reps->Rewind(0);
}
@@ -1886,8 +1809,8 @@
for (int i = 0; i < phi_list()->length(); i++) {
HPhi* phi = phi_list()->at(i);
if (!phi->CheckFlag(HValue::kTruncatingToInt32)) continue;
- for (int j = 0; j < phi->uses()->length(); j++) {
- HValue* use = phi->uses()->at(j);
+ for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
+ HValue* use = it.value();
if (!use->CheckFlag(HValue::kTruncatingToInt32)) {
phi->ClearFlag(HValue::kTruncatingToInt32);
change = true;
@@ -1897,19 +1820,17 @@
}
}
- ZoneList<HValue*> value_list(4);
- ZoneList<Representation> rep_list(4);
for (int i = 0; i < blocks_.length(); ++i) {
// Process phi instructions first.
- for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
- HPhi* phi = blocks_[i]->phis()->at(j);
- InsertRepresentationChangesForValue(phi, &value_list, &rep_list);
+ const ZoneList<HPhi*>* phis = blocks_[i]->phis();
+ for (int j = 0; j < phis->length(); j++) {
+ InsertRepresentationChangesForValue(phis->at(j));
}
// Process normal instructions.
HInstruction* current = blocks_[i]->first();
while (current != NULL) {
- InsertRepresentationChangesForValue(current, &value_list, &rep_list);
+ InsertRepresentationChangesForValue(current);
current = current->next();
}
}
@@ -5184,7 +5105,7 @@
instr = new(zone()) HInstanceOfKnownGlobal(left, target);
}
} else if (op == Token::IN) {
- return Bailout("Unsupported comparison: in");
+ instr = new(zone()) HIn(left, right);
} else if (type_info.IsNonPrimitive()) {
switch (op) {
case Token::EQ:
@@ -5943,7 +5864,7 @@
HInstruction* instruction = current->first();
while (instruction != NULL) {
int bci = 0;
- int uses = instruction->uses()->length();
+ int uses = instruction->UseCount();
trace_.Add("%d %d ", bci, uses);
instruction->PrintNameTo(&trace_);
trace_.Add(" ");
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 74c119a..32bf6d4 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -277,11 +277,10 @@
void InsertTypeConversions(HInstruction* instr);
void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
void InsertRepresentationChangeForUse(HValue* value,
- HValue* use,
+ HValue* use_value,
+ int use_index,
Representation to);
- void InsertRepresentationChangesForValue(HValue* current,
- ZoneList<HValue*>* value_list,
- ZoneList<Representation>* rep_list);
+ void InsertRepresentationChangesForValue(HValue* value);
void InferTypes(ZoneList<HValue*>* worklist);
void InitializeInferredTypes(int from_inclusive, int to_inclusive);
void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 46c71e8..4fa5bae 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -2338,6 +2338,9 @@
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) {
@@ -2366,6 +2369,7 @@
DeoptimizeIf(negative, instr->environment());
break;
case kExternalFloatArray:
+ case kExternalDoubleArray:
UNREACHABLE();
break;
}
@@ -3047,6 +3051,9 @@
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) {
@@ -3081,6 +3088,7 @@
__ mov(Operand(external_pointer, key, times_4, 0), value);
break;
case kExternalFloatArray:
+ case kExternalDoubleArray:
UNREACHABLE();
break;
}
@@ -4210,6 +4218,35 @@
}
+void LCodeGen::DoIn(LIn* instr) {
+ LOperand* obj = instr->object();
+ LOperand* key = instr->key();
+ if (key->IsConstantOperand()) {
+ __ push(ToImmediate(key));
+ } else {
+ __ push(ToOperand(key));
+ }
+ if (obj->IsConstantOperand()) {
+ __ push(ToImmediate(obj));
+ } else {
+ __ push(ToOperand(obj));
+ }
+ ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+ LPointerMap* pointers = instr->pointer_map();
+ LEnvironment* env = instr->deoptimization_environment();
+ RecordPosition(pointers->position());
+ RegisterEnvironmentForDeoptimization(env);
+ // Create safepoint generator that will also ensure enough space in the
+ // reloc info for patching in deoptimization (since this is invoking a
+ // builtin)
+ SafepointGenerator safepoint_generator(this,
+ pointers,
+ env->deoptimization_index());
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+ __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, &safepoint_generator);
+}
+
+
#undef __
} } // namespace v8::internal
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index aa91a83..8d96d09 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -852,24 +852,22 @@
right = UseFixed(right_value, ecx);
}
- // Shift operations can only deoptimize if we do a logical shift
- // by 0 and the result cannot be truncated to int32.
- bool can_deopt = (op == Token::SHR && constant_value == 0);
- if (can_deopt) {
- bool can_truncate = true;
- for (int i = 0; i < instr->uses()->length(); i++) {
- if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) {
- can_truncate = false;
+ // Shift operations can only deoptimize if we do a logical shift by 0 and
+ // the result cannot be truncated to int32.
+ bool may_deopt = (op == Token::SHR && constant_value == 0);
+ bool does_deopt = false;
+ if (may_deopt) {
+ for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
+ if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
+ does_deopt = true;
break;
}
}
- can_deopt = !can_truncate;
}
- LShiftI* result = new LShiftI(op, left, right, can_deopt);
- return can_deopt
- ? AssignEnvironment(DefineSameAsFirst(result))
- : DefineSameAsFirst(result);
+ LInstruction* result =
+ DefineSameAsFirst(new LShiftI(op, left, right, does_deopt));
+ return does_deopt ? AssignEnvironment(result) : result;
}
@@ -1890,8 +1888,11 @@
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());
@@ -1940,8 +1941,11 @@
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());
@@ -2201,6 +2205,14 @@
}
+LInstruction* LChunkBuilder::DoIn(HIn* instr) {
+ LOperand* key = UseOrConstantAtStart(instr->key());
+ LOperand* object = UseOrConstantAtStart(instr->object());
+ LIn* result = new LIn(key, object);
+ return MarkAsCall(DefineFixed(result, eax), instr);
+}
+
+
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_IA32
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 76c90be..f6f6b77 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -103,6 +103,7 @@
V(HasCachedArrayIndexAndBranch) \
V(HasInstanceType) \
V(HasInstanceTypeAndBranch) \
+ V(In) \
V(InstanceOf) \
V(InstanceOfAndBranch) \
V(InstanceOfKnownGlobal) \
@@ -2045,6 +2046,20 @@
};
+class LIn: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LIn(LOperand* key, LOperand* object) {
+ inputs_[0] = key;
+ inputs_[1] = object;
+ }
+
+ LOperand* key() { return inputs_[0]; }
+ LOperand* object() { return inputs_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(In, "in")
+};
+
+
class LChunkBuilder;
class LChunk: public ZoneObject {
public:
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index 27d2886..c625115 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -3397,6 +3397,9 @@
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;
@@ -3454,7 +3457,8 @@
__ 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);
@@ -3569,11 +3573,16 @@
__ 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();
@@ -3603,6 +3612,10 @@
__ 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.
diff --git a/src/isolate-inl.h b/src/isolate-inl.h
new file mode 100644
index 0000000..aa6b537
--- /dev/null
+++ b/src/isolate-inl.h
@@ -0,0 +1,50 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_ISOLATE_INL_H_
+#define V8_ISOLATE_INL_H_
+
+#include "isolate.h"
+
+#include "debug.h"
+
+namespace v8 {
+namespace internal {
+
+
+bool Isolate::DebuggerHasBreakPoints() {
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ return debug()->has_break_points();
+#else
+ return false;
+#endif
+}
+
+
+} } // namespace v8::internal
+
+#endif // V8_ISOLATE_INL_H_
diff --git a/src/isolate.cc b/src/isolate.cc
index e42d78e..298d2e6 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -327,10 +327,12 @@
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
Debugger* Isolate::GetDefaultIsolateDebugger() {
EnsureDefaultIsolate();
return default_isolate_->debugger();
}
+#endif
StackGuard* Isolate::GetDefaultIsolateStackGuard() {
diff --git a/src/isolate.h b/src/isolate.h
index 35ffcb4..1706b48 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -294,7 +294,6 @@
#ifdef ENABLE_DEBUGGER_SUPPORT
#define ISOLATE_DEBUGGER_INIT_LIST(V) \
- V(uint64_t, enabled_cpu_features, 0) \
V(v8::Debug::EventCallback, debug_event_callback, NULL) \
V(DebuggerAgent*, debugger_agent_instance, NULL)
#else
@@ -370,6 +369,7 @@
V(unsigned, ast_node_count, 0) \
/* SafeStackFrameIterator activations count. */ \
V(int, safe_stack_iterator_counter, 0) \
+ V(uint64_t, enabled_cpu_features, 0) \
ISOLATE_PLATFORM_INIT_LIST(V) \
ISOLATE_LOGGING_INIT_LIST(V) \
ISOLATE_DEBUGGER_INIT_LIST(V)
@@ -486,9 +486,11 @@
// Safe to call multiple times.
static void EnsureDefaultIsolate();
+#ifdef ENABLE_DEBUGGER_SUPPORT
// Get the debugger from the default isolate. Preinitializes the
// default isolate if needed.
static Debugger* GetDefaultIsolateDebugger();
+#endif
// Get the stack guard from the default isolate. Preinitializes the
// default isolate if needed.
@@ -912,6 +914,8 @@
Debug* debug() { return debug_; }
#endif
+ inline bool DebuggerHasBreakPoints();
+
#ifdef ENABLE_LOGGING_AND_PROFILING
ProducerHeapProfile* producer_heap_profile() {
return producer_heap_profile_;
diff --git a/src/liveedit.cc b/src/liveedit.cc
index 1466766..42724cb 100644
--- a/src/liveedit.cc
+++ b/src/liveedit.cc
@@ -1682,7 +1682,7 @@
}
-bool LiveEditFunctionTracker::IsActive() {
+bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
return false;
}
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index bd36459..68a5062 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -1077,6 +1077,12 @@
void MarkCompactCollector::MarkMapContents(Map* map) {
+ // Mark prototype transitions array but don't push it into marking stack.
+ // This will make references from it weak. We will clean dead prototype
+ // transitions in ClearNonLiveTransitions.
+ FixedArray* prototype_transitions = map->unchecked_prototype_transitions();
+ if (!prototype_transitions->IsMarked()) SetMark(prototype_transitions);
+
MarkDescriptorArray(reinterpret_cast<DescriptorArray*>(
*HeapObject::RawField(map, Map::kInstanceDescriptorsOffset)));
@@ -1494,7 +1500,7 @@
void MarkCompactCollector::ClearNonLiveTransitions() {
- HeapObjectIterator map_iterator(heap() ->map_space(), &SizeOfMarkedObject);
+ HeapObjectIterator map_iterator(heap()->map_space(), &SizeOfMarkedObject);
// Iterate over the map space, setting map transitions that go from
// a marked map to an unmarked map to null transitions. At the same time,
// set all the prototype fields of maps back to their original value,
@@ -1522,6 +1528,41 @@
map->unchecked_constructor()->unchecked_shared()->AttachInitialMap(map);
}
+ // Clear dead prototype transitions.
+ FixedArray* prototype_transitions = map->unchecked_prototype_transitions();
+ if (prototype_transitions->length() > 0) {
+ int finger = Smi::cast(prototype_transitions->get(0))->value();
+ int new_finger = 1;
+ for (int i = 1; i < finger; i += 2) {
+ Object* prototype = prototype_transitions->get(i);
+ Object* cached_map = prototype_transitions->get(i + 1);
+ if (HeapObject::cast(prototype)->IsMarked() &&
+ HeapObject::cast(cached_map)->IsMarked()) {
+ if (new_finger != i) {
+ prototype_transitions->set_unchecked(heap_,
+ new_finger,
+ prototype,
+ UPDATE_WRITE_BARRIER);
+ prototype_transitions->set_unchecked(heap_,
+ new_finger + 1,
+ cached_map,
+ SKIP_WRITE_BARRIER);
+ }
+ new_finger += 2;
+ }
+ }
+
+ // Fill slots that became free with undefined value.
+ Object* undefined = heap()->raw_unchecked_undefined_value();
+ for (int i = new_finger; i < finger; i++) {
+ prototype_transitions->set_unchecked(heap_,
+ i,
+ undefined,
+ SKIP_WRITE_BARRIER);
+ }
+ prototype_transitions->set_unchecked(0, Smi::FromInt(new_finger));
+ }
+
// Follow the chain of back pointers to find the prototype.
Map* current = map;
while (SafeIsMap(current)) {
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index dd606dc..a0ce605 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -116,6 +116,9 @@
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;
@@ -232,6 +235,11 @@
}
+void ExternalDoubleArray::ExternalDoubleArrayVerify() {
+ ASSERT(IsExternalDoubleArray());
+}
+
+
void JSObject::JSObjectVerify() {
VerifyHeapPointer(properties());
VerifyHeapPointer(elements());
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 823b2da..e5caa07 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -406,6 +406,13 @@
}
+bool Object::IsExternalDoubleArray() {
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map()->instance_type() ==
+ EXTERNAL_DOUBLE_ARRAY_TYPE;
+}
+
+
bool MaybeObject::IsFailure() {
return HAS_FAILURE_TAG(this);
}
@@ -1901,6 +1908,7 @@
CAST_ACCESSOR(ExternalIntArray)
CAST_ACCESSOR(ExternalUnsignedIntArray)
CAST_ACCESSOR(ExternalFloatArray)
+CAST_ACCESSOR(ExternalDoubleArray)
CAST_ACCESSOR(ExternalPixelArray)
CAST_ACCESSOR(Struct)
@@ -2315,6 +2323,20 @@
}
+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);
}
@@ -2515,6 +2537,12 @@
}
+FixedArray* Map::unchecked_prototype_transitions() {
+ return reinterpret_cast<FixedArray*>(
+ READ_FIELD(this, kPrototypeTransitionsOffset));
+}
+
+
Code::Flags Code::flags() {
return static_cast<Flags>(READ_INT_FIELD(this, kFlagsOffset));
}
@@ -2923,6 +2951,7 @@
ACCESSORS(Map, instance_descriptors, DescriptorArray,
kInstanceDescriptorsOffset)
ACCESSORS(Map, code_cache, Object, kCodeCacheOffset)
+ACCESSORS(Map, prototype_transitions, FixedArray, kPrototypeTransitionsOffset)
ACCESSORS(Map, constructor, Object, kConstructorOffset)
ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset)
@@ -3638,14 +3667,18 @@
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;
}
@@ -3686,6 +3719,8 @@
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)
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index b7e2fdd..b26fd23 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -114,6 +114,9 @@
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;
@@ -217,6 +220,11 @@
}
+void ExternalDoubleArray::ExternalDoubleArrayPrint(FILE* out) {
+ PrintF(out, "external double array");
+}
+
+
void JSObject::PrintProperties(FILE* out) {
if (HasFastProperties()) {
DescriptorArray* descs = map()->instance_descriptors();
@@ -330,6 +338,13 @@
}
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;
@@ -383,6 +398,7 @@
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";
@@ -403,8 +419,8 @@
#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: return #NAME;
STRUCT_LIST(MAKE_STRUCT_CASE)
#undef MAKE_STRUCT_CASE
+ default: return "UNKNOWN";
}
- return "UNKNOWN";
}
diff --git a/src/objects-visiting.cc b/src/objects-visiting.cc
index 5a23658..bcb48ea 100644
--- a/src/objects-visiting.cc
+++ b/src/objects-visiting.cc
@@ -121,6 +121,7 @@
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);
diff --git a/src/objects.cc b/src/objects.cc
index 6ce4c44..17d9dc6 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -1045,6 +1045,10 @@
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;
@@ -1174,6 +1178,7 @@
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);
@@ -2848,6 +2853,7 @@
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;
@@ -2967,6 +2973,7 @@
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;
@@ -3238,6 +3245,7 @@
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();
@@ -3464,6 +3472,7 @@
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();
@@ -6874,6 +6883,49 @@
}
+Object* Map::GetPrototypeTransition(Object* prototype) {
+ FixedArray* cache = prototype_transitions();
+ int capacity = cache->length();
+ if (capacity == 0) return NULL;
+ int finger = Smi::cast(cache->get(0))->value();
+ for (int i = 1; i < finger; i += 2) {
+ if (cache->get(i) == prototype) return cache->get(i + 1);
+ }
+ return NULL;
+}
+
+
+MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
+ // Don't cache prototype transition if this map is shared.
+ if (is_shared() || !FLAG_cache_prototype_transitions) return this;
+
+ FixedArray* cache = prototype_transitions();
+
+ int capacity = cache->length();
+
+ int finger = (capacity == 0) ? 1 : Smi::cast(cache->get(0))->value();
+
+ if (finger >= capacity) {
+ if (capacity > kMaxCachedPrototypeTransitions) return this;
+
+ FixedArray* new_cache;
+ { MaybeObject* maybe_cache = heap()->AllocateFixedArray(finger * 2 + 1);
+ if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
+ }
+
+ for (int i = 1; i < capacity; i++) new_cache->set(i, cache->get(i));
+ cache = new_cache;
+ set_prototype_transitions(cache);
+ }
+
+ cache->set(finger, prototype);
+ cache->set(finger + 1, map);
+ cache->set(0, Smi::FromInt(finger + 2));
+
+ return cache;
+}
+
+
MaybeObject* JSObject::SetPrototype(Object* value,
bool skip_hidden_prototypes) {
Heap* heap = GetHeap();
@@ -6924,11 +6976,25 @@
}
// Set the new prototype of the object.
- Object* new_map;
- { MaybeObject* maybe_new_map = real_receiver->map()->CopyDropTransitions();
- if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
+ Map* map = real_receiver->map();
+
+ // Nothing to do if prototype is already set.
+ if (map->prototype() == value) return value;
+
+ Object* new_map = map->GetPrototypeTransition(value);
+ if (new_map == NULL) {
+ { MaybeObject* maybe_new_map = map->CopyDropTransitions();
+ if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
+ }
+
+ { MaybeObject* maybe_new_cache =
+ map->PutPrototypeTransition(value, Map::cast(new_map));
+ if (maybe_new_cache->IsFailure()) return maybe_new_cache;
+ }
+
+ Map::cast(new_map)->set_prototype(value);
}
- Map::cast(new_map)->set_prototype(value);
+ ASSERT(Map::cast(new_map)->prototype() == value);
real_receiver->set_map(Map::cast(new_map));
heap->ClearInstanceofCache();
@@ -6963,7 +7029,8 @@
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;
@@ -7085,7 +7152,8 @@
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;
@@ -7144,7 +7212,8 @@
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;
@@ -7465,6 +7534,10 @@
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());
@@ -7606,7 +7679,8 @@
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;
@@ -7708,7 +7782,8 @@
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;
@@ -7811,6 +7886,14 @@
}
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();
@@ -7840,7 +7923,8 @@
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: {
@@ -8077,7 +8161,8 @@
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());
}
@@ -8318,7 +8403,8 @@
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) {
@@ -9233,6 +9319,26 @@
}
+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());
diff --git a/src/objects.h b/src/objects.h
index 03445e8..0f9198c 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -523,6 +523,7 @@
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
@@ -648,6 +649,13 @@
return reinterpret_cast<Object*>(this);
}
+ template<typename T>
+ inline bool To(T** obj) {
+ if (IsFailure()) return false;
+ *obj = T::cast(reinterpret_cast<Object*>(this));
+ return true;
+ }
+
#ifdef OBJECT_PRINT
// Prints this object with details.
inline void Print() {
@@ -691,6 +699,7 @@
V(ExternalIntArray) \
V(ExternalUnsignedIntArray) \
V(ExternalFloatArray) \
+ V(ExternalDoubleArray) \
V(ExternalPixelArray) \
V(ByteArray) \
V(JSObject) \
@@ -1336,6 +1345,7 @@
EXTERNAL_INT_ELEMENTS,
EXTERNAL_UNSIGNED_INT_ELEMENTS,
EXTERNAL_FLOAT_ELEMENTS,
+ EXTERNAL_DOUBLE_ELEMENTS,
EXTERNAL_PIXEL_ELEMENTS
};
@@ -1377,6 +1387,7 @@
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().
@@ -3093,6 +3104,34 @@
};
+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
@@ -3712,6 +3751,16 @@
// [stub cache]: contains stubs compiled for this map.
DECL_ACCESSORS(code_cache, Object)
+ // [prototype transitions]: cache of prototype transitions.
+ // Prototype transition is a transition that happens
+ // when we change object's prototype to a new one.
+ // Cache format:
+ // 0: finger - index of the first free cell in the cache
+ // 1 + 2 * i: prototype
+ // 2 + 2 * i: target map
+ DECL_ACCESSORS(prototype_transitions, FixedArray)
+ inline FixedArray* unchecked_prototype_transitions();
+
// Lookup in the map's instance descriptors and fill out the result
// with the given holder if the name is found. The holder may be
// NULL when this function is used from the compiler.
@@ -3811,6 +3860,12 @@
void TraverseTransitionTree(TraverseCallback callback, void* data);
+ static const int kMaxCachedPrototypeTransitions = 256;
+
+ Object* GetPrototypeTransition(Object* prototype);
+
+ MaybeObject* PutPrototypeTransition(Object* prototype, Map* map);
+
static const int kMaxPreAllocatedPropertyFields = 255;
// Layout description.
@@ -3821,14 +3876,16 @@
static const int kInstanceDescriptorsOffset =
kConstructorOffset + kPointerSize;
static const int kCodeCacheOffset = kInstanceDescriptorsOffset + kPointerSize;
- static const int kPadStart = kCodeCacheOffset + kPointerSize;
+ static const int kPrototypeTransitionsOffset =
+ kCodeCacheOffset + kPointerSize;
+ static const int kPadStart = kPrototypeTransitionsOffset + kPointerSize;
static const int kSize = MAP_POINTER_ALIGN(kPadStart);
// Layout of pointer fields. Heap iteration code relies on them
// being continiously allocated.
static const int kPointerFieldsBeginOffset = Map::kPrototypeOffset;
static const int kPointerFieldsEndOffset =
- Map::kCodeCacheOffset + kPointerSize;
+ Map::kPrototypeTransitionsOffset + kPointerSize;
// Byte offsets within kInstanceSizesOffset.
static const int kInstanceSizeOffset = kInstanceSizesOffset + 0;
diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc
index 8d258ac..ce9a308 100644
--- a/src/runtime-profiler.cc
+++ b/src/runtime-profiler.cc
@@ -171,7 +171,7 @@
// Debug::has_break_points().
ASSERT(function->IsMarkedForLazyRecompilation());
if (!FLAG_use_osr ||
- isolate_->debug()->has_break_points() ||
+ isolate_->DebuggerHasBreakPoints() ||
function->IsBuiltin()) {
return;
}
diff --git a/src/runtime.cc b/src/runtime.cc
index 53c048e..ff05037 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -2713,7 +2713,7 @@
end = RegExpImpl::GetCapture(match_info_array, 1);
}
- int length = subject->length();
+ int length = subject_handle->length();
int new_length = length - (end - start);
if (new_length == 0) {
return isolate->heap()->empty_string();
@@ -7298,13 +7298,13 @@
// If the function is not optimizable or debugger is active continue using the
// code from the full compiler.
if (!function->shared()->code()->optimizable() ||
- isolate->debug()->has_break_points()) {
+ isolate->DebuggerHasBreakPoints()) {
if (FLAG_trace_opt) {
PrintF("[failed to optimize ");
function->PrintName();
PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
function->shared()->code()->optimizable() ? "T" : "F",
- isolate->debug()->has_break_points() ? "T" : "F");
+ isolate->DebuggerHasBreakPoints() ? "T" : "F");
}
function->ReplaceCode(function->shared()->code());
return function->code();
@@ -8603,43 +8603,48 @@
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:
@@ -8773,6 +8778,11 @@
isolate, receiver, false, false, visitor);
break;
}
+ case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
+ IterateExternalArrayElements<ExternalDoubleArray, double>(
+ isolate, receiver, false, false, visitor);
+ break;
+ }
default:
UNREACHABLE();
break;
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 0c6a7f7..7a1b185 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -555,6 +555,8 @@
return kExternalUnsignedIntArray;
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
return kExternalFloatArray;
+ case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ return kExternalDoubleArray;
case JSObject::EXTERNAL_PIXEL_ELEMENTS:
return kExternalPixelArray;
default:
@@ -582,6 +584,8 @@
return heap->KeyedStoreExternalUnsignedIntArray_symbol();
case kExternalFloatArray:
return heap->KeyedStoreExternalFloatArray_symbol();
+ case kExternalDoubleArray:
+ return heap->KeyedStoreExternalDoubleArray_symbol();
case kExternalPixelArray:
return heap->KeyedStoreExternalPixelArray_symbol();
default:
@@ -604,6 +608,8 @@
return heap->KeyedLoadExternalUnsignedIntArray_symbol();
case kExternalFloatArray:
return heap->KeyedLoadExternalFloatArray_symbol();
+ case kExternalDoubleArray:
+ return heap->KeyedLoadExternalDoubleArray_symbol();
case kExternalPixelArray:
return heap->KeyedLoadExternalPixelArray_symbol();
default:
diff --git a/src/v8.h b/src/v8.h
index 776fa9c..9d98521 100644
--- a/src/v8.h
+++ b/src/v8.h
@@ -66,6 +66,7 @@
#include "log-inl.h"
#include "cpu-profiler-inl.h"
#include "handles-inl.h"
+#include "isolate-inl.h"
namespace v8 {
namespace internal {
diff --git a/src/version.cc b/src/version.cc
index ccbe56d..e9a7be2 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 3
-#define BUILD_NUMBER 1
+#define BUILD_NUMBER 2
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index c242874..de193ab 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -2350,6 +2350,9 @@
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) {
@@ -2378,6 +2381,7 @@
DeoptimizeIf(negative, instr->environment());
break;
case kExternalFloatArray:
+ case kExternalDoubleArray:
UNREACHABLE();
break;
}
@@ -3037,6 +3041,9 @@
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) {
@@ -3064,6 +3071,7 @@
__ movl(Operand(external_pointer, key, times_4, 0), value);
break;
case kExternalFloatArray:
+ case kExternalDoubleArray:
UNREACHABLE();
break;
}
@@ -3990,6 +3998,26 @@
}
+void LCodeGen::DoIn(LIn* instr) {
+ LOperand* obj = instr->object();
+ LOperand* key = instr->key();
+ EmitPushTaggedOperand(key);
+ EmitPushTaggedOperand(obj);
+ ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+ LPointerMap* pointers = instr->pointer_map();
+ LEnvironment* env = instr->deoptimization_environment();
+ RecordPosition(pointers->position());
+ RegisterEnvironmentForDeoptimization(env);
+ // Create safepoint generator that will also ensure enough space in the
+ // reloc info for patching in deoptimization (since this is invoking a
+ // builtin)
+ SafepointGenerator safepoint_generator(this,
+ pointers,
+ env->deoptimization_index());
+ __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, &safepoint_generator);
+}
+
+
void LCodeGen::DoStackCheck(LStackCheck* instr) {
// Perform stack overflow check.
NearLabel done;
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 620bbc9..4a85b79 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -851,24 +851,22 @@
right = UseFixed(right_value, rcx);
}
- // Shift operations can only deoptimize if we do a logical shift
- // by 0 and the result cannot be truncated to int32.
- bool can_deopt = (op == Token::SHR && constant_value == 0);
- if (can_deopt) {
- bool can_truncate = true;
- for (int i = 0; i < instr->uses()->length(); i++) {
- if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) {
- can_truncate = false;
+ // Shift operations can only deoptimize if we do a logical shift by 0 and
+ // the result cannot be truncated to int32.
+ bool may_deopt = (op == Token::SHR && constant_value == 0);
+ bool does_deopt = false;
+ if (may_deopt) {
+ for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
+ if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
+ does_deopt = true;
break;
}
}
- can_deopt = !can_truncate;
}
- LShiftI* result = new LShiftI(op, left, right, can_deopt);
- return can_deopt
- ? AssignEnvironment(DefineSameAsFirst(result))
- : DefineSameAsFirst(result);
+ LInstruction* result =
+ DefineSameAsFirst(new LShiftI(op, left, right, does_deopt));
+ return does_deopt ? AssignEnvironment(result) : result;
}
@@ -1846,8 +1844,11 @@
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());
@@ -1893,8 +1894,11 @@
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());
@@ -2132,6 +2136,15 @@
return NULL;
}
+
+LInstruction* LChunkBuilder::DoIn(HIn* instr) {
+ LOperand* key = UseOrConstantAtStart(instr->key());
+ LOperand* object = UseOrConstantAtStart(instr->object());
+ LIn* result = new LIn(key, object);
+ return MarkAsCall(DefineFixed(result, rax), instr);
+}
+
+
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_X64
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 74f4820..d724875 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -102,6 +102,7 @@
V(HasCachedArrayIndexAndBranch) \
V(HasInstanceType) \
V(HasInstanceTypeAndBranch) \
+ V(In) \
V(InstanceOf) \
V(InstanceOfAndBranch) \
V(InstanceOfKnownGlobal) \
@@ -830,6 +831,20 @@
};
+class LIn: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LIn(LOperand* key, LOperand* object) {
+ inputs_[0] = key;
+ inputs_[1] = object;
+ }
+
+ LOperand* key() { return inputs_[0]; }
+ LOperand* object() { return inputs_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(In, "in")
+};
+
+
class LInstanceOf: public LTemplateInstruction<1, 2, 0> {
public:
LInstanceOf(LOperand* left, LOperand* right) {
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index c19d29d..ef6f758 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -3214,6 +3214,9 @@
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;
@@ -3251,7 +3254,8 @@
__ 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);
@@ -3361,6 +3365,11 @@
__ 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;
@@ -3391,6 +3400,9 @@
__ 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.