Index: src/compiler/js-inlining.cc |
diff --git a/src/compiler/js-inlining.cc b/src/compiler/js-inlining.cc |
index 7aa82c91cb1909c9a5d26a81503dc4699eb86401..51c9dc7be1931a388bc7dd3d5cf24ac71f569255 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" |
@@ -71,9 +72,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* exceptionTarget, |
+ 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. |
@@ -130,6 +132,45 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, |
} |
} |
+ if (exceptionTarget != nullptr) { |
+ // Link uncaught calls in the inlinee to {exceptionTarget} |
+ int subcall_count = static_cast<int>(uncaught_subcalls.size()); |
+ if (uncaught_subcalls.size() > 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) { |
+ const Operator* op = common()->IfException(); |
Jarin
2016/08/05 14:04:48
Nit: no need for separate variable, just inline in
bgeron
2016/08/08 09:30:06
Done.
|
+ |
+ Node* on_exception = graph()->NewNode(op, 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(exceptionTarget, value_output, effect_output, |
+ control_output); |
+ } else { |
+ ReplaceWithValue(exceptionTarget, exceptionTarget, exceptionTarget, |
+ jsgraph()->Dead()); |
+ } |
+ } |
+ |
NodeVector values(local_zone_); |
NodeVector effects(local_zone_); |
NodeVector controls(local_zone_); |
@@ -269,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); |
@@ -343,12 +383,25 @@ 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", |
- shared_info->DebugName()->ToCString().get(), |
- info_->shared_info()->DebugName()->ToCString().get()); |
- return NoChange(); |
+ // Find the IfException node, if any. |
+ Node* exceptionTarget = nullptr; |
Jarin
2016/08/05 14:04:48
exceptionTarget -> exception_target
bgeron
2016/08/08 09:30:06
Done.
|
+ for (Edge edge : node->use_edges()) { |
+ if (NodeProperties::IsControlEdge(edge) && |
+ edge.from()->opcode() == IrOpcode::kIfException) { |
+ DCHECK_NULL(exceptionTarget); |
+ exceptionTarget = edge.from(); |
+ } |
+ } |
+ |
+ NodeVector uncaught_subcalls(local_zone_); |
+ |
+ if (exceptionTarget != nullptr) { |
+ 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(), |
+ exceptionTarget->id(), exceptionTarget->op()->mnemonic()); |
} |
Zone zone(info_->isolate()->allocator()); |
@@ -415,6 +468,27 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { |
end = graph()->end(); |
} |
+ // Find all uncaught calls in the inlinee. |
+ AllNodes inlined_nodes(local_zone_, end, graph()); |
+ for (Node* subcall : inlined_nodes.live) { |
+ if (subcall->opcode() == IrOpcode::kJSCallFunction || |
+ subcall->opcode() == IrOpcode::kJSCallConstruct || |
+ subcall->opcode() == IrOpcode::kJSCallRuntime) { |
Jarin
2016/08/05 14:04:48
As discussed offline, you need a more general way:
bgeron
2016/08/08 09:30:06
Done.
|
+ bool hasIfException = false; |
+ for (Node* use : subcall->uses()) { |
+ if (use->opcode() == IrOpcode::kIfException) { |
+ hasIfException = true; |
+ std::ostringstream s; |
+ s << "found exception node #" << use->id(); |
Jarin
2016/08/05 14:04:48
Remove the logging.
bgeron
2016/08/08 09:30:06
Done.
|
+ break; |
+ } |
+ } |
+ if (!hasIfException) { |
+ uncaught_subcalls.push_back(subcall); |
+ } |
+ } |
+ } |
+ |
Node* frame_state = call.frame_state(); |
Node* new_target = jsgraph()->UndefinedConstant(); |
@@ -513,7 +587,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, |
+ exceptionTarget, uncaught_subcalls); |
} |
Graph* JSInliner::graph() const { return jsgraph()->graph(); } |