Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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 | #ifndef V8_WASM_AST_DECODER_H_ |
| 6 | #define V8_WASM_AST_DECODER_H_ |
| 7 | |
| 8 | #include "src/signature.h" |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 9 | #include "src/wasm/decoder.h" |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 10 | #include "src/wasm/wasm-opcodes.h" |
| 11 | #include "src/wasm/wasm-result.h" |
| 12 | |
| 13 | namespace v8 { |
| 14 | namespace internal { |
| 15 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 16 | class BitVector; // forward declaration |
| 17 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 18 | namespace compiler { // external declarations from compiler. |
| 19 | class WasmGraphBuilder; |
| 20 | } |
| 21 | |
| 22 | namespace wasm { |
| 23 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 24 | // Helpers for decoding different kinds of operands which follow bytecodes. |
| 25 | struct LocalIndexOperand { |
| 26 | uint32_t index; |
| 27 | LocalType type; |
| 28 | int length; |
| 29 | |
| 30 | inline LocalIndexOperand(Decoder* decoder, const byte* pc) { |
| 31 | index = decoder->checked_read_u32v(pc, 1, &length, "local index"); |
| 32 | type = kAstStmt; |
| 33 | } |
| 34 | }; |
| 35 | |
| 36 | struct ImmI8Operand { |
| 37 | int8_t value; |
| 38 | int length; |
| 39 | inline ImmI8Operand(Decoder* decoder, const byte* pc) { |
| 40 | value = bit_cast<int8_t>(decoder->checked_read_u8(pc, 1, "immi8")); |
| 41 | length = 1; |
| 42 | } |
| 43 | }; |
| 44 | |
| 45 | struct ImmI32Operand { |
| 46 | int32_t value; |
| 47 | int length; |
| 48 | inline ImmI32Operand(Decoder* decoder, const byte* pc) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 49 | value = decoder->checked_read_i32v(pc, 1, &length, "immi32"); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 50 | } |
| 51 | }; |
| 52 | |
| 53 | struct ImmI64Operand { |
| 54 | int64_t value; |
| 55 | int length; |
| 56 | inline ImmI64Operand(Decoder* decoder, const byte* pc) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 57 | value = decoder->checked_read_i64v(pc, 1, &length, "immi64"); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 58 | } |
| 59 | }; |
| 60 | |
| 61 | struct ImmF32Operand { |
| 62 | float value; |
| 63 | int length; |
| 64 | inline ImmF32Operand(Decoder* decoder, const byte* pc) { |
| 65 | value = bit_cast<float>(decoder->checked_read_u32(pc, 1, "immf32")); |
| 66 | length = 4; |
| 67 | } |
| 68 | }; |
| 69 | |
| 70 | struct ImmF64Operand { |
| 71 | double value; |
| 72 | int length; |
| 73 | inline ImmF64Operand(Decoder* decoder, const byte* pc) { |
| 74 | value = bit_cast<double>(decoder->checked_read_u64(pc, 1, "immf64")); |
| 75 | length = 8; |
| 76 | } |
| 77 | }; |
| 78 | |
| 79 | struct GlobalIndexOperand { |
| 80 | uint32_t index; |
| 81 | LocalType type; |
| 82 | MachineType machine_type; |
| 83 | int length; |
| 84 | |
| 85 | inline GlobalIndexOperand(Decoder* decoder, const byte* pc) { |
| 86 | index = decoder->checked_read_u32v(pc, 1, &length, "global index"); |
| 87 | type = kAstStmt; |
| 88 | machine_type = MachineType::None(); |
| 89 | } |
| 90 | }; |
| 91 | |
| 92 | struct Block; |
| 93 | struct BreakDepthOperand { |
| 94 | uint32_t depth; |
| 95 | Block* target; |
| 96 | int length; |
| 97 | inline BreakDepthOperand(Decoder* decoder, const byte* pc) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 98 | depth = decoder->checked_read_u32v(pc, 1, &length, "break depth"); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 99 | target = nullptr; |
| 100 | } |
| 101 | }; |
| 102 | |
| 103 | struct BlockCountOperand { |
| 104 | uint32_t count; |
| 105 | int length; |
| 106 | inline BlockCountOperand(Decoder* decoder, const byte* pc) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 107 | count = decoder->checked_read_u32v(pc, 1, &length, "block count"); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 108 | } |
| 109 | }; |
| 110 | |
| 111 | struct SignatureIndexOperand { |
| 112 | uint32_t index; |
| 113 | FunctionSig* sig; |
| 114 | int length; |
| 115 | inline SignatureIndexOperand(Decoder* decoder, const byte* pc) { |
| 116 | index = decoder->checked_read_u32v(pc, 1, &length, "signature index"); |
| 117 | sig = nullptr; |
| 118 | } |
| 119 | }; |
| 120 | |
| 121 | struct FunctionIndexOperand { |
| 122 | uint32_t index; |
| 123 | FunctionSig* sig; |
| 124 | int length; |
| 125 | inline FunctionIndexOperand(Decoder* decoder, const byte* pc) { |
| 126 | index = decoder->checked_read_u32v(pc, 1, &length, "function index"); |
| 127 | sig = nullptr; |
| 128 | } |
| 129 | }; |
| 130 | |
| 131 | struct ImportIndexOperand { |
| 132 | uint32_t index; |
| 133 | FunctionSig* sig; |
| 134 | int length; |
| 135 | inline ImportIndexOperand(Decoder* decoder, const byte* pc) { |
| 136 | index = decoder->checked_read_u32v(pc, 1, &length, "import index"); |
| 137 | sig = nullptr; |
| 138 | } |
| 139 | }; |
| 140 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 141 | struct BranchTableOperand { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 142 | uint32_t table_count; |
| 143 | const byte* table; |
| 144 | int length; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 145 | inline BranchTableOperand(Decoder* decoder, const byte* pc) { |
| 146 | int varint_length; |
| 147 | table_count = |
| 148 | decoder->checked_read_u32v(pc, 1, &varint_length, "expected #entries"); |
| 149 | length = varint_length + (table_count + 1) * sizeof(uint32_t); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 150 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 151 | uint32_t table_start = 1 + varint_length; |
| 152 | if (decoder->check(pc, table_start, (table_count + 1) * sizeof(uint32_t), |
| 153 | "expected <table entries>")) { |
| 154 | table = pc + table_start; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 155 | } else { |
| 156 | table = nullptr; |
| 157 | } |
| 158 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 159 | inline uint32_t read_entry(Decoder* decoder, int i) { |
| 160 | DCHECK(i >= 0 && static_cast<uint32_t>(i) <= table_count); |
| 161 | return table ? decoder->read_u32(table + i * sizeof(uint32_t)) : 0; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 162 | } |
| 163 | }; |
| 164 | |
| 165 | struct MemoryAccessOperand { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 166 | uint32_t alignment; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 167 | uint32_t offset; |
| 168 | int length; |
| 169 | inline MemoryAccessOperand(Decoder* decoder, const byte* pc) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 170 | int alignment_length; |
| 171 | alignment = |
| 172 | decoder->checked_read_u32v(pc, 1, &alignment_length, "alignment"); |
| 173 | int offset_length; |
| 174 | offset = decoder->checked_read_u32v(pc, 1 + alignment_length, |
| 175 | &offset_length, "offset"); |
| 176 | length = alignment_length + offset_length; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 177 | } |
| 178 | }; |
| 179 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 180 | typedef compiler::WasmGraphBuilder TFBuilder; |
| 181 | struct ModuleEnv; // forward declaration of module interface. |
| 182 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 183 | // All of the various data structures necessary to decode a function body. |
| 184 | struct FunctionBody { |
| 185 | ModuleEnv* module; // module environment |
| 186 | FunctionSig* sig; // function signature |
| 187 | const byte* base; // base of the module bytes, for error reporting |
| 188 | const byte* start; // start of the function body |
| 189 | const byte* end; // end of the function body |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 190 | }; |
| 191 | |
| 192 | struct Tree; |
| 193 | typedef Result<Tree*> TreeResult; |
| 194 | |
| 195 | std::ostream& operator<<(std::ostream& os, const Tree& tree); |
| 196 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 197 | TreeResult VerifyWasmCode(base::AccountingAllocator* allocator, |
| 198 | FunctionBody& body); |
| 199 | TreeResult BuildTFGraph(base::AccountingAllocator* allocator, |
| 200 | TFBuilder* builder, FunctionBody& body); |
| 201 | void PrintAst(base::AccountingAllocator* allocator, FunctionBody& body); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 202 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 203 | inline TreeResult VerifyWasmCode(base::AccountingAllocator* allocator, |
| 204 | ModuleEnv* module, FunctionSig* sig, |
| 205 | const byte* start, const byte* end) { |
| 206 | FunctionBody body = {module, sig, nullptr, start, end}; |
| 207 | return VerifyWasmCode(allocator, body); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 208 | } |
| 209 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 210 | inline TreeResult BuildTFGraph(base::AccountingAllocator* allocator, |
| 211 | TFBuilder* builder, ModuleEnv* module, |
| 212 | FunctionSig* sig, const byte* start, |
| 213 | const byte* end) { |
| 214 | FunctionBody body = {module, sig, nullptr, start, end}; |
| 215 | return BuildTFGraph(allocator, builder, body); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 216 | } |
| 217 | |
| 218 | enum ReadUnsignedLEB128ErrorCode { kNoError, kInvalidLEB128, kMissingLEB128 }; |
| 219 | |
| 220 | ReadUnsignedLEB128ErrorCode ReadUnsignedLEB128Operand(const byte*, const byte*, |
| 221 | int*, uint32_t*); |
| 222 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 223 | struct AstLocalDecls { |
| 224 | // The size of the encoded declarations. |
| 225 | uint32_t decls_encoded_size; // size of encoded declarations |
| 226 | |
| 227 | // Total number of locals. |
| 228 | uint32_t total_local_count; |
| 229 | |
| 230 | // List of {local type, count} pairs. |
| 231 | ZoneVector<std::pair<LocalType, uint32_t>> local_types; |
| 232 | |
| 233 | // Constructor initializes the vector. |
| 234 | explicit AstLocalDecls(Zone* zone) |
| 235 | : decls_encoded_size(0), total_local_count(0), local_types(zone) {} |
| 236 | }; |
| 237 | |
| 238 | bool DecodeLocalDecls(AstLocalDecls& decls, const byte* start, const byte* end); |
| 239 | BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 240 | const byte* start, const byte* end); |
| 241 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 242 | // Computes the length of the opcode at the given address. |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 243 | int OpcodeLength(const byte* pc, const byte* end); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 244 | |
| 245 | // Computes the arity (number of sub-nodes) of the opcode at the given address. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 246 | int OpcodeArity(ModuleEnv* module, FunctionSig* sig, const byte* pc, |
| 247 | const byte* end); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 248 | } // namespace wasm |
| 249 | } // namespace internal |
| 250 | } // namespace v8 |
| 251 | |
| 252 | #endif // V8_WASM_AST_DECODER_H_ |