diff --git a/src/compiler/bytecode-graph-builder.cc b/src/compiler/bytecode-graph-builder.cc index a8d08b3312..1010152b57 100644 --- a/src/compiler/bytecode-graph-builder.cc +++ b/src/compiler/bytecode-graph-builder.cc @@ -2297,7 +2297,7 @@ void BytecodeGraphBuilder::VisitLogicalNot() { } void BytecodeGraphBuilder::VisitToBooleanLogicalNot() { - Node* value = NewNode(javascript()->ToBoolean(ToBooleanHint::kAny), + Node* value = NewNode(simplified()->ToBoolean(ToBooleanHint::kAny), environment()->LookupAccumulator()); Node* node = NewNode(simplified()->BooleanNot(), value); environment()->BindAccumulator(node); @@ -2952,14 +2952,14 @@ void BytecodeGraphBuilder::BuildJumpIfTrue() { void BytecodeGraphBuilder::BuildJumpIfToBooleanTrue() { Node* accumulator = environment()->LookupAccumulator(); Node* condition = - NewNode(javascript()->ToBoolean(ToBooleanHint::kAny), accumulator); + NewNode(simplified()->ToBoolean(ToBooleanHint::kAny), accumulator); BuildJumpIf(condition); } void BytecodeGraphBuilder::BuildJumpIfToBooleanFalse() { Node* accumulator = environment()->LookupAccumulator(); Node* condition = - NewNode(javascript()->ToBoolean(ToBooleanHint::kAny), accumulator); + NewNode(simplified()->ToBoolean(ToBooleanHint::kAny), accumulator); BuildJumpIfNot(condition); } diff --git a/src/compiler/effect-control-linearizer.cc b/src/compiler/effect-control-linearizer.cc index 5cf3f29122..bc0c1746b0 100644 --- a/src/compiler/effect-control-linearizer.cc +++ b/src/compiler/effect-control-linearizer.cc @@ -828,6 +828,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, case IrOpcode::kArgumentsLength: result = LowerArgumentsLength(node); break; + case IrOpcode::kToBoolean: + result = LowerToBoolean(node); + break; case IrOpcode::kTypeOf: result = LowerTypeOf(node); break; @@ -2271,6 +2274,18 @@ Node* EffectControlLinearizer::LowerTypeOf(Node* node) { __ NoContextConstant()); } +Node* EffectControlLinearizer::LowerToBoolean(Node* node) { + Node* obj = node->InputAt(0); + Callable const callable = + Builtins::CallableFor(isolate(), Builtins::kToBoolean); + 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()); diff --git a/src/compiler/effect-control-linearizer.h b/src/compiler/effect-control-linearizer.h index 42bb59ae9d..377b9e9211 100644 --- a/src/compiler/effect-control-linearizer.h +++ b/src/compiler/effect-control-linearizer.h @@ -118,6 +118,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer { Node* LowerCheckNotTaggedHole(Node* node, Node* frame_state); Node* LowerConvertTaggedHoleToUndefined(Node* node); Node* LowerTypeOf(Node* node); + Node* LowerToBoolean(Node* node); Node* LowerPlainPrimitiveToNumber(Node* node); Node* LowerPlainPrimitiveToWord32(Node* node); Node* LowerPlainPrimitiveToFloat64(Node* node); diff --git a/src/compiler/js-call-reducer.cc b/src/compiler/js-call-reducer.cc index d831e3cb52..719255e4cf 100644 --- a/src/compiler/js-call-reducer.cc +++ b/src/compiler/js-call-reducer.cc @@ -57,7 +57,7 @@ bool CanBePrimitive(Node* node) { bool CanBeNullOrUndefined(Node* node) { if (CanBePrimitive(node)) { switch (node->opcode()) { - case IrOpcode::kJSToBoolean: + case IrOpcode::kToBoolean: case IrOpcode::kJSToInteger: case IrOpcode::kJSToLength: case IrOpcode::kJSToName: @@ -137,13 +137,11 @@ Reduction JSCallReducer::ReduceBooleanConstructor(Node* node) { DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); CallParameters const& p = CallParametersOf(node->op()); - // Replace the {node} with a proper {JSToBoolean} operator. + // Replace the {node} with a proper {ToBoolean} operator. DCHECK_LE(2u, p.arity()); Node* value = (p.arity() == 2) ? jsgraph()->UndefinedConstant() : NodeProperties::GetValueInput(node, 2); - Node* context = NodeProperties::GetContextInput(node); - value = graph()->NewNode(javascript()->ToBoolean(ToBooleanHint::kAny), value, - context); + value = graph()->NewNode(simplified()->ToBoolean(ToBooleanHint::kAny), value); ReplaceWithValue(node, value); return Replace(value); } @@ -1321,8 +1319,8 @@ Reduction JSCallReducer::ReduceArrayFilter(Handle function, // We have to coerce callback_value to boolean, and only store the element in // a if it's true. The checkpoint above protects against the case that // growing {a} fails. - to = DoFilterPostCallbackWork(kind, context, &control, &effect, a, to, - element, callback_value); + to = DoFilterPostCallbackWork(kind, &control, &effect, a, to, element, + callback_value); k = next_k; loop->ReplaceInput(1, control); @@ -1345,12 +1343,12 @@ Reduction JSCallReducer::ReduceArrayFilter(Handle function, return Replace(a); } -Node* JSCallReducer::DoFilterPostCallbackWork(ElementsKind kind, Node* context, - Node** control, Node** effect, - Node* a, Node* to, Node* element, +Node* JSCallReducer::DoFilterPostCallbackWork(ElementsKind kind, Node** control, + Node** effect, Node* a, Node* to, + Node* element, Node* callback_value) { Node* boolean_result = graph()->NewNode( - javascript()->ToBoolean(ToBooleanHint::kAny), callback_value, context); + simplified()->ToBoolean(ToBooleanHint::kAny), callback_value); Node* check_boolean_result = graph()->NewNode(simplified()->ReferenceEqual(), boolean_result, diff --git a/src/compiler/js-call-reducer.h b/src/compiler/js-call-reducer.h index 10f38f8393..500efc84c5 100644 --- a/src/compiler/js-call-reducer.h +++ b/src/compiler/js-call-reducer.h @@ -89,9 +89,9 @@ class JSCallReducer final : public AdvancedReducer { // Returns the updated {to} node, and updates control and effect along the // way. - Node* DoFilterPostCallbackWork(ElementsKind kind, Node* context, - Node** control, Node** effect, Node* a, - Node* to, Node* element, Node* callback_value); + Node* DoFilterPostCallbackWork(ElementsKind kind, Node** control, + Node** effect, Node* a, Node* to, + Node* element, Node* callback_value); // If {fncallback} is not callable, throw a TypeError. // {control} is altered, and new nodes {check_fail} and {check_throw} are diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc index d476b96354..3b6574ff3a 100644 --- a/src/compiler/js-generic-lowering.cc +++ b/src/compiler/js-generic-lowering.cc @@ -126,15 +126,6 @@ void JSGenericLowering::LowerJSStrictEqual(Node* node) { Operator::kEliminatable); } -void JSGenericLowering::LowerJSToBoolean(Node* node) { - // The ToBoolean conversion doesn't need the current context. - NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant()); - Callable callable = Builtins::CallableFor(isolate(), Builtins::kToBoolean); - node->AppendInput(zone(), graph()->start()); - ReplaceWithStubCall(node, callable, CallDescriptor::kNoAllocate, - Operator::kEliminatable); -} - void JSGenericLowering::LowerJSClassOf(Node* node) { // The %_ClassOf intrinsic doesn't need the current context. NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant()); diff --git a/src/compiler/js-generic-lowering.h b/src/compiler/js-generic-lowering.h index 1a8102da59..8cd89fcb26 100644 --- a/src/compiler/js-generic-lowering.h +++ b/src/compiler/js-generic-lowering.h @@ -1,7 +1,6 @@ // Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - #ifndef V8_COMPILER_JS_GENERIC_LOWERING_H_ #define V8_COMPILER_JS_GENERIC_LOWERING_H_ diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc index 84c52f0b8f..3af69f04c3 100644 --- a/src/compiler/js-native-context-specialization.cc +++ b/src/compiler/js-native-context-specialization.cc @@ -252,8 +252,8 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) { ConvertReceiverMode::kNotNullOrUndefined)); // Rewire the value uses of {node} to ToBoolean conversion of the result. - Node* value = graph()->NewNode(javascript()->ToBoolean(ToBooleanHint::kAny), - node, context); + Node* value = + graph()->NewNode(simplified()->ToBoolean(ToBooleanHint::kAny), node); for (Edge edge : node->use_edges()) { if (NodeProperties::IsValueEdge(edge) && edge.from() != value) { edge.UpdateTo(value); diff --git a/src/compiler/js-operator.cc b/src/compiler/js-operator.cc index 5f163ca367..51ce93de98 100644 --- a/src/compiler/js-operator.cc +++ b/src/compiler/js-operator.cc @@ -58,11 +58,6 @@ ConvertReceiverMode ConvertReceiverModeOf(Operator const* op) { } -ToBooleanHints ToBooleanHintsOf(Operator const* op) { - DCHECK_EQ(IrOpcode::kJSToBoolean, op->opcode()); - return OpParameter(op); -} - std::ostream& operator<<(std::ostream& os, ConstructForwardVarargsParameters const& p) { return os << p.arity() << ", " << p.start_index(); @@ -757,15 +752,6 @@ const Operator* JSOperatorBuilder::StoreDataPropertyInLiteral( parameters); // parameter } -const Operator* JSOperatorBuilder::ToBoolean(ToBooleanHints hints) { - // TODO(turbofan): Cache most important versions of this operator. - return new (zone()) Operator1( //-- - IrOpcode::kJSToBoolean, Operator::kPure, // opcode - "JSToBoolean", // name - 1, 0, 0, 1, 0, 0, // inputs/outputs - hints); // parameter -} - const Operator* JSOperatorBuilder::CallForwardVarargs(size_t arity, uint32_t start_index) { CallForwardVarargsParameters parameters(arity, start_index); diff --git a/src/compiler/js-operator.h b/src/compiler/js-operator.h index 9abbff3f69..d5eecc7039 100644 --- a/src/compiler/js-operator.h +++ b/src/compiler/js-operator.h @@ -89,9 +89,6 @@ size_t hash_value(VectorSlotPair const&); ConvertReceiverMode ConvertReceiverModeOf(Operator const* op); -// The ToBooleanHints are used as parameter by JSToBoolean operators. -ToBooleanHints ToBooleanHintsOf(Operator const* op); - // Defines the flags for a JavaScript call forwarding parameters. This // is used as parameter by JSConstructForwardVarargs operators. class ConstructForwardVarargsParameters final { @@ -659,7 +656,6 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final const Operator* Divide(); const Operator* Modulus(); - const Operator* ToBoolean(ToBooleanHints hints); const Operator* ToInteger(); const Operator* ToLength(); const Operator* ToName(); diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc index 5b01b7f15b..c8d09c2204 100644 --- a/src/compiler/js-typed-lowering.cc +++ b/src/compiler/js-typed-lowering.cc @@ -855,52 +855,6 @@ Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node) { return NoChange(); } -Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { - Node* const input = node->InputAt(0); - Type* const input_type = NodeProperties::GetType(input); - if (input_type->Is(Type::Boolean())) { - // JSToBoolean(x:boolean) => x - return Replace(input); - } else if (input_type->Is(Type::OrderedNumber())) { - // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0)) - node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input, - jsgraph()->ZeroConstant())); - node->TrimInputCount(1); - NodeProperties::ChangeOp(node, simplified()->BooleanNot()); - return Changed(node); - } else if (input_type->Is(Type::Number())) { - // JSToBoolean(x:number) => NumberToBoolean(x) - node->TrimInputCount(1); - NodeProperties::ChangeOp(node, simplified()->NumberToBoolean()); - return Changed(node); - } else if (input_type->Is(Type::DetectableReceiverOrNull())) { - // JSToBoolean(x:detectable receiver \/ null) - // => BooleanNot(ReferenceEqual(x,#null)) - node->ReplaceInput(0, graph()->NewNode(simplified()->ReferenceEqual(), - input, jsgraph()->NullConstant())); - node->TrimInputCount(1); - NodeProperties::ChangeOp(node, simplified()->BooleanNot()); - return Changed(node); - } else if (input_type->Is(Type::ReceiverOrNullOrUndefined())) { - // JSToBoolean(x:receiver \/ null \/ undefined) - // => BooleanNot(ObjectIsUndetectable(x)) - node->ReplaceInput( - 0, graph()->NewNode(simplified()->ObjectIsUndetectable(), input)); - node->TrimInputCount(1); - NodeProperties::ChangeOp(node, simplified()->BooleanNot()); - return Changed(node); - } else if (input_type->Is(Type::String())) { - // JSToBoolean(x:string) => BooleanNot(ReferenceEqual(x,"")) - node->ReplaceInput(0, - graph()->NewNode(simplified()->ReferenceEqual(), input, - jsgraph()->EmptyStringConstant())); - node->TrimInputCount(1); - NodeProperties::ChangeOp(node, simplified()->BooleanNot()); - return Changed(node); - } - return NoChange(); -} - Reduction JSTypedLowering::ReduceJSToInteger(Node* node) { Node* const input = NodeProperties::GetValueInput(node, 0); Type* const input_type = NodeProperties::GetType(input); @@ -2265,8 +2219,6 @@ Reduction JSTypedLowering::Reduce(Node* node) { return ReduceJSHasInPrototypeChain(node); case IrOpcode::kJSOrdinaryHasInstance: return ReduceJSOrdinaryHasInstance(node); - case IrOpcode::kJSToBoolean: - return ReduceJSToBoolean(node); case IrOpcode::kJSToInteger: return ReduceJSToInteger(node); case IrOpcode::kJSToLength: diff --git a/src/compiler/js-typed-lowering.h b/src/compiler/js-typed-lowering.h index 8a513b8e43..dd7e5ecefd 100644 --- a/src/compiler/js-typed-lowering.h +++ b/src/compiler/js-typed-lowering.h @@ -50,7 +50,6 @@ class V8_EXPORT_PRIVATE JSTypedLowering final Reduction ReduceJSStoreModule(Node* node); Reduction ReduceJSEqual(Node* node); Reduction ReduceJSStrictEqual(Node* node); - Reduction ReduceJSToBoolean(Node* node); Reduction ReduceJSToInteger(Node* node); Reduction ReduceJSToLength(Node* node); Reduction ReduceJSToName(Node* node); diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h index 71ea18b683..84a5565205 100644 --- a/src/compiler/opcodes.h +++ b/src/compiler/opcodes.h @@ -116,7 +116,6 @@ V(JSOrdinaryHasInstance) #define JS_CONVERSION_UNOP_LIST(V) \ - V(JSToBoolean) \ V(JSToInteger) \ V(JSToLength) \ V(JSToName) \ @@ -357,6 +356,7 @@ V(TransitionAndStoreElement) \ V(TransitionAndStoreNumberElement) \ V(TransitionAndStoreNonNumberElement) \ + V(ToBoolean) \ V(ObjectIsArrayBufferView) \ V(ObjectIsCallable) \ V(ObjectIsConstructor) \ diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc index befe70b00d..d4f3f72996 100644 --- a/src/compiler/simplified-lowering.cc +++ b/src/compiler/simplified-lowering.cc @@ -1541,10 +1541,9 @@ class RepresentationSelector { //------------------------------------------------------------------ // JavaScript operators. //------------------------------------------------------------------ - case IrOpcode::kJSToBoolean: { + case IrOpcode::kToBoolean: { if (truncation.IsUsedAsBool()) { ProcessInput(node, 0, UseInfo::Bool()); - ProcessInput(node, 1, UseInfo::None()); SetOutput(node, MachineRepresentation::kBit); if (lower()) DeferReplacement(node, node->InputAt(0)); } else { diff --git a/src/compiler/simplified-operator.cc b/src/compiler/simplified-operator.cc index 4ade1cbdf8..690e25df97 100644 --- a/src/compiler/simplified-operator.cc +++ b/src/compiler/simplified-operator.cc @@ -102,6 +102,10 @@ std::ostream& operator<<(std::ostream& os, ElementAccess const& access) { return os; } +ToBooleanHints ToBooleanHintsOf(Operator const* op) { + DCHECK_EQ(IrOpcode::kToBoolean, op->opcode()); + return OpParameter(op); +} const FieldAccess& FieldAccessOf(const Operator* op) { DCHECK_NOT_NULL(op); @@ -1029,6 +1033,15 @@ const Operator* SimplifiedOperatorBuilder::TransitionElementsKind( transition); // parameter } +const Operator* SimplifiedOperatorBuilder::ToBoolean(ToBooleanHints hints) { + // TODO(turbofan): Cache most important versions of this operator. + return new (zone()) Operator1( //-- + IrOpcode::kToBoolean, Operator::kPure, // opcode + "ToBoolean", // name + 1, 0, 0, 1, 0, 0, // inputs/outputs + hints); // parameter +} + namespace { struct ArgumentsLengthParameters { diff --git a/src/compiler/simplified-operator.h b/src/compiler/simplified-operator.h index d6b5483ec0..6d98cec0d6 100644 --- a/src/compiler/simplified-operator.h +++ b/src/compiler/simplified-operator.h @@ -15,6 +15,7 @@ #include "src/handles.h" #include "src/machine-type.h" #include "src/objects.h" +#include "src/type-hints.h" #include "src/zone/zone-handle-set.h" namespace v8 { @@ -173,6 +174,9 @@ std::ostream& operator<<(std::ostream&, GrowFastElementsMode); GrowFastElementsMode GrowFastElementsModeOf(const Operator*) WARN_UNUSED_RESULT; +// The ToBooleanHints are used as parameter by ToBoolean operators. +ToBooleanHints ToBooleanHintsOf(Operator const* op); + // A descriptor for elements kind transitions. class ElementsTransition final { public: @@ -366,6 +370,8 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final const Operator* TypeOf(); + const Operator* ToBoolean(ToBooleanHints hints); + const Operator* StringEqual(); const Operator* StringLessThan(); const Operator* StringLessThanOrEqual(); diff --git a/src/compiler/typed-optimization.cc b/src/compiler/typed-optimization.cc index 54672c87ca..a46726f826 100644 --- a/src/compiler/typed-optimization.cc +++ b/src/compiler/typed-optimization.cc @@ -103,6 +103,8 @@ Reduction TypedOptimization::Reduce(Node* node) { return ReduceSelect(node); case IrOpcode::kTypeOf: return ReduceTypeOf(node); + case IrOpcode::kToBoolean: + return ReduceToBoolean(node); case IrOpcode::kSpeculativeToNumber: return ReduceSpeculativeToNumber(node); default: @@ -389,6 +391,52 @@ Reduction TypedOptimization::ReduceTypeOf(Node* node) { return NoChange(); } +Reduction TypedOptimization::ReduceToBoolean(Node* node) { + Node* const input = node->InputAt(0); + Type* const input_type = NodeProperties::GetType(input); + if (input_type->Is(Type::Boolean())) { + // ToBoolean(x:boolean) => x + return Replace(input); + } else if (input_type->Is(Type::OrderedNumber())) { + // SToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0)) + node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input, + jsgraph()->ZeroConstant())); + node->TrimInputCount(1); + NodeProperties::ChangeOp(node, simplified()->BooleanNot()); + return Changed(node); + } else if (input_type->Is(Type::Number())) { + // ToBoolean(x:number) => NumberToBoolean(x) + node->TrimInputCount(1); + NodeProperties::ChangeOp(node, simplified()->NumberToBoolean()); + return Changed(node); + } else if (input_type->Is(Type::DetectableReceiverOrNull())) { + // ToBoolean(x:detectable receiver \/ null) + // => BooleanNot(ReferenceEqual(x,#null)) + node->ReplaceInput(0, graph()->NewNode(simplified()->ReferenceEqual(), + input, jsgraph()->NullConstant())); + node->TrimInputCount(1); + NodeProperties::ChangeOp(node, simplified()->BooleanNot()); + return Changed(node); + } else if (input_type->Is(Type::ReceiverOrNullOrUndefined())) { + // ToBoolean(x:receiver \/ null \/ undefined) + // => BooleanNot(ObjectIsUndetectable(x)) + node->ReplaceInput( + 0, graph()->NewNode(simplified()->ObjectIsUndetectable(), input)); + node->TrimInputCount(1); + NodeProperties::ChangeOp(node, simplified()->BooleanNot()); + return Changed(node); + } else if (input_type->Is(Type::String())) { + // ToBoolean(x:string) => BooleanNot(ReferenceEqual(x,"")) + node->ReplaceInput(0, + graph()->NewNode(simplified()->ReferenceEqual(), input, + jsgraph()->EmptyStringConstant())); + node->TrimInputCount(1); + NodeProperties::ChangeOp(node, simplified()->BooleanNot()); + return Changed(node); + } + return NoChange(); +} + Factory* TypedOptimization::factory() const { return isolate()->factory(); } Graph* TypedOptimization::graph() const { return jsgraph()->graph(); } diff --git a/src/compiler/typed-optimization.h b/src/compiler/typed-optimization.h index 1f4de64aa5..ec3b9f6e55 100644 --- a/src/compiler/typed-optimization.h +++ b/src/compiler/typed-optimization.h @@ -51,6 +51,7 @@ class V8_EXPORT_PRIVATE TypedOptimization final Reduction ReduceSpeculativeToNumber(Node* node); Reduction ReduceCheckNotTaggedHole(Node* node); Reduction ReduceTypeOf(Node* node); + Reduction ReduceToBoolean(Node* node); CompilationDependencies* dependencies() const { return dependencies_; } Factory* factory() const; diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 8d0d7564ae..e7332badbd 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -1094,8 +1094,7 @@ Type* Typer::Visitor::TypeTypeOf(Node* node) { // JS conversion operators. - -Type* Typer::Visitor::TypeJSToBoolean(Node* node) { +Type* Typer::Visitor::TypeToBoolean(Node* node) { return TypeUnaryOp(node, ToBoolean); } diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc index e18dc69331..d9e68657bb 100644 --- a/src/compiler/verifier.cc +++ b/src/compiler/verifier.cc @@ -563,7 +563,7 @@ void Verifier::Visitor::Check(Node* node) { CheckTypeIs(node, Type::Number()); break; - case IrOpcode::kJSToBoolean: + case IrOpcode::kToBoolean: // Type is Boolean. CheckTypeIs(node, Type::Boolean()); break; diff --git a/test/unittests/compiler/js-typed-lowering-unittest.cc b/test/unittests/compiler/js-typed-lowering-unittest.cc index 868c8b3052..485efd6288 100644 --- a/test/unittests/compiler/js-typed-lowering-unittest.cc +++ b/test/unittests/compiler/js-typed-lowering-unittest.cc @@ -65,77 +65,6 @@ class JSTypedLoweringTest : public TypedGraphTest { }; -// ----------------------------------------------------------------------------- -// JSToBoolean - - -TEST_F(JSTypedLoweringTest, JSToBooleanWithBoolean) { - Node* input = Parameter(Type::Boolean(), 0); - Node* context = Parameter(Type::Any(), 1); - Reduction r = Reduce(graph()->NewNode( - javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); - ASSERT_TRUE(r.Changed()); - EXPECT_EQ(input, r.replacement()); -} - - -TEST_F(JSTypedLoweringTest, JSToBooleanWithOrderedNumber) { - Node* input = Parameter(Type::OrderedNumber(), 0); - Node* context = Parameter(Type::Any(), 1); - Reduction r = Reduce(graph()->NewNode( - javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsBooleanNot(IsNumberEqual(input, IsNumberConstant(0.0)))); -} - -TEST_F(JSTypedLoweringTest, JSToBooleanWithNumber) { - Node* input = Parameter(Type::Number(), 0); - Node* context = Parameter(Type::Any(), 1); - Reduction r = Reduce(graph()->NewNode( - javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberToBoolean(input)); -} - -TEST_F(JSTypedLoweringTest, JSToBooleanWithDetectableReceiverOrNull) { - Node* input = Parameter(Type::DetectableReceiverOrNull(), 0); - Node* context = Parameter(Type::Any(), 1); - Reduction r = Reduce(graph()->NewNode( - javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsBooleanNot(IsReferenceEqual(input, IsNullConstant()))); -} - -TEST_F(JSTypedLoweringTest, JSToBooleanWithReceiverOrNullOrUndefined) { - Node* input = Parameter(Type::ReceiverOrNullOrUndefined(), 0); - Node* context = Parameter(Type::Any(), 1); - Reduction r = Reduce(graph()->NewNode( - javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsBooleanNot(IsObjectIsUndetectable(input))); -} - -TEST_F(JSTypedLoweringTest, JSToBooleanWithString) { - Node* input = Parameter(Type::String(), 0); - Node* context = Parameter(Type::Any(), 1); - Reduction r = Reduce(graph()->NewNode( - javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsBooleanNot(IsReferenceEqual( - input, IsHeapConstant(factory()->empty_string())))); -} - -TEST_F(JSTypedLoweringTest, JSToBooleanWithAny) { - Node* input = Parameter(Type::Any(), 0); - Node* context = Parameter(Type::Any(), 1); - Reduction r = Reduce(graph()->NewNode( - javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); - ASSERT_FALSE(r.Changed()); -} - // ----------------------------------------------------------------------------- // JSToName diff --git a/test/unittests/compiler/typed-optimization-unittest.cc b/test/unittests/compiler/typed-optimization-unittest.cc index b527a36c55..82b6529b18 100644 --- a/test/unittests/compiler/typed-optimization-unittest.cc +++ b/test/unittests/compiler/typed-optimization-unittest.cc @@ -62,14 +62,14 @@ const double kIntegerValues[] = {-V8_INFINITY, INT_MIN, -1000.0, -42.0, class TypedOptimizationTest : public TypedGraphTest { public: TypedOptimizationTest() - : TypedGraphTest(3), javascript_(zone()), deps_(isolate(), zone()) {} + : TypedGraphTest(3), simplified_(zone()), deps_(isolate(), zone()) {} ~TypedOptimizationTest() override {} protected: Reduction Reduce(Node* node) { MachineOperatorBuilder machine(zone()); - SimplifiedOperatorBuilder simplified(zone()); - JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified, + JSOperatorBuilder javascript(zone()); + JSGraph jsgraph(isolate(), graph(), common(), &javascript, simplified(), &machine); // TODO(titzer): mock the GraphReducer here for better unit testing. GraphReducer graph_reducer(zone(), graph()); @@ -77,10 +77,10 @@ class TypedOptimizationTest : public TypedGraphTest { return reducer.Reduce(node); } - JSOperatorBuilder* javascript() { return &javascript_; } + SimplifiedOperatorBuilder* simplified() { return &simplified_; } private: - JSOperatorBuilder javascript_; + SimplifiedOperatorBuilder simplified_; CompilationDependencies deps_; }; @@ -169,7 +169,10 @@ TEST_F(TypedOptimizationTest, ParameterWithUndefined) { } } -TEST_F(TypedOptimizationTest, JSToBooleanWithFalsish) { +// ----------------------------------------------------------------------------- +// ToBoolean + +TEST_F(TypedOptimizationTest, ToBooleanWithFalsish) { Node* input = Parameter( Type::Union( Type::MinusZero(), @@ -190,36 +193,92 @@ TEST_F(TypedOptimizationTest, JSToBooleanWithFalsish) { zone()), zone()), 0); - Node* context = Parameter(Type::Any(), 1); - Reduction r = Reduce(graph()->NewNode( - javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); + Reduction r = Reduce( + graph()->NewNode(simplified()->ToBoolean(ToBooleanHint::kAny), input)); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsFalseConstant()); } -TEST_F(TypedOptimizationTest, JSToBooleanWithTruish) { +TEST_F(TypedOptimizationTest, ToBooleanWithTruish) { Node* input = Parameter( Type::Union( Type::NewConstant(factory()->true_value(), zone()), Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()), zone()), 0); - Node* context = Parameter(Type::Any(), 1); - Reduction r = Reduce(graph()->NewNode( - javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); + Reduction r = Reduce( + graph()->NewNode(simplified()->ToBoolean(ToBooleanHint::kAny), input)); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsTrueConstant()); } -TEST_F(TypedOptimizationTest, JSToBooleanWithNonZeroPlainNumber) { +TEST_F(TypedOptimizationTest, ToBooleanWithNonZeroPlainNumber) { Node* input = Parameter(Type::Range(1, V8_INFINITY, zone()), 0); - Node* context = Parameter(Type::Any(), 1); - Reduction r = Reduce(graph()->NewNode( - javascript()->ToBoolean(ToBooleanHint::kAny), input, context)); + Reduction r = Reduce( + graph()->NewNode(simplified()->ToBoolean(ToBooleanHint::kAny), input)); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsTrueConstant()); } +TEST_F(TypedOptimizationTest, ToBooleanWithBoolean) { + Node* input = Parameter(Type::Boolean(), 0); + Reduction r = Reduce( + graph()->NewNode(simplified()->ToBoolean(ToBooleanHint::kAny), input)); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(input, r.replacement()); +} + +TEST_F(TypedOptimizationTest, ToBooleanWithOrderedNumber) { + Node* input = Parameter(Type::OrderedNumber(), 0); + Reduction r = Reduce( + graph()->NewNode(simplified()->ToBoolean(ToBooleanHint::kAny), input)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsBooleanNot(IsNumberEqual(input, IsNumberConstant(0.0)))); +} + +TEST_F(TypedOptimizationTest, ToBooleanWithNumber) { + Node* input = Parameter(Type::Number(), 0); + Reduction r = Reduce( + graph()->NewNode(simplified()->ToBoolean(ToBooleanHint::kAny), input)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberToBoolean(input)); +} + +TEST_F(TypedOptimizationTest, ToBooleanWithDetectableReceiverOrNull) { + Node* input = Parameter(Type::DetectableReceiverOrNull(), 0); + Reduction r = Reduce( + graph()->NewNode(simplified()->ToBoolean(ToBooleanHint::kAny), input)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsBooleanNot(IsReferenceEqual(input, IsNullConstant()))); +} + +TEST_F(TypedOptimizationTest, ToBooleanWithReceiverOrNullOrUndefined) { + Node* input = Parameter(Type::ReceiverOrNullOrUndefined(), 0); + Reduction r = Reduce( + graph()->NewNode(simplified()->ToBoolean(ToBooleanHint::kAny), input)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsBooleanNot(IsObjectIsUndetectable(input))); +} + +TEST_F(TypedOptimizationTest, ToBooleanWithString) { + Node* input = Parameter(Type::String(), 0); + Reduction r = Reduce( + graph()->NewNode(simplified()->ToBoolean(ToBooleanHint::kAny), input)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsBooleanNot(IsReferenceEqual( + input, IsHeapConstant(factory()->empty_string())))); +} + +TEST_F(TypedOptimizationTest, ToBooleanWithAny) { + Node* input = Parameter(Type::Any(), 0); + Reduction r = Reduce( + graph()->NewNode(simplified()->ToBoolean(ToBooleanHint::kAny), input)); + ASSERT_FALSE(r.Changed()); +} + } // namespace typed_optimization_unittest } // namespace compiler } // namespace internal diff --git a/test/unittests/compiler/typer-unittest.cc b/test/unittests/compiler/typer-unittest.cc index ca0a31c81a..0505377510 100644 --- a/test/unittests/compiler/typer-unittest.cc +++ b/test/unittests/compiler/typer-unittest.cc @@ -433,14 +433,6 @@ TEST_MONOTONICITY(ToString) TEST_MONOTONICITY(ClassOf) #undef TEST_MONOTONICITY -// JS UNOPs with ToBooleanHint -#define TEST_MONOTONICITY(name) \ - TEST_F(TyperTest, Monotonicity_##name) { \ - TestUnaryMonotonicity(javascript_.name(ToBooleanHint())); \ - } -TEST_MONOTONICITY(ToBoolean) -#undef TEST_MONOTONICITY - // JS BINOPs with CompareOperationHint #define TEST_MONOTONICITY(name) \ TEST_F(TyperTest, Monotonicity_##name) { \ @@ -498,6 +490,14 @@ TEST_MONOTONICITY(ObjectIsUndetectable) TEST_MONOTONICITY(TypeOf) #undef TEST_MONOTONICITY +// SIMPLIFIED UNOPs with ToBooleanHint +#define TEST_MONOTONICITY(name) \ + TEST_F(TyperTest, Monotonicity_##name) { \ + TestUnaryMonotonicity(simplified_.name(ToBooleanHint())); \ + } +TEST_MONOTONICITY(ToBoolean) +#undef TEST_MONOTONICITY + // SIMPLIFIED BINOPs without hint, with Number input restriction #define TEST_MONOTONICITY(name) \ TEST_F(TyperTest, Monotonicity_##name) { \