[deoptimizer] Materialize context properly for construct stub frame.

Bug: chromium:895799
Change-Id: Icbc06f1fc2362a04e76961f50a8ba4b29080837c
Reviewed-on: https://chromium-review.googlesource.com/c/1286336
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Jaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56720}
This commit is contained in:
Jaroslav Sevcik 2018-10-17 11:03:12 +02:00 committed by Commit Bot
parent e1c6fa8878
commit 2d11ddab98
8 changed files with 59 additions and 28 deletions

View File

@ -1033,7 +1033,7 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor(
DCHECK(descriptor->bailout_id().IsValidForConstructStub());
translation->BeginConstructStubFrame(
descriptor->bailout_id(), shared_info_id,
static_cast<unsigned int>(descriptor->parameters_count()));
static_cast<unsigned int>(descriptor->parameters_count() + 1));
break;
case FrameStateType::kBuiltinContinuation: {
BailoutId bailout_id = descriptor->bailout_id();

View File

@ -1297,7 +1297,8 @@ class FrameStateDescriptor : public ZoneObject {
FrameStateDescriptor* outer_state() const { return outer_state_; }
bool HasContext() const {
return FrameStateFunctionInfo::IsJSFunctionType(type_) ||
type_ == FrameStateType::kBuiltinContinuation;
type_ == FrameStateType::kBuiltinContinuation ||
type_ == FrameStateType::kConstructStub;
}
size_t GetSize() const;

View File

@ -5499,7 +5499,7 @@ Reduction JSCallReducer::ReduceAsyncFunctionPromiseCreate(Node* node) {
Node* JSCallReducer::CreateArtificialFrameState(
Node* node, Node* outer_frame_state, int parameter_count,
BailoutId bailout_id, FrameStateType frame_state_type,
Handle<SharedFunctionInfo> shared) {
Handle<SharedFunctionInfo> shared, Node* context) {
const FrameStateFunctionInfo* state_info =
common()->CreateFrameStateFunctionInfo(frame_state_type,
parameter_count + 1, 0, shared);
@ -5517,9 +5517,11 @@ Node* JSCallReducer::CreateArtificialFrameState(
static_cast<int>(params.size()), SparseInputMask::Dense());
Node* params_node = graph()->NewNode(
op_param, static_cast<int>(params.size()), &params.front());
return graph()->NewNode(op, params_node, node0, node0,
jsgraph()->UndefinedConstant(), node->InputAt(0),
outer_frame_state);
if (!context) {
context = jsgraph()->UndefinedConstant();
}
return graph()->NewNode(op, params_node, node0, node0, context,
node->InputAt(0), outer_frame_state);
}
Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
@ -5556,7 +5558,7 @@ Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
DCHECK_EQ(1, promise_shared->internal_formal_parameter_count());
Node* constructor_frame_state = CreateArtificialFrameState(
node, outer_frame_state, 1, BailoutId::ConstructStubInvoke(),
FrameStateType::kConstructStub, promise_shared);
FrameStateType::kConstructStub, promise_shared, context);
// The deopt continuation of this frame state is never called; the frame state
// is only necessary to obtain the right stack trace.
@ -6126,7 +6128,7 @@ Reduction JSCallReducer::ReduceTypedArrayConstructor(
// reconstruct the proper frame when deoptimizing within the constructor.
frame_state = CreateArtificialFrameState(
node, frame_state, arity, BailoutId::ConstructStubInvoke(),
FrameStateType::kConstructStub, shared);
FrameStateType::kConstructStub, shared, context);
// This continuation just returns the newly created JSTypedArray. We
// pass the_hole as the receiver, just like the builtin construct stub

View File

@ -229,7 +229,8 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
Node* CreateArtificialFrameState(Node* node, Node* outer_frame_state,
int parameter_count, BailoutId bailout_id,
FrameStateType frame_state_type,
Handle<SharedFunctionInfo> shared);
Handle<SharedFunctionInfo> shared,
Node* context = nullptr);
Graph* graph() const;
JSGraph* jsgraph() const { return jsgraph_; }

View File

@ -234,7 +234,8 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
int parameter_count,
BailoutId bailout_id,
FrameStateType frame_state_type,
Handle<SharedFunctionInfo> shared) {
Handle<SharedFunctionInfo> shared,
Node* context) {
const FrameStateFunctionInfo* state_info =
common()->CreateFrameStateFunctionInfo(frame_state_type,
parameter_count + 1, 0, shared);
@ -251,9 +252,11 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
static_cast<int>(params.size()), SparseInputMask::Dense());
Node* params_node = graph()->NewNode(
op_param, static_cast<int>(params.size()), &params.front());
return graph()->NewNode(op, params_node, node0, node0,
jsgraph()->UndefinedConstant(), node->InputAt(0),
outer_frame_state);
if (!context) {
context = jsgraph()->UndefinedConstant();
}
return graph()->NewNode(op, params_node, node0, node0, context,
node->InputAt(0), outer_frame_state);
}
namespace {
@ -536,14 +539,14 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
// instantiation but before the invocation (i.e. inside {JSConstructStub}
// where execution continues at {construct_stub_create_deopt_pc_offset}).
Node* receiver = jsgraph()->TheHoleConstant(); // Implicit receiver.
Node* context = NodeProperties::GetContextInput(node);
if (NeedsImplicitReceiver(shared_info)) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* context = NodeProperties::GetContextInput(node);
Node* frame_state_inside = CreateArtificialFrameState(
node, frame_state, call.formal_arguments(),
BailoutId::ConstructStubCreate(), FrameStateType::kConstructStub,
shared_info);
shared_info, context);
Node* create =
graph()->NewNode(javascript()->Create(), call.target(), new_target,
context, frame_state_inside, effect, control);
@ -595,10 +598,10 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
node->ReplaceInput(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(node, frame_state, call.formal_arguments(),
BailoutId::ConstructStubInvoke(),
FrameStateType::kConstructStub, shared_info);
frame_state = CreateArtificialFrameState(
node, frame_state, call.formal_arguments(),
BailoutId::ConstructStubInvoke(), FrameStateType::kConstructStub,
shared_info, context);
}
// Insert a JSConvertReceiver node for sloppy callees. Note that the context

