Home | History | Annotate | Download | only in wasm
      1 // Copyright 2017 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 #ifndef V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_
      6 #define V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_
      7 
      8 #include "src/wasm/decoder.h"
      9 #include "src/wasm/wasm-opcodes.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 namespace wasm {
     14 
     15 struct WasmGlobal;
     16 
     17 // Helpers for decoding different kinds of operands which follow bytecodes.
     18 struct LocalIndexOperand {
     19   uint32_t index;
     20   ValueType type;
     21   unsigned length;
     22 
     23   inline LocalIndexOperand(Decoder* decoder, const byte* pc) {
     24     index = decoder->checked_read_u32v(pc, 1, &length, "local index");
     25     type = kWasmStmt;
     26   }
     27 };
     28 
     29 struct ImmI32Operand {
     30   int32_t value;
     31   unsigned length;
     32   inline ImmI32Operand(Decoder* decoder, const byte* pc) {
     33     value = decoder->checked_read_i32v(pc, 1, &length, "immi32");
     34   }
     35 };
     36 
     37 struct ImmI64Operand {
     38   int64_t value;
     39   unsigned length;
     40   inline ImmI64Operand(Decoder* decoder, const byte* pc) {
     41     value = decoder->checked_read_i64v(pc, 1, &length, "immi64");
     42   }
     43 };
     44 
     45 struct ImmF32Operand {
     46   float value;
     47   unsigned length;
     48   inline ImmF32Operand(Decoder* decoder, const byte* pc) {
     49     // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
     50     uint32_t tmp = decoder->checked_read_u32(pc, 1, "immf32");
     51     memcpy(&value, &tmp, sizeof(value));
     52     length = 4;
     53   }
     54 };
     55 
     56 struct ImmF64Operand {
     57   double value;
     58   unsigned length;
     59   inline ImmF64Operand(Decoder* decoder, const byte* pc) {
     60     // Avoid bit_cast because it might not preserve the signalling bit of a NaN.
     61     uint64_t tmp = decoder->checked_read_u64(pc, 1, "immf64");
     62     memcpy(&value, &tmp, sizeof(value));
     63     length = 8;
     64   }
     65 };
     66 
     67 struct GlobalIndexOperand {
     68   uint32_t index;
     69   ValueType type;
     70   const WasmGlobal* global;
     71   unsigned length;
     72 
     73   inline GlobalIndexOperand(Decoder* decoder, const byte* pc) {
     74     index = decoder->checked_read_u32v(pc, 1, &length, "global index");
     75     global = nullptr;
     76     type = kWasmStmt;
     77   }
     78 };
     79 
     80 struct BlockTypeOperand {
     81   uint32_t arity;
     82   const byte* types;  // pointer to encoded types for the block.
     83   unsigned length;
     84 
     85   inline BlockTypeOperand(Decoder* decoder, const byte* pc) {
     86     uint8_t val = decoder->checked_read_u8(pc, 1, "block type");
     87     ValueType type = kWasmStmt;
     88     length = 1;
     89     arity = 0;
     90     types = nullptr;
     91     if (decode_local_type(val, &type)) {
     92       arity = type == kWasmStmt ? 0 : 1;
     93       types = pc + 1;
     94     } else {
     95       // Handle multi-value blocks.
     96       if (!FLAG_wasm_mv_prototype) {
     97         decoder->error(pc, pc + 1, "invalid block arity > 1");
     98         return;
     99       }
    100       if (val != kMultivalBlock) {
    101         decoder->error(pc, pc + 1, "invalid block type");
    102         return;
    103       }
    104       // Decode and check the types vector of the block.
    105       unsigned len = 0;
    106       uint32_t count = decoder->checked_read_u32v(pc, 2, &len, "block arity");
    107       // {count} is encoded as {arity-2}, so that a {0} count here corresponds
    108       // to a block with 2 values. This makes invalid/redundant encodings
    109       // impossible.
    110       arity = count + 2;
    111       length = 1 + len + arity;
    112       types = pc + 1 + 1 + len;
    113 
    114       for (uint32_t i = 0; i < arity; i++) {
    115         uint32_t offset = 1 + 1 + len + i;
    116         val = decoder->checked_read_u8(pc, offset, "block type");
    117         decode_local_type(val, &type);
    118         if (type == kWasmStmt) {
    119           decoder->error(pc, pc + offset, "invalid block type");
    120           return;
    121         }
    122       }
    123     }
    124   }
    125   // Decode a byte representing a local type. Return {false} if the encoded
    126   // byte was invalid or {kMultivalBlock}.
    127   bool decode_local_type(uint8_t val, ValueType* result) {
    128     switch (static_cast<ValueTypeCode>(val)) {
    129       case kLocalVoid:
    130         *result = kWasmStmt;
    131         return true;
    132       case kLocalI32:
    133         *result = kWasmI32;
    134         return true;
    135       case kLocalI64:
    136         *result = kWasmI64;
    137         return true;
    138       case kLocalF32:
    139         *result = kWasmF32;
    140         return true;
    141       case kLocalF64:
    142         *result = kWasmF64;
    143         return true;
    144       case kLocalS128:
    145         *result = kWasmS128;
    146         return true;
    147       case kLocalS1x4:
    148         *result = kWasmS1x4;
    149         return true;
    150       case kLocalS1x8:
    151         *result = kWasmS1x8;
    152         return true;
    153       case kLocalS1x16:
    154         *result = kWasmS1x16;
    155         return true;
    156       default:
    157         *result = kWasmStmt;
    158         return false;
    159     }
    160   }
    161   ValueType read_entry(unsigned index) {
    162     DCHECK_LT(index, arity);
    163     ValueType result;
    164     CHECK(decode_local_type(types[index], &result));
    165     return result;
    166   }
    167 };
    168 
    169 struct Control;
    170 struct BreakDepthOperand {
    171   uint32_t depth;
    172   Control* target;
    173   unsigned length;
    174   inline BreakDepthOperand(Decoder* decoder, const byte* pc) {
    175     depth = decoder->checked_read_u32v(pc, 1, &length, "break depth");
    176     target = nullptr;
    177   }
    178 };
    179 
    180 struct CallIndirectOperand {
    181   uint32_t table_index;
    182   uint32_t index;
    183   FunctionSig* sig;
    184   unsigned length;
    185   inline CallIndirectOperand(Decoder* decoder, const byte* pc) {
    186     unsigned len = 0;
    187     index = decoder->checked_read_u32v(pc, 1, &len, "signature index");
    188     table_index = decoder->checked_read_u8(pc, 1 + len, "table index");
    189     if (table_index != 0) {
    190       decoder->error(pc, pc + 1 + len, "expected table index 0, found %u",
    191                      table_index);
    192     }
    193     length = 1 + len;
    194     sig = nullptr;
    195   }
    196 };
    197 
    198 struct CallFunctionOperand {
    199   uint32_t index;
    200   FunctionSig* sig;
    201   unsigned length;
    202   inline CallFunctionOperand(Decoder* decoder, const byte* pc) {
    203     unsigned len1 = 0;
    204     unsigned len2 = 0;
    205     index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "function index");
    206     length = len1 + len2;
    207     sig = nullptr;
    208   }
    209 };
    210 
    211 struct MemoryIndexOperand {
    212   uint32_t index;
    213   unsigned length;
    214   inline MemoryIndexOperand(Decoder* decoder, const byte* pc) {
    215     index = decoder->checked_read_u8(pc, 1, "memory index");
    216     if (index != 0) {
    217       decoder->error(pc, pc + 1, "expected memory index 0, found %u", index);
    218     }
    219     length = 1;
    220   }
    221 };
    222 
    223 struct BranchTableOperand {
    224   uint32_t table_count;
    225   const byte* start;
    226   const byte* table;
    227   inline BranchTableOperand(Decoder* decoder, const byte* pc) {
    228     DCHECK_EQ(kExprBrTable, decoder->checked_read_u8(pc, 0, "opcode"));
    229     start = pc + 1;
    230     unsigned len1 = 0;
    231     table_count = decoder->checked_read_u32v(pc, 1, &len1, "table count");
    232     if (table_count > (UINT_MAX / sizeof(uint32_t)) - 1 ||
    233         len1 > UINT_MAX - (table_count + 1) * sizeof(uint32_t)) {
    234       decoder->error(pc, "branch table size overflow");
    235     }
    236     table = pc + 1 + len1;
    237   }
    238 };
    239 
    240 // A helper to iterate over a branch table.
    241 class BranchTableIterator {
    242  public:
    243   unsigned cur_index() { return index_; }
    244   bool has_next() { return decoder_->ok() && index_ <= table_count_; }
    245   uint32_t next() {
    246     DCHECK(has_next());
    247     index_++;
    248     unsigned length = 0;
    249     uint32_t result =
    250         decoder_->checked_read_u32v(pc_, 0, &length, "branch table entry");
    251     pc_ += length;
    252     return result;
    253   }
    254   // length, including the length of the {BranchTableOperand}, but not the
    255   // opcode.
    256   unsigned length() {
    257     while (has_next()) next();
    258     return static_cast<unsigned>(pc_ - start_);
    259   }
    260   const byte* pc() { return pc_; }
    261 
    262   BranchTableIterator(Decoder* decoder, BranchTableOperand& operand)
    263       : decoder_(decoder),
    264         start_(operand.start),
    265         pc_(operand.table),
    266         index_(0),
    267         table_count_(operand.table_count) {}
    268 
    269  private:
    270   Decoder* decoder_;
    271   const byte* start_;
    272   const byte* pc_;
    273   uint32_t index_;        // the current index.
    274   uint32_t table_count_;  // the count of entries, not including default.
    275 };
    276 
    277 struct MemoryAccessOperand {
    278   uint32_t alignment;
    279   uint32_t offset;
    280   unsigned length;
    281   inline MemoryAccessOperand(Decoder* decoder, const byte* pc,
    282                              uint32_t max_alignment) {
    283     unsigned alignment_length;
    284     alignment =
    285         decoder->checked_read_u32v(pc, 1, &alignment_length, "alignment");
    286     if (max_alignment < alignment) {
    287       decoder->error(pc, pc + 1,
    288                      "invalid alignment; expected maximum alignment is %u, "
    289                      "actual alignment is %u",
    290                      max_alignment, alignment);
    291     }
    292     unsigned offset_length;
    293     offset = decoder->checked_read_u32v(pc, 1 + alignment_length,
    294                                         &offset_length, "offset");
    295     length = alignment_length + offset_length;
    296   }
    297 };
    298 
    299 // Operand for SIMD lane operations.
    300 struct SimdLaneOperand {
    301   uint8_t lane;
    302   unsigned length;
    303 
    304   inline SimdLaneOperand(Decoder* decoder, const byte* pc) {
    305     lane = decoder->checked_read_u8(pc, 2, "lane");
    306     length = 1;
    307   }
    308 };
    309 
    310 // Operand for SIMD shift operations.
    311 struct SimdShiftOperand {
    312   uint8_t shift;
    313   unsigned length;
    314 
    315   inline SimdShiftOperand(Decoder* decoder, const byte* pc) {
    316     shift = decoder->checked_read_u8(pc, 2, "shift");
    317     length = 1;
    318   }
    319 };
    320 
    321 }  // namespace wasm
    322 }  // namespace internal
    323 }  // namespace v8
    324 
    325 #endif  // V8_WASM_FUNCTION_BODY_DECODER_IMPL_H_
    326