Index: src/ia32/lithium-codegen-ia32.cc |
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc |
index 388d4969dd67ea085861780be1e2f346e2872353..00da461d0004e3e04bc5adddbade358c26bc10ee 100644 |
--- a/src/ia32/lithium-codegen-ia32.cc |
+++ b/src/ia32/lithium-codegen-ia32.cc |
@@ -30,6 +30,7 @@ |
#if defined(V8_TARGET_ARCH_IA32) |
#include "ia32/lithium-codegen-ia32.h" |
+#include "ic.h" |
#include "code-stubs.h" |
#include "deoptimizer.h" |
#include "stub-cache.h" |
@@ -70,7 +71,6 @@ bool LCodeGen::GenerateCode() { |
HPhase phase("Z_Code generation", chunk()); |
ASSERT(is_unused()); |
status_ = GENERATING; |
- CpuFeatures::Scope scope(SSE2); |
CodeStub::GenerateFPStubs(); |
@@ -79,13 +79,15 @@ bool LCodeGen::GenerateCode() { |
// the frame (that is done in GeneratePrologue). |
FrameScope frame_scope(masm_, StackFrame::MANUAL); |
- dynamic_frame_alignment_ = (chunk()->num_double_slots() > 2 && |
- !chunk()->graph()->is_recursive()) || |
- !info()->osr_ast_id().IsNone(); |
+ dynamic_frame_alignment_ = info()->IsOptimizing() && |
+ ((chunk()->num_double_slots() > 2 && |
+ !chunk()->graph()->is_recursive()) || |
+ !info()->osr_ast_id().IsNone()); |
return GeneratePrologue() && |
GenerateBody() && |
GenerateDeferredCode() && |
+ GenerateJumpTable() && |
GenerateSafepointTable(); |
} |
@@ -95,7 +97,9 @@ void LCodeGen::FinishCode(Handle<Code> code) { |
code->set_stack_slots(GetStackSlotCount()); |
code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); |
PopulateDeoptimizationData(code); |
- Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code); |
+ if (!info()->IsStub()) { |
+ Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code); |
+ } |
} |
@@ -126,35 +130,36 @@ void LCodeGen::Comment(const char* format, ...) { |
bool LCodeGen::GeneratePrologue() { |
ASSERT(is_generating()); |
- ProfileEntryHookStub::MaybeCallEntryHook(masm_); |
+ if (info()->IsOptimizing()) { |
+ ProfileEntryHookStub::MaybeCallEntryHook(masm_); |
#ifdef DEBUG |
- if (strlen(FLAG_stop_at) > 0 && |
- info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
- __ int3(); |
- } |
+ if (strlen(FLAG_stop_at) > 0 && |
+ info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
+ __ int3(); |
+ } |
#endif |
- // Strict mode functions and builtins need to replace the receiver |
- // with undefined when called as functions (without an explicit |
- // receiver object). ecx is zero for method calls and non-zero for |
- // function calls. |
- if (!info_->is_classic_mode() || info_->is_native()) { |
- Label begin; |
- __ bind(&begin); |
- Label ok; |
- __ test(ecx, Operand(ecx)); |
- __ j(zero, &ok, Label::kNear); |
- // +1 for return address. |
- int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize; |
- __ mov(Operand(esp, receiver_offset), |
- Immediate(isolate()->factory()->undefined_value())); |
- __ bind(&ok); |
- ASSERT(!FLAG_age_code || |
- (kSizeOfOptimizedStrictModePrologue == ok.pos() - begin.pos())); |
+ // Strict mode functions and builtins need to replace the receiver |
+ // with undefined when called as functions (without an explicit |
+ // receiver object). ecx is zero for method calls and non-zero for |
+ // function calls. |
+ if (!info_->is_classic_mode() || info_->is_native()) { |
+ Label begin; |
+ __ bind(&begin); |
+ Label ok; |
+ __ test(ecx, Operand(ecx)); |
+ __ j(zero, &ok, Label::kNear); |
+ // +1 for return address. |
+ int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize; |
+ __ mov(Operand(esp, receiver_offset), |
+ Immediate(isolate()->factory()->undefined_value())); |
+ __ bind(&ok); |
+ ASSERT(!FLAG_age_code || |
+ (kSizeOfOptimizedStrictModePrologue == ok.pos() - begin.pos())); |
+ } |
} |
- |
if (dynamic_frame_alignment_) { |
Label begin; |
__ bind(&begin); |
@@ -185,10 +190,19 @@ bool LCodeGen::GeneratePrologue() { |
do_not_pad.pos() - begin.pos())); |
} |
- __ push(ebp); // Caller's frame pointer. |
- __ mov(ebp, esp); |
- __ push(esi); // Callee's context. |
- __ push(edi); // Callee's JS function. |
+ if (NeedsEagerFrame()) { |
+ ASSERT(!frame_is_built_); |
+ frame_is_built_ = true; |
+ __ push(ebp); // Caller's frame pointer. |
+ __ mov(ebp, esp); |
+ if (info()->IsStub()) { |
+ __ push(esi); |
Jakob Kummerow
2012/11/28 16:28:22
nit: could hoist this out of the if/else blocks.
danno
2012/11/30 16:23:24
Done.
danno
2012/11/30 16:23:24
Done.
|
+ __ push(Immediate(Smi::FromInt(StackFrame::STUB))); |
+ } else { |
+ __ push(esi); // Callee's context. |
+ __ push(edi); // Callee's JS function. |
+ } |
+ } |
if (dynamic_frame_alignment_ && FLAG_debug_code) { |
__ test(esp, Immediate(kPointerSize)); |
@@ -197,50 +211,52 @@ bool LCodeGen::GeneratePrologue() { |
// Reserve space for the stack slots needed by the code. |
int slots = GetStackSlotCount(); |
- ASSERT_GE(slots, 1); |
- if (slots == 1) { |
- if (dynamic_frame_alignment_) { |
- __ push(edx); |
- } else { |
- __ push(Immediate(kNoAlignmentPadding)); |
- } |
- } else { |
- if (FLAG_debug_code) { |
- __ mov(Operand(eax), Immediate(slots)); |
- Label loop; |
- __ bind(&loop); |
- __ push(Immediate(kSlotsZapValue)); |
- __ dec(eax); |
- __ j(not_zero, &loop); |
+ ASSERT(slots != 0 || !info()->IsOptimizing()); |
+ if (slots > 0) { |
+ if (slots == 1) { |
+ if (dynamic_frame_alignment_) { |
+ __ push(edx); |
+ } else { |
+ __ push(Immediate(kNoAlignmentPadding)); |
+ } |
} else { |
- __ sub(Operand(esp), Immediate(slots * kPointerSize)); |
- #ifdef _MSC_VER |
- // On windows, you may not access the stack more than one page below |
- // the most recently mapped page. To make the allocated area randomly |
- // accessible, we write to each page in turn (the value is irrelevant). |
- const int kPageSize = 4 * KB; |
- for (int offset = slots * kPointerSize - kPageSize; |
- offset > 0; |
- offset -= kPageSize) { |
- __ mov(Operand(esp, offset), eax); |
+ if (FLAG_debug_code) { |
+ __ mov(Operand(eax), Immediate(slots)); |
+ Label loop; |
+ __ bind(&loop); |
+ __ push(Immediate(kSlotsZapValue)); |
+ __ dec(eax); |
+ __ j(not_zero, &loop); |
+ } else { |
+ __ sub(Operand(esp), Immediate(slots * kPointerSize)); |
+#ifdef _MSC_VER |
+ // On windows, you may not access the stack more than one page below |
+ // the most recently mapped page. To make the allocated area randomly |
+ // accessible, we write to each page in turn (the value is irrelevant). |
+ const int kPageSize = 4 * KB; |
+ for (int offset = slots * kPointerSize - kPageSize; |
+ offset > 0; |
+ offset -= kPageSize) { |
+ __ mov(Operand(esp, offset), eax); |
+ } |
+#endif |
} |
- #endif |
- } |
- // Store dynamic frame alignment state in the first local. |
- if (dynamic_frame_alignment_) { |
- __ mov(Operand(ebp, |
- JavaScriptFrameConstants::kDynamicAlignmentStateOffset), |
- edx); |
- } else { |
- __ mov(Operand(ebp, |
- JavaScriptFrameConstants::kDynamicAlignmentStateOffset), |
- Immediate(kNoAlignmentPadding)); |
+ // Store dynamic frame alignment state in the first local. |
+ if (dynamic_frame_alignment_) { |
+ __ mov(Operand(ebp, |
+ JavaScriptFrameConstants::kDynamicAlignmentStateOffset), |
+ edx); |
+ } else { |
+ __ mov(Operand(ebp, |
+ JavaScriptFrameConstants::kDynamicAlignmentStateOffset), |
+ Immediate(kNoAlignmentPadding)); |
+ } |
} |
} |
// Possibly allocate a local context. |
- int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
+ int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
if (heap_slots > 0) { |
Comment(";;; Allocate local context"); |
// Argument to NewContext is the function, which is still in edi. |
@@ -280,7 +296,7 @@ bool LCodeGen::GeneratePrologue() { |
} |
// Trace the call. |
- if (FLAG_trace) { |
+ if (FLAG_trace && info()->IsOptimizing()) { |
// We have not executed any compiled code yet, so esi still holds the |
// incoming context. |
__ CallRuntime(Runtime::kTraceEnter, 0); |
@@ -334,16 +350,104 @@ bool LCodeGen::GenerateBody() { |
} |
+bool LCodeGen::GenerateJumpTable() { |
+ Label needs_frame_not_call; |
+ bool has_generated_needs_frame_not_call = false; |
+ Label needs_frame_is_call; |
+ bool has_generated_needs_frame_is_call = false; |
+ for (int i = 0; i < jump_table_.length(); i++) { |
+ __ bind(&jump_table_[i].label); |
+ Address entry = jump_table_[i].address; |
+ if (jump_table_[i].needs_frame) { |
+ __ push(Immediate(ExternalReference::ForDeoptEntry(entry))); |
+ if (jump_table_[i].is_lazy_deopt) { |
+ if (!has_generated_needs_frame_is_call) { |
Jakob Kummerow
2012/11/28 16:28:22
I think you can replace the check for !has_generat
danno
2012/11/30 16:23:24
Done.
|
+ has_generated_needs_frame_is_call = true; |
+ __ bind(&needs_frame_is_call); |
+ __ push(esi); |
+ // If there is not frame, we don't have access to the JSFunction that |
Jakob Kummerow
2012/11/28 16:28:22
"there is not frame" has not grammar.
Aside from t
danno
2012/11/30 16:23:24
Done.
|
+ // needs to be put into the frame. |
+ ASSERT(info()->IsStub()); |
+ __ push(Immediate(Smi::FromInt(StackFrame::STUB))); |
+ // Push a PC inside the function so that the deopt code can find where |
+ // the deopt comes from. It doesn't have to be the precise return |
+ // address of a "calling" LAZY deopt, it only has to be somewhere |
+ // inside the code body. |
+ Label push_approx_pc; |
+ __ call(&push_approx_pc); |
+ __ bind(&push_approx_pc); |
+ // Push the continuation which was stashed were the ebp should |
+ // be. Replace it with the saved ebp. |
+ __ push(MemOperand(esp, 3 * kPointerSize)); |
+ __ mov(MemOperand(esp, 4 * kPointerSize), ebp); |
+ __ lea(ebp, MemOperand(esp, 4 * kPointerSize)); |
+ __ ret(0); // Call the continuation without clobbering registers. |
+ } else { |
+ __ jmp(&needs_frame_is_call); |
+ } |
+ } else { |
+ if (!has_generated_needs_frame_not_call) { |
Jakob Kummerow
2012/11/28 16:28:22
same here
danno
2012/11/30 16:23:24
Done.
|
+ has_generated_needs_frame_not_call = true; |
+ __ bind(&needs_frame_not_call); |
+ __ push(esi); |
+ // If there is not frame, we don't have access to the JSFunction that |
Jakob Kummerow
2012/11/28 16:28:22
see above.
danno
2012/11/30 16:23:24
Done.
|
+ // needs to be put into the frame. |
+ ASSERT(info()->IsStub()); |
+ __ push(Immediate(Smi::FromInt(StackFrame::STUB))); |
+ // Push the continuation which was stashed were the ebp should |
+ // be. Replace it with the saved ebp. |
+ __ push(MemOperand(esp, 2 * kPointerSize)); |
+ __ mov(MemOperand(esp, 3 * kPointerSize), ebp); |
+ __ lea(ebp, MemOperand(esp, 3 * kPointerSize)); |
+ __ ret(0); // Call the continuation without clobbering registers. |
+ } else { |
+ __ jmp(&needs_frame_not_call); |
+ } |
+ } |
+ } else { |
+ if (jump_table_[i].is_lazy_deopt) { |
+ __ call(entry, RelocInfo::RUNTIME_ENTRY); |
+ } else { |
+ __ jmp(entry, RelocInfo::RUNTIME_ENTRY); |
+ } |
+ } |
+ } |
+ return !is_aborted(); |
+} |
+ |
+ |
bool LCodeGen::GenerateDeferredCode() { |
ASSERT(is_generating()); |
if (deferred_.length() > 0) { |
for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { |
LDeferredCode* code = deferred_[i]; |
__ bind(code->entry()); |
+ if (NeedsDeferredFrame()) { |
+ Comment(";;; Deferred build frame", |
+ code->instruction_index(), |
+ code->instr()->Mnemonic()); |
+ ASSERT(!frame_is_built_); |
+ ASSERT(info()->IsStub()); |
+ frame_is_built_ = true; |
+ // Build the frame in such a way that esi isn't trashed. |
+ __ push(ebp); // Caller's frame pointer. |
+ __ push(Operand(ebp, StandardFrameConstants::kContextOffset)); |
+ __ push(Immediate(Smi::FromInt(StackFrame::STUB))); |
+ __ lea(ebp, Operand(esp, 2 * kPointerSize)); |
+ } |
Comment(";;; Deferred code @%d: %s.", |
code->instruction_index(), |
code->instr()->Mnemonic()); |
code->Generate(); |
+ if (NeedsDeferredFrame()) { |
+ Comment(";;; Deferred destory frame", |
Jakob Kummerow
2012/11/28 16:28:22
nit: "destroy"
danno
2012/11/30 16:23:24
Done.
|
+ code->instruction_index(), |
+ code->instr()->Mnemonic()); |
+ ASSERT(frame_is_built_); |
+ frame_is_built_ = false; |
+ __ mov(esp, ebp); |
+ __ pop(ebp); |
+ } |
__ jmp(code->exit()); |
} |
} |
@@ -357,6 +461,15 @@ bool LCodeGen::GenerateDeferredCode() { |
bool LCodeGen::GenerateSafepointTable() { |
ASSERT(is_done()); |
+ if (!info()->IsStub()) { |
+ // For lazy deoptimization we need space to patch a call after every call. |
+ // Ensure there is always space for such patching, even if the code ends |
+ // in a call. |
+ int target_offset = masm()->pc_offset() + Deoptimizer::patch_size(); |
+ while (masm()->pc_offset() < target_offset) { |
+ masm()->nop(); |
+ } |
+ } |
safepoints_.Emit(masm(), GetStackSlotCount()); |
return !is_aborted(); |
} |
@@ -372,6 +485,11 @@ XMMRegister LCodeGen::ToDoubleRegister(int index) const { |
} |
+bool LCodeGen::IsX87TopOfStack(LOperand* op) const { |
+ return op->IsDoubleRegister(); |
+} |
+ |
+ |
Register LCodeGen::ToRegister(LOperand* op) const { |
ASSERT(op->IsRegister()); |
return ToRegister(op->index()); |
@@ -457,7 +575,9 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, |
translation, |
arguments_index, |
arguments_count); |
- int closure_id = *info()->closure() != *environment->closure() |
+ bool has_closure_id = !info()->closure().is_null() && |
+ *info()->closure() != *environment->closure(); |
+ int closure_id = has_closure_id |
? DefineDeoptimizationLiteral(environment->closure()) |
: Translation::kSelfLiteralId; |
switch (environment->frame_type()) { |
@@ -480,6 +600,11 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, |
case ARGUMENTS_ADAPTOR: |
translation->BeginArgumentsAdaptorFrame(closure_id, translation_size); |
break; |
+ case STUB: |
+ translation->BeginCompiledStubFrame(); |
+ break; |
+ default: |
+ UNREACHABLE(); |
} |
// Inlined frames which push their arguments cause the index to be |
@@ -614,6 +739,8 @@ void LCodeGen::CallRuntime(const Runtime::Function* fun, |
__ CallRuntime(fun, argc); |
RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); |
+ |
+ ASSERT(info()->is_calling()); |
} |
@@ -638,6 +765,8 @@ void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, |
__ CallRuntimeSaveDoubles(id); |
RecordSafepointWithRegisters( |
instr->pointer_map(), argc, Safepoint::kNoLazyDeopt); |
+ |
+ ASSERT(info()->is_calling()); |
} |
@@ -683,7 +812,11 @@ void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { |
RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); |
ASSERT(environment->HasBeenRegistered()); |
int id = environment->deoptimization_index(); |
- Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); |
+ ASSERT(info()->IsOptimizing() || info()->IsStub()); |
+ Deoptimizer::BailoutType bailout_type = frame_is_built_ |
+ ? Deoptimizer::EAGER |
+ : Deoptimizer::LAZY; |
+ Address entry = Deoptimizer::GetDeoptimizationEntry(id, bailout_type); |
if (entry == NULL) { |
Abort("bailout was not prepared"); |
return; |
@@ -717,19 +850,44 @@ void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { |
__ popfd(); |
} |
+ ASSERT(info()->IsStub() || frame_is_built_); |
+ bool lazy_deopt_needed = info()->IsStub(); |
if (cc == no_condition) { |
if (FLAG_trap_on_deopt) __ int3(); |
- __ jmp(entry, RelocInfo::RUNTIME_ENTRY); |
+ if (lazy_deopt_needed) { |
+ __ call(entry, RelocInfo::RUNTIME_ENTRY); |
+ } else { |
+ __ jmp(entry, RelocInfo::RUNTIME_ENTRY); |
+ } |
} else { |
+ Label done; |
if (FLAG_trap_on_deopt) { |
- Label done; |
__ j(NegateCondition(cc), &done, Label::kNear); |
__ int3(); |
- __ jmp(entry, RelocInfo::RUNTIME_ENTRY); |
- __ bind(&done); |
+ } |
+ if (!lazy_deopt_needed && frame_is_built_) { |
+ if (FLAG_trap_on_deopt) { |
+ __ jmp(entry, RelocInfo::RUNTIME_ENTRY); |
+ } else { |
+ __ j(cc, entry, RelocInfo::RUNTIME_ENTRY); |
+ } |
} else { |
- __ j(cc, entry, RelocInfo::RUNTIME_ENTRY); |
+ // We often have several deopts to the same entry, reuse the last |
+ // jump entry if this is the case. |
+ if (jump_table_.is_empty() || |
+ jump_table_.last().address != entry || |
+ jump_table_.last().needs_frame != !frame_is_built_ || |
+ jump_table_.last().is_lazy_deopt != lazy_deopt_needed) { |
+ JumpTableEntry table_entry(entry, !frame_is_built_, lazy_deopt_needed); |
+ jump_table_.Add(table_entry, zone()); |
+ } |
+ if (FLAG_trap_on_deopt) { |
+ __ jmp(&jump_table_.last().label); |
+ } else { |
+ __ j(cc, &jump_table_.last().label); |
+ } |
} |
+ __ bind(&done); |
} |
} |
@@ -1430,7 +1588,8 @@ void LCodeGen::DoConstantD(LConstantD* instr) { |
int32_t lower = static_cast<int32_t>(int_val); |
int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt)); |
if (CpuFeatures::IsSupported(SSE4_1)) { |
- CpuFeatures::Scope scope(SSE4_1); |
+ CpuFeatures::Scope scope1(SSE2); |
+ CpuFeatures::Scope scope2(SSE4_1); |
if (lower != 0) { |
__ Set(temp, Immediate(lower)); |
__ movd(res, Operand(temp)); |
@@ -1442,6 +1601,8 @@ void LCodeGen::DoConstantD(LConstantD* instr) { |
__ pinsrd(res, Operand(temp), 1); |
} |
} else { |
+ ASSERT(CpuFeatures::IsSupported(SSE2)); |
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed. The Scope c'tor right below conta
danno
2012/11/30 16:23:24
Done.
|
+ CpuFeatures::Scope scope(SSE2); |
__ Set(temp, Immediate(upper)); |
__ movd(res, Operand(temp)); |
__ psllq(res, 32); |
@@ -1595,6 +1756,7 @@ void LCodeGen::DoAddI(LAddI* instr) { |
void LCodeGen::DoMathMinMax(LMathMinMax* instr) { |
+ CpuFeatures::Scope scope(SSE2); |
LOperand* left = instr->left(); |
LOperand* right = instr->right(); |
ASSERT(left->Equals(instr->result())); |
@@ -1656,6 +1818,8 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) { |
void LCodeGen::DoArithmeticD(LArithmeticD* instr) { |
+ ASSERT(CpuFeatures::IsSupported(SSE2)); |
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
+ CpuFeatures::Scope scope(SSE2); |
XMMRegister left = ToDoubleRegister(instr->left()); |
XMMRegister right = ToDoubleRegister(instr->right()); |
XMMRegister result = ToDoubleRegister(instr->result()); |
@@ -1666,8 +1830,8 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) { |
__ addsd(left, right); |
break; |
case Token::SUB: |
- __ subsd(left, right); |
- break; |
+ __ subsd(left, right); |
+ break; |
case Token::MUL: |
__ mulsd(left, right); |
break; |
@@ -1740,6 +1904,7 @@ void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) { |
void LCodeGen::DoBranch(LBranch* instr) { |
int true_block = chunk_->LookupDestination(instr->true_block_id()); |
int false_block = chunk_->LookupDestination(instr->false_block_id()); |
+ CpuFeatures::Scope scope(SSE2); |
Representation r = instr->hydrogen()->value()->representation(); |
if (r.IsInteger32()) { |
@@ -1899,6 +2064,7 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { |
int false_block = chunk_->LookupDestination(instr->false_block_id()); |
int true_block = chunk_->LookupDestination(instr->true_block_id()); |
Condition cc = TokenToCondition(instr->op(), instr->is_double()); |
+ CpuFeatures::Scope scope(SSE2); |
if (left->IsConstantOperand() && right->IsConstantOperand()) { |
// We can statically evaluate the comparison. |
@@ -2408,7 +2574,7 @@ void LCodeGen::DoCmpT(LCmpT* instr) { |
void LCodeGen::DoReturn(LReturn* instr) { |
- if (FLAG_trace) { |
+ if (FLAG_trace && info()->IsOptimizing()) { |
// Preserve the return value on the stack and rely on the runtime call |
// to return the value in the same register. We're leaving the code |
// managed by the register allocator and tearing down the frame, it's |
@@ -2422,8 +2588,10 @@ void LCodeGen::DoReturn(LReturn* instr) { |
__ mov(edx, Operand(ebp, |
JavaScriptFrameConstants::kDynamicAlignmentStateOffset)); |
} |
- __ mov(esp, ebp); |
- __ pop(ebp); |
+ if (NeedsEagerFrame()) { |
+ __ mov(esp, ebp); |
+ __ pop(ebp); |
+ } |
if (dynamic_frame_alignment_) { |
Label no_padding; |
__ cmp(edx, Immediate(kNoAlignmentPadding)); |
@@ -2436,7 +2604,12 @@ void LCodeGen::DoReturn(LReturn* instr) { |
__ Ret((GetParameterCount() + 2) * kPointerSize, ecx); |
__ bind(&no_padding); |
} |
- __ Ret((GetParameterCount() + 1) * kPointerSize, ecx); |
+ if (info()->IsStub()) { |
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
+ __ Ret(); |
+ } else { |
+ __ Ret((GetParameterCount() + 1) * kPointerSize, ecx); |
+ } |
} |
@@ -2812,11 +2985,23 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { |
0, |
instr->additional_index())); |
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { |
- XMMRegister result(ToDoubleRegister(instr->result())); |
- __ movss(result, operand); |
- __ cvtss2sd(result, result); |
+ if (CpuFeatures::IsSupported(SSE2)) { |
+ CpuFeatures::Scope scope(SSE2); |
+ XMMRegister result(ToDoubleRegister(instr->result())); |
+ __ movss(result, operand); |
+ __ cvtss2sd(result, result); |
+ } else { |
+ __ fld_s(operand); |
+ HandleX87FPReturnValue(instr); |
+ } |
} else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { |
- __ movdbl(ToDoubleRegister(instr->result()), operand); |
+ if (CpuFeatures::IsSupported(SSE2)) { |
+ CpuFeatures::Scope scope(SSE2); |
+ __ movdbl(ToDoubleRegister(instr->result()), operand); |
+ } else { |
+ __ fld_d(operand); |
+ HandleX87FPReturnValue(instr); |
+ } |
} else { |
Register result(ToRegister(instr->result())); |
switch (elements_kind) { |
@@ -2860,9 +3045,30 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { |
} |
-void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { |
- XMMRegister result = ToDoubleRegister(instr->result()); |
+void LCodeGen::HandleX87FPReturnValue(LInstruction* instr) { |
+ if (IsX87TopOfStack(instr->result())) { |
+ // Return value is already on stack. If the value has no uses, then |
+ // pop it off the FP stack. Otherwise, make sure that there are enough |
+ // copies of the value on the stack to feed all of the usages, e.g. |
+ // when the following instruction uses the return value in multiple |
+ // inputs. |
+ int count = instr->hydrogen_value()->UseCount(); |
+ if (count == 0) { |
+ __ fstp(0); |
+ } else { |
+ count--; |
+ ASSERT(count <= 7); |
+ while (count-- > 0) { |
+ __ fld(0); |
+ } |
+ } |
+ } else { |
+ __ fstp_d(ToOperand(instr->result())); |
+ } |
+} |
+ |
+void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { |
if (instr->hydrogen()->RequiresHoleCheck()) { |
int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag + |
sizeof(kHoleNanLower32); |
@@ -2883,7 +3089,14 @@ void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { |
FAST_DOUBLE_ELEMENTS, |
FixedDoubleArray::kHeaderSize - kHeapObjectTag, |
instr->additional_index()); |
- __ movdbl(result, double_load_operand); |
+ if (CpuFeatures::IsSupported(SSE2)) { |
+ CpuFeatures::Scope scope(SSE2); |
+ XMMRegister result = ToDoubleRegister(instr->result()); |
+ __ movdbl(result, double_load_operand); |
+ } else { |
+ __ fld_d(double_load_operand); |
+ HandleX87FPReturnValue(instr); |
+ } |
} |
@@ -3299,6 +3512,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { |
ASSERT(instr->value()->Equals(instr->result())); |
Representation r = instr->hydrogen()->value()->representation(); |
+ CpuFeatures::Scope scope(SSE2); |
if (r.IsDouble()) { |
XMMRegister scratch = xmm0; |
XMMRegister input_reg = ToDoubleRegister(instr->value()); |
@@ -3320,6 +3534,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { |
void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { |
+ CpuFeatures::Scope scope(SSE2); |
XMMRegister xmm_scratch = xmm0; |
Register output_reg = ToRegister(instr->result()); |
XMMRegister input_reg = ToDoubleRegister(instr->value()); |
@@ -3384,6 +3599,7 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { |
} |
void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { |
+ CpuFeatures::Scope scope(SSE2); |
XMMRegister xmm_scratch = xmm0; |
Register output_reg = ToRegister(instr->result()); |
XMMRegister input_reg = ToDoubleRegister(instr->value()); |
@@ -3429,6 +3645,7 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { |
void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { |
+ CpuFeatures::Scope scope(SSE2); |
XMMRegister input_reg = ToDoubleRegister(instr->value()); |
ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); |
__ sqrtsd(input_reg, input_reg); |
@@ -3436,6 +3653,7 @@ void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { |
void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) { |
+ CpuFeatures::Scope scope(SSE2); |
XMMRegister xmm_scratch = xmm0; |
XMMRegister input_reg = ToDoubleRegister(instr->value()); |
Register scratch = ToRegister(instr->temp()); |
@@ -3512,6 +3730,7 @@ void LCodeGen::DoRandom(LRandom* instr) { |
DeferredDoRandom* deferred = new(zone()) DeferredDoRandom(this, instr); |
+ CpuFeatures::Scope scope(SSE2); |
// Having marked this instruction as a call we can use any |
// registers. |
ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); |
@@ -3579,6 +3798,7 @@ void LCodeGen::DoDeferredRandom(LRandom* instr) { |
void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { |
+ CpuFeatures::Scope scope(SSE2); |
ASSERT(instr->value()->Equals(instr->result())); |
XMMRegister input_reg = ToDoubleRegister(instr->value()); |
Label positive, done, zero; |
@@ -3610,6 +3830,8 @@ void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { |
void LCodeGen::DoMathExp(LMathExp* instr) { |
+ ASSERT(CpuFeatures::IsSupported(SSE2)); |
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
+ CpuFeatures::Scope scope(SSE2); |
XMMRegister input = ToDoubleRegister(instr->value()); |
XMMRegister result = ToDoubleRegister(instr->result()); |
Register temp1 = ToRegister(instr->temp1()); |
@@ -3878,6 +4100,11 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { |
} |
DeoptimizeIf(below_equal, instr->environment()); |
} else { |
+ if (instr->hydrogen()->index()->representation().IsTagged() && |
+ !instr->hydrogen()->index()->type().IsSmi()) { |
+ __ test(ToRegister(instr->index()), Immediate(kSmiTagMask)); |
+ DeoptimizeIf(not_zero, instr->environment()); |
+ } |
__ cmp(ToRegister(instr->index()), ToOperand(instr->length())); |
DeoptimizeIf(above_equal, instr->environment()); |
} |
@@ -3900,9 +4127,11 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { |
0, |
instr->additional_index())); |
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { |
+ CpuFeatures::Scope scope(SSE2); |
__ cvtsd2ss(xmm0, ToDoubleRegister(instr->value())); |
__ movss(operand, xmm0); |
} else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { |
+ CpuFeatures::Scope scope(SSE2); |
__ movdbl(operand, ToDoubleRegister(instr->value())); |
} else { |
Register value = ToRegister(instr->value()); |
@@ -3938,6 +4167,7 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { |
void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { |
+ CpuFeatures::Scope scope(SSE2); |
XMMRegister value = ToDoubleRegister(instr->value()); |
if (instr->NeedsCanonicalization()) { |
@@ -4188,15 +4418,21 @@ void LCodeGen::DoStringAdd(LStringAdd* instr) { |
void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { |
- LOperand* input = instr->value(); |
- ASSERT(input->IsRegister() || input->IsStackSlot()); |
- LOperand* output = instr->result(); |
- ASSERT(output->IsDoubleRegister()); |
- __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input)); |
+ if (CpuFeatures::IsSupported(SSE2)) { |
+ CpuFeatures::Scope scope(SSE2); |
+ LOperand* input = instr->value(); |
+ ASSERT(input->IsRegister() || input->IsStackSlot()); |
+ LOperand* output = instr->result(); |
+ ASSERT(output->IsDoubleRegister()); |
+ __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input)); |
+ } else { |
+ UNREACHABLE(); |
+ } |
} |
void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) { |
+ CpuFeatures::Scope scope(SSE2); |
LOperand* input = instr->value(); |
LOperand* output = instr->result(); |
LOperand* temp = instr->temp(); |
@@ -4274,9 +4510,21 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, |
// the value in there. If that fails, call the runtime system. |
__ SmiUntag(reg); |
__ xor_(reg, 0x80000000); |
- __ cvtsi2sd(xmm0, Operand(reg)); |
+ if (CpuFeatures::IsSupported(SSE2)) { |
+ CpuFeatures::Scope feature_scope(SSE2); |
+ __ cvtsi2sd(xmm0, Operand(reg)); |
+ } else { |
+ __ push(reg); |
+ __ fild_s(Operand(esp, 0)); |
+ __ pop(reg); |
+ } |
} else { |
- __ LoadUint32(xmm0, reg, xmm1); |
+ if (CpuFeatures::IsSupported(SSE2)) { |
+ CpuFeatures::Scope feature_scope(SSE2); |
+ __ LoadUint32(xmm0, reg, xmm1); |
+ } else { |
+ UNREACHABLE(); |
+ } |
} |
if (FLAG_inline_new) { |
@@ -4305,7 +4553,12 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, |
// Done. Put the value in xmm0 into the value of the allocated heap |
// number. |
__ bind(&done); |
- __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0); |
+ if (CpuFeatures::IsSupported(SSE2)) { |
+ CpuFeatures::Scope feature_scope(SSE2); |
+ __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0); |
+ } else { |
+ __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset)); |
+ } |
__ StoreToSafepointRegisterSlot(reg, reg); |
} |
@@ -4321,7 +4574,6 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { |
LNumberTagD* instr_; |
}; |
- XMMRegister input_reg = ToDoubleRegister(instr->value()); |
Register reg = ToRegister(instr->result()); |
Register tmp = ToRegister(instr->temp()); |
@@ -4332,7 +4584,16 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { |
__ jmp(deferred->entry()); |
} |
__ bind(deferred->exit()); |
- __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg); |
+ if (CpuFeatures::IsSupported(SSE2)) { |
+ CpuFeatures::Scope scope(SSE2); |
+ XMMRegister input_reg = ToDoubleRegister(instr->value()); |
+ __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg); |
+ } else { |
+ if (!IsX87TopOfStack(instr->value())) { |
+ __ fld_d(ToOperand(instr->value())); |
+ } |
+ __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset)); |
+ } |
} |
@@ -4489,7 +4750,8 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { |
DeoptimizeIf(not_equal, instr->environment()); |
DeoptimizeIf(parity_even, instr->environment()); // NaN. |
} |
- } else { |
+ } else if (CpuFeatures::IsSupported(SSE2)) { |
+ CpuFeatures::Scope scope(SSE2); |
// Deoptimize if we don't have a heap number. |
__ RecordComment("Deferred TaggedToI: not a heap number"); |
DeoptimizeIf(not_equal, instr->environment()); |
@@ -4511,6 +4773,8 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { |
__ RecordComment("Deferred TaggedToI: minus zero"); |
DeoptimizeIf(not_zero, instr->environment()); |
} |
+ } else { |
+ UNREACHABLE(); |
} |
__ bind(&done); |
} |
@@ -4553,19 +4817,24 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { |
LOperand* result = instr->result(); |
ASSERT(result->IsDoubleRegister()); |
- Register input_reg = ToRegister(input); |
- XMMRegister result_reg = ToDoubleRegister(result); |
- |
- bool deoptimize_on_minus_zero = |
- instr->hydrogen()->deoptimize_on_minus_zero(); |
- Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg; |
- |
- EmitNumberUntagD(input_reg, |
- temp_reg, |
- result_reg, |
- instr->hydrogen()->deoptimize_on_undefined(), |
- deoptimize_on_minus_zero, |
- instr->environment()); |
+ if (CpuFeatures::IsSupported(SSE2)) { |
+ CpuFeatures::Scope scope(SSE2); |
+ Register input_reg = ToRegister(input); |
+ XMMRegister result_reg = ToDoubleRegister(result); |
+ |
+ bool deoptimize_on_minus_zero = |
+ instr->hydrogen()->deoptimize_on_minus_zero(); |
+ Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg; |
+ |
+ EmitNumberUntagD(input_reg, |
+ temp_reg, |
+ result_reg, |
+ instr->hydrogen()->deoptimize_on_undefined(), |
+ deoptimize_on_minus_zero, |
+ instr->environment()); |
+ } else { |
+ UNIMPLEMENTED(); |
+ } |
} |
@@ -4574,6 +4843,7 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) { |
ASSERT(input->IsDoubleRegister()); |
LOperand* result = instr->result(); |
ASSERT(result->IsRegister()); |
+ CpuFeatures::Scope scope(SSE2); |
XMMRegister input_reg = ToDoubleRegister(input); |
Register result_reg = ToRegister(result); |
@@ -4763,10 +5033,10 @@ void LCodeGen::DoCheckFunction(LCheckFunction* instr) { |
void LCodeGen::DoCheckMapCommon(Register reg, |
Handle<Map> map, |
CompareMapMode mode, |
- LEnvironment* env) { |
+ LInstruction* instr) { |
Label success; |
__ CompareMap(reg, map, &success, mode); |
- DeoptimizeIf(not_equal, env); |
+ DeoptimizeIf(not_equal, instr->environment()); |
__ bind(&success); |
} |
@@ -4784,12 +5054,14 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) { |
__ j(equal, &success); |
} |
Handle<Map> map = map_set->last(); |
- DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr->environment()); |
+ DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr); |
__ bind(&success); |
} |
void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { |
+ ASSERT(CpuFeatures::IsSupported(SSE2)); |
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
|
+ CpuFeatures::Scope scope(SSE2); |
XMMRegister value_reg = ToDoubleRegister(instr->unclamped()); |
Register result_reg = ToRegister(instr->result()); |
__ ClampDoubleToUint8(value_reg, xmm0, result_reg); |
@@ -4804,6 +5076,9 @@ void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) { |
void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { |
+ ASSERT(CpuFeatures::IsSupported(SSE2)); |
Jakob Kummerow
2012/11/28 16:28:22
nit: not needed
danno
2012/11/30 16:23:24
Done.
|
+ CpuFeatures::Scope scope(SSE2); |
+ |
ASSERT(instr->unclamped()->Equals(instr->result())); |
Register input_reg = ToRegister(instr->unclamped()); |
Label is_smi, done, heap_number; |
@@ -4850,7 +5125,7 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { |
// Check prototype maps up to the holder. |
while (!current_prototype.is_identical_to(holder)) { |
DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()), |
- ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment()); |
+ ALLOW_ELEMENT_TRANSITION_MAPS, instr); |
current_prototype = |
Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype())); |
@@ -4860,7 +5135,7 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { |
// Check the holder map. |
DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()), |
- ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment()); |
+ ALLOW_ELEMENT_TRANSITION_MAPS, instr); |
} |
@@ -5397,13 +5672,15 @@ void LCodeGen::EmitIsConstructCall(Register temp) { |
void LCodeGen::EnsureSpaceForLazyDeopt() { |
- // Ensure that we have enough space after the previous lazy-bailout |
- // instruction for patching the code here. |
- int current_pc = masm()->pc_offset(); |
- int patch_size = Deoptimizer::patch_size(); |
- if (current_pc < last_lazy_deopt_pc_ + patch_size) { |
- int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc; |
- __ Nop(padding_size); |
+ if (!info()->IsStub()) { |
+ // Ensure that we have enough space after the previous lazy-bailout |
+ // instruction for patching the code here. |
+ int current_pc = masm()->pc_offset(); |
+ int patch_size = Deoptimizer::patch_size(); |
+ if (current_pc < last_lazy_deopt_pc_ + patch_size) { |
+ int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc; |
+ __ Nop(padding_size); |
+ } |
} |
last_lazy_deopt_pc_ = masm()->pc_offset(); |
} |