diff --git a/src/compiler/code-generator.cc b/src/compiler/code-generator.cc index 143dcb36c6..a0777c62d6 100644 --- a/src/compiler/code-generator.cc +++ b/src/compiler/code-generator.cc @@ -1033,7 +1033,7 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor( DCHECK(descriptor->bailout_id().IsValidForConstructStub()); translation->BeginConstructStubFrame( descriptor->bailout_id(), shared_info_id, - static_cast(descriptor->parameters_count())); + static_cast(descriptor->parameters_count() + 1)); break; case FrameStateType::kBuiltinContinuation: { BailoutId bailout_id = descriptor->bailout_id(); diff --git a/src/compiler/instruction.h b/src/compiler/instruction.h index e38e634e15..39d083c2de 100644 --- a/src/compiler/instruction.h +++ b/src/compiler/instruction.h @@ -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; diff --git a/src/compiler/js-call-reducer.cc b/src/compiler/js-call-reducer.cc index 528f61fad4..7fdace2d0c 100644 --- a/src/compiler/js-call-reducer.cc +++ b/src/compiler/js-call-reducer.cc @@ -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 shared) { + Handle 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(params.size()), SparseInputMask::Dense()); Node* params_node = graph()->NewNode( op_param, static_cast(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 diff --git a/src/compiler/js-call-reducer.h b/src/compiler/js-call-reducer.h index f52b3e40f0..5dd818c1d0 100644 --- a/src/compiler/js-call-reducer.h +++ b/src/compiler/js-call-reducer.h @@ -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 shared); + Handle shared, + Node* context = nullptr); Graph* graph() const; JSGraph* jsgraph() const { return jsgraph_; } diff --git a/src/compiler/js-inlining.cc b/src/compiler/js-inlining.cc index 0f41fc5e10..3813bc90ef 100644 --- a/src/compiler/js-inlining.cc +++ b/src/compiler/js-inlining.cc @@ -234,7 +234,8 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state, int parameter_count, BailoutId bailout_id, FrameStateType frame_state_type, - Handle shared) { + Handle 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(params.size()), SparseInputMask::Dense()); Node* params_node = graph()->NewNode( op_param, static_cast(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 diff --git a/src/compiler/js-inlining.h b/src/compiler/js-inlining.h index 6edc67184a..083fa2892b 100644 --- a/src/compiler/js-inlining.h +++ b/src/compiler/js-inlining.h @@ -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 shared); + Handle shared, + Node* context = nullptr); Reduction InlineCall(Node* call, Node* new_target, Node* context, Node* frame_state, Node* start, Node* end, diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc index c57bdc388c..6c60a258af 100644 --- a/src/deoptimizer.cc +++ b/src/deoptimizer.cc @@ -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(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. diff --git a/test/mjsunit/compiler/regress-895799.js b/test/mjsunit/compiler/regress-895799.js new file mode 100644 index 0000000000..4305b7427b --- /dev/null +++ b/test/mjsunit/compiler/regress-895799.js @@ -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) {}