Home | History | Annotate | Download | only in wasm
      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 #include "src/wasm/module-decoder.h"
      6 
      7 #include "src/base/functional.h"
      8 #include "src/base/platform/platform.h"
      9 #include "src/macro-assembler.h"
     10 #include "src/objects.h"
     11 #include "src/v8.h"
     12 
     13 #include "src/wasm/decoder.h"
     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 namespace {
     29 
     30 // The main logic for decoding the bytes of a module.
     31 class ModuleDecoder : public Decoder {
     32  public:
     33   ModuleDecoder(Zone* zone, const byte* module_start, const byte* module_end,
     34                 ModuleOrigin origin)
     35       : Decoder(module_start, module_end), module_zone(zone), origin_(origin) {
     36     result_.start = start_;
     37     if (limit_ < start_) {
     38       error(start_, "end is less than start");
     39       limit_ = start_;
     40     }
     41   }
     42 
     43   virtual void onFirstError() {
     44     pc_ = limit_;  // On error, terminate section decoding loop.
     45   }
     46 
     47   static void DumpModule(WasmModule* module, ModuleResult result) {
     48     std::string path;
     49     if (FLAG_dump_wasm_module_path) {
     50       path = FLAG_dump_wasm_module_path;
     51       if (path.size() &&
     52           !base::OS::isDirectorySeparator(path[path.size() - 1])) {
     53         path += base::OS::DirectorySeparator();
     54       }
     55     }
     56     // File are named `HASH.{ok,failed}.wasm`.
     57     size_t hash = base::hash_range(module->module_start, module->module_end);
     58     char buf[32] = {'\0'};
     59 #if V8_OS_WIN && _MSC_VER < 1900
     60 #define snprintf sprintf_s
     61 #endif
     62     snprintf(buf, sizeof(buf) - 1, "%016zx.%s.wasm", hash,
     63              result.ok() ? "ok" : "failed");
     64     std::string name(buf);
     65     if (FILE* wasm_file = base::OS::FOpen((path + name).c_str(), "wb")) {
     66       fwrite(module->module_start, module->module_end - module->module_start, 1,
     67              wasm_file);
     68       fclose(wasm_file);
     69     }
     70   }
     71 
     72   // Decodes an entire module.
     73   ModuleResult DecodeModule(WasmModule* module, bool verify_functions = true) {
     74     pc_ = start_;
     75     module->module_start = start_;
     76     module->module_end = limit_;
     77     module->min_mem_pages = 0;
     78     module->max_mem_pages = 0;
     79     module->mem_export = false;
     80     module->mem_external = false;
     81     module->origin = origin_;
     82 
     83     const byte* pos = pc_;
     84     int current_order = 0;
     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     }
    106 
    107     // Decode the module sections.
    108     while (pc_ < limit_) {
    109       TRACE("DecodeSection\n");
    110       pos = pc_;
    111 
    112       // Read the section name.
    113       uint32_t string_length = consume_u32v("section name length");
    114       const byte* section_name_start = pc_;
    115       consume_bytes(string_length);
    116       if (failed()) {
    117         TRACE("Section name of length %u couldn't be read\n", string_length);
    118         break;
    119       }
    120 
    121       TRACE("  +%d  section name        : \"%.*s\"\n",
    122             static_cast<int>(section_name_start - start_),
    123             string_length < 20 ? string_length : 20, section_name_start);
    124 
    125       WasmSection::Code section =
    126           WasmSection::lookup(section_name_start, string_length);
    127 
    128       // Read and check the section size.
    129       uint32_t section_length = consume_u32v("section length");
    130       if (!checkAvailable(section_length)) {
    131         // The section would extend beyond the end of the module.
    132         break;
    133       }
    134       const byte* section_start = pc_;
    135       const byte* expected_section_end = pc_ + section_length;
    136 
    137       current_order = CheckSectionOrder(current_order, section);
    138 
    139       switch (section) {
    140         case WasmSection::Code::End:
    141           // Terminate section decoding.
    142           limit_ = pc_;
    143           break;
    144         case WasmSection::Code::Memory: {
    145           module->min_mem_pages = consume_u32v("min memory");
    146           module->max_mem_pages = consume_u32v("max memory");
    147           module->mem_export = consume_u8("export memory") != 0;
    148           break;
    149         }
    150         case WasmSection::Code::Signatures: {
    151           uint32_t signatures_count = consume_u32v("signatures count");
    152           module->signatures.reserve(SafeReserve(signatures_count));
    153           // Decode signatures.
    154           for (uint32_t i = 0; i < signatures_count; ++i) {
    155             if (failed()) break;
    156             TRACE("DecodeSignature[%d] module+%d\n", i,
    157                   static_cast<int>(pc_ - start_));
    158             FunctionSig* s = consume_sig();
    159             module->signatures.push_back(s);
    160           }
    161           break;
    162         }
    163         case WasmSection::Code::FunctionSignatures: {
    164           uint32_t functions_count = consume_u32v("functions count");
    165           module->functions.reserve(SafeReserve(functions_count));
    166           for (uint32_t i = 0; i < functions_count; ++i) {
    167             module->functions.push_back({nullptr,  // sig
    168                                          i,        // func_index
    169                                          0,        // sig_index
    170                                          0,        // name_offset
    171                                          0,        // name_length
    172                                          0,        // code_start_offset
    173                                          0});      // code_end_offset
    174             WasmFunction* function = &module->functions.back();
    175             function->sig_index = consume_sig_index(module, &function->sig);
    176           }
    177           break;
    178         }
    179         case WasmSection::Code::FunctionBodies: {
    180           const byte* pos = pc_;
    181           uint32_t functions_count = consume_u32v("functions count");
    182           if (functions_count != module->functions.size()) {
    183             error(pos, pos, "function body count %u mismatch (%u expected)",
    184                   functions_count,
    185                   static_cast<uint32_t>(module->functions.size()));
    186             break;
    187           }
    188           for (uint32_t i = 0; i < functions_count; ++i) {
    189             WasmFunction* function = &module->functions[i];
    190             uint32_t size = consume_u32v("body size");
    191             function->code_start_offset = pc_offset();
    192             function->code_end_offset = pc_offset() + size;
    193 
    194             TRACE("  +%d  %-20s: (%d bytes)\n", pc_offset(), "function body",
    195                   size);
    196             pc_ += size;
    197             if (pc_ > limit_) {
    198               error(pc_, "function body extends beyond end of file");
    199             }
    200           }
    201           break;
    202         }
    203         case WasmSection::Code::Names: {
    204           const byte* pos = pc_;
    205           uint32_t functions_count = consume_u32v("functions count");
    206           if (functions_count != module->functions.size()) {
    207             error(pos, pos, "function name count %u mismatch (%u expected)",
    208                   functions_count,
    209                   static_cast<uint32_t>(module->functions.size()));
    210             break;
    211           }
    212 
    213           for (uint32_t i = 0; i < functions_count; ++i) {
    214             WasmFunction* function = &module->functions[i];
    215             function->name_offset =
    216                 consume_string(&function->name_length, false);
    217 
    218             uint32_t local_names_count = consume_u32v("local names count");
    219             for (uint32_t j = 0; j < local_names_count; j++) {
    220               uint32_t unused = 0;
    221               uint32_t offset = consume_string(&unused, false);
    222               USE(unused);
    223               USE(offset);
    224             }
    225           }
    226           break;
    227         }
    228         case WasmSection::Code::Globals: {
    229           uint32_t globals_count = consume_u32v("globals count");
    230           module->globals.reserve(SafeReserve(globals_count));
    231           // Decode globals.
    232           for (uint32_t i = 0; i < globals_count; ++i) {
    233             if (failed()) break;
    234             TRACE("DecodeGlobal[%d] module+%d\n", i,
    235                   static_cast<int>(pc_ - start_));
    236             module->globals.push_back({0, 0, MachineType::Int32(), 0, false});
    237             WasmGlobal* global = &module->globals.back();
    238             DecodeGlobalInModule(global);
    239           }
    240           break;
    241         }
    242         case WasmSection::Code::DataSegments: {
    243           uint32_t data_segments_count = consume_u32v("data segments count");
    244           module->data_segments.reserve(SafeReserve(data_segments_count));
    245           // Decode data segments.
    246           for (uint32_t i = 0; i < data_segments_count; ++i) {
    247             if (failed()) break;
    248             TRACE("DecodeDataSegment[%d] module+%d\n", i,
    249                   static_cast<int>(pc_ - start_));
    250             module->data_segments.push_back({0,        // dest_addr
    251                                              0,        // source_offset
    252                                              0,        // source_size
    253                                              false});  // init
    254             WasmDataSegment* segment = &module->data_segments.back();
    255             DecodeDataSegmentInModule(module, segment);
    256           }
    257           break;
    258         }
    259         case WasmSection::Code::FunctionTablePad: {
    260           if (!FLAG_wasm_jit_prototype) {
    261             error("FunctionTablePad section without jiting enabled");
    262           }
    263           // An indirect function table requires functions first.
    264           module->indirect_table_size = consume_u32v("indirect entry count");
    265           if (module->indirect_table_size > 0 &&
    266               module->indirect_table_size < module->function_table.size()) {
    267             error("more predefined indirect entries than table can hold");
    268           }
    269           break;
    270         }
    271         case WasmSection::Code::FunctionTable: {
    272           // An indirect function table requires functions first.
    273           CheckForFunctions(module, section);
    274           uint32_t function_table_count = consume_u32v("function table count");
    275           module->function_table.reserve(SafeReserve(function_table_count));
    276           // Decode function table.
    277           for (uint32_t i = 0; i < function_table_count; ++i) {
    278             if (failed()) break;
    279             TRACE("DecodeFunctionTable[%d] module+%d\n", i,
    280                   static_cast<int>(pc_ - start_));
    281             uint16_t index = consume_u32v();
    282             if (index >= module->functions.size()) {
    283               error(pc_ - 2, "invalid function index");
    284               break;
    285             }
    286             module->function_table.push_back(index);
    287           }
    288           if (module->indirect_table_size > 0 &&
    289               module->indirect_table_size < module->function_table.size()) {
    290             error("more predefined indirect entries than table can hold");
    291           }
    292           break;
    293         }
    294         case WasmSection::Code::StartFunction: {
    295           // Declares a start function for a module.
    296           CheckForFunctions(module, section);
    297           if (module->start_function_index >= 0) {
    298             error("start function already declared");
    299             break;
    300           }
    301           WasmFunction* func;
    302           const byte* pos = pc_;
    303           module->start_function_index = consume_func_index(module, &func);
    304           if (func && func->sig->parameter_count() > 0) {
    305             error(pos, "invalid start function: non-zero parameter count");
    306             break;
    307           }
    308           break;
    309         }
    310         case WasmSection::Code::ImportTable: {
    311           uint32_t import_table_count = consume_u32v("import table count");
    312           module->import_table.reserve(SafeReserve(import_table_count));
    313           // Decode import table.
    314           for (uint32_t i = 0; i < import_table_count; ++i) {
    315             if (failed()) break;
    316             TRACE("DecodeImportTable[%d] module+%d\n", i,
    317                   static_cast<int>(pc_ - start_));
    318 
    319             module->import_table.push_back({nullptr,  // sig
    320                                             0,        // sig_index
    321                                             0,        // module_name_offset
    322                                             0,        // module_name_length
    323                                             0,        // function_name_offset
    324                                             0});      // function_name_length
    325             WasmImport* import = &module->import_table.back();
    326 
    327             import->sig_index = consume_sig_index(module, &import->sig);
    328             const byte* pos = pc_;
    329             import->module_name_offset =
    330                 consume_string(&import->module_name_length, true);
    331             if (import->module_name_length == 0) {
    332               error(pos, "import module name cannot be NULL");
    333             }
    334             import->function_name_offset =
    335                 consume_string(&import->function_name_length, true);
    336           }
    337           break;
    338         }
    339         case WasmSection::Code::ExportTable: {
    340           // Declares an export table.
    341           CheckForFunctions(module, section);
    342           uint32_t export_table_count = consume_u32v("export table count");
    343           module->export_table.reserve(SafeReserve(export_table_count));
    344           // Decode export table.
    345           for (uint32_t i = 0; i < export_table_count; ++i) {
    346             if (failed()) break;
    347             TRACE("DecodeExportTable[%d] module+%d\n", i,
    348                   static_cast<int>(pc_ - start_));
    349 
    350             module->export_table.push_back({0,    // func_index
    351                                             0,    // name_offset
    352                                             0});  // name_length
    353             WasmExport* exp = &module->export_table.back();
    354 
    355             WasmFunction* func;
    356             exp->func_index = consume_func_index(module, &func);
    357             exp->name_offset = consume_string(&exp->name_length, true);
    358           }
    359           // Check for duplicate exports.
    360           if (ok() && module->export_table.size() > 1) {
    361             std::vector<WasmExport> sorted_exports(module->export_table);
    362             const byte* base = start_;
    363             auto cmp_less = [base](const WasmExport& a, const WasmExport& b) {
    364               // Return true if a < b.
    365               uint32_t len = a.name_length;
    366               if (len != b.name_length) return len < b.name_length;
    367               return memcmp(base + a.name_offset, base + b.name_offset, len) <
    368                      0;
    369             };
    370             std::stable_sort(sorted_exports.begin(), sorted_exports.end(),
    371                              cmp_less);
    372             auto it = sorted_exports.begin();
    373             WasmExport* last = &*it++;
    374             for (auto end = sorted_exports.end(); it != end; last = &*it++) {
    375               DCHECK(!cmp_less(*it, *last));  // Vector must be sorted.
    376               if (!cmp_less(*last, *it)) {
    377                 const byte* pc = start_ + it->name_offset;
    378                 error(pc, pc,
    379                       "Duplicate export name '%.*s' for functions %d and %d",
    380                       it->name_length, pc, last->func_index, it->func_index);
    381                 break;
    382               }
    383             }
    384           }
    385           break;
    386         }
    387         case WasmSection::Code::Max:
    388           // Skip unknown sections.
    389           TRACE("Unknown section: '");
    390           for (uint32_t i = 0; i != string_length; ++i) {
    391             TRACE("%c", *(section_name_start + i));
    392           }
    393           TRACE("'\n");
    394           consume_bytes(section_length);
    395           break;
    396       }
    397 
    398       if (pc_ != expected_section_end) {
    399         const char* diff = pc_ < expected_section_end ? "shorter" : "longer";
    400         size_t expected_length = static_cast<size_t>(section_length);
    401         size_t actual_length = static_cast<size_t>(pc_ - section_start);
    402         error(pc_, pc_,
    403               "section \"%s\" %s (%zu bytes) than specified (%zu bytes)",
    404               WasmSection::getName(section), diff, actual_length,
    405               expected_length);
    406         break;
    407       }
    408     }
    409 
    410   done:
    411     if (ok()) CalculateGlobalsOffsets(module);
    412     const WasmModule* finished_module = module;
    413     ModuleResult result = toResult(finished_module);
    414     if (FLAG_dump_wasm_module) {
    415       DumpModule(module, result);
    416     }
    417     return result;
    418   }
    419 
    420   uint32_t SafeReserve(uint32_t count) {
    421     // Avoid OOM by only reserving up to a certain size.
    422     const uint32_t kMaxReserve = 20000;
    423     return count < kMaxReserve ? count : kMaxReserve;
    424   }
    425 
    426   void CheckForFunctions(WasmModule* module, WasmSection::Code section) {
    427     if (module->functions.size() == 0) {
    428       error(pc_ - 1, nullptr, "functions must appear before section %s",
    429             WasmSection::getName(section));
    430     }
    431   }
    432 
    433   int CheckSectionOrder(int current_order, WasmSection::Code section) {
    434     int next_order = WasmSection::getOrder(section);
    435     if (next_order == 0) return current_order;
    436     if (next_order == current_order) {
    437       error(pc_, pc_, "section \"%s\" already defined",
    438             WasmSection::getName(section));
    439     }
    440     if (next_order < current_order) {
    441       error(pc_, pc_, "section \"%s\" out of order",
    442             WasmSection::getName(section));
    443     }
    444     return next_order;
    445   }
    446 
    447   // Decodes a single anonymous function starting at {start_}.
    448   FunctionResult DecodeSingleFunction(ModuleEnv* module_env,
    449                                       WasmFunction* function) {
    450     pc_ = start_;
    451     function->sig = consume_sig();            // read signature
    452     function->name_offset = 0;                // ---- name
    453     function->name_length = 0;                // ---- name length
    454     function->code_start_offset = off(pc_);   // ---- code start
    455     function->code_end_offset = off(limit_);  // ---- code end
    456 
    457     if (ok()) VerifyFunctionBody(0, module_env, function);
    458 
    459     FunctionResult result;
    460     result.CopyFrom(result_);  // Copy error code and location.
    461     result.val = function;
    462     return result;
    463   }
    464 
    465   // Decodes a single function signature at {start}.
    466   FunctionSig* DecodeFunctionSignature(const byte* start) {
    467     pc_ = start;
    468     FunctionSig* result = consume_sig();
    469     return ok() ? result : nullptr;
    470   }
    471 
    472  private:
    473   Zone* module_zone;
    474   ModuleResult result_;
    475   ModuleOrigin origin_;
    476 
    477   uint32_t off(const byte* ptr) { return static_cast<uint32_t>(ptr - start_); }
    478 
    479   // Decodes a single global entry inside a module starting at {pc_}.
    480   void DecodeGlobalInModule(WasmGlobal* global) {
    481     global->name_offset = consume_string(&global->name_length, false);
    482     if (!unibrow::Utf8::Validate(start_ + global->name_offset,
    483                                  global->name_length)) {
    484       error("global name is not valid utf8");
    485     }
    486     global->type = mem_type();
    487     global->offset = 0;
    488     global->exported = consume_u8("exported") != 0;
    489   }
    490 
    491   bool IsWithinLimit(uint32_t limit, uint32_t offset, uint32_t size) {
    492     if (offset > limit) return false;
    493     if ((offset + size) < offset) return false;  // overflow
    494     return (offset + size) <= limit;
    495   }
    496 
    497   // Decodes a single data segment entry inside a module starting at {pc_}.
    498   void DecodeDataSegmentInModule(WasmModule* module, WasmDataSegment* segment) {
    499     const byte* start = pc_;
    500     segment->dest_addr = consume_u32v("destination");
    501     segment->source_size = consume_u32v("source size");
    502     segment->source_offset = static_cast<uint32_t>(pc_ - start_);
    503     segment->init = true;
    504 
    505     // Validate the data is in the module.
    506     uint32_t module_limit = static_cast<uint32_t>(limit_ - start_);
    507     if (!IsWithinLimit(module_limit, segment->source_offset,
    508                        segment->source_size)) {
    509       error(start, "segment out of bounds of module");
    510     }
    511 
    512     // Validate that the segment will fit into the (minimum) memory.
    513     uint32_t memory_limit =
    514         WasmModule::kPageSize * (module ? module->min_mem_pages
    515                                         : WasmModule::kMaxMemPages);
    516     if (!IsWithinLimit(memory_limit, segment->dest_addr,
    517                        segment->source_size)) {
    518       error(start, "segment out of bounds of memory");
    519     }
    520 
    521     consume_bytes(segment->source_size);
    522   }
    523 
    524   // Calculate individual global offsets and total size of globals table.
    525   void CalculateGlobalsOffsets(WasmModule* module) {
    526     uint32_t offset = 0;
    527     if (module->globals.size() == 0) {
    528       module->globals_size = 0;
    529       return;
    530     }
    531     for (WasmGlobal& global : module->globals) {
    532       byte size = WasmOpcodes::MemSize(global.type);
    533       offset = (offset + size - 1) & ~(size - 1);  // align
    534       global.offset = offset;
    535       offset += size;
    536     }
    537     module->globals_size = offset;
    538   }
    539 
    540   // Verifies the body (code) of a given function.
    541   void VerifyFunctionBody(uint32_t func_num, ModuleEnv* menv,
    542                           WasmFunction* function) {
    543     if (FLAG_trace_wasm_decoder || FLAG_trace_wasm_decode_time) {
    544       OFStream os(stdout);
    545       os << "Verifying WASM function " << WasmFunctionName(function, menv)
    546          << std::endl;
    547     }
    548     FunctionBody body = {menv, function->sig, start_,
    549                          start_ + function->code_start_offset,
    550                          start_ + function->code_end_offset};
    551     TreeResult result = VerifyWasmCode(module_zone->allocator(), body);
    552     if (result.failed()) {
    553       // Wrap the error message from the function decoder.
    554       std::ostringstream str;
    555       str << "in function " << WasmFunctionName(function, menv) << ": ";
    556       str << result;
    557       std::string strval = str.str();
    558       const char* raw = strval.c_str();
    559       size_t len = strlen(raw);
    560       char* buffer = new char[len];
    561       strncpy(buffer, raw, len);
    562       buffer[len - 1] = 0;
    563 
    564       // Copy error code and location.
    565       result_.CopyFrom(result);
    566       result_.error_msg.Reset(buffer);
    567     }
    568   }
    569 
    570   // Reads a single 32-bit unsigned integer interpreted as an offset, checking
    571   // the offset is within bounds and advances.
    572   uint32_t consume_offset(const char* name = nullptr) {
    573     uint32_t offset = consume_u32(name ? name : "offset");
    574     if (offset > static_cast<uint32_t>(limit_ - start_)) {
    575       error(pc_ - sizeof(uint32_t), "offset out of bounds of module");
    576     }
    577     return offset;
    578   }
    579 
    580   // Reads a length-prefixed string, checking that it is within bounds. Returns
    581   // the offset of the string, and the length as an out parameter.
    582   uint32_t consume_string(uint32_t* length, bool validate_utf8) {
    583     *length = consume_u32v("string length");
    584     uint32_t offset = pc_offset();
    585     TRACE("  +%u  %-20s: (%u bytes)\n", offset, "string", *length);
    586     if (validate_utf8 && !unibrow::Utf8::Validate(pc_, *length)) {
    587       error(pc_, "no valid UTF-8 string");
    588     }
    589     consume_bytes(*length);
    590     return offset;
    591   }
    592 
    593   uint32_t consume_sig_index(WasmModule* module, FunctionSig** sig) {
    594     const byte* pos = pc_;
    595     uint32_t sig_index = consume_u32v("signature index");
    596     if (sig_index >= module->signatures.size()) {
    597       error(pos, pos, "signature index %u out of bounds (%d signatures)",
    598             sig_index, static_cast<int>(module->signatures.size()));
    599       *sig = nullptr;
    600       return 0;
    601     }
    602     *sig = module->signatures[sig_index];
    603     return sig_index;
    604   }
    605 
    606   uint32_t consume_func_index(WasmModule* module, WasmFunction** func) {
    607     const byte* pos = pc_;
    608     uint32_t func_index = consume_u32v("function index");
    609     if (func_index >= module->functions.size()) {
    610       error(pos, pos, "function index %u out of bounds (%d functions)",
    611             func_index, static_cast<int>(module->functions.size()));
    612       *func = nullptr;
    613       return 0;
    614     }
    615     *func = &module->functions[func_index];
    616     return func_index;
    617   }
    618 
    619   // Reads a single 8-bit integer, interpreting it as a local type.
    620   LocalType consume_local_type() {
    621     byte val = consume_u8("local type");
    622     LocalTypeCode t = static_cast<LocalTypeCode>(val);
    623     switch (t) {
    624       case kLocalVoid:
    625         return kAstStmt;
    626       case kLocalI32:
    627         return kAstI32;
    628       case kLocalI64:
    629         return kAstI64;
    630       case kLocalF32:
    631         return kAstF32;
    632       case kLocalF64:
    633         return kAstF64;
    634       default:
    635         error(pc_ - 1, "invalid local type");
    636         return kAstStmt;
    637     }
    638   }
    639 
    640   // Reads a single 8-bit integer, interpreting it as a memory type.
    641   MachineType mem_type() {
    642     byte val = consume_u8("memory type");
    643     MemTypeCode t = static_cast<MemTypeCode>(val);
    644     switch (t) {
    645       case kMemI8:
    646         return MachineType::Int8();
    647       case kMemU8:
    648         return MachineType::Uint8();
    649       case kMemI16:
    650         return MachineType::Int16();
    651       case kMemU16:
    652         return MachineType::Uint16();
    653       case kMemI32:
    654         return MachineType::Int32();
    655       case kMemU32:
    656         return MachineType::Uint32();
    657       case kMemI64:
    658         return MachineType::Int64();
    659       case kMemU64:
    660         return MachineType::Uint64();
    661       case kMemF32:
    662         return MachineType::Float32();
    663       case kMemF64:
    664         return MachineType::Float64();
    665       case kMemS128:
    666         return MachineType::Simd128();
    667       default:
    668         error(pc_ - 1, "invalid memory type");
    669         return MachineType::None();
    670     }
    671   }
    672 
    673   // Parses a type entry, which is currently limited to functions only.
    674   FunctionSig* consume_sig() {
    675     const byte* pos = pc_;
    676     byte form = consume_u8("type form");
    677     if (form != kWasmFunctionTypeForm) {
    678       error(pos, pos, "expected function type form (0x%02x), got: 0x%02x",
    679             kWasmFunctionTypeForm, form);
    680       return nullptr;
    681     }
    682     // parse parameter types
    683     uint32_t param_count = consume_u32v("param count");
    684     std::vector<LocalType> params;
    685     for (uint32_t i = 0; i < param_count; ++i) {
    686       LocalType param = consume_local_type();
    687       if (param == kAstStmt) error(pc_ - 1, "invalid void parameter type");
    688       params.push_back(param);
    689     }
    690 
    691     // parse return types
    692     const byte* pt = pc_;
    693     uint32_t return_count = consume_u32v("return count");
    694     if (return_count > kMaxReturnCount) {
    695       error(pt, pt, "return count of %u exceeds maximum of %u", return_count,
    696             kMaxReturnCount);
    697       return nullptr;
    698     }
    699     std::vector<LocalType> returns;
    700     for (uint32_t i = 0; i < return_count; ++i) {
    701       LocalType ret = consume_local_type();
    702       if (ret == kAstStmt) error(pc_ - 1, "invalid void return type");
    703       returns.push_back(ret);
    704     }
    705 
    706     // FunctionSig stores the return types first.
    707     LocalType* buffer =
    708         module_zone->NewArray<LocalType>(param_count + return_count);
    709     uint32_t b = 0;
    710     for (uint32_t i = 0; i < return_count; ++i) buffer[b++] = returns[i];
    711     for (uint32_t i = 0; i < param_count; ++i) buffer[b++] = params[i];
    712 
    713     return new (module_zone) FunctionSig(return_count, param_count, buffer);
    714   }
    715 };
    716 
    717 // Helpers for nice error messages.
    718 class ModuleError : public ModuleResult {
    719  public:
    720   explicit ModuleError(const char* msg) {
    721     error_code = kError;
    722     size_t len = strlen(msg) + 1;
    723     char* result = new char[len];
    724     strncpy(result, msg, len);
    725     result[len - 1] = 0;
    726     error_msg.Reset(result);
    727   }
    728 };
    729 
    730 // Helpers for nice error messages.
    731 class FunctionError : public FunctionResult {
    732  public:
    733   explicit FunctionError(const char* msg) {
    734     error_code = kError;
    735     size_t len = strlen(msg) + 1;
    736     char* result = new char[len];
    737     strncpy(result, msg, len);
    738     result[len - 1] = 0;
    739     error_msg.Reset(result);
    740   }
    741 };
    742 
    743 Vector<const byte> FindSection(const byte* module_start, const byte* module_end,
    744                                WasmSection::Code code) {
    745   Decoder decoder(module_start, module_end);
    746 
    747   uint32_t magic_word = decoder.consume_u32("wasm magic");
    748   if (magic_word != kWasmMagic) decoder.error("wrong magic word");
    749 
    750   uint32_t magic_version = decoder.consume_u32("wasm version");
    751   if (magic_version != kWasmVersion) decoder.error("wrong wasm version");
    752 
    753   while (decoder.more() && decoder.ok()) {
    754     // Read the section name.
    755     uint32_t string_length = decoder.consume_u32v("section name length");
    756     const byte* section_name_start = decoder.pc();
    757     decoder.consume_bytes(string_length);
    758     if (decoder.failed()) break;
    759 
    760     WasmSection::Code section =
    761         WasmSection::lookup(section_name_start, string_length);
    762 
    763     // Read and check the section size.
    764     uint32_t section_length = decoder.consume_u32v("section length");
    765 
    766     const byte* section_start = decoder.pc();
    767     decoder.consume_bytes(section_length);
    768     if (section == code && decoder.ok()) {
    769       return Vector<const uint8_t>(section_start, section_length);
    770     }
    771   }
    772 
    773   return Vector<const uint8_t>();
    774 }
    775 
    776 }  // namespace
    777 
    778 ModuleResult DecodeWasmModule(Isolate* isolate, Zone* zone,
    779                               const byte* module_start, const byte* module_end,
    780                               bool verify_functions, ModuleOrigin origin) {
    781   size_t decode_memory_start = zone->allocation_size();
    782   HistogramTimerScope wasm_decode_module_time_scope(
    783       isolate->counters()->wasm_decode_module_time());
    784   size_t size = module_end - module_start;
    785   if (module_start > module_end) return ModuleError("start > end");
    786   if (size >= kMaxModuleSize) return ModuleError("size > maximum module size");
    787   // TODO(bradnelson): Improve histogram handling of size_t.
    788   isolate->counters()->wasm_module_size_bytes()->AddSample(
    789       static_cast<int>(size));
    790   WasmModule* module = new WasmModule();
    791   ModuleDecoder decoder(zone, module_start, module_end, origin);
    792   ModuleResult result = decoder.DecodeModule(module, verify_functions);
    793   // TODO(bradnelson): Improve histogram handling of size_t.
    794   isolate->counters()->wasm_decode_module_peak_memory_bytes()->AddSample(
    795       static_cast<int>(zone->allocation_size() - decode_memory_start));
    796   return result;
    797 }
    798 
    799 FunctionSig* DecodeWasmSignatureForTesting(Zone* zone, const byte* start,
    800                                            const byte* end) {
    801   ModuleDecoder decoder(zone, start, end, kWasmOrigin);
    802   return decoder.DecodeFunctionSignature(start);
    803 }
    804 
    805 FunctionResult DecodeWasmFunction(Isolate* isolate, Zone* zone,
    806                                   ModuleEnv* module_env,
    807                                   const byte* function_start,
    808                                   const byte* function_end) {
    809   HistogramTimerScope wasm_decode_function_time_scope(
    810       isolate->counters()->wasm_decode_function_time());
    811   size_t size = function_end - function_start;
    812   if (function_start > function_end) return FunctionError("start > end");
    813   if (size > kMaxFunctionSize)
    814     return FunctionError("size > maximum function size");
    815   isolate->counters()->wasm_function_size_bytes()->AddSample(
    816       static_cast<int>(size));
    817   WasmFunction* function = new WasmFunction();
    818   ModuleDecoder decoder(zone, function_start, function_end, kWasmOrigin);
    819   return decoder.DecodeSingleFunction(module_env, function);
    820 }
    821 
    822 FunctionOffsetsResult DecodeWasmFunctionOffsets(const byte* module_start,
    823                                                 const byte* module_end) {
    824   Vector<const byte> code_section =
    825       FindSection(module_start, module_end, WasmSection::Code::FunctionBodies);
    826   Decoder decoder(code_section.start(), code_section.end());
    827   if (!code_section.start()) decoder.error("no code section");
    828 
    829   uint32_t functions_count = decoder.consume_u32v("functions count");
    830   FunctionOffsets table;
    831   // Take care of invalid input here.
    832   if (functions_count < static_cast<unsigned>(code_section.length()) / 2)
    833     table.reserve(functions_count);
    834   int section_offset = static_cast<int>(code_section.start() - module_start);
    835   DCHECK_LE(0, section_offset);
    836   for (uint32_t i = 0; i < functions_count && decoder.ok(); ++i) {
    837     uint32_t size = decoder.consume_u32v("body size");
    838     int offset = static_cast<int>(section_offset + decoder.pc_offset());
    839     table.push_back(std::make_pair(offset, static_cast<int>(size)));
    840     DCHECK(table.back().first >= 0 && table.back().second >= 0);
    841     decoder.consume_bytes(size);
    842   }
    843   if (decoder.more()) decoder.error("unexpected additional bytes");
    844 
    845   return decoder.toResult(std::move(table));
    846 }
    847 
    848 }  // namespace wasm
    849 }  // namespace internal
    850 }  // namespace v8
    851