| Index: src/compiler/js-inlining.cc
|
| diff --git a/src/compiler/js-inlining.cc b/src/compiler/js-inlining.cc
|
| index 00c4933802ddf2aa8572cb9293bfc15646ee84c7..0d8b976f45171278768b13d5efe83f1baf8e8e4a 100644
|
| --- a/src/compiler/js-inlining.cc
|
| +++ b/src/compiler/js-inlining.cc
|
| @@ -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) {
|
| if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange();
|
|
|
| @@ -283,18 +295,18 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
|
| DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
|
| JSCallAccessor call(node);
|
|
|
| + // Function must be inlineable.
|
| if (!function->shared()->IsInlineable()) {
|
| - // Function must be inlineable.
|
| TRACE("Not inlining %s into %s because callee is not inlineable\n",
|
| function->shared()->DebugName()->ToCString().get(),
|
| info_->shared_info()->DebugName()->ToCString().get());
|
| return NoChange();
|
| }
|
|
|
| + // Constructor must be constructable.
|
| if (node->opcode() == IrOpcode::kJSCallConstruct &&
|
| !function->IsConstructor()) {
|
| - // Constructor must be constructable.
|
| - TRACE("Not inlining %s into %s since constructor is not constructable.\n",
|
| + TRACE("Not inlining %s into %s because constructor is not constructable.\n",
|
| function->shared()->DebugName()->ToCString().get(),
|
| info_->shared_info()->DebugName()->ToCString().get());
|
| return NoChange();
|
| @@ -302,15 +314,16 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
|
|
|
| // Class constructors are callable, but [[Call]] will raise an exception.
|
| // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
|
| - if (IsClassConstructor(function->shared()->kind())) {
|
| - TRACE("Not inlining %s into %s because callee is classConstructor\n",
|
| + if (node->opcode() == IrOpcode::kJSCallFunction &&
|
| + IsClassConstructor(function->shared()->kind())) {
|
| + TRACE("Not inlining %s into %s because callee is a class constructor.\n",
|
| function->shared()->DebugName()->ToCString().get(),
|
| info_->shared_info()->DebugName()->ToCString().get());
|
| return NoChange();
|
| }
|
|
|
| + // Function contains break points.
|
| if (function->shared()->HasDebugInfo()) {
|
| - // Function contains break points.
|
| TRACE("Not inlining %s into %s because callee may contain break points\n",
|
| function->shared()->DebugName()->ToCString().get(),
|
| info_->shared_info()->DebugName()->ToCString().get());
|
| @@ -424,27 +437,18 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
|
| Node* new_target = jsgraph_->UndefinedConstant();
|
|
|
| // 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}.
|
| // 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
|
| - // receiver is created for builtins that don't expect any.
|
| - if (node->opcode() == IrOpcode::kJSCallConstruct) {
|
| + Node* receiver = jsgraph_->UndefinedConstant(); // Implicit receiver.
|
| + if (node->opcode() == IrOpcode::kJSCallConstruct &&
|
| + NeedsImplicitReceiver(function, info_->isolate())) {
|
| Node* effect = NodeProperties::GetEffectInput(node);
|
| Node* context = NodeProperties::GetContextInput(node);
|
| Node* create = jsgraph_->graph()->NewNode(jsgraph_->javascript()->Create(),
|
| call.target(), call.new_target(),
|
| context, frame_state, effect);
|
| 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
|
| // or the implicit receiver should be selected as a result of the call.
|
| Node* check = jsgraph_->graph()->NewNode(
|
| @@ -456,6 +460,16 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
|
| NodeProperties::ReplaceValueInput(select, node, 1);
|
| NodeProperties::ReplaceValueInput(check, node, 0);
|
| 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
|
| // reconstruct the proper frame when deoptimizing within the constructor.
|
| frame_state = CreateArtificialFrameState(
|
|
|