[Interpreter] Optimize code of the form 'if (x === undefined)'.

Translates code of the form 'if (x === undefined)' into the JumpIfUndefined
bytecode, and similarly for comparisons with null. Also adds bytecodes for
JumpIfNotUndefined / Null.

Moves the peephole optimization for CompareUndefined out of the peephole
optimizer and into the BytecodeGenerator, having the side-effect of enabling
it for comparisons with undefined on both side of the compare operation.

BUG=v8:6107

Review-Url: https://codereview.chromium.org/2793923002
Cr-Commit-Position: refs/heads/master@{#44341}
This commit is contained in:
rmcilroy 2017-04-03 07:17:16 -07:00 committed by Commit bot
parent d73b11ecd2
commit f4f58e31c1
21 changed files with 700 additions and 235 deletions

View File

@ -1943,23 +1943,20 @@ void BytecodeGraphBuilder::VisitTestInstanceOf() {
}
void BytecodeGraphBuilder::VisitTestUndetectable() {
Node* object =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* object = environment()->LookupAccumulator();
Node* node = NewNode(jsgraph()->simplified()->ObjectIsUndetectable(), object);
environment()->BindAccumulator(node);
}
void BytecodeGraphBuilder::VisitTestNull() {
Node* object =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* object = environment()->LookupAccumulator();
Node* result = NewNode(simplified()->ReferenceEqual(), object,
jsgraph()->NullConstant());
environment()->BindAccumulator(result);
}
void BytecodeGraphBuilder::VisitTestUndefined() {
Node* object =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* object = environment()->LookupAccumulator();
Node* result = NewNode(simplified()->ReferenceEqual(), object,
jsgraph()->UndefinedConstant());
environment()->BindAccumulator(result);
@ -2082,6 +2079,14 @@ void BytecodeGraphBuilder::VisitJumpIfNullConstant() {
BuildJumpIfEqual(jsgraph()->NullConstant());
}
void BytecodeGraphBuilder::VisitJumpIfNotNull() {
BuildJumpIfNotEqual(jsgraph()->NullConstant());
}
void BytecodeGraphBuilder::VisitJumpIfNotNullConstant() {
BuildJumpIfNotEqual(jsgraph()->NullConstant());
}
void BytecodeGraphBuilder::VisitJumpIfUndefined() {
BuildJumpIfEqual(jsgraph()->UndefinedConstant());
}
@ -2090,6 +2095,14 @@ void BytecodeGraphBuilder::VisitJumpIfUndefinedConstant() {
BuildJumpIfEqual(jsgraph()->UndefinedConstant());
}
void BytecodeGraphBuilder::VisitJumpIfNotUndefined() {
BuildJumpIfNotEqual(jsgraph()->UndefinedConstant());
}
void BytecodeGraphBuilder::VisitJumpIfNotUndefinedConstant() {
BuildJumpIfNotEqual(jsgraph()->UndefinedConstant());
}
void BytecodeGraphBuilder::VisitJumpLoop() { BuildJump(); }
void BytecodeGraphBuilder::VisitStackCheck() {
@ -2365,6 +2378,13 @@ void BytecodeGraphBuilder::BuildJumpIfEqual(Node* comperand) {
BuildJumpIf(condition);
}
void BytecodeGraphBuilder::BuildJumpIfNotEqual(Node* comperand) {
Node* accumulator = environment()->LookupAccumulator();
Node* condition =
NewNode(simplified()->ReferenceEqual(), accumulator, comperand);
BuildJumpIfNot(condition);
}
void BytecodeGraphBuilder::BuildJumpIfFalse() {
NewBranch(environment()->LookupAccumulator());
Environment* if_true_environment = environment()->Copy();

View File

@ -212,6 +212,7 @@ class BytecodeGraphBuilder {
void BuildJumpIf(Node* condition);
void BuildJumpIfNot(Node* condition);
void BuildJumpIfEqual(Node* comperand);
void BuildJumpIfNotEqual(Node* comperand);
void BuildJumpIfTrue();
void BuildJumpIfFalse();
void BuildJumpIfToBooleanTrue();

View File

@ -389,6 +389,36 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(Token::Value op,
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CompareUndetectable() {
OutputTestUndetectable();
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CompareUndefined() {
OutputTestUndefined();
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CompareNull() {
OutputTestNull();
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CompareNil(Token::Value op,
NilValue nil) {
if (op == Token::EQ) {
return CompareUndetectable();
} else {
DCHECK_EQ(Token::EQ_STRICT, op);
if (nil == kUndefinedValue) {
return CompareUndefined();
} else {
DCHECK_EQ(kNullValue, nil);
return CompareNull();
}
}
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CompareTypeOf(
TestTypeOfFlags::LiteralFlag literal_flag) {
DCHECK(literal_flag != TestTypeOfFlags::LiteralFlag::kOther);
@ -885,6 +915,13 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNull(BytecodeLabel* label) {
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotNull(
BytecodeLabel* label) {
DCHECK(!label->is_bound());
OutputJumpIfNotNull(label, 0);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined(
BytecodeLabel* label) {
DCHECK(!label->is_bound());
@ -892,6 +929,47 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined(
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotUndefined(
BytecodeLabel* label) {
DCHECK(!label->is_bound());
OutputJumpIfNotUndefined(label, 0);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNil(BytecodeLabel* label,
Token::Value op,
NilValue nil) {
if (op == Token::EQ) {
// TODO(rmcilroy): Implement JumpIfUndetectable.
return CompareUndetectable().JumpIfTrue(label);
} else {
DCHECK_EQ(Token::EQ_STRICT, op);
if (nil == kUndefinedValue) {
return JumpIfUndefined(label);
} else {
DCHECK_EQ(kNullValue, nil);
return JumpIfNull(label);
}
}
}
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotNil(BytecodeLabel* label,
Token::Value op,
NilValue nil) {
if (op == Token::EQ) {
// TODO(rmcilroy): Implement JumpIfUndetectable.
return CompareUndetectable().JumpIfFalse(label);
} else {
DCHECK_EQ(Token::EQ_STRICT, op);
if (nil == kUndefinedValue) {
return JumpIfNotUndefined(label);
} else {
DCHECK_EQ(kNullValue, nil);
return JumpIfNotNull(label);
}
}
}
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotHole(
BytecodeLabel* label) {
DCHECK(!label->is_bound());

View File

@ -314,6 +314,10 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg,
int feedback_slot);
BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg);
BytecodeArrayBuilder& CompareUndetectable();
BytecodeArrayBuilder& CompareUndefined();
BytecodeArrayBuilder& CompareNull();
BytecodeArrayBuilder& CompareNil(Token::Value op, NilValue nil);
BytecodeArrayBuilder& CompareTypeOf(
TestTypeOfFlags::LiteralFlag literal_flag);
@ -332,7 +336,13 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
BytecodeArrayBuilder& JumpIfNotHole(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfJSReceiver(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfNotNull(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfNotUndefined(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfNil(BytecodeLabel* label, Token::Value op,
NilValue nil);
BytecodeArrayBuilder& JumpIfNotNil(BytecodeLabel* label, Token::Value op,
NilValue nil);
BytecodeArrayBuilder& JumpLoop(BytecodeLabel* label, int loop_depth);
BytecodeArrayBuilder& StackCheck(int position);

View File

@ -162,8 +162,12 @@ Bytecode GetJumpWithConstantOperand(Bytecode jump_bytecode) {
return Bytecode::kJumpIfNotHoleConstant;
case Bytecode::kJumpIfNull:
return Bytecode::kJumpIfNullConstant;
case Bytecode::kJumpIfNotNull:
return Bytecode::kJumpIfNotNullConstant;
case Bytecode::kJumpIfUndefined:
return Bytecode::kJumpIfUndefinedConstant;
case Bytecode::kJumpIfNotUndefined:
return Bytecode::kJumpIfNotUndefinedConstant;
case Bytecode::kJumpIfJSReceiver:
return Bytecode::kJumpIfJSReceiverConstant;
default:

View File

@ -3040,13 +3040,34 @@ void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) {
}
}
void BytecodeGenerator::BuildLiteralCompareNil(Token::Value op, NilValue nil) {
if (execution_result()->IsTest()) {
TestResultScope* test_result = execution_result()->AsTest();
switch (test_result->fallthrough()) {
case TestFallthrough::kThen:
builder()->JumpIfNotNil(test_result->NewElseLabel(), op, nil);
break;
case TestFallthrough::kElse:
builder()->JumpIfNil(test_result->NewThenLabel(), op, nil);
break;
case TestFallthrough::kNone:
builder()
->JumpIfNil(test_result->NewThenLabel(), op, nil)
.Jump(test_result->NewElseLabel());
}
test_result->SetResultConsumedByTest();
} else {
builder()->CompareNil(op, nil);
}
}
void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
// Emit a fast literal comparion for expressions of the form:
// typeof(x) === 'string'.
Expression* typeof_sub_expr;
Expression* sub_expr;
Literal* literal;
if (expr->IsLiteralCompareTypeof(&typeof_sub_expr, &literal)) {
VisitForTypeOfValue(typeof_sub_expr);
if (expr->IsLiteralCompareTypeof(&sub_expr, &literal)) {
// Emit a fast literal comparion for expressions of the form:
// typeof(x) === 'string'.
VisitForTypeOfValue(sub_expr);
builder()->SetExpressionPosition(expr);
TestTypeOfFlags::LiteralFlag literal_flag =
TestTypeOfFlags::GetFlagForLiteral(ast_string_constants(), literal);
@ -3055,6 +3076,14 @@ void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
} else {
builder()->CompareTypeOf(literal_flag);
}
} else if (expr->IsLiteralCompareUndefined(&sub_expr)) {
VisitForAccumulatorValue(sub_expr);
builder()->SetExpressionPosition(expr);
BuildLiteralCompareNil(expr->op(), kUndefinedValue);
} else if (expr->IsLiteralCompareNull(&sub_expr)) {
VisitForAccumulatorValue(sub_expr);
builder()->SetExpressionPosition(expr);
BuildLiteralCompareNil(expr->op(), kNullValue);
} else {
Register lhs = VisitForRegisterValue(expr->left());
VisitForAccumulatorValue(expr->right());

View File

@ -109,7 +109,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void BuildVariableAssignment(Variable* variable, Token::Value op,
FeedbackSlot slot,
HoleCheckMode hole_check_mode);
void BuildLiteralCompareNil(Token::Value compare_op, NilValue nil);
void BuildReturn();
void BuildAsyncReturn();
void BuildAsyncGeneratorReturn();

View File

@ -141,20 +141,6 @@ BytecodeNode TransformLdaZeroBinaryOpToBinaryOpWithZero(
return node;
}
BytecodeNode TransformEqualityWithNullOrUndefined(Bytecode new_bytecode,
BytecodeNode* const last,
BytecodeNode* const current) {
DCHECK((last->bytecode() == Bytecode::kLdaNull) ||
(last->bytecode() == Bytecode::kLdaUndefined));
DCHECK((current->bytecode() == Bytecode::kTestEqual) ||
(current->bytecode() == Bytecode::kTestEqualStrict));
BytecodeNode node(new_bytecode, current->operand(0), current->source_info());
if (last->source_info().is_valid()) {
node.set_source_info(last->source_info());
}
return node;
}
} // namespace
void BytecodePeepholeOptimizer::DefaultAction(
@ -268,16 +254,6 @@ void BytecodePeepholeOptimizer::
}
}
void BytecodePeepholeOptimizer::TransformEqualityWithNullOrUndefinedAction(
BytecodeNode* const node, const PeepholeActionAndData* action_data) {
DCHECK(LastIsValid());
DCHECK(!Bytecodes::IsJump(node->bytecode()));
// Fused last and current into current.
BytecodeNode new_node(TransformEqualityWithNullOrUndefined(
action_data->bytecode, last(), node));
SetLast(&new_node);
}
void BytecodePeepholeOptimizer::DefaultJumpAction(
BytecodeNode* const node, const PeepholeActionAndData* action_data) {
DCHECK(LastIsValid());

View File

@ -11,17 +11,16 @@ namespace v8 {
namespace internal {
namespace interpreter {
#define PEEPHOLE_NON_JUMP_ACTION_LIST(V) \
V(DefaultAction) \
V(UpdateLastAction) \
V(UpdateLastIfSourceInfoPresentAction) \
V(ElideCurrentAction) \
V(ElideCurrentIfOperand0MatchesAction) \
V(ElideLastAction) \
V(ChangeBytecodeAction) \
V(TransformLdaSmiBinaryOpToBinaryOpWithSmiAction) \
V(TransformLdaZeroBinaryOpToBinaryOpWithZeroAction) \
V(TransformEqualityWithNullOrUndefinedAction)
#define PEEPHOLE_NON_JUMP_ACTION_LIST(V) \
V(DefaultAction) \
V(UpdateLastAction) \
V(UpdateLastIfSourceInfoPresentAction) \
V(ElideCurrentAction) \
V(ElideCurrentIfOperand0MatchesAction) \
V(ElideLastAction) \
V(ChangeBytecodeAction) \
V(TransformLdaSmiBinaryOpToBinaryOpWithSmiAction) \
V(TransformLdaZeroBinaryOpToBinaryOpWithZeroAction)
#define PEEPHOLE_JUMP_ACTION_LIST(V) \
V(DefaultJumpAction) \

View File

@ -207,9 +207,9 @@ namespace interpreter {
V(TestEqualStrictNoFeedback, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(TestInstanceOf, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(TestIn, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(TestUndetectable, AccumulatorUse::kWrite, OperandType::kReg) \
V(TestNull, AccumulatorUse::kWrite, OperandType::kReg) \
V(TestUndefined, AccumulatorUse::kWrite, OperandType::kReg) \
V(TestUndetectable, AccumulatorUse::kReadWrite) \
V(TestNull, AccumulatorUse::kReadWrite) \
V(TestUndefined, AccumulatorUse::kReadWrite) \
V(TestTypeOf, AccumulatorUse::kReadWrite, OperandType::kFlag8) \
\
/* Cast operators */ \
@ -253,7 +253,9 @@ namespace interpreter {
/* - [Conditional jumps] */ \
/* - [Conditional constant jumps] */ \
V(JumpIfNullConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfNotNullConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfUndefinedConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfNotUndefinedConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfTrueConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfFalseConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfJSReceiverConstant, AccumulatorUse::kRead, OperandType::kIdx) \
@ -269,7 +271,9 @@ namespace interpreter {
V(JumpIfTrue, AccumulatorUse::kRead, OperandType::kUImm) \
V(JumpIfFalse, AccumulatorUse::kRead, OperandType::kUImm) \
V(JumpIfNull, AccumulatorUse::kRead, OperandType::kUImm) \
V(JumpIfNotNull, AccumulatorUse::kRead, OperandType::kUImm) \
V(JumpIfUndefined, AccumulatorUse::kRead, OperandType::kUImm) \
V(JumpIfNotUndefined, AccumulatorUse::kRead, OperandType::kUImm) \
V(JumpIfJSReceiver, AccumulatorUse::kRead, OperandType::kUImm) \
V(JumpIfNotHole, AccumulatorUse::kRead, OperandType::kUImm) \
\
@ -363,14 +367,18 @@ namespace interpreter {
V(JumpIfTrue) \
V(JumpIfFalse) \
V(JumpIfNull) \
V(JumpIfNotNull) \
V(JumpIfUndefined) \
V(JumpIfNotUndefined) \
V(JumpIfJSReceiver) \
V(JumpIfNotHole)
#define JUMP_CONDITIONAL_CONSTANT_BYTECODE_LIST(V) \
JUMP_TOBOOLEAN_CONDITIONAL_CONSTANT_BYTECODE_LIST(V) \
V(JumpIfNullConstant) \
V(JumpIfNotNullConstant) \
V(JumpIfUndefinedConstant) \
V(JumpIfNotUndefinedConstant) \
V(JumpIfTrueConstant) \
V(JumpIfFalseConstant) \
V(JumpIfJSReceiverConstant) \
@ -534,6 +542,15 @@ class V8_EXPORT_PRIVATE Bytecodes final {
bytecode == Bytecode::kLdaImmutableCurrentContextSlot;
}
// Returns true if |bytecode| is a compare operation without external effects
// (e.g., Type cooersion).
static constexpr bool IsCompareWithoutEffects(Bytecode bytecode) {
return bytecode == Bytecode::kTestUndetectable ||
bytecode == Bytecode::kTestNull ||
bytecode == Bytecode::kTestUndefined ||
bytecode == Bytecode::kTestTypeOf;
}
// Return true if |bytecode| is a register load without effects,
// e.g. Mov, Star.
static constexpr bool IsRegisterLoadWithoutEffects(Bytecode bytecode) {
@ -619,7 +636,8 @@ class V8_EXPORT_PRIVATE Bytecodes final {
static constexpr bool IsWithoutExternalSideEffects(Bytecode bytecode) {
return (IsAccumulatorLoadWithoutEffects(bytecode) ||
IsRegisterLoadWithoutEffects(bytecode) ||
bytecode == Bytecode::kNop || IsJumpWithoutEffects(bytecode));
IsCompareWithoutEffects(bytecode) || bytecode == Bytecode::kNop ||
IsJumpWithoutEffects(bytecode));
}
// Returns true if the bytecode is Ldar or Star.

View File

@ -2429,82 +2429,53 @@ void InterpreterGenerator::DoTestInstanceOf(InterpreterAssembler* assembler) {
DoCompareOp(Token::INSTANCEOF, assembler);
}
// TestUndetectable <src>
// TestUndetectable
//
// Test if the value in the <src> register equals to null/undefined. This is
// done by checking undetectable bit on the map of the object.
// Test if the value in the accumulator is undetectable (null, undefined or
// document.all).
void InterpreterGenerator::DoTestUndetectable(InterpreterAssembler* assembler) {
Node* reg_index = __ BytecodeOperandReg(0);
Node* object = __ LoadRegister(reg_index);
Label return_false(assembler), end(assembler);
Node* object = __ GetAccumulator();
Label not_equal(assembler), end(assembler);
// If the object is an Smi then return false.
__ GotoIf(__ TaggedIsSmi(object), &not_equal);
__ SetAccumulator(__ BooleanConstant(false));
__ GotoIf(__ TaggedIsSmi(object), &end);
// If it is a HeapObject, load the map and check for undetectable bit.
Node* map = __ LoadMap(object);
Node* map_bitfield = __ LoadMapBitField(map);
Node* map_undetectable =
__ Word32And(map_bitfield, __ Int32Constant(1 << Map::kIsUndetectable));
__ GotoIf(__ Word32Equal(map_undetectable, __ Int32Constant(0)), &not_equal);
__ SetAccumulator(__ BooleanConstant(true));
Node* result = __ SelectBooleanConstant(
__ Word32NotEqual(map_undetectable, __ Int32Constant(0)));
__ SetAccumulator(result);
__ Goto(&end);
__ Bind(&not_equal);
{
__ SetAccumulator(__ BooleanConstant(false));
__ Goto(&end);
}
__ Bind(&end);
__ Dispatch();
}
// TestNull <src>
// TestNull
//
// Test if the value in the <src> register is strictly equal to null.
// Test if the value in accumulator is strictly equal to null.
void InterpreterGenerator::DoTestNull(InterpreterAssembler* assembler) {
Node* reg_index = __ BytecodeOperandReg(0);
Node* object = __ LoadRegister(reg_index);
Node* object = __ GetAccumulator();
Node* null_value = __ HeapConstant(isolate_->factory()->null_value());
Label equal(assembler), end(assembler);
__ GotoIf(__ WordEqual(object, null_value), &equal);
__ SetAccumulator(__ BooleanConstant(false));
__ Goto(&end);
__ Bind(&equal);
{
__ SetAccumulator(__ BooleanConstant(true));
__ Goto(&end);
}
__ Bind(&end);
Node* result = __ SelectBooleanConstant(__ WordEqual(object, null_value));
__ SetAccumulator(result);
__ Dispatch();
}
// TestUndefined <src>
// TestUndefined
//
// Test if the value in the <src> register is strictly equal to undefined.
// Test if the value in the accumulator is strictly equal to undefined.
void InterpreterGenerator::DoTestUndefined(InterpreterAssembler* assembler) {
Node* reg_index = __ BytecodeOperandReg(0);
Node* object = __ LoadRegister(reg_index);
Node* object = __ GetAccumulator();
Node* undefined_value =
__ HeapConstant(isolate_->factory()->undefined_value());
Label equal(assembler), end(assembler);
__ GotoIf(__ WordEqual(object, undefined_value), &equal);
__ SetAccumulator(__ BooleanConstant(false));
__ Goto(&end);
__ Bind(&equal);
{
__ SetAccumulator(__ BooleanConstant(true));
__ Goto(&end);
}
__ Bind(&end);
Node* result =
__ SelectBooleanConstant(__ WordEqual(object, undefined_value));
__ SetAccumulator(result);
__ Dispatch();
}
@ -2797,6 +2768,30 @@ void InterpreterGenerator::DoJumpIfNullConstant(
__ JumpIfWordEqual(accumulator, null_value, relative_jump);
}
// JumpIfNotNull <imm>
//
// Jump by number of bytes represented by an immediate operand if the object
// referenced by the accumulator is not the null constant.
void InterpreterGenerator::DoJumpIfNotNull(InterpreterAssembler* assembler) {
Node* accumulator = __ GetAccumulator();
Node* null_value = __ HeapConstant(isolate_->factory()->null_value());
Node* relative_jump = __ BytecodeOperandUImmWord(0);
__ JumpIfWordNotEqual(accumulator, null_value, relative_jump);
}
// JumpIfNotNullConstant <idx>
//
// Jump by number of bytes in the Smi in the |idx| entry in the constant pool
// if the object referenced by the accumulator is not the null constant.
void InterpreterGenerator::DoJumpIfNotNullConstant(
InterpreterAssembler* assembler) {
Node* accumulator = __ GetAccumulator();
Node* null_value = __ HeapConstant(isolate_->factory()->null_value());
Node* index = __ BytecodeOperandIdx(0);
Node* relative_jump = __ LoadAndUntagConstantPoolEntry(index);
__ JumpIfWordNotEqual(accumulator, null_value, relative_jump);
}
// JumpIfUndefined <imm>
//
// Jump by number of bytes represented by an immediate operand if the object
@ -2823,6 +2818,33 @@ void InterpreterGenerator::DoJumpIfUndefinedConstant(
__ JumpIfWordEqual(accumulator, undefined_value, relative_jump);
}
// JumpIfNotUndefined <imm>
//
// Jump by number of bytes represented by an immediate operand if the object
// referenced by the accumulator is not the undefined constant.
void InterpreterGenerator::DoJumpIfNotUndefined(
InterpreterAssembler* assembler) {
Node* accumulator = __ GetAccumulator();
Node* undefined_value =
__ HeapConstant(isolate_->factory()->undefined_value());
Node* relative_jump = __ BytecodeOperandUImmWord(0);
__ JumpIfWordNotEqual(accumulator, undefined_value, relative_jump);
}
// JumpIfNotUndefinedConstant <idx>
//
// Jump by number of bytes in the Smi in the |idx| entry in the constant pool
// if the object referenced by the accumulator is not the undefined constant.
void InterpreterGenerator::DoJumpIfNotUndefinedConstant(
InterpreterAssembler* assembler) {
Node* accumulator = __ GetAccumulator();
Node* undefined_value =
__ HeapConstant(isolate_->factory()->undefined_value());
Node* index = __ BytecodeOperandIdx(0);
Node* relative_jump = __ LoadAndUntagConstantPoolEntry(index);
__ JumpIfWordNotEqual(accumulator, undefined_value, relative_jump);
}
// JumpIfJSReceiver <imm>
//
// Jump by number of bytes represented by an immediate operand if the object

View File

@ -192,28 +192,6 @@ PeepholeActionAndData PeepholeActionTableWriter::LookupActionAndData(
}
}
// Fuse LdaNull/LdaUndefined followed by a equality comparison with test
// undetectable. Testing undetectable is a simple check on the map which is
// more efficient than the full comparison operation.
if (last == Bytecode::kLdaNull || last == Bytecode::kLdaUndefined) {
if (current == Bytecode::kTestEqual) {
return {PeepholeAction::kTransformEqualityWithNullOrUndefinedAction,
Bytecode::kTestUndetectable};
}
}
// Fuse LdaNull/LdaUndefined followed by a strict equals with
// TestNull/TestUndefined.
if (current == Bytecode::kTestEqualStrict) {
if (last == Bytecode::kLdaNull) {
return {PeepholeAction::kTransformEqualityWithNullOrUndefinedAction,
Bytecode::kTestNull};
} else if (last == Bytecode::kLdaUndefined) {
return {PeepholeAction::kTransformEqualityWithNullOrUndefinedAction,
Bytecode::kTestUndefined};
}
}
// If there is no last bytecode to optimize against, store the incoming
// bytecode or for jumps emit incoming bytecode immediately.
if (last == Bytecode::kIllegal) {

View File

@ -0,0 +1,289 @@
#
# Autogenerated by generate-bytecode-expectations.
#
---
wrap: yes
---
snippet: "
var a = 1;
return a === null;
"
frame size: 1
parameter count: 1
bytecode array length: 7
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(1),
B(Star), R(0),
/* 45 S> */ B(TestNull),
/* 64 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
var a = undefined;
return undefined === a;
"
frame size: 1
parameter count: 1
bytecode array length: 6
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaUndefined),
B(Star), R(0),
/* 53 S> */ B(TestUndefined),
/* 77 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
var a = undefined;
return undefined !== a;
"
frame size: 1
parameter count: 1
bytecode array length: 7
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaUndefined),
B(Star), R(0),
/* 53 S> */ B(TestUndefined),
/* 70 E> */ B(LogicalNot),
/* 77 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
var a = 2;
return a != null;
"
frame size: 1
parameter count: 1
bytecode array length: 8
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(2),
B(Star), R(0),
/* 45 S> */ B(TestUndetectable),
/* 54 E> */ B(LogicalNot),
/* 63 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
var a = undefined;
return undefined == a;
"
frame size: 1
parameter count: 1
bytecode array length: 6
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaUndefined),
B(Star), R(0),
/* 53 S> */ B(TestUndetectable),
/* 76 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
var a = undefined;
return undefined === a ? 1 : 2;
"
frame size: 1
parameter count: 1
bytecode array length: 13
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaUndefined),
B(Star), R(0),
/* 53 S> */ B(JumpIfNotUndefined), U8(6),
B(LdaSmi), I8(1),
B(Jump), U8(4),
B(LdaSmi), I8(2),
/* 85 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
var a = 0;
return null == a ? 1 : 2;
"
frame size: 1
parameter count: 1
bytecode array length: 14
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaZero),
B(Star), R(0),
/* 45 S> */ B(TestUndetectable),
/* 57 E> */ B(JumpIfFalse), U8(6),
B(LdaSmi), I8(1),
B(Jump), U8(4),
B(LdaSmi), I8(2),
/* 71 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
var a = 0;
return undefined !== a ? 1 : 2;
"
frame size: 1
parameter count: 1
bytecode array length: 13
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaZero),
B(Star), R(0),
/* 45 S> */ B(JumpIfUndefined), U8(6),
B(LdaSmi), I8(1),
B(Jump), U8(4),
B(LdaSmi), I8(2),
/* 77 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
var a = 0;
return a === null ? 1 : 2;
"
frame size: 1
parameter count: 1
bytecode array length: 13
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaZero),
B(Star), R(0),
/* 45 S> */ B(JumpIfNotNull), U8(6),
B(LdaSmi), I8(1),
B(Jump), U8(4),
B(LdaSmi), I8(2),
/* 72 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
var a = 0;
if (a === null) {
return 1;
} else {
return 2;
}
"
frame size: 1
parameter count: 1
bytecode array length: 14
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaZero),
B(Star), R(0),
/* 45 S> */ B(JumpIfNotNull), U8(5),
/* 65 S> */ B(LdaSmi), I8(1),
/* 98 S> */ B(Return),
/* 86 S> */ B(LdaSmi), I8(2),
/* 98 S> */ B(Return),
B(LdaUndefined),
/* 98 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
var a = 0;
if (a != undefined) {
return 1;
}
"
frame size: 1
parameter count: 1
bytecode array length: 12
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaZero),
B(Star), R(0),
/* 45 S> */ B(TestUndetectable),
/* 51 E> */ B(JumpIfTrue), U8(5),
/* 69 S> */ B(LdaSmi), I8(1),
/* 81 S> */ B(Return),
B(LdaUndefined),
/* 81 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
var a = undefined;
var b = 0;
while (a !== undefined) {
b++;
}
"
frame size: 2
parameter count: 1
bytecode array length: 23
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaUndefined),
B(Star), R(0),
/* 61 S> */ B(LdaZero),
B(Star), R(1),
/* 73 S> */ B(Ldar), R(0),
B(JumpIfUndefined), U8(12),
/* 64 E> */ B(StackCheck),
/* 92 S> */ B(Ldar), R(1),
B(Inc), U8(5),
B(Star), R(1),
B(JumpLoop), U8(11), I8(0),
B(LdaUndefined),
/* 99 S> */ B(Return),
]
constant pool: [
]
handlers: [
]

View File

@ -15,7 +15,7 @@ bytecode array length: 6
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaSmi), I8(1),
/* 51 E> */ B(TestTypeOf), U8(0),
B(TestTypeOf), U8(0),
/* 65 S> */ B(Return),
]
constant pool: [
@ -33,7 +33,7 @@ bytecode array length: 6
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaConstant), U8(0),
/* 50 E> */ B(TestTypeOf), U8(1),
B(TestTypeOf), U8(1),
/* 69 S> */ B(Return),
]
constant pool: [
@ -52,7 +52,7 @@ bytecode array length: 5
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaTrue),
/* 54 E> */ B(TestTypeOf), U8(3),
B(TestTypeOf), U8(3),
/* 68 S> */ B(Return),
]
constant pool: [
@ -70,7 +70,7 @@ bytecode array length: 5
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaUndefined),
/* 50 E> */ B(TestTypeOf), U8(1),
B(TestTypeOf), U8(1),
/* 73 S> */ B(Return),
]
constant pool: [

View File

@ -16,7 +16,7 @@ snippet: "
"
frame size: 19
parameter count: 1
bytecode array length: 1030
bytecode array length: 1027
bytecodes: [
B(Ldar), R(new_target),
B(JumpIfUndefined), U8(39),
@ -204,8 +204,7 @@ bytecodes: [
B(LdaNamedProperty), R(12), U8(10), U8(21),
B(StaContextSlot), R(1), U8(13), U8(0),
B(LdaContextSlot), R(1), U8(13), U8(0),
B(Star), R(12),
B(TestUndetectable), R(12),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(JumpConstant), U8(15),
B(LdaContextSlot), R(1), U8(9), U8(0),
@ -468,20 +467,20 @@ constant pool: [
FIXED_ARRAY_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"],
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
Smi [560],
Smi [557],
FIXED_ARRAY_TYPE,
Smi [702],
Smi [699],
Smi [348],
Smi [374],
Smi [371],
FIXED_ARRAY_TYPE,
Smi [317],
]
handlers: [
[80, 943, 949],
[83, 889, 891],
[80, 940, 946],
[83, 886, 888],
[100, 423, 429],
[103, 375, 377],
[519, 645, 647],
[516, 642, 644],
]
---
@ -493,7 +492,7 @@ snippet: "
"
frame size: 19
parameter count: 1
bytecode array length: 1088
bytecode array length: 1085
bytecodes: [
B(Ldar), R(new_target),
B(JumpIfUndefined), U8(39),
@ -688,8 +687,7 @@ bytecodes: [
B(LdaNamedProperty), R(12), U8(10), U8(21),
B(StaContextSlot), R(1), U8(13), U8(0),
B(LdaContextSlot), R(1), U8(13), U8(0),
B(Star), R(12),
B(TestUndetectable), R(12),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(JumpConstant), U8(15),
B(LdaContextSlot), R(1), U8(9), U8(0),
@ -974,20 +972,20 @@ constant pool: [
FIXED_ARRAY_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"],
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
Smi [572],
Smi [569],
FIXED_ARRAY_TYPE,
Smi [714],
Smi [711],
Smi [348],
Smi [374],
Smi [371],
FIXED_ARRAY_TYPE,
Smi [340],
]
handlers: [
[80, 978, 984],
[83, 924, 926],
[80, 975, 981],
[83, 921, 923],
[100, 435, 441],
[103, 387, 389],
[531, 657, 659],
[528, 654, 656],
]
---
@ -1002,7 +1000,7 @@ snippet: "
"
frame size: 19
parameter count: 1
bytecode array length: 1067
bytecode array length: 1064
bytecodes: [
B(Ldar), R(new_target),
B(JumpIfUndefined), U8(39),
@ -1206,8 +1204,7 @@ bytecodes: [
B(LdaNamedProperty), R(12), U8(10), U8(23),
B(StaContextSlot), R(1), U8(13), U8(0),
B(LdaContextSlot), R(1), U8(13), U8(0),
B(Star), R(12),
B(TestUndetectable), R(12),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(JumpConstant), U8(15),
B(LdaContextSlot), R(1), U8(9), U8(0),
@ -1470,20 +1467,20 @@ constant pool: [
FIXED_ARRAY_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"],
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
Smi [597],
Smi [594],
FIXED_ARRAY_TYPE,
Smi [739],
Smi [736],
Smi [348],
Smi [374],
Smi [371],
FIXED_ARRAY_TYPE,
Smi [317],
]
handlers: [
[80, 980, 986],
[83, 926, 928],
[80, 977, 983],
[83, 923, 925],
[100, 460, 466],
[103, 412, 414],
[556, 682, 684],
[553, 679, 681],
]
---
@ -1496,7 +1493,7 @@ snippet: "
"
frame size: 14
parameter count: 1
bytecode array length: 582
bytecode array length: 579
bytecodes: [
B(Ldar), R(new_target),
B(JumpIfUndefined), U8(22),
@ -1608,14 +1605,13 @@ bytecodes: [
B(Star), R(11),
B(LdaZero),
B(TestEqualStrict), R(11), U8(21),
B(JumpIfTrue), U8(129),
B(JumpIfTrue), U8(126),
B(LdaCurrentContextSlot), U8(7),
B(Star), R(11),
B(LdaNamedProperty), R(11), U8(9), U8(22),
B(StaCurrentContextSlot), U8(11),
B(LdaCurrentContextSlot), U8(11),
B(Star), R(11),
B(TestUndetectable), R(11),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(Jump), U8(109),
B(LdaCurrentContextSlot), U8(9),
@ -1778,10 +1774,10 @@ constant pool: [
FIXED_ARRAY_TYPE,
]
handlers: [
[63, 499, 505],
[66, 445, 447],
[63, 496, 502],
[66, 442, 444],
[81, 241, 247],
[84, 193, 195],
[325, 337, 339],
[322, 334, 336],
]

View File

@ -11,7 +11,7 @@ snippet: "
"
frame size: 15
parameter count: 1
bytecode array length: 263
bytecode array length: 262
bytecodes: [
/* 30 E> */ B(StackCheck),
B(LdaZero),
@ -72,10 +72,10 @@ bytecodes: [
B(Star), R(11),
B(LdaZero),
B(TestEqualStrict), R(4), U8(16),
B(JumpIfTrue), U8(105),
B(JumpIfTrue), U8(104),
B(LdaNamedProperty), R(2), U8(7), U8(17),
B(Star), R(6),
B(TestUndetectable), R(6),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(Jump), U8(93),
B(LdaSmi), I8(1),
@ -140,7 +140,7 @@ constant pool: [
handlers: [
[7, 124, 130],
[10, 88, 90],
[191, 201, 203],
[190, 200, 202],
]
---
@ -150,7 +150,7 @@ snippet: "
"
frame size: 16
parameter count: 1
bytecode array length: 276
bytecode array length: 275
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaConstant), U8(0),
@ -213,10 +213,10 @@ bytecodes: [
B(Star), R(12),
B(LdaZero),
B(TestEqualStrict), R(5), U8(15),
B(JumpIfTrue), U8(105),
B(JumpIfTrue), U8(104),
B(LdaNamedProperty), R(3), U8(7), U8(16),
B(Star), R(7),
B(TestUndetectable), R(7),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(Jump), U8(93),
B(LdaSmi), I8(1),
@ -286,7 +286,7 @@ constant pool: [
handlers: [
[11, 127, 133],
[14, 91, 93],
[195, 205, 207],
[194, 204, 206],
]
---
@ -298,7 +298,7 @@ snippet: "
"
frame size: 15
parameter count: 1
bytecode array length: 281
bytecode array length: 280
bytecodes: [
/* 30 E> */ B(StackCheck),
B(LdaZero),
@ -367,10 +367,10 @@ bytecodes: [
B(Star), R(11),
B(LdaZero),
B(TestEqualStrict), R(4), U8(18),
B(JumpIfTrue), U8(105),
B(JumpIfTrue), U8(104),
B(LdaNamedProperty), R(2), U8(7), U8(19),
B(Star), R(6),
B(TestUndetectable), R(6),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(Jump), U8(93),
B(LdaSmi), I8(1),
@ -435,7 +435,7 @@ constant pool: [
handlers: [
[7, 142, 148],
[10, 106, 108],
[209, 219, 221],
[208, 218, 220],
]
---
@ -445,7 +445,7 @@ snippet: "
"
frame size: 14
parameter count: 1
bytecode array length: 287
bytecode array length: 286
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(CreateObjectLiteral), U8(0), U8(2), U8(1), R(8),
@ -511,10 +511,10 @@ bytecodes: [
B(Star), R(10),
B(LdaZero),
B(TestEqualStrict), R(3), U8(21),
B(JumpIfTrue), U8(105),
B(JumpIfTrue), U8(104),
B(LdaNamedProperty), R(1), U8(9), U8(22),
B(Star), R(5),
B(TestUndetectable), R(5),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(Jump), U8(93),
B(LdaSmi), I8(1),
@ -586,6 +586,6 @@ constant pool: [
handlers: [
[15, 138, 144],
[18, 102, 104],
[206, 216, 218],
[205, 215, 217],
]

View File

@ -14,15 +14,16 @@ snippet: "
"
frame size: 3
parameter count: 1
bytecode array length: 24
bytecode array length: 25
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 46 S> */ B(CreateObjectLiteral), U8(0), U8(2), U8(1), R(2),
B(Mov), R(2), R(0),
/* 63 S> */ B(LdaSmi), I8(10),
B(Star), R(1),
/* 67 S> */ B(TestUndetectable), R(0),
B(JumpIfFalse), U8(6),
/* 67 S> */ B(Ldar), R(0),
B(TestUndetectable),
/* 77 E> */ B(JumpIfFalse), U8(6),
/* 88 S> */ B(LdaSmi), I8(20),
B(Star), R(1),
/* 97 S> */ B(Ldar), R(1),
@ -43,15 +44,16 @@ snippet: "
"
frame size: 3
parameter count: 1
bytecode array length: 24
bytecode array length: 25
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 46 S> */ B(CreateObjectLiteral), U8(0), U8(2), U8(1), R(2),
B(Mov), R(2), R(0),
/* 63 S> */ B(LdaSmi), I8(10),
B(Star), R(1),
/* 67 S> */ B(TestUndetectable), R(0),
B(JumpIfFalse), U8(6),
/* 67 S> */ B(Ldar), R(0),
B(TestUndetectable),
/* 77 E> */ B(JumpIfFalse), U8(6),
/* 93 S> */ B(LdaSmi), I8(20),
B(Star), R(1),
/* 102 S> */ B(Ldar), R(1),
@ -72,15 +74,16 @@ snippet: "
"
frame size: 3
parameter count: 1
bytecode array length: 24
bytecode array length: 25
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 46 S> */ B(CreateObjectLiteral), U8(0), U8(2), U8(1), R(2),
B(Mov), R(2), R(0),
/* 63 S> */ B(LdaSmi), I8(10),
B(Star), R(1),
/* 67 S> */ B(TestUndetectable), R(0),
B(JumpIfTrue), U8(6),
/* 67 S> */ B(Ldar), R(0),
B(TestUndetectable),
/* 77 E> */ B(JumpIfTrue), U8(6),
/* 88 S> */ B(LdaSmi), I8(20),
B(Star), R(1),
/* 97 S> */ B(Ldar), R(1),
@ -101,15 +104,16 @@ snippet: "
"
frame size: 3
parameter count: 1
bytecode array length: 24
bytecode array length: 25
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 46 S> */ B(CreateObjectLiteral), U8(0), U8(2), U8(1), R(2),
B(Mov), R(2), R(0),
/* 63 S> */ B(LdaSmi), I8(10),
B(Star), R(1),
/* 67 S> */ B(TestUndetectable), R(0),
B(JumpIfTrue), U8(6),
/* 67 S> */ B(Ldar), R(0),
B(TestUndetectable),
/* 77 E> */ B(JumpIfTrue), U8(6),
/* 93 S> */ B(LdaSmi), I8(20),
B(Star), R(1),
/* 102 S> */ B(Ldar), R(1),
@ -137,8 +141,8 @@ bytecodes: [
B(Mov), R(2), R(0),
/* 63 S> */ B(LdaSmi), I8(10),
B(Star), R(1),
/* 67 S> */ B(TestNull), R(0),
B(JumpIfFalse), U8(6),
/* 67 S> */ B(Ldar), R(0),
B(JumpIfNotNull), U8(6),
/* 89 S> */ B(LdaSmi), I8(20),
B(Star), R(1),
/* 98 S> */ B(Ldar), R(1),
@ -166,8 +170,8 @@ bytecodes: [
B(Mov), R(2), R(0),
/* 63 S> */ B(LdaSmi), I8(10),
B(Star), R(1),
/* 67 S> */ B(TestUndefined), R(0),
B(JumpIfFalse), U8(6),
/* 67 S> */ B(Ldar), R(0),
B(JumpIfNotUndefined), U8(6),
/* 94 S> */ B(LdaSmi), I8(20),
B(Star), R(1),
/* 103 S> */ B(Ldar), R(1),
@ -195,8 +199,8 @@ bytecodes: [
B(Mov), R(2), R(0),
/* 63 S> */ B(LdaSmi), I8(10),
B(Star), R(1),
/* 67 S> */ B(TestNull), R(0),
B(JumpIfTrue), U8(6),
/* 67 S> */ B(Ldar), R(0),
B(JumpIfNull), U8(6),
/* 89 S> */ B(LdaSmi), I8(20),
B(Star), R(1),
/* 98 S> */ B(Ldar), R(1),
@ -224,8 +228,8 @@ bytecodes: [
B(Mov), R(2), R(0),
/* 63 S> */ B(LdaSmi), I8(10),
B(Star), R(1),
/* 67 S> */ B(TestUndefined), R(0),
B(JumpIfTrue), U8(6),
/* 67 S> */ B(Ldar), R(0),
B(JumpIfUndefined), U8(6),
/* 94 S> */ B(LdaSmi), I8(20),
B(Star), R(1),
/* 103 S> */ B(Ldar), R(1),

View File

@ -280,7 +280,7 @@ snippet: "
"
frame size: 18
parameter count: 1
bytecode array length: 754
bytecode array length: 751
bytecodes: [
B(Ldar), R(new_target),
B(JumpIfUndefined), U8(33),
@ -474,14 +474,13 @@ bytecodes: [
B(Star), R(11),
B(LdaZero),
B(TestEqualStrict), R(11), U8(16),
B(JumpIfTrue), U8(153),
B(JumpIfTrue), U8(150),
B(LdaContextSlot), R(1), U8(7), U8(0),
B(Star), R(11),
B(LdaNamedProperty), R(11), U8(9), U8(17),
B(StaContextSlot), R(1), U8(11), U8(0),
B(LdaContextSlot), R(1), U8(11), U8(0),
B(Star), R(11),
B(TestUndetectable), R(11),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(Jump), U8(127),
B(LdaContextSlot), R(1), U8(9), U8(0),
@ -617,12 +616,12 @@ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"],
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
FIXED_ARRAY_TYPE,
Smi [566],
Smi [563],
]
handlers: [
[51, 678, 684],
[51, 675, 681],
[146, 437, 443],
[149, 393, 395],
[533, 549, 551],
[530, 546, 548],
]

View File

@ -1027,6 +1027,61 @@ TEST(CompareTypeOf) {
LoadGolden("CompareTypeOf.golden")));
}
TEST(CompareNil) {
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
const char* snippets[] = {
"var a = 1;\n"
"return a === null;\n",
"var a = undefined;\n"
"return undefined === a;\n",
"var a = undefined;\n"
"return undefined !== a;\n",
"var a = 2;\n"
"return a != null;\n",
"var a = undefined;\n"
"return undefined == a;\n",
"var a = undefined;\n"
"return undefined === a ? 1 : 2;\n",
"var a = 0;\n"
"return null == a ? 1 : 2;\n",
"var a = 0;\n"
"return undefined !== a ? 1 : 2;\n",
"var a = 0;\n"
"return a === null ? 1 : 2;\n",
"var a = 0;\n"
"if (a === null) {\n"
" return 1;\n"
"} else {\n"
" return 2;\n"
"}\n",
"var a = 0;\n"
"if (a != undefined) {\n"
" return 1;\n"
"}\n",
"var a = undefined;\n"
"var b = 0;\n"
"while (a !== undefined) {\n"
" b++;\n"
"}\n",
};
CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("CompareNil.golden")));
}
TEST(Delete) {
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());

View File

@ -215,7 +215,10 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.CompareOperation(Token::Value::GTE, reg, 6)
.CompareTypeOf(TestTypeOfFlags::LiteralFlag::kNumber)
.CompareOperation(Token::Value::INSTANCEOF, reg)
.CompareOperation(Token::Value::IN, reg);
.CompareOperation(Token::Value::IN, reg)
.CompareUndetectable()
.CompareUndefined()
.CompareNull();
// Emit peephole optimizations of equality with Null or Undefined.
builder.LoadUndefined()
@ -238,23 +241,27 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
// Short jumps with Imm8 operands
{
BytecodeLabel start, after_jump1, after_jump2, after_jump3, after_jump4,
after_jump5;
after_jump5, after_jump6, after_jump7;
builder.Bind(&start)
.Jump(&after_jump1)
.Bind(&after_jump1)
.JumpIfNull(&after_jump2)
.Bind(&after_jump2)
.JumpIfUndefined(&after_jump3)
.JumpIfNotNull(&after_jump3)
.Bind(&after_jump3)
.JumpIfNotHole(&after_jump4)
.JumpIfUndefined(&after_jump4)
.Bind(&after_jump4)
.JumpIfJSReceiver(&after_jump5)
.JumpIfNotUndefined(&after_jump5)
.Bind(&after_jump5)
.JumpIfNotHole(&after_jump6)
.Bind(&after_jump6)
.JumpIfJSReceiver(&after_jump7)
.Bind(&after_jump7)
.JumpLoop(&start, 0);
}
// Longer jumps with constant operands
BytecodeLabel end[9];
BytecodeLabel end[11];
{
BytecodeLabel after_jump;
builder.Jump(&end[0])
@ -268,10 +275,12 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.LoadLiteral(Smi::kZero)
.JumpIfFalse(&end[4])
.JumpIfNull(&end[5])
.JumpIfUndefined(&end[6])
.JumpIfNotHole(&end[7])
.JumpIfNotNull(&end[6])
.JumpIfUndefined(&end[7])
.JumpIfNotUndefined(&end[8])
.JumpIfNotHole(&end[9])
.LoadLiteral(ast_factory.prototype_string())
.JumpIfJSReceiver(&end[8]);
.JumpIfJSReceiver(&end[10]);
}
// Perform an operation that returns boolean value to
@ -442,9 +451,6 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
scorecard[Bytecodes::ToByte(Bytecode::kBitwiseOrSmi)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kShiftLeftSmi)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kShiftRightSmi)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kTestUndetectable)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kTestUndefined)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kTestNull)] = 1;
}
if (!FLAG_type_profile) {

View File

@ -404,25 +404,6 @@ TEST_F(BytecodePeepholeOptimizerTest, MergeLdaZeroWithBinaryOp) {
}
}
TEST_F(BytecodePeepholeOptimizerTest, MergeLdaNullOrUndefinedWithCompareOp) {
Bytecode first_bytecodes[] = {Bytecode::kLdaUndefined, Bytecode::kLdaNull};
for (auto first_bytecode : first_bytecodes) {
uint32_t reg_operand = Register(0).ToOperand();
uint32_t idx_operand = 1;
BytecodeNode first(first_bytecode);
BytecodeNode second(Bytecode::kTestEqual, reg_operand, idx_operand);
optimizer()->Write(&first);
optimizer()->Write(&second);
Flush();
CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written().bytecode(), Bytecode::kTestUndetectable);
CHECK_EQ(last_written().operand_count(), 1);
CHECK_EQ(last_written().operand(0), reg_operand);
Reset();
}
}
} // namespace interpreter
} // namespace internal
} // namespace v8