| 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 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 5 | #include "src/wasm/module-decoder.h" | 
 | 6 |  | 
 | 7 | #include "src/base/functional.h" | 
 | 8 | #include "src/base/platform/platform.h" | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 9 | #include "src/macro-assembler.h" | 
 | 10 | #include "src/objects.h" | 
 | 11 | #include "src/v8.h" | 
 | 12 |  | 
 | 13 | #include "src/wasm/decoder.h" | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 14 |  | 
 | 15 | namespace v8 { | 
 | 16 | namespace internal { | 
 | 17 | namespace wasm { | 
 | 18 |  | 
 | 19 | #if DEBUG | 
 | 20 | #define TRACE(...)                                    \ | 
 | 21 |   do {                                                \ | 
 | 22 |     if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \ | 
 | 23 |   } while (false) | 
 | 24 | #else | 
 | 25 | #define TRACE(...) | 
 | 26 | #endif | 
 | 27 |  | 
 | 28 |  | 
 | 29 | // The main logic for decoding the bytes of a module. | 
 | 30 | class ModuleDecoder : public Decoder { | 
 | 31 |  public: | 
 | 32 |   ModuleDecoder(Zone* zone, const byte* module_start, const byte* module_end, | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 33 |                 ModuleOrigin origin) | 
 | 34 |       : Decoder(module_start, module_end), module_zone(zone), origin_(origin) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 35 |     result_.start = start_; | 
 | 36 |     if (limit_ < start_) { | 
 | 37 |       error(start_, "end is less than start"); | 
 | 38 |       limit_ = start_; | 
 | 39 |     } | 
 | 40 |   } | 
 | 41 |  | 
 | 42 |   virtual void onFirstError() { | 
 | 43 |     pc_ = limit_;  // On error, terminate section decoding loop. | 
 | 44 |   } | 
 | 45 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 46 |   static void DumpModule(WasmModule* module, ModuleResult result) { | 
 | 47 |     std::string path; | 
 | 48 |     if (FLAG_dump_wasm_module_path) { | 
 | 49 |       path = FLAG_dump_wasm_module_path; | 
 | 50 |       if (path.size() && | 
 | 51 |           !base::OS::isDirectorySeparator(path[path.size() - 1])) { | 
 | 52 |         path += base::OS::DirectorySeparator(); | 
 | 53 |       } | 
 | 54 |     } | 
 | 55 |     // File are named `HASH.{ok,failed}.wasm`. | 
 | 56 |     size_t hash = base::hash_range(module->module_start, module->module_end); | 
 | 57 |     char buf[32] = {'\0'}; | 
 | 58 | #if V8_OS_WIN && _MSC_VER < 1900 | 
 | 59 | #define snprintf sprintf_s | 
 | 60 | #endif | 
 | 61 |     snprintf(buf, sizeof(buf) - 1, "%016zx.%s.wasm", hash, | 
 | 62 |              result.ok() ? "ok" : "failed"); | 
 | 63 |     std::string name(buf); | 
 | 64 |     if (FILE* wasm_file = base::OS::FOpen((path + name).c_str(), "wb")) { | 
 | 65 |       fwrite(module->module_start, module->module_end - module->module_start, 1, | 
 | 66 |              wasm_file); | 
 | 67 |       fclose(wasm_file); | 
 | 68 |     } | 
 | 69 |   } | 
 | 70 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 71 |   // Decodes an entire module. | 
 | 72 |   ModuleResult DecodeModule(WasmModule* module, bool verify_functions = true) { | 
 | 73 |     pc_ = start_; | 
 | 74 |     module->module_start = start_; | 
 | 75 |     module->module_end = limit_; | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 76 |     module->min_mem_pages = 0; | 
 | 77 |     module->max_mem_pages = 0; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 78 |     module->mem_export = false; | 
 | 79 |     module->mem_external = false; | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 80 |     module->origin = origin_; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 81 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 82 |     bool sections[(size_t)WasmSection::Code::Max] = {false}; | 
 | 83 |  | 
 | 84 |     const byte* pos = pc_; | 
 | 85 |     uint32_t magic_word = consume_u32("wasm magic"); | 
 | 86 | #define BYTES(x) (x & 0xff), (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff | 
 | 87 |     if (magic_word != kWasmMagic) { | 
 | 88 |       error(pos, pos, | 
 | 89 |             "expected magic word %02x %02x %02x %02x, " | 
 | 90 |             "found %02x %02x %02x %02x", | 
 | 91 |             BYTES(kWasmMagic), BYTES(magic_word)); | 
 | 92 |       goto done; | 
 | 93 |     } | 
 | 94 |  | 
 | 95 |     pos = pc_; | 
 | 96 |     { | 
 | 97 |       uint32_t magic_version = consume_u32("wasm version"); | 
 | 98 |       if (magic_version != kWasmVersion) { | 
 | 99 |         error(pos, pos, | 
 | 100 |               "expected version %02x %02x %02x %02x, " | 
 | 101 |               "found %02x %02x %02x %02x", | 
 | 102 |               BYTES(kWasmVersion), BYTES(magic_version)); | 
 | 103 |         goto done; | 
 | 104 |       } | 
 | 105 |     } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 106 |  | 
 | 107 |     // Decode the module sections. | 
 | 108 |     while (pc_ < limit_) { | 
 | 109 |       TRACE("DecodeSection\n"); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 110 |       pos = pc_; | 
 | 111 |  | 
 | 112 |       int length; | 
 | 113 |       uint32_t section_length = consume_u32v(&length, "section size"); | 
 | 114 |  | 
 | 115 |       int section_string_leb_length = 0; | 
 | 116 |       uint32_t section_string_length = 0; | 
 | 117 |       WasmSection::Code section = consume_section_name( | 
 | 118 |           §ion_string_leb_length, §ion_string_length); | 
 | 119 |       uint32_t string_and_leb_length = | 
 | 120 |           section_string_leb_length + section_string_length; | 
 | 121 |       if (string_and_leb_length > section_length) { | 
 | 122 |         error(pos, pos, | 
 | 123 |               "section string of size %u longer than total section bytes %u", | 
 | 124 |               string_and_leb_length, section_length); | 
 | 125 |         break; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 126 |       } | 
 | 127 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 128 |       if (section == WasmSection::Code::Max) { | 
 | 129 |         // Skip unknown section. | 
 | 130 |         uint32_t skip = section_length - string_and_leb_length; | 
 | 131 |         TRACE("skipping %u bytes from unknown section\n", skip); | 
 | 132 |         consume_bytes(skip); | 
 | 133 |         continue; | 
 | 134 |       } | 
 | 135 |  | 
 | 136 |       // Each section should appear at most once. | 
 | 137 |       CheckForPreviousSection(sections, section, false); | 
 | 138 |       sections[(size_t)section] = true; | 
 | 139 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 140 |       switch (section) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 141 |         case WasmSection::Code::End: | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 142 |           // Terminate section decoding. | 
 | 143 |           limit_ = pc_; | 
 | 144 |           break; | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 145 |         case WasmSection::Code::Memory: | 
 | 146 |           int length; | 
 | 147 |           module->min_mem_pages = consume_u32v(&length, "min memory"); | 
 | 148 |           module->max_mem_pages = consume_u32v(&length, "max memory"); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 149 |           module->mem_export = consume_u8("export memory") != 0; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 150 |           break; | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 151 |         case WasmSection::Code::Signatures: { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 152 |           int length; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 153 |           uint32_t signatures_count = consume_u32v(&length, "signatures count"); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 154 |           module->signatures.reserve(SafeReserve(signatures_count)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 155 |           // Decode signatures. | 
 | 156 |           for (uint32_t i = 0; i < signatures_count; i++) { | 
 | 157 |             if (failed()) break; | 
 | 158 |             TRACE("DecodeSignature[%d] module+%d\n", i, | 
 | 159 |                   static_cast<int>(pc_ - start_)); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 160 |             FunctionSig* s = consume_sig();  // read function sig. | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 161 |             module->signatures.push_back(s); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 162 |           } | 
 | 163 |           break; | 
 | 164 |         } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 165 |         case WasmSection::Code::FunctionSignatures: { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 166 |           // Functions require a signature table first. | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 167 |           CheckForPreviousSection(sections, WasmSection::Code::Signatures, | 
 | 168 |                                   true); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 169 |           int length; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 170 |           uint32_t functions_count = consume_u32v(&length, "functions count"); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 171 |           module->functions.reserve(SafeReserve(functions_count)); | 
 | 172 |           for (uint32_t i = 0; i < functions_count; i++) { | 
 | 173 |             module->functions.push_back( | 
 | 174 |                 {nullptr, i, 0, 0, 0, 0, 0, 0, false, false}); | 
 | 175 |             WasmFunction* function = &module->functions.back(); | 
 | 176 |             function->sig_index = consume_sig_index(module, &function->sig); | 
 | 177 |           } | 
 | 178 |           break; | 
 | 179 |         } | 
 | 180 |         case WasmSection::Code::FunctionBodies: { | 
 | 181 |           // Function bodies should follow signatures. | 
 | 182 |           CheckForPreviousSection(sections, | 
 | 183 |                                   WasmSection::Code::FunctionSignatures, true); | 
 | 184 |           int length; | 
 | 185 |           const byte* pos = pc_; | 
 | 186 |           uint32_t functions_count = consume_u32v(&length, "functions count"); | 
 | 187 |           if (functions_count != module->functions.size()) { | 
 | 188 |             error(pos, pos, "function body count %u mismatch (%u expected)", | 
 | 189 |                   functions_count, | 
 | 190 |                   static_cast<uint32_t>(module->functions.size())); | 
 | 191 |             break; | 
 | 192 |           } | 
 | 193 |           for (uint32_t i = 0; i < functions_count; i++) { | 
 | 194 |             WasmFunction* function = &module->functions[i]; | 
 | 195 |             int length; | 
 | 196 |             uint32_t size = consume_u32v(&length, "body size"); | 
 | 197 |             function->code_start_offset = pc_offset(); | 
 | 198 |             function->code_end_offset = pc_offset() + size; | 
 | 199 |  | 
 | 200 |             TRACE("  +%d  %-20s: (%d bytes)\n", pc_offset(), "function body", | 
 | 201 |                   size); | 
 | 202 |             pc_ += size; | 
 | 203 |             if (pc_ > limit_) { | 
 | 204 |               error(pc_, "function body extends beyond end of file"); | 
 | 205 |             } | 
 | 206 |           } | 
 | 207 |           break; | 
 | 208 |         } | 
 | 209 |         case WasmSection::Code::Functions: { | 
 | 210 |           // Functions require a signature table first. | 
 | 211 |           CheckForPreviousSection(sections, WasmSection::Code::Signatures, | 
 | 212 |                                   true); | 
 | 213 |           int length; | 
 | 214 |           uint32_t functions_count = consume_u32v(&length, "functions count"); | 
 | 215 |           module->functions.reserve(SafeReserve(functions_count)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 216 |           // Set up module environment for verification. | 
 | 217 |           ModuleEnv menv; | 
 | 218 |           menv.module = module; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 219 |           menv.instance = nullptr; | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 220 |           menv.origin = origin_; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 221 |           // Decode functions. | 
 | 222 |           for (uint32_t i = 0; i < functions_count; i++) { | 
 | 223 |             if (failed()) break; | 
 | 224 |             TRACE("DecodeFunction[%d] module+%d\n", i, | 
 | 225 |                   static_cast<int>(pc_ - start_)); | 
 | 226 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 227 |             module->functions.push_back( | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 228 |                 {nullptr, i, 0, 0, 0, 0, 0, 0, false, false}); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 229 |             WasmFunction* function = &module->functions.back(); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 230 |             DecodeFunctionInModule(module, function, false); | 
 | 231 |           } | 
 | 232 |           if (ok() && verify_functions) { | 
 | 233 |             for (uint32_t i = 0; i < functions_count; i++) { | 
 | 234 |               if (failed()) break; | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 235 |               WasmFunction* function = &module->functions[i]; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 236 |               if (!function->external) { | 
 | 237 |                 VerifyFunctionBody(i, &menv, function); | 
 | 238 |                 if (result_.failed()) | 
 | 239 |                   error(result_.error_pc, result_.error_msg.get()); | 
 | 240 |               } | 
 | 241 |             } | 
 | 242 |           } | 
 | 243 |           break; | 
 | 244 |         } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 245 |         case WasmSection::Code::Names: { | 
 | 246 |           // Names correspond to functions. | 
 | 247 |           CheckForPreviousSection(sections, | 
 | 248 |                                   WasmSection::Code::FunctionSignatures, true); | 
 | 249 |           int length; | 
 | 250 |           const byte* pos = pc_; | 
 | 251 |           uint32_t functions_count = consume_u32v(&length, "functions count"); | 
 | 252 |           if (functions_count != module->functions.size()) { | 
 | 253 |             error(pos, pos, "function name count %u mismatch (%u expected)", | 
 | 254 |                   functions_count, | 
 | 255 |                   static_cast<uint32_t>(module->functions.size())); | 
 | 256 |             break; | 
 | 257 |           } | 
 | 258 |  | 
 | 259 |           for (uint32_t i = 0; i < functions_count; i++) { | 
 | 260 |             WasmFunction* function = &module->functions[i]; | 
 | 261 |             function->name_offset = | 
 | 262 |                 consume_string(&function->name_length, "function name"); | 
 | 263 |  | 
 | 264 |             uint32_t local_names_count = | 
 | 265 |                 consume_u32v(&length, "local names count"); | 
 | 266 |             for (uint32_t j = 0; j < local_names_count; j++) { | 
 | 267 |               uint32_t unused = 0; | 
 | 268 |               uint32_t offset = consume_string(&unused, "local name"); | 
 | 269 |               USE(unused); | 
 | 270 |               USE(offset); | 
 | 271 |             } | 
 | 272 |           } | 
 | 273 |           break; | 
 | 274 |         } | 
 | 275 |         case WasmSection::Code::Globals: { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 276 |           int length; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 277 |           uint32_t globals_count = consume_u32v(&length, "globals count"); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 278 |           module->globals.reserve(SafeReserve(globals_count)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 279 |           // Decode globals. | 
 | 280 |           for (uint32_t i = 0; i < globals_count; i++) { | 
 | 281 |             if (failed()) break; | 
 | 282 |             TRACE("DecodeGlobal[%d] module+%d\n", i, | 
 | 283 |                   static_cast<int>(pc_ - start_)); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 284 |             module->globals.push_back({0, 0, MachineType::Int32(), 0, false}); | 
 | 285 |             WasmGlobal* global = &module->globals.back(); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 286 |             DecodeGlobalInModule(global); | 
 | 287 |           } | 
 | 288 |           break; | 
 | 289 |         } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 290 |         case WasmSection::Code::DataSegments: { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 291 |           int length; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 292 |           uint32_t data_segments_count = | 
 | 293 |               consume_u32v(&length, "data segments count"); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 294 |           module->data_segments.reserve(SafeReserve(data_segments_count)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 295 |           // Decode data segments. | 
 | 296 |           for (uint32_t i = 0; i < data_segments_count; i++) { | 
 | 297 |             if (failed()) break; | 
 | 298 |             TRACE("DecodeDataSegment[%d] module+%d\n", i, | 
 | 299 |                   static_cast<int>(pc_ - start_)); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 300 |             module->data_segments.push_back({0, 0, 0}); | 
 | 301 |             WasmDataSegment* segment = &module->data_segments.back(); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 302 |             DecodeDataSegmentInModule(module, segment); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 303 |           } | 
 | 304 |           break; | 
 | 305 |         } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 306 |         case WasmSection::Code::FunctionTable: { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 307 |           // An indirect function table requires functions first. | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 308 |           CheckForFunctions(module, section); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 309 |           int length; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 310 |           uint32_t function_table_count = | 
 | 311 |               consume_u32v(&length, "function table count"); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 312 |           module->function_table.reserve(SafeReserve(function_table_count)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 313 |           // Decode function table. | 
 | 314 |           for (uint32_t i = 0; i < function_table_count; i++) { | 
 | 315 |             if (failed()) break; | 
 | 316 |             TRACE("DecodeFunctionTable[%d] module+%d\n", i, | 
 | 317 |                   static_cast<int>(pc_ - start_)); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 318 |             uint16_t index = consume_u32v(&length); | 
 | 319 |             if (index >= module->functions.size()) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 320 |               error(pc_ - 2, "invalid function index"); | 
 | 321 |               break; | 
 | 322 |             } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 323 |             module->function_table.push_back(index); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 324 |           } | 
 | 325 |           break; | 
 | 326 |         } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 327 |         case WasmSection::Code::StartFunction: { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 328 |           // Declares a start function for a module. | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 329 |           CheckForFunctions(module, section); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 330 |           if (module->start_function_index >= 0) { | 
 | 331 |             error("start function already declared"); | 
 | 332 |             break; | 
 | 333 |           } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 334 |           WasmFunction* func; | 
 | 335 |           const byte* pos = pc_; | 
 | 336 |           module->start_function_index = consume_func_index(module, &func); | 
 | 337 |           if (func && func->sig->parameter_count() > 0) { | 
 | 338 |             error(pos, "invalid start function: non-zero parameter count"); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 339 |             break; | 
 | 340 |           } | 
 | 341 |           break; | 
 | 342 |         } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 343 |         case WasmSection::Code::ImportTable: { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 344 |           // Declares an import table. | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 345 |           CheckForPreviousSection(sections, WasmSection::Code::Signatures, | 
 | 346 |                                   true); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 347 |           int length; | 
 | 348 |           uint32_t import_table_count = | 
 | 349 |               consume_u32v(&length, "import table count"); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 350 |           module->import_table.reserve(SafeReserve(import_table_count)); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 351 |           // Decode import table. | 
 | 352 |           for (uint32_t i = 0; i < import_table_count; i++) { | 
 | 353 |             if (failed()) break; | 
 | 354 |             TRACE("DecodeImportTable[%d] module+%d\n", i, | 
 | 355 |                   static_cast<int>(pc_ - start_)); | 
 | 356 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 357 |             module->import_table.push_back({nullptr, 0, 0}); | 
 | 358 |             WasmImport* import = &module->import_table.back(); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 359 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 360 |             import->sig_index = consume_sig_index(module, &import->sig); | 
 | 361 |             const byte* pos = pc_; | 
 | 362 |             import->module_name_offset = consume_string( | 
 | 363 |                 &import->module_name_length, "import module name"); | 
 | 364 |             if (import->module_name_length == 0) { | 
 | 365 |               error(pos, "import module name cannot be NULL"); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 366 |             } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 367 |             import->function_name_offset = consume_string( | 
 | 368 |                 &import->function_name_length, "import function name"); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 369 |           } | 
 | 370 |           break; | 
 | 371 |         } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 372 |         case WasmSection::Code::ExportTable: { | 
 | 373 |           // Declares an export table. | 
 | 374 |           CheckForFunctions(module, section); | 
 | 375 |           int length; | 
 | 376 |           uint32_t export_table_count = | 
 | 377 |               consume_u32v(&length, "export table count"); | 
 | 378 |           module->export_table.reserve(SafeReserve(export_table_count)); | 
 | 379 |           // Decode export table. | 
 | 380 |           for (uint32_t i = 0; i < export_table_count; i++) { | 
 | 381 |             if (failed()) break; | 
 | 382 |             TRACE("DecodeExportTable[%d] module+%d\n", i, | 
 | 383 |                   static_cast<int>(pc_ - start_)); | 
 | 384 |  | 
 | 385 |             module->export_table.push_back({0, 0}); | 
 | 386 |             WasmExport* exp = &module->export_table.back(); | 
 | 387 |  | 
 | 388 |             WasmFunction* func; | 
 | 389 |             exp->func_index = consume_func_index(module, &func); | 
 | 390 |             exp->name_offset = consume_string(&exp->name_length, "export name"); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 391 |           } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 392 |           break; | 
 | 393 |         } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 394 |         case WasmSection::Code::Max: | 
 | 395 |           UNREACHABLE();  // Already skipped unknown sections. | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 396 |       } | 
 | 397 |     } | 
 | 398 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 399 |   done: | 
 | 400 |     ModuleResult result = toResult(module); | 
 | 401 |     if (FLAG_dump_wasm_module) { | 
 | 402 |       DumpModule(module, result); | 
 | 403 |     } | 
 | 404 |     return result; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 405 |   } | 
 | 406 |  | 
 | 407 |   uint32_t SafeReserve(uint32_t count) { | 
 | 408 |     // Avoid OOM by only reserving up to a certain size. | 
 | 409 |     const uint32_t kMaxReserve = 20000; | 
 | 410 |     return count < kMaxReserve ? count : kMaxReserve; | 
 | 411 |   } | 
 | 412 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 413 |   void CheckForFunctions(WasmModule* module, WasmSection::Code section) { | 
 | 414 |     if (module->functions.size() == 0) { | 
 | 415 |       error(pc_ - 1, nullptr, "functions must appear before section %s", | 
 | 416 |             WasmSection::getName(section)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 417 |     } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 418 |   } | 
 | 419 |  | 
 | 420 |   void CheckForPreviousSection(bool* sections, WasmSection::Code section, | 
 | 421 |                                bool present) { | 
 | 422 |     if (section >= WasmSection::Code::Max) return; | 
 | 423 |     if (sections[(size_t)section] == present) return; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 424 |     if (present) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 425 |       error(pc_ - 1, nullptr, "required %s section missing", | 
 | 426 |             WasmSection::getName(section)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 427 |     } else { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 428 |       error(pc_ - 1, nullptr, "%s section already present", | 
 | 429 |             WasmSection::getName(section)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 430 |     } | 
 | 431 |   } | 
 | 432 |  | 
 | 433 |   // Decodes a single anonymous function starting at {start_}. | 
 | 434 |   FunctionResult DecodeSingleFunction(ModuleEnv* module_env, | 
 | 435 |                                       WasmFunction* function) { | 
 | 436 |     pc_ = start_; | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 437 |     function->sig = consume_sig();            // read signature | 
 | 438 |     function->name_offset = 0;                // ---- name | 
 | 439 |     function->name_length = 0;                // ---- name length | 
 | 440 |     function->code_start_offset = off(pc_);   // ---- code start | 
 | 441 |     function->code_end_offset = off(limit_);  // ---- code end | 
 | 442 |     function->exported = false;               // ---- exported | 
 | 443 |     function->external = false;               // ---- external | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 444 |  | 
 | 445 |     if (ok()) VerifyFunctionBody(0, module_env, function); | 
 | 446 |  | 
 | 447 |     FunctionResult result; | 
 | 448 |     result.CopyFrom(result_);  // Copy error code and location. | 
 | 449 |     result.val = function; | 
 | 450 |     return result; | 
 | 451 |   } | 
 | 452 |  | 
 | 453 |   // Decodes a single function signature at {start}. | 
 | 454 |   FunctionSig* DecodeFunctionSignature(const byte* start) { | 
 | 455 |     pc_ = start; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 456 |     FunctionSig* result = consume_sig(); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 457 |     return ok() ? result : nullptr; | 
 | 458 |   } | 
 | 459 |  | 
 | 460 |  private: | 
 | 461 |   Zone* module_zone; | 
 | 462 |   ModuleResult result_; | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 463 |   ModuleOrigin origin_; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 464 |  | 
 | 465 |   uint32_t off(const byte* ptr) { return static_cast<uint32_t>(ptr - start_); } | 
 | 466 |  | 
 | 467 |   // Decodes a single global entry inside a module starting at {pc_}. | 
 | 468 |   void DecodeGlobalInModule(WasmGlobal* global) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 469 |     global->name_offset = consume_string(&global->name_length, "global name"); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 470 |     global->type = mem_type(); | 
 | 471 |     global->offset = 0; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 472 |     global->exported = consume_u8("exported") != 0; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 473 |   } | 
 | 474 |  | 
 | 475 |   // Decodes a single function entry inside a module starting at {pc_}. | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 476 |   // TODO(titzer): legacy function body; remove | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 477 |   void DecodeFunctionInModule(WasmModule* module, WasmFunction* function, | 
 | 478 |                               bool verify_body = true) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 479 |     byte decl_bits = consume_u8("function decl"); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 480 |  | 
 | 481 |     const byte* sigpos = pc_; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 482 |     function->sig_index = consume_u16("signature index"); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 483 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 484 |     if (function->sig_index >= module->signatures.size()) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 485 |       return error(sigpos, "invalid signature index"); | 
 | 486 |     } else { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 487 |       function->sig = module->signatures[function->sig_index]; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 488 |     } | 
 | 489 |  | 
 | 490 |     TRACE("  +%d  <function attributes:%s%s%s%s%s>\n", | 
 | 491 |           static_cast<int>(pc_ - start_), | 
 | 492 |           decl_bits & kDeclFunctionName ? " name" : "", | 
 | 493 |           decl_bits & kDeclFunctionImport ? " imported" : "", | 
 | 494 |           decl_bits & kDeclFunctionLocals ? " locals" : "", | 
 | 495 |           decl_bits & kDeclFunctionExport ? " exported" : "", | 
 | 496 |           (decl_bits & kDeclFunctionImport) == 0 ? " body" : ""); | 
 | 497 |  | 
 | 498 |     if (decl_bits & kDeclFunctionName) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 499 |       function->name_offset = | 
 | 500 |           consume_string(&function->name_length, "function name"); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 501 |     } | 
 | 502 |  | 
 | 503 |     function->exported = decl_bits & kDeclFunctionExport; | 
 | 504 |  | 
 | 505 |     // Imported functions have no locals or body. | 
 | 506 |     if (decl_bits & kDeclFunctionImport) { | 
 | 507 |       function->external = true; | 
 | 508 |       return; | 
 | 509 |     } | 
 | 510 |  | 
 | 511 |     if (decl_bits & kDeclFunctionLocals) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 512 |       function->local_i32_count = consume_u16("i32 count"); | 
 | 513 |       function->local_i64_count = consume_u16("i64 count"); | 
 | 514 |       function->local_f32_count = consume_u16("f32 count"); | 
 | 515 |       function->local_f64_count = consume_u16("f64 count"); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 516 |     } | 
 | 517 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 518 |     uint16_t size = consume_u16("body size"); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 519 |     if (ok()) { | 
 | 520 |       if ((pc_ + size) > limit_) { | 
 | 521 |         return error(pc_, limit_, | 
 | 522 |                      "expected %d bytes for function body, fell off end", size); | 
 | 523 |       } | 
 | 524 |       function->code_start_offset = static_cast<uint32_t>(pc_ - start_); | 
 | 525 |       function->code_end_offset = function->code_start_offset + size; | 
 | 526 |       TRACE("  +%d  %-20s: (%d bytes)\n", static_cast<int>(pc_ - start_), | 
 | 527 |             "function body", size); | 
 | 528 |       pc_ += size; | 
 | 529 |     } | 
 | 530 |   } | 
 | 531 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 532 |   bool IsWithinLimit(uint32_t limit, uint32_t offset, uint32_t size) { | 
 | 533 |     if (offset > limit) return false; | 
 | 534 |     if ((offset + size) < offset) return false;  // overflow | 
 | 535 |     return (offset + size) <= limit; | 
 | 536 |   } | 
 | 537 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 538 |   // Decodes a single data segment entry inside a module starting at {pc_}. | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 539 |   void DecodeDataSegmentInModule(WasmModule* module, WasmDataSegment* segment) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 540 |     const byte* start = pc_; | 
 | 541 |     int length; | 
 | 542 |     segment->dest_addr = consume_u32v(&length, "destination"); | 
 | 543 |     segment->source_size = consume_u32v(&length, "source size"); | 
 | 544 |     segment->source_offset = static_cast<uint32_t>(pc_ - start_); | 
 | 545 |     segment->init = true; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 546 |  | 
 | 547 |     // Validate the data is in the module. | 
 | 548 |     uint32_t module_limit = static_cast<uint32_t>(limit_ - start_); | 
 | 549 |     if (!IsWithinLimit(module_limit, segment->source_offset, | 
 | 550 |                        segment->source_size)) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 551 |       error(start, "segment out of bounds of module"); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 552 |     } | 
 | 553 |  | 
 | 554 |     // Validate that the segment will fit into the (minimum) memory. | 
 | 555 |     uint32_t memory_limit = | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 556 |         WasmModule::kPageSize * (module ? module->min_mem_pages | 
 | 557 |                                         : WasmModule::kMaxMemPages); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 558 |     if (!IsWithinLimit(memory_limit, segment->dest_addr, | 
 | 559 |                        segment->source_size)) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 560 |       error(start, "segment out of bounds of memory"); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 561 |     } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 562 |  | 
 | 563 |     consume_bytes(segment->source_size); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 564 |   } | 
 | 565 |  | 
 | 566 |   // Verifies the body (code) of a given function. | 
 | 567 |   void VerifyFunctionBody(uint32_t func_num, ModuleEnv* menv, | 
 | 568 |                           WasmFunction* function) { | 
 | 569 |     if (FLAG_trace_wasm_decode_time) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 570 |       OFStream os(stdout); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 571 |       os << "Verifying WASM function " << WasmFunctionName(function, menv) | 
 | 572 |          << std::endl; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 573 |       os << std::endl; | 
 | 574 |     } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 575 |     FunctionBody body = {menv, function->sig, start_, | 
 | 576 |                          start_ + function->code_start_offset, | 
 | 577 |                          start_ + function->code_end_offset}; | 
 | 578 |     TreeResult result = VerifyWasmCode(module_zone->allocator(), body); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 579 |     if (result.failed()) { | 
 | 580 |       // Wrap the error message from the function decoder. | 
 | 581 |       std::ostringstream str; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 582 |       str << "in function " << WasmFunctionName(function, menv) << ": "; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 583 |       str << result; | 
 | 584 |       std::string strval = str.str(); | 
 | 585 |       const char* raw = strval.c_str(); | 
 | 586 |       size_t len = strlen(raw); | 
 | 587 |       char* buffer = new char[len]; | 
 | 588 |       strncpy(buffer, raw, len); | 
 | 589 |       buffer[len - 1] = 0; | 
 | 590 |  | 
 | 591 |       // Copy error code and location. | 
 | 592 |       result_.CopyFrom(result); | 
 | 593 |       result_.error_msg.Reset(buffer); | 
 | 594 |     } | 
 | 595 |   } | 
 | 596 |  | 
 | 597 |   // Reads a single 32-bit unsigned integer interpreted as an offset, checking | 
 | 598 |   // the offset is within bounds and advances. | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 599 |   uint32_t consume_offset(const char* name = nullptr) { | 
 | 600 |     uint32_t offset = consume_u32(name ? name : "offset"); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 601 |     if (offset > static_cast<uint32_t>(limit_ - start_)) { | 
 | 602 |       error(pc_ - sizeof(uint32_t), "offset out of bounds of module"); | 
 | 603 |     } | 
 | 604 |     return offset; | 
 | 605 |   } | 
 | 606 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 607 |   // Reads a length-prefixed string, checking that it is within bounds. Returns | 
 | 608 |   // the offset of the string, and the length as an out parameter. | 
 | 609 |   uint32_t consume_string(uint32_t* length, const char* name = nullptr) { | 
 | 610 |     int varint_length; | 
 | 611 |     *length = consume_u32v(&varint_length, "string length"); | 
 | 612 |     uint32_t offset = pc_offset(); | 
 | 613 |     TRACE("  +%u  %-20s: (%u bytes)\n", offset, "string", *length); | 
 | 614 |     consume_bytes(*length); | 
 | 615 |     return offset; | 
 | 616 |   } | 
 | 617 |  | 
 | 618 |   uint32_t consume_sig_index(WasmModule* module, FunctionSig** sig) { | 
 | 619 |     const byte* pos = pc_; | 
 | 620 |     int length; | 
 | 621 |     uint32_t sig_index = consume_u32v(&length, "signature index"); | 
 | 622 |     if (sig_index >= module->signatures.size()) { | 
 | 623 |       error(pos, pos, "signature index %u out of bounds (%d signatures)", | 
 | 624 |             sig_index, static_cast<int>(module->signatures.size())); | 
 | 625 |       *sig = nullptr; | 
 | 626 |       return 0; | 
 | 627 |     } | 
 | 628 |     *sig = module->signatures[sig_index]; | 
 | 629 |     return sig_index; | 
 | 630 |   } | 
 | 631 |  | 
 | 632 |   uint32_t consume_func_index(WasmModule* module, WasmFunction** func) { | 
 | 633 |     const byte* pos = pc_; | 
 | 634 |     int length; | 
 | 635 |     uint32_t func_index = consume_u32v(&length, "function index"); | 
 | 636 |     if (func_index >= module->functions.size()) { | 
 | 637 |       error(pos, pos, "function index %u out of bounds (%d functions)", | 
 | 638 |             func_index, static_cast<int>(module->functions.size())); | 
 | 639 |       *func = nullptr; | 
 | 640 |       return 0; | 
 | 641 |     } | 
 | 642 |     *func = &module->functions[func_index]; | 
 | 643 |     return func_index; | 
 | 644 |   } | 
 | 645 |  | 
 | 646 |   // Reads a section name. | 
 | 647 |   WasmSection::Code consume_section_name(int* string_leb_length, | 
 | 648 |                                          uint32_t* string_length) { | 
 | 649 |     *string_length = consume_u32v(string_leb_length, "name length"); | 
 | 650 |     const byte* start = pc_; | 
 | 651 |     consume_bytes(*string_length); | 
 | 652 |     if (failed()) { | 
 | 653 |       TRACE("Section name of length %u couldn't be read\n", *string_length); | 
 | 654 |       return WasmSection::Code::Max; | 
 | 655 |     } | 
 | 656 |     // TODO(jfb) Linear search, it may be better to do a common-prefix search. | 
 | 657 |     for (WasmSection::Code i = WasmSection::begin(); i != WasmSection::end(); | 
 | 658 |          i = WasmSection::next(i)) { | 
 | 659 |       if (WasmSection::getNameLength(i) == *string_length && | 
 | 660 |           0 == memcmp(WasmSection::getName(i), start, *string_length)) { | 
 | 661 |         return i; | 
 | 662 |       } | 
 | 663 |     } | 
 | 664 |     TRACE("Unknown section: '"); | 
 | 665 |     for (uint32_t i = 0; i != *string_length; ++i) TRACE("%c", *(start + i)); | 
 | 666 |     TRACE("'\n"); | 
 | 667 |     return WasmSection::Code::Max; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 668 |   } | 
 | 669 |  | 
 | 670 |   // Reads a single 8-bit integer, interpreting it as a local type. | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 671 |   LocalType consume_local_type() { | 
 | 672 |     byte val = consume_u8("local type"); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 673 |     LocalTypeCode t = static_cast<LocalTypeCode>(val); | 
 | 674 |     switch (t) { | 
 | 675 |       case kLocalVoid: | 
 | 676 |         return kAstStmt; | 
 | 677 |       case kLocalI32: | 
 | 678 |         return kAstI32; | 
 | 679 |       case kLocalI64: | 
 | 680 |         return kAstI64; | 
 | 681 |       case kLocalF32: | 
 | 682 |         return kAstF32; | 
 | 683 |       case kLocalF64: | 
 | 684 |         return kAstF64; | 
 | 685 |       default: | 
 | 686 |         error(pc_ - 1, "invalid local type"); | 
 | 687 |         return kAstStmt; | 
 | 688 |     } | 
 | 689 |   } | 
 | 690 |  | 
 | 691 |   // Reads a single 8-bit integer, interpreting it as a memory type. | 
 | 692 |   MachineType mem_type() { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 693 |     byte val = consume_u8("memory type"); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 694 |     MemTypeCode t = static_cast<MemTypeCode>(val); | 
 | 695 |     switch (t) { | 
 | 696 |       case kMemI8: | 
 | 697 |         return MachineType::Int8(); | 
 | 698 |       case kMemU8: | 
 | 699 |         return MachineType::Uint8(); | 
 | 700 |       case kMemI16: | 
 | 701 |         return MachineType::Int16(); | 
 | 702 |       case kMemU16: | 
 | 703 |         return MachineType::Uint16(); | 
 | 704 |       case kMemI32: | 
 | 705 |         return MachineType::Int32(); | 
 | 706 |       case kMemU32: | 
 | 707 |         return MachineType::Uint32(); | 
 | 708 |       case kMemI64: | 
 | 709 |         return MachineType::Int64(); | 
 | 710 |       case kMemU64: | 
 | 711 |         return MachineType::Uint64(); | 
 | 712 |       case kMemF32: | 
 | 713 |         return MachineType::Float32(); | 
 | 714 |       case kMemF64: | 
 | 715 |         return MachineType::Float64(); | 
 | 716 |       default: | 
 | 717 |         error(pc_ - 1, "invalid memory type"); | 
 | 718 |         return MachineType::None(); | 
 | 719 |     } | 
 | 720 |   } | 
 | 721 |  | 
 | 722 |   // Parses an inline function signature. | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 723 |   FunctionSig* consume_sig() { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 724 |     int length; | 
 | 725 |     byte count = consume_u32v(&length, "param count"); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 726 |     LocalType ret = consume_local_type(); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 727 |     FunctionSig::Builder builder(module_zone, ret == kAstStmt ? 0 : 1, count); | 
 | 728 |     if (ret != kAstStmt) builder.AddReturn(ret); | 
 | 729 |  | 
 | 730 |     for (int i = 0; i < count; i++) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 731 |       LocalType param = consume_local_type(); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 732 |       if (param == kAstStmt) error(pc_ - 1, "invalid void parameter type"); | 
 | 733 |       builder.AddParam(param); | 
 | 734 |     } | 
 | 735 |     return builder.Build(); | 
 | 736 |   } | 
 | 737 | }; | 
 | 738 |  | 
 | 739 |  | 
 | 740 | // Helpers for nice error messages. | 
 | 741 | class ModuleError : public ModuleResult { | 
 | 742 |  public: | 
 | 743 |   explicit ModuleError(const char* msg) { | 
 | 744 |     error_code = kError; | 
 | 745 |     size_t len = strlen(msg) + 1; | 
 | 746 |     char* result = new char[len]; | 
 | 747 |     strncpy(result, msg, len); | 
 | 748 |     result[len - 1] = 0; | 
 | 749 |     error_msg.Reset(result); | 
 | 750 |   } | 
 | 751 | }; | 
 | 752 |  | 
 | 753 |  | 
 | 754 | // Helpers for nice error messages. | 
 | 755 | class FunctionError : public FunctionResult { | 
 | 756 |  public: | 
 | 757 |   explicit FunctionError(const char* msg) { | 
 | 758 |     error_code = kError; | 
 | 759 |     size_t len = strlen(msg) + 1; | 
 | 760 |     char* result = new char[len]; | 
 | 761 |     strncpy(result, msg, len); | 
 | 762 |     result[len - 1] = 0; | 
 | 763 |     error_msg.Reset(result); | 
 | 764 |   } | 
 | 765 | }; | 
 | 766 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 767 | ModuleResult DecodeWasmModule(Isolate* isolate, Zone* zone, | 
 | 768 |                               const byte* module_start, const byte* module_end, | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 769 |                               bool verify_functions, ModuleOrigin origin) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 770 |   size_t size = module_end - module_start; | 
 | 771 |   if (module_start > module_end) return ModuleError("start > end"); | 
 | 772 |   if (size >= kMaxModuleSize) return ModuleError("size > maximum module size"); | 
 | 773 |   WasmModule* module = new WasmModule(); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 774 |   ModuleDecoder decoder(zone, module_start, module_end, origin); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 775 |   return decoder.DecodeModule(module, verify_functions); | 
 | 776 | } | 
 | 777 |  | 
 | 778 |  | 
 | 779 | FunctionSig* DecodeWasmSignatureForTesting(Zone* zone, const byte* start, | 
 | 780 |                                            const byte* end) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 781 |   ModuleDecoder decoder(zone, start, end, kWasmOrigin); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 782 |   return decoder.DecodeFunctionSignature(start); | 
 | 783 | } | 
 | 784 |  | 
 | 785 |  | 
 | 786 | FunctionResult DecodeWasmFunction(Isolate* isolate, Zone* zone, | 
 | 787 |                                   ModuleEnv* module_env, | 
 | 788 |                                   const byte* function_start, | 
 | 789 |                                   const byte* function_end) { | 
 | 790 |   size_t size = function_end - function_start; | 
 | 791 |   if (function_start > function_end) return FunctionError("start > end"); | 
 | 792 |   if (size > kMaxFunctionSize) | 
 | 793 |     return FunctionError("size > maximum function size"); | 
 | 794 |   WasmFunction* function = new WasmFunction(); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 795 |   ModuleDecoder decoder(zone, function_start, function_end, kWasmOrigin); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 796 |   return decoder.DecodeSingleFunction(module_env, function); | 
 | 797 | } | 
 | 798 | }  // namespace wasm | 
 | 799 | }  // namespace internal | 
 | 800 | }  // namespace v8 |