Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(121)

Unified Diff: src/compiler/js-typed-lowering.cc

Issue 2263273003: [turbofan] Improve fast case of JSInstanceOf lowering. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Renaming based on comment Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | test/unittests/compiler/js-typed-lowering-unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/js-typed-lowering.cc
diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc
index 62861b3c1c70cd3d82fa1a14a464e5d186ad684c..ed8f3b0dae4afa3f5db2af01cef9c10f2d79852d 100644
--- a/src/compiler/js-typed-lowering.cc
+++ b/src/compiler/js-typed-lowering.cc
@@ -1145,6 +1145,7 @@ Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) {
if (NodeProperties::IsExceptionalCall(node)) return NoChange();
JSBinopReduction r(this, node);
+ Node* object = r.left();
Node* effect = r.effect();
Node* control = r.control();
@@ -1175,134 +1176,121 @@ Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) {
Node* prototype =
jsgraph()->Constant(handle(initial_map->prototype(), isolate()));
- Node* if_is_smi = nullptr;
- Node* e_is_smi = nullptr;
- // If the left hand side is an object, no smi check is needed.
- if (r.left_type()->Maybe(Type::TaggedSigned())) {
- Node* is_smi = graph()->NewNode(simplified()->ObjectIsSmi(), r.left());
- Node* branch_is_smi =
- graph()->NewNode(common()->Branch(BranchHint::kFalse), is_smi, control);
- if_is_smi = graph()->NewNode(common()->IfTrue(), branch_is_smi);
- e_is_smi = effect;
- control = graph()->NewNode(common()->IfFalse(), branch_is_smi);
- }
+ Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), object);
+ Node* branch0 =
+ graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
- Node* object_map = effect =
- graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
- r.left(), effect, control);
+ Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
+ Node* etrue0 = effect;
+ Node* vtrue0 = jsgraph()->FalseConstant();
+
+ control = graph()->NewNode(common()->IfFalse(), branch0);
// Loop through the {object}s prototype chain looking for the {prototype}.
Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
-
- Node* loop_effect = effect =
+ Node* eloop = effect =
graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
+ Node* vloop = object = graph()->NewNode(
+ common()->Phi(MachineRepresentation::kTagged, 2), object, object, loop);
+ // TODO(jarin): This is a very ugly hack to work-around the super-smart
+ // implicit typing of the Phi, which goes completely nuts if the {object}
+ // is for example a HeapConstant.
+ NodeProperties::SetType(vloop, Type::NonInternal());
+
+ // Load the {object} map and instance type.
+ Node* object_map = effect =
+ graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), object,
+ effect, control);
+ Node* object_instance_type = effect = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForMapInstanceType()), object_map,
+ effect, control);
+
+ // Check if the {object} is a special receiver, because for special
+ // receivers, i.e. proxies or API objects that need access checks,
+ // we have to use the %HasInPrototypeChain runtime function instead.
+ Node* check1 = graph()->NewNode(
+ simplified()->NumberLessThanOrEqual(), object_instance_type,
+ jsgraph()->Constant(LAST_SPECIAL_RECEIVER_TYPE));
+ Node* branch1 =
+ graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control);
- Node* loop_object_map =
- graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
- object_map, r.left(), loop);
-
- // Check if the lhs needs access checks.
- Node* map_bit_field = effect =
- graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMapBitField()),
- loop_object_map, loop_effect, control);
- int is_access_check_needed_bit = 1 << Map::kIsAccessCheckNeeded;
- Node* is_access_check_needed_num =
- graph()->NewNode(simplified()->NumberBitwiseAnd(), map_bit_field,
- jsgraph()->Constant(is_access_check_needed_bit));
- Node* is_access_check_needed =
- graph()->NewNode(simplified()->NumberEqual(), is_access_check_needed_num,
- jsgraph()->Constant(is_access_check_needed_bit));
-
- Node* branch_is_access_check_needed = graph()->NewNode(
- common()->Branch(BranchHint::kFalse), is_access_check_needed, control);
- Node* if_is_access_check_needed =
- graph()->NewNode(common()->IfTrue(), branch_is_access_check_needed);
- Node* e_is_access_check_needed = effect;
+ control = graph()->NewNode(common()->IfFalse(), branch1);
- control =
- graph()->NewNode(common()->IfFalse(), branch_is_access_check_needed);
-
- // Check if the lhs is a proxy.
- Node* map_instance_type = effect = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
- loop_object_map, loop_effect, control);
- Node* is_proxy =
- graph()->NewNode(simplified()->NumberEqual(), map_instance_type,
- jsgraph()->Constant(JS_PROXY_TYPE));
- Node* branch_is_proxy =
- graph()->NewNode(common()->Branch(BranchHint::kFalse), is_proxy, control);
- Node* if_is_proxy = graph()->NewNode(common()->IfTrue(), branch_is_proxy);
- Node* e_is_proxy = effect;
-
- 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,
- e_is_proxy, control);
-
- // If we need an access check or the object is a Proxy, make a runtime call
- // to finish the lowering.
- Node* runtimecall = graph()->NewNode(
- javascript()->CallRuntime(Runtime::kHasInPrototypeChain), r.left(),
- prototype, context, frame_state, effect, control);
-
- Node* runtimecall_control =
- graph()->NewNode(common()->IfSuccess(), runtimecall);
-
- control = graph()->NewNode(common()->IfFalse(), branch_is_proxy);
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+ Node* etrue1 = effect;
+ Node* vtrue1;
+
+ // Check if the {object} is not a receiver at all.
+ Node* check10 =
+ graph()->NewNode(simplified()->NumberLessThan(), object_instance_type,
+ jsgraph()->Constant(FIRST_JS_RECEIVER_TYPE));
+ Node* branch10 =
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check10, if_true1);
+
+ // A primitive value cannot match the {prototype} we're looking for.
+ if_true1 = graph()->NewNode(common()->IfTrue(), branch10);
+ vtrue1 = jsgraph()->FalseConstant();
+
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch10);
+ Node* efalse1 = etrue1;
+ Node* vfalse1;
+ {
+ // Slow path, need to call the %HasInPrototypeChain runtime function.
+ vfalse1 = efalse1 = graph()->NewNode(
+ javascript()->CallRuntime(Runtime::kHasInPrototypeChain), object,
+ prototype, context, frame_state, efalse1, if_false1);
+ if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1);
+ }
+ // Load the {object} prototype.
Node* object_prototype = effect = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForMapPrototype()),
- loop_object_map, loop_effect, control);
-
- // If not, check if object prototype is the null prototype.
- Node* null_proto =
- graph()->NewNode(simplified()->ReferenceEqual(), object_prototype,
- jsgraph()->NullConstant());
- Node* branch_null_proto = graph()->NewNode(
- common()->Branch(BranchHint::kFalse), null_proto, control);
- Node* if_null_proto = graph()->NewNode(common()->IfTrue(), branch_null_proto);
- Node* e_null_proto = effect;
-
- control = graph()->NewNode(common()->IfFalse(), branch_null_proto);
-
- // Check if object prototype is equal to function prototype.
- Node* eq_proto = graph()->NewNode(simplified()->ReferenceEqual(),
- object_prototype, prototype);
- Node* branch_eq_proto =
- graph()->NewNode(common()->Branch(BranchHint::kFalse), eq_proto, control);
- Node* if_eq_proto = graph()->NewNode(common()->IfTrue(), branch_eq_proto);
- Node* e_eq_proto = effect;
-
- control = graph()->NewNode(common()->IfFalse(), branch_eq_proto);
-
- Node* load_object_map = effect =
- graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
- object_prototype, effect, control);
- // Close the loop.
- loop_effect->ReplaceInput(1, effect);
- loop_object_map->ReplaceInput(1, load_object_map);
- loop->ReplaceInput(1, control);
+ simplified()->LoadField(AccessBuilder::ForMapPrototype()), object_map,
+ effect, control);
+
+ // Check if we reached the end of {object}s prototype chain.
+ Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(),
+ object_prototype, jsgraph()->NullConstant());
+ Node* branch2 = graph()->NewNode(common()->Branch(), check2, control);
- control = graph()->NewNode(common()->Merge(3), runtimecall_control,
- if_eq_proto, if_null_proto);
- effect = graph()->NewNode(common()->EffectPhi(3), runtimecall, e_eq_proto,
- e_null_proto, control);
+ Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
+ Node* etrue2 = effect;
+ Node* vtrue2 = jsgraph()->FalseConstant();
- Node* result = graph()->NewNode(
- common()->Phi(MachineRepresentation::kTagged, 3), runtimecall,
- jsgraph()->TrueConstant(), jsgraph()->FalseConstant(), control);
+ control = graph()->NewNode(common()->IfFalse(), branch2);
- if (if_is_smi != nullptr) {
- DCHECK_NOT_NULL(e_is_smi);
- control = graph()->NewNode(common()->Merge(2), if_is_smi, control);
- effect =
- graph()->NewNode(common()->EffectPhi(2), e_is_smi, effect, control);
- result = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
- jsgraph()->FalseConstant(), result, control);
- }
+ // Check if we reached the {prototype}.
+ Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(),
+ object_prototype, prototype);
+ Node* branch3 = graph()->NewNode(common()->Branch(), check3, control);
- ReplaceWithValue(node, result, effect, control);
- return Changed(result);
+ Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3);
+ Node* etrue3 = effect;
+ Node* vtrue3 = jsgraph()->TrueConstant();
+
+ control = graph()->NewNode(common()->IfFalse(), branch3);
+
+ // Close the loop.
+ vloop->ReplaceInput(1, object_prototype);
+ eloop->ReplaceInput(1, effect);
+ loop->ReplaceInput(1, control);
+
+ control = graph()->NewNode(common()->Merge(5), if_true0, if_true1, if_true2,
+ if_true3, if_false1);
+ effect = graph()->NewNode(common()->EffectPhi(5), etrue0, etrue1, etrue2,
+ etrue3, efalse1, control);
+
+ // Morph the {node} into an appropriate Phi.
+ ReplaceWithValue(node, node, effect, control);
+ node->ReplaceInput(0, vtrue0);
+ node->ReplaceInput(1, vtrue1);
+ node->ReplaceInput(2, vtrue2);
+ node->ReplaceInput(3, vtrue3);
+ node->ReplaceInput(4, vfalse1);
+ node->ReplaceInput(5, control);
+ node->TrimInputCount(6);
+ NodeProperties::ChangeOp(node,
+ common()->Phi(MachineRepresentation::kTagged, 5));
+ return Changed(node);
}
Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
« no previous file with comments | « no previous file | test/unittests/compiler/js-typed-lowering-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698