[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:
parent
e1c6fa8878
commit
2d11ddab98
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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()), ¶ms.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
|
||||
|
@ -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_; }
|
||||
|
@ -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()), ¶ms.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
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
26
test/mjsunit/compiler/regress-895799.js
Normal file
26
test/mjsunit/compiler/regress-895799.js
Normal 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) {}
|
Loading…
Reference in New Issue
Block a user