Index: src/compiler/bytecode-graph-builder.cc |
diff --git a/src/compiler/bytecode-graph-builder.cc b/src/compiler/bytecode-graph-builder.cc |
index dec8194611fdd1b0c4534207928544575764d8e1..dbf7756bceb3447430729bc9717133016cca6297 100644 |
--- a/src/compiler/bytecode-graph-builder.cc |
+++ b/src/compiler/bytecode-graph-builder.cc |
@@ -375,7 +375,6 @@ bool BytecodeGraphBuilder::Environment::StateValuesAreUpToDate( |
1, output_poke_start, output_poke_end); |
} |
- |
BytecodeGraphBuilder::BytecodeGraphBuilder(Zone* local_zone, |
CompilationInfo* compilation_info, |
JSGraph* jsgraph) |
@@ -383,6 +382,8 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(Zone* local_zone, |
info_(compilation_info), |
jsgraph_(jsgraph), |
bytecode_array_(handle(info()->shared_info()->bytecode_array())), |
+ exception_handler_table_( |
+ handle(HandlerTable::cast(bytecode_array()->handler_table()))), |
frame_state_function_info_(common()->CreateFrameStateFunctionInfo( |
FrameStateType::kInterpretedFunction, |
bytecode_array()->parameter_count(), |
@@ -390,11 +391,12 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(Zone* local_zone, |
CALL_MAINTAINS_NATIVE_CONTEXT)), |
merge_environments_(local_zone), |
loop_header_environments_(local_zone), |
+ exception_handlers_(local_zone), |
+ current_exception_handler_(0), |
input_buffer_size_(0), |
input_buffer_(nullptr), |
exit_controls_(local_zone) {} |
- |
Node* BytecodeGraphBuilder::GetNewTarget() { |
if (!new_target_.is_set()) { |
int params = bytecode_array()->parameter_count(); |
@@ -527,6 +529,7 @@ void BytecodeGraphBuilder::VisitBytecodes() { |
while (!iterator.done()) { |
int current_offset = iterator.current_offset(); |
if (analysis.is_reachable(current_offset)) { |
+ EnterAndExitExceptionHandlers(current_offset); |
MergeEnvironmentsOfForwardBranches(current_offset); |
BuildLoopHeaderForBackwardBranches(current_offset); |
@@ -543,6 +546,7 @@ void BytecodeGraphBuilder::VisitBytecodes() { |
} |
set_branch_analysis(nullptr); |
set_bytecode_iterator(nullptr); |
+ DCHECK(exception_handlers_.empty()); |
} |
@@ -1949,6 +1953,27 @@ Node** BytecodeGraphBuilder::EnsureInputBufferSize(int size) { |
return input_buffer_; |
} |
+void BytecodeGraphBuilder::EnterAndExitExceptionHandlers(int current_offset) { |
+ Handle<HandlerTable> table = exception_handler_table(); |
+ int num_entries = table->NumberOfRangeEntries(); |
+ |
+ // Potentially exit exception handlers. |
+ while (!exception_handlers_.empty()) { |
+ int current_end = exception_handlers_.top().end_offset_; |
+ if (current_offset < current_end) break; // Still covered by range. |
+ exception_handlers_.pop(); |
+ } |
+ |
+ // Potentially enter exception handlers. |
+ while (current_exception_handler_ < num_entries) { |
+ int next_start = table->GetRangeStart(current_exception_handler_); |
+ if (current_offset < next_start) break; // Not yet covered by range. |
+ int next_end = table->GetRangeEnd(current_exception_handler_); |
+ int next_handler = table->GetRangeHandler(current_exception_handler_); |
+ exception_handlers_.push({next_start, next_end, next_handler}); |
+ current_exception_handler_++; |
+ } |
+} |
void BytecodeGraphBuilder::PrepareEntryFrameState(Node* node) { |
DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); |
@@ -1976,6 +2001,7 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count, |
if (!has_context && frame_state_count == 0 && !has_control && !has_effect) { |
result = graph()->NewNode(op, value_input_count, value_inputs, incomplete); |
} else { |
+ bool inside_handler = !exception_handlers_.empty(); |
int input_count_with_deps = value_input_count; |
if (has_context) ++input_count_with_deps; |
input_count_with_deps += frame_state_count; |
@@ -2009,11 +2035,32 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count, |
if (result->op()->EffectOutputCount() > 0) { |
environment()->UpdateEffectDependency(result); |
} |
+ // Add implicit exception continuation for throwing nodes. |
+ if (!result->op()->HasProperty(Operator::kNoThrow) && inside_handler) { |
+ int throw_offset = bytecode_iterator()->current_offset(); |
+ int handler_offset = exception_handlers_.top().handler_offset_; |
+ // TODO(mstarzinger): Thread through correct prediction! |
+ IfExceptionHint hint = IfExceptionHint::kLocallyCaught; |
+ // TODO(mstarzinger): For now we mutate the branch analysis result and |
+ // add the artificial control flow from throw-site to handler-entry. |
+ // This can be simplified by pushing environment forward along the |
+ // direction of the data-flow. |
+ branch_analysis_->AddExceptionalBranch(throw_offset, handler_offset); |
+ Environment* success_env = environment()->CopyForConditional(); |
+ const Operator* op = common()->IfException(hint); |
+ Node* effect = environment()->GetEffectDependency(); |
+ Node* on_exception = graph()->NewNode(op, effect, result); |
+ environment()->UpdateControlDependency(on_exception); |
+ environment()->UpdateEffectDependency(on_exception); |
+ environment()->BindAccumulator(on_exception); |
+ BuildJump(throw_offset, handler_offset); |
+ set_environment(success_env); |
+ } |
// Add implicit success continuation for throwing nodes. |
if (!result->op()->HasProperty(Operator::kNoThrow)) { |
const Operator* if_success = common()->IfSuccess(); |
Node* on_success = graph()->NewNode(if_success, result); |
- environment_->UpdateControlDependency(on_success); |
+ environment()->UpdateControlDependency(on_success); |
} |
} |
} |