Home | History | Annotate | Download | only in wasm
      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/runtime/runtime.h"
      8 #include "src/signature.h"
      9 
     10 namespace v8 {
     11 namespace internal {
     12 namespace wasm {
     13 
     14 typedef Signature<ValueType> FunctionSig;
     15 
     16 #define CASE_OP(name, str) \
     17   case kExpr##name:        \
     18     return str;
     19 #define CASE_I32_OP(name, str) CASE_OP(I32##name, "i32." str)
     20 #define CASE_I64_OP(name, str) CASE_OP(I64##name, "i64." str)
     21 #define CASE_F32_OP(name, str) CASE_OP(F32##name, "f32." str)
     22 #define CASE_F64_OP(name, str) CASE_OP(F64##name, "f64." str)
     23 #define CASE_S128_OP(name, str) CASE_OP(S128##name, "s128." str)
     24 #define CASE_F32x4_OP(name, str) CASE_OP(F32x4##name, "f32x4." str)
     25 #define CASE_I32x4_OP(name, str) CASE_OP(I32x4##name, "i32x4." str)
     26 #define CASE_I16x8_OP(name, str) CASE_OP(I16x8##name, "i16x8." str)
     27 #define CASE_I8x16_OP(name, str) CASE_OP(I8x16##name, "i8x16." str)
     28 #define CASE_S32x4_OP(name, str) CASE_OP(S32x4##name, "s32x4." str)
     29 #define CASE_S16x8_OP(name, str) CASE_OP(S16x8##name, "s16x8." str)
     30 #define CASE_S8x16_OP(name, str) CASE_OP(S8x16##name, "s8x16." str)
     31 #define CASE_INT_OP(name, str) CASE_I32_OP(name, str) CASE_I64_OP(name, str)
     32 #define CASE_FLOAT_OP(name, str) CASE_F32_OP(name, str) CASE_F64_OP(name, str)
     33 #define CASE_ALL_OP(name, str) CASE_FLOAT_OP(name, str) CASE_INT_OP(name, str)
     34 #define CASE_SIMD_OP(name, str)                                              \
     35   CASE_F32x4_OP(name, str) CASE_I32x4_OP(name, str) CASE_I16x8_OP(name, str) \
     36       CASE_I8x16_OP(name, str)
     37 #define CASE_SIMDI_OP(name, str) \
     38   CASE_I32x4_OP(name, str) CASE_I16x8_OP(name, str) CASE_I8x16_OP(name, str)
     39 #define CASE_SIGN_OP(TYPE, name, str) \
     40   CASE_##TYPE##_OP(name##S, str "_s") CASE_##TYPE##_OP(name##U, str "_u")
     41 #define CASE_ALL_SIGN_OP(name, str) \
     42   CASE_FLOAT_OP(name, str) CASE_SIGN_OP(INT, name, str)
     43 #define CASE_CONVERT_OP(name, RES, SRC, src_suffix, str) \
     44   CASE_##RES##_OP(U##name##SRC, str "_u/" src_suffix)    \
     45       CASE_##RES##_OP(S##name##SRC, str "_s/" src_suffix)
     46 #define CASE_L32_OP(name, str)          \
     47   CASE_SIGN_OP(I32, name##8, str "8")   \
     48   CASE_SIGN_OP(I32, name##16, str "16") \
     49   CASE_I32_OP(name, str "32")
     50 
     51 const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
     52   switch (opcode) {
     53     // clang-format off
     54 
     55     // Standard opcodes
     56     CASE_INT_OP(Eqz, "eqz")
     57     CASE_ALL_OP(Eq, "eq")
     58     CASE_ALL_OP(Ne, "ne")
     59     CASE_ALL_OP(Add, "add")
     60     CASE_ALL_OP(Sub, "sub")
     61     CASE_ALL_OP(Mul, "mul")
     62     CASE_ALL_SIGN_OP(Lt, "lt")
     63     CASE_ALL_SIGN_OP(Gt, "gt")
     64     CASE_ALL_SIGN_OP(Le, "le")
     65     CASE_ALL_SIGN_OP(Ge, "ge")
     66     CASE_INT_OP(Clz, "clz")
     67     CASE_INT_OP(Ctz, "ctz")
     68     CASE_INT_OP(Popcnt, "popcnt")
     69     CASE_ALL_SIGN_OP(Div, "div")
     70     CASE_SIGN_OP(INT, Rem, "rem")
     71     CASE_INT_OP(And, "and")
     72     CASE_INT_OP(Ior, "or")
     73     CASE_INT_OP(Xor, "xor")
     74     CASE_INT_OP(Shl, "shl")
     75     CASE_SIGN_OP(INT, Shr, "shr")
     76     CASE_INT_OP(Rol, "rol")
     77     CASE_INT_OP(Ror, "ror")
     78     CASE_FLOAT_OP(Abs, "abs")
     79     CASE_FLOAT_OP(Neg, "neg")
     80     CASE_FLOAT_OP(Ceil, "ceil")
     81     CASE_FLOAT_OP(Floor, "floor")
     82     CASE_FLOAT_OP(Trunc, "trunc")
     83     CASE_FLOAT_OP(NearestInt, "nearest")
     84     CASE_FLOAT_OP(Sqrt, "sqrt")
     85     CASE_FLOAT_OP(Min, "min")
     86     CASE_FLOAT_OP(Max, "max")
     87     CASE_FLOAT_OP(CopySign, "copysign")
     88     CASE_I32_OP(ConvertI64, "wrap/i64")
     89     CASE_CONVERT_OP(Convert, INT, F32, "f32", "trunc")
     90     CASE_CONVERT_OP(Convert, INT, F64, "f64", "trunc")
     91     CASE_CONVERT_OP(Convert, I64, I32, "i32", "extend")
     92     CASE_CONVERT_OP(Convert, F32, I32, "i32", "convert")
     93     CASE_CONVERT_OP(Convert, F32, I64, "i64", "convert")
     94     CASE_F32_OP(ConvertF64, "demote/f64")
     95     CASE_CONVERT_OP(Convert, F64, I32, "i32", "convert")
     96     CASE_CONVERT_OP(Convert, F64, I64, "i64", "convert")
     97     CASE_F64_OP(ConvertF32, "promote/f32")
     98     CASE_I32_OP(ReinterpretF32, "reinterpret/f32")
     99     CASE_I64_OP(ReinterpretF64, "reinterpret/f64")
    100     CASE_F32_OP(ReinterpretI32, "reinterpret/i32")
    101     CASE_F64_OP(ReinterpretI64, "reinterpret/i64")
    102     CASE_OP(Unreachable, "unreachable")
    103     CASE_OP(Nop, "nop")
    104     CASE_OP(Block, "block")
    105     CASE_OP(Loop, "loop")
    106     CASE_OP(If, "if")
    107     CASE_OP(Else, "else")
    108     CASE_OP(End, "end")
    109     CASE_OP(Br, "br")
    110     CASE_OP(BrIf, "br_if")
    111     CASE_OP(BrTable, "br_table")
    112     CASE_OP(Return, "return")
    113     CASE_OP(CallFunction, "call")
    114     CASE_OP(CallIndirect, "call_indirect")
    115     CASE_OP(Drop, "drop")
    116     CASE_OP(Select, "select")
    117     CASE_OP(GetLocal, "get_local")
    118     CASE_OP(SetLocal, "set_local")
    119     CASE_OP(TeeLocal, "tee_local")
    120     CASE_OP(GetGlobal, "get_global")
    121     CASE_OP(SetGlobal, "set_global")
    122     CASE_ALL_OP(Const, "const")
    123     CASE_OP(MemorySize, "current_memory")
    124     CASE_OP(GrowMemory, "grow_memory")
    125     CASE_ALL_OP(LoadMem, "load")
    126     CASE_SIGN_OP(INT, LoadMem8, "load8")
    127     CASE_SIGN_OP(INT, LoadMem16, "load16")
    128     CASE_SIGN_OP(I64, LoadMem32, "load32")
    129     CASE_ALL_OP(StoreMem, "store")
    130     CASE_INT_OP(StoreMem8, "store8")
    131     CASE_INT_OP(StoreMem16, "store16")
    132     CASE_I64_OP(StoreMem32, "store32")
    133 
    134     // Non-standard opcodes.
    135     CASE_OP(Try, "try")
    136     CASE_OP(Throw, "throw")
    137     CASE_OP(Catch, "catch")
    138 
    139     // asm.js-only opcodes.
    140     CASE_F64_OP(Acos, "acos")
    141     CASE_F64_OP(Asin, "asin")
    142     CASE_F64_OP(Atan, "atan")
    143     CASE_F64_OP(Cos, "cos")
    144     CASE_F64_OP(Sin, "sin")
    145     CASE_F64_OP(Tan, "tan")
    146     CASE_F64_OP(Exp, "exp")
    147     CASE_F64_OP(Log, "log")
    148     CASE_F64_OP(Atan2, "atan2")
    149     CASE_F64_OP(Pow, "pow")
    150     CASE_F64_OP(Mod, "mod")
    151     CASE_F32_OP(AsmjsLoadMem, "asmjs_load")
    152     CASE_F64_OP(AsmjsLoadMem, "asmjs_load")
    153     CASE_L32_OP(AsmjsLoadMem, "asmjs_load")
    154     CASE_I32_OP(AsmjsStoreMem, "asmjs_store")
    155     CASE_F32_OP(AsmjsStoreMem, "asmjs_store")
    156     CASE_F64_OP(AsmjsStoreMem, "asmjs_store")
    157     CASE_I32_OP(AsmjsStoreMem8, "asmjs_store8")
    158     CASE_I32_OP(AsmjsStoreMem16, "asmjs_store16")
    159     CASE_SIGN_OP(I32, AsmjsDiv, "asmjs_div")
    160     CASE_SIGN_OP(I32, AsmjsRem, "asmjs_rem")
    161     CASE_I32_OP(AsmjsSConvertF32, "asmjs_convert_s/f32")
    162     CASE_I32_OP(AsmjsUConvertF32, "asmjs_convert_u/f32")
    163     CASE_I32_OP(AsmjsSConvertF64, "asmjs_convert_s/f64")
    164     CASE_I32_OP(AsmjsUConvertF64, "asmjs_convert_u/f64")
    165 
    166     // SIMD opcodes.
    167     CASE_SIMD_OP(Splat, "splat")
    168     CASE_SIMD_OP(Neg, "neg")
    169     CASE_SIMD_OP(Eq, "eq")
    170     CASE_SIMD_OP(Ne, "ne")
    171     CASE_SIMD_OP(Add, "add")
    172     CASE_SIMD_OP(Sub, "sub")
    173     CASE_SIMD_OP(Mul, "mul")
    174     CASE_F32x4_OP(Abs, "abs")
    175     CASE_F32x4_OP(Sqrt, "sqrt")
    176     CASE_F32x4_OP(Div, "div")
    177     CASE_F32x4_OP(RecipApprox, "recip_approx")
    178     CASE_F32x4_OP(SqrtApprox, "sqrt_approx")
    179     CASE_F32x4_OP(Min, "min")
    180     CASE_F32x4_OP(Max, "max")
    181     CASE_F32x4_OP(MinNum, "min_num")
    182     CASE_F32x4_OP(MaxNum, "max_num")
    183     CASE_F32x4_OP(Lt, "lt")
    184     CASE_F32x4_OP(Le, "le")
    185     CASE_F32x4_OP(Gt, "gt")
    186     CASE_F32x4_OP(Ge, "ge")
    187     CASE_CONVERT_OP(Convert, F32x4, I32x4, "i32", "convert")
    188     CASE_CONVERT_OP(Convert, I32x4, F32x4, "f32", "convert")
    189     CASE_F32x4_OP(ExtractLane, "extract_lane")
    190     CASE_F32x4_OP(ReplaceLane, "replace_lane")
    191     CASE_SIMDI_OP(ExtractLane, "extract_lane")
    192     CASE_SIMDI_OP(ReplaceLane, "replace_lane")
    193     CASE_SIGN_OP(SIMDI, Min, "min")
    194     CASE_SIGN_OP(SIMDI, Max, "max")
    195     CASE_SIGN_OP(SIMDI, Lt, "lt")
    196     CASE_SIGN_OP(SIMDI, Le, "le")
    197     CASE_SIGN_OP(SIMDI, Gt, "gt")
    198     CASE_SIGN_OP(SIMDI, Ge, "ge")
    199     CASE_SIGN_OP(SIMDI, Shr, "shr")
    200     CASE_SIMDI_OP(Shl, "shl")
    201     CASE_SIGN_OP(I16x8, AddSaturate, "add_saturate")
    202     CASE_SIGN_OP(I8x16, AddSaturate, "add_saturate")
    203     CASE_SIGN_OP(I16x8, SubSaturate, "sub_saturate")
    204     CASE_SIGN_OP(I8x16, SubSaturate, "sub_saturate")
    205     CASE_S128_OP(Or, "or")
    206     CASE_S128_OP(Xor, "xor")
    207     CASE_S128_OP(And, "and")
    208     CASE_S128_OP(Not, "not")
    209     CASE_S32x4_OP(Select, "select")
    210     CASE_S32x4_OP(Swizzle, "swizzle")
    211     CASE_S32x4_OP(Shuffle, "shuffle")
    212     CASE_S16x8_OP(Select, "select")
    213     CASE_S16x8_OP(Swizzle, "swizzle")
    214     CASE_S16x8_OP(Shuffle, "shuffle")
    215     CASE_S8x16_OP(Select, "select")
    216     CASE_S8x16_OP(Swizzle, "swizzle")
    217     CASE_S8x16_OP(Shuffle, "shuffle")
    218 
    219     // Atomic operations.
    220     CASE_L32_OP(AtomicAdd, "atomic_add")
    221     CASE_L32_OP(AtomicAnd, "atomic_and")
    222     CASE_L32_OP(AtomicCompareExchange, "atomic_cmpxchng")
    223     CASE_L32_OP(AtomicExchange, "atomic_xchng")
    224     CASE_L32_OP(AtomicOr, "atomic_or")
    225     CASE_L32_OP(AtomicSub, "atomic_sub")
    226     CASE_L32_OP(AtomicXor, "atomic_xor")
    227 
    228     default : return "unknown";
    229     // clang-format on
    230   }
    231 }
    232 
    233 bool WasmOpcodes::IsPrefixOpcode(WasmOpcode opcode) {
    234   switch (opcode) {
    235 #define CHECK_PREFIX(name, opcode) \
    236   case k##name##Prefix:            \
    237     return true;
    238     FOREACH_PREFIX(CHECK_PREFIX)
    239 #undef CHECK_PREFIX
    240     default:
    241       return false;
    242   }
    243 }
    244 
    245 std::ostream& operator<<(std::ostream& os, const FunctionSig& sig) {
    246   if (sig.return_count() == 0) os << "v";
    247   for (size_t i = 0; i < sig.return_count(); ++i) {
    248     os << WasmOpcodes::ShortNameOf(sig.GetReturn(i));
    249   }
    250   os << "_";
    251   if (sig.parameter_count() == 0) os << "v";
    252   for (size_t i = 0; i < sig.parameter_count(); ++i) {
    253     os << WasmOpcodes::ShortNameOf(sig.GetParam(i));
    254   }
    255   return os;
    256 }
    257 
    258 #define DECLARE_SIG_ENUM(name, ...) kSigEnum_##name,
    259 
    260 enum WasmOpcodeSig { FOREACH_SIGNATURE(DECLARE_SIG_ENUM) };
    261 
    262 // TODO(titzer): not static-initializer safe. Wrap in LazyInstance.
    263 #define DECLARE_SIG(name, ...)                      \
    264   static ValueType kTypes_##name[] = {__VA_ARGS__}; \
    265   static const FunctionSig kSig_##name(             \
    266       1, static_cast<int>(arraysize(kTypes_##name)) - 1, kTypes_##name);
    267 
    268 FOREACH_SIGNATURE(DECLARE_SIG)
    269 
    270 #define DECLARE_SIG_ENTRY(name, ...) &kSig_##name,
    271 
    272 static const FunctionSig* kSimpleExprSigs[] = {
    273     nullptr, FOREACH_SIGNATURE(DECLARE_SIG_ENTRY)};
    274 
    275 #define DECLARE_SIMD_SIG_ENTRY(name, ...) &kSig_##name,
    276 
    277 static const FunctionSig* kSimdExprSigs[] = {
    278     nullptr, FOREACH_SIMD_SIGNATURE(DECLARE_SIMD_SIG_ENTRY)};
    279 
    280 static byte kSimpleExprSigTable[256];
    281 static byte kSimpleAsmjsExprSigTable[256];
    282 static byte kSimdExprSigTable[256];
    283 static byte kAtomicExprSigTable[256];
    284 
    285 // Initialize the signature table.
    286 static void InitSigTables() {
    287 #define SET_SIG_TABLE(name, opcode, sig) \
    288   kSimpleExprSigTable[opcode] = static_cast<int>(kSigEnum_##sig) + 1;
    289   FOREACH_SIMPLE_OPCODE(SET_SIG_TABLE);
    290 #undef SET_SIG_TABLE
    291 #define SET_ASMJS_SIG_TABLE(name, opcode, sig) \
    292   kSimpleAsmjsExprSigTable[opcode] = static_cast<int>(kSigEnum_##sig) + 1;
    293   FOREACH_ASMJS_COMPAT_OPCODE(SET_ASMJS_SIG_TABLE);
    294 #undef SET_ASMJS_SIG_TABLE
    295   byte simd_index;
    296 #define SET_SIG_TABLE(name, opcode, sig) \
    297   simd_index = opcode & 0xff;            \
    298   kSimdExprSigTable[simd_index] = static_cast<int>(kSigEnum_##sig) + 1;
    299   FOREACH_SIMD_0_OPERAND_OPCODE(SET_SIG_TABLE)
    300 #undef SET_SIG_TABLE
    301   byte atomic_index;
    302 #define SET_ATOMIC_SIG_TABLE(name, opcode, sig) \
    303   atomic_index = opcode & 0xff;                 \
    304   kAtomicExprSigTable[atomic_index] = static_cast<int>(kSigEnum_##sig) + 1;
    305   FOREACH_ATOMIC_OPCODE(SET_ATOMIC_SIG_TABLE)
    306 #undef SET_ATOMIC_SIG_TABLE
    307 }
    308 
    309 class SigTable {
    310  public:
    311   SigTable() {
    312     // TODO(ahaas): Move {InitSigTable} into the class.
    313     InitSigTables();
    314   }
    315   FunctionSig* Signature(WasmOpcode opcode) const {
    316     return const_cast<FunctionSig*>(
    317         kSimpleExprSigs[kSimpleExprSigTable[static_cast<byte>(opcode)]]);
    318   }
    319   FunctionSig* AsmjsSignature(WasmOpcode opcode) const {
    320     return const_cast<FunctionSig*>(
    321         kSimpleExprSigs[kSimpleAsmjsExprSigTable[static_cast<byte>(opcode)]]);
    322   }
    323   FunctionSig* SimdSignature(WasmOpcode opcode) const {
    324     return const_cast<FunctionSig*>(
    325         kSimdExprSigs[kSimdExprSigTable[static_cast<byte>(opcode & 0xff)]]);
    326   }
    327   FunctionSig* AtomicSignature(WasmOpcode opcode) const {
    328     return const_cast<FunctionSig*>(
    329         kSimpleExprSigs[kAtomicExprSigTable[static_cast<byte>(opcode & 0xff)]]);
    330   }
    331 };
    332 
    333 static base::LazyInstance<SigTable>::type sig_table = LAZY_INSTANCE_INITIALIZER;
    334 
    335 FunctionSig* WasmOpcodes::Signature(WasmOpcode opcode) {
    336   if (opcode >> 8 == kSimdPrefix) {
    337     return sig_table.Get().SimdSignature(opcode);
    338   } else {
    339     return sig_table.Get().Signature(opcode);
    340   }
    341 }
    342 
    343 FunctionSig* WasmOpcodes::AsmjsSignature(WasmOpcode opcode) {
    344   return sig_table.Get().AsmjsSignature(opcode);
    345 }
    346 
    347 FunctionSig* WasmOpcodes::AtomicSignature(WasmOpcode opcode) {
    348   return sig_table.Get().AtomicSignature(opcode);
    349 }
    350 
    351 // TODO(titzer): pull WASM_64 up to a common header.
    352 #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64
    353 #define WASM_64 1
    354 #else
    355 #define WASM_64 0
    356 #endif
    357 
    358 int WasmOpcodes::TrapReasonToMessageId(TrapReason reason) {
    359   switch (reason) {
    360 #define TRAPREASON_TO_MESSAGE(name) \
    361   case k##name:                     \
    362     return MessageTemplate::kWasm##name;
    363     FOREACH_WASM_TRAPREASON(TRAPREASON_TO_MESSAGE)
    364 #undef TRAPREASON_TO_MESSAGE
    365     default:
    366       return MessageTemplate::kNone;
    367   }
    368 }
    369 
    370 const char* WasmOpcodes::TrapReasonMessage(TrapReason reason) {
    371   return MessageTemplate::TemplateString(TrapReasonToMessageId(reason));
    372 }
    373 }  // namespace wasm
    374 }  // namespace internal
    375 }  // namespace v8
    376