[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:
mstarzinger 2017-02-07 01:00:18 -08:00 committed by Commit bot
parent b87d99495e
commit e34f536620
6 changed files with 50 additions and 7 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -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) \

View 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);

View File

@ -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),
_));
}

View File

@ -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
};