Commit e34f5366 authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[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}
parent b87d9949
...@@ -240,6 +240,7 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) { ...@@ -240,6 +240,7 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) {
Node* const new_target = NodeProperties::GetValueInput(node, 1); Node* const new_target = NodeProperties::GetValueInput(node, 1);
Type* const new_target_type = NodeProperties::GetType(new_target); Type* const new_target_type = NodeProperties::GetType(new_target);
Node* const effect = NodeProperties::GetEffectInput(node); Node* const effect = NodeProperties::GetEffectInput(node);
Node* const control = NodeProperties::GetControlInput(node);
// Extract constructor and original constructor function. // Extract constructor and original constructor function.
if (target_type->IsHeapConstant() && new_target_type->IsHeapConstant() && if (target_type->IsHeapConstant() && new_target_type->IsHeapConstant() &&
new_target_type->AsHeapConstant()->Value()->IsJSFunction()) { new_target_type->AsHeapConstant()->Value()->IsJSFunction()) {
...@@ -267,7 +268,7 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) { ...@@ -267,7 +268,7 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) {
// Emit code to allocate the JSObject instance for the // Emit code to allocate the JSObject instance for the
// {original_constructor}. // {original_constructor}.
AllocationBuilder a(jsgraph(), effect, graph()->start()); AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(instance_size); a.Allocate(instance_size);
a.Store(AccessBuilder::ForMap(), initial_map); a.Store(AccessBuilder::ForMap(), initial_map);
a.Store(AccessBuilder::ForJSObjectProperties(), a.Store(AccessBuilder::ForJSObjectProperties(),
...@@ -278,6 +279,7 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) { ...@@ -278,6 +279,7 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) {
a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i), a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
jsgraph()->UndefinedConstant()); jsgraph()->UndefinedConstant());
} }
RelaxControls(node);
a.FinishAndChange(node); a.FinishAndChange(node);
return Changed(node); return Changed(node);
} }
......
...@@ -636,10 +636,14 @@ Reduction JSInliner::ReduceJSCall(Node* node) { ...@@ -636,10 +636,14 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
if (NeedsImplicitReceiver(shared_info)) { if (NeedsImplicitReceiver(shared_info)) {
Node* frame_state_before = NodeProperties::FindFrameStateBefore(node); Node* frame_state_before = NodeProperties::FindFrameStateBefore(node);
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* context = NodeProperties::GetContextInput(node); Node* context = NodeProperties::GetContextInput(node);
Node* create = graph()->NewNode(javascript()->Create(), call.target(), Node* create = graph()->NewNode(javascript()->Create(), call.target(),
call.new_target(), context, 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); NodeProperties::ReplaceEffectInput(node, create);
// Insert a check of the return value to determine whether the return // 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 // value or the implicit receiver should be selected as a result of the
......
...@@ -551,7 +551,7 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) { ...@@ -551,7 +551,7 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
V(ToNumber, Operator::kNoProperties, 1, 1) \ V(ToNumber, Operator::kNoProperties, 1, 1) \
V(ToObject, Operator::kFoldable, 1, 1) \ V(ToObject, Operator::kFoldable, 1, 1) \
V(ToString, Operator::kNoProperties, 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(CreateIterResultObject, Operator::kEliminatable, 2, 1) \
V(CreateKeyValueArray, Operator::kEliminatable, 2, 1) \ V(CreateKeyValueArray, Operator::kEliminatable, 2, 1) \
V(HasProperty, Operator::kNoProperties, 2, 1) \ V(HasProperty, Operator::kNoProperties, 2, 1) \
......
// 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 { ...@@ -65,19 +65,24 @@ class JSCreateLoweringTest : public TypedGraphTest {
CompilationDependencies deps_; CompilationDependencies deps_;
}; };
// -----------------------------------------------------------------------------
// JSCreate
TEST_F(JSCreateLoweringTest, JSCreate) { TEST_F(JSCreateLoweringTest, JSCreate) {
Handle<JSFunction> function = isolate()->object_function(); Handle<JSFunction> function = isolate()->object_function();
Node* const target = Parameter(Type::HeapConstant(function, graph()->zone())); Node* const target = Parameter(Type::HeapConstant(function, graph()->zone()));
Node* const context = Parameter(Type::Any()); Node* const context = Parameter(Type::Any());
Node* const effect = graph()->start(); Node* const effect = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->Create(), target, target, Node* const control = graph()->start();
context, EmptyFrameState(), effect)); Reduction r =
Reduce(graph()->NewNode(javascript()->Create(), target, target, context,
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT( EXPECT_THAT(
r.replacement(), r.replacement(),
IsFinishRegion( IsFinishRegion(
IsAllocate(IsNumberConstant(function->initial_map()->instance_size()), IsAllocate(IsNumberConstant(function->initial_map()->instance_size()),
IsBeginRegion(effect), _), IsBeginRegion(effect), control),
_)); _));
} }
......
...@@ -44,7 +44,7 @@ const SharedOperator kSharedOperators[] = { ...@@ -44,7 +44,7 @@ const SharedOperator kSharedOperators[] = {
SHARED(ToString, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), SHARED(ToString, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2),
SHARED(ToName, 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(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), SHARED(TypeOf, Operator::kPure, 1, 0, 0, 0, 1, 0, 0),
#undef SHARED #undef SHARED
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment