Chromium Code Reviews| Index: src/compiler/js-inlining.cc | 
| diff --git a/src/compiler/js-inlining.cc b/src/compiler/js-inlining.cc | 
| index 7c12dd5bc1ef3dcb028dd108353afa1eedff9a8d..4fcad20384d69a6a6d6114f371eceda9ed4e4af7 100644 | 
| --- a/src/compiler/js-inlining.cc | 
| +++ b/src/compiler/js-inlining.cc | 
| @@ -15,6 +15,7 @@ | 
| #include "src/compiler/node-properties-inl.h" | 
| #include "src/compiler/simplified-operator.h" | 
| #include "src/compiler/typer.h" | 
| +#include "src/full-codegen.h" | 
| #include "src/parser.h" | 
| #include "src/rewriter.h" | 
| #include "src/scopes.h" | 
| @@ -56,7 +57,6 @@ static void Parse(Handle<JSFunction> function, CompilationInfoWithZone* info) { | 
| CHECK(Parser::Parse(info)); | 
| StrictMode strict_mode = info->function()->strict_mode(); | 
| info->SetStrictMode(strict_mode); | 
| - info->SetOptimizing(BailoutId::None(), Handle<Code>(function->code())); | 
| CHECK(Rewriter::Rewrite(info)); | 
| CHECK(Scope::Analyze(info)); | 
| CHECK_NE(NULL, info->scope()); | 
| @@ -92,6 +92,16 @@ class Inlinee { | 
| DCHECK_EQ(IrOpcode::kReturn, unique_return->opcode()); | 
| return unique_return; | 
| } | 
| + | 
| + // Counts JSFunction, Receiver, arguments, context but not effect, control. | 
| + size_t total_parameters() { return start_->op()->OutputCount(); } | 
| + | 
| + // Counts only formal parameters. | 
| + size_t formal_parameters() { | 
| + DCHECK_GE(total_parameters(), 3); | 
| + return total_parameters() - 3; | 
| + } | 
| + | 
| // Inline this graph at {call}, use {jsgraph} and its zone to create | 
| // any new nodes. | 
| void InlineAtCall(JSGraph* jsgraph, Node* call); | 
| @@ -198,7 +208,7 @@ class CopyVisitor : public NullNodeVisitor { | 
| private: | 
| void ReplaceSentinels() { | 
| - for (int id = 0; id < source_graph_->NodeCount(); ++id) { | 
| + for (NodeId id = 0; id < source_graph_->NodeCount(); ++id) { | 
| Node* sentinel = sentinels_[id]; | 
| if (sentinel == NULL) continue; | 
| Node* copy = copies_[id]; | 
| @@ -237,11 +247,8 @@ void Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) { | 
| NodeProperties::GetValueInput(call, 0), | 
| NodeProperties::GetEffectInput(call)); | 
| - // {inlinee_inputs} counts JSFunction, Receiver, arguments, context, | 
| - // but not effect, control. | 
| - int inlinee_inputs = start_->op()->OutputCount(); | 
| // Context is last argument. | 
| - int inlinee_context_index = inlinee_inputs - 1; | 
| + int inlinee_context_index = total_parameters() - 1; | 
| // {inliner_inputs} counts JSFunction, Receiver, arguments, but not | 
| // context, effect, control. | 
| int inliner_inputs = OperatorProperties::GetValueInputCount(call->op()); | 
| @@ -301,10 +308,73 @@ void Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) { | 
| } | 
| -void JSInliner::TryInlineCall(Node* call) { | 
| - DCHECK_EQ(IrOpcode::kJSCallFunction, call->opcode()); | 
| +class JSCallFunctionAccessor { | 
| 
 
Michael Starzinger
2014/09/16 14:12:56
While such a thing would be nice to have, spreadin
 
sigurds
2014/09/17 10:02:47
I absolutely agree. However, without this thing th
 
 | 
| + public: | 
| + explicit JSCallFunctionAccessor(Node* call) : call_(call) { | 
| + DCHECK_EQ(IrOpcode::kJSCallFunction, call->opcode()); | 
| + } | 
| + | 
| + Node* jsfunction() { return call_->InputAt(0); } | 
| + | 
| + Node* receiver() { return call_->InputAt(1); } | 
| + | 
| + Node* formal_argument(size_t index) { | 
| + DCHECK(index < formal_arguments()); | 
| + return call_->InputAt(2 + index); | 
| + } | 
| + | 
| + size_t formal_arguments() { | 
| + // {value_inputs} includes jsfunction and receiver. | 
| + size_t value_inputs = OperatorProperties::GetValueInputCount(call_->op()); | 
| + DCHECK_GE(call_->InputCount(), 2); | 
| + return value_inputs - 2; | 
| + } | 
| + | 
| + Node* frame_state() { return NodeProperties::GetFrameStateInput(call_); } | 
| + | 
| + private: | 
| + Node* call_; | 
| +}; | 
| + | 
| + | 
| +static void AddClosureToFrameState(JSGraph* jsgraph, Node* frame_state, | 
| + Handle<JSFunction> jsfunction) { | 
| + FrameStateCallInfo call_info = OpParameter<FrameStateCallInfo>(frame_state); | 
| + const Operator* op = jsgraph->common()->FrameState( | 
| + FrameStateType::JS_FRAME, call_info.bailout_id(), | 
| + call_info.state_combine(), | 
| + Unique<JSFunction>::CreateImmovable(jsfunction)); | 
| + frame_state->set_op(op); | 
| +} | 
| + | 
| + | 
| +static Node* CreateArgumentsAdaptorFrameState(JSGraph* jsgraph, | 
| + JSCallFunctionAccessor* call, | 
| + Handle<JSFunction> jsfunction, | 
| + Zone* temp_zone) { | 
| + const Operator* op = jsgraph->common()->FrameState( | 
| + FrameStateType::ARGUMENTS_ADAPTOR, BailoutId(-1), kIgnoreOutput, | 
| + Unique<JSFunction>::CreateImmovable(jsfunction)); | 
| + const Operator* op0 = jsgraph->common()->StateValues(0); | 
| + Node* node0 = jsgraph->graph()->NewNode(op0); | 
| + NodeVector params(temp_zone); | 
| + params.push_back(call->receiver()); | 
| + for (size_t argument = 0; argument != call->formal_arguments(); ++argument) { | 
| + params.push_back(call->formal_argument(argument)); | 
| + } | 
| + const Operator* op_param = jsgraph->common()->StateValues(params.size()); | 
| + Node* params_node = | 
| + jsgraph->graph()->NewNode(op_param, params.size(), ¶ms.front()); | 
| + return jsgraph->graph()->NewNode(op, params_node, node0, node0, | 
| + jsgraph->UndefinedConstant(), | 
| + call->frame_state()); | 
| +} | 
| + | 
| - HeapObjectMatcher<JSFunction> match(call->InputAt(0)); | 
| +void JSInliner::TryInlineCall(Node* call_node) { | 
| + JSCallFunctionAccessor call(call_node); | 
| + | 
| + HeapObjectMatcher<JSFunction> match(call.jsfunction()); | 
| if (!match.HasValue()) { | 
| return; | 
| } | 
| @@ -324,6 +394,16 @@ void JSInliner::TryInlineCall(Node* call) { | 
| CompilationInfoWithZone info(function); | 
| Parse(function, &info); | 
| + if (!function->shared()->has_deoptimization_support()) { | 
| + info.EnableDeoptimizationSupport(); | 
| 
 
Michael Starzinger
2014/09/16 14:12:56
OMG, we really should try to find a way to do this
 
sigurds
2014/09/17 10:02:47
Done.
 
 | 
| + if (!FullCodeGenerator::MakeCode(&info)) { | 
| + DCHECK(false); | 
| + return; | 
| + } | 
| + function->shared()->EnableDeoptimizationSupport(*info.code()); | 
| + function->shared()->set_feedback_vector(*info.feedback_vector()); | 
| + } | 
| + | 
| if (info.scope()->arguments() != NULL) { | 
| // For now do not inline functions that use their arguments array. | 
| SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString(); | 
| @@ -355,7 +435,22 @@ void JSInliner::TryInlineCall(Node* call) { | 
| visitor.CopyGraph(); | 
| Inlinee inlinee(visitor.GetCopy(graph.start()), visitor.GetCopy(graph.end())); | 
| - inlinee.InlineAtCall(jsgraph_, call); | 
| + | 
| + for (Node* node : visitor.copies()) { | 
| + if (node != NULL && node->opcode() == IrOpcode::kFrameState) { | 
| + AddClosureToFrameState(jsgraph_, node, function); | 
| + Node* outer_frame_state = call.frame_state(); | 
| + // Insert argument adaptor frame if required. | 
| + if (call.formal_arguments() != inlinee.formal_parameters()) { | 
| + outer_frame_state = CreateArgumentsAdaptorFrameState( | 
| + jsgraph_, &call, function, info.zone()); | 
| + } | 
| + NodeProperties::ReplaceFrameStateInput(node, outer_frame_state); | 
| + } | 
| + } | 
| + | 
| + | 
| + inlinee.InlineAtCall(jsgraph_, call_node); | 
| } | 
| } | 
| } |