Index: src/compiler/js-typed-lowering.cc |
diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc |
index 01122bdfb4b9cfa6c9db34a63f1d12a8b07a7a02..878c32d1bed0c152dff592ff0578088b8715bcb9 100644 |
--- a/src/compiler/js-typed-lowering.cc |
+++ b/src/compiler/js-typed-lowering.cc |
@@ -386,7 +386,6 @@ JSTypedLowering::JSTypedLowering(Editor* editor, |
} |
} |
- |
Reduction JSTypedLowering::ReduceJSAdd(Node* node) { |
JSBinopReduction r(this, node); |
NumberOperationHint hint; |
@@ -742,7 +741,6 @@ Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) { |
return NoChange(); |
} |
- |
Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { |
JSBinopReduction r(this, node); |
if (r.left() == r.right()) { |
@@ -805,7 +803,6 @@ Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { |
return NoChange(); |
} |
- |
Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { |
Node* const input = node->InputAt(0); |
Type* const input_type = NodeProperties::GetType(input); |
@@ -916,7 +913,6 @@ Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { |
return NoChange(); |
} |
- |
Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { |
// Try to reduce the input first. |
Node* const input = node->InputAt(0); |
@@ -935,7 +931,6 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { |
return NoChange(); |
} |
- |
Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) { |
if (input->opcode() == IrOpcode::kJSToString) { |
// Recursively try to reduce the input first. |
@@ -963,7 +958,6 @@ Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) { |
return NoChange(); |
} |
- |
Reduction JSTypedLowering::ReduceJSToString(Node* node) { |
// Try to reduce the input first. |
Node* const input = node->InputAt(0); |
@@ -975,7 +969,6 @@ Reduction JSTypedLowering::ReduceJSToString(Node* node) { |
return NoChange(); |
} |
- |
Reduction JSTypedLowering::ReduceJSToObject(Node* node) { |
DCHECK_EQ(IrOpcode::kJSToObject, node->opcode()); |
Node* receiver = NodeProperties::GetValueInput(node, 0); |
@@ -1053,7 +1046,6 @@ Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) { |
return NoChange(); |
} |
- |
Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { |
Node* key = NodeProperties::GetValueInput(node, 1); |
Node* base = NodeProperties::GetValueInput(node, 0); |
@@ -1101,7 +1093,6 @@ Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { |
return NoChange(); |
} |
- |
Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) { |
Node* key = NodeProperties::GetValueInput(node, 1); |
Node* base = NodeProperties::GetValueInput(node, 0); |
@@ -1179,7 +1170,6 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) { |
return NoChange(); |
} |
- |
Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) { |
DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode()); |
Node* const context = NodeProperties::GetContextInput(node); |
@@ -1282,7 +1272,6 @@ Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) { |
Node* if_is_proxy = graph()->NewNode(common()->IfTrue(), branch_is_proxy); |
Node* e_is_proxy = effect; |
- |
Node* runtime_has_in_proto_chain = control = graph()->NewNode( |
common()->Merge(2), if_is_access_check_needed, if_is_proxy); |
effect = graph()->NewNode(common()->EffectPhi(2), e_is_access_check_needed, |
@@ -1353,7 +1342,6 @@ Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) { |
return Changed(result); |
} |
- |
Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) { |
DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode()); |
ContextAccess const& access = ContextAccessOf(node->op()); |
@@ -1374,7 +1362,6 @@ Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) { |
return Changed(node); |
} |
- |
Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) { |
DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode()); |
ContextAccess const& access = ContextAccessOf(node->op()); |
@@ -1395,7 +1382,6 @@ Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) { |
return Changed(node); |
} |
- |
Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) { |
DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode()); |
ConvertReceiverMode mode = ConvertReceiverModeOf(node->op()); |
@@ -1406,89 +1392,153 @@ Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) { |
Node* frame_state = NodeProperties::GetFrameStateInput(node); |
Node* effect = NodeProperties::GetEffectInput(node); |
Node* control = NodeProperties::GetControlInput(node); |
- if (!receiver_type->Is(Type::Receiver())) { |
- if (receiver_type->Is(Type::NullOrUndefined()) || |
- mode == ConvertReceiverMode::kNullOrUndefined) { |
- if (context_type->IsConstant()) { |
- Handle<JSObject> global_proxy( |
- Handle<Context>::cast(context_type->AsConstant()->Value()) |
- ->global_proxy(), |
- isolate()); |
- receiver = jsgraph()->Constant(global_proxy); |
- } else { |
- Node* native_context = effect = graph()->NewNode( |
- javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), |
- context, context, effect); |
- receiver = effect = graph()->NewNode( |
- javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true), |
- native_context, native_context, effect); |
- } |
- } else if (!receiver_type->Maybe(Type::NullOrUndefined()) || |
- mode == ConvertReceiverMode::kNotNullOrUndefined) { |
- receiver = effect = |
- graph()->NewNode(javascript()->ToObject(), receiver, context, |
- frame_state, effect, control); |
+ |
+ // Check if {receiver} is known to be a receiver. |
+ if (receiver_type->Is(Type::Receiver())) { |
+ ReplaceWithValue(node, receiver, effect, control); |
+ return Replace(receiver); |
+ } |
+ |
+ // If the {receiver} is known to be null or undefined, we can just replace it |
+ // with the global proxy unconditionally. |
+ if (receiver_type->Is(Type::NullOrUndefined()) || |
+ mode == ConvertReceiverMode::kNullOrUndefined) { |
+ if (context_type->IsConstant()) { |
+ Handle<JSObject> global_proxy( |
+ Handle<Context>::cast(context_type->AsConstant()->Value()) |
+ ->global_proxy(), |
+ isolate()); |
+ receiver = jsgraph()->Constant(global_proxy); |
} else { |
- // Check {receiver} for undefined. |
- Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), receiver, |
- jsgraph()->UndefinedConstant()); |
- Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
- check0, control); |
- Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
- Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
- |
- // Check {receiver} for null. |
- 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); |
- } |
+ Node* native_context = effect = graph()->NewNode( |
+ javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), |
+ context, context, effect); |
+ receiver = effect = graph()->NewNode( |
+ javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true), |
+ native_context, native_context, effect); |
+ } |
+ ReplaceWithValue(node, receiver, effect, control); |
+ return Replace(receiver); |
+ } |
- // Replace {receiver} with global proxy of {context}. |
- Node* if_global = |
- graph()->NewNode(common()->Merge(2), if_true0, if_true1); |
- Node* eglobal = effect; |
- Node* rglobal; |
- { |
- 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); |
- } |
- } |
+ // If {receiver} cannot be null or undefined we can skip a few checks. |
+ if (!receiver_type->Maybe(Type::NullOrUndefined()) || |
+ mode == ConvertReceiverMode::kNotNullOrUndefined) { |
+ Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver); |
+ Node* branch = |
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
+ |
+ Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
+ Node* etrue = effect; |
+ Node* rtrue = receiver; |
+ |
+ Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
+ Node* efalse = effect; |
+ Node* rfalse; |
+ { |
+ // 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()); |
+ 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); |
- effect = |
- graph()->NewNode(common()->EffectPhi(2), econvert, eglobal, control); |
- receiver = |
- graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), |
- rconvert, rglobal, control); |
+ // Replace {receiver} with global proxy of {context}. |
+ Node* if_global = graph()->NewNode(common()->Merge(2), if_true1, if_true2); |
+ Node* eglobal = effect; |
+ Node* rglobal; |
+ { |
+ 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) { |
DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode()); |