Commit e15f5544 authored by Juliana Franco's avatar Juliana Franco Committed by Commit Bot

Changing the return address on the stack.

Rather than patching code, the deoptimizer now replaces the
return address in the frames with respective trampolines. 
This change required to change the way we search for Safepoint 
entries and for Exception Handlers. 
It's working in architectures: x64, ia32, arm, arm64 and mips. 

Bug: V8:6563
Change-Id: I3cbd4d192c3513f307b3a6a2ac99e60d03c753d3
Reviewed-on: https://chromium-review.googlesource.com/586707
Commit-Queue: Juliana Patricia Vicente Franco <jupvfranco@google.com>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46967}
parent d230b44f
......@@ -2688,12 +2688,10 @@ void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
int deoptimization_id, SourcePosition pos) {
DeoptimizeKind deoptimization_kind = GetDeoptimizationKind(deoptimization_id);
DeoptimizeReason deoptimization_reason =
GetDeoptimizationReason(deoptimization_id);
Deoptimizer::BailoutType bailout_type =
deoptimization_kind == DeoptimizeKind::kSoft ? Deoptimizer::SOFT
: Deoptimizer::EAGER;
DeoptimizerCallBailout(deoptimization_id, pos);
Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
__ isolate(), deoptimization_id, bailout_type);
// TODO(turbofan): We should be able to generate better code by sharing the
......
......@@ -2365,12 +2365,10 @@ void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
int deoptimization_id, SourcePosition pos) {
DeoptimizeKind deoptimization_kind = GetDeoptimizationKind(deoptimization_id);
DeoptimizeReason deoptimization_reason =
GetDeoptimizationReason(deoptimization_id);
Deoptimizer::BailoutType bailout_type =
deoptimization_kind == DeoptimizeKind::kSoft ? Deoptimizer::SOFT
: Deoptimizer::EAGER;
DeoptimizerCallBailout(deoptimization_id, pos);
Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
__ isolate(), deoptimization_id, bailout_type);
if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
......
......@@ -81,6 +81,23 @@ void CodeGenerator::CreateFrameAccessState(Frame* frame) {
frame_access_state_ = new (zone()) FrameAccessState(frame);
}
Deoptimizer::BailoutType CodeGenerator::DeoptimizerCallBailout(
int deoptimization_id, SourcePosition pos) {
DeoptimizeKind deopt_kind = GetDeoptimizationKind(deoptimization_id);
switch (deopt_kind) {
case DeoptimizeKind::kSoft: {
return Deoptimizer::SOFT;
}
case DeoptimizeKind::kEager: {
return Deoptimizer::EAGER;
}
case DeoptimizeKind::kLazy: {
return Deoptimizer::LAZY;
}
default: { UNREACHABLE(); }
}
}
void CodeGenerator::AssembleCode() {
CompilationInfo* info = this->info();
......@@ -191,7 +208,11 @@ void CodeGenerator::AssembleCode() {
}
}
// Assemble all eager deoptimization exits.
// This nop operation is needed to ensure that the trampoline is not
// confused with the pc of the call before deoptimization.
// The test regress/regress-259 is an example of where we need it.
tasm()->nop();
// Assemble deoptimization exits.
for (DeoptimizationExit* exit : deoptimization_exits_) {
tasm()->bind(exit->label());
int trampoline_pc = tasm()->pc_offset();
......@@ -201,6 +222,7 @@ void CodeGenerator::AssembleCode() {
AssembleDeoptimizerCall(deoptimization_id, exit->pos());
}
// TODO(juliana): check if we still need this.
// Ensure there is space for lazy deoptimization in the code.
if (info->ShouldEnsureSpaceForLazyDeopt()) {
int target_offset = tasm()->pc_offset() + Deoptimizer::patch_size();
......@@ -651,7 +673,6 @@ void CodeGenerator::RecordCallPosition(Instruction* instr) {
DeoptimizationExit* const exit = new (zone())
DeoptimizationExit(deopt_state_id, current_source_position_);
deoptimization_exits_.push_back(exit);
safepoints()->RecordLazyDeoptimizationIndex(deopt_state_id);
}
}
......
......@@ -149,6 +149,9 @@ class CodeGenerator final : public GapResolver::Assembler {
// adjusted stack pointer is returned in |slot|.
bool GetSlotAboveSPBeforeTailCall(Instruction* instr, int* slot);
Deoptimizer::BailoutType DeoptimizerCallBailout(int deoptimization_id,
SourcePosition pos);
// ===========================================================================
// ============= Architecture-specific code generation methods. ==============
// ===========================================================================
......
......@@ -2401,12 +2401,10 @@ void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
int deoptimization_id, SourcePosition pos) {
DeoptimizeKind deoptimization_kind = GetDeoptimizationKind(deoptimization_id);
DeoptimizeReason deoptimization_reason =
GetDeoptimizationReason(deoptimization_id);
Deoptimizer::BailoutType bailout_type =
deoptimization_kind == DeoptimizeKind::kSoft ? Deoptimizer::SOFT
: Deoptimizer::EAGER;
DeoptimizerCallBailout(deoptimization_id, pos);
Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
__ isolate(), deoptimization_id, bailout_type);
if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
......
......@@ -794,7 +794,7 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
}
int const state_id = sequence()->AddDeoptimizationEntry(
buffer->frame_state_descriptor, DeoptimizeKind::kEager,
buffer->frame_state_descriptor, DeoptimizeKind::kLazy,
DeoptimizeReason::kNoReason);
buffer->instruction_args.push_back(g.TempImmediate(state_id));
......@@ -2723,6 +2723,7 @@ Instruction* InstructionSelector::EmitDeoptimize(
args.push_back(inputs[i]);
}
opcode |= MiscField::encode(static_cast<int>(input_count));
DCHECK_NE(DeoptimizeKind::kLazy, kind);
int const state_id =
sequence()->AddDeoptimizationEntry(descriptor, kind, reason);
args.push_back(g.TempImmediate(state_id));
......
......@@ -3119,12 +3119,10 @@ void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
int deoptimization_id, SourcePosition pos) {
DeoptimizeKind deoptimization_kind = GetDeoptimizationKind(deoptimization_id);
DeoptimizeReason deoptimization_reason =
GetDeoptimizationReason(deoptimization_id);
Deoptimizer::BailoutType bailout_type =
deoptimization_kind == DeoptimizeKind::kSoft ? Deoptimizer::SOFT
: Deoptimizer::EAGER;
DeoptimizerCallBailout(deoptimization_id, pos);
Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
isolate(), deoptimization_id, bailout_type);
if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
......
......@@ -3417,12 +3417,10 @@ void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
int deoptimization_id, SourcePosition pos) {
DeoptimizeKind deoptimization_kind = GetDeoptimizationKind(deoptimization_id);
DeoptimizeReason deoptimization_reason =
GetDeoptimizationReason(deoptimization_id);
Deoptimizer::BailoutType bailout_type =
deoptimization_kind == DeoptimizeKind::kSoft ? Deoptimizer::SOFT
: Deoptimizer::EAGER;
DeoptimizerCallBailout(deoptimization_id, pos);
Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
tasm()->isolate(), deoptimization_id, bailout_type);
if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
......
......@@ -2904,12 +2904,10 @@ void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
int deoptimization_id, SourcePosition pos) {
DeoptimizeKind deoptimization_kind = GetDeoptimizationKind(deoptimization_id);
DeoptimizeReason deoptimization_reason =
GetDeoptimizationReason(deoptimization_id);
Deoptimizer::BailoutType bailout_type =
deoptimization_kind == DeoptimizeKind::kSoft ? Deoptimizer::SOFT
: Deoptimizer::EAGER;
DeoptimizerCallBailout(deoptimization_id, pos);
Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
__ isolate(), deoptimization_id, bailout_type);
if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
......
......@@ -222,10 +222,9 @@ void Deoptimizer::VisitAllOptimizedFunctions(
}
}
// Unlink functions referring to code marked for deoptimization, then move
// marked code from the optimized code list to the deoptimized code list,
// and patch code for lazy deopt.
// and replace pc on the stack for codes marked for deoptimization.
void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) {
DisallowHeapAllocation no_allocation;
......@@ -307,10 +306,7 @@ void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) {
#endif
// Move marked code from the optimized code list to the deoptimized
// code list, collecting them into a ZoneList.
Zone zone(isolate->allocator(), ZONE_NAME);
ZoneList<Code*> codes(10, &zone);
// code list.
// Walk over all optimized code objects in this native context.
Code* prev = NULL;
Object* element = context->OptimizedCodeListHead();
......@@ -320,9 +316,6 @@ void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) {
Object* next = code->next_code_link();
if (code->marked_for_deoptimization()) {
// Put the code into the list for later patching.
codes.Add(code, &zone);
if (prev != NULL) {
// Skip this code in the optimized code list.
prev->set_next_code_link(next);
......@@ -341,26 +334,30 @@ void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) {
element = next;
}
// We need a handle scope only because of the macro assembler,
// which is used in code patching in EnsureCodeForDeoptimizationEntry.
HandleScope scope(isolate);
// Now patch all the codes for deoptimization.
for (int i = 0; i < codes.length(); i++) {
#ifdef DEBUG
if (codes[i] == topmost_optimized_code) {
DCHECK(safe_to_deopt_topmost_optimized_code);
// Finds the with activations of codes marked for deoptimization, search for
// the trampoline to the deoptimizer call respective to each code, and use it
// to replace the current pc on the stack.
for (StackFrameIterator it(isolate, isolate->thread_local_top()); !it.done();
it.Advance()) {
if (it.frame()->type() == StackFrame::OPTIMIZED) {
Code* code = it.frame()->LookupCode();
if (code->kind() == Code::OPTIMIZED_FUNCTION &&
code->marked_for_deoptimization()) {
DeoptimizationInputData* deopt_table =
DeoptimizationInputData::cast(code->deoptimization_data());
// Find index deoptimization input data respective to this code.
SafepointEntry safepoint = code->GetSafepointEntry(it.frame()->pc());
int deopt_index = safepoint.deoptimization_index();
DCHECK(deopt_index != -1);
DCHECK_IMPLIES(code == topmost_optimized_code,
safe_to_deopt_topmost_optimized_code);
// Obtain the trampoline to the deoptimizer call.
Smi* deopt_trampoline = deopt_table->TrampolinePc(deopt_index);
// Replace the current pc on the stack with the trampoline.
it.frame()->set_pc(code->instruction_start() +
deopt_trampoline->value());
}
}
#endif
// It is finally time to die, code object.
// Do platform-specific patching to force any activations to lazy deopt.
PatchCodeForDeoptimization(isolate, codes[i]);
// We might be in the middle of incremental marking with compaction.
// Tell collector to treat this code object in a special way and
// ignore all slots that might have been recorded on it.
isolate->heap()->mark_compact_collector()->InvalidateCode(codes[i]);
}
}
......@@ -996,6 +993,7 @@ void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
DebugPrintOutputSlot(reinterpret_cast<intptr_t>(smi_bytecode_offset),
frame_index, output_offset, "bytecode offset @ ");
PrintF(trace_scope_->file(), "%d\n", bytecode_offset);
PrintF(trace_scope_->file(), " (input #%d)\n", 0);
PrintF(trace_scope_->file(), " -------------------------\n");
}
......
......@@ -1478,6 +1478,19 @@ int OptimizedFrame::LookupExceptionHandlerInTable(
HandlerTable* table = HandlerTable::cast(code->handler_table());
int pc_offset = static_cast<int>(pc() - code->entry());
if (stack_slots) *stack_slots = code->stack_slots();
// When the return pc has been replaced by a trampoline there won't be
// an handler for this trampoline. Thus we need to use the return pc that
// _used to be_ on the stack to get the right ExceptionHandler.
if (code->kind() == Code::OPTIMIZED_FUNCTION &&
code->marked_for_deoptimization()) {
DeoptimizationInputData* deopt_table =
DeoptimizationInputData::cast(code->deoptimization_data());
int ret_pc = deopt_table->TrampolinePcToReturnPc(pc_offset);
if (ret_pc != -1) {
return table->LookupReturn(ret_pc);
}
}
return table->LookupReturn(pc_offset);
}
......
......@@ -348,7 +348,7 @@ const int kNoSourcePosition = -1;
const int kNoDeoptimizationId = -1;
// Deoptimize bailout kind.
enum class DeoptimizeKind : uint8_t { kEager, kSoft };
enum class DeoptimizeKind : uint8_t { kEager, kSoft, kLazy };
inline size_t hash_value(DeoptimizeKind kind) {
return static_cast<size_t>(kind);
}
......@@ -358,6 +358,8 @@ inline std::ostream& operator<<(std::ostream& os, DeoptimizeKind kind) {
return os << "Eager";
case DeoptimizeKind::kSoft:
return os << "Soft";
case DeoptimizeKind::kLazy:
return os << "Lazy";
}
UNREACHABLE();
}
......
......@@ -13989,6 +13989,18 @@ void Code::CopyFrom(const CodeDesc& desc) {
SafepointEntry Code::GetSafepointEntry(Address pc) {
SafepointTable table(this);
if (kind() == OPTIMIZED_FUNCTION && marked_for_deoptimization()) {
DeoptimizationInputData* deopt_table =
DeoptimizationInputData::cast(deoptimization_data());
int pc_offset = static_cast<int>(pc - instruction_start());
// When the return pc has been replaced by a trampoline there won't be
// a safepoint for this trampoline. Thus we need to use the return pc that
// _used to be_ on the stack to get the right SafepointEntry.
int ret_pc = deopt_table->TrampolinePcToReturnPc(pc_offset);
if (ret_pc != -1) {
return table.FindEntry(instruction_start() + ret_pc);
}
}
return table.FindEntry(pc);
}
......@@ -14405,6 +14417,16 @@ void Code::PrintExtraICState(std::ostream& os, // NOLINT
#endif // defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
int DeoptimizationInputData::TrampolinePcToReturnPc(int pc_offset) {
int deopt_total = DeoptCount();
for (int i = 0; i < deopt_total; i++) {
if (TrampolinePc(i)->value() == pc_offset) {
return Pc(i)->value();
}
}
return -1;
}
#ifdef ENABLE_DISASSEMBLER
namespace {
......
......@@ -3590,6 +3590,8 @@ class DeoptimizationInputData: public FixedArray {
inline int DeoptCount();
int TrampolinePcToReturnPc(int pc_offset);
static const int kNotInlinedIndex = -1;
// Returns the inlined function at the given position in LiteralArray, or the
......
......@@ -61,6 +61,7 @@ SafepointEntry SafepointTable::FindEntry(Address pc) const {
// TODO(kasperl): Replace the linear search with binary search.
if (GetPcOffset(i) == pc_offset) return GetEntry(i);
}
UNREACHABLE();
return SafepointEntry();
}
......
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