Commit fe232cfd authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[turbofan] Only allocate implict receiver when needed.

This adapts the constructor call inlining machinery to only allocate
implicit receivers and perform the return value check if the callee
needs it.

R=verwaest@chromium.org
BUG=v8:4544
LOG=n

Review URL: https://codereview.chromium.org/1476833002

Cr-Commit-Position: refs/heads/master@{#32337}
parent d3e5db04
...@@ -264,6 +264,18 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state, ...@@ -264,6 +264,18 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
} }
namespace {
// TODO(mstarzinger,verwaest): Move this predicate onto SharedFunctionInfo?
bool NeedsImplicitReceiver(Handle<JSFunction> function, Isolate* isolate) {
Code* construct_stub = function->shared()->construct_stub();
return construct_stub != *isolate->builtins()->JSBuiltinsConstructStub() &&
construct_stub != *isolate->builtins()->ConstructedNonConstructable();
}
} // namespace
Reduction JSInliner::Reduce(Node* node) { Reduction JSInliner::Reduce(Node* node) {
if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange(); if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange();
...@@ -283,18 +295,18 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { ...@@ -283,18 +295,18 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
JSCallAccessor call(node); JSCallAccessor call(node);
// Function must be inlineable.
if (!function->shared()->IsInlineable()) { if (!function->shared()->IsInlineable()) {
// Function must be inlineable.
TRACE("Not inlining %s into %s because callee is not inlineable\n", TRACE("Not inlining %s into %s because callee is not inlineable\n",
function->shared()->DebugName()->ToCString().get(), function->shared()->DebugName()->ToCString().get(),
info_->shared_info()->DebugName()->ToCString().get()); info_->shared_info()->DebugName()->ToCString().get());
return NoChange(); return NoChange();
} }
// Constructor must be constructable.
if (node->opcode() == IrOpcode::kJSCallConstruct && if (node->opcode() == IrOpcode::kJSCallConstruct &&
!function->IsConstructor()) { !function->IsConstructor()) {
// Constructor must be constructable. TRACE("Not inlining %s into %s because constructor is not constructable.\n",
TRACE("Not inlining %s into %s since constructor is not constructable.\n",
function->shared()->DebugName()->ToCString().get(), function->shared()->DebugName()->ToCString().get(),
info_->shared_info()->DebugName()->ToCString().get()); info_->shared_info()->DebugName()->ToCString().get());
return NoChange(); return NoChange();
...@@ -302,15 +314,16 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { ...@@ -302,15 +314,16 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
// Class constructors are callable, but [[Call]] will raise an exception. // Class constructors are callable, but [[Call]] will raise an exception.
// See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ). // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
if (IsClassConstructor(function->shared()->kind())) { if (node->opcode() == IrOpcode::kJSCallFunction &&
TRACE("Not inlining %s into %s because callee is classConstructor\n", IsClassConstructor(function->shared()->kind())) {
TRACE("Not inlining %s into %s because callee is a class constructor.\n",
function->shared()->DebugName()->ToCString().get(), function->shared()->DebugName()->ToCString().get(),
info_->shared_info()->DebugName()->ToCString().get()); info_->shared_info()->DebugName()->ToCString().get());
return NoChange(); return NoChange();
} }
// Function contains break points.
if (function->shared()->HasDebugInfo()) { if (function->shared()->HasDebugInfo()) {
// Function contains break points.
TRACE("Not inlining %s into %s because callee may contain break points\n", TRACE("Not inlining %s into %s because callee may contain break points\n",
function->shared()->DebugName()->ToCString().get(), function->shared()->DebugName()->ToCString().get(),
info_->shared_info()->DebugName()->ToCString().get()); info_->shared_info()->DebugName()->ToCString().get());
...@@ -424,27 +437,18 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { ...@@ -424,27 +437,18 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
Node* new_target = jsgraph_->UndefinedConstant(); Node* new_target = jsgraph_->UndefinedConstant();
// Insert nodes around the call that model the behavior required for a // Insert nodes around the call that model the behavior required for a
// constructor dispatch and turn the constructor call into a regular call. // constructor dispatch (allocate implicit receiver and check return value).
// This models the behavior usually accomplished by our {JSConstructStub}. // This models the behavior usually accomplished by our {JSConstructStub}.
// Note that the context has to be the callers context (input to call node). // Note that the context has to be the callers context (input to call node).
// TODO(4544): Once we support inlining builtins, make sure no implicit Node* receiver = jsgraph_->UndefinedConstant(); // Implicit receiver.
// receiver is created for builtins that don't expect any. if (node->opcode() == IrOpcode::kJSCallConstruct &&
if (node->opcode() == IrOpcode::kJSCallConstruct) { NeedsImplicitReceiver(function, info_->isolate())) {
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
Node* context = NodeProperties::GetContextInput(node); Node* context = NodeProperties::GetContextInput(node);
Node* create = jsgraph_->graph()->NewNode(jsgraph_->javascript()->Create(), Node* create = jsgraph_->graph()->NewNode(jsgraph_->javascript()->Create(),
call.target(), call.new_target(), call.target(), call.new_target(),
context, frame_state, effect); context, frame_state, effect);
NodeProperties::ReplaceEffectInput(node, create); NodeProperties::ReplaceEffectInput(node, create);
// TODO(4544): For derived constructors we should not allocate an implicit
// receiver and also the return value should not be checked afterwards.
CHECK(!IsClassConstructor(function->shared()->kind()));
// Swizzle the inputs of the {JSCallConstruct} node to look like inputs to
// any {JSCallFunction} node so that the rest of the inlining machinery
// behaves as if we were dealing with a regular function invocation.
new_target = call.new_target(); // Retrieve new target value input.
node->RemoveInput(call.formal_arguments() + 1); // Drop new target.
node->InsertInput(jsgraph_->graph()->zone(), 1, create);
// Insert a check of the return value to determine whether the return value // Insert a check of the return value to determine whether the return value
// or the implicit receiver should be selected as a result of the call. // or the implicit receiver should be selected as a result of the call.
Node* check = jsgraph_->graph()->NewNode( Node* check = jsgraph_->graph()->NewNode(
...@@ -456,6 +460,16 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { ...@@ -456,6 +460,16 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
NodeProperties::ReplaceValueInput(select, node, 1); NodeProperties::ReplaceValueInput(select, node, 1);
NodeProperties::ReplaceValueInput(check, node, 0); NodeProperties::ReplaceValueInput(check, node, 0);
NodeProperties::ReplaceEffectInput(check, node); NodeProperties::ReplaceEffectInput(check, node);
receiver = create; // The implicit receiver.
}
// Swizzle the inputs of the {JSCallConstruct} node to look like inputs to a
// normal {JSCallFunction} node so that the rest of the inlining machinery
// behaves as if we were dealing with a regular function invocation.
if (node->opcode() == IrOpcode::kJSCallConstruct) {
new_target = call.new_target(); // Retrieve new target value input.
node->RemoveInput(call.formal_arguments() + 1); // Drop new target.
node->InsertInput(jsgraph_->graph()->zone(), 1, receiver);
// Insert a construct stub frame into the chain of frame states. This will // Insert a construct stub frame into the chain of frame states. This will
// reconstruct the proper frame when deoptimizing within the constructor. // reconstruct the proper frame when deoptimizing within the constructor.
frame_state = CreateArtificialFrameState( frame_state = CreateArtificialFrameState(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment