Commit 75020297 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Fix typed lowering of JSConvertReceiver.

We lowered JSConvertReceiver using JSToObject, w/o connecting the
JSToObject to the control chain (which is fine since that ToObject
cannot throw). But then the lowering of the JSToObject would insert
an IfSuccess, which is immediately dead, since it is not used. This
was fine in a sense that it didn't seem to crash anything, but we
now want to do more aggressive checking if IfSuccess/IfException
nodes and so we need to fix this sloppyness in the lowerings.

R=mstarzinger@chromium.org

Review-Url: https://codereview.chromium.org/2228783003
Cr-Commit-Position: refs/heads/master@{#38484}
parent b531266d
...@@ -690,11 +690,11 @@ const Operator* JSOperatorBuilder::CallConstruct( ...@@ -690,11 +690,11 @@ const Operator* JSOperatorBuilder::CallConstruct(
const Operator* JSOperatorBuilder::ConvertReceiver( const Operator* JSOperatorBuilder::ConvertReceiver(
ConvertReceiverMode convert_mode) { ConvertReceiverMode convert_mode) {
return new (zone()) Operator1<ConvertReceiverMode>( // -- return new (zone()) Operator1<ConvertReceiverMode>( // --
IrOpcode::kJSConvertReceiver, Operator::kNoThrow, // opcode IrOpcode::kJSConvertReceiver, Operator::kEliminatable, // opcode
"JSConvertReceiver", // name "JSConvertReceiver", // name
1, 1, 1, 1, 1, 0, // counts 1, 1, 1, 1, 1, 0, // counts
convert_mode); // parameter convert_mode); // parameter
} }
const Operator* JSOperatorBuilder::LoadNamed(Handle<Name> name, const Operator* JSOperatorBuilder::LoadNamed(Handle<Name> name,
......
...@@ -386,7 +386,6 @@ JSTypedLowering::JSTypedLowering(Editor* editor, ...@@ -386,7 +386,6 @@ JSTypedLowering::JSTypedLowering(Editor* editor,
} }
} }
Reduction JSTypedLowering::ReduceJSAdd(Node* node) { Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
NumberOperationHint hint; NumberOperationHint hint;
...@@ -742,7 +741,6 @@ Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) { ...@@ -742,7 +741,6 @@ Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) {
return NoChange(); return NoChange();
} }
Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
if (r.left() == r.right()) { if (r.left() == r.right()) {
...@@ -805,7 +803,6 @@ Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { ...@@ -805,7 +803,6 @@ Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
return NoChange(); return NoChange();
} }
Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
Node* const input = node->InputAt(0); Node* const input = node->InputAt(0);
Type* const input_type = NodeProperties::GetType(input); Type* const input_type = NodeProperties::GetType(input);
...@@ -916,7 +913,6 @@ Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { ...@@ -916,7 +913,6 @@ Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
return NoChange(); return NoChange();
} }
Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
// Try to reduce the input first. // Try to reduce the input first.
Node* const input = node->InputAt(0); Node* const input = node->InputAt(0);
...@@ -935,7 +931,6 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { ...@@ -935,7 +931,6 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
return NoChange(); return NoChange();
} }
Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) { Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
if (input->opcode() == IrOpcode::kJSToString) { if (input->opcode() == IrOpcode::kJSToString) {
// Recursively try to reduce the input first. // Recursively try to reduce the input first.
...@@ -963,7 +958,6 @@ Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) { ...@@ -963,7 +958,6 @@ Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
return NoChange(); return NoChange();
} }
Reduction JSTypedLowering::ReduceJSToString(Node* node) { Reduction JSTypedLowering::ReduceJSToString(Node* node) {
// Try to reduce the input first. // Try to reduce the input first.
Node* const input = node->InputAt(0); Node* const input = node->InputAt(0);
...@@ -975,7 +969,6 @@ Reduction JSTypedLowering::ReduceJSToString(Node* node) { ...@@ -975,7 +969,6 @@ Reduction JSTypedLowering::ReduceJSToString(Node* node) {
return NoChange(); return NoChange();
} }
Reduction JSTypedLowering::ReduceJSToObject(Node* node) { Reduction JSTypedLowering::ReduceJSToObject(Node* node) {
DCHECK_EQ(IrOpcode::kJSToObject, node->opcode()); DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
Node* receiver = NodeProperties::GetValueInput(node, 0); Node* receiver = NodeProperties::GetValueInput(node, 0);
...@@ -1053,7 +1046,6 @@ Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) { ...@@ -1053,7 +1046,6 @@ Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
return NoChange(); return NoChange();
} }
Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
Node* key = NodeProperties::GetValueInput(node, 1); Node* key = NodeProperties::GetValueInput(node, 1);
Node* base = NodeProperties::GetValueInput(node, 0); Node* base = NodeProperties::GetValueInput(node, 0);
...@@ -1101,7 +1093,6 @@ Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { ...@@ -1101,7 +1093,6 @@ Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
return NoChange(); return NoChange();
} }
Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) { Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
Node* key = NodeProperties::GetValueInput(node, 1); Node* key = NodeProperties::GetValueInput(node, 1);
Node* base = NodeProperties::GetValueInput(node, 0); Node* base = NodeProperties::GetValueInput(node, 0);
...@@ -1179,7 +1170,6 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) { ...@@ -1179,7 +1170,6 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
return NoChange(); return NoChange();
} }
Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) { Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) {
DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode()); DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode());
Node* const context = NodeProperties::GetContextInput(node); Node* const context = NodeProperties::GetContextInput(node);
...@@ -1282,7 +1272,6 @@ Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) { ...@@ -1282,7 +1272,6 @@ Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) {
Node* if_is_proxy = graph()->NewNode(common()->IfTrue(), branch_is_proxy); Node* if_is_proxy = graph()->NewNode(common()->IfTrue(), branch_is_proxy);
Node* e_is_proxy = effect; Node* e_is_proxy = effect;
Node* runtime_has_in_proto_chain = control = graph()->NewNode( Node* runtime_has_in_proto_chain = control = graph()->NewNode(
common()->Merge(2), if_is_access_check_needed, if_is_proxy); common()->Merge(2), if_is_access_check_needed, if_is_proxy);
effect = graph()->NewNode(common()->EffectPhi(2), e_is_access_check_needed, effect = graph()->NewNode(common()->EffectPhi(2), e_is_access_check_needed,
...@@ -1353,7 +1342,6 @@ Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) { ...@@ -1353,7 +1342,6 @@ Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) {
return Changed(result); return Changed(result);
} }
Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) { Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode()); DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
ContextAccess const& access = ContextAccessOf(node->op()); ContextAccess const& access = ContextAccessOf(node->op());
...@@ -1374,7 +1362,6 @@ Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) { ...@@ -1374,7 +1362,6 @@ Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
return Changed(node); return Changed(node);
} }
Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) { Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode()); DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
ContextAccess const& access = ContextAccessOf(node->op()); ContextAccess const& access = ContextAccessOf(node->op());
...@@ -1395,7 +1382,6 @@ Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) { ...@@ -1395,7 +1382,6 @@ Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
return Changed(node); return Changed(node);
} }
Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) { Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) {
DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode()); DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode());
ConvertReceiverMode mode = ConvertReceiverModeOf(node->op()); ConvertReceiverMode mode = ConvertReceiverModeOf(node->op());
...@@ -1406,89 +1392,153 @@ Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) { ...@@ -1406,89 +1392,153 @@ Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) {
Node* frame_state = NodeProperties::GetFrameStateInput(node); Node* frame_state = NodeProperties::GetFrameStateInput(node);
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node); Node* control = NodeProperties::GetControlInput(node);
if (!receiver_type->Is(Type::Receiver())) {
if (receiver_type->Is(Type::NullOrUndefined()) || // Check if {receiver} is known to be a receiver.
mode == ConvertReceiverMode::kNullOrUndefined) { if (receiver_type->Is(Type::Receiver())) {
if (context_type->IsConstant()) { ReplaceWithValue(node, receiver, effect, control);
Handle<JSObject> global_proxy( return Replace(receiver);
Handle<Context>::cast(context_type->AsConstant()->Value()) }
->global_proxy(),
isolate()); // If the {receiver} is known to be null or undefined, we can just replace it
receiver = jsgraph()->Constant(global_proxy); // with the global proxy unconditionally.
} else { if (receiver_type->Is(Type::NullOrUndefined()) ||
Node* native_context = effect = graph()->NewNode( mode == ConvertReceiverMode::kNullOrUndefined) {
javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), if (context_type->IsConstant()) {
context, context, effect); Handle<JSObject> global_proxy(
receiver = effect = graph()->NewNode( Handle<Context>::cast(context_type->AsConstant()->Value())
javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true), ->global_proxy(),
native_context, native_context, effect); isolate());
} receiver = jsgraph()->Constant(global_proxy);
} else if (!receiver_type->Maybe(Type::NullOrUndefined()) ||
mode == ConvertReceiverMode::kNotNullOrUndefined) {
receiver = effect =
graph()->NewNode(javascript()->ToObject(), receiver, context,
frame_state, effect, control);
} else { } else {
// Check {receiver} for undefined. Node* native_context = effect = graph()->NewNode(
Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), receiver, javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
jsgraph()->UndefinedConstant()); context, context, effect);
Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse), receiver = effect = graph()->NewNode(
check0, control); javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); native_context, native_context, effect);
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); }
ReplaceWithValue(node, receiver, effect, control);
// Check {receiver} for null. return Replace(receiver);
Node* check1 = graph()->NewNode(simplified()->ReferenceEqual(), receiver, }
jsgraph()->NullConstant());
Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
check1, if_false0);
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
// Convert {receiver} using ToObject.
Node* if_convert = if_false1;
Node* econvert = effect;
Node* rconvert;
{
rconvert = econvert =
graph()->NewNode(javascript()->ToObject(), receiver, context,
frame_state, econvert, if_convert);
}
// Replace {receiver} with global proxy of {context}. // If {receiver} cannot be null or undefined we can skip a few checks.
Node* if_global = if (!receiver_type->Maybe(Type::NullOrUndefined()) ||
graph()->NewNode(common()->Merge(2), if_true0, if_true1); mode == ConvertReceiverMode::kNotNullOrUndefined) {
Node* eglobal = effect; Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
Node* rglobal; Node* branch =
{ graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
if (context_type->IsConstant()) {
Handle<JSObject> global_proxy( Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Handle<Context>::cast(context_type->AsConstant()->Value()) Node* etrue = effect;
->global_proxy(), Node* rtrue = receiver;
isolate());
rglobal = jsgraph()->Constant(global_proxy); Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
} else { Node* efalse = effect;
Node* native_context = eglobal = graph()->NewNode( Node* rfalse;
javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), {
context, context, eglobal); // Convert {receiver} using the ToObjectStub.
rglobal = eglobal = graph()->NewNode( Callable callable = CodeFactory::ToObject(isolate());
javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true), CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
native_context, native_context, eglobal); isolate(), graph()->zone(), callable.descriptor(), 0,
} CallDescriptor::kNeedsFrameState, node->op()->properties());
} rfalse = efalse = graph()->NewNode(
common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
receiver, context, frame_state, efalse);
}
control = graph()->NewNode(common()->Merge(2), if_true, if_false);
effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
// Morph the {node} into an appropriate Phi.
ReplaceWithValue(node, node, effect, control);
node->ReplaceInput(0, rtrue);
node->ReplaceInput(1, rfalse);
node->ReplaceInput(2, control);
node->TrimInputCount(3);
NodeProperties::ChangeOp(node,
common()->Phi(MachineRepresentation::kTagged, 2));
return Changed(node);
}
// Check if {receiver} is already a JSReceiver.
Node* check0 = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
Node* branch0 =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
// Check {receiver} for undefined.
Node* check1 = graph()->NewNode(simplified()->ReferenceEqual(), receiver,
jsgraph()->UndefinedConstant());
Node* branch1 =
graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, if_false0);
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
// Check {receiver} for null.
Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(), receiver,
jsgraph()->NullConstant());
Node* branch2 =
graph()->NewNode(common()->Branch(BranchHint::kFalse), check2, if_false1);
Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
// We just use {receiver} directly.
Node* if_noop = if_true0;
Node* enoop = effect;
Node* rnoop = receiver;
// Convert {receiver} using ToObject.
Node* if_convert = if_false2;
Node* econvert = effect;
Node* rconvert;
{
// Convert {receiver} using the ToObjectStub.
Callable callable = CodeFactory::ToObject(isolate());
CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), callable.descriptor(), 0,
CallDescriptor::kNeedsFrameState, node->op()->properties());
rconvert = econvert = graph()->NewNode(
common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
receiver, context, frame_state, econvert);
}
control = graph()->NewNode(common()->Merge(2), if_convert, if_global); // Replace {receiver} with global proxy of {context}.
effect = Node* if_global = graph()->NewNode(common()->Merge(2), if_true1, if_true2);
graph()->NewNode(common()->EffectPhi(2), econvert, eglobal, control); Node* eglobal = effect;
receiver = Node* rglobal;
graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), {
rconvert, rglobal, control); if (context_type->IsConstant()) {
Handle<JSObject> global_proxy(
Handle<Context>::cast(context_type->AsConstant()->Value())
->global_proxy(),
isolate());
rglobal = jsgraph()->Constant(global_proxy);
} else {
Node* native_context = eglobal = graph()->NewNode(
javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
context, context, eglobal);
rglobal = eglobal = graph()->NewNode(
javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
native_context, native_context, eglobal);
} }
} }
ReplaceWithValue(node, receiver, effect, control);
return Changed(receiver);
}
control =
graph()->NewNode(common()->Merge(3), if_noop, if_convert, if_global);
effect = graph()->NewNode(common()->EffectPhi(3), enoop, econvert, eglobal,
control);
// Morph the {node} into an appropriate Phi.
ReplaceWithValue(node, node, effect, control);
node->ReplaceInput(0, rnoop);
node->ReplaceInput(1, rconvert);
node->ReplaceInput(2, rglobal);
node->ReplaceInput(3, control);
node->TrimInputCount(4);
NodeProperties::ChangeOp(node,
common()->Phi(MachineRepresentation::kTagged, 3));
return Changed(node);
}
Reduction JSTypedLowering::ReduceJSCallConstruct(Node* node) { Reduction JSTypedLowering::ReduceJSCallConstruct(Node* node) {
DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode()); DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode());
......
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