Merge V8 at branches/3.2 r8200: Initial merge by Git
Change-Id: I5c434306e98132997e9c5f6024b6ce200b255edf
diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h
index 079dca7..46fda3b 100644
--- a/src/ia32/assembler-ia32.h
+++ b/src/ia32/assembler-ia32.h
@@ -296,6 +296,7 @@
RelocInfo::Mode rmode_;
friend class Assembler;
+ friend class MacroAssembler;
};
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 275e8e2..5d32095 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -446,9 +446,6 @@
case TRBinaryOpIC::ODDBALL:
GenerateOddballStub(masm);
break;
- case TRBinaryOpIC::BOTH_STRING:
- GenerateBothStringStub(masm);
- break;
case TRBinaryOpIC::STRING:
GenerateStringStub(masm);
break;
@@ -912,38 +909,6 @@
}
-void TypeRecordingBinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
- Label call_runtime;
- ASSERT(operands_type_ == TRBinaryOpIC::BOTH_STRING);
- ASSERT(op_ == Token::ADD);
- // If both arguments are strings, call the string add stub.
- // Otherwise, do a transition.
-
- // Registers containing left and right operands respectively.
- Register left = edx;
- Register right = eax;
-
- // Test if left operand is a string.
- __ test(left, Immediate(kSmiTagMask));
- __ j(zero, &call_runtime);
- __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx);
- __ j(above_equal, &call_runtime);
-
- // Test if right operand is a string.
- __ test(right, Immediate(kSmiTagMask));
- __ j(zero, &call_runtime);
- __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx);
- __ j(above_equal, &call_runtime);
-
- StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
- GenerateRegisterArgsPush(masm);
- __ TailCallStub(&string_add_stub);
-
- __ bind(&call_runtime);
- GenerateTypeTransition(masm);
-}
-
-
void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
Label call_runtime;
ASSERT(operands_type_ == TRBinaryOpIC::INT32);
@@ -1155,25 +1120,23 @@
GenerateAddStrings(masm);
}
- Factory* factory = masm->isolate()->factory();
-
// Convert odd ball arguments to numbers.
NearLabel check, done;
- __ cmp(edx, factory->undefined_value());
+ __ cmp(edx, FACTORY->undefined_value());
__ j(not_equal, &check);
if (Token::IsBitOp(op_)) {
__ xor_(edx, Operand(edx));
} else {
- __ mov(edx, Immediate(factory->nan_value()));
+ __ mov(edx, Immediate(FACTORY->nan_value()));
}
__ jmp(&done);
__ bind(&check);
- __ cmp(eax, factory->undefined_value());
+ __ cmp(eax, FACTORY->undefined_value());
__ j(not_equal, &done);
if (Token::IsBitOp(op_)) {
__ xor_(eax, Operand(eax));
} else {
- __ mov(eax, Immediate(factory->nan_value()));
+ __ mov(eax, Immediate(FACTORY->nan_value()));
}
__ bind(&done);
@@ -4084,7 +4047,12 @@
__ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0));
__ j(not_equal, ¬_outermost_js);
__ mov(Operand::StaticVariable(js_entry_sp), ebp);
+ __ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
+ Label cont;
+ __ jmp(&cont);
__ bind(¬_outermost_js);
+ __ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)));
+ __ bind(&cont);
#endif
// Call a faked try-block that does the invoke.
@@ -4130,23 +4098,20 @@
__ call(Operand(edx));
// Unlink this frame from the handler chain.
- __ pop(Operand::StaticVariable(ExternalReference(
- Isolate::k_handler_address,
- masm->isolate())));
- // Pop next_sp.
- __ add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize));
+ __ PopTryHandler();
+ __ bind(&exit);
#ifdef ENABLE_LOGGING_AND_PROFILING
- // If current EBP value is the same as js_entry_sp value, it means that
- // the current function is the outermost.
- __ cmp(ebp, Operand::StaticVariable(js_entry_sp));
+ // Check if the current stack frame is marked as the outermost JS frame.
+ __ pop(ebx);
+ __ cmp(Operand(ebx),
+ Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
__ j(not_equal, ¬_outermost_js_2);
__ mov(Operand::StaticVariable(js_entry_sp), Immediate(0));
__ bind(¬_outermost_js_2);
#endif
// Restore the top frame descriptor from the stack.
- __ bind(&exit);
__ pop(Operand::StaticVariable(ExternalReference(
Isolate::k_c_entry_fp_address,
masm->isolate())));
diff --git a/src/ia32/code-stubs-ia32.h b/src/ia32/code-stubs-ia32.h
index cf73682..80a75cd 100644
--- a/src/ia32/code-stubs-ia32.h
+++ b/src/ia32/code-stubs-ia32.h
@@ -153,7 +153,6 @@
void GenerateHeapNumberStub(MacroAssembler* masm);
void GenerateOddballStub(MacroAssembler* masm);
void GenerateStringStub(MacroAssembler* masm);
- void GenerateBothStringStub(MacroAssembler* masm);
void GenerateGenericStub(MacroAssembler* masm);
void GenerateAddStrings(MacroAssembler* masm);
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 69d5e77..5d153a8 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -192,7 +192,7 @@
__ lea(edx,
Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
__ push(edx);
- __ push(Immediate(Smi::FromInt(scope()->num_parameters())));
+ __ SafePush(Immediate(Smi::FromInt(scope()->num_parameters())));
// Arguments to ArgumentsAccessStub:
// function, receiver address, parameter count.
// The stub will rewrite receiver and parameter count if the previous
@@ -381,13 +381,20 @@
void FullCodeGenerator::AccumulatorValueContext::Plug(
Handle<Object> lit) const {
- __ Set(result_register(), Immediate(lit));
+ if (lit->IsSmi()) {
+ __ SafeSet(result_register(), Immediate(lit));
+ } else {
+ __ Set(result_register(), Immediate(lit));
+ }
}
void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
- // Immediates can be pushed directly.
- __ push(Immediate(lit));
+ if (lit->IsSmi()) {
+ __ SafePush(Immediate(lit));
+ } else {
+ __ push(Immediate(lit));
+ }
}
@@ -730,7 +737,7 @@
}
ASSERT(prop->key()->AsLiteral() != NULL &&
prop->key()->AsLiteral()->handle()->IsSmi());
- __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle()));
+ __ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle()));
Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
@@ -1184,7 +1191,7 @@
__ mov(edx,
ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
slow));
- __ mov(eax, Immediate(key_literal->handle()));
+ __ SafeSet(eax, Immediate(key_literal->handle()));
Handle<Code> ic =
isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
@@ -1269,7 +1276,7 @@
ASSERT(key_literal->handle()->IsSmi());
// Load the key.
- __ mov(eax, Immediate(key_literal->handle()));
+ __ SafeSet(eax, Immediate(key_literal->handle()));
// Do a keyed property load.
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
@@ -1540,7 +1547,7 @@
MemOperand slot_operand =
EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
__ push(slot_operand);
- __ mov(eax, Immediate(property->key()->AsLiteral()->handle()));
+ __ SafeSet(eax, Immediate(property->key()->AsLiteral()->handle()));
} else {
VisitForStackValue(property->obj());
VisitForAccumulatorValue(property->key());
@@ -1553,7 +1560,7 @@
MemOperand slot_operand =
EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
__ push(slot_operand);
- __ push(Immediate(property->key()->AsLiteral()->handle()));
+ __ SafePush(Immediate(property->key()->AsLiteral()->handle()));
} else {
VisitForStackValue(property->obj());
VisitForStackValue(property->key());
@@ -1632,6 +1639,7 @@
void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
SetSourcePosition(prop->position());
Literal* key = prop->key()->AsLiteral();
+ ASSERT(!key->handle()->IsSmi());
__ mov(ecx, Immediate(key->handle()));
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET);
@@ -1796,7 +1804,7 @@
EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
}
__ mov(edx, eax);
- __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle()));
+ __ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle()));
} else {
VisitForStackValue(prop->obj());
VisitForAccumulatorValue(prop->key());
@@ -2307,7 +2315,7 @@
SetSourcePosition(expr->position());
// Load function and argument count into edi and eax.
- __ Set(eax, Immediate(arg_count));
+ __ SafeSet(eax, Immediate(arg_count));
__ mov(edi, Operand(esp, arg_count * kPointerSize));
Handle<Code> construct_builtin =
@@ -2647,7 +2655,7 @@
// parameter count in eax.
VisitForAccumulatorValue(args->at(0));
__ mov(edx, eax);
- __ mov(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
+ __ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
__ CallStub(&stub);
context()->Plug(eax);
@@ -2659,7 +2667,7 @@
Label exit;
// Get the number of formal parameters.
- __ Set(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
+ __ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
// Check if the calling frame is an arguments adaptor frame.
__ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
@@ -3087,14 +3095,15 @@
void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
ASSERT(args->length() >= 2);
- int arg_count = args->length() - 2; // 2 ~ receiver and function.
- for (int i = 0; i < arg_count + 1; ++i) {
- VisitForStackValue(args->at(i));
+ int arg_count = args->length() - 2; // For receiver and function.
+ VisitForStackValue(args->at(0)); // Receiver.
+ for (int i = 0; i < arg_count; i++) {
+ VisitForStackValue(args->at(i + 1));
}
- VisitForAccumulatorValue(args->last()); // Function.
+ VisitForAccumulatorValue(args->at(arg_count + 1)); // Function.
- // InvokeFunction requires the function in edi. Move it in there.
- __ mov(edi, result_register());
+ // InvokeFunction requires function in edi. Move it in there.
+ if (!result_register().is(edi)) __ mov(edi, result_register());
ParameterCount count(arg_count);
__ InvokeFunction(edi, count, CALL_FUNCTION);
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
@@ -3818,7 +3827,7 @@
MemOperand slot_operand =
EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
__ push(slot_operand);
- __ mov(eax, Immediate(prop->key()->AsLiteral()->handle()));
+ __ SafeSet(eax, Immediate(prop->key()->AsLiteral()->handle()));
} else {
VisitForStackValue(prop->obj());
VisitForAccumulatorValue(prop->key());
@@ -4253,7 +4262,30 @@
default:
break;
}
+
__ call(ic, mode);
+
+ // Crankshaft doesn't need patching of inlined loads and stores.
+ // When compiling the snapshot we need to produce code that works
+ // with and without Crankshaft.
+ if (V8::UseCrankshaft() && !Serializer::enabled()) {
+ return;
+ }
+
+ // If we're calling a (keyed) load or store stub, we have to mark
+ // the call as containing no inlined code so we will not attempt to
+ // patch it.
+ switch (ic->kind()) {
+ case Code::LOAD_IC:
+ case Code::KEYED_LOAD_IC:
+ case Code::STORE_IC:
+ case Code::KEYED_STORE_IC:
+ __ nop(); // Signals no inlined code.
+ break;
+ default:
+ // Do nothing.
+ break;
+ }
}
@@ -4274,6 +4306,7 @@
default:
break;
}
+
__ call(ic, RelocInfo::CODE_TARGET);
if (patch_site != NULL && patch_site->is_bound()) {
patch_site->EmitPatchInfo();
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 4106f01..b7af03c 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -371,6 +371,12 @@
}
+// The offset from the inlined patch site to the start of the
+// inlined load instruction. It is 7 bytes (test eax, imm) plus
+// 6 bytes (jne slow_label).
+const int LoadIC::kOffsetToLoadInstruction = 13;
+
+
void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : receiver
@@ -1267,6 +1273,172 @@
}
+bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
+ if (V8::UseCrankshaft()) return false;
+
+ // The address of the instruction following the call.
+ Address test_instruction_address =
+ address + Assembler::kCallTargetAddressOffset;
+ // If the instruction following the call is not a test eax, nothing
+ // was inlined.
+ if (*test_instruction_address != Assembler::kTestEaxByte) return false;
+
+ Address delta_address = test_instruction_address + 1;
+ // The delta to the start of the map check instruction.
+ int delta = *reinterpret_cast<int*>(delta_address);
+
+ // The map address is the last 4 bytes of the 7-byte
+ // operand-immediate compare instruction, so we add 3 to get the
+ // offset to the last 4 bytes.
+ Address map_address = test_instruction_address + delta + 3;
+ *(reinterpret_cast<Object**>(map_address)) = map;
+
+ // The offset is in the last 4 bytes of a six byte
+ // memory-to-register move instruction, so we add 2 to get the
+ // offset to the last 4 bytes.
+ Address offset_address =
+ test_instruction_address + delta + kOffsetToLoadInstruction + 2;
+ *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
+ return true;
+}
+
+
+// One byte opcode for mov ecx,0xXXXXXXXX.
+// Marks inlined contextual loads using all kinds of cells. Generated
+// code has the hole check:
+// mov reg, <cell>
+// mov reg, (<cell>, value offset)
+// cmp reg, <the hole>
+// je slow
+// ;; use reg
+static const byte kMovEcxByte = 0xB9;
+
+// One byte opcode for mov edx,0xXXXXXXXX.
+// Marks inlined contextual loads using only "don't delete"
+// cells. Generated code doesn't have the hole check:
+// mov reg, <cell>
+// mov reg, (<cell>, value offset)
+// ;; use reg
+static const byte kMovEdxByte = 0xBA;
+
+bool LoadIC::PatchInlinedContextualLoad(Address address,
+ Object* map,
+ Object* cell,
+ bool is_dont_delete) {
+ if (V8::UseCrankshaft()) return false;
+
+ // The address of the instruction following the call.
+ Address mov_instruction_address =
+ address + Assembler::kCallTargetAddressOffset;
+ // If the instruction following the call is not a mov ecx/edx,
+ // nothing was inlined.
+ byte b = *mov_instruction_address;
+ if (b != kMovEcxByte && b != kMovEdxByte) return false;
+ // If we don't have the hole check generated, we can only support
+ // "don't delete" cells.
+ if (b == kMovEdxByte && !is_dont_delete) return false;
+
+ Address delta_address = mov_instruction_address + 1;
+ // The delta to the start of the map check instruction.
+ int delta = *reinterpret_cast<int*>(delta_address);
+
+ // The map address is the last 4 bytes of the 7-byte
+ // operand-immediate compare instruction, so we add 3 to get the
+ // offset to the last 4 bytes.
+ Address map_address = mov_instruction_address + delta + 3;
+ *(reinterpret_cast<Object**>(map_address)) = map;
+
+ // The cell is in the last 4 bytes of a five byte mov reg, imm32
+ // instruction, so we add 1 to get the offset to the last 4 bytes.
+ Address offset_address =
+ mov_instruction_address + delta + kOffsetToLoadInstruction + 1;
+ *reinterpret_cast<Object**>(offset_address) = cell;
+ return true;
+}
+
+
+bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
+ if (V8::UseCrankshaft()) return false;
+
+ // The address of the instruction following the call.
+ Address test_instruction_address =
+ address + Assembler::kCallTargetAddressOffset;
+
+ // If the instruction following the call is not a test eax, nothing
+ // was inlined.
+ if (*test_instruction_address != Assembler::kTestEaxByte) return false;
+
+ // Extract the encoded deltas from the test eax instruction.
+ Address encoded_offsets_address = test_instruction_address + 1;
+ int encoded_offsets = *reinterpret_cast<int*>(encoded_offsets_address);
+ int delta_to_map_check = -(encoded_offsets & 0xFFFF);
+ int delta_to_record_write = encoded_offsets >> 16;
+
+ // Patch the map to check. The map address is the last 4 bytes of
+ // the 7-byte operand-immediate compare instruction.
+ Address map_check_address = test_instruction_address + delta_to_map_check;
+ Address map_address = map_check_address + 3;
+ *(reinterpret_cast<Object**>(map_address)) = map;
+
+ // Patch the offset in the store instruction. The offset is in the
+ // last 4 bytes of a six byte register-to-memory move instruction.
+ Address offset_address =
+ map_check_address + StoreIC::kOffsetToStoreInstruction + 2;
+ // The offset should have initial value (kMaxInt - 1), cleared value
+ // (-1) or we should be clearing the inlined version.
+ ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt - 1 ||
+ *reinterpret_cast<int*>(offset_address) == -1 ||
+ (offset == 0 && map == HEAP->null_value()));
+ *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
+
+ // Patch the offset in the write-barrier code. The offset is the
+ // last 4 bytes of a six byte lea instruction.
+ offset_address = map_check_address + delta_to_record_write + 2;
+ // The offset should have initial value (kMaxInt), cleared value
+ // (-1) or we should be clearing the inlined version.
+ ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt ||
+ *reinterpret_cast<int*>(offset_address) == -1 ||
+ (offset == 0 && map == HEAP->null_value()));
+ *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
+
+ return true;
+}
+
+
+static bool PatchInlinedMapCheck(Address address, Object* map) {
+ if (V8::UseCrankshaft()) return false;
+
+ Address test_instruction_address =
+ address + Assembler::kCallTargetAddressOffset;
+ // The keyed load has a fast inlined case if the IC call instruction
+ // is immediately followed by a test instruction.
+ if (*test_instruction_address != Assembler::kTestEaxByte) return false;
+
+ // Fetch the offset from the test instruction to the map cmp
+ // instruction. This offset is stored in the last 4 bytes of the 5
+ // byte test instruction.
+ Address delta_address = test_instruction_address + 1;
+ int delta = *reinterpret_cast<int*>(delta_address);
+ // Compute the map address. The map address is in the last 4 bytes
+ // of the 7-byte operand-immediate compare instruction, so we add 3
+ // to the offset to get the map address.
+ Address map_address = test_instruction_address + delta + 3;
+ // Patch the map check.
+ *(reinterpret_cast<Object**>(map_address)) = map;
+ return true;
+}
+
+
+bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
+ return PatchInlinedMapCheck(address, map);
+}
+
+
+bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
+ return PatchInlinedMapCheck(address, map);
+}
+
+
void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : key
@@ -1347,6 +1519,12 @@
}
+// The offset from the inlined patch site to the start of the inlined
+// store instruction. It is 7 bytes (test reg, imm) plus 6 bytes (jne
+// slow_label).
+const int StoreIC::kOffsetToStoreInstruction = 13;
+
+
void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : value
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 46c71e8..0f96f78 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -77,7 +77,7 @@
void LCodeGen::FinishCode(Handle<Code> code) {
ASSERT(is_done());
- code->set_stack_slots(GetStackSlotCount());
+ code->set_stack_slots(StackSlotCount());
code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
PopulateDeoptimizationData(code);
Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
@@ -132,7 +132,7 @@
__ push(edi); // Callee's JS function.
// Reserve space for the stack slots needed by the code.
- int slots = GetStackSlotCount();
+ int slots = StackSlotCount();
if (slots > 0) {
if (FLAG_debug_code) {
__ mov(Operand(eax), Immediate(slots));
@@ -254,7 +254,7 @@
bool LCodeGen::GenerateSafepointTable() {
ASSERT(is_done());
- safepoints_.Emit(masm(), GetStackSlotCount());
+ safepoints_.Emit(masm(), StackSlotCount());
return !is_aborted();
}
@@ -386,7 +386,7 @@
translation->StoreDoubleStackSlot(op->index());
} else if (op->IsArgument()) {
ASSERT(is_tagged);
- int src_index = GetStackSlotCount() + op->index();
+ int src_index = StackSlotCount() + op->index();
translation->StoreStackSlot(src_index);
} else if (op->IsRegister()) {
Register reg = ToRegister(op);
@@ -2057,7 +2057,7 @@
}
__ mov(esp, ebp);
__ pop(ebp);
- __ Ret((GetParameterCount() + 1) * kPointerSize, ecx);
+ __ Ret((ParameterCount() + 1) * kPointerSize, ecx);
}
@@ -2493,7 +2493,7 @@
SafepointGenerator safepoint_generator(this,
pointers,
env->deoptimization_index());
- ParameterCount actual(eax);
+ v8::internal::ParameterCount actual(eax);
__ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator);
}
@@ -2707,16 +2707,25 @@
Register output_reg = ToRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
- Label below_half, done;
// xmm_scratch = 0.5
ExternalReference one_half = ExternalReference::address_of_one_half();
__ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
- __ ucomisd(xmm_scratch, input_reg);
- __ j(above, &below_half);
// input = input + 0.5
__ addsd(input_reg, xmm_scratch);
+ // We need to return -0 for the input range [-0.5, 0[, otherwise
+ // compute Math.floor(value + 0.5).
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ __ ucomisd(input_reg, xmm_scratch);
+ DeoptimizeIf(below_equal, instr->environment());
+ } else {
+ // If we don't need to bailout on -0, we check only bailout
+ // on negative inputs.
+ __ xorpd(xmm_scratch, xmm_scratch); // Zero the register.
+ __ ucomisd(input_reg, xmm_scratch);
+ DeoptimizeIf(below, instr->environment());
+ }
// Compute Math.floor(value + 0.5).
// Use truncating instruction (OK because input is positive).
@@ -2725,27 +2734,6 @@
// Overflow is signalled with minint.
__ cmp(output_reg, 0x80000000u);
DeoptimizeIf(equal, instr->environment());
- __ jmp(&done);
-
- __ bind(&below_half);
-
- // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
- // we can ignore the difference between a result of -0 and +0.
- if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- // If the sign is positive, we return +0.
- __ movmskpd(output_reg, input_reg);
- __ test(output_reg, Immediate(1));
- DeoptimizeIf(not_zero, instr->environment());
- } else {
- // If the input is >= -0.5, we return +0.
- __ mov(output_reg, Immediate(0xBF000000));
- __ movd(xmm_scratch, Operand(output_reg));
- __ cvtss2sd(xmm_scratch, xmm_scratch);
- __ ucomisd(input_reg, xmm_scratch);
- DeoptimizeIf(below, instr->environment());
- }
- __ Set(output_reg, Immediate(0));
- __ bind(&done);
}
@@ -2905,21 +2893,6 @@
}
-void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
- ASSERT(ToRegister(instr->context()).is(esi));
- ASSERT(ToRegister(instr->function()).is(edi));
- ASSERT(instr->HasPointerMap());
- ASSERT(instr->HasDeoptimizationEnvironment());
- LPointerMap* pointers = instr->pointer_map();
- LEnvironment* env = instr->deoptimization_environment();
- RecordPosition(pointers->position());
- RegisterEnvironmentForDeoptimization(env);
- SafepointGenerator generator(this, pointers, env->deoptimization_index());
- ParameterCount count(instr->arity());
- __ InvokeFunction(edi, count, CALL_FUNCTION, &generator);
-}
-
-
void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->key()).is(ecx));
@@ -3323,22 +3296,6 @@
}
-void LCodeGen::DoStringAdd(LStringAdd* instr) {
- if (instr->left()->IsConstantOperand()) {
- __ push(ToImmediate(instr->left()));
- } else {
- __ push(ToOperand(instr->left()));
- }
- if (instr->right()->IsConstantOperand()) {
- __ push(ToImmediate(instr->right()));
- } else {
- __ push(ToOperand(instr->right()));
- }
- StringAddStub stub(NO_STRING_CHECK_IN_STUB);
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
-}
-
-
void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
LOperand* input = instr->InputAt(0);
ASSERT(input->IsRegister() || input->IsStackSlot());
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index f8bbea3..6d42cd7 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -147,8 +147,8 @@
Register temporary,
Register temporary2);
- int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
- int GetParameterCount() const { return scope()->num_parameters(); }
+ int StackSlotCount() const { return chunk()->spill_slot_count(); }
+ int ParameterCount() const { return scope()->num_parameters(); }
void Abort(const char* format, ...);
void Comment(const char* format, ...);
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index aa91a83..9ccd189 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -71,21 +71,22 @@
#ifdef DEBUG
void LInstruction::VerifyCall() {
- // Call instructions can use only fixed registers as temporaries and
- // outputs because all registers are blocked by the calling convention.
- // Inputs operands must use a fixed register or use-at-start policy or
- // a non-register policy.
+ // Call instructions can use only fixed registers as
+ // temporaries and outputs because all registers
+ // are blocked by the calling convention.
+ // Inputs must use a fixed register.
ASSERT(Output() == NULL ||
LUnallocated::cast(Output())->HasFixedPolicy() ||
!LUnallocated::cast(Output())->HasRegisterPolicy());
for (UseIterator it(this); it.HasNext(); it.Advance()) {
- LUnallocated* operand = LUnallocated::cast(it.Next());
- ASSERT(operand->HasFixedPolicy() ||
- operand->IsUsedAtStart());
+ LOperand* operand = it.Next();
+ ASSERT(LUnallocated::cast(operand)->HasFixedPolicy() ||
+ !LUnallocated::cast(operand)->HasRegisterPolicy());
}
for (TempIterator it(this); it.HasNext(); it.Advance()) {
- LUnallocated* operand = LUnallocated::cast(it.Next());
- ASSERT(operand->HasFixedPolicy() ||!operand->HasRegisterPolicy());
+ LOperand* operand = it.Next();
+ ASSERT(LUnallocated::cast(operand)->HasFixedPolicy() ||
+ !LUnallocated::cast(operand)->HasRegisterPolicy());
}
}
#endif
@@ -302,15 +303,6 @@
}
-void LInvokeFunction::PrintDataTo(StringStream* stream) {
- stream->Add("= ");
- InputAt(0)->PrintTo(stream);
- stream->Add(" ");
- InputAt(1)->PrintTo(stream);
- stream->Add(" #%d / ", arity());
-}
-
-
void LCallKeyed::PrintDataTo(StringStream* stream) {
stream->Add("[ecx] #%d / ", arity());
}
@@ -1230,15 +1222,6 @@
}
-LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
- LOperand* context = UseFixed(instr->context(), esi);
- LOperand* function = UseFixed(instr->function(), edi);
- argument_count_ -= instr->argument_count();
- LInvokeFunction* result = new LInvokeFunction(context, function);
- return MarkAsCall(DefineFixed(result, eax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
-}
-
-
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
BuiltinFunctionId op = instr->op();
if (op == kMathLog) {
@@ -2019,13 +2002,6 @@
}
-LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
- LOperand* left = UseOrConstantAtStart(instr->left());
- LOperand* right = UseOrConstantAtStart(instr->right());
- return MarkAsCall(DefineFixed(new LStringAdd(left, right), eax), instr);
-}
-
-
LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
LOperand* string = UseRegister(instr->string());
LOperand* index = UseRegisterOrConstant(instr->index());
@@ -2070,8 +2046,7 @@
LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) {
LDeleteProperty* result =
- new LDeleteProperty(UseAtStart(instr->object()),
- UseOrConstantAtStart(instr->key()));
+ new LDeleteProperty(Use(instr->object()), UseOrConstant(instr->key()));
return MarkAsCall(DefineFixed(result, eax), instr);
}
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 76c90be..9ace8f8 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -39,7 +39,6 @@
// Forward declarations.
class LCodeGen;
-
#define LITHIUM_ALL_INSTRUCTION_LIST(V) \
V(ControlInstruction) \
V(Call) \
@@ -107,7 +106,6 @@
V(InstanceOfAndBranch) \
V(InstanceOfKnownGlobal) \
V(Integer32ToDouble) \
- V(InvokeFunction) \
V(IsNull) \
V(IsNullAndBranch) \
V(IsObject) \
@@ -156,7 +154,6 @@
V(StoreKeyedSpecializedArrayElement) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
- V(StringAdd) \
V(StringCharCodeAt) \
V(StringCharFromCode) \
V(StringLength) \
@@ -1453,25 +1450,6 @@
};
-class LInvokeFunction: public LTemplateInstruction<1, 2, 0> {
- public:
- LInvokeFunction(LOperand* context, LOperand* function) {
- inputs_[0] = context;
- inputs_[1] = function;
- }
-
- DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function")
- DECLARE_HYDROGEN_ACCESSOR(InvokeFunction)
-
- LOperand* context() { return inputs_[0]; }
- LOperand* function() { return inputs_[1]; }
-
- virtual void PrintDataTo(StringStream* stream);
-
- int arity() const { return hydrogen()->argument_count() - 1; }
-};
-
-
class LCallKeyed: public LTemplateInstruction<1, 2, 0> {
public:
LCallKeyed(LOperand* context, LOperand* key) {
@@ -1791,21 +1769,6 @@
};
-class LStringAdd: public LTemplateInstruction<1, 2, 0> {
- public:
- LStringAdd(LOperand* left, LOperand* right) {
- inputs_[0] = left;
- inputs_[1] = right;
- }
-
- DECLARE_CONCRETE_INSTRUCTION(StringAdd, "string-add")
- DECLARE_HYDROGEN_ACCESSOR(StringAdd)
-
- LOperand* left() { return inputs_[0]; }
- LOperand* right() { return inputs_[1]; }
-};
-
-
class LStringCharCodeAt: public LTemplateInstruction<1, 2, 0> {
public:
LStringCharCodeAt(LOperand* string, LOperand* index) {
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index ad567bc..13394cb 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -164,7 +164,7 @@
void MacroAssembler::Set(Register dst, const Immediate& x) {
if (x.is_zero()) {
- xor_(dst, Operand(dst)); // shorter than mov
+ xor_(dst, Operand(dst)); // Shorter than mov.
} else {
mov(dst, x);
}
@@ -176,6 +176,33 @@
}
+bool MacroAssembler::IsUnsafeImmediate(const Immediate& x) {
+ static const int kMaxImmediateBits = 17;
+ if (x.rmode_ != RelocInfo::NONE) return false;
+ return !is_intn(x.x_, kMaxImmediateBits);
+}
+
+
+void MacroAssembler::SafeSet(Register dst, const Immediate& x) {
+ if (IsUnsafeImmediate(x) && jit_cookie() != 0) {
+ Set(dst, Immediate(x.x_ ^ jit_cookie()));
+ xor_(dst, jit_cookie());
+ } else {
+ Set(dst, x);
+ }
+}
+
+
+void MacroAssembler::SafePush(const Immediate& x) {
+ if (IsUnsafeImmediate(x) && jit_cookie() != 0) {
+ push(Immediate(x.x_ ^ jit_cookie()));
+ xor_(Operand(esp, 0), Immediate(jit_cookie()));
+ } else {
+ push(x);
+ }
+}
+
+
void MacroAssembler::CmpObjectType(Register heap_object,
InstanceType type,
Register map) {
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index 6909272..b986264 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -197,6 +197,11 @@
void Set(Register dst, const Immediate& x);
void Set(const Operand& dst, const Immediate& x);
+ // Support for constant splitting.
+ bool IsUnsafeImmediate(const Immediate& x);
+ void SafeSet(Register dst, const Immediate& x);
+ void SafePush(const Immediate& x);
+
// Compare object type for heap object.
// Incoming register is heap_object and outgoing register is map.
void CmpObjectType(Register heap_object, InstanceType type, Register map);
diff --git a/src/ia32/regexp-macro-assembler-ia32.cc b/src/ia32/regexp-macro-assembler-ia32.cc
index 067f8c8..5b2f208 100644
--- a/src/ia32/regexp-macro-assembler-ia32.cc
+++ b/src/ia32/regexp-macro-assembler-ia32.cc
@@ -662,7 +662,7 @@
}
-Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
+Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
// Finalize code - write the entry point code now we know how many
// registers we need.
@@ -879,7 +879,7 @@
Code::ComputeFlags(Code::REGEXP),
masm_->CodeObject());
PROFILE(masm_->isolate(), RegExpCodeCreateEvent(*code, *source));
- return Handle<Object>::cast(code);
+ return Handle<HeapObject>::cast(code);
}
diff --git a/src/ia32/regexp-macro-assembler-ia32.h b/src/ia32/regexp-macro-assembler-ia32.h
index 0af61f2..70606da 100644
--- a/src/ia32/regexp-macro-assembler-ia32.h
+++ b/src/ia32/regexp-macro-assembler-ia32.h
@@ -80,7 +80,7 @@
virtual void CheckPosition(int cp_offset, Label* on_outside_input);
virtual bool CheckSpecialCharacterClass(uc16 type, Label* on_no_match);
virtual void Fail();
- virtual Handle<Object> GetCode(Handle<String> source);
+ virtual Handle<HeapObject> GetCode(Handle<String> source);
virtual void GoTo(Label* label);
virtual void IfRegisterGE(int reg, int comparand, Label* if_ge);
virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);