blob: 0e122a6c14de1589e512d9d475236a255d069d3d [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Ben Murdoch014dc512016-03-22 12:00:34 +00005#include "src/compiler/js-inlining.h"
6
Ben Murdoch014dc512016-03-22 12:00:34 +00007#include "src/ast/ast-numbering.h"
Ben Murdoch13e2dad2016-09-16 13:49:30 +01008#include "src/ast/ast.h"
Ben Murdochf3b273f2017-01-17 12:11:28 +00009#include "src/compilation-info.h"
Ben Murdoch014dc512016-03-22 12:00:34 +000010#include "src/compiler.h"
Ben Murdochf3b273f2017-01-17 12:11:28 +000011#include "src/compiler/all-nodes.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012#include "src/compiler/ast-graph-builder.h"
Ben Murdoch13e2dad2016-09-16 13:49:30 +010013#include "src/compiler/ast-loop-assignment-analyzer.h"
Ben Murdochf3b273f2017-01-17 12:11:28 +000014#include "src/compiler/bytecode-graph-builder.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015#include "src/compiler/common-operator.h"
Ben Murdoch014dc512016-03-22 12:00:34 +000016#include "src/compiler/graph-reducer.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017#include "src/compiler/js-operator.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018#include "src/compiler/node-matchers.h"
Ben Murdoch014dc512016-03-22 12:00:34 +000019#include "src/compiler/node-properties.h"
20#include "src/compiler/operator-properties.h"
Ben Murdochf91f0612016-11-29 16:50:11 +000021#include "src/compiler/simplified-operator.h"
Ben Murdoch13e2dad2016-09-16 13:49:30 +010022#include "src/compiler/type-hint-analyzer.h"
Ben Murdoch014dc512016-03-22 12:00:34 +000023#include "src/isolate-inl.h"
Ben Murdochf91f0612016-11-29 16:50:11 +000024#include "src/parsing/parse-info.h"
Ben Murdoch014dc512016-03-22 12:00:34 +000025#include "src/parsing/rewriter.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000026
27namespace v8 {
28namespace internal {
29namespace compiler {
30
Ben Murdoch014dc512016-03-22 12:00:34 +000031#define TRACE(...) \
32 do { \
33 if (FLAG_trace_turbo_inlining) PrintF(__VA_ARGS__); \
34 } while (false)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035
Ben Murdoch014dc512016-03-22 12:00:34 +000036
37// Provides convenience accessors for the common layout of nodes having either
38// the {JSCallFunction} or the {JSCallConstruct} operator.
39class JSCallAccessor {
40 public:
41 explicit JSCallAccessor(Node* call) : call_(call) {
42 DCHECK(call->opcode() == IrOpcode::kJSCallFunction ||
43 call->opcode() == IrOpcode::kJSCallConstruct);
44 }
45
46 Node* target() {
47 // Both, {JSCallFunction} and {JSCallConstruct}, have same layout here.
48 return call_->InputAt(0);
49 }
50
51 Node* receiver() {
52 DCHECK_EQ(IrOpcode::kJSCallFunction, call_->opcode());
53 return call_->InputAt(1);
54 }
55
56 Node* new_target() {
57 DCHECK_EQ(IrOpcode::kJSCallConstruct, call_->opcode());
58 return call_->InputAt(formal_arguments() + 1);
59 }
60
Ben Murdoch13e2dad2016-09-16 13:49:30 +010061 Node* frame_state() {
62 // Both, {JSCallFunction} and {JSCallConstruct}, have frame state.
Ben Murdochf91f0612016-11-29 16:50:11 +000063 return NodeProperties::GetFrameStateInput(call_);
Ben Murdoch014dc512016-03-22 12:00:34 +000064 }
65
66 int formal_arguments() {
67 // Both, {JSCallFunction} and {JSCallConstruct}, have two extra inputs:
68 // - JSCallConstruct: Includes target function and new target.
69 // - JSCallFunction: Includes target function and receiver.
70 return call_->op()->ValueInputCount() - 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000071 }
72
Ben Murdochf3b273f2017-01-17 12:11:28 +000073 float frequency() const {
74 return (call_->opcode() == IrOpcode::kJSCallFunction)
75 ? CallFunctionParametersOf(call_->op()).frequency()
76 : CallConstructParametersOf(call_->op()).frequency();
77 }
78
Ben Murdochb8a8cc12014-11-26 15:28:44 +000079 private:
Ben Murdoch014dc512016-03-22 12:00:34 +000080 Node* call_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000081};
82
Ben Murdoch014dc512016-03-22 12:00:34 +000083Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
Ben Murdochf3b273f2017-01-17 12:11:28 +000084 Node* frame_state, Node* start, Node* end,
85 Node* exception_target,
86 const NodeVector& uncaught_subcalls) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000087 // The scheduler is smart enough to place our code; we just ensure {control}
Ben Murdoch014dc512016-03-22 12:00:34 +000088 // becomes the control input of the start of the inlinee, and {effect} becomes
89 // the effect input of the start of the inlinee.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000090 Node* control = NodeProperties::GetControlInput(call);
Ben Murdoch014dc512016-03-22 12:00:34 +000091 Node* effect = NodeProperties::GetEffectInput(call);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000092
Ben Murdoch014dc512016-03-22 12:00:34 +000093 int const inlinee_new_target_index =
94 static_cast<int>(start->op()->ValueOutputCount()) - 3;
95 int const inlinee_arity_index =
96 static_cast<int>(start->op()->ValueOutputCount()) - 2;
97 int const inlinee_context_index =
98 static_cast<int>(start->op()->ValueOutputCount()) - 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000099
Ben Murdoch014dc512016-03-22 12:00:34 +0000100 // {inliner_inputs} counts JSFunction, receiver, arguments, but not
101 // new target value, argument count, context, effect or control.
Emily Bernier958fae72015-03-24 16:35:39 -0400102 int inliner_inputs = call->op()->ValueInputCount();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000103 // Iterate over all uses of the start node.
Ben Murdoch014dc512016-03-22 12:00:34 +0000104 for (Edge edge : start->use_edges()) {
Emily Bernier958fae72015-03-24 16:35:39 -0400105 Node* use = edge.from();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000106 switch (use->opcode()) {
107 case IrOpcode::kParameter: {
Ben Murdoch014dc512016-03-22 12:00:34 +0000108 int index = 1 + ParameterIndexOf(use->op());
109 DCHECK_LE(index, inlinee_context_index);
110 if (index < inliner_inputs && index < inlinee_new_target_index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000111 // There is an input from the call, and the index is a value
112 // projection but not the context, so rewire the input.
Ben Murdoch014dc512016-03-22 12:00:34 +0000113 Replace(use, call->InputAt(index));
114 } else if (index == inlinee_new_target_index) {
115 // The projection is requesting the new target value.
116 Replace(use, new_target);
117 } else if (index == inlinee_arity_index) {
118 // The projection is requesting the number of arguments.
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000119 Replace(use, jsgraph()->Constant(inliner_inputs - 2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000120 } else if (index == inlinee_context_index) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000121 // The projection is requesting the inlinee function context.
122 Replace(use, context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000123 } else {
Ben Murdoch014dc512016-03-22 12:00:34 +0000124 // Call has fewer arguments than required, fill with undefined.
Ben Murdochf91f0612016-11-29 16:50:11 +0000125 Replace(use, jsgraph()->UndefinedConstant());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000126 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000127 break;
128 }
129 default:
Emily Bernier958fae72015-03-24 16:35:39 -0400130 if (NodeProperties::IsEffectEdge(edge)) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000131 edge.UpdateTo(effect);
Emily Bernier958fae72015-03-24 16:35:39 -0400132 } else if (NodeProperties::IsControlEdge(edge)) {
133 edge.UpdateTo(control);
Ben Murdoch014dc512016-03-22 12:00:34 +0000134 } else if (NodeProperties::IsFrameStateEdge(edge)) {
135 edge.UpdateTo(frame_state);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000136 } else {
137 UNREACHABLE();
138 }
139 break;
140 }
141 }
142
Ben Murdochf3b273f2017-01-17 12:11:28 +0000143 if (exception_target != nullptr) {
144 // Link uncaught calls in the inlinee to {exception_target}
145 int subcall_count = static_cast<int>(uncaught_subcalls.size());
146 if (subcall_count > 0) {
147 TRACE(
148 "Inlinee contains %d calls without IfException; "
149 "linking to existing IfException\n",
150 subcall_count);
151 }
152 NodeVector on_exception_nodes(local_zone_);
153 for (Node* subcall : uncaught_subcalls) {
154 Node* on_exception =
155 graph()->NewNode(common()->IfException(), subcall, subcall);
156 on_exception_nodes.push_back(on_exception);
157 }
158
159 DCHECK_EQ(subcall_count, static_cast<int>(on_exception_nodes.size()));
160 if (subcall_count > 0) {
161 Node* control_output =
162 graph()->NewNode(common()->Merge(subcall_count), subcall_count,
163 &on_exception_nodes.front());
164 NodeVector values_effects(local_zone_);
165 values_effects = on_exception_nodes;
166 values_effects.push_back(control_output);
167 Node* value_output = graph()->NewNode(
168 common()->Phi(MachineRepresentation::kTagged, subcall_count),
169 subcall_count + 1, &values_effects.front());
170 Node* effect_output =
171 graph()->NewNode(common()->EffectPhi(subcall_count),
172 subcall_count + 1, &values_effects.front());
173 ReplaceWithValue(exception_target, value_output, effect_output,
174 control_output);
175 } else {
176 ReplaceWithValue(exception_target, exception_target, exception_target,
177 jsgraph()->Dead());
178 }
179 }
180
Ben Murdoch014dc512016-03-22 12:00:34 +0000181 NodeVector values(local_zone_);
182 NodeVector effects(local_zone_);
183 NodeVector controls(local_zone_);
184 for (Node* const input : end->inputs()) {
185 switch (input->opcode()) {
186 case IrOpcode::kReturn:
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000187 values.push_back(NodeProperties::GetValueInput(input, 1));
Ben Murdoch014dc512016-03-22 12:00:34 +0000188 effects.push_back(NodeProperties::GetEffectInput(input));
189 controls.push_back(NodeProperties::GetControlInput(input));
190 break;
191 case IrOpcode::kDeoptimize:
192 case IrOpcode::kTerminate:
193 case IrOpcode::kThrow:
Ben Murdochf91f0612016-11-29 16:50:11 +0000194 NodeProperties::MergeControlToEnd(graph(), common(), input);
195 Revisit(graph()->end());
Ben Murdoch014dc512016-03-22 12:00:34 +0000196 break;
197 default:
198 UNREACHABLE();
199 break;
200 }
201 }
202 DCHECK_EQ(values.size(), effects.size());
203 DCHECK_EQ(values.size(), controls.size());
204
205 // Depending on whether the inlinee produces a value, we either replace value
206 // uses with said value or kill value uses if no value can be returned.
207 if (values.size() > 0) {
208 int const input_count = static_cast<int>(controls.size());
Ben Murdochf91f0612016-11-29 16:50:11 +0000209 Node* control_output = graph()->NewNode(common()->Merge(input_count),
210 input_count, &controls.front());
Ben Murdoch014dc512016-03-22 12:00:34 +0000211 values.push_back(control_output);
212 effects.push_back(control_output);
Ben Murdochf91f0612016-11-29 16:50:11 +0000213 Node* value_output = graph()->NewNode(
214 common()->Phi(MachineRepresentation::kTagged, input_count),
Ben Murdoch014dc512016-03-22 12:00:34 +0000215 static_cast<int>(values.size()), &values.front());
Ben Murdochf91f0612016-11-29 16:50:11 +0000216 Node* effect_output =
217 graph()->NewNode(common()->EffectPhi(input_count),
218 static_cast<int>(effects.size()), &effects.front());
Ben Murdoch014dc512016-03-22 12:00:34 +0000219 ReplaceWithValue(call, value_output, effect_output, control_output);
220 return Changed(value_output);
221 } else {
Ben Murdochf91f0612016-11-29 16:50:11 +0000222 ReplaceWithValue(call, call, call, jsgraph()->Dead());
Ben Murdoch014dc512016-03-22 12:00:34 +0000223 return Changed(call);
224 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000225}
226
227
Ben Murdoch014dc512016-03-22 12:00:34 +0000228Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
229 int parameter_count,
230 FrameStateType frame_state_type,
231 Handle<SharedFunctionInfo> shared) {
232 const FrameStateFunctionInfo* state_info =
Ben Murdochf91f0612016-11-29 16:50:11 +0000233 common()->CreateFrameStateFunctionInfo(frame_state_type,
234 parameter_count + 1, 0, shared);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000235
Ben Murdochf91f0612016-11-29 16:50:11 +0000236 const Operator* op = common()->FrameState(
Ben Murdoch014dc512016-03-22 12:00:34 +0000237 BailoutId(-1), OutputFrameStateCombine::Ignore(), state_info);
Ben Murdochf91f0612016-11-29 16:50:11 +0000238 const Operator* op0 = common()->StateValues(0);
239 Node* node0 = graph()->NewNode(op0);
Ben Murdoch014dc512016-03-22 12:00:34 +0000240 NodeVector params(local_zone_);
241 for (int parameter = 0; parameter < parameter_count + 1; ++parameter) {
242 params.push_back(node->InputAt(1 + parameter));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000243 }
244 const Operator* op_param =
Ben Murdochf91f0612016-11-29 16:50:11 +0000245 common()->StateValues(static_cast<int>(params.size()));
246 Node* params_node = graph()->NewNode(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000247 op_param, static_cast<int>(params.size()), &params.front());
Ben Murdochf91f0612016-11-29 16:50:11 +0000248 return graph()->NewNode(op, params_node, node0, node0,
249 jsgraph()->UndefinedConstant(), node->InputAt(0),
250 outer_frame_state);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000251}
252
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100253Node* JSInliner::CreateTailCallerFrameState(Node* node, Node* frame_state) {
254 FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state);
255 Handle<SharedFunctionInfo> shared;
256 frame_info.shared_info().ToHandle(&shared);
257
258 Node* function = frame_state->InputAt(kFrameStateFunctionInput);
259
260 // If we are inlining a tail call drop caller's frame state and an
261 // arguments adaptor if it exists.
Ben Murdochf91f0612016-11-29 16:50:11 +0000262 frame_state = NodeProperties::GetFrameStateInput(frame_state);
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100263 if (frame_state->opcode() == IrOpcode::kFrameState) {
264 FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state);
265 if (frame_info.type() == FrameStateType::kArgumentsAdaptor) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000266 frame_state = NodeProperties::GetFrameStateInput(frame_state);
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100267 }
268 }
269
270 const FrameStateFunctionInfo* state_info =
Ben Murdochf91f0612016-11-29 16:50:11 +0000271 common()->CreateFrameStateFunctionInfo(
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100272 FrameStateType::kTailCallerFunction, 0, 0, shared);
273
Ben Murdochf91f0612016-11-29 16:50:11 +0000274 const Operator* op = common()->FrameState(
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100275 BailoutId(-1), OutputFrameStateCombine::Ignore(), state_info);
Ben Murdochf91f0612016-11-29 16:50:11 +0000276 const Operator* op0 = common()->StateValues(0);
277 Node* node0 = graph()->NewNode(op0);
278 return graph()->NewNode(op, node0, node0, node0,
279 jsgraph()->UndefinedConstant(), function,
280 frame_state);
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100281}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000282
Ben Murdoch014dc512016-03-22 12:00:34 +0000283namespace {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000285// TODO(turbofan): Shall we move this to the NodeProperties? Or some (untyped)
286// alias analyzer?
287bool IsSame(Node* a, Node* b) {
288 if (a == b) {
289 return true;
290 } else if (a->opcode() == IrOpcode::kCheckHeapObject) {
291 return IsSame(a->InputAt(0), b);
292 } else if (b->opcode() == IrOpcode::kCheckHeapObject) {
293 return IsSame(a, b->InputAt(0));
294 }
295 return false;
296}
297
Ben Murdochf3b273f2017-01-17 12:11:28 +0000298// TODO(bmeurer): Unify this with the witness helper functions in the
299// js-builtin-reducer.cc once we have a better understanding of the
300// map tracking we want to do, and eventually changed the CheckMaps
301// operator to carry map constants on the operator instead of inputs.
302// I.e. if the CheckMaps has some kind of SmallMapSet as operator
303// parameter, then this could be changed to call a generic
304//
305// SmallMapSet NodeProperties::CollectMapWitness(receiver, effect)
306//
307// function, which either returns the map set from the CheckMaps or
308// a singleton set from a StoreField.
309bool NeedsConvertReceiver(Node* receiver, Node* effect) {
310 for (Node* dominator = effect;;) {
311 if (dominator->opcode() == IrOpcode::kCheckMaps &&
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000312 IsSame(dominator->InputAt(0), receiver)) {
Ben Murdochf3b273f2017-01-17 12:11:28 +0000313 // Check if all maps have the given {instance_type}.
314 for (int i = 1; i < dominator->op()->ValueInputCount(); ++i) {
315 HeapObjectMatcher m(NodeProperties::GetValueInput(dominator, i));
316 if (!m.HasValue()) return true;
317 Handle<Map> const map = Handle<Map>::cast(m.Value());
318 if (!map->IsJSReceiverMap()) return true;
319 }
320 return false;
321 }
322 switch (dominator->opcode()) {
323 case IrOpcode::kStoreField: {
324 FieldAccess const& access = FieldAccessOf(dominator->op());
325 if (access.base_is_tagged == kTaggedBase &&
326 access.offset == HeapObject::kMapOffset) {
327 return true;
328 }
329 break;
330 }
331 case IrOpcode::kStoreElement:
332 case IrOpcode::kStoreTypedElement:
333 break;
334 default: {
335 DCHECK_EQ(1, dominator->op()->EffectOutputCount());
336 if (dominator->op()->EffectInputCount() != 1 ||
337 !dominator->op()->HasProperty(Operator::kNoWrite)) {
338 // Didn't find any appropriate CheckMaps node.
339 return true;
340 }
341 break;
342 }
343 }
344 dominator = NodeProperties::GetEffectInput(dominator);
345 }
346}
347
Ben Murdoch014dc512016-03-22 12:00:34 +0000348// TODO(mstarzinger,verwaest): Move this predicate onto SharedFunctionInfo?
Ben Murdoch109988c2016-05-18 11:27:45 +0100349bool NeedsImplicitReceiver(Handle<SharedFunctionInfo> shared_info) {
350 DisallowHeapAllocation no_gc;
351 Isolate* const isolate = shared_info->GetIsolate();
352 Code* const construct_stub = shared_info->construct_stub();
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100353 return construct_stub != *isolate->builtins()->JSBuiltinsConstructStub() &&
354 construct_stub !=
355 *isolate->builtins()->JSBuiltinsConstructStubForDerived() &&
356 construct_stub != *isolate->builtins()->JSConstructStubApi();
Ben Murdoch109988c2016-05-18 11:27:45 +0100357}
358
359bool IsNonConstructible(Handle<SharedFunctionInfo> shared_info) {
360 DisallowHeapAllocation no_gc;
361 Isolate* const isolate = shared_info->GetIsolate();
362 Code* const construct_stub = shared_info->construct_stub();
363 return construct_stub == *isolate->builtins()->ConstructedNonConstructable();
Ben Murdoch014dc512016-03-22 12:00:34 +0000364}
365
366} // namespace
367
368
369Reduction JSInliner::Reduce(Node* node) {
370 if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange();
371
372 // This reducer can handle both normal function calls as well a constructor
373 // calls whenever the target is a constant function object, as follows:
374 // - JSCallFunction(target:constant, receiver, args...)
375 // - JSCallConstruct(target:constant, args..., new.target)
376 HeapObjectMatcher match(node->InputAt(0));
377 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange();
378 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value());
379
380 return ReduceJSCall(node, function);
381}
382
Ben Murdoch014dc512016-03-22 12:00:34 +0000383Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
384 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
385 JSCallAccessor call(node);
Ben Murdoch109988c2016-05-18 11:27:45 +0100386 Handle<SharedFunctionInfo> shared_info(function->shared());
Ben Murdoch014dc512016-03-22 12:00:34 +0000387
388 // Function must be inlineable.
Ben Murdoch109988c2016-05-18 11:27:45 +0100389 if (!shared_info->IsInlineable()) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000390 TRACE("Not inlining %s into %s because callee is not inlineable\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100391 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000392 info_->shared_info()->DebugName()->ToCString().get());
393 return NoChange();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000394 }
395
Ben Murdoch014dc512016-03-22 12:00:34 +0000396 // Constructor must be constructable.
397 if (node->opcode() == IrOpcode::kJSCallConstruct &&
Ben Murdoch109988c2016-05-18 11:27:45 +0100398 IsNonConstructible(shared_info)) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000399 TRACE("Not inlining %s into %s because constructor is not constructable.\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100400 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000401 info_->shared_info()->DebugName()->ToCString().get());
402 return NoChange();
403 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000404
Ben Murdoch014dc512016-03-22 12:00:34 +0000405 // Class constructors are callable, but [[Call]] will raise an exception.
406 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
407 if (node->opcode() == IrOpcode::kJSCallFunction &&
Ben Murdoch109988c2016-05-18 11:27:45 +0100408 IsClassConstructor(shared_info->kind())) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000409 TRACE("Not inlining %s into %s because callee is a class constructor.\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100410 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000411 info_->shared_info()->DebugName()->ToCString().get());
412 return NoChange();
413 }
414
415 // Function contains break points.
Ben Murdoch109988c2016-05-18 11:27:45 +0100416 if (shared_info->HasDebugInfo()) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000417 TRACE("Not inlining %s into %s because callee may contain break points\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100418 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000419 info_->shared_info()->DebugName()->ToCString().get());
420 return NoChange();
421 }
422
423 // Disallow cross native-context inlining for now. This means that all parts
424 // of the resulting code will operate on the same global object.
425 // This also prevents cross context leaks for asm.js code, where we could
426 // inline functions from a different context and hold on to that context (and
427 // closure) from the code object.
428 // TODO(turbofan): We might want to revisit this restriction later when we
429 // have a need for this, and we know how to model different native contexts
430 // in the same graph in a compositional way.
431 if (function->context()->native_context() !=
432 info_->context()->native_context()) {
433 TRACE("Not inlining %s into %s because of different native contexts\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100434 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000435 info_->shared_info()->DebugName()->ToCString().get());
436 return NoChange();
437 }
438
439 // TODO(turbofan): TranslatedState::GetAdaptedArguments() currently relies on
440 // not inlining recursive functions. We might want to relax that at some
441 // point.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100442 for (Node* frame_state = call.frame_state();
Ben Murdoch014dc512016-03-22 12:00:34 +0000443 frame_state->opcode() == IrOpcode::kFrameState;
444 frame_state = frame_state->InputAt(kFrameStateOuterStateInput)) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100445 FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state);
446 Handle<SharedFunctionInfo> frame_shared_info;
447 if (frame_info.shared_info().ToHandle(&frame_shared_info) &&
448 *frame_shared_info == *shared_info) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000449 TRACE("Not inlining %s into %s because call is recursive\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100450 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000451 info_->shared_info()->DebugName()->ToCString().get());
452 return NoChange();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000453 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000454 }
455
Ben Murdochf3b273f2017-01-17 12:11:28 +0000456 // Find the IfException node, if any.
457 Node* exception_target = nullptr;
458 for (Edge edge : node->use_edges()) {
459 if (NodeProperties::IsControlEdge(edge) &&
460 edge.from()->opcode() == IrOpcode::kIfException) {
461 DCHECK_NULL(exception_target);
462 exception_target = edge.from();
463 }
464 }
465
466 NodeVector uncaught_subcalls(local_zone_);
467
468 if (exception_target != nullptr) {
469 if (!FLAG_inline_into_try) {
470 TRACE(
471 "Try block surrounds #%d:%s and --no-inline-into-try active, so not "
472 "inlining %s into %s.\n",
473 exception_target->id(), exception_target->op()->mnemonic(),
Ben Murdoch109988c2016-05-18 11:27:45 +0100474 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000475 info_->shared_info()->DebugName()->ToCString().get());
Ben Murdochf3b273f2017-01-17 12:11:28 +0000476 return NoChange();
477 } else {
478 TRACE(
479 "Inlining %s into %s regardless of surrounding try-block to catcher "
480 "#%d:%s\n",
481 shared_info->DebugName()->ToCString().get(),
482 info_->shared_info()->DebugName()->ToCString().get(),
483 exception_target->id(), exception_target->op()->mnemonic());
484 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000485 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000486
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000487 Zone zone(info_->isolate()->allocator(), ZONE_NAME);
488 ParseInfo parse_info(&zone, shared_info);
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100489 CompilationInfo info(&parse_info, function);
Ben Murdoch109988c2016-05-18 11:27:45 +0100490 if (info_->is_deoptimization_enabled()) info.MarkAsDeoptimizationEnabled();
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100491 if (info_->is_type_feedback_enabled()) info.MarkAsTypeFeedbackEnabled();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000492 if (info_->is_optimizing_from_bytecode()) info.MarkAsOptimizeFromBytecode();
Ben Murdoch014dc512016-03-22 12:00:34 +0000493
Ben Murdochf3b273f2017-01-17 12:11:28 +0000494 if (info.is_optimizing_from_bytecode() && !Compiler::EnsureBytecode(&info)) {
495 TRACE("Not inlining %s into %s because bytecode generation failed\n",
496 shared_info->DebugName()->ToCString().get(),
497 info_->shared_info()->DebugName()->ToCString().get());
498 if (info_->isolate()->has_pending_exception()) {
499 info_->isolate()->clear_pending_exception();
500 }
501 return NoChange();
502 }
503
504 if (!info.is_optimizing_from_bytecode() &&
505 !Compiler::ParseAndAnalyze(info.parse_info())) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000506 TRACE("Not inlining %s into %s because parsing failed\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100507 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000508 info_->shared_info()->DebugName()->ToCString().get());
509 if (info_->isolate()->has_pending_exception()) {
510 info_->isolate()->clear_pending_exception();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000511 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000512 return NoChange();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000513 }
514
Ben Murdochf3b273f2017-01-17 12:11:28 +0000515 if (!info.is_optimizing_from_bytecode() &&
516 !Compiler::EnsureDeoptimizationSupport(&info)) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000517 TRACE("Not inlining %s into %s because deoptimization support failed\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100518 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000519 info_->shared_info()->DebugName()->ToCString().get());
520 return NoChange();
521 }
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100522
Ben Murdoch014dc512016-03-22 12:00:34 +0000523 // Remember that we inlined this function. This needs to be called right
524 // after we ensure deoptimization support so that the code flusher
525 // does not remove the code with the deoptimization support.
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000526 int inlining_id = info_->AddInlinedFunction(
527 shared_info, source_positions_->GetSourcePosition(node));
Ben Murdoch014dc512016-03-22 12:00:34 +0000528
529 // ----------------------------------------------------------------
530 // After this point, we've made a decision to inline this function.
531 // We shall not bailout from inlining if we got here.
532
533 TRACE("Inlining %s into %s\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100534 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000535 info_->shared_info()->DebugName()->ToCString().get());
536
Ben Murdochf3b273f2017-01-17 12:11:28 +0000537 // If function was lazily compiled, its literals array may not yet be set up.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100538 JSFunction::EnsureLiterals(function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000539
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100540 // Create the subgraph for the inlinee.
541 Node* start;
542 Node* end;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000543 if (info.is_optimizing_from_bytecode()) {
544 // Run the BytecodeGraphBuilder to create the subgraph.
545 Graph::SubgraphScope scope(graph());
546 BytecodeGraphBuilder graph_builder(&zone, &info, jsgraph(),
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000547 call.frequency(), source_positions_,
548 inlining_id);
549 graph_builder.CreateGraph(false);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000550
551 // Extract the inlinee start/end nodes.
552 start = graph()->start();
553 end = graph()->end();
554 } else {
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100555 // Run the loop assignment analyzer on the inlinee.
556 AstLoopAssignmentAnalyzer loop_assignment_analyzer(&zone, &info);
557 LoopAssignmentAnalysis* loop_assignment =
558 loop_assignment_analyzer.Analyze();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000559
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100560 // Run the type hint analyzer on the inlinee.
561 TypeHintAnalyzer type_hint_analyzer(&zone);
562 TypeHintAnalysis* type_hint_analysis =
563 type_hint_analyzer.Analyze(handle(shared_info->code(), info.isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000564
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100565 // Run the AstGraphBuilder to create the subgraph.
566 Graph::SubgraphScope scope(graph());
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000567 AstGraphBuilderWithPositions graph_builder(
568 &zone, &info, jsgraph(), call.frequency(), loop_assignment,
569 type_hint_analysis, source_positions_, inlining_id);
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100570 graph_builder.CreateGraph(false);
571
572 // Extract the inlinee start/end nodes.
573 start = graph()->start();
574 end = graph()->end();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000575 }
576
Ben Murdochf3b273f2017-01-17 12:11:28 +0000577 if (exception_target != nullptr) {
578 // Find all uncaught 'calls' in the inlinee.
579 AllNodes inlined_nodes(local_zone_, end, graph());
580 for (Node* subnode : inlined_nodes.reachable) {
581 // Every possibly throwing node with an IfSuccess should get an
582 // IfException.
583 if (subnode->op()->HasProperty(Operator::kNoThrow)) {
584 continue;
585 }
586 bool hasIfException = false;
587 for (Node* use : subnode->uses()) {
588 if (use->opcode() == IrOpcode::kIfException) {
589 hasIfException = true;
590 break;
591 }
592 }
593 if (!hasIfException) {
594 DCHECK_EQ(2, subnode->op()->ControlOutputCount());
595 uncaught_subcalls.push_back(subnode);
596 }
597 }
598 }
599
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100600 Node* frame_state = call.frame_state();
Ben Murdochf91f0612016-11-29 16:50:11 +0000601 Node* new_target = jsgraph()->UndefinedConstant();
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100602
603 // Inline {JSCallConstruct} requires some additional magic.
Ben Murdoch014dc512016-03-22 12:00:34 +0000604 if (node->opcode() == IrOpcode::kJSCallConstruct) {
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100605 // Insert nodes around the call that model the behavior required for a
606 // constructor dispatch (allocate implicit receiver and check return value).
607 // This models the behavior usually accomplished by our {JSConstructStub}.
608 // Note that the context has to be the callers context (input to call node).
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000609 Node* receiver = jsgraph()->TheHoleConstant(); // Implicit receiver.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100610 if (NeedsImplicitReceiver(shared_info)) {
611 Node* frame_state_before = NodeProperties::FindFrameStateBefore(node);
612 Node* effect = NodeProperties::GetEffectInput(node);
613 Node* context = NodeProperties::GetContextInput(node);
Ben Murdochf91f0612016-11-29 16:50:11 +0000614 Node* create = graph()->NewNode(javascript()->Create(), call.target(),
615 call.new_target(), context,
616 frame_state_before, effect);
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100617 NodeProperties::ReplaceEffectInput(node, create);
618 // Insert a check of the return value to determine whether the return
Ben Murdochf91f0612016-11-29 16:50:11 +0000619 // value or the implicit receiver should be selected as a result of the
620 // call.
621 Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), node);
622 Node* select =
623 graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
624 check, node, create);
625 NodeProperties::ReplaceUses(node, select, node, node, node);
626 // Fix-up inputs that have been mangled by the {ReplaceUses} call above.
627 NodeProperties::ReplaceValueInput(select, node, 1); // Fix-up input.
628 NodeProperties::ReplaceValueInput(check, node, 0); // Fix-up input.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100629 receiver = create; // The implicit receiver.
630 }
631
632 // Swizzle the inputs of the {JSCallConstruct} node to look like inputs to a
633 // normal {JSCallFunction} node so that the rest of the inlining machinery
634 // behaves as if we were dealing with a regular function invocation.
Ben Murdoch014dc512016-03-22 12:00:34 +0000635 new_target = call.new_target(); // Retrieve new target value input.
636 node->RemoveInput(call.formal_arguments() + 1); // Drop new target.
Ben Murdochf91f0612016-11-29 16:50:11 +0000637 node->InsertInput(graph()->zone(), 1, receiver);
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100638
Ben Murdoch014dc512016-03-22 12:00:34 +0000639 // Insert a construct stub frame into the chain of frame states. This will
640 // reconstruct the proper frame when deoptimizing within the constructor.
641 frame_state = CreateArtificialFrameState(
642 node, frame_state, call.formal_arguments(),
643 FrameStateType::kConstructStub, info.shared_info());
644 }
645
646 // The inlinee specializes to the context from the JSFunction object.
647 // TODO(turbofan): We might want to load the context from the JSFunction at
648 // runtime in case we only know the SharedFunctionInfo once we have dynamic
649 // type feedback in the compiler.
Ben Murdochf91f0612016-11-29 16:50:11 +0000650 Node* context = jsgraph()->Constant(handle(function->context()));
Ben Murdoch014dc512016-03-22 12:00:34 +0000651
652 // Insert a JSConvertReceiver node for sloppy callees. Note that the context
653 // passed into this node has to be the callees context (loaded above). Note
654 // that the frame state passed to the JSConvertReceiver must be the frame
655 // state _before_ the call; it is not necessary to fiddle with the receiver
656 // in that frame state tho, as the conversion of the receiver can be repeated
657 // any number of times, it's not observable.
658 if (node->opcode() == IrOpcode::kJSCallFunction &&
Ben Murdochf3b273f2017-01-17 12:11:28 +0000659 is_sloppy(shared_info->language_mode()) && !shared_info->native()) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000660 Node* effect = NodeProperties::GetEffectInput(node);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000661 if (NeedsConvertReceiver(call.receiver(), effect)) {
662 const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
663 Node* frame_state_before = NodeProperties::FindFrameStateBefore(node);
664 Node* convert = effect = graph()->NewNode(
665 javascript()->ConvertReceiver(p.convert_mode()), call.receiver(),
666 context, frame_state_before, effect, start);
667 NodeProperties::ReplaceValueInput(node, convert, 1);
668 NodeProperties::ReplaceEffectInput(node, effect);
669 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000670 }
671
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100672 // If we are inlining a JS call at tail position then we have to pop current
673 // frame state and its potential arguments adaptor frame state in order to
674 // make the call stack be consistent with non-inlining case.
675 // After that we add a tail caller frame state which lets deoptimizer handle
676 // the case when the outermost function inlines a tail call (it should remove
677 // potential arguments adaptor frame that belongs to outermost function when
678 // deopt happens).
679 if (node->opcode() == IrOpcode::kJSCallFunction) {
680 const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
681 if (p.tail_call_mode() == TailCallMode::kAllow) {
682 frame_state = CreateTailCallerFrameState(node, frame_state);
683 }
684 }
685
Ben Murdoch014dc512016-03-22 12:00:34 +0000686 // Insert argument adaptor frame if required. The callees formal parameter
687 // count (i.e. value outputs of start node minus target, receiver, new target,
688 // arguments count and context) have to match the number of arguments passed
689 // to the call.
Ben Murdochf3b273f2017-01-17 12:11:28 +0000690 int parameter_count = shared_info->internal_formal_parameter_count();
Ben Murdoch014dc512016-03-22 12:00:34 +0000691 DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 5);
692 if (call.formal_arguments() != parameter_count) {
693 frame_state = CreateArtificialFrameState(
694 node, frame_state, call.formal_arguments(),
Ben Murdoch109988c2016-05-18 11:27:45 +0100695 FrameStateType::kArgumentsAdaptor, shared_info);
Ben Murdoch014dc512016-03-22 12:00:34 +0000696 }
697
Ben Murdochf3b273f2017-01-17 12:11:28 +0000698 return InlineCall(node, new_target, context, frame_state, start, end,
699 exception_target, uncaught_subcalls);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000700}
Emily Bernier958fae72015-03-24 16:35:39 -0400701
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100702Graph* JSInliner::graph() const { return jsgraph()->graph(); }
703
Ben Murdochf91f0612016-11-29 16:50:11 +0000704JSOperatorBuilder* JSInliner::javascript() const {
705 return jsgraph()->javascript();
706}
707
708CommonOperatorBuilder* JSInliner::common() const { return jsgraph()->common(); }
709
710SimplifiedOperatorBuilder* JSInliner::simplified() const {
711 return jsgraph()->simplified();
712}
713
Ben Murdoch014dc512016-03-22 12:00:34 +0000714} // namespace compiler
715} // namespace internal
716} // namespace v8