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/flags.h"
     10 #include "src/macro-assembler.h"
     11 #include "src/objects.h"
     12 #include "src/v8.h"
     13 
     14 #include "src/wasm/decoder.h"
     15 
     16 namespace v8 {
     17 namespace internal {
     18 namespace wasm {
     19 
     20 #if DEBUG
     21 #define TRACE(...)                                    \
     22   do {                                                \
     23     if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
     24   } while (false)
     25 #else
     26 #define TRACE(...)
     27 #endif
     28 
     29 namespace {
     30 
     31 const char* kNameString = "name";
     32 const size_t kNameStringLength = 4;
     33 
     34 LocalType TypeOf(const WasmModule* module, const WasmInitExpr& expr) {
     35   switch (expr.kind) {
     36     case WasmInitExpr::kNone:
     37       return kAstStmt;
     38     case WasmInitExpr::kGlobalIndex:
     39       return expr.val.global_index < module->globals.size()
     40                  ? module->globals[expr.val.global_index].type
     41                  : kAstStmt;
     42     case WasmInitExpr::kI32Const:
     43       return kAstI32;
     44     case WasmInitExpr::kI64Const:
     45       return kAstI64;
     46     case WasmInitExpr::kF32Const:
     47       return kAstF32;
     48     case WasmInitExpr::kF64Const:
     49       return kAstF64;
     50     default:
     51       UNREACHABLE();
     52       return kAstStmt;
     53   }
     54 }
     55 
     56 // An iterator over the sections in a WASM binary module.
     57 // Automatically skips all unknown sections.
     58 class WasmSectionIterator {
     59  public:
     60   explicit WasmSectionIterator(Decoder& decoder)
     61       : decoder_(decoder),
     62         section_code_(kUnknownSectionCode),
     63         section_start_(decoder.pc()),
     64         section_end_(decoder.pc()) {
     65     next();
     66   }
     67 
     68   inline bool more() const {
     69     return section_code_ != kUnknownSectionCode && decoder_.more();
     70   }
     71 
     72   inline WasmSectionCode section_code() const { return section_code_; }
     73 
     74   inline const byte* section_start() const { return section_start_; }
     75 
     76   inline uint32_t section_length() const {
     77     return static_cast<uint32_t>(section_end_ - section_start_);
     78   }
     79 
     80   inline const byte* payload_start() const { return payload_start_; }
     81 
     82   inline uint32_t payload_length() const {
     83     return static_cast<uint32_t>(section_end_ - payload_start_);
     84   }
     85 
     86   inline const byte* section_end() const { return section_end_; }
     87 
     88   // Advances to the next section, checking that decoding the current section
     89   // stopped at {section_end_}.
     90   void advance() {
     91     if (decoder_.pc() != section_end_) {
     92       const char* msg = decoder_.pc() < section_end_ ? "shorter" : "longer";
     93       decoder_.error(decoder_.pc(), decoder_.pc(),
     94                      "section was %s than expected size "
     95                      "(%u bytes expected, %zu decoded)",
     96                      msg, section_length(),
     97                      static_cast<size_t>(decoder_.pc() - section_start_));
     98     }
     99     next();
    100   }
    101 
    102  private:
    103   Decoder& decoder_;
    104   WasmSectionCode section_code_;
    105   const byte* section_start_;
    106   const byte* payload_start_;
    107   const byte* section_end_;
    108 
    109   // Reads the section code/name at the current position and sets up
    110   // the internal fields.
    111   void next() {
    112     while (true) {
    113       if (!decoder_.more()) {
    114         section_code_ = kUnknownSectionCode;
    115         return;
    116       }
    117       uint8_t section_code = decoder_.consume_u8("section code");
    118       // Read and check the section size.
    119       uint32_t section_length = decoder_.consume_u32v("section length");
    120       section_start_ = decoder_.pc();
    121       payload_start_ = section_start_;
    122       if (decoder_.checkAvailable(section_length)) {
    123         // Get the limit of the section within the module.
    124         section_end_ = section_start_ + section_length;
    125       } else {
    126         // The section would extend beyond the end of the module.
    127         section_end_ = section_start_;
    128       }
    129 
    130       if (section_code == kUnknownSectionCode) {
    131         // Check for the known "name" section.
    132         uint32_t string_length = decoder_.consume_u32v("section name length");
    133         const byte* section_name_start = decoder_.pc();
    134         decoder_.consume_bytes(string_length, "section name");
    135         if (decoder_.failed() || decoder_.pc() > section_end_) {
    136           TRACE("Section name of length %u couldn't be read\n", string_length);
    137           section_code_ = kUnknownSectionCode;
    138           return;
    139         }
    140         payload_start_ = decoder_.pc();
    141 
    142         TRACE("  +%d  section name        : \"%.*s\"\n",
    143               static_cast<int>(section_name_start - decoder_.start()),
    144               string_length < 20 ? string_length : 20, section_name_start);
    145 
    146         if (string_length == kNameStringLength &&
    147             strncmp(reinterpret_cast<const char*>(section_name_start),
    148                     kNameString, kNameStringLength) == 0) {
    149           section_code = kNameSectionCode;
    150         } else {
    151           section_code = kUnknownSectionCode;
    152         }
    153       } else if (!IsValidSectionCode(section_code)) {
    154         decoder_.error(decoder_.pc(), decoder_.pc(),
    155                        "unknown section code #0x%02x", section_code);
    156         section_code = kUnknownSectionCode;
    157       }
    158       section_code_ = static_cast<WasmSectionCode>(section_code);
    159 
    160       TRACE("Section: %s\n", SectionName(section_code_));
    161       if (section_code_ == kUnknownSectionCode &&
    162           section_end_ > decoder_.pc()) {
    163         // skip to the end of the unknown section.
    164         uint32_t remaining =
    165             static_cast<uint32_t>(section_end_ - decoder_.pc());
    166         decoder_.consume_bytes(remaining, "section payload");
    167         // fall through and continue to the next section.
    168       } else {
    169         return;
    170       }
    171     }
    172   }
    173 };
    174 
    175 // The main logic for decoding the bytes of a module.
    176 class ModuleDecoder : public Decoder {
    177  public:
    178   ModuleDecoder(Zone* zone, const byte* module_start, const byte* module_end,
    179                 ModuleOrigin origin)
    180       : Decoder(module_start, module_end), module_zone(zone), origin_(origin) {
    181     result_.start = start_;
    182     if (limit_ < start_) {
    183       error(start_, "end is less than start");
    184       limit_ = start_;
    185     }
    186   }
    187 
    188   virtual void onFirstError() {
    189     pc_ = limit_;  // On error, terminate section decoding loop.
    190   }
    191 
    192   static void DumpModule(WasmModule* module, const ModuleResult& result) {
    193     std::string path;
    194     if (FLAG_dump_wasm_module_path) {
    195       path = FLAG_dump_wasm_module_path;
    196       if (path.size() &&
    197           !base::OS::isDirectorySeparator(path[path.size() - 1])) {
    198         path += base::OS::DirectorySeparator();
    199       }
    200     }
    201     // File are named `HASH.{ok,failed}.wasm`.
    202     size_t hash = base::hash_range(module->module_start, module->module_end);
    203     char buf[32] = {'\0'};
    204 #if V8_OS_WIN && _MSC_VER < 1900
    205 #define snprintf sprintf_s
    206 #endif
    207     snprintf(buf, sizeof(buf) - 1, "%016zx.%s.wasm", hash,
    208              result.ok() ? "ok" : "failed");
    209     std::string name(buf);
    210     if (FILE* wasm_file = base::OS::FOpen((path + name).c_str(), "wb")) {
    211       fwrite(module->module_start, module->module_end - module->module_start, 1,
    212              wasm_file);
    213       fclose(wasm_file);
    214     }
    215   }
    216 
    217   // Decodes an entire module.
    218   ModuleResult DecodeModule(WasmModule* module, bool verify_functions = true) {
    219     pc_ = start_;
    220     module->module_start = start_;
    221     module->module_end = limit_;
    222     module->min_mem_pages = 0;
    223     module->max_mem_pages = 0;
    224     module->mem_export = false;
    225     module->origin = origin_;
    226 
    227     const byte* pos = pc_;
    228     uint32_t magic_word = consume_u32("wasm magic");
    229 #define BYTES(x) (x & 0xff), (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff
    230     if (magic_word != kWasmMagic) {
    231       error(pos, pos,
    232             "expected magic word %02x %02x %02x %02x, "
    233             "found %02x %02x %02x %02x",
    234             BYTES(kWasmMagic), BYTES(magic_word));
    235     }
    236 
    237     pos = pc_;
    238     {
    239       uint32_t magic_version = consume_u32("wasm version");
    240       if (magic_version != kWasmVersion) {
    241         error(pos, pos,
    242               "expected version %02x %02x %02x %02x, "
    243               "found %02x %02x %02x %02x",
    244               BYTES(kWasmVersion), BYTES(magic_version));
    245       }
    246     }
    247 
    248     WasmSectionIterator section_iter(*this);
    249 
    250     // ===== Type section ====================================================
    251     if (section_iter.section_code() == kTypeSectionCode) {
    252       uint32_t signatures_count = consume_u32v("signatures count");
    253       module->signatures.reserve(SafeReserve(signatures_count));
    254       for (uint32_t i = 0; ok() && i < signatures_count; ++i) {
    255         TRACE("DecodeSignature[%d] module+%d\n", i,
    256               static_cast<int>(pc_ - start_));
    257         FunctionSig* s = consume_sig();
    258         module->signatures.push_back(s);
    259       }
    260       section_iter.advance();
    261     }
    262 
    263     // ===== Import section ==================================================
    264     if (section_iter.section_code() == kImportSectionCode) {
    265       uint32_t import_table_count = consume_u32v("import table count");
    266       module->import_table.reserve(SafeReserve(import_table_count));
    267       for (uint32_t i = 0; ok() && i < import_table_count; ++i) {
    268         TRACE("DecodeImportTable[%d] module+%d\n", i,
    269               static_cast<int>(pc_ - start_));
    270 
    271         module->import_table.push_back({
    272             0,                  // module_name_length
    273             0,                  // module_name_offset
    274             0,                  // field_name_offset
    275             0,                  // field_name_length
    276             kExternalFunction,  // kind
    277             0                   // index
    278         });
    279         WasmImport* import = &module->import_table.back();
    280         const byte* pos = pc_;
    281         import->module_name_offset =
    282             consume_string(&import->module_name_length, true);
    283         if (import->module_name_length == 0) {
    284           error(pos, "import module name cannot be NULL");
    285         }
    286         import->field_name_offset =
    287             consume_string(&import->field_name_length, true);
    288 
    289         import->kind = static_cast<WasmExternalKind>(consume_u8("import kind"));
    290         switch (import->kind) {
    291           case kExternalFunction: {
    292             // ===== Imported function =======================================
    293             import->index = static_cast<uint32_t>(module->functions.size());
    294             module->num_imported_functions++;
    295             module->functions.push_back({nullptr,        // sig
    296                                          import->index,  // func_index
    297                                          0,              // sig_index
    298                                          0,              // name_offset
    299                                          0,              // name_length
    300                                          0,              // code_start_offset
    301                                          0,              // code_end_offset
    302                                          true,           // imported
    303                                          false});        // exported
    304             WasmFunction* function = &module->functions.back();
    305             function->sig_index = consume_sig_index(module, &function->sig);
    306             break;
    307           }
    308           case kExternalTable: {
    309             // ===== Imported table ==========================================
    310             import->index =
    311                 static_cast<uint32_t>(module->function_tables.size());
    312             module->function_tables.push_back({0, 0, false,
    313                                                std::vector<int32_t>(), true,
    314                                                false, SignatureMap()});
    315             expect_u8("element type", kWasmAnyFunctionTypeForm);
    316             WasmIndirectFunctionTable* table = &module->function_tables.back();
    317             consume_resizable_limits(
    318                 "element count", "elements", WasmModule::kV8MaxTableSize,
    319                 &table->min_size, &table->has_max, WasmModule::kV8MaxTableSize,
    320                 &table->max_size);
    321             break;
    322           }
    323           case kExternalMemory: {
    324             // ===== Imported memory =========================================
    325             bool has_max = false;
    326             consume_resizable_limits("memory", "pages", WasmModule::kV8MaxPages,
    327                                      &module->min_mem_pages, &has_max,
    328                                      WasmModule::kSpecMaxPages,
    329                                      &module->max_mem_pages);
    330             module->has_memory = true;
    331             break;
    332           }
    333           case kExternalGlobal: {
    334             // ===== Imported global =========================================
    335             import->index = static_cast<uint32_t>(module->globals.size());
    336             module->globals.push_back(
    337                 {kAstStmt, false, WasmInitExpr(), 0, true, false});
    338             WasmGlobal* global = &module->globals.back();
    339             global->type = consume_value_type();
    340             global->mutability = consume_u8("mutability") != 0;
    341             if (global->mutability) {
    342               error("mutable globals cannot be imported");
    343             }
    344             break;
    345           }
    346           default:
    347             error(pos, pos, "unknown import kind 0x%02x", import->kind);
    348             break;
    349         }
    350       }
    351       section_iter.advance();
    352     }
    353 
    354     // ===== Function section ================================================
    355     if (section_iter.section_code() == kFunctionSectionCode) {
    356       uint32_t functions_count = consume_u32v("functions count");
    357       module->functions.reserve(SafeReserve(functions_count));
    358       module->num_declared_functions = functions_count;
    359       for (uint32_t i = 0; ok() && i < functions_count; ++i) {
    360         uint32_t func_index = static_cast<uint32_t>(module->functions.size());
    361         module->functions.push_back({nullptr,     // sig
    362                                      func_index,  // func_index
    363                                      0,           // sig_index
    364                                      0,           // name_offset
    365                                      0,           // name_length
    366                                      0,           // code_start_offset
    367                                      0,           // code_end_offset
    368                                      false,       // imported
    369                                      false});     // exported
    370         WasmFunction* function = &module->functions.back();
    371         function->sig_index = consume_sig_index(module, &function->sig);
    372       }
    373       section_iter.advance();
    374     }
    375 
    376     // ===== Table section ===================================================
    377     if (section_iter.section_code() == kTableSectionCode) {
    378       const byte* pos = pc_;
    379       uint32_t table_count = consume_u32v("table count");
    380       // Require at most one table for now.
    381       if (table_count > 1) {
    382         error(pos, pos, "invalid table count %d, maximum 1", table_count);
    383       }
    384       if (module->function_tables.size() < 1) {
    385         module->function_tables.push_back({0, 0, false, std::vector<int32_t>(),
    386                                            false, false, SignatureMap()});
    387       }
    388 
    389       for (uint32_t i = 0; ok() && i < table_count; i++) {
    390         WasmIndirectFunctionTable* table = &module->function_tables.back();
    391         expect_u8("table type", kWasmAnyFunctionTypeForm);
    392         consume_resizable_limits("table elements", "elements",
    393                                  WasmModule::kV8MaxTableSize, &table->min_size,
    394                                  &table->has_max, WasmModule::kV8MaxTableSize,
    395                                  &table->max_size);
    396       }
    397       section_iter.advance();
    398     }
    399 
    400     // ===== Memory section ==================================================
    401     if (section_iter.section_code() == kMemorySectionCode) {
    402       const byte* pos = pc_;
    403       uint32_t memory_count = consume_u32v("memory count");
    404       // Require at most one memory for now.
    405       if (memory_count > 1) {
    406         error(pos, pos, "invalid memory count %d, maximum 1", memory_count);
    407       }
    408 
    409       for (uint32_t i = 0; ok() && i < memory_count; i++) {
    410         bool has_max = false;
    411         consume_resizable_limits(
    412             "memory", "pages", WasmModule::kV8MaxPages, &module->min_mem_pages,
    413             &has_max, WasmModule::kSpecMaxPages, &module->max_mem_pages);
    414       }
    415       module->has_memory = true;
    416       section_iter.advance();
    417     }
    418 
    419     // ===== Global section ==================================================
    420     if (section_iter.section_code() == kGlobalSectionCode) {
    421       uint32_t globals_count = consume_u32v("globals count");
    422       uint32_t imported_globals = static_cast<uint32_t>(module->globals.size());
    423       if (!IsWithinLimit(std::numeric_limits<int32_t>::max(), globals_count,
    424                          imported_globals)) {
    425         error(pos, pos, "too many imported+defined globals: %u + %u",
    426               imported_globals, globals_count);
    427       }
    428       module->globals.reserve(SafeReserve(imported_globals + globals_count));
    429       for (uint32_t i = 0; ok() && i < globals_count; ++i) {
    430         TRACE("DecodeGlobal[%d] module+%d\n", i,
    431               static_cast<int>(pc_ - start_));
    432         // Add an uninitialized global and pass a pointer to it.
    433         module->globals.push_back(
    434             {kAstStmt, false, WasmInitExpr(), 0, false, false});
    435         WasmGlobal* global = &module->globals.back();
    436         DecodeGlobalInModule(module, i + imported_globals, global);
    437       }
    438       section_iter.advance();
    439     }
    440 
    441     // ===== Export section ==================================================
    442     if (section_iter.section_code() == kExportSectionCode) {
    443       uint32_t export_table_count = consume_u32v("export table count");
    444       module->export_table.reserve(SafeReserve(export_table_count));
    445       for (uint32_t i = 0; ok() && i < export_table_count; ++i) {
    446         TRACE("DecodeExportTable[%d] module+%d\n", i,
    447               static_cast<int>(pc_ - start_));
    448 
    449         module->export_table.push_back({
    450             0,                  // name_length
    451             0,                  // name_offset
    452             kExternalFunction,  // kind
    453             0                   // index
    454         });
    455         WasmExport* exp = &module->export_table.back();
    456 
    457         exp->name_offset = consume_string(&exp->name_length, true);
    458         const byte* pos = pc();
    459         exp->kind = static_cast<WasmExternalKind>(consume_u8("export kind"));
    460         switch (exp->kind) {
    461           case kExternalFunction: {
    462             WasmFunction* func = nullptr;
    463             exp->index = consume_func_index(module, &func);
    464             module->num_exported_functions++;
    465             if (func) func->exported = true;
    466             break;
    467           }
    468           case kExternalTable: {
    469             WasmIndirectFunctionTable* table = nullptr;
    470             exp->index = consume_table_index(module, &table);
    471             if (table) table->exported = true;
    472             break;
    473           }
    474           case kExternalMemory: {
    475             uint32_t index = consume_u32v("memory index");
    476             if (index != 0) error("invalid memory index != 0");
    477             module->mem_export = true;
    478             break;
    479           }
    480           case kExternalGlobal: {
    481             WasmGlobal* global = nullptr;
    482             exp->index = consume_global_index(module, &global);
    483             if (global) {
    484               if (global->mutability) {
    485                 error("mutable globals cannot be exported");
    486               }
    487               global->exported = true;
    488             }
    489             break;
    490           }
    491           default:
    492             error(pos, pos, "invalid export kind 0x%02x", exp->kind);
    493             break;
    494         }
    495       }
    496       // Check for duplicate exports.
    497       if (ok() && module->export_table.size() > 1) {
    498         std::vector<WasmExport> sorted_exports(module->export_table);
    499         const byte* base = start_;
    500         auto cmp_less = [base](const WasmExport& a, const WasmExport& b) {
    501           // Return true if a < b.
    502           if (a.name_length != b.name_length) {
    503             return a.name_length < b.name_length;
    504           }
    505           return memcmp(base + a.name_offset, base + b.name_offset,
    506                         a.name_length) < 0;
    507         };
    508         std::stable_sort(sorted_exports.begin(), sorted_exports.end(),
    509                          cmp_less);
    510         auto it = sorted_exports.begin();
    511         WasmExport* last = &*it++;
    512         for (auto end = sorted_exports.end(); it != end; last = &*it++) {
    513           DCHECK(!cmp_less(*it, *last));  // Vector must be sorted.
    514           if (!cmp_less(*last, *it)) {
    515             const byte* pc = start_ + it->name_offset;
    516             error(pc, pc,
    517                   "Duplicate export name '%.*s' for functions %d and %d",
    518                   it->name_length, pc, last->index, it->index);
    519             break;
    520           }
    521         }
    522       }
    523       section_iter.advance();
    524     }
    525 
    526     // ===== Start section ===================================================
    527     if (section_iter.section_code() == kStartSectionCode) {
    528       WasmFunction* func;
    529       const byte* pos = pc_;
    530       module->start_function_index = consume_func_index(module, &func);
    531       if (func &&
    532           (func->sig->parameter_count() > 0 || func->sig->return_count() > 0)) {
    533         error(pos,
    534               "invalid start function: non-zero parameter or return count");
    535       }
    536       section_iter.advance();
    537     }
    538 
    539     // ===== Elements section ================================================
    540     if (section_iter.section_code() == kElementSectionCode) {
    541       uint32_t element_count = consume_u32v("element count");
    542       for (uint32_t i = 0; ok() && i < element_count; ++i) {
    543         const byte* pos = pc();
    544         uint32_t table_index = consume_u32v("table index");
    545         if (table_index != 0) {
    546           error(pos, pos, "illegal table index %u != 0", table_index);
    547         }
    548         WasmIndirectFunctionTable* table = nullptr;
    549         if (table_index >= module->function_tables.size()) {
    550           error(pos, pos, "out of bounds table index %u", table_index);
    551         } else {
    552           table = &module->function_tables[table_index];
    553         }
    554         WasmInitExpr offset = consume_init_expr(module, kAstI32);
    555         uint32_t num_elem = consume_u32v("number of elements");
    556         std::vector<uint32_t> vector;
    557         module->table_inits.push_back({table_index, offset, vector});
    558         WasmTableInit* init = &module->table_inits.back();
    559         init->entries.reserve(SafeReserve(num_elem));
    560         for (uint32_t j = 0; ok() && j < num_elem; j++) {
    561           WasmFunction* func = nullptr;
    562           uint32_t index = consume_func_index(module, &func);
    563           init->entries.push_back(index);
    564           if (table && index < module->functions.size()) {
    565             // Canonicalize signature indices during decoding.
    566             // TODO(titzer): suboptimal, redundant when verifying only.
    567             table->map.FindOrInsert(module->functions[index].sig);
    568           }
    569         }
    570       }
    571 
    572       section_iter.advance();
    573     }
    574 
    575     // ===== Code section ====================================================
    576     if (section_iter.section_code() == kCodeSectionCode) {
    577       const byte* pos = pc_;
    578       uint32_t functions_count = consume_u32v("functions count");
    579       if (functions_count != module->num_declared_functions) {
    580         error(pos, pos, "function body count %u mismatch (%u expected)",
    581               functions_count, module->num_declared_functions);
    582       }
    583       for (uint32_t i = 0; ok() && i < functions_count; ++i) {
    584         WasmFunction* function =
    585             &module->functions[i + module->num_imported_functions];
    586         uint32_t size = consume_u32v("body size");
    587         function->code_start_offset = pc_offset();
    588         function->code_end_offset = pc_offset() + size;
    589         if (verify_functions) {
    590           ModuleEnv module_env;
    591           module_env.module = module;
    592           module_env.origin = module->origin;
    593 
    594           VerifyFunctionBody(i + module->num_imported_functions, &module_env,
    595                              function);
    596         }
    597         consume_bytes(size, "function body");
    598       }
    599       section_iter.advance();
    600     }
    601 
    602     // ===== Data section ====================================================
    603     if (section_iter.section_code() == kDataSectionCode) {
    604       uint32_t data_segments_count = consume_u32v("data segments count");
    605       module->data_segments.reserve(SafeReserve(data_segments_count));
    606       for (uint32_t i = 0; ok() && i < data_segments_count; ++i) {
    607         if (!module->has_memory) {
    608           error("cannot load data without memory");
    609           break;
    610         }
    611         TRACE("DecodeDataSegment[%d] module+%d\n", i,
    612               static_cast<int>(pc_ - start_));
    613         module->data_segments.push_back({
    614             WasmInitExpr(),  // dest_addr
    615             0,               // source_offset
    616             0                // source_size
    617         });
    618         WasmDataSegment* segment = &module->data_segments.back();
    619         DecodeDataSegmentInModule(module, segment);
    620       }
    621       section_iter.advance();
    622     }
    623 
    624     // ===== Name section ====================================================
    625     if (section_iter.section_code() == kNameSectionCode) {
    626       uint32_t functions_count = consume_u32v("functions count");
    627 
    628       for (uint32_t i = 0; ok() && i < functions_count; ++i) {
    629         uint32_t function_name_length = 0;
    630         uint32_t name_offset = consume_string(&function_name_length, false);
    631         uint32_t func_index = i;
    632         if (func_index < module->functions.size()) {
    633           module->functions[func_index].name_offset = name_offset;
    634           module->functions[func_index].name_length = function_name_length;
    635         }
    636 
    637         uint32_t local_names_count = consume_u32v("local names count");
    638         for (uint32_t j = 0; ok() && j < local_names_count; j++) {
    639           skip_string();
    640         }
    641       }
    642       section_iter.advance();
    643     }
    644 
    645     // ===== Remaining sections ==============================================
    646     if (section_iter.more() && ok()) {
    647       error(pc(), pc(), "unexpected section: %s",
    648             SectionName(section_iter.section_code()));
    649     }
    650 
    651     if (ok()) {
    652       CalculateGlobalOffsets(module);
    653     }
    654     const WasmModule* finished_module = module;
    655     ModuleResult result = toResult(finished_module);
    656     if (verify_functions && result.ok()) {
    657       result.MoveFrom(result_);  // Copy error code and location.
    658     }
    659     if (FLAG_dump_wasm_module) DumpModule(module, result);
    660     return result;
    661   }
    662 
    663   uint32_t SafeReserve(uint32_t count) {
    664     // Avoid OOM by only reserving up to a certain size.
    665     const uint32_t kMaxReserve = 20000;
    666     return count < kMaxReserve ? count : kMaxReserve;
    667   }
    668 
    669   // Decodes a single anonymous function starting at {start_}.
    670   FunctionResult DecodeSingleFunction(ModuleEnv* module_env,
    671                                       WasmFunction* function) {
    672     pc_ = start_;
    673     function->sig = consume_sig();            // read signature
    674     function->name_offset = 0;                // ---- name
    675     function->name_length = 0;                // ---- name length
    676     function->code_start_offset = off(pc_);   // ---- code start
    677     function->code_end_offset = off(limit_);  // ---- code end
    678 
    679     if (ok()) VerifyFunctionBody(0, module_env, function);
    680 
    681     FunctionResult result;
    682     result.MoveFrom(result_);  // Copy error code and location.
    683     result.val = function;
    684     return result;
    685   }
    686 
    687   // Decodes a single function signature at {start}.
    688   FunctionSig* DecodeFunctionSignature(const byte* start) {
    689     pc_ = start;
    690     FunctionSig* result = consume_sig();
    691     return ok() ? result : nullptr;
    692   }
    693 
    694   WasmInitExpr DecodeInitExpr(const byte* start) {
    695     pc_ = start;
    696     return consume_init_expr(nullptr, kAstStmt);
    697   }
    698 
    699  private:
    700   Zone* module_zone;
    701   ModuleResult result_;
    702   ModuleOrigin origin_;
    703 
    704   uint32_t off(const byte* ptr) { return static_cast<uint32_t>(ptr - start_); }
    705 
    706   // Decodes a single global entry inside a module starting at {pc_}.
    707   void DecodeGlobalInModule(WasmModule* module, uint32_t index,
    708                             WasmGlobal* global) {
    709     global->type = consume_value_type();
    710     global->mutability = consume_u8("mutability") != 0;
    711     const byte* pos = pc();
    712     global->init = consume_init_expr(module, kAstStmt);
    713     switch (global->init.kind) {
    714       case WasmInitExpr::kGlobalIndex: {
    715         uint32_t other_index = global->init.val.global_index;
    716         if (other_index >= index) {
    717           error(pos, pos,
    718                 "invalid global index in init expression, "
    719                 "index %u, other_index %u",
    720                 index, other_index);
    721         } else if (module->globals[other_index].type != global->type) {
    722           error(pos, pos,
    723                 "type mismatch in global initialization "
    724                 "(from global #%u), expected %s, got %s",
    725                 other_index, WasmOpcodes::TypeName(global->type),
    726                 WasmOpcodes::TypeName(module->globals[other_index].type));
    727         }
    728         break;
    729       }
    730       default:
    731         if (global->type != TypeOf(module, global->init)) {
    732           error(pos, pos,
    733                 "type error in global initialization, expected %s, got %s",
    734                 WasmOpcodes::TypeName(global->type),
    735                 WasmOpcodes::TypeName(TypeOf(module, global->init)));
    736         }
    737     }
    738   }
    739 
    740   bool IsWithinLimit(uint32_t limit, uint32_t offset, uint32_t size) {
    741     if (offset > limit) return false;
    742     if ((offset + size) < offset) return false;  // overflow
    743     return (offset + size) <= limit;
    744   }
    745 
    746   // Decodes a single data segment entry inside a module starting at {pc_}.
    747   void DecodeDataSegmentInModule(WasmModule* module, WasmDataSegment* segment) {
    748     const byte* start = pc_;
    749     expect_u8("linear memory index", 0);
    750     segment->dest_addr = consume_init_expr(module, kAstI32);
    751     segment->source_size = consume_u32v("source size");
    752     segment->source_offset = static_cast<uint32_t>(pc_ - start_);
    753 
    754     // Validate the data is in the module.
    755     uint32_t module_limit = static_cast<uint32_t>(limit_ - start_);
    756     if (!IsWithinLimit(module_limit, segment->source_offset,
    757                        segment->source_size)) {
    758       error(start, "segment out of bounds of module");
    759     }
    760 
    761     consume_bytes(segment->source_size, "segment data");
    762   }
    763 
    764   // Calculate individual global offsets and total size of globals table.
    765   void CalculateGlobalOffsets(WasmModule* module) {
    766     uint32_t offset = 0;
    767     if (module->globals.size() == 0) {
    768       module->globals_size = 0;
    769       return;
    770     }
    771     for (WasmGlobal& global : module->globals) {
    772       byte size =
    773           WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(global.type));
    774       offset = (offset + size - 1) & ~(size - 1);  // align
    775       global.offset = offset;
    776       offset += size;
    777     }
    778     module->globals_size = offset;
    779   }
    780 
    781   // Verifies the body (code) of a given function.
    782   void VerifyFunctionBody(uint32_t func_num, ModuleEnv* menv,
    783                           WasmFunction* function) {
    784     if (FLAG_trace_wasm_decoder || FLAG_trace_wasm_decode_time) {
    785       OFStream os(stdout);
    786       os << "Verifying WASM function " << WasmFunctionName(function, menv)
    787          << std::endl;
    788     }
    789     FunctionBody body = {menv, function->sig, start_,
    790                          start_ + function->code_start_offset,
    791                          start_ + function->code_end_offset};
    792     DecodeResult result = VerifyWasmCode(module_zone->allocator(), body);
    793     if (result.failed()) {
    794       // Wrap the error message from the function decoder.
    795       std::ostringstream str;
    796       str << "in function " << WasmFunctionName(function, menv) << ": ";
    797       str << result;
    798       std::string strval = str.str();
    799       const char* raw = strval.c_str();
    800       size_t len = strlen(raw);
    801       char* buffer = new char[len];
    802       strncpy(buffer, raw, len);
    803       buffer[len - 1] = 0;
    804 
    805       // Copy error code and location.
    806       result_.MoveFrom(result);
    807       result_.error_msg.reset(buffer);
    808     }
    809   }
    810 
    811   // Reads a length-prefixed string, checking that it is within bounds. Returns
    812   // the offset of the string, and the length as an out parameter.
    813   uint32_t consume_string(uint32_t* length, bool validate_utf8) {
    814     *length = consume_u32v("string length");
    815     uint32_t offset = pc_offset();
    816     const byte* string_start = pc_;
    817     // Consume bytes before validation to guarantee that the string is not oob.
    818     if (*length > 0) consume_bytes(*length, "string");
    819     if (ok() && validate_utf8 &&
    820         !unibrow::Utf8::Validate(string_start, *length)) {
    821       error(string_start, "no valid UTF-8 string");
    822     }
    823     return offset;
    824   }
    825 
    826   // Skips over a length-prefixed string, but checks that it is within bounds.
    827   void skip_string() {
    828     uint32_t length = consume_u32v("string length");
    829     consume_bytes(length, "string");
    830   }
    831 
    832   uint32_t consume_sig_index(WasmModule* module, FunctionSig** sig) {
    833     const byte* pos = pc_;
    834     uint32_t sig_index = consume_u32v("signature index");
    835     if (sig_index >= module->signatures.size()) {
    836       error(pos, pos, "signature index %u out of bounds (%d signatures)",
    837             sig_index, static_cast<int>(module->signatures.size()));
    838       *sig = nullptr;
    839       return 0;
    840     }
    841     *sig = module->signatures[sig_index];
    842     return sig_index;
    843   }
    844 
    845   uint32_t consume_func_index(WasmModule* module, WasmFunction** func) {
    846     return consume_index("function index", module->functions, func);
    847   }
    848 
    849   uint32_t consume_global_index(WasmModule* module, WasmGlobal** global) {
    850     return consume_index("global index", module->globals, global);
    851   }
    852 
    853   uint32_t consume_table_index(WasmModule* module,
    854                                WasmIndirectFunctionTable** table) {
    855     return consume_index("table index", module->function_tables, table);
    856   }
    857 
    858   template <typename T>
    859   uint32_t consume_index(const char* name, std::vector<T>& vector, T** ptr) {
    860     const byte* pos = pc_;
    861     uint32_t index = consume_u32v(name);
    862     if (index >= vector.size()) {
    863       error(pos, pos, "%s %u out of bounds (%d entries)", name, index,
    864             static_cast<int>(vector.size()));
    865       *ptr = nullptr;
    866       return 0;
    867     }
    868     *ptr = &vector[index];
    869     return index;
    870   }
    871 
    872   void consume_resizable_limits(const char* name, const char* units,
    873                                 uint32_t max_initial, uint32_t* initial,
    874                                 bool* has_max, uint32_t max_maximum,
    875                                 uint32_t* maximum) {
    876     uint32_t flags = consume_u32v("resizable limits flags");
    877     const byte* pos = pc();
    878     *initial = consume_u32v("initial size");
    879     *has_max = false;
    880     if (*initial > max_initial) {
    881       error(pos, pos,
    882             "initial %s size (%u %s) is larger than implementation limit (%u)",
    883             name, *initial, units, max_initial);
    884     }
    885     if (flags & 1) {
    886       *has_max = true;
    887       pos = pc();
    888       *maximum = consume_u32v("maximum size");
    889       if (*maximum > max_maximum) {
    890         error(
    891             pos, pos,
    892             "maximum %s size (%u %s) is larger than implementation limit (%u)",
    893             name, *maximum, units, max_maximum);
    894       }
    895       if (*maximum < *initial) {
    896         error(pos, pos, "maximum %s size (%u %s) is less than initial (%u %s)",
    897               name, *maximum, units, *initial, units);
    898       }
    899     } else {
    900       *has_max = false;
    901       *maximum = max_initial;
    902     }
    903   }
    904 
    905   bool expect_u8(const char* name, uint8_t expected) {
    906     const byte* pos = pc();
    907     uint8_t value = consume_u8(name);
    908     if (value != expected) {
    909       error(pos, pos, "expected %s 0x%02x, got 0x%02x", name, expected, value);
    910       return false;
    911     }
    912     return true;
    913   }
    914 
    915   WasmInitExpr consume_init_expr(WasmModule* module, LocalType expected) {
    916     const byte* pos = pc();
    917     uint8_t opcode = consume_u8("opcode");
    918     WasmInitExpr expr;
    919     unsigned len = 0;
    920     switch (opcode) {
    921       case kExprGetGlobal: {
    922         GlobalIndexOperand operand(this, pc() - 1);
    923         if (module->globals.size() <= operand.index) {
    924           error("global index is out of bounds");
    925           expr.kind = WasmInitExpr::kNone;
    926           expr.val.i32_const = 0;
    927           break;
    928         }
    929         WasmGlobal* global = &module->globals[operand.index];
    930         if (global->mutability || !global->imported) {
    931           error(
    932               "only immutable imported globals can be used in initializer "
    933               "expressions");
    934           expr.kind = WasmInitExpr::kNone;
    935           expr.val.i32_const = 0;
    936           break;
    937         }
    938         expr.kind = WasmInitExpr::kGlobalIndex;
    939         expr.val.global_index = operand.index;
    940         len = operand.length;
    941         break;
    942       }
    943       case kExprI32Const: {
    944         ImmI32Operand operand(this, pc() - 1);
    945         expr.kind = WasmInitExpr::kI32Const;
    946         expr.val.i32_const = operand.value;
    947         len = operand.length;
    948         break;
    949       }
    950       case kExprF32Const: {
    951         ImmF32Operand operand(this, pc() - 1);
    952         expr.kind = WasmInitExpr::kF32Const;
    953         expr.val.f32_const = operand.value;
    954         len = operand.length;
    955         break;
    956       }
    957       case kExprI64Const: {
    958         ImmI64Operand operand(this, pc() - 1);
    959         expr.kind = WasmInitExpr::kI64Const;
    960         expr.val.i64_const = operand.value;
    961         len = operand.length;
    962         break;
    963       }
    964       case kExprF64Const: {
    965         ImmF64Operand operand(this, pc() - 1);
    966         expr.kind = WasmInitExpr::kF64Const;
    967         expr.val.f64_const = operand.value;
    968         len = operand.length;
    969         break;
    970       }
    971       default: {
    972         error("invalid opcode in initialization expression");
    973         expr.kind = WasmInitExpr::kNone;
    974         expr.val.i32_const = 0;
    975       }
    976     }
    977     consume_bytes(len, "init code");
    978     if (!expect_u8("end opcode", kExprEnd)) {
    979       expr.kind = WasmInitExpr::kNone;
    980     }
    981     if (expected != kAstStmt && TypeOf(module, expr) != kAstI32) {
    982       error(pos, pos, "type error in init expression, expected %s, got %s",
    983             WasmOpcodes::TypeName(expected),
    984             WasmOpcodes::TypeName(TypeOf(module, expr)));
    985     }
    986     return expr;
    987   }
    988 
    989   // Reads a single 8-bit integer, interpreting it as a local type.
    990   LocalType consume_value_type() {
    991     byte val = consume_u8("value type");
    992     LocalTypeCode t = static_cast<LocalTypeCode>(val);
    993     switch (t) {
    994       case kLocalI32:
    995         return kAstI32;
    996       case kLocalI64:
    997         return kAstI64;
    998       case kLocalF32:
    999         return kAstF32;
   1000       case kLocalF64:
   1001         return kAstF64;
   1002       case kLocalS128:
   1003         if (origin_ != kAsmJsOrigin && FLAG_wasm_simd_prototype) {
   1004           return kAstS128;
   1005         } else {
   1006           error(pc_ - 1, "invalid local type");
   1007           return kAstStmt;
   1008         }
   1009       default:
   1010         error(pc_ - 1, "invalid local type");
   1011         return kAstStmt;
   1012     }
   1013   }
   1014 
   1015   // Parses a type entry, which is currently limited to functions only.
   1016   FunctionSig* consume_sig() {
   1017     if (!expect_u8("type form", kWasmFunctionTypeForm)) return nullptr;
   1018     // parse parameter types
   1019     uint32_t param_count = consume_u32v("param count");
   1020     std::vector<LocalType> params;
   1021     for (uint32_t i = 0; ok() && i < param_count; ++i) {
   1022       LocalType param = consume_value_type();
   1023       params.push_back(param);
   1024     }
   1025 
   1026     // parse return types
   1027     const byte* pt = pc_;
   1028     uint32_t return_count = consume_u32v("return count");
   1029     if (return_count > kMaxReturnCount) {
   1030       error(pt, pt, "return count of %u exceeds maximum of %u", return_count,
   1031             kMaxReturnCount);
   1032       return nullptr;
   1033     }
   1034     std::vector<LocalType> returns;
   1035     for (uint32_t i = 0; ok() && i < return_count; ++i) {
   1036       LocalType ret = consume_value_type();
   1037       returns.push_back(ret);
   1038     }
   1039 
   1040     if (failed()) {
   1041       // Decoding failed, return void -> void
   1042       return new (module_zone) FunctionSig(0, 0, nullptr);
   1043     }
   1044 
   1045     // FunctionSig stores the return types first.
   1046     LocalType* buffer =
   1047         module_zone->NewArray<LocalType>(param_count + return_count);
   1048     uint32_t b = 0;
   1049     for (uint32_t i = 0; i < return_count; ++i) buffer[b++] = returns[i];
   1050     for (uint32_t i = 0; i < param_count; ++i) buffer[b++] = params[i];
   1051 
   1052     return new (module_zone) FunctionSig(return_count, param_count, buffer);
   1053   }
   1054 };
   1055 
   1056 // Helpers for nice error messages.
   1057 class ModuleError : public ModuleResult {
   1058  public:
   1059   explicit ModuleError(const char* msg) {
   1060     error_code = kError;
   1061     size_t len = strlen(msg) + 1;
   1062     char* result = new char[len];
   1063     strncpy(result, msg, len);
   1064     result[len - 1] = 0;
   1065     error_msg.reset(result);
   1066   }
   1067 };
   1068 
   1069 // Helpers for nice error messages.
   1070 class FunctionError : public FunctionResult {
   1071  public:
   1072   explicit FunctionError(const char* msg) {
   1073     error_code = kError;
   1074     size_t len = strlen(msg) + 1;
   1075     char* result = new char[len];
   1076     strncpy(result, msg, len);
   1077     result[len - 1] = 0;
   1078     error_msg.reset(result);
   1079   }
   1080 };
   1081 
   1082 // Find section with given section code. Return Vector of the payload, or null
   1083 // Vector if section is not found or module bytes are invalid.
   1084 Vector<const byte> FindSection(const byte* module_start, const byte* module_end,
   1085                                WasmSectionCode code) {
   1086   Decoder decoder(module_start, module_end);
   1087 
   1088   uint32_t magic_word = decoder.consume_u32("wasm magic");
   1089   if (magic_word != kWasmMagic) decoder.error("wrong magic word");
   1090 
   1091   uint32_t magic_version = decoder.consume_u32("wasm version");
   1092   if (magic_version != kWasmVersion) decoder.error("wrong wasm version");
   1093 
   1094   WasmSectionIterator section_iter(decoder);
   1095   while (section_iter.more()) {
   1096     if (section_iter.section_code() == code) {
   1097       return Vector<const uint8_t>(section_iter.payload_start(),
   1098                                    section_iter.payload_length());
   1099     }
   1100     decoder.consume_bytes(section_iter.payload_length(), "section payload");
   1101     section_iter.advance();
   1102   }
   1103 
   1104   return Vector<const uint8_t>();
   1105 }
   1106 
   1107 }  // namespace
   1108 
   1109 ModuleResult DecodeWasmModule(Isolate* isolate, const byte* module_start,
   1110                               const byte* module_end, bool verify_functions,
   1111                               ModuleOrigin origin) {
   1112   HistogramTimerScope wasm_decode_module_time_scope(
   1113       isolate->counters()->wasm_decode_module_time());
   1114   size_t size = module_end - module_start;
   1115   if (module_start > module_end) return ModuleError("start > end");
   1116   if (size >= kMaxModuleSize) return ModuleError("size > maximum module size");
   1117   // TODO(bradnelson): Improve histogram handling of size_t.
   1118   isolate->counters()->wasm_module_size_bytes()->AddSample(
   1119       static_cast<int>(size));
   1120   // Signatures are stored in zone memory, which have the same lifetime
   1121   // as the {module}.
   1122   Zone* zone = new Zone(isolate->allocator(), ZONE_NAME);
   1123   WasmModule* module = new WasmModule(zone, module_start);
   1124   ModuleDecoder decoder(zone, module_start, module_end, origin);
   1125   ModuleResult result = decoder.DecodeModule(module, verify_functions);
   1126   // TODO(bradnelson): Improve histogram handling of size_t.
   1127   // TODO(titzer): this isn't accurate, since it doesn't count the data
   1128   // allocated on the C++ heap.
   1129   // https://bugs.chromium.org/p/chromium/issues/detail?id=657320
   1130   isolate->counters()->wasm_decode_module_peak_memory_bytes()->AddSample(
   1131       static_cast<int>(zone->allocation_size()));
   1132   return result;
   1133 }
   1134 
   1135 FunctionSig* DecodeWasmSignatureForTesting(Zone* zone, const byte* start,
   1136                                            const byte* end) {
   1137   ModuleDecoder decoder(zone, start, end, kWasmOrigin);
   1138   return decoder.DecodeFunctionSignature(start);
   1139 }
   1140 
   1141 WasmInitExpr DecodeWasmInitExprForTesting(const byte* start, const byte* end) {
   1142   AccountingAllocator allocator;
   1143   Zone zone(&allocator, ZONE_NAME);
   1144   ModuleDecoder decoder(&zone, start, end, kWasmOrigin);
   1145   return decoder.DecodeInitExpr(start);
   1146 }
   1147 
   1148 FunctionResult DecodeWasmFunction(Isolate* isolate, Zone* zone,
   1149                                   ModuleEnv* module_env,
   1150                                   const byte* function_start,
   1151                                   const byte* function_end) {
   1152   HistogramTimerScope wasm_decode_function_time_scope(
   1153       isolate->counters()->wasm_decode_function_time());
   1154   size_t size = function_end - function_start;
   1155   if (function_start > function_end) return FunctionError("start > end");
   1156   if (size > kMaxFunctionSize)
   1157     return FunctionError("size > maximum function size");
   1158   isolate->counters()->wasm_function_size_bytes()->AddSample(
   1159       static_cast<int>(size));
   1160   WasmFunction* function = new WasmFunction();
   1161   ModuleDecoder decoder(zone, function_start, function_end, kWasmOrigin);
   1162   return decoder.DecodeSingleFunction(module_env, function);
   1163 }
   1164 
   1165 FunctionOffsetsResult DecodeWasmFunctionOffsets(const byte* module_start,
   1166                                                 const byte* module_end) {
   1167   // Find and decode the code section.
   1168   Vector<const byte> code_section =
   1169       FindSection(module_start, module_end, kCodeSectionCode);
   1170   Decoder decoder(code_section.start(), code_section.end());
   1171   FunctionOffsets table;
   1172   if (!code_section.start()) {
   1173     decoder.error("no code section");
   1174     return decoder.toResult(std::move(table));
   1175   }
   1176 
   1177   uint32_t functions_count = decoder.consume_u32v("functions count");
   1178   // Reserve space for the entries, taking care of invalid input.
   1179   if (functions_count < static_cast<unsigned>(code_section.length()) / 2) {
   1180     table.reserve(functions_count);
   1181   }
   1182 
   1183   int section_offset = static_cast<int>(code_section.start() - module_start);
   1184   DCHECK_LE(0, section_offset);
   1185   for (uint32_t i = 0; i < functions_count && decoder.ok(); ++i) {
   1186     uint32_t size = decoder.consume_u32v("body size");
   1187     int offset = static_cast<int>(section_offset + decoder.pc_offset());
   1188     table.push_back(std::make_pair(offset, static_cast<int>(size)));
   1189     DCHECK(table.back().first >= 0 && table.back().second >= 0);
   1190     decoder.consume_bytes(size);
   1191   }
   1192   if (decoder.more()) decoder.error("unexpected additional bytes");
   1193 
   1194   return decoder.toResult(std::move(table));
   1195 }
   1196 
   1197 AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* tables_start,
   1198                                       const byte* tables_end) {
   1199   AsmJsOffsets table;
   1200 
   1201   Decoder decoder(tables_start, tables_end);
   1202   uint32_t functions_count = decoder.consume_u32v("functions count");
   1203   // Reserve space for the entries, taking care of invalid input.
   1204   if (functions_count < static_cast<unsigned>(tables_end - tables_start)) {
   1205     table.reserve(functions_count);
   1206   }
   1207 
   1208   for (uint32_t i = 0; i < functions_count && decoder.ok(); ++i) {
   1209     uint32_t size = decoder.consume_u32v("table size");
   1210     if (size == 0) {
   1211       table.push_back(std::vector<std::pair<int, int>>());
   1212       continue;
   1213     }
   1214     if (!decoder.checkAvailable(size)) {
   1215       decoder.error("illegal asm function offset table size");
   1216     }
   1217     const byte* table_end = decoder.pc() + size;
   1218     uint32_t locals_size = decoder.consume_u32("locals size");
   1219     int last_byte_offset = locals_size;
   1220     int last_asm_position = 0;
   1221     std::vector<std::pair<int, int>> func_asm_offsets;
   1222     func_asm_offsets.reserve(size / 4);  // conservative estimation
   1223     while (decoder.ok() && decoder.pc() < table_end) {
   1224       last_byte_offset += decoder.consume_u32v("byte offset delta");
   1225       last_asm_position += decoder.consume_i32v("asm position delta");
   1226       func_asm_offsets.push_back({last_byte_offset, last_asm_position});
   1227     }
   1228     if (decoder.pc() != table_end) {
   1229       decoder.error("broken asm offset table");
   1230     }
   1231     table.push_back(std::move(func_asm_offsets));
   1232   }
   1233   if (decoder.more()) decoder.error("unexpected additional bytes");
   1234 
   1235   return decoder.toResult(std::move(table));
   1236 }
   1237 
   1238 }  // namespace wasm
   1239 }  // namespace internal
   1240 }  // namespace v8
   1241