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