Upgrade V8 to 5.1.281.57  DO NOT MERGE

FPIIM-449

Change-Id: Id981b686b4d587ac31697662eb98bb34be42ad90
(cherry picked from commit 3b9bc31999c9787eb726ecdbfd5796bfdec32a18)
diff --git a/src/wasm/module-decoder.cc b/src/wasm/module-decoder.cc
index 62b000d..3e85a1b 100644
--- a/src/wasm/module-decoder.cc
+++ b/src/wasm/module-decoder.cc
@@ -2,12 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "src/wasm/module-decoder.h"
+
+#include "src/base/functional.h"
+#include "src/base/platform/platform.h"
 #include "src/macro-assembler.h"
 #include "src/objects.h"
 #include "src/v8.h"
 
 #include "src/wasm/decoder.h"
-#include "src/wasm/module-decoder.h"
 
 namespace v8 {
 namespace internal {
@@ -27,8 +30,8 @@
 class ModuleDecoder : public Decoder {
  public:
   ModuleDecoder(Zone* zone, const byte* module_start, const byte* module_end,
-                bool asm_js)
-      : Decoder(module_start, module_end), module_zone(zone), asm_js_(asm_js) {
+                ModuleOrigin origin)
+      : Decoder(module_start, module_end), module_zone(zone), origin_(origin) {
     result_.start = start_;
     if (limit_ < start_) {
       error(start_, "end is less than start");
@@ -40,86 +43,196 @@
     pc_ = limit_;  // On error, terminate section decoding loop.
   }
 
+  static void DumpModule(WasmModule* module, ModuleResult result) {
+    std::string path;
+    if (FLAG_dump_wasm_module_path) {
+      path = FLAG_dump_wasm_module_path;
+      if (path.size() &&
+          !base::OS::isDirectorySeparator(path[path.size() - 1])) {
+        path += base::OS::DirectorySeparator();
+      }
+    }
+    // File are named `HASH.{ok,failed}.wasm`.
+    size_t hash = base::hash_range(module->module_start, module->module_end);
+    char buf[32] = {'\0'};
+#if V8_OS_WIN && _MSC_VER < 1900
+#define snprintf sprintf_s
+#endif
+    snprintf(buf, sizeof(buf) - 1, "%016zx.%s.wasm", hash,
+             result.ok() ? "ok" : "failed");
+    std::string name(buf);
+    if (FILE* wasm_file = base::OS::FOpen((path + name).c_str(), "wb")) {
+      fwrite(module->module_start, module->module_end - module->module_start, 1,
+             wasm_file);
+      fclose(wasm_file);
+    }
+  }
+
   // Decodes an entire module.
   ModuleResult DecodeModule(WasmModule* module, bool verify_functions = true) {
     pc_ = start_;
     module->module_start = start_;
     module->module_end = limit_;
-    module->min_mem_size_log2 = 0;
-    module->max_mem_size_log2 = 0;
+    module->min_mem_pages = 0;
+    module->max_mem_pages = 0;
     module->mem_export = false;
     module->mem_external = false;
-    module->globals = new std::vector<WasmGlobal>();
-    module->signatures = new std::vector<FunctionSig*>();
-    module->functions = new std::vector<WasmFunction>();
-    module->data_segments = new std::vector<WasmDataSegment>();
-    module->function_table = new std::vector<uint16_t>();
-    module->import_table = new std::vector<WasmImport>();
+    module->origin = origin_;
 
-    bool sections[kMaxModuleSectionCode];
-    memset(sections, 0, sizeof(sections));
+    bool sections[(size_t)WasmSection::Code::Max] = {false};
+
+    const byte* pos = pc_;
+    uint32_t magic_word = consume_u32("wasm magic");
+#define BYTES(x) (x & 0xff), (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff
+    if (magic_word != kWasmMagic) {
+      error(pos, pos,
+            "expected magic word %02x %02x %02x %02x, "
+            "found %02x %02x %02x %02x",
+            BYTES(kWasmMagic), BYTES(magic_word));
+      goto done;
+    }
+
+    pos = pc_;
+    {
+      uint32_t magic_version = consume_u32("wasm version");
+      if (magic_version != kWasmVersion) {
+        error(pos, pos,
+              "expected version %02x %02x %02x %02x, "
+              "found %02x %02x %02x %02x",
+              BYTES(kWasmVersion), BYTES(magic_version));
+        goto done;
+      }
+    }
 
     // Decode the module sections.
     while (pc_ < limit_) {
       TRACE("DecodeSection\n");
-      WasmSectionDeclCode section =
-          static_cast<WasmSectionDeclCode>(consume_u8("section"));
-      // Each section should appear at most once.
-      if (section < kMaxModuleSectionCode) {
-        CheckForPreviousSection(sections, section, false);
-        sections[section] = true;
+      pos = pc_;
+
+      int length;
+      uint32_t section_length = consume_u32v(&length, "section size");
+
+      int section_string_leb_length = 0;
+      uint32_t section_string_length = 0;
+      WasmSection::Code section = consume_section_name(
+          &section_string_leb_length, &section_string_length);
+      uint32_t string_and_leb_length =
+          section_string_leb_length + section_string_length;
+      if (string_and_leb_length > section_length) {
+        error(pos, pos,
+              "section string of size %u longer than total section bytes %u",
+              string_and_leb_length, section_length);
+        break;
       }
 
+      if (section == WasmSection::Code::Max) {
+        // Skip unknown section.
+        uint32_t skip = section_length - string_and_leb_length;
+        TRACE("skipping %u bytes from unknown section\n", skip);
+        consume_bytes(skip);
+        continue;
+      }
+
+      // Each section should appear at most once.
+      CheckForPreviousSection(sections, section, false);
+      sections[(size_t)section] = true;
+
       switch (section) {
-        case kDeclEnd:
+        case WasmSection::Code::End:
           // Terminate section decoding.
           limit_ = pc_;
           break;
-        case kDeclMemory:
-          module->min_mem_size_log2 = consume_u8("min memory");
-          module->max_mem_size_log2 = consume_u8("max memory");
+        case WasmSection::Code::Memory:
+          int length;
+          module->min_mem_pages = consume_u32v(&length, "min memory");
+          module->max_mem_pages = consume_u32v(&length, "max memory");
           module->mem_export = consume_u8("export memory") != 0;
           break;
-        case kDeclSignatures: {
+        case WasmSection::Code::Signatures: {
           int length;
           uint32_t signatures_count = consume_u32v(&length, "signatures count");
-          module->signatures->reserve(SafeReserve(signatures_count));
+          module->signatures.reserve(SafeReserve(signatures_count));
           // Decode signatures.
           for (uint32_t i = 0; i < signatures_count; i++) {
             if (failed()) break;
             TRACE("DecodeSignature[%d] module+%d\n", i,
                   static_cast<int>(pc_ - start_));
             FunctionSig* s = consume_sig();  // read function sig.
-            module->signatures->push_back(s);
+            module->signatures.push_back(s);
           }
           break;
         }
-        case kDeclFunctions: {
+        case WasmSection::Code::FunctionSignatures: {
           // Functions require a signature table first.
-          CheckForPreviousSection(sections, kDeclSignatures, true);
+          CheckForPreviousSection(sections, WasmSection::Code::Signatures,
+                                  true);
           int length;
           uint32_t functions_count = consume_u32v(&length, "functions count");
-          module->functions->reserve(SafeReserve(functions_count));
+          module->functions.reserve(SafeReserve(functions_count));
+          for (uint32_t i = 0; i < functions_count; i++) {
+            module->functions.push_back(
+                {nullptr, i, 0, 0, 0, 0, 0, 0, false, false});
+            WasmFunction* function = &module->functions.back();
+            function->sig_index = consume_sig_index(module, &function->sig);
+          }
+          break;
+        }
+        case WasmSection::Code::FunctionBodies: {
+          // Function bodies should follow signatures.
+          CheckForPreviousSection(sections,
+                                  WasmSection::Code::FunctionSignatures, true);
+          int length;
+          const byte* pos = pc_;
+          uint32_t functions_count = consume_u32v(&length, "functions count");
+          if (functions_count != module->functions.size()) {
+            error(pos, pos, "function body count %u mismatch (%u expected)",
+                  functions_count,
+                  static_cast<uint32_t>(module->functions.size()));
+            break;
+          }
+          for (uint32_t i = 0; i < functions_count; i++) {
+            WasmFunction* function = &module->functions[i];
+            int length;
+            uint32_t size = consume_u32v(&length, "body size");
+            function->code_start_offset = pc_offset();
+            function->code_end_offset = pc_offset() + size;
+
+            TRACE("  +%d  %-20s: (%d bytes)\n", pc_offset(), "function body",
+                  size);
+            pc_ += size;
+            if (pc_ > limit_) {
+              error(pc_, "function body extends beyond end of file");
+            }
+          }
+          break;
+        }
+        case WasmSection::Code::Functions: {
+          // Functions require a signature table first.
+          CheckForPreviousSection(sections, WasmSection::Code::Signatures,
+                                  true);
+          int length;
+          uint32_t functions_count = consume_u32v(&length, "functions count");
+          module->functions.reserve(SafeReserve(functions_count));
           // Set up module environment for verification.
           ModuleEnv menv;
           menv.module = module;
           menv.instance = nullptr;
-          menv.asm_js = asm_js_;
+          menv.origin = origin_;
           // Decode functions.
           for (uint32_t i = 0; i < functions_count; i++) {
             if (failed()) break;
             TRACE("DecodeFunction[%d] module+%d\n", i,
                   static_cast<int>(pc_ - start_));
 
-            module->functions->push_back(
+            module->functions.push_back(
                 {nullptr, i, 0, 0, 0, 0, 0, 0, false, false});
-            WasmFunction* function = &module->functions->back();
+            WasmFunction* function = &module->functions.back();
             DecodeFunctionInModule(module, function, false);
           }
           if (ok() && verify_functions) {
             for (uint32_t i = 0; i < functions_count; i++) {
               if (failed()) break;
-              WasmFunction* function = &module->functions->at(i);
+              WasmFunction* function = &module->functions[i];
               if (!function->external) {
                 VerifyFunctionBody(i, &menv, function);
                 if (result_.failed())
@@ -129,132 +242,166 @@
           }
           break;
         }
-        case kDeclGlobals: {
+        case WasmSection::Code::Names: {
+          // Names correspond to functions.
+          CheckForPreviousSection(sections,
+                                  WasmSection::Code::FunctionSignatures, true);
+          int length;
+          const byte* pos = pc_;
+          uint32_t functions_count = consume_u32v(&length, "functions count");
+          if (functions_count != module->functions.size()) {
+            error(pos, pos, "function name count %u mismatch (%u expected)",
+                  functions_count,
+                  static_cast<uint32_t>(module->functions.size()));
+            break;
+          }
+
+          for (uint32_t i = 0; i < functions_count; i++) {
+            WasmFunction* function = &module->functions[i];
+            function->name_offset =
+                consume_string(&function->name_length, "function name");
+
+            uint32_t local_names_count =
+                consume_u32v(&length, "local names count");
+            for (uint32_t j = 0; j < local_names_count; j++) {
+              uint32_t unused = 0;
+              uint32_t offset = consume_string(&unused, "local name");
+              USE(unused);
+              USE(offset);
+            }
+          }
+          break;
+        }
+        case WasmSection::Code::Globals: {
           int length;
           uint32_t globals_count = consume_u32v(&length, "globals count");
-          module->globals->reserve(SafeReserve(globals_count));
+          module->globals.reserve(SafeReserve(globals_count));
           // Decode globals.
           for (uint32_t i = 0; i < globals_count; i++) {
             if (failed()) break;
             TRACE("DecodeGlobal[%d] module+%d\n", i,
                   static_cast<int>(pc_ - start_));
-            module->globals->push_back({0, MachineType::Int32(), 0, false});
-            WasmGlobal* global = &module->globals->back();
+            module->globals.push_back({0, 0, MachineType::Int32(), 0, false});
+            WasmGlobal* global = &module->globals.back();
             DecodeGlobalInModule(global);
           }
           break;
         }
-        case kDeclDataSegments: {
+        case WasmSection::Code::DataSegments: {
           int length;
           uint32_t data_segments_count =
               consume_u32v(&length, "data segments count");
-          module->data_segments->reserve(SafeReserve(data_segments_count));
+          module->data_segments.reserve(SafeReserve(data_segments_count));
           // Decode data segments.
           for (uint32_t i = 0; i < data_segments_count; i++) {
             if (failed()) break;
             TRACE("DecodeDataSegment[%d] module+%d\n", i,
                   static_cast<int>(pc_ - start_));
-            module->data_segments->push_back({0, 0, 0});
-            WasmDataSegment* segment = &module->data_segments->back();
+            module->data_segments.push_back({0, 0, 0});
+            WasmDataSegment* segment = &module->data_segments.back();
             DecodeDataSegmentInModule(module, segment);
           }
           break;
         }
-        case kDeclFunctionTable: {
+        case WasmSection::Code::FunctionTable: {
           // An indirect function table requires functions first.
-          CheckForPreviousSection(sections, kDeclFunctions, true);
+          CheckForFunctions(module, section);
           int length;
           uint32_t function_table_count =
               consume_u32v(&length, "function table count");
-          module->function_table->reserve(SafeReserve(function_table_count));
+          module->function_table.reserve(SafeReserve(function_table_count));
           // Decode function table.
           for (uint32_t i = 0; i < function_table_count; i++) {
             if (failed()) break;
             TRACE("DecodeFunctionTable[%d] module+%d\n", i,
                   static_cast<int>(pc_ - start_));
-            uint16_t index = consume_u16();
-            if (index >= module->functions->size()) {
+            uint16_t index = consume_u32v(&length);
+            if (index >= module->functions.size()) {
               error(pc_ - 2, "invalid function index");
               break;
             }
-            module->function_table->push_back(index);
+            module->function_table.push_back(index);
           }
           break;
         }
-        case kDeclStartFunction: {
+        case WasmSection::Code::StartFunction: {
           // Declares a start function for a module.
-          CheckForPreviousSection(sections, kDeclFunctions, true);
+          CheckForFunctions(module, section);
           if (module->start_function_index >= 0) {
             error("start function already declared");
             break;
           }
-          int length;
-          const byte* before = pc_;
-          uint32_t index = consume_u32v(&length, "start function index");
-          if (index >= module->functions->size()) {
-            error(before, "invalid start function index");
-            break;
-          }
-          module->start_function_index = static_cast<int>(index);
-          FunctionSig* sig =
-              module->signatures->at(module->functions->at(index).sig_index);
-          if (sig->parameter_count() > 0) {
-            error(before, "invalid start function: non-zero parameter count");
+          WasmFunction* func;
+          const byte* pos = pc_;
+          module->start_function_index = consume_func_index(module, &func);
+          if (func && func->sig->parameter_count() > 0) {
+            error(pos, "invalid start function: non-zero parameter count");
             break;
           }
           break;
         }
-        case kDeclImportTable: {
+        case WasmSection::Code::ImportTable: {
           // Declares an import table.
-          CheckForPreviousSection(sections, kDeclSignatures, true);
+          CheckForPreviousSection(sections, WasmSection::Code::Signatures,
+                                  true);
           int length;
           uint32_t import_table_count =
               consume_u32v(&length, "import table count");
-          module->import_table->reserve(SafeReserve(import_table_count));
+          module->import_table.reserve(SafeReserve(import_table_count));
           // Decode import table.
           for (uint32_t i = 0; i < import_table_count; i++) {
             if (failed()) break;
             TRACE("DecodeImportTable[%d] module+%d\n", i,
                   static_cast<int>(pc_ - start_));
 
-            module->import_table->push_back({nullptr, 0, 0});
-            WasmImport* import = &module->import_table->back();
+            module->import_table.push_back({nullptr, 0, 0});
+            WasmImport* import = &module->import_table.back();
 
-            const byte* sigpos = pc_;
-            import->sig_index = consume_u16("signature index");
-
-            if (import->sig_index >= module->signatures->size()) {
-              error(sigpos, "invalid signature index");
-            } else {
-              import->sig = module->signatures->at(import->sig_index);
+            import->sig_index = consume_sig_index(module, &import->sig);
+            const byte* pos = pc_;
+            import->module_name_offset = consume_string(
+                &import->module_name_length, "import module name");
+            if (import->module_name_length == 0) {
+              error(pos, "import module name cannot be NULL");
             }
-            import->module_name_offset = consume_string("import module name");
-            import->function_name_offset =
-                consume_string("import function name");
+            import->function_name_offset = consume_string(
+                &import->function_name_length, "import function name");
           }
           break;
         }
-        case kDeclWLL: {
-          // Reserved for experimentation by the Web Low-level Language project
-          // which is augmenting the binary encoding with source code meta
-          // information. This section does not affect the semantics of the code
-          // and can be ignored by the runtime. https://github.com/JSStats/wll
-          int length = 0;
-          uint32_t section_size = consume_u32v(&length, "section size");
-          if (pc_ + section_size > limit_ || pc_ + section_size < pc_) {
-            error(pc_ - length, "invalid section size");
-            break;
+        case WasmSection::Code::ExportTable: {
+          // Declares an export table.
+          CheckForFunctions(module, section);
+          int length;
+          uint32_t export_table_count =
+              consume_u32v(&length, "export table count");
+          module->export_table.reserve(SafeReserve(export_table_count));
+          // Decode export table.
+          for (uint32_t i = 0; i < export_table_count; i++) {
+            if (failed()) break;
+            TRACE("DecodeExportTable[%d] module+%d\n", i,
+                  static_cast<int>(pc_ - start_));
+
+            module->export_table.push_back({0, 0});
+            WasmExport* exp = &module->export_table.back();
+
+            WasmFunction* func;
+            exp->func_index = consume_func_index(module, &func);
+            exp->name_offset = consume_string(&exp->name_length, "export name");
           }
-          pc_ += section_size;
           break;
         }
-        default:
-          error(pc_ - 1, nullptr, "unrecognized section 0x%02x", section);
-          break;
+        case WasmSection::Code::Max:
+          UNREACHABLE();  // Already skipped unknown sections.
       }
     }
 
-    return toResult(module);
+  done:
+    ModuleResult result = toResult(module);
+    if (FLAG_dump_wasm_module) {
+      DumpModule(module, result);
+    }
+    return result;
   }
 
   uint32_t SafeReserve(uint32_t count) {
@@ -263,38 +410,23 @@
     return count < kMaxReserve ? count : kMaxReserve;
   }
 
-  void CheckForPreviousSection(bool* sections, WasmSectionDeclCode section,
-                               bool present) {
-    if (section >= kMaxModuleSectionCode) return;
-    if (sections[section] == present) return;
-    const char* name = "";
-    switch (section) {
-      case kDeclMemory:
-        name = "memory";
-        break;
-      case kDeclSignatures:
-        name = "signatures";
-        break;
-      case kDeclFunctions:
-        name = "function declaration";
-        break;
-      case kDeclGlobals:
-        name = "global variable";
-        break;
-      case kDeclDataSegments:
-        name = "data segment";
-        break;
-      case kDeclFunctionTable:
-        name = "function table";
-        break;
-      default:
-        name = "";
-        break;
+  void CheckForFunctions(WasmModule* module, WasmSection::Code section) {
+    if (module->functions.size() == 0) {
+      error(pc_ - 1, nullptr, "functions must appear before section %s",
+            WasmSection::getName(section));
     }
+  }
+
+  void CheckForPreviousSection(bool* sections, WasmSection::Code section,
+                               bool present) {
+    if (section >= WasmSection::Code::Max) return;
+    if (sections[(size_t)section] == present) return;
     if (present) {
-      error(pc_ - 1, nullptr, "required %s section missing", name);
+      error(pc_ - 1, nullptr, "required %s section missing",
+            WasmSection::getName(section));
     } else {
-      error(pc_ - 1, nullptr, "%s section already present", name);
+      error(pc_ - 1, nullptr, "%s section already present",
+            WasmSection::getName(section));
     }
   }
 
@@ -302,16 +434,13 @@
   FunctionResult DecodeSingleFunction(ModuleEnv* module_env,
                                       WasmFunction* function) {
     pc_ = start_;
-    function->sig = consume_sig();                  // read signature
-    function->name_offset = 0;                   // ---- name
-    function->code_start_offset = off(pc_ + 8);  // ---- code start
-    function->code_end_offset = off(limit_);     // ---- code end
-    function->local_i32_count = consume_u16();      // read u16
-    function->local_i64_count = consume_u16();      // read u16
-    function->local_f32_count = consume_u16();      // read u16
-    function->local_f64_count = consume_u16();      // read u16
-    function->exported = false;                  // ---- exported
-    function->external = false;                  // ---- external
+    function->sig = consume_sig();            // read signature
+    function->name_offset = 0;                // ---- name
+    function->name_length = 0;                // ---- name length
+    function->code_start_offset = off(pc_);   // ---- code start
+    function->code_end_offset = off(limit_);  // ---- code end
+    function->exported = false;               // ---- exported
+    function->external = false;               // ---- external
 
     if (ok()) VerifyFunctionBody(0, module_env, function);
 
@@ -331,19 +460,20 @@
  private:
   Zone* module_zone;
   ModuleResult result_;
-  bool asm_js_;
+  ModuleOrigin origin_;
 
   uint32_t off(const byte* ptr) { return static_cast<uint32_t>(ptr - start_); }
 
   // Decodes a single global entry inside a module starting at {pc_}.
   void DecodeGlobalInModule(WasmGlobal* global) {
-    global->name_offset = consume_string("global name");
+    global->name_offset = consume_string(&global->name_length, "global name");
     global->type = mem_type();
     global->offset = 0;
     global->exported = consume_u8("exported") != 0;
   }
 
   // Decodes a single function entry inside a module starting at {pc_}.
+  // TODO(titzer): legacy function body; remove
   void DecodeFunctionInModule(WasmModule* module, WasmFunction* function,
                               bool verify_body = true) {
     byte decl_bits = consume_u8("function decl");
@@ -351,10 +481,10 @@
     const byte* sigpos = pc_;
     function->sig_index = consume_u16("signature index");
 
-    if (function->sig_index >= module->signatures->size()) {
+    if (function->sig_index >= module->signatures.size()) {
       return error(sigpos, "invalid signature index");
     } else {
-      function->sig = module->signatures->at(function->sig_index);
+      function->sig = module->signatures[function->sig_index];
     }
 
     TRACE("  +%d  <function attributes:%s%s%s%s%s>\n",
@@ -366,7 +496,8 @@
           (decl_bits & kDeclFunctionImport) == 0 ? " body" : "");
 
     if (decl_bits & kDeclFunctionName) {
-      function->name_offset = consume_string("function name");
+      function->name_offset =
+          consume_string(&function->name_length, "function name");
     }
 
     function->exported = decl_bits & kDeclFunctionExport;
@@ -406,25 +537,30 @@
 
   // Decodes a single data segment entry inside a module starting at {pc_}.
   void DecodeDataSegmentInModule(WasmModule* module, WasmDataSegment* segment) {
-    segment->dest_addr = consume_u32("destination");
-    segment->source_offset = consume_offset("source offset");
-    segment->source_size = consume_u32("source size");
-    segment->init = consume_u8("init");
+    const byte* start = pc_;
+    int length;
+    segment->dest_addr = consume_u32v(&length, "destination");
+    segment->source_size = consume_u32v(&length, "source size");
+    segment->source_offset = static_cast<uint32_t>(pc_ - start_);
+    segment->init = true;
 
     // Validate the data is in the module.
     uint32_t module_limit = static_cast<uint32_t>(limit_ - start_);
     if (!IsWithinLimit(module_limit, segment->source_offset,
                        segment->source_size)) {
-      error(pc_ - sizeof(uint32_t), "segment out of bounds of module");
+      error(start, "segment out of bounds of module");
     }
 
     // Validate that the segment will fit into the (minimum) memory.
     uint32_t memory_limit =
-        1 << (module ? module->min_mem_size_log2 : WasmModule::kMaxMemSize);
+        WasmModule::kPageSize * (module ? module->min_mem_pages
+                                        : WasmModule::kMaxMemPages);
     if (!IsWithinLimit(memory_limit, segment->dest_addr,
                        segment->source_size)) {
-      error(pc_ - sizeof(uint32_t), "segment out of bounds of memory");
+      error(start, "segment out of bounds of memory");
     }
+
+    consume_bytes(segment->source_size);
   }
 
   // Verifies the body (code) of a given function.
@@ -436,18 +572,10 @@
          << std::endl;
       os << std::endl;
     }
-    FunctionEnv fenv;
-    fenv.module = menv;
-    fenv.sig = function->sig;
-    fenv.local_i32_count = function->local_i32_count;
-    fenv.local_i64_count = function->local_i64_count;
-    fenv.local_f32_count = function->local_f32_count;
-    fenv.local_f64_count = function->local_f64_count;
-    fenv.SumLocals();
-
-    TreeResult result =
-        VerifyWasmCode(&fenv, start_, start_ + function->code_start_offset,
-                       start_ + function->code_end_offset);
+    FunctionBody body = {menv, function->sig, start_,
+                         start_ + function->code_start_offset,
+                         start_ + function->code_end_offset};
+    TreeResult result = VerifyWasmCode(module_zone->allocator(), body);
     if (result.failed()) {
       // Wrap the error message from the function decoder.
       std::ostringstream str;
@@ -476,11 +604,67 @@
     return offset;
   }
 
-  // Reads a single 32-bit unsigned integer interpreted as an offset into the
-  // data and validating the string there and advances.
-  uint32_t consume_string(const char* name = nullptr) {
-    // TODO(titzer): validate string
-    return consume_offset(name ? name : "string");
+  // Reads a length-prefixed string, checking that it is within bounds. Returns
+  // the offset of the string, and the length as an out parameter.
+  uint32_t consume_string(uint32_t* length, const char* name = nullptr) {
+    int varint_length;
+    *length = consume_u32v(&varint_length, "string length");
+    uint32_t offset = pc_offset();
+    TRACE("  +%u  %-20s: (%u bytes)\n", offset, "string", *length);
+    consume_bytes(*length);
+    return offset;
+  }
+
+  uint32_t consume_sig_index(WasmModule* module, FunctionSig** sig) {
+    const byte* pos = pc_;
+    int length;
+    uint32_t sig_index = consume_u32v(&length, "signature index");
+    if (sig_index >= module->signatures.size()) {
+      error(pos, pos, "signature index %u out of bounds (%d signatures)",
+            sig_index, static_cast<int>(module->signatures.size()));
+      *sig = nullptr;
+      return 0;
+    }
+    *sig = module->signatures[sig_index];
+    return sig_index;
+  }
+
+  uint32_t consume_func_index(WasmModule* module, WasmFunction** func) {
+    const byte* pos = pc_;
+    int length;
+    uint32_t func_index = consume_u32v(&length, "function index");
+    if (func_index >= module->functions.size()) {
+      error(pos, pos, "function index %u out of bounds (%d functions)",
+            func_index, static_cast<int>(module->functions.size()));
+      *func = nullptr;
+      return 0;
+    }
+    *func = &module->functions[func_index];
+    return func_index;
+  }
+
+  // Reads a section name.
+  WasmSection::Code consume_section_name(int* string_leb_length,
+                                         uint32_t* string_length) {
+    *string_length = consume_u32v(string_leb_length, "name length");
+    const byte* start = pc_;
+    consume_bytes(*string_length);
+    if (failed()) {
+      TRACE("Section name of length %u couldn't be read\n", *string_length);
+      return WasmSection::Code::Max;
+    }
+    // TODO(jfb) Linear search, it may be better to do a common-prefix search.
+    for (WasmSection::Code i = WasmSection::begin(); i != WasmSection::end();
+         i = WasmSection::next(i)) {
+      if (WasmSection::getNameLength(i) == *string_length &&
+          0 == memcmp(WasmSection::getName(i), start, *string_length)) {
+        return i;
+      }
+    }
+    TRACE("Unknown section: '");
+    for (uint32_t i = 0; i != *string_length; ++i) TRACE("%c", *(start + i));
+    TRACE("'\n");
+    return WasmSection::Code::Max;
   }
 
   // Reads a single 8-bit integer, interpreting it as a local type.
@@ -537,7 +721,8 @@
 
   // Parses an inline function signature.
   FunctionSig* consume_sig() {
-    byte count = consume_u8("param count");
+    int length;
+    byte count = consume_u32v(&length, "param count");
     LocalType ret = consume_local_type();
     FunctionSig::Builder builder(module_zone, ret == kAstStmt ? 0 : 1, count);
     if (ret != kAstStmt) builder.AddReturn(ret);
@@ -579,22 +764,21 @@
   }
 };
 
-
 ModuleResult DecodeWasmModule(Isolate* isolate, Zone* zone,
                               const byte* module_start, const byte* module_end,
-                              bool verify_functions, bool asm_js) {
+                              bool verify_functions, ModuleOrigin origin) {
   size_t size = module_end - module_start;
   if (module_start > module_end) return ModuleError("start > end");
   if (size >= kMaxModuleSize) return ModuleError("size > maximum module size");
   WasmModule* module = new WasmModule();
-  ModuleDecoder decoder(zone, module_start, module_end, asm_js);
+  ModuleDecoder decoder(zone, module_start, module_end, origin);
   return decoder.DecodeModule(module, verify_functions);
 }
 
 
 FunctionSig* DecodeWasmSignatureForTesting(Zone* zone, const byte* start,
                                            const byte* end) {
-  ModuleDecoder decoder(zone, start, end, false);
+  ModuleDecoder decoder(zone, start, end, kWasmOrigin);
   return decoder.DecodeFunctionSignature(start);
 }
 
@@ -608,7 +792,7 @@
   if (size > kMaxFunctionSize)
     return FunctionError("size > maximum function size");
   WasmFunction* function = new WasmFunction();
-  ModuleDecoder decoder(zone, function_start, function_end, false);
+  ModuleDecoder decoder(zone, function_start, function_end, kWasmOrigin);
   return decoder.DecodeSingleFunction(module_env, function);
 }
 }  // namespace wasm