Index: src/compiler/js-inlining.cc |
diff --git a/src/compiler/js-inlining.cc b/src/compiler/js-inlining.cc |
index 7aa82c91cb1909c9a5d26a81503dc4699eb86401..c8eced7a1960f281df32f55e13eed26462258d55 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* exception_target, |
+ NodeVector uncaught_subcalls) { |
Jarin
2016/08/10 12:02:52
You should pass the uncought_subcalls as a pointer
bgeron
2016/08/10 14:37:26
Agree, done.
|
// 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,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 (uncaught_subcalls.size() > 0) { |
Jarin
2016/08/10 12:02:52
Nit: why don't you use subcall_count that you defi
bgeron
2016/08/10 14:37:26
Done.
|
+ 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_); |
@@ -269,7 +309,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 +382,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* 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) { |
+ 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()); |
@@ -415,6 +467,31 @@ 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.live) { |
+ // Every possibly throwing node with an IfSuccess should get an |
+ // IfException. |
+ if (subnode->op()->HasProperty(Operator::kNoThrow)) { |
+ continue; |
+ } |
+ bool hasIfSuccess = false; |
+ bool hasIfException = false; |
+ for (Node* use : subnode->uses()) { |
+ if (use->opcode() == IrOpcode::kIfSuccess) { |
Jarin
2016/08/10 12:02:52
I assume this won't be needed once every no-no-thr
bgeron
2016/08/10 14:37:26
Hm, I fixed some things to make them saner, but cu
Jarin
2016/08/11 09:54:23
Actually, if Throw does not have IfSuccess, this c
bgeron
2016/08/11 18:55:55
Removed that condition.
To make this work, I had
|
+ hasIfSuccess = true; |
+ } else if (use->opcode() == IrOpcode::kIfException) { |
+ hasIfException = true; |
+ } |
+ } |
+ if (hasIfSuccess && !hasIfException) { |
+ DCHECK_EQ(2, subnode->op()->ControlOutputCount()); |
+ uncaught_subcalls.push_back(subnode); |
+ } |
+ } |
+ } |
+ |
Node* frame_state = call.frame_state(); |
Node* new_target = jsgraph()->UndefinedConstant(); |
@@ -513,7 +590,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(); } |