View File

@ -68,7 +68,8 @@ class JSInliner final : public AdvancedReducer {
Node* CreateArtificialFrameState(Node* node, Node* outer_frame_state,
int parameter_count, BailoutId bailout_id,
FrameStateType frame_state_type,
Handle<SharedFunctionInfo> shared);
Handle<SharedFunctionInfo> shared,
Node* context = nullptr);
Reduction InlineCall(Node* call, Node* new_target, Node* context,
Node* frame_state, Node* start, Node* end,

View File

@ -1187,7 +1187,8 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
BailoutId bailout_id = translated_frame->node_id();
unsigned height = translated_frame->height();
unsigned height_in_bytes = height * kPointerSize;
unsigned parameter_count = height - 1; // Exclude the context.
unsigned height_in_bytes = parameter_count * kPointerSize;
// If the construct frame appears to be topmost we should ensure that the
// value of result register is preserved during continuation execution.
@ -1199,7 +1200,6 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
if (PadTopOfStackRegister()) height_in_bytes += kPointerSize;
}
int parameter_count = height;
if (ShouldPadArguments(parameter_count)) height_in_bytes += kPointerSize;
TranslatedFrame::iterator function_iterator = value_iterator++;
@ -1241,7 +1241,7 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
TranslatedFrame::iterator receiver_iterator = value_iterator;
// Compute the incoming parameter translation.
for (int i = 0; i < parameter_count; ++i, ++value_iterator) {
for (unsigned i = 0; i < parameter_count; ++i, ++value_iterator) {
frame_writer.PushTranslatedValue(value_iterator, "stack parameter");
}
@ -1273,13 +1273,10 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
intptr_t marker = StackFrame::TypeToMarker(StackFrame::CONSTRUCT);
frame_writer.PushRawValue(marker, "context (construct stub sentinel)\n");
// The context can be gotten from the previous frame.
Object* context =
reinterpret_cast<Object*>(output_[frame_index - 1]->GetContext());
frame_writer.PushRawObject(context, "context\n");
frame_writer.PushTranslatedValue(value_iterator++, "context\n");
// Number of incoming arguments.
frame_writer.PushRawObject(Smi::FromInt(height - 1), "argc\n");
frame_writer.PushRawObject(Smi::FromInt(parameter_count - 1), "argc\n");
// The constructor function was mentioned explicitly in the
// CONSTRUCT_STUB_FRAME.

View File

@ -0,0 +1,26 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
class C extends Object {
constructor() {
try { super(); } catch (e) { };
return 1;
}
}
class A extends C {
constructor() {
super();
throw new Error();
return { get: () => this };
}
}
var D = new Proxy(A, { get() { %DeoptimizeFunction(A); } });
try { Reflect.construct(A, [], D); } catch(e) {}
%OptimizeFunctionOnNextCall(A);
try { Reflect.construct(A, [], D); } catch(e) {}