MIPS: Fix lazy deoptimization at HInvokeFunction and enable target-recording call-function stub.

Port r10006 (4b344a03).

Original commit message:

Changes the way we do lazy deoptimization:

1. For side-effect instructions, we insert the lazy-deopt call at
the following LLazyBailout instruction.

     CALL
     GAP
     LAZY-BAILOUT ==> lazy-deopt-call

2. For other instructions (StackCheck) we insert it right after the
instruction since the deopt targets an earlier deoptimization environment.

   STACK-CHECK
   GAP ==> lazy-deopt-call

The pc of the lazy-deopt call that will be patched in is recorded in the
deoptimization input data. Each Lithium instruction can have 0..n safepoints.
All safepoints get the deoptimization index of the associated LAZY-BAILOUT
instruction. On lazy deoptimization we use the return-pc to find the safepoint.
The safepoint tells us the deoptimization index, which in turn finds us the
PC where to insert the lazy-deopt-call.

Additional changes:
* RegExpLiteral marked it as having side-effects so that it
  gets an explicitlazy-bailout instruction (instead of
  treating it specially like stack-checks)
* Enable target recording CallFunctionStub to achieve
  more inlining on optimized code.

BUG=
TEST=
Review URL: http://codereview.chromium.org/8587008

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10020 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 8fbf1d50
...@@ -45,12 +45,6 @@ int Deoptimizer::patch_size() { ...@@ -45,12 +45,6 @@ int Deoptimizer::patch_size() {
} }
void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
// Nothing to do. No new relocation information is written for lazy
// deoptimization on MIPS.
}
void Deoptimizer::DeoptimizeFunction(JSFunction* function) { void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
HandleScope scope; HandleScope scope;
AssertNoAllocation no_allocation; AssertNoAllocation no_allocation;
...@@ -59,58 +53,38 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { ...@@ -59,58 +53,38 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
// Get the optimized code. // Get the optimized code.
Code* code = function->code(); Code* code = function->code();
Address code_start_address = code->instruction_start();
// Invalidate the relocation information, as it will become invalid by the // Invalidate the relocation information, as it will become invalid by the
// code patching below, and is not needed any more. // code patching below, and is not needed any more.
code->InvalidateRelocation(); code->InvalidateRelocation();
// For each return after a safepoint insert an absolute call to the // For each LLazyBailout instruction insert a call to the corresponding
// corresponding deoptimization entry. // deoptimization entry.
unsigned last_pc_offset = 0; DeoptimizationInputData* deopt_data =
SafepointTable table(function->code()); DeoptimizationInputData::cast(code->deoptimization_data());
for (unsigned i = 0; i < table.length(); i++) {
unsigned pc_offset = table.GetPcOffset(i);
SafepointEntry safepoint_entry = table.GetEntry(i);
int deoptimization_index = safepoint_entry.deoptimization_index();
int gap_code_size = safepoint_entry.gap_code_size();
// Check that we did not shoot past next safepoint.
CHECK(pc_offset >= last_pc_offset);
#ifdef DEBUG #ifdef DEBUG
// Destroy the code which is not supposed to be run again. Address prev_call_address = NULL;
int instructions = (pc_offset - last_pc_offset) / Assembler::kInstrSize;
CodePatcher destroyer(code->instruction_start() + last_pc_offset,
instructions);
for (int x = 0; x < instructions; x++) {
destroyer.masm()->break_(0);
}
#endif #endif
last_pc_offset = pc_offset; for (int i = 0; i < deopt_data->DeoptCount(); i++) {
if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { if (deopt_data->Pc(i)->value() == -1) continue;
Address deoptimization_entry = Deoptimizer::GetDeoptimizationEntry( Address call_address = code_start_address + deopt_data->Pc(i)->value();
deoptimization_index, Deoptimizer::LAZY); Address deopt_entry = GetDeoptimizationEntry(i, LAZY);
last_pc_offset += gap_code_size; int call_size_in_bytes = MacroAssembler::CallSize(deopt_entry,
int call_size_in_bytes = MacroAssembler::CallSize(deoptimization_entry,
RelocInfo::NONE); RelocInfo::NONE);
int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize; int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize;
ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0); ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0);
ASSERT(call_size_in_bytes <= patch_size()); ASSERT(call_size_in_bytes <= patch_size());
CodePatcher patcher(code->instruction_start() + last_pc_offset, CodePatcher patcher(call_address, call_size_in_words);
call_size_in_words); patcher.masm()->Call(deopt_entry, RelocInfo::NONE);
patcher.masm()->Call(deoptimization_entry, RelocInfo::NONE); ASSERT(prev_call_address == NULL ||
last_pc_offset += call_size_in_bytes; call_address >= prev_call_address + patch_size());
} ASSERT(call_address + patch_size() <= code->instruction_end());
}
#ifdef DEBUG #ifdef DEBUG
// Destroy the code which is not supposed to be run again. prev_call_address = call_address;
int instructions =
(code->safepoint_table_offset() - last_pc_offset) / Assembler::kInstrSize;
CodePatcher destroyer(code->instruction_start() + last_pc_offset,
instructions);
for (int x = 0; x < instructions; x++) {
destroyer.masm()->break_(0);
}
#endif #endif
}
Isolate* isolate = code->GetIsolate(); Isolate* isolate = code->GetIsolate();
......
...@@ -40,37 +40,22 @@ class SafepointGenerator : public CallWrapper { ...@@ -40,37 +40,22 @@ class SafepointGenerator : public CallWrapper {
public: public:
SafepointGenerator(LCodeGen* codegen, SafepointGenerator(LCodeGen* codegen,
LPointerMap* pointers, LPointerMap* pointers,
int deoptimization_index) Safepoint::DeoptMode mode)
: codegen_(codegen), : codegen_(codegen),
pointers_(pointers), pointers_(pointers),
deoptimization_index_(deoptimization_index) { } deopt_mode_(mode) { }
virtual ~SafepointGenerator() { } virtual ~SafepointGenerator() { }
virtual void BeforeCall(int call_size) const { virtual void BeforeCall(int call_size) const { }
ASSERT(call_size >= 0);
// Ensure that we have enough space after the previous safepoint position
// for the generated code there.
int call_end = codegen_->masm()->pc_offset() + call_size;
int prev_jump_end =
codegen_->LastSafepointEnd() + Deoptimizer::patch_size();
if (call_end < prev_jump_end) {
int padding_size = prev_jump_end - call_end;
ASSERT_EQ(0, padding_size % Assembler::kInstrSize);
while (padding_size > 0) {
codegen_->masm()->nop();
padding_size -= Assembler::kInstrSize;
}
}
}
virtual void AfterCall() const { virtual void AfterCall() const {
codegen_->RecordSafepoint(pointers_, deoptimization_index_); codegen_->RecordSafepoint(pointers_, deopt_mode_);
} }
private: private:
LCodeGen* codegen_; LCodeGen* codegen_;
LPointerMap* pointers_; LPointerMap* pointers_;
int deoptimization_index_; Safepoint::DeoptMode deopt_mode_;
}; };
...@@ -101,7 +86,6 @@ void LCodeGen::FinishCode(Handle<Code> code) { ...@@ -101,7 +86,6 @@ void LCodeGen::FinishCode(Handle<Code> code) {
code->set_stack_slots(GetStackSlotCount()); code->set_stack_slots(GetStackSlotCount());
code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
PopulateDeoptimizationData(code); PopulateDeoptimizationData(code);
Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
} }
...@@ -198,7 +182,7 @@ bool LCodeGen::GeneratePrologue() { ...@@ -198,7 +182,7 @@ bool LCodeGen::GeneratePrologue() {
} else { } else {
__ CallRuntime(Runtime::kNewFunctionContext, 1); __ CallRuntime(Runtime::kNewFunctionContext, 1);
} }
RecordSafepoint(Safepoint::kNoDeoptimizationIndex); RecordSafepoint(Safepoint::kNoLazyDeopt);
// Context is returned in both v0 and cp. It replaces the context // Context is returned in both v0 and cp. It replaces the context
// passed to us. It's saved in the stack and kept live in cp. // passed to us. It's saved in the stack and kept live in cp.
__ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
...@@ -226,6 +210,7 @@ bool LCodeGen::GeneratePrologue() { ...@@ -226,6 +210,7 @@ bool LCodeGen::GeneratePrologue() {
if (FLAG_trace) { if (FLAG_trace) {
__ CallRuntime(Runtime::kTraceEnter, 0); __ CallRuntime(Runtime::kTraceEnter, 0);
} }
EnsureSpaceForLazyDeopt();
return !is_aborted(); return !is_aborted();
} }
...@@ -251,15 +236,6 @@ bool LCodeGen::GenerateBody() { ...@@ -251,15 +236,6 @@ bool LCodeGen::GenerateBody() {
} }
LInstruction* LCodeGen::GetNextInstruction() {
if (current_instruction_ < instructions_->length() - 1) {
return instructions_->at(current_instruction_ + 1);
} else {
return NULL;
}
}
bool LCodeGen::GenerateDeferredCode() { bool LCodeGen::GenerateDeferredCode() {
ASSERT(is_generating()); ASSERT(is_generating());
if (deferred_.length() > 0) { if (deferred_.length() > 0) {
...@@ -272,13 +248,6 @@ bool LCodeGen::GenerateDeferredCode() { ...@@ -272,13 +248,6 @@ bool LCodeGen::GenerateDeferredCode() {
code->Generate(); code->Generate();
__ jmp(code->exit()); __ jmp(code->exit());
} }
// Pad code to ensure that the last piece of deferred code have
// room for lazy bailout.
while ((masm()->pc_offset() - LastSafepointEnd())
< Deoptimizer::patch_size()) {
__ nop();
}
} }
// Deferred code is the last part of the instruction sequence. Mark // Deferred code is the last part of the instruction sequence. Mark
// the generated code as done unless we bailed out. // the generated code as done unless we bailed out.
...@@ -534,7 +503,7 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code, ...@@ -534,7 +503,7 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code,
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
__ Call(code, mode); __ Call(code, mode);
RegisterLazyDeoptimization(instr, safepoint_mode); RecordSafepointWithLazyDeopt(instr, safepoint_mode);
} }
...@@ -547,7 +516,7 @@ void LCodeGen::CallRuntime(const Runtime::Function* function, ...@@ -547,7 +516,7 @@ void LCodeGen::CallRuntime(const Runtime::Function* function,
RecordPosition(pointers->position()); RecordPosition(pointers->position());
__ CallRuntime(function, num_arguments); __ CallRuntime(function, num_arguments);
RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT); RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
} }
...@@ -556,37 +525,12 @@ void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, ...@@ -556,37 +525,12 @@ void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
LInstruction* instr) { LInstruction* instr) {
__ CallRuntimeSaveDoubles(id); __ CallRuntimeSaveDoubles(id);
RecordSafepointWithRegisters( RecordSafepointWithRegisters(
instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex); instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
} }
void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr, void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
SafepointMode safepoint_mode) { Safepoint::DeoptMode mode) {
// Create the environment to bailout to. If the call has side effects
// execution has to continue after the call otherwise execution can continue
// from a previous bailout point repeating the call.
LEnvironment* deoptimization_environment;
if (instr->HasDeoptimizationEnvironment()) {
deoptimization_environment = instr->deoptimization_environment();
} else {
deoptimization_environment = instr->environment();
}
RegisterEnvironmentForDeoptimization(deoptimization_environment);
if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
RecordSafepoint(instr->pointer_map(),
deoptimization_environment->deoptimization_index());
} else {
ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
RecordSafepointWithRegisters(
instr->pointer_map(),
0,
deoptimization_environment->deoptimization_index());
}
}
void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
if (!environment->HasBeenRegistered()) { if (!environment->HasBeenRegistered()) {
// Physical stack frame layout: // Physical stack frame layout:
// -x ............. -4 0 ..................................... y // -x ............. -4 0 ..................................... y
...@@ -608,7 +552,10 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) { ...@@ -608,7 +552,10 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
Translation translation(&translations_, frame_count); Translation translation(&translations_, frame_count);
WriteTranslation(environment, &translation); WriteTranslation(environment, &translation);
int deoptimization_index = deoptimizations_.length(); int deoptimization_index = deoptimizations_.length();
environment->Register(deoptimization_index, translation.index()); int pc_offset = masm()->pc_offset();
environment->Register(deoptimization_index,
translation.index(),
(mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
deoptimizations_.Add(environment); deoptimizations_.Add(environment);
} }
} }
...@@ -618,7 +565,7 @@ void LCodeGen::DeoptimizeIf(Condition cc, ...@@ -618,7 +565,7 @@ void LCodeGen::DeoptimizeIf(Condition cc,
LEnvironment* environment, LEnvironment* environment,
Register src1, Register src1,
const Operand& src2) { const Operand& src2) {
RegisterEnvironmentForDeoptimization(environment); RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
ASSERT(environment->HasBeenRegistered()); ASSERT(environment->HasBeenRegistered());
int id = environment->deoptimization_index(); int id = environment->deoptimization_index();
Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
...@@ -683,6 +630,7 @@ void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) { ...@@ -683,6 +630,7 @@ void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
data->SetTranslationIndex(i, Smi::FromInt(env->translation_index())); data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
data->SetArgumentsStackHeight(i, data->SetArgumentsStackHeight(i,
Smi::FromInt(env->arguments_stack_height())); Smi::FromInt(env->arguments_stack_height()));
data->SetPc(i, Smi::FromInt(env->pc_offset()));
} }
code->set_deoptimization_data(*data); code->set_deoptimization_data(*data);
} }
...@@ -714,16 +662,28 @@ void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() { ...@@ -714,16 +662,28 @@ void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
} }
void LCodeGen::RecordSafepointWithLazyDeopt(
LInstruction* instr, SafepointMode safepoint_mode) {
if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
} else {
ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
RecordSafepointWithRegisters(
instr->pointer_map(), 0, Safepoint::kLazyDeopt);
}
}
void LCodeGen::RecordSafepoint( void LCodeGen::RecordSafepoint(
LPointerMap* pointers, LPointerMap* pointers,
Safepoint::Kind kind, Safepoint::Kind kind,
int arguments, int arguments,
int deoptimization_index) { Safepoint::DeoptMode deopt_mode) {
ASSERT(expected_safepoint_kind_ == kind); ASSERT(expected_safepoint_kind_ == kind);
const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands(); const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
Safepoint safepoint = safepoints_.DefineSafepoint(masm(), Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
kind, arguments, deoptimization_index); kind, arguments, deopt_mode);
for (int i = 0; i < operands->length(); i++) { for (int i = 0; i < operands->length(); i++) {
LOperand* pointer = operands->at(i); LOperand* pointer = operands->at(i);
if (pointer->IsStackSlot()) { if (pointer->IsStackSlot()) {
...@@ -740,31 +700,31 @@ void LCodeGen::RecordSafepoint( ...@@ -740,31 +700,31 @@ void LCodeGen::RecordSafepoint(
void LCodeGen::RecordSafepoint(LPointerMap* pointers, void LCodeGen::RecordSafepoint(LPointerMap* pointers,
int deoptimization_index) { Safepoint::DeoptMode deopt_mode) {
RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode);
} }
void LCodeGen::RecordSafepoint(int deoptimization_index) { void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
LPointerMap empty_pointers(RelocInfo::kNoPosition); LPointerMap empty_pointers(RelocInfo::kNoPosition);
RecordSafepoint(&empty_pointers, deoptimization_index); RecordSafepoint(&empty_pointers, deopt_mode);
} }
void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index) { Safepoint::DeoptMode deopt_mode) {
RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, RecordSafepoint(
deoptimization_index); pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
} }
void LCodeGen::RecordSafepointWithRegistersAndDoubles( void LCodeGen::RecordSafepointWithRegistersAndDoubles(
LPointerMap* pointers, LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index) { Safepoint::DeoptMode deopt_mode) {
RecordSafepoint(pointers, Safepoint::kWithRegistersAndDoubles, arguments, RecordSafepoint(
deoptimization_index); pointers, Safepoint::kWithRegistersAndDoubles, arguments, deopt_mode);
} }
...@@ -799,12 +759,6 @@ void LCodeGen::DoGap(LGap* gap) { ...@@ -799,12 +759,6 @@ void LCodeGen::DoGap(LGap* gap) {
LParallelMove* move = gap->GetParallelMove(inner_pos); LParallelMove* move = gap->GetParallelMove(inner_pos);
if (move != NULL) DoParallelMove(move); if (move != NULL) DoParallelMove(move);
} }
LInstruction* next = GetNextInstruction();
if (next != NULL && next->IsLazyBailout()) {
int pc = masm()->pc_offset();
safepoints_.SetPcAfterGap(pc);
}
} }
...@@ -1936,7 +1890,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { ...@@ -1936,7 +1890,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
LInstanceOfKnownGlobal* instr) LInstanceOfKnownGlobal* instr)
: LDeferredCode(codegen), instr_(instr) { } : LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() { virtual void Generate() {
codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
} }
virtual LInstruction* instr() { return instr_; } virtual LInstruction* instr() { return instr_; }
Label* map_check() { return &map_check_; } Label* map_check() { return &map_check_; }
...@@ -2004,7 +1958,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { ...@@ -2004,7 +1958,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
} }
void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check) { Label* map_check) {
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
ASSERT(result.is(v0)); ASSERT(result.is(v0));
...@@ -2039,6 +1993,9 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, ...@@ -2039,6 +1993,9 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
RelocInfo::CODE_TARGET, RelocInfo::CODE_TARGET,
instr, instr,
RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
ASSERT(instr->HasDeoptimizationEnvironment());
LEnvironment* env = instr->deoptimization_environment();
safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
// Put the result value into the result register slot and // Put the result value into the result register slot and
// restore all registers. // restore all registers.
__ StoreToSafepointRegisterSlot(result, result); __ StoreToSafepointRegisterSlot(result, result);
...@@ -2665,12 +2622,9 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { ...@@ -2665,12 +2622,9 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
__ bind(&invoke); __ bind(&invoke);
ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env); SafepointGenerator safepoint_generator(
SafepointGenerator safepoint_generator(this, this, pointers, Safepoint::kLazyDeopt);
pointers,
env->deoptimization_index());
// The number of arguments is stored in receiver which is a0, as expected // The number of arguments is stored in receiver which is a0, as expected
// by InvokeFunction. // by InvokeFunction.
v8::internal::ParameterCount actual(receiver); v8::internal::ParameterCount actual(receiver);
...@@ -2753,7 +2707,7 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function, ...@@ -2753,7 +2707,7 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
__ Call(at); __ Call(at);
// Setup deoptimization. // Setup deoptimization.
RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT); RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
// Restore context. // Restore context.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
...@@ -3130,10 +3084,8 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { ...@@ -3130,10 +3084,8 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
ASSERT(instr->HasPointerMap()); ASSERT(instr->HasPointerMap());
ASSERT(instr->HasDeoptimizationEnvironment()); ASSERT(instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env); SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
SafepointGenerator generator(this, pointers, env->deoptimization_index());
ParameterCount count(instr->arity()); ParameterCount count(instr->arity());
__ InvokeFunction(a1, count, CALL_FUNCTION, generator, CALL_AS_METHOD); __ InvokeFunction(a1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
...@@ -4513,9 +4465,29 @@ void LCodeGen::EmitIsConstructCall(Register temp1, Register temp2) { ...@@ -4513,9 +4465,29 @@ void LCodeGen::EmitIsConstructCall(Register temp1, Register temp2) {
} }
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;
ASSERT_EQ(0, padding_size % Assembler::kInstrSize);
while (padding_size > 0) {
__ nop();
padding_size -= Assembler::kInstrSize;
}
}
last_lazy_deopt_pc_ = current_pc;
}
void LCodeGen::DoLazyBailout(LLazyBailout* instr) { void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
// No code for lazy bailout instruction. Used to capture environment after a EnsureSpaceForLazyDeopt();
// call for populating the safepoint data with deoptimization data. ASSERT(instr->HasEnvironment());
LEnvironment* env = instr->environment();
RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
} }
...@@ -4532,12 +4504,9 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { ...@@ -4532,12 +4504,9 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
__ Push(object, key, strict); __ Push(object, key, strict);
ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env); SafepointGenerator safepoint_generator(
SafepointGenerator safepoint_generator(this, this, pointers, Safepoint::kLazyDeopt);
pointers,
env->deoptimization_index());
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
} }
...@@ -4548,27 +4517,20 @@ void LCodeGen::DoIn(LIn* instr) { ...@@ -4548,27 +4517,20 @@ void LCodeGen::DoIn(LIn* instr) {
__ Push(key, obj); __ Push(key, obj);
ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env); SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt);
SafepointGenerator safepoint_generator(this,
pointers,
env->deoptimization_index());
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
} }
void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
{
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
__ CallRuntimeSaveDoubles(Runtime::kStackGuard); __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
RegisterLazyDeoptimization( RecordSafepointWithLazyDeopt(
instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
} ASSERT(instr->HasEnvironment());
LEnvironment* env = instr->environment();
// The gap code includes the restoring of the safepoint registers. safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
int pc = masm()->pc_offset();
safepoints_.SetPcAfterGap(pc);
} }
...@@ -4583,6 +4545,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { ...@@ -4583,6 +4545,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
LStackCheck* instr_; LStackCheck* instr_;
}; };
ASSERT(instr->HasEnvironment());
LEnvironment* env = instr->environment();
// There is no LLazyBailout instruction for stack-checks. We have to
// prepare for lazy deoptimization explicitly here.
if (instr->hydrogen()->is_function_entry()) { if (instr->hydrogen()->is_function_entry()) {
// Perform stack overflow check. // Perform stack overflow check.
Label done; Label done;
...@@ -4590,7 +4556,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { ...@@ -4590,7 +4556,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
__ Branch(&done, hs, sp, Operand(at)); __ Branch(&done, hs, sp, Operand(at));
StackCheckStub stub; StackCheckStub stub;
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
EnsureSpaceForLazyDeopt();
__ bind(&done); __ bind(&done);
RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
} else { } else {
ASSERT(instr->hydrogen()->is_backwards_branch()); ASSERT(instr->hydrogen()->is_backwards_branch());
// Perform stack overflow check if this goto needs it before jumping. // Perform stack overflow check if this goto needs it before jumping.
...@@ -4598,8 +4567,13 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { ...@@ -4598,8 +4567,13 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
new DeferredStackCheck(this, instr); new DeferredStackCheck(this, instr);
__ LoadRoot(at, Heap::kStackLimitRootIndex); __ LoadRoot(at, Heap::kStackLimitRootIndex);
__ Branch(deferred_stack_check->entry(), lo, sp, Operand(at)); __ Branch(deferred_stack_check->entry(), lo, sp, Operand(at));
EnsureSpaceForLazyDeopt();
__ bind(instr->done_label()); __ bind(instr->done_label());
deferred_stack_check->SetExit(instr->done_label()); deferred_stack_check->SetExit(instr->done_label());
RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
// Don't record a deoptimization index for the safepoint here.
// This will be done explicitly when emitting call and the safepoint in
// the deferred code.
} }
} }
...@@ -4615,7 +4589,7 @@ void LCodeGen::DoOsrEntry(LOsrEntry* instr) { ...@@ -4615,7 +4589,7 @@ void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
// If the environment were already registered, we would have no way of // If the environment were already registered, we would have no way of
// backpatching it with the spill slot operands. // backpatching it with the spill slot operands.
ASSERT(!environment->HasBeenRegistered()); ASSERT(!environment->HasBeenRegistered());
RegisterEnvironmentForDeoptimization(environment); RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
ASSERT(osr_pc_offset_ == -1); ASSERT(osr_pc_offset_ == -1);
osr_pc_offset_ = masm()->pc_offset(); osr_pc_offset_ = masm()->pc_offset();
} }
......
...@@ -58,6 +58,7 @@ class LCodeGen BASE_EMBEDDED { ...@@ -58,6 +58,7 @@ class LCodeGen BASE_EMBEDDED {
status_(UNUSED), status_(UNUSED),
deferred_(8), deferred_(8),
osr_pc_offset_(-1), osr_pc_offset_(-1),
last_lazy_deopt_pc_(0),
resolver_(this), resolver_(this),
expected_safepoint_kind_(Safepoint::kSimple) { expected_safepoint_kind_(Safepoint::kSimple) {
PopulateDeoptimizationLiteralsWithInlinedFunctions(); PopulateDeoptimizationLiteralsWithInlinedFunctions();
...@@ -108,7 +109,7 @@ class LCodeGen BASE_EMBEDDED { ...@@ -108,7 +109,7 @@ class LCodeGen BASE_EMBEDDED {
void DoDeferredStackCheck(LStackCheck* instr); void DoDeferredStackCheck(LStackCheck* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredStringCharFromCode(LStringCharFromCode* instr); void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check); Label* map_check);
// Parallel move support. // Parallel move support.
...@@ -212,10 +213,11 @@ class LCodeGen BASE_EMBEDDED { ...@@ -212,10 +213,11 @@ class LCodeGen BASE_EMBEDDED {
void LoadHeapObject(Register result, Handle<HeapObject> object); void LoadHeapObject(Register result, Handle<HeapObject> object);
void RegisterLazyDeoptimization(LInstruction* instr, void RecordSafepointWithLazyDeopt(LInstruction* instr,
SafepointMode safepoint_mode); SafepointMode safepoint_mode);
void RegisterEnvironmentForDeoptimization(LEnvironment* environment); void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
Safepoint::DeoptMode mode);
void DeoptimizeIf(Condition cc, void DeoptimizeIf(Condition cc,
LEnvironment* environment, LEnvironment* environment,
Register src1, Register src1,
...@@ -247,19 +249,16 @@ class LCodeGen BASE_EMBEDDED { ...@@ -247,19 +249,16 @@ class LCodeGen BASE_EMBEDDED {
void RecordSafepoint(LPointerMap* pointers, void RecordSafepoint(LPointerMap* pointers,
Safepoint::Kind kind, Safepoint::Kind kind,
int arguments, int arguments,
int deoptimization_index); Safepoint::DeoptMode mode);
void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
void RecordSafepoint(int deoptimization_index); void RecordSafepoint(Safepoint::DeoptMode mode);
void RecordSafepointWithRegisters(LPointerMap* pointers, void RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index); Safepoint::DeoptMode mode);
void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers, void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index); Safepoint::DeoptMode mode);
void RecordPosition(int position); void RecordPosition(int position);
int LastSafepointEnd() {
return static_cast<int>(safepoints_.GetPcAfterGap());
}
static Condition TokenToCondition(Token::Value op, bool is_unsigned); static Condition TokenToCondition(Token::Value op, bool is_unsigned);
void EmitGoto(int block); void EmitGoto(int block);
...@@ -317,6 +316,8 @@ class LCodeGen BASE_EMBEDDED { ...@@ -317,6 +316,8 @@ class LCodeGen BASE_EMBEDDED {
Address address; Address address;
}; };
void EnsureSpaceForLazyDeopt();
LChunk* const chunk_; LChunk* const chunk_;
MacroAssembler* const masm_; MacroAssembler* const masm_;
CompilationInfo* const info_; CompilationInfo* const info_;
...@@ -333,6 +334,7 @@ class LCodeGen BASE_EMBEDDED { ...@@ -333,6 +334,7 @@ class LCodeGen BASE_EMBEDDED {
TranslationBuffer translations_; TranslationBuffer translations_;
ZoneList<LDeferredCode*> deferred_; ZoneList<LDeferredCode*> deferred_;
int osr_pc_offset_; int osr_pc_offset_;
int last_lazy_deopt_pc_;
// Builder that keeps track of safepoints in the code. The table // Builder that keeps track of safepoints in the code. The table
// itself is emitted at the end of the generated code. // itself is emitted at the end of the generated code.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment