• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/compiler/js-inlining.h"
6 
7 #include "src/ast/ast.h"
8 #include "src/compiler.h"
9 #include "src/compiler/all-nodes.h"
10 #include "src/compiler/bytecode-graph-builder.h"
11 #include "src/compiler/common-operator.h"
12 #include "src/compiler/compiler-source-position-table.h"
13 #include "src/compiler/graph-reducer.h"
14 #include "src/compiler/js-operator.h"
15 #include "src/compiler/node-matchers.h"
16 #include "src/compiler/node-properties.h"
17 #include "src/compiler/operator-properties.h"
18 #include "src/compiler/simplified-operator.h"
19 #include "src/isolate-inl.h"
20 #include "src/optimized-compilation-info.h"
21 #include "src/parsing/parse-info.h"
22 
23 namespace v8 {
24 namespace internal {
25 namespace compiler {
26 
27 namespace {
28 // This is just to avoid some corner cases, especially since we allow recursive
29 // inlining.
30 static const int kMaxDepthForInlining = 50;
31 }  // namespace
32 
33 #define TRACE(...)                                      \
34   do {                                                  \
35     if (FLAG_trace_turbo_inlining) PrintF(__VA_ARGS__); \
36   } while (false)
37 
38 
39 // Provides convenience accessors for the common layout of nodes having either
40 // the {JSCall} or the {JSConstruct} operator.
41 class JSCallAccessor {
42  public:
JSCallAccessor(Node * call)43   explicit JSCallAccessor(Node* call) : call_(call) {
44     DCHECK(call->opcode() == IrOpcode::kJSCall ||
45            call->opcode() == IrOpcode::kJSConstruct);
46   }
47 
target()48   Node* target() {
49     // Both, {JSCall} and {JSConstruct}, have same layout here.
50     return call_->InputAt(0);
51   }
52 
receiver()53   Node* receiver() {
54     DCHECK_EQ(IrOpcode::kJSCall, call_->opcode());
55     return call_->InputAt(1);
56   }
57 
new_target()58   Node* new_target() {
59     DCHECK_EQ(IrOpcode::kJSConstruct, call_->opcode());
60     return call_->InputAt(formal_arguments() + 1);
61   }
62 
frame_state()63   Node* frame_state() {
64     // Both, {JSCall} and {JSConstruct}, have frame state.
65     return NodeProperties::GetFrameStateInput(call_);
66   }
67 
formal_arguments()68   int formal_arguments() {
69     // Both, {JSCall} and {JSConstruct}, have two extra inputs:
70     //  - JSConstruct: Includes target function and new target.
71     //  - JSCall: Includes target function and receiver.
72     return call_->op()->ValueInputCount() - 2;
73   }
74 
frequency() const75   CallFrequency frequency() const {
76     return (call_->opcode() == IrOpcode::kJSCall)
77                ? CallParametersOf(call_->op()).frequency()
78                : ConstructParametersOf(call_->op()).frequency();
79   }
80 
81  private:
82   Node* call_;
83 };
84 
InlineCall(Node * call,Node * new_target,Node * context,Node * frame_state,Node * start,Node * end,Node * exception_target,const NodeVector & uncaught_subcalls)85 Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
86                                 Node* frame_state, Node* start, Node* end,
87                                 Node* exception_target,
88                                 const NodeVector& uncaught_subcalls) {
89   // The scheduler is smart enough to place our code; we just ensure {control}
90   // becomes the control input of the start of the inlinee, and {effect} becomes
91   // the effect input of the start of the inlinee.
92   Node* control = NodeProperties::GetControlInput(call);
93   Node* effect = NodeProperties::GetEffectInput(call);
94 
95   int const inlinee_new_target_index =
96       static_cast<int>(start->op()->ValueOutputCount()) - 3;
97   int const inlinee_arity_index =
98       static_cast<int>(start->op()->ValueOutputCount()) - 2;
99   int const inlinee_context_index =
100       static_cast<int>(start->op()->ValueOutputCount()) - 1;
101 
102   // {inliner_inputs} counts JSFunction, receiver, arguments, but not
103   // new target value, argument count, context, effect or control.
104   int inliner_inputs = call->op()->ValueInputCount();
105   // Iterate over all uses of the start node.
106   for (Edge edge : start->use_edges()) {
107     Node* use = edge.from();
108     switch (use->opcode()) {
109       case IrOpcode::kParameter: {
110         int index = 1 + ParameterIndexOf(use->op());
111         DCHECK_LE(index, inlinee_context_index);
112         if (index < inliner_inputs && index < inlinee_new_target_index) {
113           // There is an input from the call, and the index is a value
114           // projection but not the context, so rewire the input.
115           Replace(use, call->InputAt(index));
116         } else if (index == inlinee_new_target_index) {
117           // The projection is requesting the new target value.
118           Replace(use, new_target);
119         } else if (index == inlinee_arity_index) {
120           // The projection is requesting the number of arguments.
121           Replace(use, jsgraph()->Constant(inliner_inputs - 2));
122         } else if (index == inlinee_context_index) {
123           // The projection is requesting the inlinee function context.
124           Replace(use, context);
125         } else {
126           // Call has fewer arguments than required, fill with undefined.
127           Replace(use, jsgraph()->UndefinedConstant());
128         }
129         break;
130       }
131       default:
132         if (NodeProperties::IsEffectEdge(edge)) {
133           edge.UpdateTo(effect);
134         } else if (NodeProperties::IsControlEdge(edge)) {
135           edge.UpdateTo(control);
136         } else if (NodeProperties::IsFrameStateEdge(edge)) {
137           edge.UpdateTo(frame_state);
138         } else {
139           UNREACHABLE();
140         }
141         break;
142     }
143   }
144 
145   if (exception_target != nullptr) {
146     // Link uncaught calls in the inlinee to {exception_target}
147     int subcall_count = static_cast<int>(uncaught_subcalls.size());
148     if (subcall_count > 0) {
149       TRACE(
150           "Inlinee contains %d calls without local exception handler; "
151           "linking to surrounding exception handler\n",
152           subcall_count);
153     }
154     NodeVector on_exception_nodes(local_zone_);
155     for (Node* subcall : uncaught_subcalls) {
156       Node* on_success = graph()->NewNode(common()->IfSuccess(), subcall);
157       NodeProperties::ReplaceUses(subcall, subcall, subcall, on_success);
158       NodeProperties::ReplaceControlInput(on_success, subcall);
159       Node* on_exception =
160           graph()->NewNode(common()->IfException(), subcall, subcall);
161       on_exception_nodes.push_back(on_exception);
162     }
163 
164     DCHECK_EQ(subcall_count, static_cast<int>(on_exception_nodes.size()));
165     if (subcall_count > 0) {
166       Node* control_output =
167           graph()->NewNode(common()->Merge(subcall_count), subcall_count,
168                            &on_exception_nodes.front());
169       NodeVector values_effects(local_zone_);
170       values_effects = on_exception_nodes;
171       values_effects.push_back(control_output);
172       Node* value_output = graph()->NewNode(
173           common()->Phi(MachineRepresentation::kTagged, subcall_count),
174           subcall_count + 1, &values_effects.front());
175       Node* effect_output =
176           graph()->NewNode(common()->EffectPhi(subcall_count),
177                            subcall_count + 1, &values_effects.front());
178       ReplaceWithValue(exception_target, value_output, effect_output,
179                        control_output);
180     } else {
181       ReplaceWithValue(exception_target, exception_target, exception_target,
182                        jsgraph()->Dead());
183     }
184   }
185 
186   NodeVector values(local_zone_);
187   NodeVector effects(local_zone_);
188   NodeVector controls(local_zone_);
189   for (Node* const input : end->inputs()) {
190     switch (input->opcode()) {
191       case IrOpcode::kReturn:
192         values.push_back(NodeProperties::GetValueInput(input, 1));
193         effects.push_back(NodeProperties::GetEffectInput(input));
194         controls.push_back(NodeProperties::GetControlInput(input));
195         break;
196       case IrOpcode::kDeoptimize:
197       case IrOpcode::kTerminate:
198       case IrOpcode::kThrow:
199         NodeProperties::MergeControlToEnd(graph(), common(), input);
200         Revisit(graph()->end());
201         break;
202       default:
203         UNREACHABLE();
204         break;
205     }
206   }
207   DCHECK_EQ(values.size(), effects.size());
208   DCHECK_EQ(values.size(), controls.size());
209 
210   // Depending on whether the inlinee produces a value, we either replace value
211   // uses with said value or kill value uses if no value can be returned.
212   if (values.size() > 0) {
213     int const input_count = static_cast<int>(controls.size());
214     Node* control_output = graph()->NewNode(common()->Merge(input_count),
215                                             input_count, &controls.front());
216     values.push_back(control_output);
217     effects.push_back(control_output);
218     Node* value_output = graph()->NewNode(
219         common()->Phi(MachineRepresentation::kTagged, input_count),
220         static_cast<int>(values.size()), &values.front());
221     Node* effect_output =
222         graph()->NewNode(common()->EffectPhi(input_count),
223                          static_cast<int>(effects.size()), &effects.front());
224     ReplaceWithValue(call, value_output, effect_output, control_output);
225     return Changed(value_output);
226   } else {
227     ReplaceWithValue(call, jsgraph()->Dead(), jsgraph()->Dead(),
228                      jsgraph()->Dead());
229     return Changed(call);
230   }
231 }
232 
CreateArtificialFrameState(Node * node,Node * outer_frame_state,int parameter_count,BailoutId bailout_id,FrameStateType frame_state_type,Handle<SharedFunctionInfo> shared)233 Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
234                                             int parameter_count,
235                                             BailoutId bailout_id,
236                                             FrameStateType frame_state_type,
237                                             Handle<SharedFunctionInfo> shared) {
238   const FrameStateFunctionInfo* state_info =
239       common()->CreateFrameStateFunctionInfo(frame_state_type,
240                                              parameter_count + 1, 0, shared);
241 
242   const Operator* op = common()->FrameState(
243       bailout_id, OutputFrameStateCombine::Ignore(), state_info);
244   const Operator* op0 = common()->StateValues(0, SparseInputMask::Dense());
245   Node* node0 = graph()->NewNode(op0);
246   NodeVector params(local_zone_);
247   for (int parameter = 0; parameter < parameter_count + 1; ++parameter) {
248     params.push_back(node->InputAt(1 + parameter));
249   }
250   const Operator* op_param = common()->StateValues(
251       static_cast<int>(params.size()), SparseInputMask::Dense());
252   Node* params_node = graph()->NewNode(
253       op_param, static_cast<int>(params.size()), &params.front());
254   return graph()->NewNode(op, params_node, node0, node0,
255                           jsgraph()->UndefinedConstant(), node->InputAt(0),
256                           outer_frame_state);
257 }
258 
259 namespace {
260 
261 // TODO(mstarzinger,verwaest): Move this predicate onto SharedFunctionInfo?
NeedsImplicitReceiver(Handle<SharedFunctionInfo> shared_info)262 bool NeedsImplicitReceiver(Handle<SharedFunctionInfo> shared_info) {
263   DisallowHeapAllocation no_gc;
264   if (!shared_info->construct_as_builtin()) {
265     return !IsDerivedConstructor(shared_info->kind());
266   } else {
267     return false;
268   }
269 }
270 
271 }  // namespace
272 
273 // Determines whether the call target of the given call {node} is statically
274 // known and can be used as an inlining candidate. The {SharedFunctionInfo} of
275 // the call target is provided (the exact closure might be unknown).
DetermineCallTarget(Node * node,Handle<SharedFunctionInfo> & shared_info_out)276 bool JSInliner::DetermineCallTarget(
277     Node* node, Handle<SharedFunctionInfo>& shared_info_out) {
278   DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
279   HeapObjectMatcher match(node->InputAt(0));
280 
281   // This reducer can handle both normal function calls as well a constructor
282   // calls whenever the target is a constant function object, as follows:
283   //  - JSCall(target:constant, receiver, args...)
284   //  - JSConstruct(target:constant, args..., new.target)
285   if (match.HasValue() && match.Value()->IsJSFunction()) {
286     Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value());
287 
288     // Disallow cross native-context inlining for now. This means that all parts
289     // of the resulting code will operate on the same global object. This also
290     // prevents cross context leaks, where we could inline functions from a
291     // different context and hold on to that context (and closure) from the code
292     // object.
293     // TODO(turbofan): We might want to revisit this restriction later when we
294     // have a need for this, and we know how to model different native contexts
295     // in the same graph in a compositional way.
296     if (function->context()->native_context() !=
297         info_->context()->native_context()) {
298       return false;
299     }
300 
301     shared_info_out = handle(function->shared(), isolate());
302     return true;
303   }
304 
305   // This reducer can also handle calls where the target is statically known to
306   // be the result of a closure instantiation operation, as follows:
307   //  - JSCall(JSCreateClosure[shared](context), receiver, args...)
308   //  - JSConstruct(JSCreateClosure[shared](context), args..., new.target)
309   if (match.IsJSCreateClosure()) {
310     CreateClosureParameters const& p = CreateClosureParametersOf(match.op());
311 
312     // Disallow inlining in case the instantiation site was never run and hence
313     // the vector cell does not contain a valid feedback vector for the call
314     // target.
315     // TODO(turbofan): We might consider to eagerly create the feedback vector
316     // in such a case (in {DetermineCallContext} below) eventually.
317     Handle<FeedbackCell> cell = p.feedback_cell();
318     if (!cell->value()->IsFeedbackVector()) return false;
319 
320     shared_info_out = p.shared_info();
321     return true;
322   }
323 
324   return false;
325 }
326 
327 // Determines statically known information about the call target (assuming that
328 // the call target is known according to {DetermineCallTarget} above). The
329 // following static information is provided:
330 //  - context         : The context (as SSA value) bound by the call target.
331 //  - feedback_vector : The target is guaranteed to use this feedback vector.
DetermineCallContext(Node * node,Node * & context_out,Handle<FeedbackVector> & feedback_vector_out)332 void JSInliner::DetermineCallContext(
333     Node* node, Node*& context_out,
334     Handle<FeedbackVector>& feedback_vector_out) {
335   DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
336   HeapObjectMatcher match(node->InputAt(0));
337 
338   if (match.HasValue() && match.Value()->IsJSFunction()) {
339     Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value());
340 
341     // If the target function was never invoked, its feedback cell array might
342     // not contain a feedback vector. We ensure at this point that it's created.
343     JSFunction::EnsureFeedbackVector(function);
344 
345     // The inlinee specializes to the context from the JSFunction object.
346     context_out = jsgraph()->Constant(handle(function->context(), isolate()));
347     feedback_vector_out = handle(function->feedback_vector(), isolate());
348     return;
349   }
350 
351   if (match.IsJSCreateClosure()) {
352     CreateClosureParameters const& p = CreateClosureParametersOf(match.op());
353 
354     // Load the feedback vector of the target by looking up its vector cell at
355     // the instantiation site (we only decide to inline if it's populated).
356     Handle<FeedbackCell> cell = p.feedback_cell();
357     DCHECK(cell->value()->IsFeedbackVector());
358 
359     // The inlinee uses the locally provided context at instantiation.
360     context_out = NodeProperties::GetContextInput(match.node());
361     feedback_vector_out =
362         handle(FeedbackVector::cast(cell->value()), isolate());
363     return;
364   }
365 
366   // Must succeed.
367   UNREACHABLE();
368 }
369 
Reduce(Node * node)370 Reduction JSInliner::Reduce(Node* node) {
371   if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange();
372   return ReduceJSCall(node);
373 }
374 
native_context() const375 Handle<Context> JSInliner::native_context() const {
376   return handle(info_->context()->native_context(), isolate());
377 }
378 
ReduceJSCall(Node * node)379 Reduction JSInliner::ReduceJSCall(Node* node) {
380   DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
381   Handle<SharedFunctionInfo> shared_info;
382   JSCallAccessor call(node);
383 
384   // Determine the call target.
385   if (!DetermineCallTarget(node, shared_info)) return NoChange();
386 
387   // Function must be inlineable.
388   if (!shared_info->IsInlineable()) {
389     TRACE("Not inlining %s into %s because callee is not inlineable\n",
390           shared_info->DebugName()->ToCString().get(),
391           info_->shared_info()->DebugName()->ToCString().get());
392     return NoChange();
393   }
394 
395   // Constructor must be constructable.
396   if (node->opcode() == IrOpcode::kJSConstruct &&
397       !IsConstructable(shared_info->kind())) {
398     TRACE("Not inlining %s into %s because constructor is not constructable.\n",
399           shared_info->DebugName()->ToCString().get(),
400           info_->shared_info()->DebugName()->ToCString().get());
401     return NoChange();
402   }
403 
404   // Class constructors are callable, but [[Call]] will raise an exception.
405   // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
406   if (node->opcode() == IrOpcode::kJSCall &&
407       IsClassConstructor(shared_info->kind())) {
408     TRACE("Not inlining %s into %s because callee is a class constructor.\n",
409           shared_info->DebugName()->ToCString().get(),
410           info_->shared_info()->DebugName()->ToCString().get());
411     return NoChange();
412   }
413 
414   // Function contains break points.
415   if (shared_info->HasBreakInfo()) {
416     TRACE("Not inlining %s into %s because callee may contain break points\n",
417           shared_info->DebugName()->ToCString().get(),
418           info_->shared_info()->DebugName()->ToCString().get());
419     return NoChange();
420   }
421 
422   // To ensure inlining always terminates, we have an upper limit on inlining
423   // the nested calls.
424   int nesting_level = 0;
425   for (Node* frame_state = call.frame_state();
426        frame_state->opcode() == IrOpcode::kFrameState;
427        frame_state = frame_state->InputAt(kFrameStateOuterStateInput)) {
428     nesting_level++;
429     if (nesting_level > kMaxDepthForInlining) {
430       TRACE(
431           "Not inlining %s into %s because call has exceeded the maximum depth "
432           "for function inlining\n",
433           shared_info->DebugName()->ToCString().get(),
434           info_->shared_info()->DebugName()->ToCString().get());
435       return NoChange();
436     }
437   }
438 
439   // Calls surrounded by a local try-block are only inlined if the appropriate
440   // flag is active. We also discover the {IfException} projection this way.
441   Node* exception_target = nullptr;
442   if (NodeProperties::IsExceptionalCall(node, &exception_target) &&
443       !FLAG_inline_into_try) {
444     TRACE(
445         "Try block surrounds #%d:%s and --no-inline-into-try active, so not "
446         "inlining %s into %s.\n",
447         exception_target->id(), exception_target->op()->mnemonic(),
448         shared_info->DebugName()->ToCString().get(),
449         info_->shared_info()->DebugName()->ToCString().get());
450     return NoChange();
451   }
452 
453   if (!shared_info->is_compiled() &&
454       !Compiler::Compile(shared_info, Compiler::CLEAR_EXCEPTION)) {
455     TRACE("Not inlining %s into %s because bytecode generation failed\n",
456           shared_info->DebugName()->ToCString().get(),
457           info_->shared_info()->DebugName()->ToCString().get());
458     return NoChange();
459   }
460 
461   // ----------------------------------------------------------------
462   // After this point, we've made a decision to inline this function.
463   // We shall not bailout from inlining if we got here.
464 
465   TRACE("Inlining %s into %s%s\n", shared_info->DebugName()->ToCString().get(),
466         info_->shared_info()->DebugName()->ToCString().get(),
467         (exception_target != nullptr) ? " (inside try-block)" : "");
468 
469   // Determine the targets feedback vector and its context.
470   Node* context;
471   Handle<FeedbackVector> feedback_vector;
472   DetermineCallContext(node, context, feedback_vector);
473 
474   // Remember that we inlined this function.
475   int inlining_id = info_->AddInlinedFunction(
476       shared_info, source_positions_->GetSourcePosition(node));
477 
478   // Create the subgraph for the inlinee.
479   Node* start;
480   Node* end;
481   {
482     // Run the BytecodeGraphBuilder to create the subgraph.
483     Graph::SubgraphScope scope(graph());
484     JSTypeHintLowering::Flags flags = JSTypeHintLowering::kNoFlags;
485     if (info_->is_bailout_on_uninitialized()) {
486       flags |= JSTypeHintLowering::kBailoutOnUninitialized;
487     }
488     CallFrequency frequency = call.frequency();
489     BytecodeGraphBuilder graph_builder(
490         zone(), shared_info, feedback_vector, BailoutId::None(), jsgraph(),
491         frequency, source_positions_, native_context(), inlining_id,
492         flags, false, info_->is_analyze_environment_liveness());
493     graph_builder.CreateGraph();
494 
495     // Extract the inlinee start/end nodes.
496     start = graph()->start();
497     end = graph()->end();
498   }
499 
500   // If we are inlining into a surrounding exception handler, we collect all
501   // potentially throwing nodes within the inlinee that are not handled locally
502   // by the inlinee itself. They are later wired into the surrounding handler.
503   NodeVector uncaught_subcalls(local_zone_);
504   if (exception_target != nullptr) {
505     // Find all uncaught 'calls' in the inlinee.
506     AllNodes inlined_nodes(local_zone_, end, graph());
507     for (Node* subnode : inlined_nodes.reachable) {
508       // Every possibly throwing node should get {IfSuccess} and {IfException}
509       // projections, unless there already is local exception handling.
510       if (subnode->op()->HasProperty(Operator::kNoThrow)) continue;
511       if (!NodeProperties::IsExceptionalCall(subnode)) {
512         DCHECK_EQ(2, subnode->op()->ControlOutputCount());
513         uncaught_subcalls.push_back(subnode);
514       }
515     }
516   }
517 
518   Node* frame_state = call.frame_state();
519   Node* new_target = jsgraph()->UndefinedConstant();
520 
521   // Inline {JSConstruct} requires some additional magic.
522   if (node->opcode() == IrOpcode::kJSConstruct) {
523     // Swizzle the inputs of the {JSConstruct} node to look like inputs to a
524     // normal {JSCall} node so that the rest of the inlining machinery
525     // behaves as if we were dealing with a regular function invocation.
526     new_target = call.new_target();  // Retrieve new target value input.
527     node->RemoveInput(call.formal_arguments() + 1);  // Drop new target.
528     node->InsertInput(graph()->zone(), 1, new_target);
529 
530     // Insert nodes around the call that model the behavior required for a
531     // constructor dispatch (allocate implicit receiver and check return value).
532     // This models the behavior usually accomplished by our {JSConstructStub}.
533     // Note that the context has to be the callers context (input to call node).
534     // Also note that by splitting off the {JSCreate} piece of the constructor
535     // call, we create an observable deoptimization point after the receiver
536     // instantiation but before the invocation (i.e. inside {JSConstructStub}
537     // where execution continues at {construct_stub_create_deopt_pc_offset}).
538     Node* receiver = jsgraph()->TheHoleConstant();  // Implicit receiver.
539     if (NeedsImplicitReceiver(shared_info)) {
540       Node* effect = NodeProperties::GetEffectInput(node);
541       Node* control = NodeProperties::GetControlInput(node);
542       Node* context = NodeProperties::GetContextInput(node);
543       Node* frame_state_inside = CreateArtificialFrameState(
544           node, frame_state, call.formal_arguments(),
545           BailoutId::ConstructStubCreate(), FrameStateType::kConstructStub,
546           shared_info);
547       Node* create =
548           graph()->NewNode(javascript()->Create(), call.target(), new_target,
549                            context, frame_state_inside, effect, control);
550       uncaught_subcalls.push_back(create);  // Adds {IfSuccess} & {IfException}.
551       NodeProperties::ReplaceControlInput(node, create);
552       NodeProperties::ReplaceEffectInput(node, create);
553       // Placeholder to hold {node}'s value dependencies while {node} is
554       // replaced.
555       Node* dummy = graph()->NewNode(common()->Dead());
556       NodeProperties::ReplaceUses(node, dummy, node, node, node);
557       Node* result;
558       // Insert a check of the return value to determine whether the return
559       // value or the implicit receiver should be selected as a result of the
560       // call.
561       Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), node);
562       result =
563           graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
564                            check, node, create);
565       receiver = create;  // The implicit receiver.
566       ReplaceWithValue(dummy, result);
567     } else if (IsDerivedConstructor(shared_info->kind())) {
568       Node* node_success =
569           NodeProperties::FindSuccessfulControlProjection(node);
570       Node* is_receiver =
571           graph()->NewNode(simplified()->ObjectIsReceiver(), node);
572       Node* branch_is_receiver =
573           graph()->NewNode(common()->Branch(), is_receiver, node_success);
574       Node* branch_is_receiver_true =
575           graph()->NewNode(common()->IfTrue(), branch_is_receiver);
576       Node* branch_is_receiver_false =
577           graph()->NewNode(common()->IfFalse(), branch_is_receiver);
578       branch_is_receiver_false =
579           graph()->NewNode(javascript()->CallRuntime(
580                                Runtime::kThrowConstructorReturnedNonObject),
581                            context, NodeProperties::GetFrameStateInput(node),
582                            node, branch_is_receiver_false);
583       uncaught_subcalls.push_back(branch_is_receiver_false);
584       branch_is_receiver_false =
585           graph()->NewNode(common()->Throw(), branch_is_receiver_false,
586                            branch_is_receiver_false);
587       NodeProperties::MergeControlToEnd(graph(), common(),
588                                         branch_is_receiver_false);
589 
590       ReplaceWithValue(node_success, node_success, node_success,
591                        branch_is_receiver_true);
592       // Fix input destroyed by the above {ReplaceWithValue} call.
593       NodeProperties::ReplaceControlInput(branch_is_receiver, node_success, 0);
594     }
595     node->ReplaceInput(1, receiver);
596     // Insert a construct stub frame into the chain of frame states. This will
597     // reconstruct the proper frame when deoptimizing within the constructor.
598     frame_state =
599         CreateArtificialFrameState(node, frame_state, call.formal_arguments(),
600                                    BailoutId::ConstructStubInvoke(),
601                                    FrameStateType::kConstructStub, shared_info);
602   }
603 
604   // Insert a JSConvertReceiver node for sloppy callees. Note that the context
605   // passed into this node has to be the callees context (loaded above).
606   if (node->opcode() == IrOpcode::kJSCall &&
607       is_sloppy(shared_info->language_mode()) && !shared_info->native()) {
608     Node* effect = NodeProperties::GetEffectInput(node);
609     if (NodeProperties::CanBePrimitive(isolate(), call.receiver(), effect)) {
610       CallParameters const& p = CallParametersOf(node->op());
611       Node* global_proxy = jsgraph()->HeapConstant(
612           handle(info_->native_context()->global_proxy(), isolate()));
613       Node* receiver = effect =
614           graph()->NewNode(simplified()->ConvertReceiver(p.convert_mode()),
615                            call.receiver(), global_proxy, effect, start);
616       NodeProperties::ReplaceValueInput(node, receiver, 1);
617       NodeProperties::ReplaceEffectInput(node, effect);
618     }
619   }
620 
621   // Insert argument adaptor frame if required. The callees formal parameter
622   // count (i.e. value outputs of start node minus target, receiver, new target,
623   // arguments count and context) have to match the number of arguments passed
624   // to the call.
625   int parameter_count = shared_info->internal_formal_parameter_count();
626   DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 5);
627   if (call.formal_arguments() != parameter_count) {
628     frame_state = CreateArtificialFrameState(
629         node, frame_state, call.formal_arguments(), BailoutId::None(),
630         FrameStateType::kArgumentsAdaptor, shared_info);
631   }
632 
633   return InlineCall(node, new_target, context, frame_state, start, end,
634                     exception_target, uncaught_subcalls);
635 }
636 
graph() const637 Graph* JSInliner::graph() const { return jsgraph()->graph(); }
638 
javascript() const639 JSOperatorBuilder* JSInliner::javascript() const {
640   return jsgraph()->javascript();
641 }
642 
common() const643 CommonOperatorBuilder* JSInliner::common() const { return jsgraph()->common(); }
644 
simplified() const645 SimplifiedOperatorBuilder* JSInliner::simplified() const {
646   return jsgraph()->simplified();
647 }
648 
649 #undef TRACE
650 
651 }  // namespace compiler
652 }  // namespace internal
653 }  // namespace v8
654