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
11namespace v8 {
12namespace internal {
13namespace wasm {
14
15struct WasmGlobal;
16
17// Helpers for decoding different kinds of operands which follow bytecodes.
18struct 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
29struct 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
37struct 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
45struct 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
56struct 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
67struct 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
80struct 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
169struct Control;
170struct 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
180struct 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
198struct 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
211struct 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
223struct 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.
241class 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
277struct 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.
300struct 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.
311struct 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