Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(680)

Unified Diff: src/interpreter/bytecode-array-builder.cc

Issue 1343363002: [Interpreter] Basic flow control. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Switch test-bytecode-generator/IfConditions to use new style bytecode array check. Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/interpreter/bytecode-array-builder.h ('k') | src/interpreter/bytecode-array-iterator.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/interpreter/bytecode-array-builder.cc
diff --git a/src/interpreter/bytecode-array-builder.cc b/src/interpreter/bytecode-array-builder.cc
index 2d06765cd1cb1e12592f9cb8a213e63ea0ef8619..9bc634ef94cd538b541186177e19c56c5b30e53e 100644
--- a/src/interpreter/bytecode-array-builder.cc
+++ b/src/interpreter/bytecode-array-builder.cc
@@ -12,6 +12,9 @@ BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone)
: isolate_(isolate),
bytecodes_(zone),
bytecode_generated_(false),
+ last_block_end_(0),
+ last_bytecode_start_(~0),
+ return_seen_in_block_(false),
constants_map_(isolate->heap(), zone),
constants_(zone),
parameter_count_(-1),
@@ -37,14 +40,6 @@ void BytecodeArrayBuilder::set_parameter_count(int number_of_parameters) {
int BytecodeArrayBuilder::parameter_count() const { return parameter_count_; }
-bool BytecodeArrayBuilder::HasExplicitReturn() {
- // TODO(rmcilroy): When we have control flow we should return false here if
- // there is an outstanding jump target, even if the last bytecode is kReturn.
- return !bytecodes_.empty() &&
- bytecodes_.back() == Bytecodes::ToByte(Bytecode::kReturn);
-}
-
-
Register BytecodeArrayBuilder::Parameter(int parameter_index) {
DCHECK_GE(parameter_index, 0);
DCHECK_LT(parameter_index, parameter_count_);
@@ -56,6 +51,9 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
DCHECK_EQ(bytecode_generated_, false);
DCHECK_GE(parameter_count_, 0);
DCHECK_GE(local_register_count_, 0);
+
+ EnsureReturn();
+
int bytecode_size = static_cast<int>(bytecodes_.size());
int register_count = local_register_count_ + temporary_register_count_;
int frame_size = register_count * kPointerSize;
@@ -76,9 +74,57 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
}
-BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value binop,
+template <size_t N>
+void BytecodeArrayBuilder::Output(uint8_t(&bytes)[N]) {
+ DCHECK_EQ(Bytecodes::NumberOfOperands(Bytecodes::FromByte(bytes[0])), N - 1);
+ last_bytecode_start_ = bytecodes()->size();
+ for (int i = 1; i < static_cast<int>(N); i++) {
+ DCHECK(OperandIsValid(Bytecodes::FromByte(bytes[0]), i - 1, bytes[i]));
+ }
+ bytecodes()->insert(bytecodes()->end(), bytes, bytes + N);
+}
+
+
+void BytecodeArrayBuilder::Output(Bytecode bytecode, uint8_t operand0,
+ uint8_t operand1, uint8_t operand2) {
+ uint8_t bytes[] = {Bytecodes::ToByte(bytecode), operand0, operand1, operand2};
+ Output(bytes);
+}
+
+
+void BytecodeArrayBuilder::Output(Bytecode bytecode, uint8_t operand0,
+ uint8_t operand1) {
+ uint8_t bytes[] = {Bytecodes::ToByte(bytecode), operand0, operand1};
+ Output(bytes);
+}
+
+
+void BytecodeArrayBuilder::Output(Bytecode bytecode, uint8_t operand0) {
+ uint8_t bytes[] = {Bytecodes::ToByte(bytecode), operand0};
+ Output(bytes);
+}
+
+
+void BytecodeArrayBuilder::Output(Bytecode bytecode) {
+ uint8_t bytes[] = {Bytecodes::ToByte(bytecode)};
+ Output(bytes);
+}
+
+
+BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op,
Register reg) {
- Output(BytecodeForBinaryOperation(binop), reg.ToOperand());
+ Output(BytecodeForBinaryOperation(op), reg.ToOperand());
+ return *this;
+}
+
+
+BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(
+ Token::Value op, Register reg, LanguageMode language_mode) {
+ if (!is_sloppy(language_mode)) {
+ UNIMPLEMENTED();
+ }
+
+ Output(BytecodeForCompareOperation(op), reg.ToOperand());
return *this;
}
@@ -99,7 +145,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) {
size_t entry = GetConstantPoolEntry(object);
- if (FitsInByteOperand(entry)) {
+ if (FitsInIdxOperand(entry)) {
Output(Bytecode::kLdaConstant, static_cast<uint8_t>(entry));
} else {
UNIMPLEMENTED();
@@ -154,7 +200,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister(
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(int slot_index) {
DCHECK(slot_index >= 0);
- if (FitsInByteOperand(slot_index)) {
+ if (FitsInIdxOperand(slot_index)) {
Output(Bytecode::kLdaGlobal, static_cast<uint8_t>(slot_index));
} else {
UNIMPLEMENTED();
@@ -168,7 +214,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty(
UNIMPLEMENTED();
}
- if (FitsInByteOperand(feedback_slot)) {
+ if (FitsInIdxOperand(feedback_slot)) {
Output(Bytecode::kLoadIC, object.ToOperand(),
static_cast<uint8_t>(feedback_slot));
} else {
@@ -184,7 +230,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty(
UNIMPLEMENTED();
}
- if (FitsInByteOperand(feedback_slot)) {
+ if (FitsInIdxOperand(feedback_slot)) {
Output(Bytecode::kKeyedLoadIC, object.ToOperand(),
static_cast<uint8_t>(feedback_slot));
} else {
@@ -201,7 +247,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty(
UNIMPLEMENTED();
}
- if (FitsInByteOperand(feedback_slot)) {
+ if (FitsInIdxOperand(feedback_slot)) {
Output(Bytecode::kStoreIC, object.ToOperand(), name.ToOperand(),
static_cast<uint8_t>(feedback_slot));
} else {
@@ -218,7 +264,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty(
UNIMPLEMENTED();
}
- if (FitsInByteOperand(feedback_slot)) {
+ if (FitsInIdxOperand(feedback_slot)) {
Output(Bytecode::kKeyedStoreIC, object.ToOperand(), key.ToOperand(),
static_cast<uint8_t>(feedback_slot));
} else {
@@ -228,16 +274,179 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty(
}
+BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() {
+ if (LastBytecodeInSameBlock()) {
+ // If the previous bytecode puts a boolean in the accumulator
+ // there is no need to emit an instruction.
+ switch (Bytecodes::FromByte(bytecodes()->at(last_bytecode_start_))) {
+ case Bytecode::kToBoolean:
+ UNREACHABLE();
+ case Bytecode::kLdaTrue:
+ case Bytecode::kLdaFalse:
+ case Bytecode::kTestEqual:
+ case Bytecode::kTestNotEqual:
+ case Bytecode::kTestEqualStrict:
+ case Bytecode::kTestNotEqualStrict:
+ case Bytecode::kTestLessThan:
+ case Bytecode::kTestLessThanEqual:
+ case Bytecode::kTestGreaterThan:
+ case Bytecode::kTestGreaterThanEqual:
+ case Bytecode::kTestInstanceOf:
+ case Bytecode::kTestIn:
+ break;
+ default:
+ Output(Bytecode::kToBoolean);
+ }
+ }
+ return *this;
+}
+
+
+BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) {
+ if (label->is_forward_target()) {
+ // An earlier jump instruction refers to this label. Update it's location.
+ PatchJump(bytecodes()->end(), bytecodes()->begin() + label->offset());
+ // Now treat as if the label will only be back referred to.
+ }
+ label->bind_to(bytecodes()->size());
+ return *this;
+}
+
+
+// static
+bool BytecodeArrayBuilder::IsJumpWithImm8Operand(Bytecode jump_bytecode) {
+ return jump_bytecode == Bytecode::kJump ||
+ jump_bytecode == Bytecode::kJumpIfTrue ||
+ jump_bytecode == Bytecode::kJumpIfFalse;
+}
+
+
+// static
+Bytecode BytecodeArrayBuilder::GetJumpWithConstantOperand(
+ Bytecode jump_bytecode) {
+ switch (jump_bytecode) {
+ case Bytecode::kJump:
+ return Bytecode::kJumpConstant;
+ case Bytecode::kJumpIfTrue:
+ return Bytecode::kJumpIfTrueConstant;
+ case Bytecode::kJumpIfFalse:
+ return Bytecode::kJumpIfFalseConstant;
+ default:
+ UNREACHABLE();
+ return Bytecode::kJumpConstant;
+ }
+}
+
+
+void BytecodeArrayBuilder::PatchJump(
+ const ZoneVector<uint8_t>::iterator& jump_target,
+ ZoneVector<uint8_t>::iterator jump_location) {
+ Bytecode jump_bytecode = Bytecodes::FromByte(*jump_location);
+ int delta = static_cast<int>(jump_target - jump_location);
+
+ DCHECK(IsJumpWithImm8Operand(jump_bytecode));
+ DCHECK_EQ(Bytecodes::Size(jump_bytecode), 2);
+ DCHECK_GE(delta, 0);
+
+ if (FitsInImm8Operand(delta)) {
+ // Just update the operand
+ jump_location++;
+ *jump_location = static_cast<uint8_t>(delta);
+ } else {
+ // Update the jump type and operand
+ size_t entry = GetConstantPoolEntry(handle(Smi::FromInt(delta), isolate()));
+ if (FitsInIdxOperand(entry)) {
+ *jump_location++ =
+ Bytecodes::ToByte(GetJumpWithConstantOperand(jump_bytecode));
+ *jump_location = static_cast<uint8_t>(entry);
+ } else {
+ // TODO(oth): OutputJump should reserve a constant pool entry
+ // when jump is written. The reservation should be used here if
+ // needed, or cancelled if not. This is due to the patch needing
+ // to match the size of the code it's replacing. In future,
+ // there will probably be a jump with 32-bit operand for cases
+ // when constant pool is full, but that needs to be emitted in
+ // OutputJump too.
+ UNIMPLEMENTED();
+ }
+ }
+}
+
+
+BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode,
+ BytecodeLabel* label) {
+ int delta;
+ if (label->is_bound()) {
+ // Label has been bound already so this is a backwards jump.
+ CHECK_GE(bytecodes()->size(), label->offset());
+ CHECK_LE(bytecodes()->size(), static_cast<size_t>(kMaxInt));
+ size_t abs_delta = bytecodes()->size() - label->offset();
+ delta = -static_cast<int>(abs_delta);
+ } else {
+ // Label has not yet been bound so this is a forward reference
+ // that will be patched when the label is bound.
+ label->set_referrer(bytecodes()->size());
+ delta = 0;
+ }
+
+ if (FitsInImm8Operand(delta)) {
+ Output(jump_bytecode, static_cast<uint8_t>(delta));
+ } else {
+ size_t entry = GetConstantPoolEntry(handle(Smi::FromInt(delta), isolate()));
+ if (FitsInIdxOperand(entry)) {
+ Output(GetJumpWithConstantOperand(jump_bytecode),
+ static_cast<uint8_t>(entry));
+ } else {
+ UNIMPLEMENTED();
+ }
+ }
+ return *this;
+}
+
+
+BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) {
+ return OutputJump(Bytecode::kJump, label);
+}
+
+
+BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfTrue(BytecodeLabel* label) {
+ return OutputJump(Bytecode::kJumpIfTrue, label);
+}
+
+
+BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(BytecodeLabel* label) {
+ return OutputJump(Bytecode::kJumpIfFalse, label);
+}
+
+
BytecodeArrayBuilder& BytecodeArrayBuilder::Return() {
Output(Bytecode::kReturn);
+ return_seen_in_block_ = true;
return *this;
}
+BytecodeArrayBuilder& BytecodeArrayBuilder::EnterBlock() { return *this; }
+
+
+BytecodeArrayBuilder& BytecodeArrayBuilder::LeaveBlock() {
+ last_block_end_ = bytecodes()->size();
+ return_seen_in_block_ = false;
+ return *this;
+}
+
+
+void BytecodeArrayBuilder::EnsureReturn() {
+ if (!return_seen_in_block_) {
+ LoadUndefined();
+ Return();
+ }
+}
+
BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
Register receiver,
size_t arg_count) {
- if (FitsInByteOperand(arg_count)) {
+ if (FitsInIdxOperand(arg_count)) {
Output(Bytecode::kCall, callable.ToOperand(), receiver.ToOperand(),
static_cast<uint8_t>(arg_count));
} else {
@@ -308,42 +517,9 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
return false;
}
-
-void BytecodeArrayBuilder::Output(Bytecode bytecode, uint8_t operand0,
- uint8_t operand1, uint8_t operand2) {
- DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), 3);
- DCHECK(OperandIsValid(bytecode, 0, operand0) &&
- OperandIsValid(bytecode, 1, operand1) &&
- OperandIsValid(bytecode, 2, operand2));
- bytecodes_.push_back(Bytecodes::ToByte(bytecode));
- bytecodes_.push_back(operand0);
- bytecodes_.push_back(operand1);
- bytecodes_.push_back(operand2);
-}
-
-
-void BytecodeArrayBuilder::Output(Bytecode bytecode, uint8_t operand0,
- uint8_t operand1) {
- DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), 2);
- DCHECK(OperandIsValid(bytecode, 0, operand0) &&
- OperandIsValid(bytecode, 1, operand1));
- bytecodes_.push_back(Bytecodes::ToByte(bytecode));
- bytecodes_.push_back(operand0);
- bytecodes_.push_back(operand1);
-}
-
-
-void BytecodeArrayBuilder::Output(Bytecode bytecode, uint8_t operand0) {
- DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), 1);
- DCHECK(OperandIsValid(bytecode, 0, operand0));
- bytecodes_.push_back(Bytecodes::ToByte(bytecode));
- bytecodes_.push_back(operand0);
-}
-
-
-void BytecodeArrayBuilder::Output(Bytecode bytecode) {
- DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), 0);
- bytecodes_.push_back(Bytecodes::ToByte(bytecode));
+bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const {
+ return last_bytecode_start_ < bytecodes()->size() &&
+ last_bytecode_start_ >= last_block_end_;
}
@@ -361,21 +537,57 @@ Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) {
case Token::Value::MOD:
return Bytecode::kMod;
default:
- UNIMPLEMENTED();
+ UNREACHABLE();
return static_cast<Bytecode>(-1);
}
}
// static
-bool BytecodeArrayBuilder::FitsInByteOperand(int value) {
- return 0 <= value && value <= 255;
+Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) {
+ switch (op) {
+ case Token::Value::EQ:
+ return Bytecode::kTestEqual;
+ case Token::Value::NE:
+ return Bytecode::kTestNotEqual;
+ case Token::Value::EQ_STRICT:
+ return Bytecode::kTestEqualStrict;
+ case Token::Value::NE_STRICT:
+ return Bytecode::kTestNotEqualStrict;
+ case Token::Value::LT:
+ return Bytecode::kTestLessThan;
+ case Token::Value::GT:
+ return Bytecode::kTestGreaterThan;
+ case Token::Value::LTE:
+ return Bytecode::kTestLessThanEqual;
+ case Token::Value::GTE:
+ return Bytecode::kTestGreaterThanEqual;
+ case Token::Value::INSTANCEOF:
+ return Bytecode::kTestInstanceOf;
+ case Token::Value::IN:
+ return Bytecode::kTestIn;
+ default:
+ UNREACHABLE();
+ return static_cast<Bytecode>(-1);
+ }
+}
+
+
+// static
+bool BytecodeArrayBuilder::FitsInIdxOperand(int value) {
+ return kMinUInt8 <= value && value <= kMaxUInt8;
+}
+
+
+// static
+bool BytecodeArrayBuilder::FitsInIdxOperand(size_t value) {
+ return value <= static_cast<size_t>(kMaxUInt8);
}
// static
-bool BytecodeArrayBuilder::FitsInByteOperand(size_t value) {
- return value <= 255;
+bool BytecodeArrayBuilder::FitsInImm8Operand(int value) {
+ return kMinInt8 <= value && value < kMaxInt8;
}
« no previous file with comments | « src/interpreter/bytecode-array-builder.h ('k') | src/interpreter/bytecode-array-iterator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698