[Turbofan] Model ClassOf as a simplified operator

JSClassOf may lower to a call to a builtin, and needs to be
modeled in a way that the effect chain can be maintained.

Bug: v8:6929
Change-Id: Ida332e6d85e2eb8b33fcad810d195ef3e897ccb0
Reviewed-on: https://chromium-review.googlesource.com/727204
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Michael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48786}
This commit is contained in:
Mike Stanton 2017-10-19 14:49:32 +02:00 committed by Commit Bot
parent 9884bc5dee
commit c877c77996
12 changed files with 28 additions and 21 deletions

View File

@ -763,6 +763,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kTypeOf:
result = LowerTypeOf(node);
break;
case IrOpcode::kClassOf:
result = LowerClassOf(node);
break;
case IrOpcode::kNewDoubleElements:
result = LowerNewDoubleElements(node);
break;
@ -2209,7 +2212,18 @@ Node* EffectControlLinearizer::LowerObjectIsUndetectable(Node* node) {
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::LowerClassOf(Node* node) {
Node* obj = node->InputAt(0);
Callable const callable =
Builtins::CallableFor(isolate(), Builtins::kClassOf);
Operator::Properties const properties = Operator::kEliminatable;
CallDescriptor::Flags const flags = CallDescriptor::kNoAllocate;
CallDescriptor* desc = Linkage::GetStubCallDescriptor(

View File

@ -121,6 +121,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
void LowerCheckEqualsInternalizedString(Node* node, Node* frame_state);
void LowerCheckEqualsSymbol(Node* node, Node* frame_state);
Node* LowerTypeOf(Node* node);
Node* LowerClassOf(Node* node);
Node* LowerToBoolean(Node* node);
Node* LowerPlainPrimitiveToNumber(Node* node);
Node* LowerPlainPrimitiveToWord32(Node* node);

View File

@ -126,15 +126,6 @@ void JSGenericLowering::LowerJSStrictEqual(Node* node) {
Operator::kEliminatable);
}
void JSGenericLowering::LowerJSClassOf(Node* node) {
// The %_ClassOf intrinsic doesn't need the current context.
NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
Callable callable = Builtins::CallableFor(isolate(), Builtins::kClassOf);
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());

View File

@ -385,8 +385,11 @@ Reduction JSIntrinsicLowering::ReduceTheHole(Node* node) {
Reduction JSIntrinsicLowering::ReduceClassOf(Node* node) {
RelaxEffectsAndControls(node);
// The ClassOf operator has a single value input and control input.
Node* control_input = NodeProperties::GetControlInput(node, 0);
node->TrimInputCount(2);
NodeProperties::ChangeOp(node, javascript()->ClassOf());
node->ReplaceInput(1, control_input);
NodeProperties::ChangeOp(node, simplified()->ClassOf());
return Changed(node);
}

View File

@ -592,7 +592,6 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
V(CreateIterResultObject, Operator::kEliminatable, 2, 1) \
V(CreateKeyValueArray, Operator::kEliminatable, 2, 1) \
V(HasProperty, Operator::kNoProperties, 2, 1) \
V(ClassOf, Operator::kPure, 1, 1) \
V(HasInPrototypeChain, Operator::kNoProperties, 2, 1) \
V(InstanceOf, Operator::kNoProperties, 2, 1) \
V(OrdinaryHasInstance, Operator::kNoProperties, 2, 1) \

View File

@ -121,11 +121,7 @@
V(JSToObject) \
V(JSToString)
#define JS_OTHER_UNOP_LIST(V) V(JSClassOf)
#define JS_SIMPLE_UNOP_LIST(V) \
JS_CONVERSION_UNOP_LIST(V) \
JS_OTHER_UNOP_LIST(V)
#define JS_SIMPLE_UNOP_LIST(V) JS_CONVERSION_UNOP_LIST(V)
#define JS_OBJECT_OP_LIST(V) \
V(JSCreate) \
@ -345,6 +341,7 @@
V(CompareMaps) \
V(ConvertTaggedHoleToUndefined) \
V(TypeOf) \
V(ClassOf) \
V(Allocate) \
V(LoadFieldByIndex) \
V(LoadField) \

View File

@ -2345,6 +2345,7 @@ class RepresentationSelector {
}
return;
}
case IrOpcode::kClassOf:
case IrOpcode::kTypeOf: {
return VisitUnop(node, UseInfo::AnyTagged(),
MachineRepresentation::kTaggedPointer);
@ -2990,7 +2991,6 @@ class RepresentationSelector {
// All JavaScript operators except JSToNumber have uniform handling.
#define OPCODE_CASE(name) case IrOpcode::k##name:
JS_SIMPLE_BINOP_LIST(OPCODE_CASE)
JS_OTHER_UNOP_LIST(OPCODE_CASE)
JS_OBJECT_OP_LIST(OPCODE_CASE)
JS_CONTEXT_OP_LIST(OPCODE_CASE)
JS_OTHER_OP_LIST(OPCODE_CASE)

View File

@ -558,6 +558,7 @@ DeoptimizeReason DeoptimizeReasonOf(const Operator* op) {
V(StringToLowerCaseIntl, Operator::kNoProperties, 1, 0) \
V(StringToUpperCaseIntl, Operator::kNoProperties, 1, 0) \
V(TypeOf, Operator::kNoProperties, 1, 1) \
V(ClassOf, Operator::kNoProperties, 1, 1) \
V(PlainPrimitiveToNumber, Operator::kNoProperties, 1, 0) \
V(PlainPrimitiveToWord32, Operator::kNoProperties, 1, 0) \
V(PlainPrimitiveToFloat64, Operator::kNoProperties, 1, 0) \

View File

@ -369,6 +369,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* ReferenceEqual();
const Operator* TypeOf();
const Operator* ClassOf();
const Operator* ToBoolean(ToBooleanHints hints);

View File

@ -1079,7 +1079,7 @@ Type* Typer::Visitor::JSModulusTyper(Type* lhs, Type* rhs, Typer* t) {
// JS unary operators.
Type* Typer::Visitor::TypeJSClassOf(Node* node) {
Type* Typer::Visitor::TypeClassOf(Node* node) {
return Type::InternalizedStringOrNull();
}

View File

@ -675,7 +675,7 @@ void Verifier::Visitor::Check(Node* node) {
// Type is Boolean.
CheckTypeIs(node, Type::Boolean());
break;
case IrOpcode::kJSClassOf:
case IrOpcode::kClassOf:
// Type is InternaliedString \/ Null.
CheckTypeIs(node, Type::InternalizedStringOrNull());
break;

View File

@ -431,7 +431,6 @@ TEST_MONOTONICITY(ToName)
TEST_MONOTONICITY(ToNumber)
TEST_MONOTONICITY(ToObject)
TEST_MONOTONICITY(ToString)
TEST_MONOTONICITY(ClassOf)
#undef TEST_MONOTONICITY
// JS BINOPs with CompareOperationHint
@ -489,6 +488,7 @@ TEST_MONOTONICITY(ObjectIsString)
TEST_MONOTONICITY(ObjectIsSymbol)
TEST_MONOTONICITY(ObjectIsUndetectable)
TEST_MONOTONICITY(TypeOf)
TEST_MONOTONICITY(ClassOf)
#undef TEST_MONOTONICITY
// SIMPLIFIED UNOPs with ToBooleanHint