[turbofan] Mark {JSCreate} as potentially throwing.
This correctly marks the {JSCreate} operator as potentially throwing, since it might trigger a property access of the 'prototype' property during instantiation. This is observable, can throw (not kNoThrow), might have side-effects (not kNoWrite), or even trigger a lazy deopt event (not kNoDeopt). The inlining logic has been adapted to wire up control projections accordingly. Note that this does not yet take care of the "after" frame-state which is associated with the {JSCreate} node introduced by the inliner. We still might re-evaluate the property access upon lazy deoptimization. R=bmeurer@chromium.org TEST=mjsunit/regress/regress-5638 BUG=v8:5638 Review-Url: https://codereview.chromium.org/2671203003 Cr-Commit-Position: refs/heads/master@{#42981}
This commit is contained in:
parent
b87d99495e
commit
e34f536620
@ -240,6 +240,7 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) {
|
||||
Node* const new_target = NodeProperties::GetValueInput(node, 1);
|
||||
Type* const new_target_type = NodeProperties::GetType(new_target);
|
||||
Node* const effect = NodeProperties::GetEffectInput(node);
|
||||
Node* const control = NodeProperties::GetControlInput(node);
|
||||
// Extract constructor and original constructor function.
|
||||
if (target_type->IsHeapConstant() && new_target_type->IsHeapConstant() &&
|
||||
new_target_type->AsHeapConstant()->Value()->IsJSFunction()) {
|
||||
@ -267,7 +268,7 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) {
|
||||
|
||||
// Emit code to allocate the JSObject instance for the
|
||||
// {original_constructor}.
|
||||
AllocationBuilder a(jsgraph(), effect, graph()->start());
|
||||
AllocationBuilder a(jsgraph(), effect, control);
|
||||
a.Allocate(instance_size);
|
||||
a.Store(AccessBuilder::ForMap(), initial_map);
|
||||
a.Store(AccessBuilder::ForJSObjectProperties(),
|
||||
@ -278,6 +279,7 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) {
|
||||
a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
|
||||
jsgraph()->UndefinedConstant());
|
||||
}
|
||||
RelaxControls(node);
|
||||
a.FinishAndChange(node);
|
||||
return Changed(node);
|
||||
}
|
||||
|
@ -636,10 +636,14 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
|
||||
if (NeedsImplicitReceiver(shared_info)) {
|
||||
Node* frame_state_before = NodeProperties::FindFrameStateBefore(node);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
Node* context = NodeProperties::GetContextInput(node);
|
||||
Node* create = graph()->NewNode(javascript()->Create(), call.target(),
|
||||
call.new_target(), context,
|
||||
frame_state_before, effect);
|
||||
frame_state_before, effect, control);
|
||||
Node* success = graph()->NewNode(common()->IfSuccess(), create);
|
||||
uncaught_subcalls.push_back(create); // Adds {IfException}.
|
||||
NodeProperties::ReplaceControlInput(node, success);
|
||||
NodeProperties::ReplaceEffectInput(node, 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
|
||||
|
@ -551,7 +551,7 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
|
||||
V(ToNumber, Operator::kNoProperties, 1, 1) \
|
||||
V(ToObject, Operator::kFoldable, 1, 1) \
|
||||
V(ToString, Operator::kNoProperties, 1, 1) \
|
||||
V(Create, Operator::kEliminatable, 2, 1) \
|
||||
V(Create, Operator::kNoProperties, 2, 1) \
|
||||
V(CreateIterResultObject, Operator::kEliminatable, 2, 1) \
|
||||
V(CreateKeyValueArray, Operator::kEliminatable, 2, 1) \
|
||||
V(HasProperty, Operator::kNoProperties, 2, 1) \
|
||||
|
32
test/mjsunit/regress/regress-5638.js
Normal file
32
test/mjsunit/regress/regress-5638.js
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2017 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 MyErrorA {}
|
||||
|
||||
class MyErrorB {}
|
||||
|
||||
class A {}
|
||||
|
||||
class B extends A {
|
||||
constructor() {
|
||||
try {
|
||||
super();
|
||||
} catch (e) {
|
||||
throw new MyErrorB();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var thrower = new Proxy(A, {
|
||||
get(target, property, receiver) {
|
||||
if (property === 'prototype') throw new MyErrorA();
|
||||
}
|
||||
});
|
||||
|
||||
assertThrows(() => Reflect.construct(B, [], thrower), MyErrorB);
|
||||
assertThrows(() => Reflect.construct(B, [], thrower), MyErrorB);
|
||||
%OptimizeFunctionOnNextCall(B);
|
||||
assertThrows(() => Reflect.construct(B, [], thrower), MyErrorB);
|
@ -65,19 +65,24 @@ class JSCreateLoweringTest : public TypedGraphTest {
|
||||
CompilationDependencies deps_;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// JSCreate
|
||||
|
||||
TEST_F(JSCreateLoweringTest, JSCreate) {
|
||||
Handle<JSFunction> function = isolate()->object_function();
|
||||
Node* const target = Parameter(Type::HeapConstant(function, graph()->zone()));
|
||||
Node* const context = Parameter(Type::Any());
|
||||
Node* const effect = graph()->start();
|
||||
Reduction r = Reduce(graph()->NewNode(javascript()->Create(), target, target,
|
||||
context, EmptyFrameState(), effect));
|
||||
Node* const control = graph()->start();
|
||||
Reduction r =
|
||||
Reduce(graph()->NewNode(javascript()->Create(), target, target, context,
|
||||
EmptyFrameState(), effect, control));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(
|
||||
r.replacement(),
|
||||
IsFinishRegion(
|
||||
IsAllocate(IsNumberConstant(function->initial_map()->instance_size()),
|
||||
IsBeginRegion(effect), _),
|
||||
IsBeginRegion(effect), control),
|
||||
_));
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ const SharedOperator kSharedOperators[] = {
|
||||
SHARED(ToString, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2),
|
||||
SHARED(ToName, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2),
|
||||
SHARED(ToObject, Operator::kFoldable, 1, 1, 1, 1, 1, 1, 2),
|
||||
SHARED(Create, Operator::kEliminatable, 2, 1, 1, 0, 1, 1, 0),
|
||||
SHARED(Create, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
|
||||
SHARED(TypeOf, Operator::kPure, 1, 0, 0, 0, 1, 0, 0),
|
||||
#undef SHARED
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user