Index: src/compiler/js-inlining.cc |
diff --git a/src/compiler/js-inlining.cc b/src/compiler/js-inlining.cc |
index 635daa4d761421e87dd10f7ff060e7598ce91803..ac4100ab776e9517c7ac089913e18324cf88f45b 100644 |
--- a/src/compiler/js-inlining.cc |
+++ b/src/compiler/js-inlining.cc |
@@ -8,6 +8,7 @@ |
#include "src/ast/ast.h" |
#include "src/ast/scopes.h" |
#include "src/compiler.h" |
+#include "src/compiler/all-nodes.h" |
#include "src/compiler/ast-graph-builder.h" |
#include "src/compiler/ast-loop-assignment-analyzer.h" |
#include "src/compiler/common-operator.h" |
@@ -72,9 +73,10 @@ class JSCallAccessor { |
Node* call_; |
}; |
- |
Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, |
- Node* frame_state, Node* start, Node* end) { |
+ Node* frame_state, Node* start, Node* end, |
+ Node* exception_target, |
+ const NodeVector& uncaught_subcalls) { |
// The scheduler is smart enough to place our code; we just ensure {control} |
// becomes the control input of the start of the inlinee, and {effect} becomes |
// the effect input of the start of the inlinee. |
@@ -131,6 +133,44 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, |
} |
} |
+ if (exception_target != nullptr) { |
+ // Link uncaught calls in the inlinee to {exception_target} |
+ int subcall_count = static_cast<int>(uncaught_subcalls.size()); |
+ if (subcall_count > 0) { |
+ TRACE( |
+ "Inlinee contains %d calls without IfException; " |
+ "linking to existing IfException\n", |
+ subcall_count); |
+ } |
+ NodeVector on_exception_nodes(local_zone_); |
+ for (Node* subcall : uncaught_subcalls) { |
+ Node* on_exception = |
+ graph()->NewNode(common()->IfException(), subcall, subcall); |
+ on_exception_nodes.push_back(on_exception); |
+ } |
+ |
+ DCHECK_EQ(subcall_count, static_cast<int>(on_exception_nodes.size())); |
+ if (subcall_count > 0) { |
+ Node* control_output = |
+ graph()->NewNode(common()->Merge(subcall_count), subcall_count, |
+ &on_exception_nodes.front()); |
+ NodeVector values_effects(local_zone_); |
+ values_effects = on_exception_nodes; |
+ values_effects.push_back(control_output); |
+ Node* value_output = graph()->NewNode( |
+ common()->Phi(MachineRepresentation::kTagged, subcall_count), |
+ subcall_count + 1, &values_effects.front()); |
+ Node* effect_output = |
+ graph()->NewNode(common()->EffectPhi(subcall_count), |
+ subcall_count + 1, &values_effects.front()); |
+ ReplaceWithValue(exception_target, value_output, effect_output, |
+ control_output); |
+ } else { |
+ ReplaceWithValue(exception_target, exception_target, exception_target, |
+ jsgraph()->Dead()); |
+ } |
+ } |
+ |
NodeVector values(local_zone_); |
NodeVector effects(local_zone_); |
NodeVector controls(local_zone_); |
@@ -270,7 +310,6 @@ Reduction JSInliner::Reduce(Node* node) { |
return ReduceJSCall(node, function); |
} |
- |
Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { |
DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); |
JSCallAccessor call(node); |
@@ -344,12 +383,35 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { |
} |
} |
- // TODO(turbofan): Inlining into a try-block is not yet supported. |
- if (NodeProperties::IsExceptionalCall(node)) { |
- TRACE("Not inlining %s into %s because of surrounding try-block\n", |
+ // Find the IfException node, if any. |
+ Node* exception_target = nullptr; |
+ for (Edge edge : node->use_edges()) { |
+ if (NodeProperties::IsControlEdge(edge) && |
+ edge.from()->opcode() == IrOpcode::kIfException) { |
+ DCHECK_NULL(exception_target); |
+ exception_target = edge.from(); |
+ } |
+ } |
+ |
+ NodeVector uncaught_subcalls(local_zone_); |
+ |
+ if (exception_target != nullptr) { |
+ if (!FLAG_inline_into_try) { |
+ TRACE( |
+ "Try block surrounds #%d:%s and --no-inline-into-try active, so not " |
+ "inlining %s into %s.\n", |
+ exception_target->id(), exception_target->op()->mnemonic(), |
shared_info->DebugName()->ToCString().get(), |
info_->shared_info()->DebugName()->ToCString().get()); |
- return NoChange(); |
+ return NoChange(); |
+ } else { |
+ TRACE( |
+ "Inlining %s into %s regardless of surrounding try-block to catcher " |
+ "#%d:%s\n", |
+ shared_info->DebugName()->ToCString().get(), |
+ info_->shared_info()->DebugName()->ToCString().get(), |
+ exception_target->id(), exception_target->op()->mnemonic()); |
+ } |
} |
Zone zone(info_->isolate()->allocator()); |
@@ -388,7 +450,7 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { |
shared_info->DebugName()->ToCString().get(), |
info_->shared_info()->DebugName()->ToCString().get()); |
- // If function was lazily compiled, it's literals array may not yet be set up. |
+ // If function was lazily compiled, its literals array may not yet be set up. |
JSFunction::EnsureLiterals(function); |
// Create the subgraph for the inlinee. |
@@ -416,6 +478,29 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { |
end = graph()->end(); |
} |
+ if (exception_target != nullptr) { |
+ // Find all uncaught 'calls' in the inlinee. |
+ AllNodes inlined_nodes(local_zone_, end, graph()); |
+ for (Node* subnode : inlined_nodes.reachable) { |
+ // Every possibly throwing node with an IfSuccess should get an |
+ // IfException. |
+ if (subnode->op()->HasProperty(Operator::kNoThrow)) { |
+ continue; |
+ } |
+ bool hasIfException = false; |
+ for (Node* use : subnode->uses()) { |
+ if (use->opcode() == IrOpcode::kIfException) { |
+ hasIfException = true; |
+ break; |
+ } |
+ } |
+ if (!hasIfException) { |
+ DCHECK_EQ(2, subnode->op()->ControlOutputCount()); |
+ uncaught_subcalls.push_back(subnode); |
+ } |
+ } |
+ } |
+ |
Node* frame_state = call.frame_state(); |
Node* new_target = jsgraph()->UndefinedConstant(); |
@@ -512,7 +597,8 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { |
FrameStateType::kArgumentsAdaptor, shared_info); |
} |
- return InlineCall(node, new_target, context, frame_state, start, end); |
+ return InlineCall(node, new_target, context, frame_state, start, end, |
+ exception_target, uncaught_subcalls); |
} |
Graph* JSInliner::graph() const { return jsgraph()->graph(); } |