1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/wasm/wasm-opcodes.h"
6 #include "src/messages.h"
7 #include "src/signature.h"
8 
9 namespace v8 {
10 namespace internal {
11 namespace wasm {
12 
13 typedef Signature<LocalType> FunctionSig;
14 
OpcodeName(WasmOpcode opcode)15 const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
16   switch (opcode) {
17 #define DECLARE_NAME_CASE(name, opcode, sig) \
18   case kExpr##name:                          \
19     return "Expr" #name;
20     FOREACH_OPCODE(DECLARE_NAME_CASE)
21 #undef DECLARE_NAME_CASE
22     default:
23       break;
24   }
25   return "Unknown";
26 }
27 
ShortOpcodeName(WasmOpcode opcode)28 const char* WasmOpcodes::ShortOpcodeName(WasmOpcode opcode) {
29   switch (opcode) {
30 #define DECLARE_NAME_CASE(name, opcode, sig) \
31   case kExpr##name:                          \
32     return #name;
33     FOREACH_OPCODE(DECLARE_NAME_CASE)
34 #undef DECLARE_NAME_CASE
35     default:
36       break;
37   }
38   return "Unknown";
39 }
40 
IsPrefixOpcode(WasmOpcode opcode)41 bool WasmOpcodes::IsPrefixOpcode(WasmOpcode opcode) {
42   switch (opcode) {
43 #define CHECK_PREFIX(name, opcode) \
44   case k##name##Prefix:            \
45     return true;
46     FOREACH_PREFIX(CHECK_PREFIX)
47 #undef CHECK_PREFIX
48     default:
49       return false;
50   }
51 }
52 
operator <<(std::ostream & os,const FunctionSig & sig)53 std::ostream& operator<<(std::ostream& os, const FunctionSig& sig) {
54   if (sig.return_count() == 0) os << "v";
55   for (size_t i = 0; i < sig.return_count(); ++i) {
56     os << WasmOpcodes::ShortNameOf(sig.GetReturn(i));
57   }
58   os << "_";
59   if (sig.parameter_count() == 0) os << "v";
60   for (size_t i = 0; i < sig.parameter_count(); ++i) {
61     os << WasmOpcodes::ShortNameOf(sig.GetParam(i));
62   }
63   return os;
64 }
65 
66 #define DECLARE_SIG_ENUM(name, ...) kSigEnum_##name,
67 
68 enum WasmOpcodeSig { FOREACH_SIGNATURE(DECLARE_SIG_ENUM) };
69 
70 // TODO(titzer): not static-initializer safe. Wrap in LazyInstance.
71 #define DECLARE_SIG(name, ...)                      \
72   static LocalType kTypes_##name[] = {__VA_ARGS__}; \
73   static const FunctionSig kSig_##name(             \
74       1, static_cast<int>(arraysize(kTypes_##name)) - 1, kTypes_##name);
75 
76 FOREACH_SIGNATURE(DECLARE_SIG)
77 
78 #define DECLARE_SIG_ENTRY(name, ...) &kSig_##name,
79 
80 static const FunctionSig* kSimpleExprSigs[] = {
81     nullptr, FOREACH_SIGNATURE(DECLARE_SIG_ENTRY)};
82 
83 #define DECLARE_SIMD_SIG_ENTRY(name, ...) &kSig_##name,
84 
85 static const FunctionSig* kSimdExprSigs[] = {
86     nullptr, FOREACH_SIMD_SIGNATURE(DECLARE_SIMD_SIG_ENTRY)};
87 
88 static byte kSimpleExprSigTable[256];
89 static byte kSimpleAsmjsExprSigTable[256];
90 static byte kSimdExprSigTable[256];
91 static byte kAtomicExprSigTable[256];
92 
93 // Initialize the signature table.
InitSigTables()94 static void InitSigTables() {
95 #define SET_SIG_TABLE(name, opcode, sig) \
96   kSimpleExprSigTable[opcode] = static_cast<int>(kSigEnum_##sig) + 1;
97   FOREACH_SIMPLE_OPCODE(SET_SIG_TABLE);
98 #undef SET_SIG_TABLE
99 #define SET_ASMJS_SIG_TABLE(name, opcode, sig) \
100   kSimpleAsmjsExprSigTable[opcode] = static_cast<int>(kSigEnum_##sig) + 1;
101   FOREACH_ASMJS_COMPAT_OPCODE(SET_ASMJS_SIG_TABLE);
102 #undef SET_ASMJS_SIG_TABLE
103   byte simd_index;
104 #define SET_SIG_TABLE(name, opcode, sig) \
105   simd_index = opcode & 0xff;            \
106   kSimdExprSigTable[simd_index] = static_cast<int>(kSigEnum_##sig) + 1;
107   FOREACH_SIMD_0_OPERAND_OPCODE(SET_SIG_TABLE)
108 #undef SET_SIG_TABLE
109   byte atomic_index;
110 #define SET_ATOMIC_SIG_TABLE(name, opcode, sig) \
111   atomic_index = opcode & 0xff;                 \
112   kAtomicExprSigTable[atomic_index] = static_cast<int>(kSigEnum_##sig) + 1;
113   FOREACH_ATOMIC_OPCODE(SET_ATOMIC_SIG_TABLE)
114 #undef SET_ATOMIC_SIG_TABLE
115 }
116 
117 class SigTable {
118  public:
SigTable()119   SigTable() {
120     // TODO(ahaas): Move {InitSigTable} into the class.
121     InitSigTables();
122   }
Signature(WasmOpcode opcode) const123   FunctionSig* Signature(WasmOpcode opcode) const {
124     return const_cast<FunctionSig*>(
125         kSimpleExprSigs[kSimpleExprSigTable[static_cast<byte>(opcode)]]);
126   }
AsmjsSignature(WasmOpcode opcode) const127   FunctionSig* AsmjsSignature(WasmOpcode opcode) const {
128     return const_cast<FunctionSig*>(
129         kSimpleExprSigs[kSimpleAsmjsExprSigTable[static_cast<byte>(opcode)]]);
130   }
SimdSignature(WasmOpcode opcode) const131   FunctionSig* SimdSignature(WasmOpcode opcode) const {
132     return const_cast<FunctionSig*>(
133         kSimdExprSigs[kSimdExprSigTable[static_cast<byte>(opcode & 0xff)]]);
134   }
AtomicSignature(WasmOpcode opcode) const135   FunctionSig* AtomicSignature(WasmOpcode opcode) const {
136     return const_cast<FunctionSig*>(
137         kSimpleExprSigs[kAtomicExprSigTable[static_cast<byte>(opcode & 0xff)]]);
138   }
139 };
140 
141 static base::LazyInstance<SigTable>::type sig_table = LAZY_INSTANCE_INITIALIZER;
142 
Signature(WasmOpcode opcode)143 FunctionSig* WasmOpcodes::Signature(WasmOpcode opcode) {
144   if (opcode >> 8 == kSimdPrefix) {
145     return sig_table.Get().SimdSignature(opcode);
146   } else {
147     return sig_table.Get().Signature(opcode);
148   }
149 }
150 
AsmjsSignature(WasmOpcode opcode)151 FunctionSig* WasmOpcodes::AsmjsSignature(WasmOpcode opcode) {
152   return sig_table.Get().AsmjsSignature(opcode);
153 }
154 
AtomicSignature(WasmOpcode opcode)155 FunctionSig* WasmOpcodes::AtomicSignature(WasmOpcode opcode) {
156   return sig_table.Get().AtomicSignature(opcode);
157 }
158 
159 // TODO(titzer): pull WASM_64 up to a common header.
160 #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64
161 #define WASM_64 1
162 #else
163 #define WASM_64 0
164 #endif
165 
TrapReasonToMessageId(TrapReason reason)166 int WasmOpcodes::TrapReasonToMessageId(TrapReason reason) {
167   switch (reason) {
168 #define TRAPREASON_TO_MESSAGE(name) \
169   case k##name:                     \
170     return MessageTemplate::kWasm##name;
171     FOREACH_WASM_TRAPREASON(TRAPREASON_TO_MESSAGE)
172 #undef TRAPREASON_TO_MESSAGE
173     default:
174       return MessageTemplate::kNone;
175   }
176 }
177 
TrapReasonMessage(TrapReason reason)178 const char* WasmOpcodes::TrapReasonMessage(TrapReason reason) {
179   return MessageTemplate::TemplateString(TrapReasonToMessageId(reason));
180 }
181 }  // namespace wasm
182 }  // namespace internal
183 }  // namespace v8
184