Index: src/interpreter/bytecodes.cc |
diff --git a/src/interpreter/bytecodes.cc b/src/interpreter/bytecodes.cc |
index 89fcaf60e8e2339eb716ea9db5a900e134b94752..b86bb82094249467bfd7a3692d42f52852e2cc83 100644 |
--- a/src/interpreter/bytecodes.cc |
+++ b/src/interpreter/bytecodes.cc |
@@ -2,18 +2,86 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#define OPERANDS(x) OperandInfo##x |
rmcilroy
2015/07/24 18:34:48
Is this required?
|
+ |
#include "src/interpreter/bytecodes.h" |
namespace v8 { |
namespace internal { |
namespace interpreter { |
+static const int kMaxOperands = 3; |
+ |
+template <enum Operand O> |
+struct OperandInfo { |
+ static const int is_explicit; |
rmcilroy
2015/07/24 18:34:48
instead of having is_explicit, could we just speci
|
+ static const int size; |
+}; |
+ |
+#define OPERAND_INFO(op, sz) \ |
+ template <> \ |
+ struct OperandInfo<Operand::k##op> { \ |
+ static const int is_explicit = (sz == 0) ? 0 : 1; \ |
+ static const int size = sz; \ |
+ } |
+ |
+OPERAND_INFO(None, 0); |
+OPERAND_INFO(Imm0, 0); |
rmcilroy
2015/07/24 18:34:48
What is Imm0? Seems unrequired.
|
+OPERAND_INFO(Imm8, 1); |
+OPERAND_INFO(Smi, 4); |
rmcilroy
2015/07/24 18:34:47
As mentioned offline, this can't be a 4 byte opera
|
+OPERAND_INFO(Reg, 1); |
+ |
+ |
+template <enum Bytecode B> |
+struct BytecodeInfo { |
+ // Size of byte code and operands |
+ static const int size; |
+ // Number of operands |
+ static const int number_of_operands; |
+ // Packed operand values |
+ static const int operands; |
+}; |
+ |
+ |
+// Packing operands into a single integer (makes indexing easier) |
+static const int kOperandShift = 4; |
+STATIC_ASSERT(static_cast<int>(Operand::kLast) < ((1 << kOperandShift) - 1)); |
+#define PACK_OPERAND(op, i) (static_cast<int>(op) << (i * kOperandShift)) |
+#define PACK_OPERANDS(op0, op1, op2) \ |
+ PACK_OPERAND(op0, 0) | PACK_OPERAND(op1, 1) | PACK_OPERAND(op2, 2) |
rmcilroy
2015/07/24 18:34:48
I personally don't think it's worth packing operan
|
+#define UNPACK_OPERAND(op, pos) (Operand)(op >> (pos * kOperandShift)) |
+ |
+// Generator of BytecodeInfos for each bytecode. |
+#define BYTECODE_INFO(code, op0, op1, op2) \ |
rmcilroy
2015/07/24 18:34:48
As much as I like pre-processor magic </sarcasm> -
|
+ template <> \ |
+ struct BytecodeInfo<Bytecode::code> { \ |
+ static const int size = 1 + OperandInfo<op0>::size + \ |
+ OperandInfo<op1>::size + OperandInfo<op2>::size; \ |
+ static const int number_of_operands = OperandInfo<op0>::is_explicit + \ |
+ OperandInfo<op1>::is_explicit + \ |
+ OperandInfo<op2>::is_explicit; \ |
+ static const int operands = PACK_OPERANDS(op0, op1, op2); \ |
+ } |
+ |
+// Bytecode declarations |
+BYTECODE_INFO(kLoadSmi0, Operand::kReg, Operand::kNone, Operand::kNone); |
+BYTECODE_INFO(kLoadSmi8, Operand::kReg, Operand::kImm8, Operand::kNone); |
+BYTECODE_INFO(kLoadSmi, Operand::kReg, Operand::kSmi, Operand::kNone); |
+BYTECODE_INFO(kMove, Operand::kReg, Operand::kReg, Operand::kNone); |
+BYTECODE_INFO(kAdd, Operand::kReg, Operand::kReg, Operand::kReg); |
+BYTECODE_INFO(kSub, Operand::kReg, Operand::kReg, Operand::kReg); |
+BYTECODE_INFO(kMul, Operand::kReg, Operand::kReg, Operand::kReg); |
+BYTECODE_INFO(kDiv, Operand::kReg, Operand::kReg, Operand::kReg); |
+BYTECODE_INFO(kMod, Operand::kReg, Operand::kReg, Operand::kReg); |
+BYTECODE_INFO(kReturn, Operand::kNone, Operand::kNone, Operand::kNone); |
rmcilroy
2015/07/24 18:34:48
I would really like this list of declarations to b
|
+ |
+ |
// static |
const char* Bytecodes::ToString(Bytecode bytecode) { |
switch (bytecode) { |
-#define CASE(Name, _) \ |
- case Bytecode::k##Name: \ |
- return #Name; |
+#define CASE(Name) \ |
+ case Bytecode::k##Name: \ |
+ return #Name; |
BYTECODE_LIST(CASE) |
#undef CASE |
} |
@@ -23,11 +91,19 @@ const char* Bytecodes::ToString(Bytecode bytecode) { |
// static |
-const int Bytecodes::NumberOfArguments(Bytecode bytecode) { |
+Bytecode Bytecodes::FromByte(uint8_t value) { |
+ Bytecode code = static_cast<Bytecode>(value); |
+ CHECK(code <= Bytecode::kLast); |
+ return code; |
+} |
+ |
+ |
+// static |
+const int Bytecodes::NumberOfOperands(Bytecode bytecode) { |
switch (bytecode) { |
-#define CASE(Name, arg_count) \ |
- case Bytecode::k##Name: \ |
- return arg_count; |
+#define CASE(Name) \ |
+ case Bytecode::k##Name: \ |
+ return BytecodeInfo<Bytecode::k##Name>::number_of_operands; |
BYTECODE_LIST(CASE) |
#undef CASE |
} |
@@ -37,15 +113,62 @@ const int Bytecodes::NumberOfArguments(Bytecode bytecode) { |
// static |
+const Operand Bytecodes::GetOperand(Bytecode bytecode, int i) { |
+ CHECK(i < kMaxOperands); |
+ |
+ int packed = 0; |
+ switch (bytecode) { |
+#define CASE(Name) \ |
+ case Bytecode::k##Name: \ |
+ packed = BytecodeInfo<Bytecode::k##Name>::operands; |
+ BYTECODE_LIST(CASE) |
+#undef CASE |
+ } |
+ return UNPACK_OPERAND(packed, i); |
+} |
+ |
+ |
+// static |
+const int Bytecodes::GetOperandSize(Operand operand) { |
+ switch (operand) { |
+#define CASE(Name) \ |
+ case Operand::k##Name: \ |
+ return OperandInfo<Operand::k##Name>::size; |
+ OPERAND_LIST(CASE) |
+#undef CASE |
+ } |
+ UNREACHABLE(); |
+ return 0; |
+} |
+ |
+ |
+// static |
const int Bytecodes::Size(Bytecode bytecode) { |
- return NumberOfArguments(bytecode) + 1; |
+ switch (bytecode) { |
+#define CASE(Name) \ |
+ case Bytecode::k##Name: \ |
+ return BytecodeInfo<Bytecode::k##Name>::size; |
+ BYTECODE_LIST(CASE) |
+#undef CASE |
+ } |
+ UNREACHABLE(); |
+ return 0; |
} |
-#define CHECK_SIZE(Name, arg_count) \ |
- STATIC_ASSERT(arg_count <= Bytecodes::kMaximumNumberOfArguments); |
- BYTECODE_LIST(CHECK_SIZE) |
-#undef CHECK_SIZE |
+// static |
+const int Bytecodes::MaximumNumberOfOperands() { |
+ // TODO(oth): STATIC_ASSERT on number of operands. |
+ return kMaxOperands; |
+} |
+ |
+ |
+// static |
+const int Bytecodes::MaximumSize() { |
+ // TODO(oth): Maximum size of bytecode and associated operands |
+ STATIC_ASSERT(BytecodeInfo<Bytecode::kLoadSmi>::size == 6); |
+ return 6; |
+} |
std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode) { |