Commit 9b2a8c22 authored by Mike Stanton's avatar Mike Stanton Committed by Commit Bot

[TurboFan] Model TypeOf as a simplified operator

Because the typeof operator may lower to a builtin call (which is
effectful in turbofan parlance after effect control linearization),
it really should be encoded as a simplified operator, which can
be optimized with respect for the effect chain in linearization.

No new functionality here, rather a furniture rearrangement in
the TurboFan node structure.

BUG=v8:6929

Change-Id: I38593e10956ebd57cecdd606c35f3f73efb1327e
Reviewed-on: https://chromium-review.googlesource.com/718745Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Michael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48613}
parent 6627b0aa
...@@ -2305,7 +2305,7 @@ void BytecodeGraphBuilder::VisitToBooleanLogicalNot() { ...@@ -2305,7 +2305,7 @@ void BytecodeGraphBuilder::VisitToBooleanLogicalNot() {
void BytecodeGraphBuilder::VisitTypeOf() { void BytecodeGraphBuilder::VisitTypeOf() {
Node* node = Node* node =
NewNode(javascript()->TypeOf(), environment()->LookupAccumulator()); NewNode(simplified()->TypeOf(), environment()->LookupAccumulator());
environment()->BindAccumulator(node); environment()->BindAccumulator(node);
} }
......
...@@ -757,6 +757,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, ...@@ -757,6 +757,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kArgumentsLength: case IrOpcode::kArgumentsLength:
result = LowerArgumentsLength(node); result = LowerArgumentsLength(node);
break; break;
case IrOpcode::kTypeOf:
result = LowerTypeOf(node);
break;
case IrOpcode::kNewDoubleElements: case IrOpcode::kNewDoubleElements:
result = LowerNewDoubleElements(node); result = LowerNewDoubleElements(node);
break; break;
...@@ -2185,6 +2188,18 @@ Node* EffectControlLinearizer::LowerObjectIsUndetectable(Node* node) { ...@@ -2185,6 +2188,18 @@ Node* EffectControlLinearizer::LowerObjectIsUndetectable(Node* node) {
return done.PhiAt(0); return done.PhiAt(0);
} }
Node* EffectControlLinearizer::LowerTypeOf(Node* node) {
Node* obj = node->InputAt(0);
Callable const callable = Builtins::CallableFor(isolate(), Builtins::kTypeof);
// TODO(mvstanton): is it okay to ignore the properties from the operator?
Operator::Properties const properties = Operator::kEliminatable;
CallDescriptor::Flags const flags = CallDescriptor::kNoAllocate;
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
return __ Call(desc, __ HeapConstant(callable.code()), obj,
__ NoContextConstant());
}
Node* EffectControlLinearizer::LowerArgumentsLength(Node* node) { Node* EffectControlLinearizer::LowerArgumentsLength(Node* node) {
Node* arguments_frame = NodeProperties::GetValueInput(node, 0); Node* arguments_frame = NodeProperties::GetValueInput(node, 0);
int formal_parameter_count = FormalParameterCountOf(node->op()); int formal_parameter_count = FormalParameterCountOf(node->op());
......
...@@ -117,6 +117,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer { ...@@ -117,6 +117,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerCheckFloat64Hole(Node* node, Node* frame_state); Node* LowerCheckFloat64Hole(Node* node, Node* frame_state);
Node* LowerCheckNotTaggedHole(Node* node, Node* frame_state); Node* LowerCheckNotTaggedHole(Node* node, Node* frame_state);
Node* LowerConvertTaggedHoleToUndefined(Node* node); Node* LowerConvertTaggedHoleToUndefined(Node* node);
Node* LowerTypeOf(Node* node);
Node* LowerPlainPrimitiveToNumber(Node* node); Node* LowerPlainPrimitiveToNumber(Node* node);
Node* LowerPlainPrimitiveToWord32(Node* node); Node* LowerPlainPrimitiveToWord32(Node* node);
Node* LowerPlainPrimitiveToFloat64(Node* node); Node* LowerPlainPrimitiveToFloat64(Node* node);
......
...@@ -144,16 +144,6 @@ void JSGenericLowering::LowerJSClassOf(Node* node) { ...@@ -144,16 +144,6 @@ void JSGenericLowering::LowerJSClassOf(Node* node) {
Operator::kEliminatable); Operator::kEliminatable);
} }
void JSGenericLowering::LowerJSTypeOf(Node* node) {
// The typeof operator doesn't need the current context.
NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
Callable callable = Builtins::CallableFor(isolate(), Builtins::kTypeof);
node->AppendInput(zone(), graph()->start());
ReplaceWithStubCall(node, callable, CallDescriptor::kNoAllocate,
Operator::kEliminatable);
}
void JSGenericLowering::LowerJSLoadProperty(Node* node) { void JSGenericLowering::LowerJSLoadProperty(Node* node) {
CallDescriptor::Flags flags = FrameStateFlagForCall(node); CallDescriptor::Flags flags = FrameStateFlagForCall(node);
const PropertyAccess& p = PropertyAccessOf(node->op()); const PropertyAccess& p = PropertyAccessOf(node->op());
......
...@@ -571,7 +571,6 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) { ...@@ -571,7 +571,6 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
V(CreateKeyValueArray, Operator::kEliminatable, 2, 1) \ V(CreateKeyValueArray, Operator::kEliminatable, 2, 1) \
V(HasProperty, Operator::kNoProperties, 2, 1) \ V(HasProperty, Operator::kNoProperties, 2, 1) \
V(ClassOf, Operator::kPure, 1, 1) \ V(ClassOf, Operator::kPure, 1, 1) \
V(TypeOf, Operator::kPure, 1, 1) \
V(HasInPrototypeChain, Operator::kNoProperties, 2, 1) \ V(HasInPrototypeChain, Operator::kNoProperties, 2, 1) \
V(InstanceOf, Operator::kNoProperties, 2, 1) \ V(InstanceOf, Operator::kNoProperties, 2, 1) \
V(OrdinaryHasInstance, Operator::kNoProperties, 2, 1) \ V(OrdinaryHasInstance, Operator::kNoProperties, 2, 1) \
......
...@@ -721,7 +721,6 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final ...@@ -721,7 +721,6 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* StoreModule(int32_t cell_index); const Operator* StoreModule(int32_t cell_index);
const Operator* ClassOf(); const Operator* ClassOf();
const Operator* TypeOf();
const Operator* HasInPrototypeChain(); const Operator* HasInPrototypeChain();
const Operator* InstanceOf(); const Operator* InstanceOf();
const Operator* OrdinaryHasInstance(); const Operator* OrdinaryHasInstance();
......
...@@ -750,32 +750,6 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) { ...@@ -750,32 +750,6 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
return r.ChangeToPureOperator(comparison); return r.ChangeToPureOperator(comparison);
} }
Reduction JSTypedLowering::ReduceJSTypeOf(Node* node) {
Node* const input = node->InputAt(0);
Type* type = NodeProperties::GetType(input);
Factory* const f = factory();
if (type->Is(Type::Boolean())) {
return Replace(jsgraph()->Constant(f->boolean_string()));
} else if (type->Is(Type::Number())) {
return Replace(jsgraph()->Constant(f->number_string()));
} else if (type->Is(Type::String())) {
return Replace(jsgraph()->Constant(f->string_string()));
} else if (type->Is(Type::Symbol())) {
return Replace(jsgraph()->Constant(f->symbol_string()));
} else if (type->Is(Type::OtherUndetectableOrUndefined())) {
return Replace(jsgraph()->Constant(f->undefined_string()));
} else if (type->Is(Type::NonCallableOrNull())) {
return Replace(jsgraph()->Constant(f->object_string()));
} else if (type->Is(Type::Function())) {
return Replace(jsgraph()->Constant(f->function_string()));
} else if (type->IsHeapConstant()) {
return Replace(jsgraph()->Constant(
Object::TypeOf(isolate(), type->AsHeapConstant()->Value())));
}
return NoChange();
}
Reduction JSTypedLowering::ReduceJSEqual(Node* node) { Reduction JSTypedLowering::ReduceJSEqual(Node* node) {
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
...@@ -2303,8 +2277,6 @@ Reduction JSTypedLowering::Reduce(Node* node) { ...@@ -2303,8 +2277,6 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceJSToString(node); return ReduceJSToString(node);
case IrOpcode::kJSToObject: case IrOpcode::kJSToObject:
return ReduceJSToObject(node); return ReduceJSToObject(node);
case IrOpcode::kJSTypeOf:
return ReduceJSTypeOf(node);
case IrOpcode::kJSLoadNamed: case IrOpcode::kJSLoadNamed:
return ReduceJSLoadNamed(node); return ReduceJSLoadNamed(node);
case IrOpcode::kJSLoadContext: case IrOpcode::kJSLoadContext:
......
...@@ -71,7 +71,6 @@ class V8_EXPORT_PRIVATE JSTypedLowering final ...@@ -71,7 +71,6 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
Reduction ReduceJSGeneratorStore(Node* node); Reduction ReduceJSGeneratorStore(Node* node);
Reduction ReduceJSGeneratorRestoreContinuation(Node* node); Reduction ReduceJSGeneratorRestoreContinuation(Node* node);
Reduction ReduceJSGeneratorRestoreRegister(Node* node); Reduction ReduceJSGeneratorRestoreRegister(Node* node);
Reduction ReduceJSTypeOf(Node* node);
Reduction ReduceNumberBinop(Node* node); Reduction ReduceNumberBinop(Node* node);
Reduction ReduceInt32Binop(Node* node); Reduction ReduceInt32Binop(Node* node);
Reduction ReduceUI32Shift(Node* node, Signedness signedness); Reduction ReduceUI32Shift(Node* node, Signedness signedness);
......
...@@ -122,9 +122,7 @@ ...@@ -122,9 +122,7 @@
V(JSToObject) \ V(JSToObject) \
V(JSToString) V(JSToString)
#define JS_OTHER_UNOP_LIST(V) \ #define JS_OTHER_UNOP_LIST(V) V(JSClassOf)
V(JSClassOf) \
V(JSTypeOf)
#define JS_SIMPLE_UNOP_LIST(V) \ #define JS_SIMPLE_UNOP_LIST(V) \
JS_CONVERSION_UNOP_LIST(V) \ JS_CONVERSION_UNOP_LIST(V) \
...@@ -343,6 +341,7 @@ ...@@ -343,6 +341,7 @@
V(CheckNotTaggedHole) \ V(CheckNotTaggedHole) \
V(CompareMaps) \ V(CompareMaps) \
V(ConvertTaggedHoleToUndefined) \ V(ConvertTaggedHoleToUndefined) \
V(TypeOf) \
V(Allocate) \ V(Allocate) \
V(LoadFieldByIndex) \ V(LoadFieldByIndex) \
V(LoadField) \ V(LoadField) \
......
...@@ -113,7 +113,7 @@ bool NeedsCheckHeapObject(Node* receiver) { ...@@ -113,7 +113,7 @@ bool NeedsCheckHeapObject(Node* receiver) {
case IrOpcode::kJSToName: case IrOpcode::kJSToName:
case IrOpcode::kJSToString: case IrOpcode::kJSToString:
case IrOpcode::kJSToObject: case IrOpcode::kJSToObject:
case IrOpcode::kJSTypeOf: case IrOpcode::kTypeOf:
case IrOpcode::kJSGetSuperConstructor: case IrOpcode::kJSGetSuperConstructor:
return false; return false;
case IrOpcode::kPhi: { case IrOpcode::kPhi: {
......
...@@ -2346,6 +2346,10 @@ class RepresentationSelector { ...@@ -2346,6 +2346,10 @@ class RepresentationSelector {
} }
return; return;
} }
case IrOpcode::kTypeOf: {
return VisitUnop(node, UseInfo::AnyTagged(),
MachineRepresentation::kTaggedPointer);
}
case IrOpcode::kStringEqual: case IrOpcode::kStringEqual:
case IrOpcode::kStringLessThan: case IrOpcode::kStringLessThan:
case IrOpcode::kStringLessThanOrEqual: { case IrOpcode::kStringLessThanOrEqual: {
......
...@@ -552,6 +552,7 @@ DeoptimizeReason DeoptimizeReasonOf(const Operator* op) { ...@@ -552,6 +552,7 @@ DeoptimizeReason DeoptimizeReasonOf(const Operator* op) {
V(StringIndexOf, Operator::kNoProperties, 3, 0) \ V(StringIndexOf, Operator::kNoProperties, 3, 0) \
V(StringToLowerCaseIntl, Operator::kNoProperties, 1, 0) \ V(StringToLowerCaseIntl, Operator::kNoProperties, 1, 0) \
V(StringToUpperCaseIntl, Operator::kNoProperties, 1, 0) \ V(StringToUpperCaseIntl, Operator::kNoProperties, 1, 0) \
V(TypeOf, Operator::kNoProperties, 1, 1) \
V(PlainPrimitiveToNumber, Operator::kNoProperties, 1, 0) \ V(PlainPrimitiveToNumber, Operator::kNoProperties, 1, 0) \
V(PlainPrimitiveToWord32, Operator::kNoProperties, 1, 0) \ V(PlainPrimitiveToWord32, Operator::kNoProperties, 1, 0) \
V(PlainPrimitiveToFloat64, Operator::kNoProperties, 1, 0) \ V(PlainPrimitiveToFloat64, Operator::kNoProperties, 1, 0) \
......
...@@ -364,6 +364,8 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final ...@@ -364,6 +364,8 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* ReferenceEqual(); const Operator* ReferenceEqual();
const Operator* TypeOf();
const Operator* StringEqual(); const Operator* StringEqual();
const Operator* StringLessThan(); const Operator* StringLessThan();
const Operator* StringLessThanOrEqual(); const Operator* StringLessThanOrEqual();
......
...@@ -101,6 +101,8 @@ Reduction TypedOptimization::Reduce(Node* node) { ...@@ -101,6 +101,8 @@ Reduction TypedOptimization::Reduce(Node* node) {
return ReduceReferenceEqual(node); return ReduceReferenceEqual(node);
case IrOpcode::kSelect: case IrOpcode::kSelect:
return ReduceSelect(node); return ReduceSelect(node);
case IrOpcode::kTypeOf:
return ReduceTypeOf(node);
case IrOpcode::kSpeculativeToNumber: case IrOpcode::kSpeculativeToNumber:
return ReduceSpeculativeToNumber(node); return ReduceSpeculativeToNumber(node);
default: default:
...@@ -361,6 +363,32 @@ Reduction TypedOptimization::ReduceSpeculativeToNumber(Node* node) { ...@@ -361,6 +363,32 @@ Reduction TypedOptimization::ReduceSpeculativeToNumber(Node* node) {
return NoChange(); return NoChange();
} }
Reduction TypedOptimization::ReduceTypeOf(Node* node) {
Node* const input = node->InputAt(0);
Type* const type = NodeProperties::GetType(input);
Factory* const f = factory();
if (type->Is(Type::Boolean())) {
return Replace(jsgraph()->Constant(f->boolean_string()));
} else if (type->Is(Type::Number())) {
return Replace(jsgraph()->Constant(f->number_string()));
} else if (type->Is(Type::String())) {
return Replace(jsgraph()->Constant(f->string_string()));
} else if (type->Is(Type::Symbol())) {
return Replace(jsgraph()->Constant(f->symbol_string()));
} else if (type->Is(Type::OtherUndetectableOrUndefined())) {
return Replace(jsgraph()->Constant(f->undefined_string()));
} else if (type->Is(Type::NonCallableOrNull())) {
return Replace(jsgraph()->Constant(f->object_string()));
} else if (type->Is(Type::Function())) {
return Replace(jsgraph()->Constant(f->function_string()));
} else if (type->IsHeapConstant()) {
return Replace(jsgraph()->Constant(
Object::TypeOf(isolate(), type->AsHeapConstant()->Value())));
}
return NoChange();
}
Factory* TypedOptimization::factory() const { return isolate()->factory(); } Factory* TypedOptimization::factory() const { return isolate()->factory(); }
Graph* TypedOptimization::graph() const { return jsgraph()->graph(); } Graph* TypedOptimization::graph() const { return jsgraph()->graph(); }
......
...@@ -50,6 +50,7 @@ class V8_EXPORT_PRIVATE TypedOptimization final ...@@ -50,6 +50,7 @@ class V8_EXPORT_PRIVATE TypedOptimization final
Reduction ReduceSelect(Node* node); Reduction ReduceSelect(Node* node);
Reduction ReduceSpeculativeToNumber(Node* node); Reduction ReduceSpeculativeToNumber(Node* node);
Reduction ReduceCheckNotTaggedHole(Node* node); Reduction ReduceCheckNotTaggedHole(Node* node);
Reduction ReduceTypeOf(Node* node);
CompilationDependencies* dependencies() const { return dependencies_; } CompilationDependencies* dependencies() const { return dependencies_; }
Factory* factory() const; Factory* factory() const;
......
...@@ -1083,7 +1083,7 @@ Type* Typer::Visitor::TypeJSClassOf(Node* node) { ...@@ -1083,7 +1083,7 @@ Type* Typer::Visitor::TypeJSClassOf(Node* node) {
return Type::InternalizedStringOrNull(); return Type::InternalizedStringOrNull();
} }
Type* Typer::Visitor::TypeJSTypeOf(Node* node) { Type* Typer::Visitor::TypeTypeOf(Node* node) {
return Type::InternalizedString(); return Type::InternalizedString();
} }
......
...@@ -675,7 +675,7 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -675,7 +675,7 @@ void Verifier::Visitor::Check(Node* node) {
// Type is InternaliedString \/ Null. // Type is InternaliedString \/ Null.
CheckTypeIs(node, Type::InternalizedStringOrNull()); CheckTypeIs(node, Type::InternalizedStringOrNull());
break; break;
case IrOpcode::kJSTypeOf: case IrOpcode::kTypeOf:
// Type is InternalizedString. // Type is InternalizedString.
CheckTypeIs(node, Type::InternalizedString()); CheckTypeIs(node, Type::InternalizedString());
break; break;
......
...@@ -46,7 +46,6 @@ const SharedOperator kSharedOperators[] = { ...@@ -46,7 +46,6 @@ const SharedOperator kSharedOperators[] = {
SHARED(ToName, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), SHARED(ToName, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2),
SHARED(ToObject, Operator::kFoldable, 1, 1, 1, 1, 1, 1, 2), SHARED(ToObject, Operator::kFoldable, 1, 1, 1, 1, 1, 1, 2),
SHARED(Create, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(Create, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
SHARED(TypeOf, Operator::kPure, 1, 0, 0, 0, 1, 0, 0),
#undef SHARED #undef SHARED
}; };
......
...@@ -67,7 +67,7 @@ const PureOperator kPureOperators[] = { ...@@ -67,7 +67,7 @@ const PureOperator kPureOperators[] = {
PURE(TruncateTaggedToBit, Operator::kNoProperties, 1), PURE(TruncateTaggedToBit, Operator::kNoProperties, 1),
PURE(ObjectIsNumber, Operator::kNoProperties, 1), PURE(ObjectIsNumber, Operator::kNoProperties, 1),
PURE(ObjectIsReceiver, Operator::kNoProperties, 1), PURE(ObjectIsReceiver, Operator::kNoProperties, 1),
PURE(ObjectIsSmi, Operator::kNoProperties, 1) PURE(ObjectIsSmi, Operator::kNoProperties, 1),
#undef PURE #undef PURE
}; };
......
...@@ -431,7 +431,6 @@ TEST_MONOTONICITY(ToNumber) ...@@ -431,7 +431,6 @@ TEST_MONOTONICITY(ToNumber)
TEST_MONOTONICITY(ToObject) TEST_MONOTONICITY(ToObject)
TEST_MONOTONICITY(ToString) TEST_MONOTONICITY(ToString)
TEST_MONOTONICITY(ClassOf) TEST_MONOTONICITY(ClassOf)
TEST_MONOTONICITY(TypeOf)
#undef TEST_MONOTONICITY #undef TEST_MONOTONICITY
// JS UNOPs with ToBooleanHint // JS UNOPs with ToBooleanHint
...@@ -496,6 +495,7 @@ TEST_MONOTONICITY(ObjectIsSmi) ...@@ -496,6 +495,7 @@ TEST_MONOTONICITY(ObjectIsSmi)
TEST_MONOTONICITY(ObjectIsString) TEST_MONOTONICITY(ObjectIsString)
TEST_MONOTONICITY(ObjectIsSymbol) TEST_MONOTONICITY(ObjectIsSymbol)
TEST_MONOTONICITY(ObjectIsUndetectable) TEST_MONOTONICITY(ObjectIsUndetectable)
TEST_MONOTONICITY(TypeOf)
#undef TEST_MONOTONICITY #undef TEST_MONOTONICITY
// SIMPLIFIED BINOPs without hint, with Number input restriction // SIMPLIFIED BINOPs without hint, with Number input restriction
......
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