Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(161)

Unified Diff: src/deoptimizer.cc

Issue 1416543006: [turbofan] Unwind and jump to the catch handler in the deoptimizer. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Rebase, review comments Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/deoptimizer.h ('k') | src/full-codegen/full-codegen.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/deoptimizer.cc
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 63d8462d1f9a8e86ef709c3c60d0dafcc6cd7d71..1e3ff146b5be80b615df6df0a8df9ac2deb85bdd 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -502,7 +502,6 @@ const char* Deoptimizer::MessageFor(BailoutType type) {
return NULL;
}
-
Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction* function,
BailoutType type, unsigned bailout_id, Address from,
int fp_to_sp_delta, Code* optimized_code)
@@ -513,11 +512,19 @@ Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction* function,
from_(from),
fp_to_sp_delta_(fp_to_sp_delta),
has_alignment_padding_(0),
+ deoptimizing_throw_(false),
+ catch_handler_data_(-1),
+ catch_handler_pc_offset_(-1),
input_(nullptr),
output_count_(0),
jsframe_count_(0),
output_(nullptr),
trace_scope_(nullptr) {
+ if (isolate->deoptimizer_lazy_throw()) {
+ isolate->set_deoptimizer_lazy_throw(false);
+ deoptimizing_throw_ = true;
+ }
+
// For COMPILED_STUBs called from builtins, the function pointer is a SMI
// indicating an internal frame.
if (function->IsSmi()) {
@@ -691,6 +698,41 @@ int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
return length;
}
+namespace {
+
+int LookupCatchHandler(TranslatedFrame* translated_frame, int* data_out) {
+ switch (translated_frame->kind()) {
+ case TranslatedFrame::kFunction: {
+ BailoutId node_id = translated_frame->node_id();
+ JSFunction* function =
+ JSFunction::cast(translated_frame->begin()->GetRawValue());
+ Code* non_optimized_code = function->shared()->code();
+ FixedArray* raw_data = non_optimized_code->deoptimization_data();
+ DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
+ unsigned pc_and_state =
+ Deoptimizer::GetOutputInfo(data, node_id, function->shared());
+ unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
+ HandlerTable* table =
+ HandlerTable::cast(non_optimized_code->handler_table());
+ HandlerTable::CatchPrediction prediction;
+ return table->LookupRange(pc_offset, data_out, &prediction);
+ }
+ case TranslatedFrame::kInterpretedFunction: {
+ int bytecode_offset = translated_frame->node_id().ToInt();
+ JSFunction* function =
+ JSFunction::cast(translated_frame->begin()->GetRawValue());
+ BytecodeArray* bytecode = function->shared()->bytecode_array();
+ HandlerTable* table = HandlerTable::cast(bytecode->handler_table());
+ HandlerTable::CatchPrediction prediction;
+ return table->LookupRange(bytecode_offset, data_out, &prediction);
+ }
+ default:
+ break;
+ }
+ return -1;
+}
+
+} // namespace
// We rely on this function not causing a GC. It is called from generated code
// without having a real stack frame in place.
@@ -731,6 +773,22 @@ void Deoptimizer::DoComputeOutputFrames() {
// Do the input frame to output frame(s) translation.
size_t count = translated_state_.frames().size();
+ // If we are supposed to go to the catch handler, find the catching frame
+ // for the catch and make sure we only deoptimize upto that frame.
+ if (deoptimizing_throw_) {
+ size_t catch_handler_frame_index = count;
+ for (size_t i = count; i-- > 0;) {
+ catch_handler_pc_offset_ = LookupCatchHandler(
+ &(translated_state_.frames()[i]), &catch_handler_data_);
+ if (catch_handler_pc_offset_ >= 0) {
+ catch_handler_frame_index = i;
+ break;
+ }
+ }
+ CHECK_LT(catch_handler_frame_index, count);
+ count = catch_handler_frame_index + 1;
+ }
+
DCHECK(output_ == NULL);
output_ = new FrameDescription*[count];
for (size_t i = 0; i < count; ++i) {
@@ -749,11 +807,12 @@ void Deoptimizer::DoComputeOutputFrames() {
int frame_index = static_cast<int>(i);
switch (translated_state_.frames()[i].kind()) {
case TranslatedFrame::kFunction:
- DoComputeJSFrame(frame_index);
+ DoComputeJSFrame(frame_index, deoptimizing_throw_ && i == count - 1);
jsframe_count_++;
break;
case TranslatedFrame::kInterpretedFunction:
- DoComputeInterpretedFrame(frame_index);
+ DoComputeInterpretedFrame(frame_index,
+ deoptimizing_throw_ && i == count - 1);
jsframe_count_++;
break;
case TranslatedFrame::kArgumentsAdaptor:
@@ -798,19 +857,28 @@ void Deoptimizer::DoComputeOutputFrames() {
}
}
-
-void Deoptimizer::DoComputeJSFrame(int frame_index) {
+void Deoptimizer::DoComputeJSFrame(int frame_index, bool goto_catch_handler) {
TranslatedFrame* translated_frame =
&(translated_state_.frames()[frame_index]);
SharedFunctionInfo* shared = translated_frame->raw_shared_info();
TranslatedFrame::iterator value_iterator = translated_frame->begin();
+ bool is_bottommost = (0 == frame_index);
+ bool is_topmost = (output_count_ - 1 == frame_index);
int input_index = 0;
BailoutId node_id = translated_frame->node_id();
unsigned height =
translated_frame->height() - 1; // Do not count the context.
unsigned height_in_bytes = height * kPointerSize;
+ if (goto_catch_handler) {
+ // Take the stack height from the handler table.
+ height = catch_handler_data_;
+ // We also make space for the exception itself.
+ height_in_bytes = (height + 1) * kPointerSize;
+ DCHECK(is_topmost);
+ }
+
JSFunction* function = JSFunction::cast(value_iterator->GetRawValue());
value_iterator++;
input_index++;
@@ -820,6 +888,8 @@ void Deoptimizer::DoComputeJSFrame(int frame_index) {
PrintF(trace_scope_->file(), "%s", name.get());
PrintF(trace_scope_->file(),
" => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes);
+ PrintF(trace_scope_->file(), " => node=%d, height=%d%s\n", node_id.ToInt(),
+ height_in_bytes, goto_catch_handler ? " (throw)" : "");
}
// The 'fixed' part of the frame consists of the incoming parameters and
@@ -833,8 +903,6 @@ void Deoptimizer::DoComputeJSFrame(int frame_index) {
new(output_frame_size) FrameDescription(output_frame_size, function);
output_frame->SetFrameType(StackFrame::JAVA_SCRIPT);
- bool is_bottommost = (0 == frame_index);
- bool is_topmost = (output_count_ - 1 == frame_index);
CHECK(frame_index >= 0 && frame_index < output_count_);
CHECK_NULL(output_[frame_index]);
output_[frame_index] = output_frame;
@@ -935,8 +1003,20 @@ void Deoptimizer::DoComputeJSFrame(int frame_index) {
Register context_reg = JavaScriptFrame::context_register();
output_offset -= kPointerSize;
input_offset -= kPointerSize;
+
+ TranslatedFrame::iterator context_pos = value_iterator;
+ int context_input_index = input_index;
+ // When deoptimizing into a catch block, we need to take the context
+ // from just above the top of the operand stack (we push the context
+ // at the entry of the try block).
+ if (goto_catch_handler) {
+ for (unsigned i = 0; i < height + 1; ++i) {
+ context_pos++;
+ context_input_index++;
+ }
+ }
// Read the context from the translations.
- Object* context = value_iterator->GetRawValue();
+ Object* context = context_pos->GetRawValue();
if (context == isolate_->heap()->undefined_value()) {
// If the context was optimized away, just use the context from
// the activation. This should only apply to Crankshaft code.
@@ -949,13 +1029,13 @@ void Deoptimizer::DoComputeJSFrame(int frame_index) {
value = reinterpret_cast<intptr_t>(context);
output_frame->SetContext(value);
if (is_topmost) output_frame->SetRegister(context_reg.code(), value);
- WriteValueToOutput(context, input_index, frame_index, output_offset,
+ WriteValueToOutput(context, context_input_index, frame_index, output_offset,
"context ");
if (context == isolate_->heap()->arguments_marker()) {
Address output_address =
reinterpret_cast<Address>(output_[frame_index]->GetTop()) +
output_offset;
- values_to_materialize_.push_back({output_address, value_iterator});
+ values_to_materialize_.push_back({output_address, context_pos});
}
value_iterator++;
input_index++;
@@ -975,19 +1055,19 @@ void Deoptimizer::DoComputeJSFrame(int frame_index) {
WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
output_offset);
}
+ if (goto_catch_handler) {
+ // Write out the exception for the catch handler.
+ output_offset -= kPointerSize;
+ Object* exception_obj = reinterpret_cast<Object*>(
+ input_->GetRegister(FullCodeGenerator::result_register().code()));
+ WriteValueToOutput(exception_obj, input_index, frame_index, output_offset,
+ "exception ");
+ input_index++;
+ }
CHECK_EQ(0u, output_offset);
- // Compute this frame's PC, state, and continuation.
- Code* non_optimized_code = shared->code();
- FixedArray* raw_data = non_optimized_code->deoptimization_data();
- DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
- Address start = non_optimized_code->instruction_start();
- unsigned pc_and_state = GetOutputInfo(data, node_id, shared);
- unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
- intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset);
- output_frame->SetPc(pc_value);
-
// Update constant pool.
+ Code* non_optimized_code = shared->code();
if (FLAG_enable_embedded_constant_pool) {
intptr_t constant_pool_value =
reinterpret_cast<intptr_t>(non_optimized_code->constant_pool());
@@ -999,8 +1079,22 @@ void Deoptimizer::DoComputeJSFrame(int frame_index) {
}
}
+ // Compute this frame's PC, state, and continuation.
+ FixedArray* raw_data = non_optimized_code->deoptimization_data();
+ DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
+ Address start = non_optimized_code->instruction_start();
+ unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
+ unsigned pc_offset = goto_catch_handler
+ ? catch_handler_pc_offset_
+ : FullCodeGenerator::PcField::decode(pc_and_state);
+ intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset);
+ output_frame->SetPc(pc_value);
+
+ // If we are going to the catch handler, then the exception lives in
+ // the accumulator.
FullCodeGenerator::State state =
- FullCodeGenerator::StateField::decode(pc_and_state);
+ goto_catch_handler ? FullCodeGenerator::TOS_REG
+ : FullCodeGenerator::StateField::decode(pc_and_state);
output_frame->SetState(Smi::FromInt(state));
// Set the continuation for the topmost frame.
@@ -1019,8 +1113,8 @@ void Deoptimizer::DoComputeJSFrame(int frame_index) {
}
}
-
-void Deoptimizer::DoComputeInterpretedFrame(int frame_index) {
+void Deoptimizer::DoComputeInterpretedFrame(int frame_index,
+ bool goto_catch_handler) {
TranslatedFrame* translated_frame =
&(translated_state_.frames()[frame_index]);
SharedFunctionInfo* shared = translated_frame->raw_shared_info();
@@ -1028,7 +1122,7 @@ void Deoptimizer::DoComputeInterpretedFrame(int frame_index) {
TranslatedFrame::iterator value_iterator = translated_frame->begin();
int input_index = 0;
- BailoutId bytecode_offset = translated_frame->node_id();
+ int bytecode_offset = translated_frame->node_id().ToInt();
unsigned height = translated_frame->height();
unsigned height_in_bytes = height * kPointerSize;
JSFunction* function = JSFunction::cast(value_iterator->GetRawValue());
@@ -1038,8 +1132,12 @@ void Deoptimizer::DoComputeInterpretedFrame(int frame_index) {
PrintF(trace_scope_->file(), " translating interpreted frame ");
base::SmartArrayPointer<char> name = shared->DebugName()->ToCString();
PrintF(trace_scope_->file(), "%s", name.get());
- PrintF(trace_scope_->file(), " => bytecode_offset=%d, height=%d\n",
- bytecode_offset.ToInt(), height_in_bytes);
+ PrintF(trace_scope_->file(), " => bytecode_offset=%d, height=%d%s\n",
+ bytecode_offset, height_in_bytes,
+ goto_catch_handler ? " (throw)" : "");
+ }
+ if (goto_catch_handler) {
+ bytecode_offset = catch_handler_pc_offset_;
}
// The 'fixed' part of the frame consists of the incoming parameters and
@@ -1151,14 +1249,27 @@ void Deoptimizer::DoComputeInterpretedFrame(int frame_index) {
Register context_reg = InterpretedFrame::context_register();
output_offset -= kPointerSize;
input_offset -= kPointerSize;
+
+ // When deoptimizing into a catch block, we need to take the context
+ // from a register that was specified in the handler table.
+ TranslatedFrame::iterator context_pos = value_iterator;
+ int context_input_index = input_index;
+ if (goto_catch_handler) {
+ // Skip to the translated value of the register specified
+ // in the handler table.
+ for (int i = 0; i < catch_handler_data_ + 1; ++i) {
+ context_pos++;
+ context_input_index++;
+ }
+ }
// Read the context from the translations.
- Object* context = value_iterator->GetRawValue();
+ Object* context = context_pos->GetRawValue();
// The context should not be a placeholder for a materialized object.
CHECK(context != isolate_->heap()->arguments_marker());
value = reinterpret_cast<intptr_t>(context);
output_frame->SetContext(value);
if (is_topmost) output_frame->SetRegister(context_reg.code(), value);
- WriteValueToOutput(context, input_index, frame_index, output_offset,
+ WriteValueToOutput(context, context_input_index, frame_index, output_offset,
"context ");
value_iterator++;
input_index++;
@@ -1191,7 +1302,7 @@ void Deoptimizer::DoComputeInterpretedFrame(int frame_index) {
output_offset -= kPointerSize;
input_offset -= kPointerSize;
int raw_bytecode_offset =
- BytecodeArray::kHeaderSize - kHeapObjectTag + bytecode_offset.ToInt();
+ BytecodeArray::kHeaderSize - kHeapObjectTag + bytecode_offset;
Smi* smi_bytecode_offset = Smi::FromInt(raw_bytecode_offset);
WriteValueToOutput(smi_bytecode_offset, 0, frame_index, output_offset,
"bytecode offset ");
@@ -1204,10 +1315,15 @@ void Deoptimizer::DoComputeInterpretedFrame(int frame_index) {
}
CHECK_EQ(0u, output_offset);
- // Set the accumulator register.
- output_frame->SetRegister(
- kInterpreterAccumulatorRegister.code(),
- reinterpret_cast<intptr_t>(value_iterator->GetRawValue()));
+ // Set the accumulator register. If we are lazy deopting to a catch handler,
+ // we set the accumulator to the exception (which lives in the result
+ // register).
+ intptr_t accumulator_value =
+ goto_catch_handler
+ ? input_->GetRegister(FullCodeGenerator::result_register().code())
+ : reinterpret_cast<intptr_t>(value_iterator->GetRawValue());
+ output_frame->SetRegister(kInterpreterAccumulatorRegister.code(),
+ accumulator_value);
value_iterator++;
Builtins* builtins = isolate_->builtins();
« no previous file with comments | « src/deoptimizer.h ('k') | src/full-codegen/full-codegen.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698