Commit 935340a4 authored by klaasb's avatar klaasb Committed by Commit bot

[interpreter] VisitForTest for bytecode generator

Adds TestResultScope and uses it to directly jump/fall through to the
correct branch in expressions used as branch conditions.
Should enable nicer TurboFan-graphs for easier control-flow
transformations in the future.

BUG=v8:4280
LOG=n

Review-Url: https://codereview.chromium.org/2242463002
Cr-Commit-Position: refs/heads/master@{#38634}
parent 160d0a18
......@@ -1381,6 +1381,7 @@ v8_source_set("v8_base") {
"src/interpreter/bytecode-flags.h",
"src/interpreter/bytecode-generator.cc",
"src/interpreter/bytecode-generator.h",
"src/interpreter/bytecode-label.cc",
"src/interpreter/bytecode-label.h",
"src/interpreter/bytecode-peephole-optimizer.cc",
"src/interpreter/bytecode-peephole-optimizer.h",
......
......@@ -8,6 +8,7 @@
#include "src/code-stubs.h"
#include "src/compiler.h"
#include "src/interpreter/bytecode-flags.h"
#include "src/interpreter/bytecode-label.h"
#include "src/interpreter/bytecode-register-allocator.h"
#include "src/interpreter/control-flow-builders.h"
#include "src/objects.h"
......@@ -445,6 +446,12 @@ class BytecodeGenerator::ExpressionResultScope {
bool IsEffect() const { return kind_ == Expression::kEffect; }
bool IsValue() const { return kind_ == Expression::kValue; }
bool IsTest() const { return kind_ == Expression::kTest; }
TestResultScope* AsTest() {
DCHECK(IsTest());
return reinterpret_cast<TestResultScope*>(this);
}
virtual void SetResultInAccumulator() = 0;
virtual void SetResultInRegister(Register reg) = 0;
......@@ -535,6 +542,61 @@ class BytecodeGenerator::RegisterResultScope final
Register result_register_;
};
// Scoped class used when the result of the current expression to be
// evaluated is only tested with jumps to two branches.
class BytecodeGenerator::TestResultScope final : public ExpressionResultScope {
public:
TestResultScope(BytecodeGenerator* generator, BytecodeLabels* then_labels,
BytecodeLabels* else_labels, TestFallthrough fallthrough)
: ExpressionResultScope(generator, Expression::kTest),
then_labels_(then_labels),
else_labels_(else_labels),
fallthrough_(fallthrough),
result_consumed_by_test_(false) {}
virtual void SetResultInAccumulator() { set_result_identified(); }
virtual void SetResultInRegister(Register reg) {
builder()->LoadAccumulatorWithRegister(reg);
set_result_identified();
}
// Used when code special cases for TestResultScope and consumes any
// possible value by testing and jumping to a then/else label.
void SetResultConsumedByTest() {
result_consumed_by_test_ = true;
set_result_identified();
}
bool ResultConsumedByTest() { return result_consumed_by_test_; }
BytecodeLabel* NewThenLabel() { return then_labels_->New(); }
BytecodeLabel* NewElseLabel() { return else_labels_->New(); }
BytecodeLabels* then_labels() const { return then_labels_; }
BytecodeLabels* else_labels() const { return else_labels_; }
TestFallthrough fallthrough() const { return fallthrough_; }
TestFallthrough inverted_fallthrough() const {
switch (fallthrough_) {
case TestFallthrough::kThen:
return TestFallthrough::kElse;
case TestFallthrough::kElse:
return TestFallthrough::kThen;
default:
return TestFallthrough::kNone;
}
}
private:
BytecodeLabels* then_labels_;
BytecodeLabels* else_labels_;
TestFallthrough fallthrough_;
bool result_consumed_by_test_;
DISALLOW_COPY_AND_ASSIGN(TestResultScope);
};
// Used to build a list of global declaration initial value pairs.
class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject {
public:
......@@ -983,7 +1045,6 @@ void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
builder()->SetStatementPosition(stmt);
BytecodeLabel else_label, end_label;
if (stmt->condition()->ToBooleanIsTrue()) {
// Generate then block unconditionally as always true.
Visit(stmt->then_statement());
......@@ -996,15 +1057,20 @@ void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
// TODO(oth): If then statement is BreakStatement or
// ContinueStatement we can reduce number of generated
// jump/jump_ifs here. See BasicLoops test.
VisitForAccumulatorValue(stmt->condition());
builder()->JumpIfFalse(&else_label);
BytecodeLabel end_label;
BytecodeLabels then_labels(zone()), else_labels(zone());
VisitForTest(stmt->condition(), &then_labels, &else_labels,
TestFallthrough::kThen);
then_labels.Bind(builder());
Visit(stmt->then_statement());
if (stmt->HasElseStatement()) {
builder()->Jump(&end_label);
builder()->Bind(&else_label);
else_labels.Bind(builder());
Visit(stmt->else_statement());
} else {
builder()->Bind(&else_label);
else_labels.Bind(builder());
}
builder()->Bind(&end_label);
}
......@@ -1113,6 +1179,7 @@ void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
VisitIterationHeader(stmt, &loop_builder);
VisitIterationBody(stmt, &loop_builder);
builder()->SetExpressionAsStatementPosition(stmt->cond());
// TODO(klaasb) VisitForTest for loop conditions
VisitForAccumulatorValue(stmt->cond());
loop_builder.JumpToHeaderIfTrue();
}
......@@ -1129,6 +1196,7 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
VisitIterationHeader(stmt, &loop_builder);
if (!stmt->cond()->ToBooleanIsTrue()) {
builder()->SetExpressionAsStatementPosition(stmt->cond());
// TODO(klaasb) VisitForTest for loop conditions
VisitForAccumulatorValue(stmt->cond());
loop_builder.BreakIfFalse();
}
......@@ -1151,6 +1219,7 @@ void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
VisitIterationHeader(stmt, &loop_builder);
if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) {
builder()->SetExpressionAsStatementPosition(stmt->cond());
// TODO(klaasb) VisitForTest for loop conditions
VisitForAccumulatorValue(stmt->cond());
loop_builder.BreakIfFalse();
}
......@@ -1568,21 +1637,27 @@ void BytecodeGenerator::VisitDoExpression(DoExpression* expr) {
}
void BytecodeGenerator::VisitConditional(Conditional* expr) {
// TODO(rmcilroy): Spot easy cases where there code would not need to
// emit the then block or the else block, e.g. condition is
// obviously true/1/false/0.
BytecodeLabel else_label, end_label;
if (expr->condition()->ToBooleanIsTrue()) {
// Generate then block unconditionally as always true.
VisitForAccumulatorValue(expr->then_expression());
} else if (expr->condition()->ToBooleanIsFalse()) {
// Generate else block unconditionally if it exists.
VisitForAccumulatorValue(expr->else_expression());
} else {
BytecodeLabel end_label;
BytecodeLabels then_labels(zone()), else_labels(zone());
VisitForAccumulatorValue(expr->condition());
builder()->JumpIfFalse(&else_label);
VisitForTest(expr->condition(), &then_labels, &else_labels,
TestFallthrough::kThen);
VisitForAccumulatorValue(expr->then_expression());
builder()->Jump(&end_label);
then_labels.Bind(builder());
VisitForAccumulatorValue(expr->then_expression());
builder()->Jump(&end_label);
builder()->Bind(&else_label);
VisitForAccumulatorValue(expr->else_expression());
builder()->Bind(&end_label);
else_labels.Bind(builder());
VisitForAccumulatorValue(expr->else_expression());
builder()->Bind(&end_label);
}
execution_result()->SetResultInAccumulator();
}
......@@ -1866,6 +1941,9 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
switch (variable->location()) {
case VariableLocation::LOCAL: {
Register source(Register(variable->index()));
// We need to load the variable into the accumulator, even when in a
// VisitForRegisterScope, in order to avoid register aliasing if
// subsequent expressions assign to the same variable.
builder()->LoadAccumulatorWithRegister(source);
BuildHoleCheckForVariableLoad(variable);
break;
......@@ -1874,6 +1952,9 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
// The parameter indices are shifted by 1 (receiver is variable
// index -1 but is parameter index 0 in BytecodeArrayBuilder).
Register source = builder()->Parameter(variable->index() + 1);
// We need to load the variable into the accumulator, even when in a
// VisitForRegisterScope, in order to avoid register aliasing if
// subsequent expressions assign to the same variable.
builder()->LoadAccumulatorWithRegister(source);
BuildHoleCheckForVariableLoad(variable);
break;
......@@ -2714,9 +2795,21 @@ void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) {
}
void BytecodeGenerator::VisitNot(UnaryOperation* expr) {
VisitForAccumulatorValue(expr->expression());
builder()->LogicalNot();
execution_result()->SetResultInAccumulator();
if (execution_result()->IsEffect()) {
VisitForEffect(expr->expression());
} else if (execution_result()->IsTest()) {
TestResultScope* test_result = execution_result()->AsTest();
// No actual logical negation happening, we just swap the control flow by
// swapping the target labels and the fallthrough branch.
VisitForTest(expr->expression(), test_result->else_labels(),
test_result->then_labels(),
test_result->inverted_fallthrough());
test_result->SetResultConsumedByTest();
} else {
VisitForAccumulatorValue(expr->expression());
builder()->LogicalNot();
execution_result()->SetResultInAccumulator();
}
}
void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
......@@ -2991,36 +3084,72 @@ void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) {
Expression* left = binop->left();
Expression* right = binop->right();
// Short-circuit evaluation- If it is known that left is always true,
// no need to visit right
if (left->ToBooleanIsTrue()) {
VisitForAccumulatorValue(left);
if (execution_result()->IsTest()) {
TestResultScope* test_result = execution_result()->AsTest();
if (left->ToBooleanIsTrue() || right->ToBooleanIsTrue()) {
builder()->Jump(test_result->NewThenLabel());
} else if (left->ToBooleanIsFalse() && right->ToBooleanIsFalse()) {
builder()->Jump(test_result->NewElseLabel());
} else {
BytecodeLabels test_right(zone());
VisitForTest(left, test_result->then_labels(), &test_right,
TestFallthrough::kElse);
test_right.Bind(builder());
VisitForTest(right, test_result->then_labels(),
test_result->else_labels(), test_result->fallthrough());
}
test_result->SetResultConsumedByTest();
} else {
BytecodeLabel end_label;
VisitForAccumulatorValue(left);
builder()->JumpIfTrue(&end_label);
VisitForAccumulatorValue(right);
builder()->Bind(&end_label);
if (left->ToBooleanIsTrue()) {
VisitForAccumulatorValue(left);
} else if (left->ToBooleanIsFalse()) {
VisitForAccumulatorValue(right);
} else {
BytecodeLabel end_label;
VisitForAccumulatorValue(left);
builder()->JumpIfTrue(&end_label);
VisitForAccumulatorValue(right);
builder()->Bind(&end_label);
}
execution_result()->SetResultInAccumulator();
}
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) {
Expression* left = binop->left();
Expression* right = binop->right();
// Short-circuit evaluation- If it is known that left is always false,
// no need to visit right
if (left->ToBooleanIsFalse()) {
VisitForAccumulatorValue(left);
if (execution_result()->IsTest()) {
TestResultScope* test_result = execution_result()->AsTest();
if (left->ToBooleanIsFalse() || right->ToBooleanIsFalse()) {
builder()->Jump(test_result->NewElseLabel());
} else if (left->ToBooleanIsTrue() && right->ToBooleanIsTrue()) {
builder()->Jump(test_result->NewThenLabel());
} else {
BytecodeLabels test_right(zone());
VisitForTest(left, &test_right, test_result->else_labels(),
TestFallthrough::kThen);
test_right.Bind(builder());
VisitForTest(right, test_result->then_labels(),
test_result->else_labels(), test_result->fallthrough());
}
test_result->SetResultConsumedByTest();
} else {
BytecodeLabel end_label;
VisitForAccumulatorValue(left);
builder()->JumpIfFalse(&end_label);
VisitForAccumulatorValue(right);
builder()->Bind(&end_label);
if (left->ToBooleanIsFalse()) {
VisitForAccumulatorValue(left);
} else if (left->ToBooleanIsTrue()) {
VisitForAccumulatorValue(right);
} else {
BytecodeLabel end_label;
VisitForAccumulatorValue(left);
builder()->JumpIfFalse(&end_label);
VisitForAccumulatorValue(right);
builder()->Bind(&end_label);
}
execution_result()->SetResultInAccumulator();
}
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitRewritableExpression(RewritableExpression* expr) {
......@@ -3262,6 +3391,36 @@ void BytecodeGenerator::VisitForRegisterValue(Expression* expr,
builder()->StoreAccumulatorInRegister(destination);
}
// Visits the expression |expr| for testing its boolean value and jumping to the
// |then| or |other| label depending on value and short-circuit semantics
void BytecodeGenerator::VisitForTest(Expression* expr,
BytecodeLabels* then_labels,
BytecodeLabels* else_labels,
TestFallthrough fallthrough) {
bool result_consumed;
{
// To make sure that all temporary registers are returned before generating
// jumps below, we ensure that the result scope is deleted before doing so.
// Dead registers might be materialized otherwise.
TestResultScope test_result(this, then_labels, else_labels, fallthrough);
Visit(expr);
result_consumed = test_result.ResultConsumedByTest();
}
if (!result_consumed) {
switch (fallthrough) {
case TestFallthrough::kThen:
builder()->JumpIfFalse(else_labels->New());
break;
case TestFallthrough::kElse:
builder()->JumpIfTrue(then_labels->New());
break;
case TestFallthrough::kNone:
builder()->JumpIfTrue(then_labels->New());
builder()->Jump(else_labels->New());
}
}
}
void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) {
ContextScope context_scope(this, scope);
DCHECK(scope->declarations()->is_empty());
......
......@@ -48,6 +48,9 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
class GlobalDeclarationsBuilder;
class RegisterResultScope;
class RegisterAllocationScope;
class TestResultScope;
enum class TestFallthrough { kThen, kElse, kNone };
void GenerateBytecode();
void GenerateBytecodeBody();
......@@ -162,6 +165,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
MUST_USE_RESULT Register VisitForRegisterValue(Expression* expr);
void VisitForRegisterValue(Expression* expr, Register destination);
void VisitForEffect(Expression* expr);
void VisitForTest(Expression* expr, BytecodeLabels* then_labels,
BytecodeLabels* else_labels, TestFallthrough fallthrough);
// Methods for tracking and remapping register.
void RecordStoreToRegister(Register reg);
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/interpreter/bytecode-label.h"
#include "src/interpreter/bytecode-array-builder.h"
namespace v8 {
namespace internal {
namespace interpreter {
BytecodeLabel* BytecodeLabels::New() {
labels_.push_back(BytecodeLabel());
return &labels_.back();
}
void BytecodeLabels::Bind(BytecodeArrayBuilder* builder) {
for (auto label : labels_) {
builder->Bind(&label);
}
}
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -5,10 +5,14 @@
#ifndef V8_INTERPRETER_BYTECODE_LABEL_H_
#define V8_INTERPRETER_BYTECODE_LABEL_H_
#include "src/zone-containers.h"
namespace v8 {
namespace internal {
namespace interpreter {
class BytecodeArrayBuilder;
// A label representing a branch target in a bytecode array. When a
// label is bound, it represents a known position in the bytecode
// array. For labels that are forward references there can be at most
......@@ -49,6 +53,21 @@ class BytecodeLabel final {
friend class BytecodeArrayWriter;
};
// Class representing a branch target of multiple jumps.
class BytecodeLabels {
public:
explicit BytecodeLabels(Zone* zone) : labels_(zone) {}
BytecodeLabel* New();
void Bind(BytecodeArrayBuilder* builder);
private:
ZoneVector<BytecodeLabel> labels_;
DISALLOW_COPY_AND_ASSIGN(BytecodeLabels);
};
} // namespace interpreter
} // namespace internal
} // namespace v8
......
......@@ -985,6 +985,7 @@
'interpreter/bytecode-flags.h',
'interpreter/bytecode-generator.cc',
'interpreter/bytecode-generator.h',
'interpreter/bytecode-label.cc',
'interpreter/bytecode-label.h',
'interpreter/bytecode-peephole-optimizer.cc',
'interpreter/bytecode-peephole-optimizer.h',
......
......@@ -18,10 +18,10 @@ bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), U8(1),
B(Star), R(0),
/* 45 S> */ B(JumpIfToBooleanTrue), U8(5),
/* 45 S> */ B(JumpIfToBooleanTrue), U8(7),
B(LdaZero),
/* 56 E> */ B(TestLessThan), R(0),
B(JumpIfToBooleanFalse), U8(5),
B(JumpIfFalse), U8(5),
/* 63 S> */ B(LdaSmi), U8(1),
/* 75 S> */ B(Return),
B(LdaUndefined),
......@@ -43,10 +43,10 @@ bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), U8(1),
B(Star), R(0),
/* 45 S> */ B(JumpIfToBooleanFalse), U8(5),
/* 45 S> */ B(JumpIfToBooleanFalse), U8(10),
B(LdaZero),
/* 56 E> */ B(TestLessThan), R(0),
B(JumpIfToBooleanFalse), U8(5),
B(JumpIfFalse), U8(5),
/* 63 S> */ B(LdaSmi), U8(1),
/* 75 S> */ B(Return),
B(LdaUndefined),
......@@ -68,10 +68,10 @@ bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), U8(1),
B(Star), R(0),
/* 45 S> */ B(JumpIfToBooleanTrue), U8(5),
/* 45 S> */ B(JumpIfToBooleanTrue), U8(7),
B(LdaZero),
/* 57 E> */ B(TestLessThan), R(0),
B(JumpIfToBooleanFalse), U8(6),
B(JumpIfFalse), U8(6),
B(LdaSmi), U8(2),
B(Jump), U8(4),
B(LdaSmi), U8(3),
......
......@@ -13,14 +13,10 @@ snippet: "
"
frame size: 0
parameter count: 1
bytecode array length: 12
bytecode array length: 4
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaSmi), U8(1),
B(JumpIfToBooleanFalse), U8(6),
B(LdaSmi), U8(2),
B(Jump), U8(4),
B(LdaSmi), U8(3),
/* 34 S> */ B(LdaSmi), U8(2),
/* 52 S> */ B(Return),
]
constant pool: [
......@@ -34,19 +30,58 @@ snippet: "
"
frame size: 0
parameter count: 1
bytecode array length: 20
bytecode array length: 4
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaSmi), U8(1),
B(JumpIfToBooleanFalse), U8(14),
/* 34 S> */ B(LdaSmi), U8(3),
/* 60 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
return 0 < 1 ? 2 : 3;
"
frame size: 1
parameter count: 1
bytecode array length: 17
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaZero),
B(Star), R(0),
B(LdaSmi), U8(1),
/* 43 E> */ B(TestLessThan), R(0),
B(JumpIfFalse), U8(6),
B(LdaSmi), U8(2),
B(JumpIfToBooleanFalse), U8(6),
B(LdaSmi), U8(3),
B(Jump), U8(4),
B(LdaSmi), U8(4),
B(LdaSmi), U8(3),
/* 56 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
var x = 0;
return x ? 2 : 3;
"
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(JumpIfToBooleanFalse), U8(6),
B(LdaSmi), U8(2),
B(Jump), U8(4),
B(LdaSmi), U8(5),
/* 60 S> */ B(Return),
B(LdaSmi), U8(3),
/* 63 S> */ B(Return),
]
constant pool: [
]
......
......@@ -13,7 +13,7 @@ snippet: "
"
frame size: 16
parameter count: 1
bytecode array length: 283
bytecode array length: 282
bytecodes: [
/* 30 E> */ B(StackCheck),
B(LdaZero),
......@@ -70,11 +70,10 @@ bytecodes: [
B(Star), R(11),
B(LdaZero),
B(TestEqualStrict), R(3),
B(JumpIfTrue), U8(5),
B(JumpIfTrue), U8(123),
B(LdaUndefined),
B(TestEqualStrict), R(1),
B(ToBooleanLogicalNot),
B(JumpIfFalse), U8(118),
B(JumpIfTrue), U8(118),
B(LdrNamedProperty), R(1), U8(6), U8(13), R(5),
B(LdaNull),
B(TestEqual), R(5),
......@@ -144,7 +143,7 @@ constant pool: [
handlers: [
[7, 121, 127],
[10, 80, 82],
[200, 210, 212],
[199, 209, 211],
]
---
......@@ -154,7 +153,7 @@ snippet: "
"
frame size: 17
parameter count: 1
bytecode array length: 296
bytecode array length: 295
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaConstant), U8(0),
......@@ -213,11 +212,10 @@ bytecodes: [
B(Star), R(12),
B(LdaZero),
B(TestEqualStrict), R(3),
B(JumpIfTrue), U8(5),
B(JumpIfTrue), U8(123),
B(LdaUndefined),
B(TestEqualStrict), R(1),
B(ToBooleanLogicalNot),
B(JumpIfFalse), U8(118),
B(JumpIfTrue), U8(118),
B(LdrNamedProperty), R(1), U8(6), U8(13), R(5),
B(LdaNull),
B(TestEqual), R(5),
......@@ -292,7 +290,7 @@ constant pool: [
handlers: [
[11, 124, 130],
[14, 83, 85],
[204, 214, 216],
[203, 213, 215],
]
---
......@@ -304,7 +302,7 @@ snippet: "
"
frame size: 16
parameter count: 1
bytecode array length: 299
bytecode array length: 298
bytecodes: [
/* 30 E> */ B(StackCheck),
B(LdaZero),
......@@ -369,11 +367,10 @@ bytecodes: [
B(Star), R(11),
B(LdaZero),
B(TestEqualStrict), R(3),
B(JumpIfTrue), U8(5),
B(JumpIfTrue), U8(123),
B(LdaUndefined),
B(TestEqualStrict), R(1),
B(ToBooleanLogicalNot),
B(JumpIfFalse), U8(118),
B(JumpIfTrue), U8(118),
B(LdrNamedProperty), R(1), U8(6), U8(13), R(5),
B(LdaNull),
B(TestEqual), R(5),
......@@ -443,7 +440,7 @@ constant pool: [
handlers: [
[7, 137, 143],
[10, 96, 98],
[216, 226, 228],
[215, 225, 227],
]
---
......@@ -453,7 +450,7 @@ snippet: "
"
frame size: 15
parameter count: 1
bytecode array length: 309
bytecode array length: 308
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(1), R(8),
......@@ -515,11 +512,10 @@ bytecodes: [
B(Star), R(10),
B(LdaZero),
B(TestEqualStrict), R(2),
B(JumpIfTrue), U8(5),
B(JumpIfTrue), U8(123),
B(LdaUndefined),
B(TestEqualStrict), R(0),
B(ToBooleanLogicalNot),
B(JumpIfFalse), U8(118),
B(JumpIfTrue), U8(118),
B(LdrNamedProperty), R(0), U8(8), U8(17), R(4),
B(LdaNull),
B(TestEqual), R(4),
......@@ -596,6 +592,6 @@ constant pool: [
handlers: [
[15, 137, 143],
[18, 96, 98],
[217, 227, 229],
[216, 226, 228],
]
......@@ -264,7 +264,7 @@ snippet: "
"
frame size: 18
parameter count: 1
bytecode array length: 769
bytecode array length: 768
bytecodes: [
B(Ldar), R(new_target),
B(JumpIfUndefined), U8(26),
......@@ -316,7 +316,7 @@ bytecodes: [
B(Star), R(6),
B(LdaZero),
B(Star), R(5),
B(JumpConstant), U8(16),
B(JumpConstant), U8(17),
B(Ldar), R(10),
/* 11 E> */ B(Throw),
B(LdaConstant), U8(0),
......@@ -452,12 +452,11 @@ bytecodes: [
B(LdrContextSlot), R(1), U8(9), R(11),
B(LdaZero),
B(TestEqualStrict), R(11),
B(JumpIfTrue), U8(9),
B(JumpIfTrueConstant), U8(15),
B(LdrContextSlot), R(1), U8(7), R(11),
B(LdaUndefined),
B(TestEqualStrict), R(11),
B(ToBooleanLogicalNot),
B(JumpIfFalseConstant), U8(15),
B(JumpIfTrueConstant), U8(16),
B(LdrContextSlot), R(1), U8(7), R(11),
B(LdaNamedProperty), R(11), U8(12), U8(13),
B(StaContextSlot), R(1), U8(11),
......@@ -596,11 +595,12 @@ constant pool: [
InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE,
kInstanceTypeDontCare,
kInstanceTypeDontCare,
kInstanceTypeDontCare,
]
handlers: [
[41, 688, 694],
[41, 687, 693],
[147, 442, 448],
[150, 396, 398],
[545, 557, 559],
[544, 556, 558],
]
......@@ -737,3 +737,47 @@ constant pool: [
handlers: [
]
---
snippet: "
function f(a, b) {
if (a == b || a < 0) {
return 1;
} else if (a > 0 && b > 0) {
return 0;
} else {
return -1;
}
};
f(-1, 1);
"
frame size: 0
parameter count: 3
bytecode array length: 32
bytecodes: [
/* 10 E> */ B(StackCheck),
/* 21 S> */ B(Ldar), R(arg1),
/* 27 E> */ B(TestEqual), R(arg0),
B(JumpIfTrue), U8(7),
B(LdaZero),
/* 37 E> */ B(TestLessThan), R(arg0),
B(JumpIfFalse), U8(5),
/* 48 S> */ B(LdaSmi), U8(1),
/* 133 S> */ B(Return),
/* 67 S> */ B(LdaZero),
/* 73 E> */ B(TestGreaterThan), R(arg0),
B(JumpIfFalse), U8(9),
B(LdaZero),
/* 82 E> */ B(TestGreaterThan), R(arg1),
B(JumpIfFalse), U8(4),
/* 93 S> */ B(LdaZero),
/* 133 S> */ B(Return),
/* 118 S> */ B(LdaSmi), U8(-1),
/* 133 S> */ B(Return),
B(LdaUndefined),
/* 133 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
......@@ -705,6 +705,17 @@ TEST(IfConditions) {
" }\n"
"};\n"
"f();\n",
"function f(a, b) {\n"
" if (a == b || a < 0) {\n"
" return 1;\n"
" } else if (a > 0 && b > 0) {\n"
" return 0;\n"
" } else {\n"
" return -1;\n"
" }\n"
"};\n"
"f(-1, 1);\n",
};
CHECK(CompareTexts(BuildActual(printer, snippets),
......@@ -1615,6 +1626,11 @@ TEST(Conditional) {
"return 1 ? 2 : 3;\n",
"return 1 ? 2 ? 3 : 4 : 5;\n",
"return 0 < 1 ? 2 : 3;\n",
"var x = 0;\n"
"return x ? 2 : 3;\n",
};
CHECK(CompareTexts(BuildActual(printer, snippets),
......
......@@ -287,7 +287,8 @@ TEST(MultipleFuncsConditional) {
v8::HandleScope scope(CcTest::isolate());
v8::Local<v8::Script> script = Compile(CcTest::isolate(),
"fun1 = 0 ?\n"
"var x = 0;\n"
"fun1 = x ?\n"
" function() { return 1; } :\n"
" function() { return 2; }");
CheckFunctionName(script, "return 1", "fun1");
......@@ -301,9 +302,10 @@ TEST(MultipleFuncsInLiteral) {
v8::Local<v8::Script> script =
Compile(CcTest::isolate(),
"var x = 0;\n"
"function MyClass() {}\n"
"MyClass.prototype = {\n"
" method1: 0 ? function() { return 1; } :\n"
" method1: x ? function() { return 1; } :\n"
" function() { return 2; } }");
CheckFunctionName(script, "return 1", "MyClass.method1");
CheckFunctionName(script, "return 2", "MyClass.method1");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment