OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/js-inlining.h" | 5 #include "src/compiler/js-inlining.h" |
6 | 6 |
7 #include "src/ast.h" | 7 #include "src/ast.h" |
8 #include "src/ast-numbering.h" | 8 #include "src/ast-numbering.h" |
9 #include "src/compiler.h" | 9 #include "src/compiler.h" |
10 #include "src/compiler/all-nodes.h" | 10 #include "src/compiler/all-nodes.h" |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
257 const Operator* op_param = | 257 const Operator* op_param = |
258 jsgraph_->common()->StateValues(static_cast<int>(params.size())); | 258 jsgraph_->common()->StateValues(static_cast<int>(params.size())); |
259 Node* params_node = jsgraph_->graph()->NewNode( | 259 Node* params_node = jsgraph_->graph()->NewNode( |
260 op_param, static_cast<int>(params.size()), ¶ms.front()); | 260 op_param, static_cast<int>(params.size()), ¶ms.front()); |
261 return jsgraph_->graph()->NewNode(op, params_node, node0, node0, | 261 return jsgraph_->graph()->NewNode(op, params_node, node0, node0, |
262 jsgraph_->UndefinedConstant(), | 262 jsgraph_->UndefinedConstant(), |
263 node->InputAt(0), outer_frame_state); | 263 node->InputAt(0), outer_frame_state); |
264 } | 264 } |
265 | 265 |
266 | 266 |
| 267 namespace { |
| 268 |
| 269 // TODO(mstarzinger,verwaest): Move this predicate onto SharedFunctionInfo? |
| 270 bool NeedsImplicitReceiver(Handle<JSFunction> function, Isolate* isolate) { |
| 271 Code* construct_stub = function->shared()->construct_stub(); |
| 272 return construct_stub != *isolate->builtins()->JSBuiltinsConstructStub() && |
| 273 construct_stub != *isolate->builtins()->ConstructedNonConstructable(); |
| 274 } |
| 275 |
| 276 } // namespace |
| 277 |
| 278 |
267 Reduction JSInliner::Reduce(Node* node) { | 279 Reduction JSInliner::Reduce(Node* node) { |
268 if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange(); | 280 if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange(); |
269 | 281 |
270 // This reducer can handle both normal function calls as well a constructor | 282 // This reducer can handle both normal function calls as well a constructor |
271 // calls whenever the target is a constant function object, as follows: | 283 // calls whenever the target is a constant function object, as follows: |
272 // - JSCallFunction(target:constant, receiver, args...) | 284 // - JSCallFunction(target:constant, receiver, args...) |
273 // - JSCallConstruct(target:constant, args..., new.target) | 285 // - JSCallConstruct(target:constant, args..., new.target) |
274 HeapObjectMatcher match(node->InputAt(0)); | 286 HeapObjectMatcher match(node->InputAt(0)); |
275 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange(); | 287 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange(); |
276 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value()); | 288 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value()); |
277 | 289 |
278 return ReduceJSCall(node, function); | 290 return ReduceJSCall(node, function); |
279 } | 291 } |
280 | 292 |
281 | 293 |
282 Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { | 294 Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { |
283 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); | 295 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); |
284 JSCallAccessor call(node); | 296 JSCallAccessor call(node); |
285 | 297 |
| 298 // Function must be inlineable. |
286 if (!function->shared()->IsInlineable()) { | 299 if (!function->shared()->IsInlineable()) { |
287 // Function must be inlineable. | |
288 TRACE("Not inlining %s into %s because callee is not inlineable\n", | 300 TRACE("Not inlining %s into %s because callee is not inlineable\n", |
289 function->shared()->DebugName()->ToCString().get(), | 301 function->shared()->DebugName()->ToCString().get(), |
290 info_->shared_info()->DebugName()->ToCString().get()); | 302 info_->shared_info()->DebugName()->ToCString().get()); |
291 return NoChange(); | 303 return NoChange(); |
292 } | 304 } |
293 | 305 |
| 306 // Constructor must be constructable. |
294 if (node->opcode() == IrOpcode::kJSCallConstruct && | 307 if (node->opcode() == IrOpcode::kJSCallConstruct && |
295 !function->IsConstructor()) { | 308 !function->IsConstructor()) { |
296 // Constructor must be constructable. | 309 TRACE("Not inlining %s into %s because constructor is not constructable.\n", |
297 TRACE("Not inlining %s into %s since constructor is not constructable.\n", | |
298 function->shared()->DebugName()->ToCString().get(), | 310 function->shared()->DebugName()->ToCString().get(), |
299 info_->shared_info()->DebugName()->ToCString().get()); | 311 info_->shared_info()->DebugName()->ToCString().get()); |
300 return NoChange(); | 312 return NoChange(); |
301 } | 313 } |
302 | 314 |
303 // Class constructors are callable, but [[Call]] will raise an exception. | 315 // Class constructors are callable, but [[Call]] will raise an exception. |
304 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ). | 316 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ). |
305 if (IsClassConstructor(function->shared()->kind())) { | 317 if (node->opcode() == IrOpcode::kJSCallFunction && |
306 TRACE("Not inlining %s into %s because callee is classConstructor\n", | 318 IsClassConstructor(function->shared()->kind())) { |
| 319 TRACE("Not inlining %s into %s because callee is a class constructor.\n", |
307 function->shared()->DebugName()->ToCString().get(), | 320 function->shared()->DebugName()->ToCString().get(), |
308 info_->shared_info()->DebugName()->ToCString().get()); | 321 info_->shared_info()->DebugName()->ToCString().get()); |
309 return NoChange(); | 322 return NoChange(); |
310 } | 323 } |
311 | 324 |
| 325 // Function contains break points. |
312 if (function->shared()->HasDebugInfo()) { | 326 if (function->shared()->HasDebugInfo()) { |
313 // Function contains break points. | |
314 TRACE("Not inlining %s into %s because callee may contain break points\n", | 327 TRACE("Not inlining %s into %s because callee may contain break points\n", |
315 function->shared()->DebugName()->ToCString().get(), | 328 function->shared()->DebugName()->ToCString().get(), |
316 info_->shared_info()->DebugName()->ToCString().get()); | 329 info_->shared_info()->DebugName()->ToCString().get()); |
317 return NoChange(); | 330 return NoChange(); |
318 } | 331 } |
319 | 332 |
320 // Disallow cross native-context inlining for now. This means that all parts | 333 // Disallow cross native-context inlining for now. This means that all parts |
321 // of the resulting code will operate on the same global object. | 334 // of the resulting code will operate on the same global object. |
322 // This also prevents cross context leaks for asm.js code, where we could | 335 // This also prevents cross context leaks for asm.js code, where we could |
323 // inline functions from a different context and hold on to that context (and | 336 // inline functions from a different context and hold on to that context (and |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 | 430 |
418 CopyVisitor visitor(&graph, jsgraph_->graph(), &zone); | 431 CopyVisitor visitor(&graph, jsgraph_->graph(), &zone); |
419 visitor.CopyGraph(); | 432 visitor.CopyGraph(); |
420 | 433 |
421 Node* start = visitor.GetCopy(graph.start()); | 434 Node* start = visitor.GetCopy(graph.start()); |
422 Node* end = visitor.GetCopy(graph.end()); | 435 Node* end = visitor.GetCopy(graph.end()); |
423 Node* frame_state = call.frame_state_after(); | 436 Node* frame_state = call.frame_state_after(); |
424 Node* new_target = jsgraph_->UndefinedConstant(); | 437 Node* new_target = jsgraph_->UndefinedConstant(); |
425 | 438 |
426 // Insert nodes around the call that model the behavior required for a | 439 // Insert nodes around the call that model the behavior required for a |
427 // constructor dispatch and turn the constructor call into a regular call. | 440 // constructor dispatch (allocate implicit receiver and check return value). |
428 // This models the behavior usually accomplished by our {JSConstructStub}. | 441 // This models the behavior usually accomplished by our {JSConstructStub}. |
429 // Note that the context has to be the callers context (input to call node). | 442 // Note that the context has to be the callers context (input to call node). |
430 // TODO(4544): Once we support inlining builtins, make sure no implicit | 443 Node* receiver = jsgraph_->UndefinedConstant(); // Implicit receiver. |
431 // receiver is created for builtins that don't expect any. | 444 if (node->opcode() == IrOpcode::kJSCallConstruct && |
432 if (node->opcode() == IrOpcode::kJSCallConstruct) { | 445 NeedsImplicitReceiver(function, info_->isolate())) { |
433 Node* effect = NodeProperties::GetEffectInput(node); | 446 Node* effect = NodeProperties::GetEffectInput(node); |
434 Node* context = NodeProperties::GetContextInput(node); | 447 Node* context = NodeProperties::GetContextInput(node); |
435 Node* create = jsgraph_->graph()->NewNode(jsgraph_->javascript()->Create(), | 448 Node* create = jsgraph_->graph()->NewNode(jsgraph_->javascript()->Create(), |
436 call.target(), call.new_target(), | 449 call.target(), call.new_target(), |
437 context, frame_state, effect); | 450 context, frame_state, effect); |
438 NodeProperties::ReplaceEffectInput(node, create); | 451 NodeProperties::ReplaceEffectInput(node, create); |
439 // TODO(4544): For derived constructors we should not allocate an implicit | |
440 // receiver and also the return value should not be checked afterwards. | |
441 CHECK(!IsClassConstructor(function->shared()->kind())); | |
442 // Swizzle the inputs of the {JSCallConstruct} node to look like inputs to | |
443 // any {JSCallFunction} node so that the rest of the inlining machinery | |
444 // behaves as if we were dealing with a regular function invocation. | |
445 new_target = call.new_target(); // Retrieve new target value input. | |
446 node->RemoveInput(call.formal_arguments() + 1); // Drop new target. | |
447 node->InsertInput(jsgraph_->graph()->zone(), 1, create); | |
448 // Insert a check of the return value to determine whether the return value | 452 // Insert a check of the return value to determine whether the return value |
449 // or the implicit receiver should be selected as a result of the call. | 453 // or the implicit receiver should be selected as a result of the call. |
450 Node* check = jsgraph_->graph()->NewNode( | 454 Node* check = jsgraph_->graph()->NewNode( |
451 jsgraph_->javascript()->CallRuntime(Runtime::kInlineIsSpecObject, 1), | 455 jsgraph_->javascript()->CallRuntime(Runtime::kInlineIsSpecObject, 1), |
452 node, context, node, start); | 456 node, context, node, start); |
453 Node* select = jsgraph_->graph()->NewNode( | 457 Node* select = jsgraph_->graph()->NewNode( |
454 jsgraph_->common()->Select(kMachAnyTagged), check, node, create); | 458 jsgraph_->common()->Select(kMachAnyTagged), check, node, create); |
455 NodeProperties::ReplaceUses(node, select, check, node, node); | 459 NodeProperties::ReplaceUses(node, select, check, node, node); |
456 NodeProperties::ReplaceValueInput(select, node, 1); | 460 NodeProperties::ReplaceValueInput(select, node, 1); |
457 NodeProperties::ReplaceValueInput(check, node, 0); | 461 NodeProperties::ReplaceValueInput(check, node, 0); |
458 NodeProperties::ReplaceEffectInput(check, node); | 462 NodeProperties::ReplaceEffectInput(check, node); |
| 463 receiver = create; // The implicit receiver. |
| 464 } |
| 465 |
| 466 // Swizzle the inputs of the {JSCallConstruct} node to look like inputs to a |
| 467 // normal {JSCallFunction} node so that the rest of the inlining machinery |
| 468 // behaves as if we were dealing with a regular function invocation. |
| 469 if (node->opcode() == IrOpcode::kJSCallConstruct) { |
| 470 new_target = call.new_target(); // Retrieve new target value input. |
| 471 node->RemoveInput(call.formal_arguments() + 1); // Drop new target. |
| 472 node->InsertInput(jsgraph_->graph()->zone(), 1, receiver); |
459 // Insert a construct stub frame into the chain of frame states. This will | 473 // Insert a construct stub frame into the chain of frame states. This will |
460 // reconstruct the proper frame when deoptimizing within the constructor. | 474 // reconstruct the proper frame when deoptimizing within the constructor. |
461 frame_state = CreateArtificialFrameState( | 475 frame_state = CreateArtificialFrameState( |
462 node, frame_state, call.formal_arguments(), | 476 node, frame_state, call.formal_arguments(), |
463 FrameStateType::kConstructStub, info.shared_info()); | 477 FrameStateType::kConstructStub, info.shared_info()); |
464 } | 478 } |
465 | 479 |
466 // The inlinee specializes to the context from the JSFunction object. | 480 // The inlinee specializes to the context from the JSFunction object. |
467 // TODO(turbofan): We might want to load the context from the JSFunction at | 481 // TODO(turbofan): We might want to load the context from the JSFunction at |
468 // runtime in case we only know the SharedFunctionInfo once we have dynamic | 482 // runtime in case we only know the SharedFunctionInfo once we have dynamic |
(...skipping 27 matching lines...) Expand all Loading... |
496 node, frame_state, call.formal_arguments(), | 510 node, frame_state, call.formal_arguments(), |
497 FrameStateType::kArgumentsAdaptor, info.shared_info()); | 511 FrameStateType::kArgumentsAdaptor, info.shared_info()); |
498 } | 512 } |
499 | 513 |
500 return InlineCall(node, new_target, context, frame_state, start, end); | 514 return InlineCall(node, new_target, context, frame_state, start, end); |
501 } | 515 } |
502 | 516 |
503 } // namespace compiler | 517 } // namespace compiler |
504 } // namespace internal | 518 } // namespace internal |
505 } // namespace v8 | 519 } // namespace v8 |
OLD | NEW |