Index: src/interpreter/bytecode-array-builder.cc |
diff --git a/src/interpreter/bytecode-array-builder.cc b/src/interpreter/bytecode-array-builder.cc |
index f3a1b1ea0803959990370da458ae10da87d8ec54..791ab5a1517a75535ae6fb76e4add31eace79c49 100644 |
--- a/src/interpreter/bytecode-array-builder.cc |
+++ b/src/interpreter/bytecode-array-builder.cc |
@@ -14,6 +14,8 @@ BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone) |
bytecode_generated_(false), |
constants_map_(isolate->heap(), zone), |
constants_(zone), |
+ forward_labels_(zone), |
+ bound_labels_(zone), |
parameter_count_(-1), |
local_register_count_(-1), |
temporary_register_count_(0), |
@@ -76,9 +78,90 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { |
} |
-BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value binop, |
+template <size_t N> |
+void BytecodeArrayBuilder::RawOutputAt(ZoneVector<uint8_t>::iterator pos, |
+ uint8_t(&bytes)[N]) { |
+ DCHECK_EQ(Bytecodes::NumberOfOperands(Bytecodes::FromByte(bytes[0])), N - 1); |
+ for (int i = 1; i < static_cast<int>(N); i++) { |
+ DCHECK(OperandIsValid(Bytecodes::FromByte(bytes[0]), i - 1, bytes[i])); |
+ } |
+ |
+ if (bytecodes()->end() == pos) { |
rmcilroy
2015/09/18 10:42:23
I'm not keen on having the Output operators do pat
oth
2015/09/23 10:46:55
Done.
|
+ bytecodes()->insert(pos, bytes, bytes + N); |
+ } else { |
+ std::copy(bytes, bytes + N, pos); |
+ } |
+} |
+ |
+ |
+void BytecodeArrayBuilder::Output(const ZoneVector<uint8_t>::iterator& pos, |
+ Bytecode bytecode, uint8_t operand0) { |
+ uint8_t bytes[] = {Bytecodes::ToByte(bytecode), operand0}; |
+ RawOutputAt(pos, bytes); |
+} |
+ |
+ |
+void BytecodeArrayBuilder::Output(Bytecode bytecode, uint8_t operand0, |
+ uint8_t operand1, uint8_t operand2) { |
+ uint8_t bytes[] = {Bytecodes::ToByte(bytecode), operand0, operand1, operand2}; |
+ RawOutputAt(bytecodes()->end(), bytes); |
+} |
+ |
+ |
+void BytecodeArrayBuilder::Output(Bytecode bytecode, uint8_t operand0, |
+ uint8_t operand1) { |
+ uint8_t bytes[] = {Bytecodes::ToByte(bytecode), operand0, operand1}; |
+ RawOutputAt(bytecodes()->end(), bytes); |
+} |
+ |
+ |
+void BytecodeArrayBuilder::Output(Bytecode bytecode, uint8_t operand0) { |
+ uint8_t bytes[] = {Bytecodes::ToByte(bytecode), operand0}; |
+ RawOutputAt(bytecodes()->end(), bytes); |
+} |
+ |
+ |
+void BytecodeArrayBuilder::Output(Bytecode bytecode) { |
+ uint8_t bytes[] = {Bytecodes::ToByte(bytecode)}; |
+ RawOutputAt(bytecodes()->end(), bytes); |
+} |
+ |
+ |
+BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op, |
Register reg) { |
- Output(BytecodeForBinaryOperation(binop), reg.ToOperand()); |
+ Output(BytecodeForBinaryOperation(op), reg.ToOperand()); |
+ return *this; |
+} |
+ |
+ |
+BytecodeArrayBuilder& BytecodeArrayBuilder::Add(Register reg) { |
+ return BinaryOperation(Token::Value::ADD, reg); |
+} |
+ |
+ |
+BytecodeArrayBuilder& BytecodeArrayBuilder::Subtract(Register reg) { |
+ return BinaryOperation(Token::Value::SUB, reg); |
+} |
+ |
+ |
+BytecodeArrayBuilder& BytecodeArrayBuilder::Multiply(Register reg) { |
+ return BinaryOperation(Token::Value::MUL, reg); |
+} |
+ |
+ |
+BytecodeArrayBuilder& BytecodeArrayBuilder::Divide(Register reg) { |
+ return BinaryOperation(Token::Value::DIV, reg); |
+} |
+ |
+ |
+BytecodeArrayBuilder& BytecodeArrayBuilder::Modulo(Register reg) { |
+ return BinaryOperation(Token::Value::MOD, reg); |
+} |
+ |
+ |
+BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(Token::Value op, |
+ Register reg) { |
+ Output(BytecodeForCompareOperation(op), reg.ToOperand()); |
return *this; |
} |
@@ -99,7 +182,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(); |
@@ -108,6 +191,21 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) { |
} |
+BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(int value) { |
+ Handle<Object> v = isolate()->factory()->NewNumberFromInt(value); |
+ if (v->IsSmi()) { |
+ return LoadLiteral(Smi::cast(*v)); |
+ } else { |
+ return LoadLiteral(v); |
+ } |
+} |
+ |
+ |
+BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(double value) { |
+ return LoadLiteral(isolate()->factory()->NewNumber(value)); |
+} |
+ |
+ |
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() { |
Output(Bytecode::kLdaUndefined); |
return *this; |
@@ -158,7 +256,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 { |
@@ -174,7 +272,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 { |
@@ -191,7 +289,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 { |
@@ -208,7 +306,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 { |
@@ -218,6 +316,101 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty( |
} |
+BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) { |
+ auto forward_labels_iterator = forward_labels_.find(label); |
+ if (forward_labels_.end() != forward_labels_iterator) { |
+ // Label is forward referred to, update the referring jump instruction. |
+ ZoneVector<uint8_t>::iterator it = bytecodes()->begin() + label->offset(); |
+ OutputJump(Bytecodes::FromByte(*it), it, bytecodes()->end()); |
+ forward_labels_.erase(forward_labels_iterator); |
+ // Now treat as if the label will only be back referred to. |
+ } |
+ |
+ DCHECK(bound_labels_.end() == bound_labels_.find(label)); |
+ label->bind_to(bytecodes()->size()); |
+ bound_labels_.insert(label); |
+ return *this; |
+} |
+ |
+ |
+// static |
+bool BytecodeArrayBuilder::IsJumpWithSmi8Operand(Bytecode jump_bytecode) { |
+ return jump_bytecode == Bytecode::kJumpSmi8 || |
+ jump_bytecode == Bytecode::kJumpIfTrueSmi8 || |
+ jump_bytecode == Bytecode::kJumpIfFalseSmi8; |
+} |
+ |
+ |
+// static |
+Bytecode BytecodeArrayBuilder::GetJumpWithConstantOperand( |
+ Bytecode jump_bytecode) { |
+ switch (jump_bytecode) { |
+ case Bytecode::kJumpSmi8: |
+ return Bytecode::kJumpConstant; |
+ case Bytecode::kJumpIfTrueSmi8: |
+ return Bytecode::kJumpIfTrueConstant; |
+ case Bytecode::kJumpIfFalseSmi8: |
+ return Bytecode::kJumpIfFalseConstant; |
+ default: |
+ UNREACHABLE(); |
+ return Bytecode::kJumpConstant; |
+ } |
+} |
+ |
+ |
+void BytecodeArrayBuilder::OutputJump( |
+ Bytecode jump_bytecode, const ZoneVector<uint8_t>::iterator& jump_location, |
+ const ZoneVector<uint8_t>::iterator& jump_target) { |
+ DCHECK(IsJumpWithSmi8Operand(jump_bytecode)); |
+ |
+ int delta = static_cast<int>(jump_target - jump_location); |
+ if (FitsInImm8Operand(delta)) { |
+ Output(jump_location, jump_bytecode, static_cast<uint8_t>(delta)); |
+ } else { |
+ size_t entry = GetConstantPoolEntry(handle(Smi::FromInt(delta), isolate())); |
+ if (FitsInIdxOperand(entry)) { |
+ jump_bytecode = GetJumpWithConstantOperand(jump_bytecode); |
+ Output(jump_location, jump_bytecode, static_cast<uint8_t>(entry)); |
+ } else { |
+ UNIMPLEMENTED(); |
+ } |
+ } |
+} |
+ |
+ |
+BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(Bytecode jump_bytecode, |
+ BytecodeLabel* label) { |
+ if (bound_labels_.find(label) != bound_labels_.end()) { |
+ // Label has been bound already so this is a backwards jump. |
+ OutputJump(jump_bytecode, bytecodes()->end(), |
+ bytecodes()->begin() + label->offset()); |
+ } else { |
+ // Label has not yet been bound so this is a forward reference |
+ // that will be patched when the label is bound. |
+ DCHECK(forward_labels_.find(label) == forward_labels_.end()); |
+ label->bind_to(bytecodes()->size()); |
+ forward_labels_.insert(label); |
+ OutputJump(jump_bytecode, bytecodes()->end(), bytecodes()->end()); |
+ } |
+ return *this; |
+} |
+ |
+ |
+BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) { |
+ return Jump(Bytecode::kJumpSmi8, label); |
+} |
+ |
+ |
+BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfTrue(BytecodeLabel* label) { |
+ return Jump(Bytecode::kJumpIfTrueSmi8, label); |
+} |
+ |
+ |
+BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(BytecodeLabel* label) { |
+ return Jump(Bytecode::kJumpIfFalseSmi8, label); |
+} |
+ |
+ |
BytecodeArrayBuilder& BytecodeArrayBuilder::Return() { |
Output(Bytecode::kReturn); |
return *this; |
@@ -227,7 +420,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::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 { |
@@ -299,44 +492,6 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, |
} |
-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)); |
-} |
- |
- |
// static |
Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) { |
switch (op) { |
@@ -358,17 +513,53 @@ Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) { |
// static |
-bool BytecodeArrayBuilder::FitsInByteOperand(int value) { |
+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: |
+ UNIMPLEMENTED(); |
+ return static_cast<Bytecode>(-1); |
+ } |
+} |
+ |
+ |
+// static |
+bool BytecodeArrayBuilder::FitsInIdxOperand(int value) { |
return 0 <= value && value <= 255; |
} |
// static |
-bool BytecodeArrayBuilder::FitsInByteOperand(size_t value) { |
+bool BytecodeArrayBuilder::FitsInIdxOperand(size_t value) { |
return value <= 255; |
} |
+// static |
+bool BytecodeArrayBuilder::FitsInImm8Operand(int value) { |
+ return -128 <= value && value < 127; |
+} |
+ |
+ |
TemporaryRegisterScope::TemporaryRegisterScope(BytecodeArrayBuilder* builder) |
: builder_(builder), count_(0), last_register_index_(-1) {} |