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") { ...@@ -1381,6 +1381,7 @@ v8_source_set("v8_base") {
"src/interpreter/bytecode-flags.h", "src/interpreter/bytecode-flags.h",
"src/interpreter/bytecode-generator.cc", "src/interpreter/bytecode-generator.cc",
"src/interpreter/bytecode-generator.h", "src/interpreter/bytecode-generator.h",
"src/interpreter/bytecode-label.cc",
"src/interpreter/bytecode-label.h", "src/interpreter/bytecode-label.h",
"src/interpreter/bytecode-peephole-optimizer.cc", "src/interpreter/bytecode-peephole-optimizer.cc",
"src/interpreter/bytecode-peephole-optimizer.h", "src/interpreter/bytecode-peephole-optimizer.h",
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "src/code-stubs.h" #include "src/code-stubs.h"
#include "src/compiler.h" #include "src/compiler.h"
#include "src/interpreter/bytecode-flags.h" #include "src/interpreter/bytecode-flags.h"
#include "src/interpreter/bytecode-label.h"
#include "src/interpreter/bytecode-register-allocator.h" #include "src/interpreter/bytecode-register-allocator.h"
#include "src/interpreter/control-flow-builders.h" #include "src/interpreter/control-flow-builders.h"
#include "src/objects.h" #include "src/objects.h"
...@@ -445,6 +446,12 @@ class BytecodeGenerator::ExpressionResultScope { ...@@ -445,6 +446,12 @@ class BytecodeGenerator::ExpressionResultScope {
bool IsEffect() const { return kind_ == Expression::kEffect; } bool IsEffect() const { return kind_ == Expression::kEffect; }
bool IsValue() const { return kind_ == Expression::kValue; } 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 SetResultInAccumulator() = 0;
virtual void SetResultInRegister(Register reg) = 0; virtual void SetResultInRegister(Register reg) = 0;
...@@ -535,6 +542,61 @@ class BytecodeGenerator::RegisterResultScope final ...@@ -535,6 +542,61 @@ class BytecodeGenerator::RegisterResultScope final
Register result_register_; 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. // Used to build a list of global declaration initial value pairs.
class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject { class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject {
public: public:
...@@ -983,7 +1045,6 @@ void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { ...@@ -983,7 +1045,6 @@ void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
builder()->SetStatementPosition(stmt); builder()->SetStatementPosition(stmt);
BytecodeLabel else_label, end_label;
if (stmt->condition()->ToBooleanIsTrue()) { if (stmt->condition()->ToBooleanIsTrue()) {
// Generate then block unconditionally as always true. // Generate then block unconditionally as always true.
Visit(stmt->then_statement()); Visit(stmt->then_statement());
...@@ -996,15 +1057,20 @@ void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { ...@@ -996,15 +1057,20 @@ void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
// TODO(oth): If then statement is BreakStatement or // TODO(oth): If then statement is BreakStatement or
// ContinueStatement we can reduce number of generated // ContinueStatement we can reduce number of generated
// jump/jump_ifs here. See BasicLoops test. // jump/jump_ifs here. See BasicLoops test.
VisitForAccumulatorValue(stmt->condition()); BytecodeLabel end_label;
builder()->JumpIfFalse(&else_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()); Visit(stmt->then_statement());
if (stmt->HasElseStatement()) { if (stmt->HasElseStatement()) {
builder()->Jump(&end_label); builder()->Jump(&end_label);
builder()->Bind(&else_label); else_labels.Bind(builder());
Visit(stmt->else_statement()); Visit(stmt->else_statement());
} else { } else {
builder()->Bind(&else_label); else_labels.Bind(builder());
} }
builder()->Bind(&end_label); builder()->Bind(&end_label);
} }
...@@ -1113,6 +1179,7 @@ void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { ...@@ -1113,6 +1179,7 @@ void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
VisitIterationHeader(stmt, &loop_builder); VisitIterationHeader(stmt, &loop_builder);
VisitIterationBody(stmt, &loop_builder); VisitIterationBody(stmt, &loop_builder);
builder()->SetExpressionAsStatementPosition(stmt->cond()); builder()->SetExpressionAsStatementPosition(stmt->cond());
// TODO(klaasb) VisitForTest for loop conditions
VisitForAccumulatorValue(stmt->cond()); VisitForAccumulatorValue(stmt->cond());
loop_builder.JumpToHeaderIfTrue(); loop_builder.JumpToHeaderIfTrue();
} }
...@@ -1129,6 +1196,7 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { ...@@ -1129,6 +1196,7 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
VisitIterationHeader(stmt, &loop_builder); VisitIterationHeader(stmt, &loop_builder);
if (!stmt->cond()->ToBooleanIsTrue()) { if (!stmt->cond()->ToBooleanIsTrue()) {
builder()->SetExpressionAsStatementPosition(stmt->cond()); builder()->SetExpressionAsStatementPosition(stmt->cond());
// TODO(klaasb) VisitForTest for loop conditions
VisitForAccumulatorValue(stmt->cond()); VisitForAccumulatorValue(stmt->cond());
loop_builder.BreakIfFalse(); loop_builder.BreakIfFalse();
} }
...@@ -1151,6 +1219,7 @@ void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { ...@@ -1151,6 +1219,7 @@ void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
VisitIterationHeader(stmt, &loop_builder); VisitIterationHeader(stmt, &loop_builder);
if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) { if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) {
builder()->SetExpressionAsStatementPosition(stmt->cond()); builder()->SetExpressionAsStatementPosition(stmt->cond());
// TODO(klaasb) VisitForTest for loop conditions
VisitForAccumulatorValue(stmt->cond()); VisitForAccumulatorValue(stmt->cond());
loop_builder.BreakIfFalse(); loop_builder.BreakIfFalse();
} }
...@@ -1568,21 +1637,27 @@ void BytecodeGenerator::VisitDoExpression(DoExpression* expr) { ...@@ -1568,21 +1637,27 @@ void BytecodeGenerator::VisitDoExpression(DoExpression* expr) {
} }
void BytecodeGenerator::VisitConditional(Conditional* expr) { void BytecodeGenerator::VisitConditional(Conditional* expr) {
// TODO(rmcilroy): Spot easy cases where there code would not need to if (expr->condition()->ToBooleanIsTrue()) {
// emit the then block or the else block, e.g. condition is // Generate then block unconditionally as always true.
// obviously true/1/false/0. VisitForAccumulatorValue(expr->then_expression());
} else if (expr->condition()->ToBooleanIsFalse()) {
BytecodeLabel else_label, end_label; // 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()); VisitForTest(expr->condition(), &then_labels, &else_labels,
builder()->JumpIfFalse(&else_label); TestFallthrough::kThen);
VisitForAccumulatorValue(expr->then_expression()); then_labels.Bind(builder());
builder()->Jump(&end_label); VisitForAccumulatorValue(expr->then_expression());
builder()->Jump(&end_label);
builder()->Bind(&else_label); else_labels.Bind(builder());
VisitForAccumulatorValue(expr->else_expression()); VisitForAccumulatorValue(expr->else_expression());
builder()->Bind(&end_label); builder()->Bind(&end_label);
}
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
...@@ -1866,6 +1941,9 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, ...@@ -1866,6 +1941,9 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
switch (variable->location()) { switch (variable->location()) {
case VariableLocation::LOCAL: { case VariableLocation::LOCAL: {
Register source(Register(variable->index())); 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); builder()->LoadAccumulatorWithRegister(source);
BuildHoleCheckForVariableLoad(variable); BuildHoleCheckForVariableLoad(variable);
break; break;
...@@ -1874,6 +1952,9 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, ...@@ -1874,6 +1952,9 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
// The parameter indices are shifted by 1 (receiver is variable // The parameter indices are shifted by 1 (receiver is variable
// index -1 but is parameter index 0 in BytecodeArrayBuilder). // index -1 but is parameter index 0 in BytecodeArrayBuilder).
Register source = builder()->Parameter(variable->index() + 1); 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); builder()->LoadAccumulatorWithRegister(source);
BuildHoleCheckForVariableLoad(variable); BuildHoleCheckForVariableLoad(variable);
break; break;
...@@ -2714,9 +2795,21 @@ void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) { ...@@ -2714,9 +2795,21 @@ void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) {
} }
void BytecodeGenerator::VisitNot(UnaryOperation* expr) { void BytecodeGenerator::VisitNot(UnaryOperation* expr) {
VisitForAccumulatorValue(expr->expression()); if (execution_result()->IsEffect()) {
builder()->LogicalNot(); VisitForEffect(expr->expression());
execution_result()->SetResultInAccumulator(); } 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) { void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
...@@ -2991,36 +3084,72 @@ void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { ...@@ -2991,36 +3084,72 @@ void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) {
Expression* left = binop->left(); Expression* left = binop->left();
Expression* right = binop->right(); Expression* right = binop->right();
// Short-circuit evaluation- If it is known that left is always true, if (execution_result()->IsTest()) {
// no need to visit right TestResultScope* test_result = execution_result()->AsTest();
if (left->ToBooleanIsTrue()) {
VisitForAccumulatorValue(left); 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 { } else {
BytecodeLabel end_label; if (left->ToBooleanIsTrue()) {
VisitForAccumulatorValue(left); VisitForAccumulatorValue(left);
builder()->JumpIfTrue(&end_label); } else if (left->ToBooleanIsFalse()) {
VisitForAccumulatorValue(right); VisitForAccumulatorValue(right);
builder()->Bind(&end_label); } 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) { void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) {
Expression* left = binop->left(); Expression* left = binop->left();
Expression* right = binop->right(); Expression* right = binop->right();
// Short-circuit evaluation- If it is known that left is always false, if (execution_result()->IsTest()) {
// no need to visit right TestResultScope* test_result = execution_result()->AsTest();
if (left->ToBooleanIsFalse()) {
VisitForAccumulatorValue(left); 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 { } else {
BytecodeLabel end_label; if (left->ToBooleanIsFalse()) {
VisitForAccumulatorValue(left); VisitForAccumulatorValue(left);
builder()->JumpIfFalse(&end_label); } else if (left->ToBooleanIsTrue()) {
VisitForAccumulatorValue(right); VisitForAccumulatorValue(right);
builder()->Bind(&end_label); } 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) { void BytecodeGenerator::VisitRewritableExpression(RewritableExpression* expr) {
...@@ -3262,6 +3391,36 @@ void BytecodeGenerator::VisitForRegisterValue(Expression* expr, ...@@ -3262,6 +3391,36 @@ void BytecodeGenerator::VisitForRegisterValue(Expression* expr,
builder()->StoreAccumulatorInRegister(destination); 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) { void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) {
ContextScope context_scope(this, scope); ContextScope context_scope(this, scope);
DCHECK(scope->declarations()->is_empty()); DCHECK(scope->declarations()->is_empty());
......
...@@ -48,6 +48,9 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -48,6 +48,9 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
class GlobalDeclarationsBuilder; class GlobalDeclarationsBuilder;
class RegisterResultScope; class RegisterResultScope;
class RegisterAllocationScope; class RegisterAllocationScope;
class TestResultScope;
enum class TestFallthrough { kThen, kElse, kNone };
void GenerateBytecode(); void GenerateBytecode();
void GenerateBytecodeBody(); void GenerateBytecodeBody();
...@@ -162,6 +165,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -162,6 +165,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
MUST_USE_RESULT Register VisitForRegisterValue(Expression* expr); MUST_USE_RESULT Register VisitForRegisterValue(Expression* expr);
void VisitForRegisterValue(Expression* expr, Register destination); void VisitForRegisterValue(Expression* expr, Register destination);
void VisitForEffect(Expression* expr); void VisitForEffect(Expression* expr);
void VisitForTest(Expression* expr, BytecodeLabels* then_labels,
BytecodeLabels* else_labels, TestFallthrough fallthrough);
// Methods for tracking and remapping register. // Methods for tracking and remapping register.
void RecordStoreToRegister(Register reg); 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 @@ ...@@ -5,10 +5,14 @@
#ifndef V8_INTERPRETER_BYTECODE_LABEL_H_ #ifndef V8_INTERPRETER_BYTECODE_LABEL_H_
#define V8_INTERPRETER_BYTECODE_LABEL_H_ #define V8_INTERPRETER_BYTECODE_LABEL_H_
#include "src/zone-containers.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
namespace interpreter { namespace interpreter {
class BytecodeArrayBuilder;
// A label representing a branch target in a bytecode array. When a // A label representing a branch target in a bytecode array. When a
// label is bound, it represents a known position in the bytecode // label is bound, it represents a known position in the bytecode
// array. For labels that are forward references there can be at most // array. For labels that are forward references there can be at most
...@@ -49,6 +53,21 @@ class BytecodeLabel final { ...@@ -49,6 +53,21 @@ class BytecodeLabel final {
friend class BytecodeArrayWriter; 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 interpreter
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -985,6 +985,7 @@ ...@@ -985,6 +985,7 @@
'interpreter/bytecode-flags.h', 'interpreter/bytecode-flags.h',
'interpreter/bytecode-generator.cc', 'interpreter/bytecode-generator.cc',
'interpreter/bytecode-generator.h', 'interpreter/bytecode-generator.h',
'interpreter/bytecode-label.cc',
'interpreter/bytecode-label.h', 'interpreter/bytecode-label.h',
'interpreter/bytecode-peephole-optimizer.cc', 'interpreter/bytecode-peephole-optimizer.cc',
'interpreter/bytecode-peephole-optimizer.h', 'interpreter/bytecode-peephole-optimizer.h',
......
...@@ -18,10 +18,10 @@ bytecodes: [ ...@@ -18,10 +18,10 @@ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), U8(1), /* 42 S> */ B(LdaSmi), U8(1),
B(Star), R(0), B(Star), R(0),
/* 45 S> */ B(JumpIfToBooleanTrue), U8(5), /* 45 S> */ B(JumpIfToBooleanTrue), U8(7),
B(LdaZero), B(LdaZero),
/* 56 E> */ B(TestLessThan), R(0), /* 56 E> */ B(TestLessThan), R(0),
B(JumpIfToBooleanFalse), U8(5), B(JumpIfFalse), U8(5),
/* 63 S> */ B(LdaSmi), U8(1), /* 63 S> */ B(LdaSmi), U8(1),
/* 75 S> */ B(Return), /* 75 S> */ B(Return),
B(LdaUndefined), B(LdaUndefined),
...@@ -43,10 +43,10 @@ bytecodes: [ ...@@ -43,10 +43,10 @@ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), U8(1), /* 42 S> */ B(LdaSmi), U8(1),
B(Star), R(0), B(Star), R(0),
/* 45 S> */ B(JumpIfToBooleanFalse), U8(5), /* 45 S> */ B(JumpIfToBooleanFalse), U8(10),
B(LdaZero), B(LdaZero),
/* 56 E> */ B(TestLessThan), R(0), /* 56 E> */ B(TestLessThan), R(0),
B(JumpIfToBooleanFalse), U8(5), B(JumpIfFalse), U8(5),
/* 63 S> */ B(LdaSmi), U8(1), /* 63 S> */ B(LdaSmi), U8(1),
/* 75 S> */ B(Return), /* 75 S> */ B(Return),
B(LdaUndefined), B(LdaUndefined),
...@@ -68,10 +68,10 @@ bytecodes: [ ...@@ -68,10 +68,10 @@ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), U8(1), /* 42 S> */ B(LdaSmi), U8(1),
B(Star), R(0), B(Star), R(0),
/* 45 S> */ B(JumpIfToBooleanTrue), U8(5), /* 45 S> */ B(JumpIfToBooleanTrue), U8(7),
B(LdaZero), B(LdaZero),
/* 57 E> */ B(TestLessThan), R(0), /* 57 E> */ B(TestLessThan), R(0),
B(JumpIfToBooleanFalse), U8(6), B(JumpIfFalse), U8(6),
B(LdaSmi), U8(2), B(LdaSmi), U8(2),
B(Jump), U8(4), B(Jump), U8(4),
B(LdaSmi), U8(3), B(LdaSmi), U8(3),
......
...@@ -13,14 +13,10 @@ snippet: " ...@@ -13,14 +13,10 @@ snippet: "
" "
frame size: 0 frame size: 0
parameter count: 1 parameter count: 1
bytecode array length: 12 bytecode array length: 4
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaSmi), U8(1), /* 34 S> */ B(LdaSmi), U8(2),
B(JumpIfToBooleanFalse), U8(6),
B(LdaSmi), U8(2),
B(Jump), U8(4),
B(LdaSmi), U8(3),
/* 52 S> */ B(Return), /* 52 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -34,19 +30,58 @@ snippet: " ...@@ -34,19 +30,58 @@ snippet: "
" "
frame size: 0 frame size: 0
parameter count: 1 parameter count: 1
bytecode array length: 20 bytecode array length: 4
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaSmi), U8(1), /* 34 S> */ B(LdaSmi), U8(3),
B(JumpIfToBooleanFalse), U8(14), /* 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(LdaSmi), U8(2),
B(JumpIfToBooleanFalse), U8(6),
B(LdaSmi), U8(3),
B(Jump), U8(4), 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(Jump), U8(4),
B(LdaSmi), U8(5), B(LdaSmi), U8(3),
/* 60 S> */ B(Return), /* 63 S> */ B(Return),
] ]
constant pool: [ constant pool: [
] ]
......
...@@ -13,7 +13,7 @@ snippet: " ...@@ -13,7 +13,7 @@ snippet: "
" "
frame size: 16 frame size: 16
parameter count: 1 parameter count: 1
bytecode array length: 283 bytecode array length: 282
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
B(LdaZero), B(LdaZero),
...@@ -70,11 +70,10 @@ bytecodes: [ ...@@ -70,11 +70,10 @@ bytecodes: [
B(Star), R(11), B(Star), R(11),
B(LdaZero), B(LdaZero),
B(TestEqualStrict), R(3), B(TestEqualStrict), R(3),
B(JumpIfTrue), U8(5), B(JumpIfTrue), U8(123),
B(LdaUndefined), B(LdaUndefined),
B(TestEqualStrict), R(1), B(TestEqualStrict), R(1),
B(ToBooleanLogicalNot), B(JumpIfTrue), U8(118),
B(JumpIfFalse), U8(118),
B(LdrNamedProperty), R(1), U8(6), U8(13), R(5), B(LdrNamedProperty), R(1), U8(6), U8(13), R(5),
B(LdaNull), B(LdaNull),
B(TestEqual), R(5), B(TestEqual), R(5),
...@@ -144,7 +143,7 @@ constant pool: [ ...@@ -144,7 +143,7 @@ constant pool: [
handlers: [ handlers: [
[7, 121, 127], [7, 121, 127],
[10, 80, 82], [10, 80, 82],
[200, 210, 212], [199, 209, 211],
] ]
--- ---
...@@ -154,7 +153,7 @@ snippet: " ...@@ -154,7 +153,7 @@ snippet: "
" "
frame size: 17 frame size: 17
parameter count: 1 parameter count: 1
bytecode array length: 296 bytecode array length: 295
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaConstant), U8(0), /* 42 S> */ B(LdaConstant), U8(0),
...@@ -213,11 +212,10 @@ bytecodes: [ ...@@ -213,11 +212,10 @@ bytecodes: [
B(Star), R(12), B(Star), R(12),
B(LdaZero), B(LdaZero),
B(TestEqualStrict), R(3), B(TestEqualStrict), R(3),
B(JumpIfTrue), U8(5), B(JumpIfTrue), U8(123),
B(LdaUndefined), B(LdaUndefined),
B(TestEqualStrict), R(1), B(TestEqualStrict), R(1),
B(ToBooleanLogicalNot), B(JumpIfTrue), U8(118),
B(JumpIfFalse), U8(118),
B(LdrNamedProperty), R(1), U8(6), U8(13), R(5), B(LdrNamedProperty), R(1), U8(6), U8(13), R(5),
B(LdaNull), B(LdaNull),
B(TestEqual), R(5), B(TestEqual), R(5),
...@@ -292,7 +290,7 @@ constant pool: [ ...@@ -292,7 +290,7 @@ constant pool: [
handlers: [ handlers: [
[11, 124, 130], [11, 124, 130],
[14, 83, 85], [14, 83, 85],
[204, 214, 216], [203, 213, 215],
] ]
--- ---
...@@ -304,7 +302,7 @@ snippet: " ...@@ -304,7 +302,7 @@ snippet: "
" "
frame size: 16 frame size: 16
parameter count: 1 parameter count: 1
bytecode array length: 299 bytecode array length: 298
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
B(LdaZero), B(LdaZero),
...@@ -369,11 +367,10 @@ bytecodes: [ ...@@ -369,11 +367,10 @@ bytecodes: [
B(Star), R(11), B(Star), R(11),
B(LdaZero), B(LdaZero),
B(TestEqualStrict), R(3), B(TestEqualStrict), R(3),
B(JumpIfTrue), U8(5), B(JumpIfTrue), U8(123),
B(LdaUndefined), B(LdaUndefined),
B(TestEqualStrict), R(1), B(TestEqualStrict), R(1),
B(ToBooleanLogicalNot), B(JumpIfTrue), U8(118),
B(JumpIfFalse), U8(118),
B(LdrNamedProperty), R(1), U8(6), U8(13), R(5), B(LdrNamedProperty), R(1), U8(6), U8(13), R(5),
B(LdaNull), B(LdaNull),
B(TestEqual), R(5), B(TestEqual), R(5),
...@@ -443,7 +440,7 @@ constant pool: [ ...@@ -443,7 +440,7 @@ constant pool: [
handlers: [ handlers: [
[7, 137, 143], [7, 137, 143],
[10, 96, 98], [10, 96, 98],
[216, 226, 228], [215, 225, 227],
] ]
--- ---
...@@ -453,7 +450,7 @@ snippet: " ...@@ -453,7 +450,7 @@ snippet: "
" "
frame size: 15 frame size: 15
parameter count: 1 parameter count: 1
bytecode array length: 309 bytecode array length: 308
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(1), R(8), /* 42 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(1), R(8),
...@@ -515,11 +512,10 @@ bytecodes: [ ...@@ -515,11 +512,10 @@ bytecodes: [
B(Star), R(10), B(Star), R(10),
B(LdaZero), B(LdaZero),
B(TestEqualStrict), R(2), B(TestEqualStrict), R(2),
B(JumpIfTrue), U8(5), B(JumpIfTrue), U8(123),
B(LdaUndefined), B(LdaUndefined),
B(TestEqualStrict), R(0), B(TestEqualStrict), R(0),
B(ToBooleanLogicalNot), B(JumpIfTrue), U8(118),
B(JumpIfFalse), U8(118),
B(LdrNamedProperty), R(0), U8(8), U8(17), R(4), B(LdrNamedProperty), R(0), U8(8), U8(17), R(4),
B(LdaNull), B(LdaNull),
B(TestEqual), R(4), B(TestEqual), R(4),
...@@ -596,6 +592,6 @@ constant pool: [ ...@@ -596,6 +592,6 @@ constant pool: [
handlers: [ handlers: [
[15, 137, 143], [15, 137, 143],
[18, 96, 98], [18, 96, 98],
[217, 227, 229], [216, 226, 228],
] ]
...@@ -264,7 +264,7 @@ snippet: " ...@@ -264,7 +264,7 @@ snippet: "
" "
frame size: 18 frame size: 18
parameter count: 1 parameter count: 1
bytecode array length: 769 bytecode array length: 768
bytecodes: [ bytecodes: [
B(Ldar), R(new_target), B(Ldar), R(new_target),
B(JumpIfUndefined), U8(26), B(JumpIfUndefined), U8(26),
...@@ -316,7 +316,7 @@ bytecodes: [ ...@@ -316,7 +316,7 @@ bytecodes: [
B(Star), R(6), B(Star), R(6),
B(LdaZero), B(LdaZero),
B(Star), R(5), B(Star), R(5),
B(JumpConstant), U8(16), B(JumpConstant), U8(17),
B(Ldar), R(10), B(Ldar), R(10),
/* 11 E> */ B(Throw), /* 11 E> */ B(Throw),
B(LdaConstant), U8(0), B(LdaConstant), U8(0),
...@@ -452,12 +452,11 @@ bytecodes: [ ...@@ -452,12 +452,11 @@ bytecodes: [
B(LdrContextSlot), R(1), U8(9), R(11), B(LdrContextSlot), R(1), U8(9), R(11),
B(LdaZero), B(LdaZero),
B(TestEqualStrict), R(11), B(TestEqualStrict), R(11),
B(JumpIfTrue), U8(9), B(JumpIfTrueConstant), U8(15),
B(LdrContextSlot), R(1), U8(7), R(11), B(LdrContextSlot), R(1), U8(7), R(11),
B(LdaUndefined), B(LdaUndefined),
B(TestEqualStrict), R(11), B(TestEqualStrict), R(11),
B(ToBooleanLogicalNot), B(JumpIfTrueConstant), U8(16),
B(JumpIfFalseConstant), U8(15),
B(LdrContextSlot), R(1), U8(7), R(11), B(LdrContextSlot), R(1), U8(7), R(11),
B(LdaNamedProperty), R(11), U8(12), U8(13), B(LdaNamedProperty), R(11), U8(12), U8(13),
B(StaContextSlot), R(1), U8(11), B(StaContextSlot), R(1), U8(11),
...@@ -596,11 +595,12 @@ constant pool: [ ...@@ -596,11 +595,12 @@ constant pool: [
InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE,
kInstanceTypeDontCare, kInstanceTypeDontCare,
kInstanceTypeDontCare, kInstanceTypeDontCare,
kInstanceTypeDontCare,
] ]
handlers: [ handlers: [
[41, 688, 694], [41, 687, 693],
[147, 442, 448], [147, 442, 448],
[150, 396, 398], [150, 396, 398],
[545, 557, 559], [544, 556, 558],
] ]
...@@ -737,3 +737,47 @@ constant pool: [ ...@@ -737,3 +737,47 @@ constant pool: [
handlers: [ 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) { ...@@ -705,6 +705,17 @@ TEST(IfConditions) {
" }\n" " }\n"
"};\n" "};\n"
"f();\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), CHECK(CompareTexts(BuildActual(printer, snippets),
...@@ -1615,6 +1626,11 @@ TEST(Conditional) { ...@@ -1615,6 +1626,11 @@ TEST(Conditional) {
"return 1 ? 2 : 3;\n", "return 1 ? 2 : 3;\n",
"return 1 ? 2 ? 3 : 4 : 5;\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), CHECK(CompareTexts(BuildActual(printer, snippets),
......
...@@ -287,7 +287,8 @@ TEST(MultipleFuncsConditional) { ...@@ -287,7 +287,8 @@ TEST(MultipleFuncsConditional) {
v8::HandleScope scope(CcTest::isolate()); v8::HandleScope scope(CcTest::isolate());
v8::Local<v8::Script> script = Compile(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 1; } :\n"
" function() { return 2; }"); " function() { return 2; }");
CheckFunctionName(script, "return 1", "fun1"); CheckFunctionName(script, "return 1", "fun1");
...@@ -301,9 +302,10 @@ TEST(MultipleFuncsInLiteral) { ...@@ -301,9 +302,10 @@ TEST(MultipleFuncsInLiteral) {
v8::Local<v8::Script> script = v8::Local<v8::Script> script =
Compile(CcTest::isolate(), Compile(CcTest::isolate(),
"var x = 0;\n"
"function MyClass() {}\n" "function MyClass() {}\n"
"MyClass.prototype = {\n" "MyClass.prototype = {\n"
" method1: 0 ? function() { return 1; } :\n" " method1: x ? function() { return 1; } :\n"
" function() { return 2; } }"); " function() { return 2; } }");
CheckFunctionName(script, "return 1", "MyClass.method1"); CheckFunctionName(script, "return 1", "MyClass.method1");
CheckFunctionName(script, "return 2", "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