diff options
Diffstat (limited to 'deps/v8/src/compiler/js-inlining.cc')
-rw-r--r-- | deps/v8/src/compiler/js-inlining.cc | 277 |
1 files changed, 123 insertions, 154 deletions
diff --git a/deps/v8/src/compiler/js-inlining.cc b/deps/v8/src/compiler/js-inlining.cc index e3254bd077..635daa4d76 100644 --- a/deps/v8/src/compiler/js-inlining.cc +++ b/deps/v8/src/compiler/js-inlining.cc @@ -4,20 +4,22 @@ #include "src/compiler/js-inlining.h" -#include "src/ast/ast.h" #include "src/ast/ast-numbering.h" +#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" #include "src/compiler/graph-reducer.h" #include "src/compiler/js-operator.h" #include "src/compiler/node-matchers.h" #include "src/compiler/node-properties.h" #include "src/compiler/operator-properties.h" +#include "src/compiler/simplified-operator.h" +#include "src/compiler/type-hint-analyzer.h" #include "src/isolate-inl.h" -#include "src/parsing/parser.h" +#include "src/parsing/parse-info.h" #include "src/parsing/rewriter.h" namespace v8 { @@ -54,13 +56,9 @@ class JSCallAccessor { return call_->InputAt(formal_arguments() + 1); } - Node* frame_state_before() { - return NodeProperties::GetFrameStateInput(call_, 1); - } - - Node* frame_state_after() { - // Both, {JSCallFunction} and {JSCallConstruct}, have frame state after. - return NodeProperties::GetFrameStateInput(call_, 0); + Node* frame_state() { + // Both, {JSCallFunction} and {JSCallConstruct}, have frame state. + return NodeProperties::GetFrameStateInput(call_); } int formal_arguments() { @@ -75,63 +73,6 @@ class JSCallAccessor { }; -class CopyVisitor { - public: - CopyVisitor(Graph* source_graph, Graph* target_graph, Zone* temp_zone) - : sentinel_op_(IrOpcode::kDead, Operator::kNoProperties, "Sentinel", 0, 0, - 0, 0, 0, 0), - sentinel_(target_graph->NewNode(&sentinel_op_)), - copies_(source_graph->NodeCount(), sentinel_, temp_zone), - source_graph_(source_graph), - target_graph_(target_graph), - temp_zone_(temp_zone) {} - - Node* GetCopy(Node* orig) { return copies_[orig->id()]; } - - void CopyGraph() { - NodeVector inputs(temp_zone_); - // TODO(bmeurer): AllNodes should be turned into something like - // Graph::CollectNodesReachableFromEnd() and the gray set stuff should be - // removed since it's only needed by the visualizer. - AllNodes all(temp_zone_, source_graph_); - // Copy all nodes reachable from end. - for (Node* orig : all.live) { - Node* copy = GetCopy(orig); - if (copy != sentinel_) { - // Mapping already exists. - continue; - } - // Copy the node. - inputs.clear(); - for (Node* input : orig->inputs()) inputs.push_back(copies_[input->id()]); - copy = target_graph_->NewNode(orig->op(), orig->InputCount(), - inputs.empty() ? nullptr : &inputs[0]); - copies_[orig->id()] = copy; - } - // For missing inputs. - for (Node* orig : all.live) { - Node* copy = copies_[orig->id()]; - for (int i = 0; i < copy->InputCount(); ++i) { - Node* input = copy->InputAt(i); - if (input == sentinel_) { - copy->ReplaceInput(i, GetCopy(orig->InputAt(i))); - } - } - } - } - - const NodeVector& copies() const { return copies_; } - - private: - Operator const sentinel_op_; - Node* const sentinel_; - NodeVector copies_; - Graph* const source_graph_; - Graph* const target_graph_; - Zone* const temp_zone_; -}; - - Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, Node* frame_state, Node* start, Node* end) { // The scheduler is smart enough to place our code; we just ensure {control} @@ -166,13 +107,13 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, Replace(use, new_target); } else if (index == inlinee_arity_index) { // The projection is requesting the number of arguments. - Replace(use, jsgraph_->Int32Constant(inliner_inputs - 2)); + Replace(use, jsgraph()->Int32Constant(inliner_inputs - 2)); } else if (index == inlinee_context_index) { // The projection is requesting the inlinee function context. Replace(use, context); } else { // Call has fewer arguments than required, fill with undefined. - Replace(use, jsgraph_->UndefinedConstant()); + Replace(use, jsgraph()->UndefinedConstant()); } break; } @@ -203,9 +144,8 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, case IrOpcode::kDeoptimize: case IrOpcode::kTerminate: case IrOpcode::kThrow: - NodeProperties::MergeControlToEnd(jsgraph_->graph(), jsgraph_->common(), - input); - Revisit(jsgraph_->graph()->end()); + NodeProperties::MergeControlToEnd(graph(), common(), input); + Revisit(graph()->end()); break; default: UNREACHABLE(); @@ -219,20 +159,20 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, // uses with said value or kill value uses if no value can be returned. if (values.size() > 0) { int const input_count = static_cast<int>(controls.size()); - Node* control_output = jsgraph_->graph()->NewNode( - jsgraph_->common()->Merge(input_count), input_count, &controls.front()); + Node* control_output = graph()->NewNode(common()->Merge(input_count), + input_count, &controls.front()); values.push_back(control_output); effects.push_back(control_output); - Node* value_output = jsgraph_->graph()->NewNode( - jsgraph_->common()->Phi(MachineRepresentation::kTagged, input_count), + Node* value_output = graph()->NewNode( + common()->Phi(MachineRepresentation::kTagged, input_count), static_cast<int>(values.size()), &values.front()); - Node* effect_output = jsgraph_->graph()->NewNode( - jsgraph_->common()->EffectPhi(input_count), - static_cast<int>(effects.size()), &effects.front()); + Node* effect_output = + graph()->NewNode(common()->EffectPhi(input_count), + static_cast<int>(effects.size()), &effects.front()); ReplaceWithValue(call, value_output, effect_output, control_output); return Changed(value_output); } else { - ReplaceWithValue(call, call, call, jsgraph_->Dead()); + ReplaceWithValue(call, call, call, jsgraph()->Dead()); return Changed(call); } } @@ -243,24 +183,24 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state, FrameStateType frame_state_type, Handle<SharedFunctionInfo> shared) { const FrameStateFunctionInfo* state_info = - jsgraph_->common()->CreateFrameStateFunctionInfo( - frame_state_type, parameter_count + 1, 0, shared); + common()->CreateFrameStateFunctionInfo(frame_state_type, + parameter_count + 1, 0, shared); - const Operator* op = jsgraph_->common()->FrameState( + const Operator* op = common()->FrameState( BailoutId(-1), OutputFrameStateCombine::Ignore(), state_info); - const Operator* op0 = jsgraph_->common()->StateValues(0); - Node* node0 = jsgraph_->graph()->NewNode(op0); + const Operator* op0 = common()->StateValues(0); + Node* node0 = graph()->NewNode(op0); NodeVector params(local_zone_); for (int parameter = 0; parameter < parameter_count + 1; ++parameter) { params.push_back(node->InputAt(1 + parameter)); } const Operator* op_param = - jsgraph_->common()->StateValues(static_cast<int>(params.size())); - Node* params_node = jsgraph_->graph()->NewNode( + common()->StateValues(static_cast<int>(params.size())); + Node* params_node = graph()->NewNode( op_param, static_cast<int>(params.size()), ¶ms.front()); - return jsgraph_->graph()->NewNode(op, params_node, node0, node0, - jsgraph_->UndefinedConstant(), - node->InputAt(0), outer_frame_state); + return graph()->NewNode(op, params_node, node0, node0, + jsgraph()->UndefinedConstant(), node->InputAt(0), + outer_frame_state); } Node* JSInliner::CreateTailCallerFrameState(Node* node, Node* frame_state) { @@ -272,25 +212,25 @@ Node* JSInliner::CreateTailCallerFrameState(Node* node, Node* frame_state) { // If we are inlining a tail call drop caller's frame state and an // arguments adaptor if it exists. - frame_state = NodeProperties::GetFrameStateInput(frame_state, 0); + frame_state = NodeProperties::GetFrameStateInput(frame_state); if (frame_state->opcode() == IrOpcode::kFrameState) { FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state); if (frame_info.type() == FrameStateType::kArgumentsAdaptor) { - frame_state = NodeProperties::GetFrameStateInput(frame_state, 0); + frame_state = NodeProperties::GetFrameStateInput(frame_state); } } const FrameStateFunctionInfo* state_info = - jsgraph_->common()->CreateFrameStateFunctionInfo( + common()->CreateFrameStateFunctionInfo( FrameStateType::kTailCallerFunction, 0, 0, shared); - const Operator* op = jsgraph_->common()->FrameState( + const Operator* op = common()->FrameState( BailoutId(-1), OutputFrameStateCombine::Ignore(), state_info); - const Operator* op0 = jsgraph_->common()->StateValues(0); - Node* node0 = jsgraph_->graph()->NewNode(op0); - return jsgraph_->graph()->NewNode(op, node0, node0, node0, - jsgraph_->UndefinedConstant(), function, - frame_state); + const Operator* op0 = common()->StateValues(0); + Node* node0 = graph()->NewNode(op0); + return graph()->NewNode(op, node0, node0, node0, + jsgraph()->UndefinedConstant(), function, + frame_state); } namespace { @@ -390,7 +330,7 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { // TODO(turbofan): TranslatedState::GetAdaptedArguments() currently relies on // not inlining recursive functions. We might want to relax that at some // point. - for (Node* frame_state = call.frame_state_after(); + for (Node* frame_state = call.frame_state(); frame_state->opcode() == IrOpcode::kFrameState; frame_state = frame_state->InputAt(kFrameStateOuterStateInput)) { FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state); @@ -414,8 +354,9 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { Zone zone(info_->isolate()->allocator()); ParseInfo parse_info(&zone, function); - CompilationInfo info(&parse_info); + CompilationInfo info(&parse_info, function); if (info_->is_deoptimization_enabled()) info.MarkAsDeoptimizationEnabled(); + if (info_->is_type_feedback_enabled()) info.MarkAsTypeFeedbackEnabled(); if (!Compiler::ParseAndAnalyze(info.parse_info())) { TRACE("Not inlining %s into %s because parsing failed\n", @@ -433,6 +374,7 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { info_->shared_info()->DebugName()->ToCString().get()); return NoChange(); } + // Remember that we inlined this function. This needs to be called right // after we ensure deoptimization support so that the code flusher // does not remove the code with the deoptimization support. @@ -446,59 +388,73 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { shared_info->DebugName()->ToCString().get(), info_->shared_info()->DebugName()->ToCString().get()); - // TODO(mstarzinger): We could use the temporary zone for the graph because - // nodes are copied. This however leads to Zone-Types being allocated in the - // wrong zone and makes the engine explode at high speeds. Explosion bad! - Graph graph(jsgraph_->zone()); - JSGraph jsgraph(info.isolate(), &graph, jsgraph_->common(), - jsgraph_->javascript(), jsgraph_->simplified(), - jsgraph_->machine()); - AstGraphBuilder graph_builder(local_zone_, &info, &jsgraph); - graph_builder.CreateGraph(false); - - CopyVisitor visitor(&graph, jsgraph_->graph(), &zone); - visitor.CopyGraph(); - - Node* start = visitor.GetCopy(graph.start()); - Node* end = visitor.GetCopy(graph.end()); - Node* frame_state = call.frame_state_after(); - Node* new_target = jsgraph_->UndefinedConstant(); - - // Insert nodes around the call that model the behavior required for a - // constructor dispatch (allocate implicit receiver and check return value). - // This models the behavior usually accomplished by our {JSConstructStub}. - // Note that the context has to be the callers context (input to call node). - Node* receiver = jsgraph_->UndefinedConstant(); // Implicit receiver. - if (node->opcode() == IrOpcode::kJSCallConstruct && - NeedsImplicitReceiver(shared_info)) { - Node* effect = NodeProperties::GetEffectInput(node); - Node* context = NodeProperties::GetContextInput(node); - Node* create = jsgraph_->graph()->NewNode( - jsgraph_->javascript()->Create(), call.target(), call.new_target(), - context, call.frame_state_before(), effect); - NodeProperties::ReplaceEffectInput(node, create); - // Insert a check of the return value to determine whether the return value - // or the implicit receiver should be selected as a result of the call. - Node* check = jsgraph_->graph()->NewNode( - jsgraph_->javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), - node, context, node, start); - Node* select = jsgraph_->graph()->NewNode( - jsgraph_->common()->Select(MachineRepresentation::kTagged), check, node, - create); - NodeProperties::ReplaceUses(node, select, check, node, node); - NodeProperties::ReplaceValueInput(select, node, 1); - NodeProperties::ReplaceValueInput(check, node, 0); - NodeProperties::ReplaceEffectInput(check, node); - receiver = create; // The implicit receiver. + // If function was lazily compiled, it's literals array may not yet be set up. + JSFunction::EnsureLiterals(function); + + // Create the subgraph for the inlinee. + Node* start; + Node* end; + { + // Run the loop assignment analyzer on the inlinee. + AstLoopAssignmentAnalyzer loop_assignment_analyzer(&zone, &info); + LoopAssignmentAnalysis* loop_assignment = + loop_assignment_analyzer.Analyze(); + + // Run the type hint analyzer on the inlinee. + TypeHintAnalyzer type_hint_analyzer(&zone); + TypeHintAnalysis* type_hint_analysis = + type_hint_analyzer.Analyze(handle(shared_info->code(), info.isolate())); + + // Run the AstGraphBuilder to create the subgraph. + Graph::SubgraphScope scope(graph()); + AstGraphBuilder graph_builder(&zone, &info, jsgraph(), loop_assignment, + type_hint_analysis); + graph_builder.CreateGraph(false); + + // Extract the inlinee start/end nodes. + start = graph()->start(); + end = graph()->end(); } - // Swizzle the inputs of the {JSCallConstruct} node to look like inputs to a - // normal {JSCallFunction} node so that the rest of the inlining machinery - // behaves as if we were dealing with a regular function invocation. + Node* frame_state = call.frame_state(); + Node* new_target = jsgraph()->UndefinedConstant(); + + // Inline {JSCallConstruct} requires some additional magic. if (node->opcode() == IrOpcode::kJSCallConstruct) { + // Insert nodes around the call that model the behavior required for a + // constructor dispatch (allocate implicit receiver and check return value). + // This models the behavior usually accomplished by our {JSConstructStub}. + // Note that the context has to be the callers context (input to call node). + Node* receiver = jsgraph()->UndefinedConstant(); // Implicit receiver. + if (NeedsImplicitReceiver(shared_info)) { + Node* frame_state_before = NodeProperties::FindFrameStateBefore(node); + Node* effect = NodeProperties::GetEffectInput(node); + Node* context = NodeProperties::GetContextInput(node); + Node* create = graph()->NewNode(javascript()->Create(), call.target(), + call.new_target(), context, + frame_state_before, effect); + NodeProperties::ReplaceEffectInput(node, create); + // Insert a check of the return value to determine whether the return + // value or the implicit receiver should be selected as a result of the + // call. + Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), node); + Node* select = + graph()->NewNode(common()->Select(MachineRepresentation::kTagged), + check, node, create); + NodeProperties::ReplaceUses(node, select, node, node, node); + // Fix-up inputs that have been mangled by the {ReplaceUses} call above. + NodeProperties::ReplaceValueInput(select, node, 1); // Fix-up input. + NodeProperties::ReplaceValueInput(check, node, 0); // Fix-up input. + receiver = create; // The implicit receiver. + } + + // Swizzle the inputs of the {JSCallConstruct} node to look like inputs to a + // normal {JSCallFunction} node so that the rest of the inlining machinery + // behaves as if we were dealing with a regular function invocation. new_target = call.new_target(); // Retrieve new target value input. node->RemoveInput(call.formal_arguments() + 1); // Drop new target. - node->InsertInput(jsgraph_->graph()->zone(), 1, receiver); + node->InsertInput(graph()->zone(), 1, receiver); + // Insert a construct stub frame into the chain of frame states. This will // reconstruct the proper frame when deoptimizing within the constructor. frame_state = CreateArtificialFrameState( @@ -510,7 +466,7 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { // TODO(turbofan): We might want to load the context from the JSFunction at // runtime in case we only know the SharedFunctionInfo once we have dynamic // type feedback in the compiler. - Node* context = jsgraph_->Constant(handle(function->context())); + Node* context = jsgraph()->Constant(handle(function->context())); // Insert a JSConvertReceiver node for sloppy callees. Note that the context // passed into this node has to be the callees context (loaded above). Note @@ -519,12 +475,13 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { // in that frame state tho, as the conversion of the receiver can be repeated // any number of times, it's not observable. if (node->opcode() == IrOpcode::kJSCallFunction && - is_sloppy(info.language_mode()) && !shared_info->native()) { + is_sloppy(parse_info.language_mode()) && !shared_info->native()) { const CallFunctionParameters& p = CallFunctionParametersOf(node->op()); + Node* frame_state_before = NodeProperties::FindFrameStateBefore(node); Node* effect = NodeProperties::GetEffectInput(node); - Node* convert = jsgraph_->graph()->NewNode( - jsgraph_->javascript()->ConvertReceiver(p.convert_mode()), - call.receiver(), context, call.frame_state_before(), effect, start); + Node* convert = graph()->NewNode( + javascript()->ConvertReceiver(p.convert_mode()), call.receiver(), + context, frame_state_before, effect, start); NodeProperties::ReplaceValueInput(node, convert, 1); NodeProperties::ReplaceEffectInput(node, convert); } @@ -558,6 +515,18 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { return InlineCall(node, new_target, context, frame_state, start, end); } +Graph* JSInliner::graph() const { return jsgraph()->graph(); } + +JSOperatorBuilder* JSInliner::javascript() const { + return jsgraph()->javascript(); +} + +CommonOperatorBuilder* JSInliner::common() const { return jsgraph()->common(); } + +SimplifiedOperatorBuilder* JSInliner::simplified() const { + return jsgraph()->simplified(); +} + } // namespace compiler } // namespace internal } // namespace v8 |