Upgrade V8 to version 4.9.385.28

https://chromium.googlesource.com/v8/v8/+/4.9.385.28

Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/test/unittests/wasm/module-decoder-unittest.cc b/test/unittests/wasm/module-decoder-unittest.cc
new file mode 100644
index 0000000..0738b59
--- /dev/null
+++ b/test/unittests/wasm/module-decoder-unittest.cc
@@ -0,0 +1,957 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/unittests/test-utils.h"
+
+#include "src/wasm/module-decoder.h"
+#include "src/wasm/wasm-opcodes.h"
+
+namespace v8 {
+namespace internal {
+namespace wasm {
+
+class WasmModuleVerifyTest : public TestWithZone {
+ public:
+  ModuleResult DecodeModule(const byte* module_start, const byte* module_end) {
+    return DecodeWasmModule(nullptr, zone(), module_start, module_end, false,
+                            false);
+  }
+};
+
+
+#define EXPECT_VERIFIES(data)                                         \
+  do {                                                                \
+    ModuleResult result = DecodeModule(data, data + arraysize(data)); \
+    EXPECT_TRUE(result.ok());                                         \
+    if (result.val) delete result.val;                                \
+  } while (false)
+
+
+#define EXPECT_FAILURE(data)                                          \
+  do {                                                                \
+    ModuleResult result = DecodeModule(data, data + arraysize(data)); \
+    EXPECT_FALSE(result.ok());                                        \
+    if (result.val) delete result.val;                                \
+  } while (false)
+
+
+struct LocalTypePair {
+  uint8_t code;
+  LocalType type;
+} kLocalTypes[] = {{kLocalI32, kAstI32},
+                   {kLocalI64, kAstI64},
+                   {kLocalF32, kAstF32},
+                   {kLocalF64, kAstF64}};
+
+
+TEST_F(WasmModuleVerifyTest, DecodeEmpty) {
+  static const byte data[1]{kDeclEnd};
+  {
+    ModuleResult result = DecodeModule(data, data);
+    EXPECT_TRUE(result.ok());
+    if (result.val) delete result.val;
+  }
+  {
+    ModuleResult result = DecodeModule(data, data + 1);
+    EXPECT_TRUE(result.ok());
+    if (result.val) delete result.val;
+  }
+}
+
+
+TEST_F(WasmModuleVerifyTest, OneGlobal) {
+  const byte data[] = {
+      kDeclGlobals,
+      1,
+      0,
+      0,
+      0,
+      0,        // name offset
+      kMemI32,  // memory type
+      0,        // exported
+  };
+
+  {
+    // Should decode to exactly one global.
+    ModuleResult result = DecodeModule(data, data + arraysize(data));
+    EXPECT_TRUE(result.ok());
+    EXPECT_EQ(1, result.val->globals->size());
+    EXPECT_EQ(0, result.val->functions->size());
+    EXPECT_EQ(0, result.val->data_segments->size());
+
+    WasmGlobal* global = &result.val->globals->back();
+
+    EXPECT_EQ(0, global->name_offset);
+    EXPECT_EQ(MachineType::Int32(), global->type);
+    EXPECT_EQ(0, global->offset);
+    EXPECT_FALSE(global->exported);
+
+    if (result.val) delete result.val;
+  }
+
+  for (size_t size = 1; size < arraysize(data); size++) {
+    // Should fall off end of module bytes.
+    ModuleResult result = DecodeModule(data, data + size);
+    EXPECT_FALSE(result.ok());
+    if (result.val) delete result.val;
+  }
+}
+
+
+TEST_F(WasmModuleVerifyTest, ZeroGlobals) {
+  const byte data[] = {
+      kDeclGlobals, 0,  // declare 0 globals
+  };
+  ModuleResult result = DecodeModule(data, data + arraysize(data));
+  EXPECT_TRUE(result.ok());
+  if (result.val) delete result.val;
+}
+
+
+static void AppendUint32v(std::vector<byte>& buffer, uint32_t val) {
+  while (true) {
+    uint32_t next = val >> 7;
+    uint32_t out = val & 0x7f;
+    if (next) {
+      buffer.push_back(static_cast<byte>(0x80 | out));
+      val = next;
+    } else {
+      buffer.push_back(static_cast<byte>(out));
+      break;
+    }
+  }
+}
+
+
+TEST_F(WasmModuleVerifyTest, NGlobals) {
+  const byte data[] = {
+      0,       0, 0, 0,  // name offset
+      kMemI32,           // memory type
+      0,                 // exported
+  };
+  for (uint32_t i = 0; i < 1000000; i = i * 7 + 1) {
+    std::vector<byte> buffer;
+    buffer.push_back(kDeclGlobals);
+    AppendUint32v(buffer, i);
+    for (uint32_t j = 0; j < i; j++) {
+      buffer.insert(buffer.end(), data, data + arraysize(data));
+    }
+
+    ModuleResult result = DecodeModule(&buffer[0], &buffer[0] + buffer.size());
+    EXPECT_TRUE(result.ok());
+    if (result.val) delete result.val;
+  }
+}
+
+
+TEST_F(WasmModuleVerifyTest, GlobalWithInvalidNameOffset) {
+  const byte data[] = {
+      kDeclGlobals,
+      1,  // declare one global
+      0,
+      3,
+      0,
+      0,        // name offset
+      kMemI32,  // memory type
+      0,        // exported
+  };
+
+  EXPECT_FAILURE(data);
+}
+
+
+TEST_F(WasmModuleVerifyTest, GlobalWithInvalidMemoryType) {
+  const byte data[] = {
+      kDeclGlobals,
+      1,  // declare one global
+      0,
+      0,
+      0,
+      0,   // name offset
+      33,  // memory type
+      0,   // exported
+  };
+
+  EXPECT_FAILURE(data);
+}
+
+
+TEST_F(WasmModuleVerifyTest, TwoGlobals) {
+  const byte data[] = {
+      kDeclGlobals,
+      2,
+      0,
+      0,
+      0,
+      0,        // #0: name offset
+      kMemF32,  // memory type
+      0,        // exported
+      0,
+      0,
+      0,
+      0,        // #1: name offset
+      kMemF64,  // memory type
+      1,        // exported
+  };
+
+  {
+    // Should decode to exactly two globals.
+    ModuleResult result = DecodeModule(data, data + arraysize(data));
+    EXPECT_TRUE(result.ok());
+    EXPECT_EQ(2, result.val->globals->size());
+    EXPECT_EQ(0, result.val->functions->size());
+    EXPECT_EQ(0, result.val->data_segments->size());
+
+    WasmGlobal* g0 = &result.val->globals->at(0);
+    WasmGlobal* g1 = &result.val->globals->at(1);
+
+    EXPECT_EQ(0, g0->name_offset);
+    EXPECT_EQ(MachineType::Float32(), g0->type);
+    EXPECT_EQ(0, g0->offset);
+    EXPECT_FALSE(g0->exported);
+
+    EXPECT_EQ(0, g1->name_offset);
+    EXPECT_EQ(MachineType::Float64(), g1->type);
+    EXPECT_EQ(0, g1->offset);
+    EXPECT_TRUE(g1->exported);
+
+    if (result.val) delete result.val;
+  }
+
+  for (size_t size = 1; size < arraysize(data); size++) {
+    // Should fall off end of module bytes.
+    ModuleResult result = DecodeModule(data, data + size);
+    EXPECT_FALSE(result.ok());
+    if (result.val) delete result.val;
+  }
+}
+
+
+TEST_F(WasmModuleVerifyTest, OneSignature) {
+  static const byte data[] = {
+      kDeclSignatures, 1, 0, kLocalVoid  // void -> void
+  };
+  EXPECT_VERIFIES(data);
+}
+
+
+TEST_F(WasmModuleVerifyTest, MultipleSignatures) {
+  static const byte data[] = {
+      kDeclSignatures,
+      3,
+      0,
+      kLocalVoid,  // void -> void
+      1,
+      kLocalI32,
+      kLocalF32,  // f32 -> i32
+      2,
+      kLocalI32,
+      kLocalF64,
+      kLocalF64,  // (f64,f64) -> i32
+  };
+
+  ModuleResult result = DecodeModule(data, data + arraysize(data));
+  EXPECT_TRUE(result.ok());
+  EXPECT_EQ(3, result.val->signatures->size());
+  if (result.val->signatures->size() == 3) {
+    EXPECT_EQ(0, result.val->signatures->at(0)->return_count());
+    EXPECT_EQ(1, result.val->signatures->at(1)->return_count());
+    EXPECT_EQ(1, result.val->signatures->at(2)->return_count());
+
+    EXPECT_EQ(0, result.val->signatures->at(0)->parameter_count());
+    EXPECT_EQ(1, result.val->signatures->at(1)->parameter_count());
+    EXPECT_EQ(2, result.val->signatures->at(2)->parameter_count());
+  }
+  if (result.val) delete result.val;
+
+  for (size_t size = 1; size < arraysize(data); size++) {
+    ModuleResult result = DecodeModule(data, data + size);
+    // Should fall off the end of module bytes.
+    EXPECT_FALSE(result.ok());
+    if (result.val) delete result.val;
+  }
+}
+
+
+TEST_F(WasmModuleVerifyTest, FunctionWithoutSig) {
+  static const byte data[] = {
+      kDeclFunctions, 1,
+      // func#0 ------------------------------------------------------
+      0, 0,        // signature index
+      0, 0, 0, 0,  // name offset
+      0, 0, 0, 0,  // code start offset
+      0, 0, 0, 0,  // code end offset
+      1, 2,        // local int32 count
+      3, 4,        // local int64 count
+      5, 6,        // local float32 count
+      7, 8,        // local float64 count
+      0,           // exported
+      1            // external
+  };
+
+  ModuleResult result = DecodeModule(data, data + arraysize(data));
+  EXPECT_FALSE(result.ok());
+  if (result.val) delete result.val;
+}
+
+
+TEST_F(WasmModuleVerifyTest, OneEmptyVoidVoidFunction) {
+  const int kCodeStartOffset = 23;
+  const int kCodeEndOffset = kCodeStartOffset + 1;
+
+  static const byte data[] = {
+      kDeclSignatures, 1,
+      // sig#0 -------------------------------------------------------
+      0, 0,  // void -> void
+      // func#0 ------------------------------------------------------
+      kDeclFunctions, 1,
+      kDeclFunctionLocals | kDeclFunctionExport | kDeclFunctionName, 0,
+      0,           // signature index
+      9, 0, 0, 0,  // name offset
+      11, 2,       // local int32 count
+      13, 4,       // local int64 count
+      15, 6,       // local float32 count
+      17, 8,       // local float64 count
+      1, 0,        // size
+      kExprNop,
+  };
+
+  {
+    // Should decode to exactly one function.
+    ModuleResult result = DecodeModule(data, data + arraysize(data));
+    EXPECT_TRUE(result.ok());
+    EXPECT_EQ(0, result.val->globals->size());
+    EXPECT_EQ(1, result.val->signatures->size());
+    EXPECT_EQ(1, result.val->functions->size());
+    EXPECT_EQ(0, result.val->data_segments->size());
+    EXPECT_EQ(0, result.val->function_table->size());
+
+    WasmFunction* function = &result.val->functions->back();
+
+    EXPECT_EQ(9, function->name_offset);
+    EXPECT_EQ(kCodeStartOffset, function->code_start_offset);
+    EXPECT_EQ(kCodeEndOffset, function->code_end_offset);
+
+    EXPECT_EQ(523, function->local_int32_count);
+    EXPECT_EQ(1037, function->local_int64_count);
+    EXPECT_EQ(1551, function->local_float32_count);
+    EXPECT_EQ(2065, function->local_float64_count);
+
+    EXPECT_TRUE(function->exported);
+    EXPECT_FALSE(function->external);
+
+    if (result.val) delete result.val;
+  }
+
+  for (size_t size = 5; size < arraysize(data); size++) {
+    // Should fall off end of module bytes.
+    ModuleResult result = DecodeModule(data, data + size);
+    EXPECT_FALSE(result.ok());
+    if (result.val) delete result.val;
+  }
+}
+
+
+TEST_F(WasmModuleVerifyTest, OneFunctionImported) {
+  static const byte data[] = {
+      kDeclSignatures, 1,
+      // sig#0 -------------------------------------------------------
+      0, 0,  // void -> void
+      kDeclFunctions, 1,
+      // func#0 ------------------------------------------------------
+      kDeclFunctionImport,  // no name, no locals, imported
+      0, 0,                 // signature index
+  };
+
+  ModuleResult result = DecodeModule(data, data + arraysize(data));
+  EXPECT_TRUE(result.ok());
+  EXPECT_EQ(1, result.val->functions->size());
+  WasmFunction* function = &result.val->functions->back();
+
+  EXPECT_EQ(0, function->name_offset);
+  EXPECT_EQ(0, function->code_start_offset);
+  EXPECT_EQ(0, function->code_end_offset);
+
+  EXPECT_EQ(0, function->local_int32_count);
+  EXPECT_EQ(0, function->local_int64_count);
+  EXPECT_EQ(0, function->local_float32_count);
+  EXPECT_EQ(0, function->local_float64_count);
+
+  EXPECT_FALSE(function->exported);
+  EXPECT_TRUE(function->external);
+
+  if (result.val) delete result.val;
+}
+
+
+TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody) {
+  static const byte kCodeStartOffset = 11;
+  static const byte kCodeEndOffset = kCodeStartOffset + 1;
+
+  static const byte data[] = {
+      kDeclSignatures, 1,
+      // sig#0 -------------------------------------------------------
+      0, 0,  // void -> void
+      kDeclFunctions, 1,
+      // func#0 ------------------------------------------------------
+      0,        // no name, no locals
+      0, 0,     // signature index
+      1, 0,     // body size
+      kExprNop  // body
+  };
+
+  ModuleResult result = DecodeModule(data, data + arraysize(data));
+  EXPECT_TRUE(result.ok());
+  EXPECT_EQ(1, result.val->functions->size());
+  WasmFunction* function = &result.val->functions->back();
+
+  EXPECT_EQ(0, function->name_offset);
+  EXPECT_EQ(kCodeStartOffset, function->code_start_offset);
+  EXPECT_EQ(kCodeEndOffset, function->code_end_offset);
+
+  EXPECT_EQ(0, function->local_int32_count);
+  EXPECT_EQ(0, function->local_int64_count);
+  EXPECT_EQ(0, function->local_float32_count);
+  EXPECT_EQ(0, function->local_float64_count);
+
+  EXPECT_FALSE(function->exported);
+  EXPECT_FALSE(function->external);
+
+  if (result.val) delete result.val;
+}
+
+
+TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody_WithLocals) {
+  static const byte kCodeStartOffset = 19;
+  static const byte kCodeEndOffset = kCodeStartOffset + 1;
+
+  static const byte data[] = {
+      kDeclSignatures, 1,
+      // sig#0 -------------------------------------------------------
+      0, 0,  // void -> void
+      kDeclFunctions, 1,
+      // func#0 ------------------------------------------------------
+      kDeclFunctionLocals, 0, 0,  // signature index
+      1, 2,                       // local int32 count
+      3, 4,                       // local int64 count
+      5, 6,                       // local float32 count
+      7, 8,                       // local float64 count
+      1, 0,                       // body size
+      kExprNop                    // body
+  };
+
+  ModuleResult result = DecodeModule(data, data + arraysize(data));
+  EXPECT_TRUE(result.ok());
+  EXPECT_EQ(1, result.val->functions->size());
+  WasmFunction* function = &result.val->functions->back();
+
+  EXPECT_EQ(0, function->name_offset);
+  EXPECT_EQ(kCodeStartOffset, function->code_start_offset);
+  EXPECT_EQ(kCodeEndOffset, function->code_end_offset);
+
+  EXPECT_EQ(513, function->local_int32_count);
+  EXPECT_EQ(1027, function->local_int64_count);
+  EXPECT_EQ(1541, function->local_float32_count);
+  EXPECT_EQ(2055, function->local_float64_count);
+
+  EXPECT_FALSE(function->exported);
+  EXPECT_FALSE(function->external);
+
+  if (result.val) delete result.val;
+}
+
+
+TEST_F(WasmModuleVerifyTest, OneGlobalOneFunctionWithNopBodyOneDataSegment) {
+  static const byte kCodeStartOffset = 2 + kDeclGlobalSize + 4 + 2 + 17;
+  static const byte kCodeEndOffset = kCodeStartOffset + 3;
+
+  static const byte data[] = {
+      // global#0 --------------------------------------------------
+      kDeclGlobals, 1, 0, 0, 0, 0,  // name offset
+      kMemU8,                       // memory type
+      0,                            // exported
+      // sig#0 -----------------------------------------------------
+      kDeclSignatures, 1, 0, 0,  // void -> void
+      // func#0 ----------------------------------------------------
+      kDeclFunctions, 1, kDeclFunctionLocals | kDeclFunctionName, 0,
+      0,           // signature index
+      9, 0, 0, 0,  // name offset
+      1, 2,        // local int32 count
+      3, 4,        // local int64 count
+      5, 6,        // local float32 count
+      7, 8,        // local float64 count
+      3, 0,        // body size
+      kExprNop,    // func#0 body
+      kExprNop,    // func#0 body
+      kExprNop,    // func#0 body
+      // segment#0 -------------------------------------------------
+      kDeclDataSegments, 1, 0xae, 0xb3, 0x08, 0,  // dest addr
+      15, 0, 0, 0,                                // source offset
+      5, 0, 0, 0,                                 // source size
+      1,                                          // init
+      // rest ------------------------------------------------------
+      kDeclEnd,
+  };
+
+  {
+    ModuleResult result = DecodeModule(data, data + arraysize(data));
+    EXPECT_TRUE(result.ok());
+    EXPECT_EQ(1, result.val->globals->size());
+    EXPECT_EQ(1, result.val->functions->size());
+    EXPECT_EQ(1, result.val->data_segments->size());
+
+    WasmGlobal* global = &result.val->globals->back();
+
+    EXPECT_EQ(0, global->name_offset);
+    EXPECT_EQ(MachineType::Uint8(), global->type);
+    EXPECT_EQ(0, global->offset);
+    EXPECT_FALSE(global->exported);
+
+    WasmFunction* function = &result.val->functions->back();
+
+    EXPECT_EQ(9, function->name_offset);
+    EXPECT_EQ(kCodeStartOffset, function->code_start_offset);
+    EXPECT_EQ(kCodeEndOffset, function->code_end_offset);
+
+    EXPECT_FALSE(function->exported);
+    EXPECT_FALSE(function->external);
+
+    WasmDataSegment* segment = &result.val->data_segments->back();
+
+    EXPECT_EQ(0x8b3ae, segment->dest_addr);
+    EXPECT_EQ(15, segment->source_offset);
+    EXPECT_EQ(5, segment->source_size);
+    EXPECT_TRUE(segment->init);
+
+    if (result.val) delete result.val;
+  }
+}
+
+
+TEST_F(WasmModuleVerifyTest, OneDataSegment) {
+  const byte data[] = {
+      kDeclDataSegments,
+      1,
+      0xaa,
+      0xbb,
+      0x09,
+      0,  // dest addr
+      11,
+      0,
+      0,
+      0,  // source offset
+      3,
+      0,
+      0,
+      0,  // source size
+      1,  // init
+  };
+
+  {
+    ModuleResult result = DecodeModule(data, data + arraysize(data));
+    EXPECT_TRUE(result.ok());
+    EXPECT_EQ(0, result.val->globals->size());
+    EXPECT_EQ(0, result.val->functions->size());
+    EXPECT_EQ(1, result.val->data_segments->size());
+
+    WasmDataSegment* segment = &result.val->data_segments->back();
+
+    EXPECT_EQ(0x9bbaa, segment->dest_addr);
+    EXPECT_EQ(11, segment->source_offset);
+    EXPECT_EQ(3, segment->source_size);
+    EXPECT_TRUE(segment->init);
+
+    if (result.val) delete result.val;
+  }
+
+  for (size_t size = 1; size < arraysize(data); size++) {
+    // Should fall off end of module bytes.
+    ModuleResult result = DecodeModule(data, data + size);
+    EXPECT_FALSE(result.ok());
+    if (result.val) delete result.val;
+  }
+}
+
+
+TEST_F(WasmModuleVerifyTest, TwoDataSegments) {
+  const byte data[] = {
+      kDeclDataSegments,
+      2,
+      0xee,
+      0xff,
+      0x07,
+      0,  // dest addr
+      9,
+      0,
+      0,
+      0,  // #0: source offset
+      4,
+      0,
+      0,
+      0,  // source size
+      0,  // init
+      0xcc,
+      0xdd,
+      0x06,
+      0,  // #1: dest addr
+      6,
+      0,
+      0,
+      0,  // source offset
+      10,
+      0,
+      0,
+      0,  // source size
+      1,  // init
+  };
+
+  {
+    ModuleResult result = DecodeModule(data, data + arraysize(data));
+    EXPECT_TRUE(result.ok());
+    EXPECT_EQ(0, result.val->globals->size());
+    EXPECT_EQ(0, result.val->functions->size());
+    EXPECT_EQ(2, result.val->data_segments->size());
+
+    WasmDataSegment* s0 = &result.val->data_segments->at(0);
+    WasmDataSegment* s1 = &result.val->data_segments->at(1);
+
+    EXPECT_EQ(0x7ffee, s0->dest_addr);
+    EXPECT_EQ(9, s0->source_offset);
+    EXPECT_EQ(4, s0->source_size);
+    EXPECT_FALSE(s0->init);
+
+    EXPECT_EQ(0x6ddcc, s1->dest_addr);
+    EXPECT_EQ(6, s1->source_offset);
+    EXPECT_EQ(10, s1->source_size);
+    EXPECT_TRUE(s1->init);
+
+    if (result.val) delete result.val;
+  }
+
+  for (size_t size = 1; size < arraysize(data); size++) {
+    // Should fall off end of module bytes.
+    ModuleResult result = DecodeModule(data, data + size);
+    EXPECT_FALSE(result.ok());
+    if (result.val) delete result.val;
+  }
+}
+
+
+// To make below tests for indirect calls much shorter.
+#define FUNCTION(sig_index, external)                \
+  kDeclFunctionImport, static_cast<byte>(sig_index), \
+      static_cast<byte>(sig_index >> 8)
+
+
+TEST_F(WasmModuleVerifyTest, OneIndirectFunction) {
+  static const byte data[] = {
+      // sig#0 -------------------------------------------------------
+      kDeclSignatures, 1, 0, 0,  // void -> void
+      // func#0 ------------------------------------------------------
+      kDeclFunctions, 1, FUNCTION(0, 0),
+      // indirect table ----------------------------------------------
+      kDeclFunctionTable, 1, 0, 0};
+
+  ModuleResult result = DecodeModule(data, data + arraysize(data));
+  EXPECT_TRUE(result.ok());
+  if (result.ok()) {
+    EXPECT_EQ(1, result.val->signatures->size());
+    EXPECT_EQ(1, result.val->functions->size());
+    EXPECT_EQ(1, result.val->function_table->size());
+    EXPECT_EQ(0, result.val->function_table->at(0));
+  }
+  if (result.val) delete result.val;
+}
+
+
+TEST_F(WasmModuleVerifyTest, MultipleIndirectFunctions) {
+  static const byte data[] = {
+      // sig#0 -------------------------------------------------------
+      kDeclSignatures, 2, 0, 0,  // void -> void
+      0, kLocalI32,              // void -> i32
+      // func#0 ------------------------------------------------------
+      kDeclFunctions, 4, FUNCTION(0, 1), FUNCTION(1, 1), FUNCTION(0, 1),
+      FUNCTION(1, 1),
+      // indirect table ----------------------------------------------
+      kDeclFunctionTable, 8, 0, 0, 1, 0, 2, 0, 3, 0, 0, 0, 1, 0, 2, 0, 3, 0,
+  };
+
+  ModuleResult result = DecodeModule(data, data + arraysize(data));
+  EXPECT_TRUE(result.ok());
+  if (result.ok()) {
+    EXPECT_EQ(2, result.val->signatures->size());
+    EXPECT_EQ(4, result.val->functions->size());
+    EXPECT_EQ(8, result.val->function_table->size());
+    for (int i = 0; i < 8; i++) {
+      EXPECT_EQ(i & 3, result.val->function_table->at(i));
+    }
+  }
+  if (result.val) delete result.val;
+}
+
+
+TEST_F(WasmModuleVerifyTest, IndirectFunctionNoFunctions) {
+  static const byte data[] = {
+      // sig#0 -------------------------------------------------------
+      kDeclSignatures, 1, 0, 0,  // void -> void
+      // indirect table ----------------------------------------------
+      kDeclFunctionTable, 1, 0, 0,
+  };
+
+  EXPECT_FAILURE(data);
+}
+
+
+TEST_F(WasmModuleVerifyTest, IndirectFunctionInvalidIndex) {
+  static const byte data[] = {
+      // sig#0 -------------------------------------------------------
+      kDeclSignatures, 1, 0, 0,  // void -> void
+      // functions ---------------------------------------------------
+      kDeclFunctions, 1, FUNCTION(0, 1),
+      // indirect table ----------------------------------------------
+      kDeclFunctionTable, 1, 1, 0,
+  };
+
+  EXPECT_FAILURE(data);
+}
+
+
+class WasmSignatureDecodeTest : public TestWithZone {};
+
+
+TEST_F(WasmSignatureDecodeTest, Ok_v_v) {
+  static const byte data[] = {0, 0};
+  Zone zone;
+  FunctionSig* sig =
+      DecodeWasmSignatureForTesting(&zone, data, data + arraysize(data));
+
+  EXPECT_TRUE(sig != nullptr);
+  EXPECT_EQ(0, sig->parameter_count());
+  EXPECT_EQ(0, sig->return_count());
+}
+
+
+TEST_F(WasmSignatureDecodeTest, Ok_t_v) {
+  for (size_t i = 0; i < arraysize(kLocalTypes); i++) {
+    LocalTypePair ret_type = kLocalTypes[i];
+    const byte data[] = {0, ret_type.code};
+    FunctionSig* sig =
+        DecodeWasmSignatureForTesting(zone(), data, data + arraysize(data));
+
+    EXPECT_TRUE(sig != nullptr);
+    EXPECT_EQ(0, sig->parameter_count());
+    EXPECT_EQ(1, sig->return_count());
+    EXPECT_EQ(ret_type.type, sig->GetReturn());
+  }
+}
+
+
+TEST_F(WasmSignatureDecodeTest, Ok_v_t) {
+  for (size_t i = 0; i < arraysize(kLocalTypes); i++) {
+    LocalTypePair param_type = kLocalTypes[i];
+    const byte data[] = {1, 0, param_type.code};
+    FunctionSig* sig =
+        DecodeWasmSignatureForTesting(zone(), data, data + arraysize(data));
+
+    EXPECT_TRUE(sig != nullptr);
+    EXPECT_EQ(1, sig->parameter_count());
+    EXPECT_EQ(0, sig->return_count());
+    EXPECT_EQ(param_type.type, sig->GetParam(0));
+  }
+}
+
+
+TEST_F(WasmSignatureDecodeTest, Ok_t_t) {
+  for (size_t i = 0; i < arraysize(kLocalTypes); i++) {
+    LocalTypePair ret_type = kLocalTypes[i];
+    for (size_t j = 0; j < arraysize(kLocalTypes); j++) {
+      LocalTypePair param_type = kLocalTypes[j];
+      const byte data[] = {1,                 // param count
+                           ret_type.code,     // ret
+                           param_type.code};  // param
+      FunctionSig* sig =
+          DecodeWasmSignatureForTesting(zone(), data, data + arraysize(data));
+
+      EXPECT_TRUE(sig != nullptr);
+      EXPECT_EQ(1, sig->parameter_count());
+      EXPECT_EQ(1, sig->return_count());
+      EXPECT_EQ(param_type.type, sig->GetParam(0));
+      EXPECT_EQ(ret_type.type, sig->GetReturn());
+    }
+  }
+}
+
+
+TEST_F(WasmSignatureDecodeTest, Ok_i_tt) {
+  for (size_t i = 0; i < arraysize(kLocalTypes); i++) {
+    LocalTypePair p0_type = kLocalTypes[i];
+    for (size_t j = 0; j < arraysize(kLocalTypes); j++) {
+      LocalTypePair p1_type = kLocalTypes[j];
+      const byte data[] = {2,              // param count
+                           kLocalI32,      // ret
+                           p0_type.code,   // p0
+                           p1_type.code};  // p1
+      FunctionSig* sig =
+          DecodeWasmSignatureForTesting(zone(), data, data + arraysize(data));
+
+      EXPECT_TRUE(sig != nullptr);
+      EXPECT_EQ(2, sig->parameter_count());
+      EXPECT_EQ(1, sig->return_count());
+      EXPECT_EQ(p0_type.type, sig->GetParam(0));
+      EXPECT_EQ(p1_type.type, sig->GetParam(1));
+    }
+  }
+}
+
+
+TEST_F(WasmSignatureDecodeTest, Fail_off_end) {
+  byte data[256];
+  for (int p = 0; p <= 255; p = p + 1 + p * 3) {
+    for (int i = 0; i <= p; i++) data[i] = kLocalI32;
+    data[0] = static_cast<byte>(p);
+
+    for (int i = 0; i < p + 1; i++) {
+      // Should fall off the end for all signatures.
+      FunctionSig* sig = DecodeWasmSignatureForTesting(zone(), data, data + i);
+      EXPECT_EQ(nullptr, sig);
+    }
+  }
+}
+
+
+TEST_F(WasmSignatureDecodeTest, Fail_invalid_type) {
+  byte kInvalidType = 76;
+  for (int i = 1; i < 3; i++) {
+    byte data[] = {2, kLocalI32, kLocalI32, kLocalI32};
+    data[i] = kInvalidType;
+    FunctionSig* sig =
+        DecodeWasmSignatureForTesting(zone(), data, data + arraysize(data));
+    EXPECT_EQ(nullptr, sig);
+  }
+}
+
+
+TEST_F(WasmSignatureDecodeTest, Fail_invalid_param_type) {
+  static const int kParamCount = 3;
+  for (int i = 0; i < kParamCount; i++) {
+    byte data[] = {kParamCount, kLocalI32, kLocalI32, kLocalI32, kLocalI32};
+    data[i + 2] = kLocalVoid;
+    FunctionSig* sig =
+        DecodeWasmSignatureForTesting(zone(), data, data + arraysize(data));
+    EXPECT_EQ(nullptr, sig);
+  }
+}
+
+
+class WasmFunctionVerifyTest : public TestWithZone {};
+
+
+TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) {
+  byte data[] = {
+      0,       kLocalVoid,  // signature
+      3,       0,           // local int32 count
+      4,       0,           // local int64 count
+      5,       0,           // local float32 count
+      6,       0,           // local float64 count
+      kExprNop              // body
+  };
+
+  FunctionResult result = DecodeWasmFunction(nullptr, zone(), nullptr, data,
+                                             data + arraysize(data));
+  EXPECT_TRUE(result.ok());
+
+  if (result.val && result.ok()) {
+    WasmFunction* function = result.val;
+    EXPECT_EQ(0, function->sig->parameter_count());
+    EXPECT_EQ(0, function->sig->return_count());
+    EXPECT_EQ(0, function->name_offset);
+    EXPECT_EQ(arraysize(data) - 1, function->code_start_offset);
+    EXPECT_EQ(arraysize(data), function->code_end_offset);
+    EXPECT_EQ(3, function->local_int32_count);
+    EXPECT_EQ(4, function->local_int64_count);
+    EXPECT_EQ(5, function->local_float32_count);
+    EXPECT_EQ(6, function->local_float64_count);
+    EXPECT_FALSE(function->external);
+    EXPECT_FALSE(function->exported);
+  }
+
+  if (result.val) delete result.val;
+}
+
+
+TEST_F(WasmModuleVerifyTest, WLLSectionNoLen) {
+  const byte data[] = {
+      kDeclWLL,  // section without length.
+  };
+  EXPECT_FAILURE(data);
+}
+
+
+TEST_F(WasmModuleVerifyTest, WLLSectionEmpty) {
+  const byte data[] = {
+      kDeclWLL, 0,  // empty section
+  };
+  ModuleResult result = DecodeModule(data, data + arraysize(data));
+  EXPECT_TRUE(result.ok());
+  if (result.val) delete result.val;
+}
+
+
+TEST_F(WasmModuleVerifyTest, WLLSectionOne) {
+  const byte data[] = {
+      kDeclWLL,
+      1,  // LEB128 1
+      0,  // one byte section
+  };
+  ModuleResult result = DecodeModule(data, data + arraysize(data));
+  EXPECT_TRUE(result.ok());
+  if (result.val) delete result.val;
+}
+
+
+TEST_F(WasmModuleVerifyTest, WLLSectionTen) {
+  const byte data[] = {
+      kDeclWLL,
+      10,                             // LEB128 10
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10,  // 10 byte section
+  };
+  ModuleResult result = DecodeModule(data, data + arraysize(data));
+  EXPECT_TRUE(result.ok());
+  if (result.val) delete result.val;
+}
+
+
+TEST_F(WasmModuleVerifyTest, WLLSectionOverflow) {
+  const byte data[] = {
+      kDeclWLL,
+      11,                             // LEB128 11
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10,  // 10 byte section
+  };
+  EXPECT_FAILURE(data);
+}
+
+
+TEST_F(WasmModuleVerifyTest, WLLSectionUnderflow) {
+  const byte data[] = {
+    kDeclWLL,
+    0xff, 0xff, 0xff, 0xff, 0x0f,  // LEB128 0xffffffff
+    1, 2, 3, 4,                    // 4 byte section
+  };
+  EXPECT_FAILURE(data);
+}
+
+
+TEST_F(WasmModuleVerifyTest, WLLSectionLoop) {
+  // Would infinite loop decoding if wrapping and allowed.
+  const byte data[] = {
+    kDeclWLL,
+    0xfa, 0xff, 0xff, 0xff, 0x0f,  // LEB128 0xfffffffa
+    1, 2, 3, 4,                    // 4 byte section
+  };
+  EXPECT_FAILURE(data);
+}
+
+}  // namespace wasm
+}  // namespace internal
+}  // namespace v8