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,
case IrOpcode::kObjectIsCallable:
result = LowerObjectIsCallable(node);
break;
case IrOpcode::kObjectIsNonCallable:
result = LowerObjectIsNonCallable(node);
break;
case IrOpcode::kObjectIsNumber:
result = LowerObjectIsNumber(node);
break;
......@@ -1688,6 +1691,37 @@ Node* EffectControlLinearizer::LowerObjectIsCallable(Node* node) {
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* value = node->InputAt(0);
......
......@@ -80,6 +80,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerTruncateTaggedToWord32(Node* node);
Node* LowerCheckedTruncateTaggedToWord32(Node* node, Node* frame_state);
Node* LowerObjectIsCallable(Node* node);
Node* LowerObjectIsNonCallable(Node* node);
Node* LowerObjectIsNumber(Node* node);
Node* LowerObjectIsReceiver(Node* node);
Node* LowerObjectIsSmi(Node* node);
......
......@@ -903,6 +903,13 @@ Reduction JSTypedLowering::ReduceJSEqualTypeOf(Node* node, bool invert) {
value = graph()->NewNode(simplified()->ObjectIsCallable(), input);
} else if (String::Equals(type, factory()->number_string())) {
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())) {
value = graph()->NewNode(simplified()->ObjectIsString(), input);
} else if (String::Equals(type, factory()->undefined_string())) {
......
......@@ -325,6 +325,7 @@
V(StoreElement) \
V(StoreTypedElement) \
V(ObjectIsCallable) \
V(ObjectIsNonCallable) \
V(ObjectIsNumber) \
V(ObjectIsReceiver) \
V(ObjectIsSmi) \
......
......@@ -2515,8 +2515,11 @@ class RepresentationSelector {
return;
}
case IrOpcode::kObjectIsCallable: {
// TODO(turbofan): Add Type::Callable to optimize this?
VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
VisitObjectIs(node, Type::Callable(), lowering);
return;
}
case IrOpcode::kObjectIsNonCallable: {
VisitObjectIs(node, Type::NonCallable(), lowering);
return;
}
case IrOpcode::kObjectIsNumber: {
......
......@@ -479,6 +479,7 @@ UnicodeEncoding UnicodeEncodingOf(const Operator* op) {
V(TruncateTaggedToWord32, Operator::kNoProperties, 1, 0) \
V(TruncateTaggedToFloat64, Operator::kNoProperties, 1, 0) \
V(ObjectIsCallable, Operator::kNoProperties, 1, 0) \
V(ObjectIsNonCallable, Operator::kNoProperties, 1, 0) \
V(ObjectIsNumber, Operator::kNoProperties, 1, 0) \
V(ObjectIsReceiver, Operator::kNoProperties, 1, 0) \
V(ObjectIsSmi, Operator::kNoProperties, 1, 0) \
......
......@@ -410,6 +410,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* ConvertTaggedHoleToUndefined();
const Operator* ObjectIsCallable();
const Operator* ObjectIsNonCallable();
const Operator* ObjectIsNumber();
const Operator* ObjectIsReceiver();
const Operator* ObjectIsSmi();
......
......@@ -284,6 +284,7 @@ class Typer::Visitor : public Reducer {
#undef DECLARE_METHOD
static Type* ObjectIsCallable(Type*, Typer*);
static Type* ObjectIsNonCallable(Type*, Typer*);
static Type* ObjectIsNumber(Type*, Typer*);
static Type* ObjectIsReceiver(Type*, Typer*);
static Type* ObjectIsSmi(Type*, Typer*);
......@@ -502,8 +503,14 @@ Type* Typer::Visitor::ToString(Type* type, Typer* t) {
// Type checks.
Type* Typer::Visitor::ObjectIsCallable(Type* type, Typer* t) {
if (type->Is(Type::Function())) return t->singleton_true_;
if (type->Is(Type::Primitive())) return t->singleton_false_;
if (type->Is(Type::Callable())) return t->singleton_true_;
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();
}
......@@ -1828,6 +1835,10 @@ Type* Typer::Visitor::TypeObjectIsCallable(Node* node) {
return TypeUnaryOp(node, ObjectIsCallable);
}
Type* Typer::Visitor::TypeObjectIsNonCallable(Node* node) {
return TypeUnaryOp(node, ObjectIsNonCallable);
}
Type* Typer::Visitor::TypeObjectIsNumber(Node* node) {
return TypeUnaryOp(node, ObjectIsNumber);
}
......
......@@ -926,6 +926,7 @@ void Verifier::Visitor::Check(Node* node) {
break;
}
case IrOpcode::kObjectIsCallable:
case IrOpcode::kObjectIsNonCallable:
case IrOpcode::kObjectIsNumber:
case IrOpcode::kObjectIsReceiver:
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