Chromium Code Reviews| 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(); |
| } |