blob: 58e5a276ccc24dd64bd313ae9983b8c04aec99bb [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 Murdochf91f0612016-11-29 16:50:11 +0000119 Replace(use, jsgraph()->Int32Constant(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:
187 values.push_back(NodeProperties::GetValueInput(input, 0));
188 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 Murdochf3b273f2017-01-17 12:11:28 +0000285// TODO(bmeurer): Unify this with the witness helper functions in the
286// js-builtin-reducer.cc once we have a better understanding of the
287// map tracking we want to do, and eventually changed the CheckMaps
288// operator to carry map constants on the operator instead of inputs.
289// I.e. if the CheckMaps has some kind of SmallMapSet as operator
290// parameter, then this could be changed to call a generic
291//
292// SmallMapSet NodeProperties::CollectMapWitness(receiver, effect)
293//
294// function, which either returns the map set from the CheckMaps or
295// a singleton set from a StoreField.
296bool NeedsConvertReceiver(Node* receiver, Node* effect) {
297 for (Node* dominator = effect;;) {
298 if (dominator->opcode() == IrOpcode::kCheckMaps &&
299 dominator->InputAt(0) == receiver) {
300 // Check if all maps have the given {instance_type}.
301 for (int i = 1; i < dominator->op()->ValueInputCount(); ++i) {
302 HeapObjectMatcher m(NodeProperties::GetValueInput(dominator, i));
303 if (!m.HasValue()) return true;
304 Handle<Map> const map = Handle<Map>::cast(m.Value());
305 if (!map->IsJSReceiverMap()) return true;
306 }
307 return false;
308 }
309 switch (dominator->opcode()) {
310 case IrOpcode::kStoreField: {
311 FieldAccess const& access = FieldAccessOf(dominator->op());
312 if (access.base_is_tagged == kTaggedBase &&
313 access.offset == HeapObject::kMapOffset) {
314 return true;
315 }
316 break;
317 }
318 case IrOpcode::kStoreElement:
319 case IrOpcode::kStoreTypedElement:
320 break;
321 default: {
322 DCHECK_EQ(1, dominator->op()->EffectOutputCount());
323 if (dominator->op()->EffectInputCount() != 1 ||
324 !dominator->op()->HasProperty(Operator::kNoWrite)) {
325 // Didn't find any appropriate CheckMaps node.
326 return true;
327 }
328 break;
329 }
330 }
331 dominator = NodeProperties::GetEffectInput(dominator);
332 }
333}
334
Ben Murdoch014dc512016-03-22 12:00:34 +0000335// TODO(mstarzinger,verwaest): Move this predicate onto SharedFunctionInfo?
Ben Murdoch109988c2016-05-18 11:27:45 +0100336bool NeedsImplicitReceiver(Handle<SharedFunctionInfo> shared_info) {
337 DisallowHeapAllocation no_gc;
338 Isolate* const isolate = shared_info->GetIsolate();
339 Code* const construct_stub = shared_info->construct_stub();
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100340 return construct_stub != *isolate->builtins()->JSBuiltinsConstructStub() &&
341 construct_stub !=
342 *isolate->builtins()->JSBuiltinsConstructStubForDerived() &&
343 construct_stub != *isolate->builtins()->JSConstructStubApi();
Ben Murdoch109988c2016-05-18 11:27:45 +0100344}
345
346bool IsNonConstructible(Handle<SharedFunctionInfo> shared_info) {
347 DisallowHeapAllocation no_gc;
348 Isolate* const isolate = shared_info->GetIsolate();
349 Code* const construct_stub = shared_info->construct_stub();
350 return construct_stub == *isolate->builtins()->ConstructedNonConstructable();
Ben Murdoch014dc512016-03-22 12:00:34 +0000351}
352
353} // namespace
354
355
356Reduction JSInliner::Reduce(Node* node) {
357 if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange();
358
359 // This reducer can handle both normal function calls as well a constructor
360 // calls whenever the target is a constant function object, as follows:
361 // - JSCallFunction(target:constant, receiver, args...)
362 // - JSCallConstruct(target:constant, args..., new.target)
363 HeapObjectMatcher match(node->InputAt(0));
364 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange();
365 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value());
366
367 return ReduceJSCall(node, function);
368}
369
Ben Murdoch014dc512016-03-22 12:00:34 +0000370Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
371 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
372 JSCallAccessor call(node);
Ben Murdoch109988c2016-05-18 11:27:45 +0100373 Handle<SharedFunctionInfo> shared_info(function->shared());
Ben Murdoch014dc512016-03-22 12:00:34 +0000374
375 // Function must be inlineable.
Ben Murdoch109988c2016-05-18 11:27:45 +0100376 if (!shared_info->IsInlineable()) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000377 TRACE("Not inlining %s into %s because callee is not inlineable\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100378 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000379 info_->shared_info()->DebugName()->ToCString().get());
380 return NoChange();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000381 }
382
Ben Murdoch014dc512016-03-22 12:00:34 +0000383 // Constructor must be constructable.
384 if (node->opcode() == IrOpcode::kJSCallConstruct &&
Ben Murdoch109988c2016-05-18 11:27:45 +0100385 IsNonConstructible(shared_info)) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000386 TRACE("Not inlining %s into %s because constructor is not constructable.\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100387 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000388 info_->shared_info()->DebugName()->ToCString().get());
389 return NoChange();
390 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000391
Ben Murdoch014dc512016-03-22 12:00:34 +0000392 // Class constructors are callable, but [[Call]] will raise an exception.
393 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
394 if (node->opcode() == IrOpcode::kJSCallFunction &&
Ben Murdoch109988c2016-05-18 11:27:45 +0100395 IsClassConstructor(shared_info->kind())) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000396 TRACE("Not inlining %s into %s because callee is a class constructor.\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100397 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000398 info_->shared_info()->DebugName()->ToCString().get());
399 return NoChange();
400 }
401
402 // Function contains break points.
Ben Murdoch109988c2016-05-18 11:27:45 +0100403 if (shared_info->HasDebugInfo()) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000404 TRACE("Not inlining %s into %s because callee may contain break points\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100405 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000406 info_->shared_info()->DebugName()->ToCString().get());
407 return NoChange();
408 }
409
410 // Disallow cross native-context inlining for now. This means that all parts
411 // of the resulting code will operate on the same global object.
412 // This also prevents cross context leaks for asm.js code, where we could
413 // inline functions from a different context and hold on to that context (and
414 // closure) from the code object.
415 // TODO(turbofan): We might want to revisit this restriction later when we
416 // have a need for this, and we know how to model different native contexts
417 // in the same graph in a compositional way.
418 if (function->context()->native_context() !=
419 info_->context()->native_context()) {
420 TRACE("Not inlining %s into %s because of different native contexts\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100421 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000422 info_->shared_info()->DebugName()->ToCString().get());
423 return NoChange();
424 }
425
426 // TODO(turbofan): TranslatedState::GetAdaptedArguments() currently relies on
427 // not inlining recursive functions. We might want to relax that at some
428 // point.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100429 for (Node* frame_state = call.frame_state();
Ben Murdoch014dc512016-03-22 12:00:34 +0000430 frame_state->opcode() == IrOpcode::kFrameState;
431 frame_state = frame_state->InputAt(kFrameStateOuterStateInput)) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100432 FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state);
433 Handle<SharedFunctionInfo> frame_shared_info;
434 if (frame_info.shared_info().ToHandle(&frame_shared_info) &&
435 *frame_shared_info == *shared_info) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000436 TRACE("Not inlining %s into %s because call is recursive\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100437 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000438 info_->shared_info()->DebugName()->ToCString().get());
439 return NoChange();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000440 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000441 }
442
Ben Murdochf3b273f2017-01-17 12:11:28 +0000443 // Find the IfException node, if any.
444 Node* exception_target = nullptr;
445 for (Edge edge : node->use_edges()) {
446 if (NodeProperties::IsControlEdge(edge) &&
447 edge.from()->opcode() == IrOpcode::kIfException) {
448 DCHECK_NULL(exception_target);
449 exception_target = edge.from();
450 }
451 }
452
453 NodeVector uncaught_subcalls(local_zone_);
454
455 if (exception_target != nullptr) {
456 if (!FLAG_inline_into_try) {
457 TRACE(
458 "Try block surrounds #%d:%s and --no-inline-into-try active, so not "
459 "inlining %s into %s.\n",
460 exception_target->id(), exception_target->op()->mnemonic(),
Ben Murdoch109988c2016-05-18 11:27:45 +0100461 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000462 info_->shared_info()->DebugName()->ToCString().get());
Ben Murdochf3b273f2017-01-17 12:11:28 +0000463 return NoChange();
464 } else {
465 TRACE(
466 "Inlining %s into %s regardless of surrounding try-block to catcher "
467 "#%d:%s\n",
468 shared_info->DebugName()->ToCString().get(),
469 info_->shared_info()->DebugName()->ToCString().get(),
470 exception_target->id(), exception_target->op()->mnemonic());
471 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000472 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000473
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100474 Zone zone(info_->isolate()->allocator());
Ben Murdoch014dc512016-03-22 12:00:34 +0000475 ParseInfo parse_info(&zone, function);
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100476 CompilationInfo info(&parse_info, function);
Ben Murdoch109988c2016-05-18 11:27:45 +0100477 if (info_->is_deoptimization_enabled()) info.MarkAsDeoptimizationEnabled();
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100478 if (info_->is_type_feedback_enabled()) info.MarkAsTypeFeedbackEnabled();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000479 if (info_->is_optimizing_from_bytecode()) info.MarkAsOptimizeFromBytecode();
Ben Murdoch014dc512016-03-22 12:00:34 +0000480
Ben Murdochf3b273f2017-01-17 12:11:28 +0000481 if (info.is_optimizing_from_bytecode() && !Compiler::EnsureBytecode(&info)) {
482 TRACE("Not inlining %s into %s because bytecode generation failed\n",
483 shared_info->DebugName()->ToCString().get(),
484 info_->shared_info()->DebugName()->ToCString().get());
485 if (info_->isolate()->has_pending_exception()) {
486 info_->isolate()->clear_pending_exception();
487 }
488 return NoChange();
489 }
490
491 if (!info.is_optimizing_from_bytecode() &&
492 !Compiler::ParseAndAnalyze(info.parse_info())) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000493 TRACE("Not inlining %s into %s because parsing failed\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100494 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000495 info_->shared_info()->DebugName()->ToCString().get());
496 if (info_->isolate()->has_pending_exception()) {
497 info_->isolate()->clear_pending_exception();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000498 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000499 return NoChange();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000500 }
501
Ben Murdochf3b273f2017-01-17 12:11:28 +0000502 if (!info.is_optimizing_from_bytecode() &&
503 !Compiler::EnsureDeoptimizationSupport(&info)) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000504 TRACE("Not inlining %s into %s because deoptimization support failed\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100505 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000506 info_->shared_info()->DebugName()->ToCString().get());
507 return NoChange();
508 }
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100509
Ben Murdoch014dc512016-03-22 12:00:34 +0000510 // Remember that we inlined this function. This needs to be called right
511 // after we ensure deoptimization support so that the code flusher
512 // does not remove the code with the deoptimization support.
Ben Murdoch109988c2016-05-18 11:27:45 +0100513 info_->AddInlinedFunction(shared_info);
Ben Murdoch014dc512016-03-22 12:00:34 +0000514
515 // ----------------------------------------------------------------
516 // After this point, we've made a decision to inline this function.
517 // We shall not bailout from inlining if we got here.
518
519 TRACE("Inlining %s into %s\n",
Ben Murdoch109988c2016-05-18 11:27:45 +0100520 shared_info->DebugName()->ToCString().get(),
Ben Murdoch014dc512016-03-22 12:00:34 +0000521 info_->shared_info()->DebugName()->ToCString().get());
522
Ben Murdochf3b273f2017-01-17 12:11:28 +0000523 // If function was lazily compiled, its literals array may not yet be set up.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100524 JSFunction::EnsureLiterals(function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000525
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100526 // Create the subgraph for the inlinee.
527 Node* start;
528 Node* end;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000529 if (info.is_optimizing_from_bytecode()) {
530 // Run the BytecodeGraphBuilder to create the subgraph.
531 Graph::SubgraphScope scope(graph());
532 BytecodeGraphBuilder graph_builder(&zone, &info, jsgraph(),
533 call.frequency());
534 graph_builder.CreateGraph();
535
536 // Extract the inlinee start/end nodes.
537 start = graph()->start();
538 end = graph()->end();
539 } else {
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100540 // Run the loop assignment analyzer on the inlinee.
541 AstLoopAssignmentAnalyzer loop_assignment_analyzer(&zone, &info);
542 LoopAssignmentAnalysis* loop_assignment =
543 loop_assignment_analyzer.Analyze();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000544
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100545 // Run the type hint analyzer on the inlinee.
546 TypeHintAnalyzer type_hint_analyzer(&zone);
547 TypeHintAnalysis* type_hint_analysis =
548 type_hint_analyzer.Analyze(handle(shared_info->code(), info.isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000549
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100550 // Run the AstGraphBuilder to create the subgraph.
551 Graph::SubgraphScope scope(graph());
Ben Murdochf3b273f2017-01-17 12:11:28 +0000552 AstGraphBuilder graph_builder(&zone, &info, jsgraph(), call.frequency(),
553 loop_assignment, type_hint_analysis);
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100554 graph_builder.CreateGraph(false);
555
556 // Extract the inlinee start/end nodes.
557 start = graph()->start();
558 end = graph()->end();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000559 }
560
Ben Murdochf3b273f2017-01-17 12:11:28 +0000561 if (exception_target != nullptr) {
562 // Find all uncaught 'calls' in the inlinee.
563 AllNodes inlined_nodes(local_zone_, end, graph());
564 for (Node* subnode : inlined_nodes.reachable) {
565 // Every possibly throwing node with an IfSuccess should get an
566 // IfException.
567 if (subnode->op()->HasProperty(Operator::kNoThrow)) {
568 continue;
569 }
570 bool hasIfException = false;
571 for (Node* use : subnode->uses()) {
572 if (use->opcode() == IrOpcode::kIfException) {
573 hasIfException = true;
574 break;
575 }
576 }
577 if (!hasIfException) {
578 DCHECK_EQ(2, subnode->op()->ControlOutputCount());
579 uncaught_subcalls.push_back(subnode);
580 }
581 }
582 }
583
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100584 Node* frame_state = call.frame_state();
Ben Murdochf91f0612016-11-29 16:50:11 +0000585 Node* new_target = jsgraph()->UndefinedConstant();
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100586
587 // Inline {JSCallConstruct} requires some additional magic.
Ben Murdoch014dc512016-03-22 12:00:34 +0000588 if (node->opcode() == IrOpcode::kJSCallConstruct) {
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100589 // Insert nodes around the call that model the behavior required for a
590 // constructor dispatch (allocate implicit receiver and check return value).
591 // This models the behavior usually accomplished by our {JSConstructStub}.
592 // Note that the context has to be the callers context (input to call node).
Ben Murdochf91f0612016-11-29 16:50:11 +0000593 Node* receiver = jsgraph()->UndefinedConstant(); // Implicit receiver.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100594 if (NeedsImplicitReceiver(shared_info)) {
595 Node* frame_state_before = NodeProperties::FindFrameStateBefore(node);
596 Node* effect = NodeProperties::GetEffectInput(node);
597 Node* context = NodeProperties::GetContextInput(node);
Ben Murdochf91f0612016-11-29 16:50:11 +0000598 Node* create = graph()->NewNode(javascript()->Create(), call.target(),
599 call.new_target(), context,
600 frame_state_before, effect);
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100601 NodeProperties::ReplaceEffectInput(node, create);
602 // Insert a check of the return value to determine whether the return
Ben Murdochf91f0612016-11-29 16:50:11 +0000603 // value or the implicit receiver should be selected as a result of the
604 // call.
605 Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), node);
606 Node* select =
607 graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
608 check, node, create);
609 NodeProperties::ReplaceUses(node, select, node, node, node);
610 // Fix-up inputs that have been mangled by the {ReplaceUses} call above.
611 NodeProperties::ReplaceValueInput(select, node, 1); // Fix-up input.
612 NodeProperties::ReplaceValueInput(check, node, 0); // Fix-up input.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100613 receiver = create; // The implicit receiver.
614 }
615
616 // Swizzle the inputs of the {JSCallConstruct} node to look like inputs to a
617 // normal {JSCallFunction} node so that the rest of the inlining machinery
618 // behaves as if we were dealing with a regular function invocation.
Ben Murdoch014dc512016-03-22 12:00:34 +0000619 new_target = call.new_target(); // Retrieve new target value input.
620 node->RemoveInput(call.formal_arguments() + 1); // Drop new target.
Ben Murdochf91f0612016-11-29 16:50:11 +0000621 node->InsertInput(graph()->zone(), 1, receiver);
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100622
Ben Murdoch014dc512016-03-22 12:00:34 +0000623 // Insert a construct stub frame into the chain of frame states. This will
624 // reconstruct the proper frame when deoptimizing within the constructor.
625 frame_state = CreateArtificialFrameState(
626 node, frame_state, call.formal_arguments(),
627 FrameStateType::kConstructStub, info.shared_info());
628 }
629
630 // The inlinee specializes to the context from the JSFunction object.
631 // TODO(turbofan): We might want to load the context from the JSFunction at
632 // runtime in case we only know the SharedFunctionInfo once we have dynamic
633 // type feedback in the compiler.
Ben Murdochf91f0612016-11-29 16:50:11 +0000634 Node* context = jsgraph()->Constant(handle(function->context()));
Ben Murdoch014dc512016-03-22 12:00:34 +0000635
636 // Insert a JSConvertReceiver node for sloppy callees. Note that the context
637 // passed into this node has to be the callees context (loaded above). Note
638 // that the frame state passed to the JSConvertReceiver must be the frame
639 // state _before_ the call; it is not necessary to fiddle with the receiver
640 // in that frame state tho, as the conversion of the receiver can be repeated
641 // any number of times, it's not observable.
642 if (node->opcode() == IrOpcode::kJSCallFunction &&
Ben Murdochf3b273f2017-01-17 12:11:28 +0000643 is_sloppy(shared_info->language_mode()) && !shared_info->native()) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000644 Node* effect = NodeProperties::GetEffectInput(node);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000645 if (NeedsConvertReceiver(call.receiver(), effect)) {
646 const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
647 Node* frame_state_before = NodeProperties::FindFrameStateBefore(node);
648 Node* convert = effect = graph()->NewNode(
649 javascript()->ConvertReceiver(p.convert_mode()), call.receiver(),
650 context, frame_state_before, effect, start);
651 NodeProperties::ReplaceValueInput(node, convert, 1);
652 NodeProperties::ReplaceEffectInput(node, effect);
653 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000654 }
655
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100656 // If we are inlining a JS call at tail position then we have to pop current
657 // frame state and its potential arguments adaptor frame state in order to
658 // make the call stack be consistent with non-inlining case.
659 // After that we add a tail caller frame state which lets deoptimizer handle
660 // the case when the outermost function inlines a tail call (it should remove
661 // potential arguments adaptor frame that belongs to outermost function when
662 // deopt happens).
663 if (node->opcode() == IrOpcode::kJSCallFunction) {
664 const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
665 if (p.tail_call_mode() == TailCallMode::kAllow) {
666 frame_state = CreateTailCallerFrameState(node, frame_state);
667 }
668 }
669
Ben Murdoch014dc512016-03-22 12:00:34 +0000670 // Insert argument adaptor frame if required. The callees formal parameter
671 // count (i.e. value outputs of start node minus target, receiver, new target,
672 // arguments count and context) have to match the number of arguments passed
673 // to the call.
Ben Murdochf3b273f2017-01-17 12:11:28 +0000674 int parameter_count = shared_info->internal_formal_parameter_count();
Ben Murdoch014dc512016-03-22 12:00:34 +0000675 DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 5);
676 if (call.formal_arguments() != parameter_count) {
677 frame_state = CreateArtificialFrameState(
678 node, frame_state, call.formal_arguments(),
Ben Murdoch109988c2016-05-18 11:27:45 +0100679 FrameStateType::kArgumentsAdaptor, shared_info);
Ben Murdoch014dc512016-03-22 12:00:34 +0000680 }
681
Ben Murdochf3b273f2017-01-17 12:11:28 +0000682 return InlineCall(node, new_target, context, frame_state, start, end,
683 exception_target, uncaught_subcalls);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000684}
Emily Bernier958fae72015-03-24 16:35:39 -0400685
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100686Graph* JSInliner::graph() const { return jsgraph()->graph(); }
687
Ben Murdochf91f0612016-11-29 16:50:11 +0000688JSOperatorBuilder* JSInliner::javascript() const {
689 return jsgraph()->javascript();
690}
691
692CommonOperatorBuilder* JSInliner::common() const { return jsgraph()->common(); }
693
694SimplifiedOperatorBuilder* JSInliner::simplified() const {
695 return jsgraph()->simplified();
696}
697
Ben Murdoch014dc512016-03-22 12:00:34 +0000698} // namespace compiler
699} // namespace internal
700} // namespace v8