[Interpreter / TurboFan] Add TestTypeof bytecode.

Adds a TestTypeof bytecode to deal with comparisons of the form:
  typeof(object) === 'string';

Also adds support to Turbofan to perform these comparisons without
inserting checkpoints.

BUG=v8:4280,v8:5267

Change-Id: Ib5cc1c6816dfe70a4120838d8eada2fc0267750f
Reviewed-on: https://chromium-review.googlesource.com/454837
Reviewed-by: Mythri Alle <mythria@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#43832}
This commit is contained in:
Ross McIlroy 2017-03-15 11:29:12 +00:00 committed by Commit Bot
parent 8692e7b86b
commit 3db32e064f
24 changed files with 643 additions and 189 deletions

View File

@ -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") \

View File

@ -905,24 +905,21 @@ void CompareOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec,
}
// Check for the pattern: typeof <expression> equals <string literal>.
static bool MatchLiteralCompareTypeof(Expression* left,
Token::Value op,
Expression* right,
Expression** expr,
Handle<String>* 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<String>::cast(right->AsLiteral()->value());
*literal = right->AsLiteral();
return true;
}
return false;
}
bool CompareOperation::IsLiteralCompareTypeof(Expression** expr,
Handle<String>* 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);
}

View File

@ -2275,7 +2275,7 @@ class CompareOperation final : public Expression {
FeedbackSlot CompareOperationFeedbackSlot() const { return feedback_slot_; }
// Match special cases.
bool IsLiteralCompareTypeof(Expression** expr, Handle<String>* check);
bool IsLiteralCompareTypeof(Expression** expr, Literal** literal);
bool IsLiteralCompareUndefined(Expression** expr);
bool IsLiteralCompareNull(Expression** expr);

View File

@ -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") \

View File

@ -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<String> 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<String>::cast(literal->value()));
}
if (expr->IsLiteralCompareUndefined(&sub_expr)) {
return VisitLiteralCompareNil(expr, sub_expr,

View File

@ -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,

View File

@ -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<String> 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<String>::cast(literal->value()));
}
if (expr->IsLiteralCompareUndefined(&sub_expr)) {
return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue);

View File

@ -1445,10 +1445,11 @@ void FullCodeGenerator::VisitRewritableExpression(RewritableExpression* expr) {
bool FullCodeGenerator::TryLiteralCompare(CompareOperation* expr) {
Expression* sub_expr;
Handle<String> 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<String>::cast(literal->value()));
return true;
}

View File

@ -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);

View File

@ -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);

View File

@ -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<uint8_t>(literal_flag);
}
// static
TestTypeOfFlags::LiteralFlag TestTypeOfFlags::Decode(uint8_t raw_flag) {
DCHECK_LE(raw_flag, static_cast<uint8_t>(LiteralFlag::kOther));
return static_cast<LiteralFlag>(raw_flag);
}
} // namespace interpreter
} // namespace internal
} // namespace v8

View File

@ -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

View File

@ -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) {
// 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) {

View File

@ -14,6 +14,7 @@
namespace v8 {
namespace internal {
class AstStringConstants;
class CompilationInfo;
namespace interpreter {
@ -71,6 +72,9 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
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<BytecodeGenerator> {
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<BytecodeGenerator> {
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<BytecodeGenerator> {
ZoneVector<BytecodeLabel> generator_resume_points_;
Register generator_state_;
int loop_depth_;
const AstRawString* prototype_string_;
const AstRawString* undefined_string_;
};
} // namespace interpreter

View File

@ -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:

View File

@ -2584,6 +2584,126 @@ void Interpreter::DoTestUndefined(InterpreterAssembler* assembler) {
__ Dispatch();
}
// TestTypeOf <literal_flag>
//
// Tests if the object in the <accumulator> 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<int32_t>(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 <imm>
//
// Jump by number of bytes represented by the immediate operand |imm|.

View File

@ -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<char> 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<Object>>();
Handle<Object> return_value =
callable(snippets[i].parameter(0)).ToHandleChecked();
CHECK(return_value->SameValue(*snippets[i].return_value()));
}
}
TEST(BytecodeGraphBuilderCountOperation) {
HandleAndZoneScope scope;

View File

@ -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: [
]

View File

@ -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],
]

View File

@ -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],
]

View File

@ -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],
]

View File

@ -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());

View File

@ -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<Handle<Object>, 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<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
InterpreterTester tester(isolate, bytecode_array);
auto callable = tester.GetCallable<Handle<Object>>();
for (size_t i = 0; i < arraysize(inputs); i++) {
Handle<Object> 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();

View File

@ -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()