diff --git a/src/ast/ast-value-factory.h b/src/ast/ast-value-factory.h index c1ed7acc57..84ad9640e7 100644 --- a/src/ast/ast-value-factory.h +++ b/src/ast/ast-value-factory.h @@ -310,6 +310,7 @@ class AstValue : public ZoneObject { F(arguments, "arguments") \ F(async, "async") \ F(await, "await") \ + F(boolean, "boolean") \ F(constructor, "constructor") \ F(default, "default") \ F(done, "done") \ @@ -330,11 +331,15 @@ class AstValue : public ZoneObject { F(native, "native") \ F(new_target, ".new.target") \ F(next, "next") \ + F(number, "number") \ + F(object, "object") \ F(proto, "__proto__") \ F(prototype, "prototype") \ F(return, "return") \ F(set_space, "set ") \ F(star_default_star, "*default*") \ + F(string, "string") \ + F(symbol, "symbol") \ F(this, "this") \ F(this_function, ".this_function") \ F(throw, "throw") \ diff --git a/src/ast/ast.cc b/src/ast/ast.cc index 5b98e31654..b039678124 100644 --- a/src/ast/ast.cc +++ b/src/ast/ast.cc @@ -905,24 +905,21 @@ void CompareOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec, } // Check for the pattern: typeof equals . -static bool MatchLiteralCompareTypeof(Expression* left, - Token::Value op, - Expression* right, - Expression** expr, - Handle* check) { +static bool MatchLiteralCompareTypeof(Expression* left, Token::Value op, + Expression* right, Expression** expr, + Literal** literal) { if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) { *expr = left->AsUnaryOperation()->expression(); - *check = Handle::cast(right->AsLiteral()->value()); + *literal = right->AsLiteral(); return true; } return false; } - bool CompareOperation::IsLiteralCompareTypeof(Expression** expr, - Handle* check) { - return MatchLiteralCompareTypeof(left_, op(), right_, expr, check) || - MatchLiteralCompareTypeof(right_, op(), left_, expr, check); + Literal** literal) { + return MatchLiteralCompareTypeof(left_, op(), right_, expr, literal) || + MatchLiteralCompareTypeof(right_, op(), left_, expr, literal); } diff --git a/src/ast/ast.h b/src/ast/ast.h index c3790b34b3..3705b2d840 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -2275,7 +2275,7 @@ class CompareOperation final : public Expression { FeedbackSlot CompareOperationFeedbackSlot() const { return feedback_slot_; } // Match special cases. - bool IsLiteralCompareTypeof(Expression** expr, Handle* check); + bool IsLiteralCompareTypeof(Expression** expr, Literal** literal); bool IsLiteralCompareUndefined(Expression** expr); bool IsLiteralCompareNull(Expression** expr); diff --git a/src/bailout-reason.h b/src/bailout-reason.h index b5e39c69f7..e8b1bcac7d 100644 --- a/src/bailout-reason.h +++ b/src/bailout-reason.h @@ -237,6 +237,8 @@ namespace internal { V(kUnexpectedStackDepth, "Unexpected operand stack depth in full-codegen") \ V(kUnexpectedStackPointer, "The stack pointer is not the expected value") \ V(kUnexpectedStringType, "Unexpected string type") \ + V(kUnexpectedTestTypeofLiteralFlag, \ + "Unexpected literal flag for TestTypeof bytecode") \ V(kUnexpectedTypeForRegExpDataFixedArrayExpected, \ "Unexpected type for RegExp data, FixedArray expected") \ V(kUnexpectedValue, "Unexpected value") \ diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index 5a73c8c8b6..0fba963ab5 100644 --- a/src/compiler/ast-graph-builder.cc +++ b/src/compiler/ast-graph-builder.cc @@ -1972,9 +1972,10 @@ void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) { // with the full codegen: We don't push both left and right values onto // the expression stack when one side is a special-case literal. Expression* sub_expr = nullptr; - Handle check; - if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { - return VisitLiteralCompareTypeof(expr, sub_expr, check); + Literal* literal; + if (expr->IsLiteralCompareTypeof(&sub_expr, &literal)) { + return VisitLiteralCompareTypeof(expr, sub_expr, + Handle::cast(literal->value())); } if (expr->IsLiteralCompareUndefined(&sub_expr)) { return VisitLiteralCompareNil(expr, sub_expr, diff --git a/src/compiler/bytecode-graph-builder.cc b/src/compiler/bytecode-graph-builder.cc index de9685e08a..66ef614b2d 100644 --- a/src/compiler/bytecode-graph-builder.cc +++ b/src/compiler/bytecode-graph-builder.cc @@ -7,6 +7,7 @@ #include "src/ast/ast.h" #include "src/ast/scopes.h" #include "src/compilation-info.h" +#include "src/compiler/access-builder.h" #include "src/compiler/compiler-source-position-table.h" #include "src/compiler/js-type-hint-lowering.h" #include "src/compiler/linkage.h" @@ -1924,6 +1925,57 @@ void BytecodeGraphBuilder::VisitTestUndefined() { environment()->BindAccumulator(result); } +void BytecodeGraphBuilder::VisitTestTypeOf() { + Node* object = environment()->LookupAccumulator(); + auto literal_flag = interpreter::TestTypeOfFlags::Decode( + bytecode_iterator().GetFlagOperand(0)); + Node* result; + switch (literal_flag) { + case interpreter::TestTypeOfFlags::LiteralFlag::kNumber: + result = NewNode(simplified()->ObjectIsNumber(), object); + break; + case interpreter::TestTypeOfFlags::LiteralFlag::kString: + result = NewNode(simplified()->ObjectIsString(), object); + break; + case interpreter::TestTypeOfFlags::LiteralFlag::kSymbol: + result = NewNode(simplified()->ObjectIsSymbol(), object); + break; + case interpreter::TestTypeOfFlags::LiteralFlag::kBoolean: + result = NewNode(common()->Select(MachineRepresentation::kTagged), + NewNode(simplified()->ReferenceEqual(), object, + jsgraph()->TrueConstant()), + jsgraph()->TrueConstant(), + NewNode(simplified()->ReferenceEqual(), object, + jsgraph()->FalseConstant())); + break; + case interpreter::TestTypeOfFlags::LiteralFlag::kUndefined: + result = graph()->NewNode( + common()->Select(MachineRepresentation::kTagged), + graph()->NewNode(simplified()->ReferenceEqual(), object, + jsgraph()->NullConstant()), + jsgraph()->FalseConstant(), + graph()->NewNode(simplified()->ObjectIsUndetectable(), object)); + break; + case interpreter::TestTypeOfFlags::LiteralFlag::kFunction: + result = + graph()->NewNode(simplified()->ObjectIsDetectableCallable(), object); + break; + case interpreter::TestTypeOfFlags::LiteralFlag::kObject: + result = graph()->NewNode( + common()->Select(MachineRepresentation::kTagged), + graph()->NewNode(simplified()->ObjectIsNonCallable(), object), + jsgraph()->TrueConstant(), + graph()->NewNode(simplified()->ReferenceEqual(), object, + jsgraph()->NullConstant())); + break; + case interpreter::TestTypeOfFlags::LiteralFlag::kOther: + UNREACHABLE(); // Should never be emitted. + result = nullptr; + break; + } + environment()->BindAccumulator(result); +} + void BytecodeGraphBuilder::BuildCastOperator(const Operator* js_op) { Node* value = NewNode(js_op, environment()->LookupAccumulator()); environment()->BindRegister(bytecode_iterator().GetRegisterOperand(0), value, diff --git a/src/crankshaft/hydrogen.cc b/src/crankshaft/hydrogen.cc index a806d8f9b6..f0caf1bd8e 100644 --- a/src/crankshaft/hydrogen.cc +++ b/src/crankshaft/hydrogen.cc @@ -11200,9 +11200,10 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { // with the full codegen: We don't push both left and right values onto // the expression stack when one side is a special-case literal. Expression* sub_expr = NULL; - Handle check; - if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { - return HandleLiteralCompareTypeof(expr, sub_expr, check); + Literal* literal; + if (expr->IsLiteralCompareTypeof(&sub_expr, &literal)) { + return HandleLiteralCompareTypeof(expr, sub_expr, + Handle::cast(literal->value())); } if (expr->IsLiteralCompareUndefined(&sub_expr)) { return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue); diff --git a/src/full-codegen/full-codegen.cc b/src/full-codegen/full-codegen.cc index 59644b58db..3573c1f2f4 100644 --- a/src/full-codegen/full-codegen.cc +++ b/src/full-codegen/full-codegen.cc @@ -1445,10 +1445,11 @@ void FullCodeGenerator::VisitRewritableExpression(RewritableExpression* expr) { bool FullCodeGenerator::TryLiteralCompare(CompareOperation* expr) { Expression* sub_expr; - Handle check; - if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { + Literal* literal; + if (expr->IsLiteralCompareTypeof(&sub_expr, &literal)) { SetExpressionPosition(expr); - EmitLiteralCompareTypeof(expr, sub_expr, check); + EmitLiteralCompareTypeof(expr, sub_expr, + Handle::cast(literal->value())); return true; } diff --git a/src/interpreter/bytecode-array-builder.cc b/src/interpreter/bytecode-array-builder.cc index c66be795e0..c8d1682354 100644 --- a/src/interpreter/bytecode-array-builder.cc +++ b/src/interpreter/bytecode-array-builder.cc @@ -364,6 +364,13 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation( return *this; } +BytecodeArrayBuilder& BytecodeArrayBuilder::CompareTypeOf( + TestTypeOfFlags::LiteralFlag literal_flag) { + DCHECK(literal_flag != TestTypeOfFlags::LiteralFlag::kOther); + OutputTestTypeOf(TestTypeOfFlags::Encode(literal_flag)); + return *this; +} + BytecodeArrayBuilder& BytecodeArrayBuilder::LoadConstantPoolEntry( size_t entry) { OutputLdaConstant(entry); diff --git a/src/interpreter/bytecode-array-builder.h b/src/interpreter/bytecode-array-builder.h index 6c09f5cdf4..36e4edaa72 100644 --- a/src/interpreter/bytecode-array-builder.h +++ b/src/interpreter/bytecode-array-builder.h @@ -9,6 +9,7 @@ #include "src/base/compiler-specific.h" #include "src/globals.h" #include "src/interpreter/bytecode-array-writer.h" +#include "src/interpreter/bytecode-flags.h" #include "src/interpreter/bytecode-register-allocator.h" #include "src/interpreter/bytecode-register.h" #include "src/interpreter/bytecodes.h" @@ -306,6 +307,8 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final // Tests. BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg, int feedback_slot = kNoFeedbackSlot); + BytecodeArrayBuilder& CompareTypeOf( + TestTypeOfFlags::LiteralFlag literal_flag); // Converts accumulator and stores result in register |out|. BytecodeArrayBuilder& ConvertAccumulatorToObject(Register out); diff --git a/src/interpreter/bytecode-flags.cc b/src/interpreter/bytecode-flags.cc index 57277c8a33..172f63ed00 100644 --- a/src/interpreter/bytecode-flags.cc +++ b/src/interpreter/bytecode-flags.cc @@ -4,6 +4,8 @@ #include "src/interpreter/bytecode-flags.h" +#include "src/ast/ast-value-factory.h" +#include "src/ast/ast.h" #include "src/builtins/builtins-constructor.h" #include "src/code-stubs.h" #include "src/objects-inl.h" @@ -48,6 +50,40 @@ uint8_t CreateClosureFlags::Encode(bool pretenure, bool is_function_scope) { return result; } +// static +TestTypeOfFlags::LiteralFlag TestTypeOfFlags::GetFlagForLiteral( + const AstStringConstants* ast_constants, Literal* literal) { + const AstRawString* raw_literal = literal->raw_value()->AsString(); + if (raw_literal == ast_constants->number_string()) { + return LiteralFlag::kNumber; + } else if (raw_literal == ast_constants->string_string()) { + return LiteralFlag::kString; + } else if (raw_literal == ast_constants->symbol_string()) { + return LiteralFlag::kSymbol; + } else if (raw_literal == ast_constants->boolean_string()) { + return LiteralFlag::kBoolean; + } else if (raw_literal == ast_constants->undefined_string()) { + return LiteralFlag::kUndefined; + } else if (raw_literal == ast_constants->function_string()) { + return LiteralFlag::kFunction; + } else if (raw_literal == ast_constants->object_string()) { + return LiteralFlag::kObject; + } else { + return LiteralFlag::kOther; + } +} + +// static +uint8_t TestTypeOfFlags::Encode(LiteralFlag literal_flag) { + return static_cast(literal_flag); +} + +// static +TestTypeOfFlags::LiteralFlag TestTypeOfFlags::Decode(uint8_t raw_flag) { + DCHECK_LE(raw_flag, static_cast(LiteralFlag::kOther)); + return static_cast(raw_flag); +} + } // namespace interpreter } // namespace internal } // namespace v8 diff --git a/src/interpreter/bytecode-flags.h b/src/interpreter/bytecode-flags.h index 6e87ce20b2..98459e7fed 100644 --- a/src/interpreter/bytecode-flags.h +++ b/src/interpreter/bytecode-flags.h @@ -9,6 +9,11 @@ namespace v8 { namespace internal { + +// Forward declarations. +class Literal; +class AstStringConstants; + namespace interpreter { class CreateArrayLiteralFlags { @@ -46,6 +51,33 @@ class CreateClosureFlags { DISALLOW_IMPLICIT_CONSTRUCTORS(CreateClosureFlags); }; +#define TYPEOF_LITERAL_LIST(V) \ + V(Number, number) \ + V(String, string) \ + V(Symbol, symbol) \ + V(Boolean, boolean) \ + V(Undefined, undefined) \ + V(Function, function) \ + V(Object, object) \ + V(Other, other) + +class TestTypeOfFlags { + public: + enum class LiteralFlag : uint8_t { +#define DECLARE_LITERAL_FLAG(name, _) k##name, + TYPEOF_LITERAL_LIST(DECLARE_LITERAL_FLAG) +#undef DECLARE_LITERAL_FLAG + }; + + static LiteralFlag GetFlagForLiteral(const AstStringConstants* ast_constants, + Literal* literal); + static uint8_t Encode(LiteralFlag literal_flag); + static LiteralFlag Decode(uint8_t raw_flag); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(TestTypeOfFlags); +}; + } // namespace interpreter } // namespace internal } // namespace v8 diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc index a4e9e1a5e8..052f29367d 100644 --- a/src/interpreter/bytecode-generator.cc +++ b/src/interpreter/bytecode-generator.cc @@ -621,6 +621,7 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info) info->scope()->num_stack_slots(), info->literal(), info->SourcePositionRecordingMode())), info_(info), + ast_string_constants_(info->isolate()->ast_string_constants()), closure_scope_(info->scope()), current_scope_(info->scope()), globals_builder_(new (zone()) GlobalDeclarationsBuilder(info->zone())), @@ -634,11 +635,7 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info) execution_result_(nullptr), generator_resume_points_(info->literal()->yield_count(), info->zone()), generator_state_(), - loop_depth_(0), - prototype_string_( - info->isolate()->ast_string_constants()->prototype_string()), - undefined_string_( - info->isolate()->ast_string_constants()->undefined_string()) { + loop_depth_(0) { DCHECK_EQ(closure_scope(), closure_scope()->GetClosureScope()); } @@ -1556,7 +1553,7 @@ void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr, // do not need to do this for every property. BytecodeLabel done; builder() - ->LoadLiteral(prototype_string()) + ->LoadLiteral(ast_string_constants()->prototype_string()) .CompareOperation(Token::Value::EQ_STRICT, key) .JumpIfFalse(&done) .CallRuntime(Runtime::kThrowStaticPrototypeError) @@ -1945,7 +1942,7 @@ void BytecodeGenerator::BuildVariableLoad(Variable* variable, FeedbackSlot slot, // The global identifier "undefined" is immutable. Everything // else could be reassigned. For performance, we do a pointer comparison // rather than checking if the raw_name is really "undefined". - if (variable->raw_name() == undefined_string()) { + if (variable->raw_name() == ast_string_constants()->undefined_string()) { builder()->LoadUndefined(); } else { builder()->LoadGlobal(variable->raw_name(), feedback_index(slot), @@ -2710,17 +2707,21 @@ void BytecodeGenerator::VisitVoid(UnaryOperation* expr) { builder()->LoadUndefined(); } -void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) { - if (expr->expression()->IsVariableProxy()) { +void BytecodeGenerator::VisitForTypeOfValue(Expression* expr) { + if (expr->IsVariableProxy()) { // Typeof does not throw a reference error on global variables, hence we // perform a non-contextual load in case the operand is a variable proxy. - VariableProxy* proxy = expr->expression()->AsVariableProxy(); + VariableProxy* proxy = expr->AsVariableProxy(); BuildVariableLoadForAccumulatorValue( proxy->var(), proxy->VariableFeedbackSlot(), proxy->hole_check_mode(), INSIDE_TYPEOF); } else { - VisitForAccumulatorValue(expr->expression()); + VisitForAccumulatorValue(expr); } +} + +void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) { + VisitForTypeOfValue(expr->expression()); builder()->TypeOf(); } @@ -2963,11 +2964,27 @@ void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) { } void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { - Register lhs = VisitForRegisterValue(expr->left()); - VisitForAccumulatorValue(expr->right()); - builder()->SetExpressionPosition(expr); - FeedbackSlot slot = expr->CompareOperationFeedbackSlot(); - builder()->CompareOperation(expr->op(), lhs, feedback_index(slot)); + // Emit a fast literal comparion for expressions of the form: + // typeof(x) === 'string'. + Expression* typeof_sub_expr; + Literal* literal; + if (expr->IsLiteralCompareTypeof(&typeof_sub_expr, &literal)) { + VisitForTypeOfValue(typeof_sub_expr); + builder()->SetExpressionPosition(expr); + TestTypeOfFlags::LiteralFlag literal_flag = + TestTypeOfFlags::GetFlagForLiteral(ast_string_constants(), literal); + if (literal_flag == TestTypeOfFlags::LiteralFlag::kOther) { + builder()->LoadFalse(); + } else { + builder()->CompareTypeOf(literal_flag); + } + } else { + Register lhs = VisitForRegisterValue(expr->left()); + VisitForAccumulatorValue(expr->right()); + builder()->SetExpressionPosition(expr); + FeedbackSlot slot = expr->CompareOperationFeedbackSlot(); + builder()->CompareOperation(expr->op(), lhs, feedback_index(slot)); + } } void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { diff --git a/src/interpreter/bytecode-generator.h b/src/interpreter/bytecode-generator.h index 26305e361a..89739f9466 100644 --- a/src/interpreter/bytecode-generator.h +++ b/src/interpreter/bytecode-generator.h @@ -14,6 +14,7 @@ namespace v8 { namespace internal { +class AstStringConstants; class CompilationInfo; namespace interpreter { @@ -71,6 +72,9 @@ class BytecodeGenerator final : public AstVisitor { void VisitNot(UnaryOperation* expr); void VisitDelete(UnaryOperation* expr); + // Visits a typeof expression for the value on which to perform the typeof. + void VisitForTypeOfValue(Expression* expr); + // Used by flow control routines to evaluate loop condition. void VisitCondition(Expression* expr); @@ -175,6 +179,9 @@ class BytecodeGenerator final : public AstVisitor { inline Zone* zone() const { return zone_; } inline DeclarationScope* closure_scope() const { return closure_scope_; } inline CompilationInfo* info() const { return info_; } + inline const AstStringConstants* ast_string_constants() const { + return ast_string_constants_; + } inline Scope* current_scope() const { return current_scope_; } inline void set_current_scope(Scope* scope) { current_scope_ = scope; } @@ -202,12 +209,10 @@ class BytecodeGenerator final : public AstVisitor { inline LanguageMode language_mode() const; int feedback_index(FeedbackSlot slot) const; - const AstRawString* prototype_string() const { return prototype_string_; } - const AstRawString* undefined_string() const { return undefined_string_; } - Zone* zone_; BytecodeArrayBuilder* builder_; CompilationInfo* info_; + const AstStringConstants* ast_string_constants_; DeclarationScope* closure_scope_; Scope* current_scope_; @@ -226,9 +231,6 @@ class BytecodeGenerator final : public AstVisitor { ZoneVector generator_resume_points_; Register generator_state_; int loop_depth_; - - const AstRawString* prototype_string_; - const AstRawString* undefined_string_; }; } // namespace interpreter diff --git a/src/interpreter/bytecodes.h b/src/interpreter/bytecodes.h index 9d666429e0..f724136564 100644 --- a/src/interpreter/bytecodes.h +++ b/src/interpreter/bytecodes.h @@ -205,11 +205,10 @@ namespace interpreter { OperandType::kIdx) \ V(TestInstanceOf, AccumulatorUse::kReadWrite, OperandType::kReg) \ V(TestIn, AccumulatorUse::kReadWrite, OperandType::kReg) \ - \ - /* TestEqual with Null or Undefined */ \ V(TestUndetectable, AccumulatorUse::kWrite, OperandType::kReg) \ V(TestNull, AccumulatorUse::kWrite, OperandType::kReg) \ V(TestUndefined, AccumulatorUse::kWrite, OperandType::kReg) \ + V(TestTypeOf, AccumulatorUse::kReadWrite, OperandType::kFlag8) \ \ /* Cast operators */ \ V(ToName, AccumulatorUse::kRead, OperandType::kRegOut) \ @@ -506,6 +505,7 @@ class V8_EXPORT_PRIVATE Bytecodes final { case Bytecode::kTestInstanceOf: case Bytecode::kTestIn: case Bytecode::kTestUndetectable: + case Bytecode::kTestTypeOf: case Bytecode::kForInContinue: case Bytecode::kTestUndefined: case Bytecode::kTestNull: diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc index 78a64ad87d..a2949d5f78 100644 --- a/src/interpreter/interpreter.cc +++ b/src/interpreter/interpreter.cc @@ -2584,6 +2584,126 @@ void Interpreter::DoTestUndefined(InterpreterAssembler* assembler) { __ Dispatch(); } +// TestTypeOf +// +// Tests if the object in the is typeof the literal represented +// by |literal_flag|. +void Interpreter::DoTestTypeOf(InterpreterAssembler* assembler) { + Node* object = __ GetAccumulator(); + Node* literal_flag = __ BytecodeOperandFlag(0); + +#define MAKE_LABEL(name, lower_case) Label if_##lower_case(assembler); + TYPEOF_LITERAL_LIST(MAKE_LABEL) +#undef MAKE_LABEL + +#define LABEL_POINTER(name, lower_case) &if_##lower_case, + Label* labels[] = {TYPEOF_LITERAL_LIST(LABEL_POINTER)}; +#undef LABEL_POINTER + +#define CASE(name, lower_case) \ + static_cast(TestTypeOfFlags::LiteralFlag::k##name), + int32_t cases[] = {TYPEOF_LITERAL_LIST(CASE)}; +#undef CASE + + Label if_true(assembler), if_false(assembler), end(assembler), + abort(assembler, Label::kDeferred); + + __ Switch(literal_flag, &abort, cases, labels, arraysize(cases)); + + __ Bind(&abort); + { + __ Comment("Abort"); + __ Abort(BailoutReason::kUnexpectedTestTypeofLiteralFlag); + __ Goto(&if_false); + } + __ Bind(&if_number); + { + __ Comment("IfNumber"); + __ GotoIfNumber(object, &if_true); + __ Goto(&if_false); + } + __ Bind(&if_string); + { + __ Comment("IfString"); + __ GotoIf(__ TaggedIsSmi(object), &if_false); + __ Branch(__ IsString(object), &if_true, &if_false); + } + __ Bind(&if_symbol); + { + __ Comment("IfSymbol"); + __ GotoIf(__ TaggedIsSmi(object), &if_false); + __ Branch(__ IsSymbol(object), &if_true, &if_false); + } + __ Bind(&if_boolean); + { + __ Comment("IfBoolean"); + __ GotoIf(__ WordEqual(object, __ BooleanConstant(true)), &if_true); + __ Branch(__ WordEqual(object, __ BooleanConstant(false)), &if_true, + &if_false); + } + __ Bind(&if_undefined); + { + __ Comment("IfUndefined"); + __ GotoIf(__ TaggedIsSmi(object), &if_false); + // Check it is not null and the map has the undetectable bit set. + __ GotoIf(__ WordEqual(object, __ NullConstant()), &if_false); + Node* map_bitfield = __ LoadMapBitField(__ LoadMap(object)); + Node* undetectable_bit = + __ Word32And(map_bitfield, __ Int32Constant(1 << Map::kIsUndetectable)); + __ Branch(__ Word32Equal(undetectable_bit, __ Int32Constant(0)), &if_false, + &if_true); + } + __ Bind(&if_function); + { + __ Comment("IfFunction"); + __ GotoIf(__ TaggedIsSmi(object), &if_false); + // Check if callable bit is set and not undetectable. + Node* map_bitfield = __ LoadMapBitField(__ LoadMap(object)); + Node* callable_undetectable = __ Word32And( + map_bitfield, + __ Int32Constant(1 << Map::kIsUndetectable | 1 << Map::kIsCallable)); + __ Branch(__ Word32Equal(callable_undetectable, + __ Int32Constant(1 << Map::kIsCallable)), + &if_true, &if_false); + } + __ Bind(&if_object); + { + __ Comment("IfObject"); + __ GotoIf(__ TaggedIsSmi(object), &if_false); + + // If the object is null then return true. + __ GotoIf(__ WordEqual(object, __ NullConstant()), &if_true); + + // Check if the object is a receiver type and is not undefined or callable. + Node* map = __ LoadMap(object); + __ GotoIfNot(__ IsJSReceiverMap(map), &if_false); + Node* map_bitfield = __ LoadMapBitField(map); + Node* callable_undetectable = __ Word32And( + map_bitfield, + __ Int32Constant(1 << Map::kIsUndetectable | 1 << Map::kIsCallable)); + __ Branch(__ Word32Equal(callable_undetectable, __ Int32Constant(0)), + &if_true, &if_false); + } + __ Bind(&if_other); + { + // Typeof doesn't return any other string value. + __ Goto(&if_false); + } + + __ Bind(&if_false); + { + __ SetAccumulator(__ BooleanConstant(false)); + __ Goto(&end); + } + __ Bind(&if_true); + { + __ SetAccumulator(__ BooleanConstant(true)); + __ Goto(&end); + } + __ Bind(&end); + __ Dispatch(); +} + // Jump // // Jump by number of bytes represented by the immediate operand |imm|. diff --git a/test/cctest/compiler/test-run-bytecode-graph-builder.cc b/test/cctest/compiler/test-run-bytecode-graph-builder.cc index 3783822563..e784ff38ee 100644 --- a/test/cctest/compiler/test-run-bytecode-graph-builder.cc +++ b/test/cctest/compiler/test-run-bytecode-graph-builder.cc @@ -827,6 +827,49 @@ TEST(BytecodeGraphBuilderTypeOf) { } } +TEST(BytecodeGraphBuilderCompareTypeOf) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Factory* factory = isolate->factory(); + + ExpectedSnippet<1> snippets[] = { + {"return typeof p1 === 'number';", + {factory->true_value(), factory->NewNumber(1.1)}}, + {"return typeof p1 === 'string';", + {factory->false_value(), factory->NewNumber(1.1)}}, + {"return typeof p1 === 'string';", + {factory->true_value(), factory->NewStringFromStaticChars("string")}}, + {"return typeof p1 === 'string';", + {factory->false_value(), factory->undefined_value()}}, + {"return typeof p1 === 'undefined';", + {factory->true_value(), factory->undefined_value()}}, + {"return typeof p1 === 'object';", + {factory->true_value(), factory->null_value()}}, + {"return typeof p1 === 'object';", + {factory->true_value(), BytecodeGraphTester::NewObject("({val : 10})")}}, + {"return typeof p1 === 'function';", + {factory->false_value(), + BytecodeGraphTester::NewObject("({val : 10})")}}, + {"return typeof p1 === 'symbol';", + {factory->true_value(), factory->NewSymbol()}}, + {"return typeof p1 === 'symbol';", + {factory->false_value(), factory->NewStringFromStaticChars("string")}}, + {"return typeof p1 === 'other';", + {factory->false_value(), factory->NewNumber(1.1)}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector script(1024); + SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, script.start()); + auto callable = tester.GetCallable>(); + Handle return_value = + callable(snippets[i].parameter(0)).ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} TEST(BytecodeGraphBuilderCountOperation) { HandleAndZoneScope scope; diff --git a/test/cctest/interpreter/bytecode_expectations/CompareTypeOf.golden b/test/cctest/interpreter/bytecode_expectations/CompareTypeOf.golden new file mode 100644 index 0000000000..55d8bb073f --- /dev/null +++ b/test/cctest/interpreter/bytecode_expectations/CompareTypeOf.golden @@ -0,0 +1,97 @@ +# +# Autogenerated by generate-bytecode-expectations. +# + +--- +wrap: yes + +--- +snippet: " + return typeof(1) === 'number'; +" +frame size: 0 +parameter count: 1 +bytecode array length: 6 +bytecodes: [ + /* 30 E> */ B(StackCheck), + /* 34 S> */ B(LdaSmi), I8(1), + /* 51 E> */ B(TestTypeOf), U8(0), + /* 65 S> */ B(Return), +] +constant pool: [ +] +handlers: [ +] + +--- +snippet: " + return 'string' === typeof('foo'); +" +frame size: 0 +parameter count: 1 +bytecode array length: 6 +bytecodes: [ + /* 30 E> */ B(StackCheck), + /* 34 S> */ B(LdaConstant), U8(0), + /* 50 E> */ B(TestTypeOf), U8(1), + /* 69 S> */ B(Return), +] +constant pool: [ + ONE_BYTE_INTERNALIZED_STRING_TYPE ["foo"], +] +handlers: [ +] + +--- +snippet: " + return typeof(true) == 'boolean'; +" +frame size: 0 +parameter count: 1 +bytecode array length: 5 +bytecodes: [ + /* 30 E> */ B(StackCheck), + /* 34 S> */ B(LdaTrue), + /* 54 E> */ B(TestTypeOf), U8(3), + /* 68 S> */ B(Return), +] +constant pool: [ +] +handlers: [ +] + +--- +snippet: " + return 'string' === typeof(undefined); +" +frame size: 0 +parameter count: 1 +bytecode array length: 5 +bytecodes: [ + /* 30 E> */ B(StackCheck), + /* 34 S> */ B(LdaUndefined), + /* 50 E> */ B(TestTypeOf), U8(1), + /* 73 S> */ B(Return), +] +constant pool: [ +] +handlers: [ +] + +--- +snippet: " + return 'unknown' === typeof(undefined); +" +frame size: 0 +parameter count: 1 +bytecode array length: 3 +bytecodes: [ + /* 30 E> */ B(StackCheck), + /* 34 S> */ B(LdaFalse), + /* 74 S> */ B(Return), +] +constant pool: [ +] +handlers: [ +] + diff --git a/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden b/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden index edf7fba211..bd071db856 100644 --- a/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden +++ b/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden @@ -16,7 +16,7 @@ snippet: " " frame size: 19 parameter count: 1 -bytecode array length: 1052 +bytecode array length: 1046 bytecodes: [ B(Ldar), R(new_target), B(JumpIfUndefined), U8(42), @@ -29,10 +29,10 @@ bytecodes: [ B(JumpIfTrue), U8(134), B(LdaSmi), I8(1), B(TestEqualStrict), R(3), U8(0), - B(JumpIfTrueConstant), U8(13), + B(JumpIfTrueConstant), U8(12), B(LdaSmi), I8(2), B(TestEqualStrict), R(3), U8(0), - B(JumpIfTrueConstant), U8(15), + B(JumpIfTrueConstant), U8(14), B(LdaSmi), I8(78), B(Star), R(5), B(CallRuntime), U16(Runtime::kAbort), R(5), U8(1), @@ -198,7 +198,7 @@ bytecodes: [ B(Star), R(12), B(LdaZero), B(TestEqualStrict), R(12), U8(20), - B(JumpIfTrueConstant), U8(17), + B(JumpIfTrueConstant), U8(16), B(LdaContextSlot), R(1), U8(7), U8(0), B(Star), R(12), B(LdaNamedProperty), R(12), U8(10), U8(21), @@ -207,22 +207,19 @@ bytecodes: [ B(Star), R(12), B(TestUndetectable), R(12), B(JumpIfFalse), U8(4), - B(JumpConstant), U8(16), + B(JumpConstant), U8(15), B(LdaContextSlot), R(1), U8(9), U8(0), B(Star), R(12), B(LdaSmi), I8(1), B(TestEqualStrict), R(12), U8(24), - B(JumpIfFalse), U8(186), + B(JumpIfFalse), U8(180), B(LdaContextSlot), R(1), U8(13), U8(0), - B(TypeOf), - B(Star), R(12), - B(LdaConstant), U8(11), - B(TestEqualStrict), R(12), U8(25), + B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), B(Wide), B(LdaSmi), I16(130), B(Star), R(12), - B(LdaConstant), U8(12), + B(LdaConstant), U8(11), B(Star), R(13), B(CallRuntime), U16(Runtime::kNewTypeError), R(12), U8(2), B(Throw), @@ -274,14 +271,14 @@ bytecodes: [ B(Star), R(6), B(LdaZero), B(Star), R(5), - B(JumpConstant), U8(19), + B(JumpConstant), U8(18), B(Ldar), R(15), B(ReThrow), B(Ldar), R(15), B(Jump), U8(20), B(Star), R(13), B(Ldar), R(closure), - B(CreateCatchContext), R(13), U8(8), U8(14), + B(CreateCatchContext), R(13), U8(8), U8(13), B(Star), R(12), B(LdaTheHole), B(SetPendingMessage), @@ -386,7 +383,7 @@ bytecodes: [ B(Jump), U8(54), B(Star), R(9), B(Ldar), R(closure), - B(CreateCatchContext), R(9), U8(8), U8(18), + B(CreateCatchContext), R(9), U8(8), U8(17), B(Star), R(8), B(LdaTheHole), B(SetPendingMessage), @@ -470,22 +467,21 @@ constant pool: [ ONE_BYTE_INTERNALIZED_STRING_TYPE [".catch"], FIXED_ARRAY_TYPE, ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"], - ONE_BYTE_INTERNALIZED_STRING_TYPE ["function"], ONE_BYTE_INTERNALIZED_STRING_TYPE [""], - Smi [569], + Smi [563], FIXED_ARRAY_TYPE, - Smi [711], - Smi [356], - Smi [382], + Smi [705], + Smi [350], + Smi [376], FIXED_ARRAY_TYPE, Smi [320], ] handlers: [ - [83, 959, 965], - [86, 905, 907], + [83, 953, 959], + [86, 899, 901], [103, 429, 435], [106, 381, 383], - [531, 658, 660], + [525, 652, 654], ] --- @@ -497,7 +493,7 @@ snippet: " " frame size: 19 parameter count: 1 -bytecode array length: 1112 +bytecode array length: 1106 bytecodes: [ B(Ldar), R(new_target), B(JumpIfUndefined), U8(42), @@ -510,10 +506,10 @@ bytecodes: [ B(JumpIfTrue), U8(134), B(LdaSmi), I8(1), B(TestEqualStrict), R(3), U8(0), - B(JumpIfTrueConstant), U8(13), + B(JumpIfTrueConstant), U8(12), B(LdaSmi), I8(2), B(TestEqualStrict), R(3), U8(0), - B(JumpIfTrueConstant), U8(15), + B(JumpIfTrueConstant), U8(14), B(LdaSmi), I8(78), B(Star), R(5), B(CallRuntime), U16(Runtime::kAbort), R(5), U8(1), @@ -686,7 +682,7 @@ bytecodes: [ B(Star), R(12), B(LdaZero), B(TestEqualStrict), R(12), U8(20), - B(JumpIfTrueConstant), U8(17), + B(JumpIfTrueConstant), U8(16), B(LdaContextSlot), R(1), U8(7), U8(0), B(Star), R(12), B(LdaNamedProperty), R(12), U8(10), U8(21), @@ -695,22 +691,19 @@ bytecodes: [ B(Star), R(12), B(TestUndetectable), R(12), B(JumpIfFalse), U8(4), - B(JumpConstant), U8(16), + B(JumpConstant), U8(15), B(LdaContextSlot), R(1), U8(9), U8(0), B(Star), R(12), B(LdaSmi), I8(1), B(TestEqualStrict), R(12), U8(24), - B(JumpIfFalse), U8(186), + B(JumpIfFalse), U8(180), B(LdaContextSlot), R(1), U8(13), U8(0), - B(TypeOf), - B(Star), R(12), - B(LdaConstant), U8(11), - B(TestEqualStrict), R(12), U8(25), + B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), B(Wide), B(LdaSmi), I16(130), B(Star), R(12), - B(LdaConstant), U8(12), + B(LdaConstant), U8(11), B(Star), R(13), B(CallRuntime), U16(Runtime::kNewTypeError), R(12), U8(2), B(Throw), @@ -762,14 +755,14 @@ bytecodes: [ B(Star), R(6), B(LdaZero), B(Star), R(5), - B(JumpConstant), U8(19), + B(JumpConstant), U8(18), B(Ldar), R(15), B(ReThrow), B(Ldar), R(15), B(Jump), U8(20), B(Star), R(13), B(Ldar), R(closure), - B(CreateCatchContext), R(13), U8(8), U8(14), + B(CreateCatchContext), R(13), U8(8), U8(13), B(Star), R(12), B(LdaTheHole), B(SetPendingMessage), @@ -885,7 +878,7 @@ bytecodes: [ B(Jump), U8(54), B(Star), R(9), B(Ldar), R(closure), - B(CreateCatchContext), R(9), U8(8), U8(18), + B(CreateCatchContext), R(9), U8(8), U8(17), B(Star), R(8), B(LdaTheHole), B(SetPendingMessage), @@ -980,22 +973,21 @@ constant pool: [ ONE_BYTE_INTERNALIZED_STRING_TYPE [".catch"], FIXED_ARRAY_TYPE, ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"], - ONE_BYTE_INTERNALIZED_STRING_TYPE ["function"], ONE_BYTE_INTERNALIZED_STRING_TYPE [""], - Smi [581], + Smi [575], FIXED_ARRAY_TYPE, - Smi [723], - Smi [356], - Smi [382], + Smi [717], + Smi [350], + Smi [376], FIXED_ARRAY_TYPE, Smi [344], ] handlers: [ - [83, 995, 1001], - [86, 941, 943], + [83, 989, 995], + [86, 935, 937], [103, 441, 447], [106, 393, 395], - [543, 670, 672], + [537, 664, 666], ] --- @@ -1010,7 +1002,7 @@ snippet: " " frame size: 19 parameter count: 1 -bytecode array length: 1089 +bytecode array length: 1083 bytecodes: [ B(Ldar), R(new_target), B(JumpIfUndefined), U8(42), @@ -1023,10 +1015,10 @@ bytecodes: [ B(JumpIfTrue), U8(134), B(LdaSmi), I8(1), B(TestEqualStrict), R(3), U8(0), - B(JumpIfTrueConstant), U8(13), + B(JumpIfTrueConstant), U8(12), B(LdaSmi), I8(2), B(TestEqualStrict), R(3), U8(0), - B(JumpIfTrueConstant), U8(15), + B(JumpIfTrueConstant), U8(14), B(LdaSmi), I8(78), B(Star), R(5), B(CallRuntime), U16(Runtime::kAbort), R(5), U8(1), @@ -1208,7 +1200,7 @@ bytecodes: [ B(Star), R(12), B(LdaZero), B(TestEqualStrict), R(12), U8(22), - B(JumpIfTrueConstant), U8(17), + B(JumpIfTrueConstant), U8(16), B(LdaContextSlot), R(1), U8(7), U8(0), B(Star), R(12), B(LdaNamedProperty), R(12), U8(10), U8(23), @@ -1217,22 +1209,19 @@ bytecodes: [ B(Star), R(12), B(TestUndetectable), R(12), B(JumpIfFalse), U8(4), - B(JumpConstant), U8(16), + B(JumpConstant), U8(15), B(LdaContextSlot), R(1), U8(9), U8(0), B(Star), R(12), B(LdaSmi), I8(1), B(TestEqualStrict), R(12), U8(26), - B(JumpIfFalse), U8(186), + B(JumpIfFalse), U8(180), B(LdaContextSlot), R(1), U8(13), U8(0), - B(TypeOf), - B(Star), R(12), - B(LdaConstant), U8(11), - B(TestEqualStrict), R(12), U8(27), + B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), B(Wide), B(LdaSmi), I16(130), B(Star), R(12), - B(LdaConstant), U8(12), + B(LdaConstant), U8(11), B(Star), R(13), B(CallRuntime), U16(Runtime::kNewTypeError), R(12), U8(2), B(Throw), @@ -1284,14 +1273,14 @@ bytecodes: [ B(Star), R(6), B(LdaZero), B(Star), R(5), - B(JumpConstant), U8(19), + B(JumpConstant), U8(18), B(Ldar), R(15), B(ReThrow), B(Ldar), R(15), B(Jump), U8(20), B(Star), R(13), B(Ldar), R(closure), - B(CreateCatchContext), R(13), U8(8), U8(14), + B(CreateCatchContext), R(13), U8(8), U8(13), B(Star), R(12), B(LdaTheHole), B(SetPendingMessage), @@ -1396,7 +1385,7 @@ bytecodes: [ B(Jump), U8(54), B(Star), R(9), B(Ldar), R(closure), - B(CreateCatchContext), R(9), U8(8), U8(18), + B(CreateCatchContext), R(9), U8(8), U8(17), B(Star), R(8), B(LdaTheHole), B(SetPendingMessage), @@ -1480,22 +1469,21 @@ constant pool: [ ONE_BYTE_INTERNALIZED_STRING_TYPE [".catch"], FIXED_ARRAY_TYPE, ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"], - ONE_BYTE_INTERNALIZED_STRING_TYPE ["function"], ONE_BYTE_INTERNALIZED_STRING_TYPE [""], - Smi [606], + Smi [600], FIXED_ARRAY_TYPE, - Smi [748], - Smi [356], - Smi [382], + Smi [742], + Smi [350], + Smi [376], FIXED_ARRAY_TYPE, Smi [320], ] handlers: [ - [83, 996, 1002], - [86, 942, 944], + [83, 990, 996], + [86, 936, 938], [103, 466, 472], [106, 418, 420], - [568, 695, 697], + [562, 689, 691], ] --- @@ -1508,7 +1496,7 @@ snippet: " " frame size: 14 parameter count: 1 -bytecode array length: 594 +bytecode array length: 588 bytecodes: [ B(Ldar), R(new_target), B(JumpIfUndefined), U8(22), @@ -1620,7 +1608,7 @@ bytecodes: [ B(Star), R(11), B(LdaZero), B(TestEqualStrict), R(11), U8(21), - B(JumpIfTrue), U8(135), + B(JumpIfTrue), U8(129), B(LdaCurrentContextSlot), U8(7), B(Star), R(11), B(LdaNamedProperty), R(11), U8(9), U8(22), @@ -1629,22 +1617,19 @@ bytecodes: [ B(Star), R(11), B(TestUndetectable), R(11), B(JumpIfFalse), U8(4), - B(Jump), U8(115), + B(Jump), U8(109), B(LdaCurrentContextSlot), U8(9), B(Star), R(11), B(LdaSmi), I8(1), B(TestEqualStrict), R(11), U8(25), - B(JumpIfFalse), U8(69), + B(JumpIfFalse), U8(63), B(LdaCurrentContextSlot), U8(11), - B(TypeOf), - B(Star), R(11), - B(LdaConstant), U8(10), - B(TestEqualStrict), R(11), U8(26), + B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), B(Wide), B(LdaSmi), I16(130), B(Star), R(11), - B(LdaConstant), U8(11), + B(LdaConstant), U8(10), B(Star), R(12), B(CallRuntime), U16(Runtime::kNewTypeError), R(11), U8(2), B(Throw), @@ -1657,7 +1642,7 @@ bytecodes: [ B(Jump), U8(20), B(Star), R(12), B(Ldar), R(closure), - B(CreateCatchContext), R(12), U8(7), U8(12), + B(CreateCatchContext), R(12), U8(7), U8(11), B(Star), R(11), B(LdaTheHole), B(SetPendingMessage), @@ -1709,7 +1694,7 @@ bytecodes: [ B(Jump), U8(54), B(Star), R(8), B(Ldar), R(closure), - B(CreateCatchContext), R(8), U8(7), U8(13), + B(CreateCatchContext), R(8), U8(7), U8(12), B(Star), R(7), B(LdaTheHole), B(SetPendingMessage), @@ -1788,16 +1773,15 @@ constant pool: [ ONE_BYTE_INTERNALIZED_STRING_TYPE [".catch"], FIXED_ARRAY_TYPE, ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"], - ONE_BYTE_INTERNALIZED_STRING_TYPE ["function"], ONE_BYTE_INTERNALIZED_STRING_TYPE [""], FIXED_ARRAY_TYPE, FIXED_ARRAY_TYPE, ] handlers: [ - [63, 507, 513], - [66, 453, 455], + [63, 501, 507], + [66, 447, 449], [81, 241, 247], [84, 193, 195], - [331, 343, 345], + [325, 337, 339], ] diff --git a/test/cctest/interpreter/bytecode_expectations/ForOf.golden b/test/cctest/interpreter/bytecode_expectations/ForOf.golden index a61dc5bf5e..c47d1c372d 100644 --- a/test/cctest/interpreter/bytecode_expectations/ForOf.golden +++ b/test/cctest/interpreter/bytecode_expectations/ForOf.golden @@ -11,7 +11,7 @@ snippet: " " frame size: 15 parameter count: 1 -bytecode array length: 270 +bytecode array length: 264 bytecodes: [ /* 30 E> */ B(StackCheck), B(LdaZero), @@ -72,25 +72,22 @@ bytecodes: [ B(Star), R(11), B(LdaZero), B(TestEqualStrict), R(4), U8(16), - B(JumpIfTrue), U8(111), + B(JumpIfTrue), U8(105), B(LdaNamedProperty), R(2), U8(7), U8(17), B(Star), R(6), B(TestUndetectable), R(6), B(JumpIfFalse), U8(4), - B(Jump), U8(99), + B(Jump), U8(93), B(LdaSmi), I8(1), B(TestEqualStrict), R(4), U8(20), - B(JumpIfFalse), U8(67), + B(JumpIfFalse), U8(61), B(Ldar), R(6), - B(TypeOf), - B(Star), R(12), - B(LdaConstant), U8(8), - B(TestEqualStrict), R(12), U8(21), + B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), B(Wide), B(LdaSmi), I16(130), B(Star), R(12), - B(LdaConstant), U8(9), + B(LdaConstant), U8(8), B(Star), R(13), B(CallRuntime), U16(Runtime::kNewTypeError), R(12), U8(2), B(Throw), @@ -101,7 +98,7 @@ bytecodes: [ B(Jump), U8(20), B(Star), R(13), B(Ldar), R(closure), - B(CreateCatchContext), R(13), U8(5), U8(10), + B(CreateCatchContext), R(13), U8(5), U8(9), B(Star), R(12), B(LdaTheHole), B(SetPendingMessage), @@ -137,14 +134,13 @@ constant pool: [ ONE_BYTE_INTERNALIZED_STRING_TYPE [".catch"], FIXED_ARRAY_TYPE, ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"], - ONE_BYTE_INTERNALIZED_STRING_TYPE ["function"], ONE_BYTE_INTERNALIZED_STRING_TYPE [""], FIXED_ARRAY_TYPE, ] handlers: [ [7, 124, 130], [10, 88, 90], - [197, 207, 209], + [191, 201, 203], ] --- @@ -154,7 +150,7 @@ snippet: " " frame size: 16 parameter count: 1 -bytecode array length: 284 +bytecode array length: 278 bytecodes: [ /* 30 E> */ B(StackCheck), /* 42 S> */ B(LdaConstant), U8(0), @@ -217,25 +213,22 @@ bytecodes: [ B(Star), R(12), B(LdaZero), B(TestEqualStrict), R(5), U8(15), - B(JumpIfTrue), U8(111), + B(JumpIfTrue), U8(105), B(LdaNamedProperty), R(3), U8(7), U8(16), B(Star), R(7), B(TestUndetectable), R(7), B(JumpIfFalse), U8(4), - B(Jump), U8(99), + B(Jump), U8(93), B(LdaSmi), I8(1), B(TestEqualStrict), R(5), U8(19), - B(JumpIfFalse), U8(67), + B(JumpIfFalse), U8(61), B(Ldar), R(7), - B(TypeOf), - B(Star), R(13), - B(LdaConstant), U8(8), - B(TestEqualStrict), R(13), U8(20), + B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), B(Wide), B(LdaSmi), I16(130), B(Star), R(13), - B(LdaConstant), U8(9), + B(LdaConstant), U8(8), B(Star), R(14), B(CallRuntime), U16(Runtime::kNewTypeError), R(13), U8(2), B(Throw), @@ -246,7 +239,7 @@ bytecodes: [ B(Jump), U8(20), B(Star), R(14), B(Ldar), R(closure), - B(CreateCatchContext), R(14), U8(5), U8(10), + B(CreateCatchContext), R(14), U8(5), U8(9), B(Star), R(13), B(LdaTheHole), B(SetPendingMessage), @@ -287,14 +280,13 @@ constant pool: [ ONE_BYTE_INTERNALIZED_STRING_TYPE [".catch"], FIXED_ARRAY_TYPE, ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"], - ONE_BYTE_INTERNALIZED_STRING_TYPE ["function"], ONE_BYTE_INTERNALIZED_STRING_TYPE [""], FIXED_ARRAY_TYPE, ] handlers: [ [11, 127, 133], [14, 91, 93], - [201, 211, 213], + [195, 205, 207], ] --- @@ -306,7 +298,7 @@ snippet: " " frame size: 15 parameter count: 1 -bytecode array length: 288 +bytecode array length: 282 bytecodes: [ /* 30 E> */ B(StackCheck), B(LdaZero), @@ -375,25 +367,22 @@ bytecodes: [ B(Star), R(11), B(LdaZero), B(TestEqualStrict), R(4), U8(18), - B(JumpIfTrue), U8(111), + B(JumpIfTrue), U8(105), B(LdaNamedProperty), R(2), U8(7), U8(19), B(Star), R(6), B(TestUndetectable), R(6), B(JumpIfFalse), U8(4), - B(Jump), U8(99), + B(Jump), U8(93), B(LdaSmi), I8(1), B(TestEqualStrict), R(4), U8(22), - B(JumpIfFalse), U8(67), + B(JumpIfFalse), U8(61), B(Ldar), R(6), - B(TypeOf), - B(Star), R(12), - B(LdaConstant), U8(8), - B(TestEqualStrict), R(12), U8(23), + B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), B(Wide), B(LdaSmi), I16(130), B(Star), R(12), - B(LdaConstant), U8(9), + B(LdaConstant), U8(8), B(Star), R(13), B(CallRuntime), U16(Runtime::kNewTypeError), R(12), U8(2), B(Throw), @@ -404,7 +393,7 @@ bytecodes: [ B(Jump), U8(20), B(Star), R(13), B(Ldar), R(closure), - B(CreateCatchContext), R(13), U8(5), U8(10), + B(CreateCatchContext), R(13), U8(5), U8(9), B(Star), R(12), B(LdaTheHole), B(SetPendingMessage), @@ -440,14 +429,13 @@ constant pool: [ ONE_BYTE_INTERNALIZED_STRING_TYPE [".catch"], FIXED_ARRAY_TYPE, ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"], - ONE_BYTE_INTERNALIZED_STRING_TYPE ["function"], ONE_BYTE_INTERNALIZED_STRING_TYPE [""], FIXED_ARRAY_TYPE, ] handlers: [ [7, 142, 148], [10, 106, 108], - [215, 225, 227], + [209, 219, 221], ] --- @@ -457,7 +445,7 @@ snippet: " " frame size: 14 parameter count: 1 -bytecode array length: 295 +bytecode array length: 289 bytecodes: [ /* 30 E> */ B(StackCheck), /* 42 S> */ B(CreateObjectLiteral), U8(0), U8(2), U8(1), R(8), @@ -523,25 +511,22 @@ bytecodes: [ B(Star), R(10), B(LdaZero), B(TestEqualStrict), R(3), U8(21), - B(JumpIfTrue), U8(111), + B(JumpIfTrue), U8(105), B(LdaNamedProperty), R(1), U8(9), U8(22), B(Star), R(5), B(TestUndetectable), R(5), B(JumpIfFalse), U8(4), - B(Jump), U8(99), + B(Jump), U8(93), B(LdaSmi), I8(1), B(TestEqualStrict), R(3), U8(25), - B(JumpIfFalse), U8(67), + B(JumpIfFalse), U8(61), B(Ldar), R(5), - B(TypeOf), - B(Star), R(11), - B(LdaConstant), U8(10), - B(TestEqualStrict), R(11), U8(26), + B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), B(Wide), B(LdaSmi), I16(130), B(Star), R(11), - B(LdaConstant), U8(11), + B(LdaConstant), U8(10), B(Star), R(12), B(CallRuntime), U16(Runtime::kNewTypeError), R(11), U8(2), B(Throw), @@ -552,7 +537,7 @@ bytecodes: [ B(Jump), U8(20), B(Star), R(12), B(Ldar), R(closure), - B(CreateCatchContext), R(12), U8(7), U8(12), + B(CreateCatchContext), R(12), U8(7), U8(11), B(Star), R(11), B(LdaTheHole), B(SetPendingMessage), @@ -595,13 +580,12 @@ constant pool: [ ONE_BYTE_INTERNALIZED_STRING_TYPE [".catch"], FIXED_ARRAY_TYPE, ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"], - ONE_BYTE_INTERNALIZED_STRING_TYPE ["function"], ONE_BYTE_INTERNALIZED_STRING_TYPE [""], FIXED_ARRAY_TYPE, ] handlers: [ [15, 138, 144], [18, 102, 104], - [212, 222, 224], + [206, 216, 218], ] diff --git a/test/cctest/interpreter/bytecode_expectations/Generators.golden b/test/cctest/interpreter/bytecode_expectations/Generators.golden index 1af5eaf500..bc992bc1fa 100644 --- a/test/cctest/interpreter/bytecode_expectations/Generators.golden +++ b/test/cctest/interpreter/bytecode_expectations/Generators.golden @@ -280,7 +280,7 @@ snippet: " " frame size: 18 parameter count: 1 -bytecode array length: 773 +bytecode array length: 767 bytecodes: [ B(Ldar), R(new_target), B(JumpIfUndefined), U8(35), @@ -337,7 +337,7 @@ bytecodes: [ B(Star), R(6), B(LdaZero), B(Star), R(5), - B(JumpConstant), U8(13), + B(JumpConstant), U8(12), B(Ldar), R(10), /* 11 E> */ B(Throw), B(Ldar), R(closure), @@ -474,7 +474,7 @@ bytecodes: [ B(Star), R(11), B(LdaZero), B(TestEqualStrict), R(11), U8(16), - B(JumpIfTrue), U8(159), + B(JumpIfTrue), U8(153), B(LdaContextSlot), R(1), U8(7), U8(0), B(Star), R(11), B(LdaNamedProperty), R(11), U8(9), U8(17), @@ -483,22 +483,19 @@ bytecodes: [ B(Star), R(11), B(TestUndetectable), R(11), B(JumpIfFalse), U8(4), - B(Jump), U8(133), + B(Jump), U8(127), B(LdaContextSlot), R(1), U8(9), U8(0), B(Star), R(11), B(LdaSmi), I8(1), B(TestEqualStrict), R(11), U8(20), - B(JumpIfFalse), U8(75), + B(JumpIfFalse), U8(69), B(LdaContextSlot), R(1), U8(11), U8(0), - B(TypeOf), - B(Star), R(11), - B(LdaConstant), U8(10), - B(TestEqualStrict), R(11), U8(21), + B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), B(Wide), B(LdaSmi), I16(130), B(Star), R(11), - B(LdaConstant), U8(11), + B(LdaConstant), U8(10), B(Star), R(12), B(CallRuntime), U16(Runtime::kNewTypeError), R(11), U8(2), B(Throw), @@ -511,7 +508,7 @@ bytecodes: [ B(Jump), U8(20), B(Star), R(12), B(Ldar), R(closure), - B(CreateCatchContext), R(12), U8(7), U8(12), + B(CreateCatchContext), R(12), U8(7), U8(11), B(Star), R(11), B(LdaTheHole), B(SetPendingMessage), @@ -618,15 +615,14 @@ constant pool: [ ONE_BYTE_INTERNALIZED_STRING_TYPE [".catch"], FIXED_ARRAY_TYPE, ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"], - ONE_BYTE_INTERNALIZED_STRING_TYPE ["function"], ONE_BYTE_INTERNALIZED_STRING_TYPE [""], FIXED_ARRAY_TYPE, - Smi [577], + Smi [571], ] handlers: [ - [53, 692, 698], + [53, 686, 692], [149, 443, 449], [152, 399, 401], - [545, 561, 563], + [539, 555, 557], ] diff --git a/test/cctest/interpreter/test-bytecode-generator.cc b/test/cctest/interpreter/test-bytecode-generator.cc index 5ee0a6fc3c..4acc5964c6 100644 --- a/test/cctest/interpreter/test-bytecode-generator.cc +++ b/test/cctest/interpreter/test-bytecode-generator.cc @@ -1007,6 +1007,26 @@ TEST(Typeof) { LoadGolden("Typeof.golden"))); } +TEST(CompareTypeOf) { + InitializedIgnitionHandleScope scope; + BytecodeExpectationsPrinter printer(CcTest::isolate()); + + const char* snippets[] = { + "return typeof(1) === 'number';\n", + + "return 'string' === typeof('foo');\n", + + "return typeof(true) == 'boolean';\n", + + "return 'string' === typeof(undefined);\n", + + "return 'unknown' === typeof(undefined);\n", + }; + + CHECK(CompareTexts(BuildActual(printer, snippets), + LoadGolden("CompareTypeOf.golden"))); +} + TEST(Delete) { InitializedIgnitionHandleScope scope; BytecodeExpectationsPrinter printer(CcTest::isolate()); diff --git a/test/cctest/interpreter/test-interpreter.cc b/test/cctest/interpreter/test-interpreter.cc index 06eb8d3c15..ed986bba4b 100644 --- a/test/cctest/interpreter/test-interpreter.cc +++ b/test/cctest/interpreter/test-interpreter.cc @@ -10,6 +10,7 @@ #include "src/handles.h" #include "src/interpreter/bytecode-array-builder.h" #include "src/interpreter/bytecode-array-iterator.h" +#include "src/interpreter/bytecode-flags.h" #include "src/interpreter/bytecode-label.h" #include "src/interpreter/interpreter.h" #include "src/objects-inl.h" @@ -2073,6 +2074,58 @@ TEST(InterpreterStrictNotEqual) { } } +TEST(InterpreterCompareTypeOf) { + typedef TestTypeOfFlags::LiteralFlag LiteralFlag; + HandleAndZoneScope handles; + Isolate* isolate = handles.main_isolate(); + Factory* factory = isolate->factory(); + Zone* zone = handles.main_zone(); + std::pair, LiteralFlag> inputs[] = { + {handle(Smi::FromInt(24), isolate), LiteralFlag::kNumber}, + {factory->NewNumber(2.5), LiteralFlag::kNumber}, + {factory->NewStringFromAsciiChecked("foo"), LiteralFlag::kString}, + {factory + ->NewConsString(factory->NewStringFromAsciiChecked("foo"), + factory->NewStringFromAsciiChecked("bar")) + .ToHandleChecked(), + LiteralFlag::kString}, + {factory->prototype_string(), LiteralFlag::kString}, + {factory->NewSymbol(), LiteralFlag::kSymbol}, + {factory->true_value(), LiteralFlag::kBoolean}, + {factory->false_value(), LiteralFlag::kBoolean}, + {factory->undefined_value(), LiteralFlag::kUndefined}, + {InterpreterTester::NewObject( + "(function() { return function() {}; })();"), + LiteralFlag::kFunction}, + {InterpreterTester::NewObject("new Object();"), LiteralFlag::kObject}, + {factory->null_value(), LiteralFlag::kObject}, + }; + const LiteralFlag kLiterals[] = { +#define LITERAL_FLAG(name, _) LiteralFlag::k##name, + TYPEOF_LITERAL_LIST(LITERAL_FLAG) +#undef LITERAL_FLAG + }; + + for (size_t l = 0; l < arraysize(kLiterals); l++) { + LiteralFlag literal_flag = kLiterals[l]; + if (literal_flag == LiteralFlag::kOther) continue; + + BytecodeArrayBuilder builder(isolate, zone, 1, 0, 0); + builder.LoadAccumulatorWithRegister(builder.Parameter(0)) + .CompareTypeOf(kLiterals[l]) + .Return(); + Handle bytecode_array = builder.ToBytecodeArray(isolate); + InterpreterTester tester(isolate, bytecode_array); + auto callable = tester.GetCallable>(); + + for (size_t i = 0; i < arraysize(inputs); i++) { + Handle return_value = callable(inputs[i].first).ToHandleChecked(); + CHECK(return_value->IsBoolean()); + CHECK_EQ(return_value->BooleanValue(), inputs[i].second == literal_flag); + } + } +} + TEST(InterpreterInstanceOf) { HandleAndZoneScope handles; Isolate* isolate = handles.main_isolate(); diff --git a/test/unittests/interpreter/bytecode-array-builder-unittest.cc b/test/unittests/interpreter/bytecode-array-builder-unittest.cc index 9f2459ecaa..0e9b24aaf2 100644 --- a/test/unittests/interpreter/bytecode-array-builder-unittest.cc +++ b/test/unittests/interpreter/bytecode-array-builder-unittest.cc @@ -213,7 +213,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { .CompareOperation(Token::Value::LTE, reg, 5) .CompareOperation(Token::Value::GTE, reg, 6) .CompareOperation(Token::Value::INSTANCEOF, reg, 7) - .CompareOperation(Token::Value::IN, reg, 8); + .CompareOperation(Token::Value::IN, reg, 8) + .CompareTypeOf(TestTypeOfFlags::LiteralFlag::kNumber); // Emit peephole optimizations of equality with Null or Undefined. builder.LoadUndefined()