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() {
void BytecodeGraphBuilder::VisitTypeOf() {
Node* node =
NewNode(javascript()->TypeOf(), environment()->LookupAccumulator());
NewNode(simplified()->TypeOf(), environment()->LookupAccumulator());
environment()->BindAccumulator(node);
}
......
......@@ -757,6 +757,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kArgumentsLength:
result = LowerArgumentsLength(node);
break;
case IrOpcode::kTypeOf:
result = LowerTypeOf(node);
break;
case IrOpcode::kNewDoubleElements:
result = LowerNewDoubleElements(node);
break;
......@@ -2185,6 +2188,18 @@ Node* EffectControlLinearizer::LowerObjectIsUndetectable(Node* node) {
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* arguments_frame = NodeProperties::GetValueInput(node, 0);
int formal_parameter_count = FormalParameterCountOf(node->op());
......
......@@ -117,6 +117,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerCheckFloat64Hole(Node* node, Node* frame_state);
Node* LowerCheckNotTaggedHole(Node* node, Node* frame_state);
Node* LowerConvertTaggedHoleToUndefined(Node* node);
Node* LowerTypeOf(Node* node);
Node* LowerPlainPrimitiveToNumber(Node* node);
Node* LowerPlainPrimitiveToWord32(Node* node);
Node* LowerPlainPrimitiveToFloat64(Node* node);
......
......@@ -144,16 +144,6 @@ void JSGenericLowering::LowerJSClassOf(Node* node) {
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) {
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
const PropertyAccess& p = PropertyAccessOf(node->op());
......
......@@ -571,7 +571,6 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
V(CreateKeyValueArray, Operator::kEliminatable, 2, 1) \
V(HasProperty, Operator::kNoProperties, 2, 1) \
V(ClassOf, Operator::kPure, 1, 1) \
V(TypeOf, Operator::kPure, 1, 1) \
V(HasInPrototypeChain, Operator::kNoProperties, 2, 1) \
V(InstanceOf, Operator::kNoProperties, 2, 1) \
V(OrdinaryHasInstance, Operator::kNoProperties, 2, 1) \
......
......@@ -721,7 +721,6 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* StoreModule(int32_t cell_index);
const Operator* ClassOf();
const Operator* TypeOf();
const Operator* HasInPrototypeChain();
const Operator* InstanceOf();
const Operator* OrdinaryHasInstance();
......
......@@ -750,32 +750,6 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
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) {
JSBinopReduction r(this, node);
......@@ -2303,8 +2277,6 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceJSToString(node);
case IrOpcode::kJSToObject:
return ReduceJSToObject(node);
case IrOpcode::kJSTypeOf:
return ReduceJSTypeOf(node);
case IrOpcode::kJSLoadNamed:
return ReduceJSLoadNamed(node);
case IrOpcode::kJSLoadContext:
......
......@@ -71,7 +71,6 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
Reduction ReduceJSGeneratorStore(Node* node);
Reduction ReduceJSGeneratorRestoreContinuation(Node* node);
Reduction ReduceJSGeneratorRestoreRegister(Node* node);
Reduction ReduceJSTypeOf(Node* node);
Reduction ReduceNumberBinop(Node* node);
Reduction ReduceInt32Binop(Node* node);
Reduction ReduceUI32Shift(Node* node, Signedness signedness);
......
......@@ -122,9 +122,7 @@
V(JSToObject) \
V(JSToString)
#define JS_OTHER_UNOP_LIST(V) \
V(JSClassOf) \
V(JSTypeOf)
#define JS_OTHER_UNOP_LIST(V) V(JSClassOf)
#define JS_SIMPLE_UNOP_LIST(V) \
JS_CONVERSION_UNOP_LIST(V) \
......@@ -343,6 +341,7 @@
V(CheckNotTaggedHole) \
V(CompareMaps) \
V(ConvertTaggedHoleToUndefined) \
V(TypeOf) \
V(Allocate) \
V(LoadFieldByIndex) \
V(LoadField) \
......
......@@ -113,7 +113,7 @@ bool NeedsCheckHeapObject(Node* receiver) {
case IrOpcode::kJSToName:
case IrOpcode::kJSToString:
case IrOpcode::kJSToObject:
case IrOpcode::kJSTypeOf:
case IrOpcode::kTypeOf:
case IrOpcode::kJSGetSuperConstructor:
return false;
case IrOpcode::kPhi: {
......
......@@ -2346,6 +2346,10 @@ class RepresentationSelector {
}
return;
}
case IrOpcode::kTypeOf: {
return VisitUnop(node, UseInfo::AnyTagged(),
MachineRepresentation::kTaggedPointer);
}
case IrOpcode::kStringEqual:
case IrOpcode::kStringLessThan:
case IrOpcode::kStringLessThanOrEqual: {
......
......@@ -552,6 +552,7 @@ DeoptimizeReason DeoptimizeReasonOf(const Operator* op) {
V(StringIndexOf, Operator::kNoProperties, 3, 0) \
V(StringToLowerCaseIntl, Operator::kNoProperties, 1, 0) \
V(StringToUpperCaseIntl, Operator::kNoProperties, 1, 0) \
V(TypeOf, Operator::kNoProperties, 1, 1) \
V(PlainPrimitiveToNumber, Operator::kNoProperties, 1, 0) \
V(PlainPrimitiveToWord32, Operator::kNoProperties, 1, 0) \
V(PlainPrimitiveToFloat64, Operator::kNoProperties, 1, 0) \
......
......@@ -364,6 +364,8 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* ReferenceEqual();
const Operator* TypeOf();
const Operator* StringEqual();
const Operator* StringLessThan();
const Operator* StringLessThanOrEqual();
......
......@@ -101,6 +101,8 @@ Reduction TypedOptimization::Reduce(Node* node) {
return ReduceReferenceEqual(node);
case IrOpcode::kSelect:
return ReduceSelect(node);
case IrOpcode::kTypeOf:
return ReduceTypeOf(node);
case IrOpcode::kSpeculativeToNumber:
return ReduceSpeculativeToNumber(node);
default:
......@@ -361,6 +363,32 @@ Reduction TypedOptimization::ReduceSpeculativeToNumber(Node* node) {
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(); }
Graph* TypedOptimization::graph() const { return jsgraph()->graph(); }
......
......@@ -50,6 +50,7 @@ class V8_EXPORT_PRIVATE TypedOptimization final
Reduction ReduceSelect(Node* node);
Reduction ReduceSpeculativeToNumber(Node* node);
Reduction ReduceCheckNotTaggedHole(Node* node);
Reduction ReduceTypeOf(Node* node);
CompilationDependencies* dependencies() const { return dependencies_; }
Factory* factory() const;
......
......@@ -1083,7 +1083,7 @@ Type* Typer::Visitor::TypeJSClassOf(Node* node) {
return Type::InternalizedStringOrNull();
}
Type* Typer::Visitor::TypeJSTypeOf(Node* node) {
Type* Typer::Visitor::TypeTypeOf(Node* node) {
return Type::InternalizedString();
}
......
......@@ -675,7 +675,7 @@ void Verifier::Visitor::Check(Node* node) {
// Type is InternaliedString \/ Null.
CheckTypeIs(node, Type::InternalizedStringOrNull());
break;
case IrOpcode::kJSTypeOf:
case IrOpcode::kTypeOf:
// Type is InternalizedString.
CheckTypeIs(node, Type::InternalizedString());
break;
......
......@@ -46,7 +46,6 @@ const SharedOperator kSharedOperators[] = {
SHARED(ToName, Operator::kNoProperties, 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(TypeOf, Operator::kPure, 1, 0, 0, 0, 1, 0, 0),
#undef SHARED
};
......
......@@ -67,7 +67,7 @@ const PureOperator kPureOperators[] = {
PURE(TruncateTaggedToBit, Operator::kNoProperties, 1),
PURE(ObjectIsNumber, Operator::kNoProperties, 1),
PURE(ObjectIsReceiver, Operator::kNoProperties, 1),
PURE(ObjectIsSmi, Operator::kNoProperties, 1)
PURE(ObjectIsSmi, Operator::kNoProperties, 1),
#undef PURE
};
......
......@@ -431,7 +431,6 @@ TEST_MONOTONICITY(ToNumber)
TEST_MONOTONICITY(ToObject)
TEST_MONOTONICITY(ToString)
TEST_MONOTONICITY(ClassOf)
TEST_MONOTONICITY(TypeOf)
#undef TEST_MONOTONICITY
// JS UNOPs with ToBooleanHint
......@@ -496,6 +495,7 @@ TEST_MONOTONICITY(ObjectIsSmi)
TEST_MONOTONICITY(ObjectIsString)
TEST_MONOTONICITY(ObjectIsSymbol)
TEST_MONOTONICITY(ObjectIsUndetectable)
TEST_MONOTONICITY(TypeOf)
#undef TEST_MONOTONICITY
// 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