• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
LocalIndexOperandLocalIndexOperand23   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;
ImmI32OperandImmI32Operand32   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;
ImmI64OperandImmI64Operand40   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;
ImmF32OperandImmF32Operand48   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;
ImmF64OperandImmF64Operand59   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 
GlobalIndexOperandGlobalIndexOperand73   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 
BlockTypeOperandBlockTypeOperand85   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}.
decode_local_typeBlockTypeOperand127   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   }
read_entryBlockTypeOperand161   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;
BreakDepthOperandBreakDepthOperand174   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;
CallIndirectOperandCallIndirectOperand185   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;
CallFunctionOperandCallFunctionOperand202   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;
MemoryIndexOperandMemoryIndexOperand214   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;
BranchTableOperandBranchTableOperand227   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:
cur_index()243   unsigned cur_index() { return index_; }
has_next()244   bool has_next() { return decoder_->ok() && index_ <= table_count_; }
next()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.
length()256   unsigned length() {
257     while (has_next()) next();
258     return static_cast<unsigned>(pc_ - start_);
259   }
pc()260   const byte* pc() { return pc_; }
261 
BranchTableIterator(Decoder * decoder,BranchTableOperand & operand)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;
MemoryAccessOperandMemoryAccessOperand281   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 
SimdLaneOperandSimdLaneOperand304   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 
SimdShiftOperandSimdShiftOperand315   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