Commit 695026d4 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Optimize typeof o === "object" checks.

Properly recognize and optimize typeof in a strict/abstract equality
comparison with the string literal "object" to a check for Null or a
check of the map for Receiver instance type and non-callable.

Drive-by-fix: Also optimize typeof o === "function" somewhat, now that
we have the new types for Callable and NonCallable.

R=jarin@chromium.org
BUG=v8:5267

Review-Url: https://codereview.chromium.org/2646763003
Cr-Commit-Position: refs/heads/master@{#42501}
parent 1c278ebe
...@@ -717,6 +717,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, ...@@ -717,6 +717,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kObjectIsCallable: case IrOpcode::kObjectIsCallable:
result = LowerObjectIsCallable(node); result = LowerObjectIsCallable(node);
break; break;
case IrOpcode::kObjectIsNonCallable:
result = LowerObjectIsNonCallable(node);
break;
case IrOpcode::kObjectIsNumber: case IrOpcode::kObjectIsNumber:
result = LowerObjectIsNumber(node); result = LowerObjectIsNumber(node);
break; break;
...@@ -1688,6 +1691,37 @@ Node* EffectControlLinearizer::LowerObjectIsCallable(Node* node) { ...@@ -1688,6 +1691,37 @@ Node* EffectControlLinearizer::LowerObjectIsCallable(Node* node) {
return done.PhiAt(0); return done.PhiAt(0);
} }
Node* EffectControlLinearizer::LowerObjectIsNonCallable(Node* node) {
Node* value = node->InputAt(0);
auto if_primitive = __ MakeDeferredLabel<2>();
auto done = __ MakeLabel<2>(MachineRepresentation::kBit);
Node* check0 = ObjectIsSmi(value);
__ GotoIf(check0, &if_primitive);
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
Node* value_instance_type =
__ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
Node* check1 = __ Uint32LessThanOrEqual(
__ Uint32Constant(FIRST_JS_RECEIVER_TYPE), value_instance_type);
__ GotoUnless(check1, &if_primitive);
Node* value_bit_field =
__ LoadField(AccessBuilder::ForMapBitField(), value_map);
Node* check2 = __ Word32Equal(
__ Int32Constant(0),
__ Word32And(value_bit_field, __ Int32Constant(1 << Map::kIsCallable)));
__ Goto(&done, check2);
__ Bind(&if_primitive);
__ Goto(&done, __ Int32Constant(0));
__ Bind(&done);
return done.PhiAt(0);
}
Node* EffectControlLinearizer::LowerObjectIsNumber(Node* node) { Node* EffectControlLinearizer::LowerObjectIsNumber(Node* node) {
Node* value = node->InputAt(0); Node* value = node->InputAt(0);
......
...@@ -80,6 +80,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer { ...@@ -80,6 +80,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerTruncateTaggedToWord32(Node* node); Node* LowerTruncateTaggedToWord32(Node* node);
Node* LowerCheckedTruncateTaggedToWord32(Node* node, Node* frame_state); Node* LowerCheckedTruncateTaggedToWord32(Node* node, Node* frame_state);
Node* LowerObjectIsCallable(Node* node); Node* LowerObjectIsCallable(Node* node);
Node* LowerObjectIsNonCallable(Node* node);
Node* LowerObjectIsNumber(Node* node); Node* LowerObjectIsNumber(Node* node);
Node* LowerObjectIsReceiver(Node* node); Node* LowerObjectIsReceiver(Node* node);
Node* LowerObjectIsSmi(Node* node); Node* LowerObjectIsSmi(Node* node);
......
...@@ -903,6 +903,13 @@ Reduction JSTypedLowering::ReduceJSEqualTypeOf(Node* node, bool invert) { ...@@ -903,6 +903,13 @@ Reduction JSTypedLowering::ReduceJSEqualTypeOf(Node* node, bool invert) {
value = graph()->NewNode(simplified()->ObjectIsCallable(), input); value = graph()->NewNode(simplified()->ObjectIsCallable(), input);
} else if (String::Equals(type, factory()->number_string())) { } else if (String::Equals(type, factory()->number_string())) {
value = graph()->NewNode(simplified()->ObjectIsNumber(), input); value = graph()->NewNode(simplified()->ObjectIsNumber(), input);
} else if (String::Equals(type, factory()->object_string())) {
value = graph()->NewNode(
common()->Select(MachineRepresentation::kTagged),
graph()->NewNode(simplified()->ObjectIsNonCallable(), input),
jsgraph()->TrueConstant(),
graph()->NewNode(simplified()->ReferenceEqual(), input,
jsgraph()->NullConstant()));
} else if (String::Equals(type, factory()->string_string())) { } else if (String::Equals(type, factory()->string_string())) {
value = graph()->NewNode(simplified()->ObjectIsString(), input); value = graph()->NewNode(simplified()->ObjectIsString(), input);
} else if (String::Equals(type, factory()->undefined_string())) { } else if (String::Equals(type, factory()->undefined_string())) {
......
...@@ -325,6 +325,7 @@ ...@@ -325,6 +325,7 @@
V(StoreElement) \ V(StoreElement) \
V(StoreTypedElement) \ V(StoreTypedElement) \
V(ObjectIsCallable) \ V(ObjectIsCallable) \
V(ObjectIsNonCallable) \
V(ObjectIsNumber) \ V(ObjectIsNumber) \
V(ObjectIsReceiver) \ V(ObjectIsReceiver) \
V(ObjectIsSmi) \ V(ObjectIsSmi) \
......
...@@ -2515,8 +2515,11 @@ class RepresentationSelector { ...@@ -2515,8 +2515,11 @@ class RepresentationSelector {
return; return;
} }
case IrOpcode::kObjectIsCallable: { case IrOpcode::kObjectIsCallable: {
// TODO(turbofan): Add Type::Callable to optimize this? VisitObjectIs(node, Type::Callable(), lowering);
VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit); return;
}
case IrOpcode::kObjectIsNonCallable: {
VisitObjectIs(node, Type::NonCallable(), lowering);
return; return;
} }
case IrOpcode::kObjectIsNumber: { case IrOpcode::kObjectIsNumber: {
......
...@@ -479,6 +479,7 @@ UnicodeEncoding UnicodeEncodingOf(const Operator* op) { ...@@ -479,6 +479,7 @@ UnicodeEncoding UnicodeEncodingOf(const Operator* op) {
V(TruncateTaggedToWord32, Operator::kNoProperties, 1, 0) \ V(TruncateTaggedToWord32, Operator::kNoProperties, 1, 0) \
V(TruncateTaggedToFloat64, Operator::kNoProperties, 1, 0) \ V(TruncateTaggedToFloat64, Operator::kNoProperties, 1, 0) \
V(ObjectIsCallable, Operator::kNoProperties, 1, 0) \ V(ObjectIsCallable, Operator::kNoProperties, 1, 0) \
V(ObjectIsNonCallable, Operator::kNoProperties, 1, 0) \
V(ObjectIsNumber, Operator::kNoProperties, 1, 0) \ V(ObjectIsNumber, Operator::kNoProperties, 1, 0) \
V(ObjectIsReceiver, Operator::kNoProperties, 1, 0) \ V(ObjectIsReceiver, Operator::kNoProperties, 1, 0) \
V(ObjectIsSmi, Operator::kNoProperties, 1, 0) \ V(ObjectIsSmi, Operator::kNoProperties, 1, 0) \
......
...@@ -410,6 +410,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final ...@@ -410,6 +410,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* ConvertTaggedHoleToUndefined(); const Operator* ConvertTaggedHoleToUndefined();
const Operator* ObjectIsCallable(); const Operator* ObjectIsCallable();
const Operator* ObjectIsNonCallable();
const Operator* ObjectIsNumber(); const Operator* ObjectIsNumber();
const Operator* ObjectIsReceiver(); const Operator* ObjectIsReceiver();
const Operator* ObjectIsSmi(); const Operator* ObjectIsSmi();
......
...@@ -284,6 +284,7 @@ class Typer::Visitor : public Reducer { ...@@ -284,6 +284,7 @@ class Typer::Visitor : public Reducer {
#undef DECLARE_METHOD #undef DECLARE_METHOD
static Type* ObjectIsCallable(Type*, Typer*); static Type* ObjectIsCallable(Type*, Typer*);
static Type* ObjectIsNonCallable(Type*, Typer*);
static Type* ObjectIsNumber(Type*, Typer*); static Type* ObjectIsNumber(Type*, Typer*);
static Type* ObjectIsReceiver(Type*, Typer*); static Type* ObjectIsReceiver(Type*, Typer*);
static Type* ObjectIsSmi(Type*, Typer*); static Type* ObjectIsSmi(Type*, Typer*);
...@@ -502,8 +503,14 @@ Type* Typer::Visitor::ToString(Type* type, Typer* t) { ...@@ -502,8 +503,14 @@ Type* Typer::Visitor::ToString(Type* type, Typer* t) {
// Type checks. // Type checks.
Type* Typer::Visitor::ObjectIsCallable(Type* type, Typer* t) { Type* Typer::Visitor::ObjectIsCallable(Type* type, Typer* t) {
if (type->Is(Type::Function())) return t->singleton_true_; if (type->Is(Type::Callable())) return t->singleton_true_;
if (type->Is(Type::Primitive())) return t->singleton_false_; if (!type->Maybe(Type::Callable())) return t->singleton_false_;
return Type::Boolean();
}
Type* Typer::Visitor::ObjectIsNonCallable(Type* type, Typer* t) {
if (type->Is(Type::NonCallable())) return t->singleton_true_;
if (!type->Maybe(Type::NonCallable())) return t->singleton_false_;
return Type::Boolean(); return Type::Boolean();
} }
...@@ -1828,6 +1835,10 @@ Type* Typer::Visitor::TypeObjectIsCallable(Node* node) { ...@@ -1828,6 +1835,10 @@ Type* Typer::Visitor::TypeObjectIsCallable(Node* node) {
return TypeUnaryOp(node, ObjectIsCallable); return TypeUnaryOp(node, ObjectIsCallable);
} }
Type* Typer::Visitor::TypeObjectIsNonCallable(Node* node) {
return TypeUnaryOp(node, ObjectIsNonCallable);
}
Type* Typer::Visitor::TypeObjectIsNumber(Node* node) { Type* Typer::Visitor::TypeObjectIsNumber(Node* node) {
return TypeUnaryOp(node, ObjectIsNumber); return TypeUnaryOp(node, ObjectIsNumber);
} }
......
...@@ -926,6 +926,7 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -926,6 +926,7 @@ void Verifier::Visitor::Check(Node* node) {
break; break;
} }
case IrOpcode::kObjectIsCallable: case IrOpcode::kObjectIsCallable:
case IrOpcode::kObjectIsNonCallable:
case IrOpcode::kObjectIsNumber: case IrOpcode::kObjectIsNumber:
case IrOpcode::kObjectIsReceiver: case IrOpcode::kObjectIsReceiver:
case IrOpcode::kObjectIsSmi: case IrOpcode::kObjectIsSmi:
......
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