[wasm] Implement bulk memory table.copy in interpreter

Most of the mjsunit/wasm/table-copy.js tests have been ported to
cctests, so they can be tested with all execution tiers.

Bug: v8:8965
Change-Id: I448719be30a4b2bddb9e2cffb4c74d3134db2f50
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1529548
Commit-Queue: Ben Smith <binji@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60396}
diff --git a/src/wasm/wasm-interpreter.cc b/src/wasm/wasm-interpreter.cc
index 71a869a..93026fa 100644
--- a/src/wasm/wasm-interpreter.cc
+++ b/src/wasm/wasm-interpreter.cc
@@ -1705,6 +1705,18 @@
         len += imm.length;
         return ok;
       }
+      case kExprTableCopy: {
+        TableCopyImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc));
+        auto size = Pop().to<uint32_t>();
+        auto src = Pop().to<uint32_t>();
+        auto dst = Pop().to<uint32_t>();
+        bool ok = WasmInstanceObject::CopyTableEntries(
+            instance_object_->GetIsolate(), instance_object_,
+            imm.table_dst.index, imm.table_src.index, dst, src, size);
+        if (!ok) DoTrap(kTrapTableOutOfBounds, pc);
+        len += imm.length;
+        return ok;
+      }
       default:
         FATAL("Unknown or unimplemented opcode #%d:%s", code->start[pc],
               OpcodeName(code->start[pc]));
diff --git a/test/cctest/wasm/test-run-wasm-bulk-memory.cc b/test/cctest/wasm/test-run-wasm-bulk-memory.cc
index f145553..70748fa 100644
--- a/test/cctest/wasm/test-run-wasm-bulk-memory.cc
+++ b/test/cctest/wasm/test-run-wasm-bulk-memory.cc
@@ -4,6 +4,7 @@
 
 #include "test/cctest/cctest.h"
 #include "test/cctest/wasm/wasm-run-utils.h"
+#include "test/common/wasm/test-signatures.h"
 #include "test/common/wasm/wasm-macro-gen.h"
 
 namespace v8 {
@@ -350,6 +351,222 @@
   CHECK_EQ(0xDEADBEEF, r.Call());
 }
 
+WASM_EXEC_TEST(TableCopyInbounds) {
+  EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
+  WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
+  const uint32_t kTableSize = 5;
+  r.builder().AddIndirectFunctionTable(nullptr, kTableSize);
+  BUILD(
+      r,
+      WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
+      kExprI32Const, 0);
+
+  for (uint32_t i = 0; i <= kTableSize; ++i) {
+    r.CheckCallViaJS(0, 0, 0, i);  // nop
+    r.CheckCallViaJS(0, 0, i, kTableSize - i);
+    r.CheckCallViaJS(0, i, 0, kTableSize - i);
+  }
+}
+
+namespace {
+template <typename... Args>
+void CheckTable(Isolate* isolate, Handle<WasmTableObject> table, Args... args) {
+  uint32_t args_length = static_cast<uint32_t>(sizeof...(args));
+  CHECK_EQ(table->current_length(), args_length);
+  Handle<Object> handles[] = {args...};
+  for (uint32_t i = 0; i < args_length; ++i) {
+    CHECK(WasmTableObject::Get(isolate, table, i).is_identical_to(handles[i]));
+  }
+}
+
+template <typename WasmRunner, typename... Args>
+void CheckTableCall(Isolate* isolate, Handle<WasmTableObject> table,
+                    WasmRunner& r, uint32_t function_index, Args... args) {
+  uint32_t args_length = static_cast<uint32_t>(sizeof...(args));
+  CHECK_EQ(table->current_length(), args_length);
+  double expected[] = {args...};
+  for (uint32_t i = 0; i < args_length; ++i) {
+    Handle<Object> buffer[] = {isolate->factory()->NewNumber(i)};
+    r.CheckCallApplyViaJS(expected[i], function_index, buffer, 1);
+  }
+}
+}  // namespace
+
+WASM_EXEC_TEST(TableCopyElems) {
+  EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
+  Isolate* isolate = CcTest::InitIsolateOnce();
+  HandleScope scope(isolate);
+  TestSignatures sigs;
+  WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
+  const uint32_t kTableSize = 5;
+  uint16_t function_indexes[kTableSize];
+  const uint32_t sig_index = r.builder().AddSignature(sigs.i_v());
+
+  for (uint32_t i = 0; i < kTableSize; ++i) {
+    WasmFunctionCompiler& fn = r.NewFunction(sigs.i_v(), "f");
+    BUILD(fn, WASM_I32V_1(i));
+    fn.SetSigIndex(sig_index);
+    function_indexes[i] = fn.function_index();
+  }
+
+  r.builder().AddIndirectFunctionTable(function_indexes, kTableSize);
+
+  BUILD(
+      r,
+      WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
+      kExprI32Const, 0);
+
+  auto table = handle(
+      WasmTableObject::cast(r.builder().instance_object()->tables().get(0)),
+      isolate);
+  auto f0 = WasmTableObject::Get(isolate, table, 0);
+  auto f1 = WasmTableObject::Get(isolate, table, 1);
+  auto f2 = WasmTableObject::Get(isolate, table, 2);
+  auto f3 = WasmTableObject::Get(isolate, table, 3);
+  auto f4 = WasmTableObject::Get(isolate, table, 4);
+
+  CheckTable(isolate, table, f0, f1, f2, f3, f4);
+  r.CheckCallViaJS(0, 0, 1, 1);
+  CheckTable(isolate, table, f1, f1, f2, f3, f4);
+  r.CheckCallViaJS(0, 0, 1, 2);
+  CheckTable(isolate, table, f1, f2, f2, f3, f4);
+  r.CheckCallViaJS(0, 3, 0, 2);
+  CheckTable(isolate, table, f1, f2, f2, f1, f2);
+  r.CheckCallViaJS(0, 1, 0, 2);
+  CheckTable(isolate, table, f1, f1, f2, f1, f2);
+}
+
+WASM_EXEC_TEST(TableCopyCalls) {
+  EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
+  Isolate* isolate = CcTest::InitIsolateOnce();
+  HandleScope scope(isolate);
+  TestSignatures sigs;
+  WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
+  const uint32_t kTableSize = 5;
+  uint16_t function_indexes[kTableSize];
+  const uint32_t sig_index = r.builder().AddSignature(sigs.i_v());
+
+  for (uint32_t i = 0; i < kTableSize; ++i) {
+    WasmFunctionCompiler& fn = r.NewFunction(sigs.i_v(), "f");
+    BUILD(fn, WASM_I32V_1(i));
+    fn.SetSigIndex(sig_index);
+    function_indexes[i] = fn.function_index();
+  }
+
+  r.builder().AddIndirectFunctionTable(function_indexes, kTableSize);
+
+  WasmFunctionCompiler& call = r.NewFunction(sigs.i_i(), "call");
+  BUILD(call, WASM_CALL_INDIRECT0(sig_index, WASM_GET_LOCAL(0)));
+  const uint32_t call_index = call.function_index();
+
+  BUILD(
+      r,
+      WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
+      kExprI32Const, 0);
+
+  auto table = handle(
+      WasmTableObject::cast(r.builder().instance_object()->tables().get(0)),
+      isolate);
+
+  CheckTableCall(isolate, table, r, call_index, 0, 1, 2, 3, 4);
+  r.CheckCallViaJS(0, 0, 1, 1);
+  CheckTableCall(isolate, table, r, call_index, 1, 1, 2, 3, 4);
+  r.CheckCallViaJS(0, 0, 1, 2);
+  CheckTableCall(isolate, table, r, call_index, 1, 2, 2, 3, 4);
+  r.CheckCallViaJS(0, 3, 0, 2);
+  CheckTableCall(isolate, table, r, call_index, 1, 2, 2, 1, 2);
+}
+
+WASM_EXEC_TEST(TableCopyOobWrites) {
+  EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
+  Isolate* isolate = CcTest::InitIsolateOnce();
+  HandleScope scope(isolate);
+  TestSignatures sigs;
+  WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
+  const uint32_t kTableSize = 5;
+  uint16_t function_indexes[kTableSize];
+  const uint32_t sig_index = r.builder().AddSignature(sigs.i_v());
+
+  for (uint32_t i = 0; i < kTableSize; ++i) {
+    WasmFunctionCompiler& fn = r.NewFunction(sigs.i_v(), "f");
+    BUILD(fn, WASM_I32V_1(i));
+    fn.SetSigIndex(sig_index);
+    function_indexes[i] = fn.function_index();
+  }
+
+  r.builder().AddIndirectFunctionTable(function_indexes, kTableSize);
+
+  BUILD(
+      r,
+      WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
+      kExprI32Const, 0);
+
+  auto table = handle(
+      WasmTableObject::cast(r.builder().instance_object()->tables().get(0)),
+      isolate);
+  auto f0 = WasmTableObject::Get(isolate, table, 0);
+  auto f1 = WasmTableObject::Get(isolate, table, 1);
+  auto f2 = WasmTableObject::Get(isolate, table, 2);
+  auto f3 = WasmTableObject::Get(isolate, table, 3);
+  auto f4 = WasmTableObject::Get(isolate, table, 4);
+
+  CheckTable(isolate, table, f0, f1, f2, f3, f4);
+
+  // Non-overlapping, src < dst.
+  r.CheckCallViaJS(0xDEADBEEF, 3, 0, 3);
+  CheckTable(isolate, table, f0, f1, f2, f0, f1);
+
+  // Non-overlapping, dst < src.
+  r.CheckCallViaJS(0xDEADBEEF, 0, 4, 2);
+  CheckTable(isolate, table, f1, f1, f2, f0, f1);
+
+  // Overlapping, src < dst. This is required to copy backward, but the first
+  // access will be out-of-bounds, so nothing changes.
+  r.CheckCallViaJS(0xDEADBEEF, 3, 0, 99);
+  CheckTable(isolate, table, f1, f1, f2, f0, f1);
+
+  // Overlapping, dst < src.
+  r.CheckCallViaJS(0xDEADBEEF, 0, 1, 99);
+  CheckTable(isolate, table, f1, f2, f0, f1, f1);
+}
+
+WASM_EXEC_TEST(TableCopyOob1) {
+  EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
+  WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
+  const uint32_t kTableSize = 5;
+
+  r.builder().AddIndirectFunctionTable(nullptr, kTableSize);
+
+  BUILD(
+      r,
+      WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
+      kExprI32Const, 0);
+
+  r.CheckCallViaJS(0, 0, 0, 1);           // nop
+  r.CheckCallViaJS(0, 0, 0, kTableSize);  // nop
+  r.CheckCallViaJS(0xDEADBEEF, 0, 0, kTableSize + 1);
+  r.CheckCallViaJS(0xDEADBEEF, 1, 0, kTableSize);
+  r.CheckCallViaJS(0xDEADBEEF, 0, 1, kTableSize);
+
+  {
+    const uint32_t big = 1000000;
+    r.CheckCallViaJS(0xDEADBEEF, big, 0, 0);
+    r.CheckCallViaJS(0xDEADBEEF, 0, big, 0);
+  }
+
+  for (uint32_t big = 4294967295; big > 1000; big >>= 1) {
+    r.CheckCallViaJS(0xDEADBEEF, big, 0, 1);
+    r.CheckCallViaJS(0xDEADBEEF, 0, big, 1);
+    r.CheckCallViaJS(0xDEADBEEF, 0, 0, big);
+  }
+
+  for (uint32_t big = -1000; big != 0; big <<= 1) {
+    r.CheckCallViaJS(0xDEADBEEF, big, 0, 1);
+    r.CheckCallViaJS(0xDEADBEEF, 0, big, 1);
+    r.CheckCallViaJS(0xDEADBEEF, 0, 0, big);
+  }
+}
+
 }  // namespace test_run_wasm_bulk_memory
 }  // namespace wasm
 }  // namespace internal
diff --git a/test/cctest/wasm/wasm-run-utils.cc b/test/cctest/wasm/wasm-run-utils.cc
index d205101..6a4b6e3 100644
--- a/test/cctest/wasm/wasm-run-utils.cc
+++ b/test/cctest/wasm/wasm-run-utils.cc
@@ -40,6 +40,8 @@
   }
 
   instance_object_ = InitInstanceObject();
+  Handle<FixedArray> tables(isolate_->factory()->NewFixedArray(0));
+  instance_object_->set_tables(*tables);
 
   if (maybe_import) {
     // Manually compile an import wrapper and insert it into the instance.
@@ -161,6 +163,7 @@
 void TestingModuleBuilder::AddIndirectFunctionTable(
     const uint16_t* function_indexes, uint32_t table_size) {
   auto instance = instance_object();
+  uint32_t table_index = static_cast<uint32_t>(test_module_->tables.size());
   test_module_->tables.emplace_back();
   WasmTable& table = test_module_->tables.back();
   table.initial_size = table_size;
@@ -169,12 +172,29 @@
   table.type = kWasmAnyFunc;
   WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
       instance_object(), table_size);
-  for (uint32_t i = 0; i < table_size; ++i) {
-    WasmFunction& function = test_module_->functions[function_indexes[i]];
-    int sig_id = test_module_->signature_map.Find(*function.sig);
-    IndirectFunctionTableEntry(instance, i)
-        .Set(sig_id, instance, function.func_index);
+  Handle<WasmTableObject> table_obj =
+      WasmTableObject::New(isolate_, table.type, table.initial_size,
+                           table.has_maximum_size, table.maximum_size, nullptr);
+
+  WasmTableObject::AddDispatchTable(isolate_, table_obj, instance_object_,
+                                    table_index);
+
+  if (function_indexes) {
+    for (uint32_t i = 0; i < table_size; ++i) {
+      WasmFunction& function = test_module_->functions[function_indexes[i]];
+      int sig_id = test_module_->signature_map.Find(*function.sig);
+      IndirectFunctionTableEntry(instance, i)
+          .Set(sig_id, instance, function.func_index);
+      WasmTableObject::SetFunctionTablePlaceholder(
+          isolate_, table_obj, i, instance_object_, function_indexes[i]);
+    }
   }
+
+  Handle<FixedArray> old_tables(instance_object_->tables(), isolate_);
+  Handle<FixedArray> new_tables = isolate_->factory()->CopyFixedArrayAndGrow(
+      old_tables, old_tables->length() + 1);
+  new_tables->set(old_tables->length(), *table_obj);
+  instance_object_->set_tables(*new_tables);
 }
 
 uint32_t TestingModuleBuilder::AddBytes(Vector<const byte> bytes) {
diff --git a/test/cctest/wasm/wasm-run-utils.h b/test/cctest/wasm/wasm-run-utils.h
index 27d466f..aa3664b 100644
--- a/test/cctest/wasm/wasm-run-utils.h
+++ b/test/cctest/wasm/wasm-run-utils.h
@@ -181,6 +181,8 @@
   // Wrap the code so it can be called as a JS function.
   Handle<JSFunction> WrapCode(uint32_t index);
 
+  // If function_indexes is {nullptr}, the contents of the table will be
+  // initialized with null functions.
   void AddIndirectFunctionTable(const uint16_t* function_indexes,
                                 uint32_t table_size);
 
@@ -515,15 +517,19 @@
     Handle<JSFunction> jsfunc = jsfuncs_[function_index];
     Handle<Object> global(isolate->context()->global_object(), isolate);
     MaybeHandle<Object> retval =
-        Execution::Call(isolate, jsfunc, global, count, buffer);
+        Execution::TryCall(isolate, jsfunc, global, count, buffer,
+                           Execution::MessageHandling::kReport, nullptr);
 
-    CHECK(!retval.is_null());
-    Handle<Object> result = retval.ToHandleChecked();
-    if (result->IsSmi()) {
-      CHECK_EQ(expected, Smi::ToInt(*result));
+    if (retval.is_null()) {
+      CHECK_EQ(expected, static_cast<double>(0xDEADBEEF));
     } else {
-      CHECK(result->IsHeapNumber());
-      CHECK_DOUBLE_EQ(expected, HeapNumber::cast(*result)->value());
+      Handle<Object> result = retval.ToHandleChecked();
+      if (result->IsSmi()) {
+        CHECK_EQ(expected, Smi::ToInt(*result));
+      } else {
+        CHECK(result->IsHeapNumber());
+        CHECK_DOUBLE_EQ(expected, HeapNumber::cast(*result)->value());
+      }
     }
 
     if (builder_.interpret()) {
diff --git a/test/mjsunit/wasm/table-copy.js b/test/mjsunit/wasm/table-copy.js
index dab2a0e..db0dc83 100644
--- a/test/mjsunit/wasm/table-copy.js
+++ b/test/mjsunit/wasm/table-copy.js
@@ -6,241 +6,18 @@
 
 load("test/mjsunit/wasm/wasm-module-builder.js");
 
-(function TestTableCopyInbounds() {
-  print(arguments.callee.name);
-  let builder = new WasmModuleBuilder();
-  let sig_v_iii = builder.addType(kSig_v_iii);
-  let kTableSize = 5;
-
-  builder.setTableBounds(kTableSize, kTableSize);
-
-  builder.addFunction("copy", sig_v_iii)
-    .addBody([
-      kExprGetLocal, 0,
-      kExprGetLocal, 1,
-      kExprGetLocal, 2,
-      kNumericPrefix, kExprTableCopy, kTableZero, kTableZero])
-    .exportAs("copy");
-
-  let instance = builder.instantiate();
-  let copy = instance.exports.copy;
-  for (let i = 0; i <= kTableSize; i++) {
-    copy(0, 0, i); // nop
-    copy(0, i, kTableSize - i);
-    copy(i, 0, kTableSize - i);
-  }
-})();
-
 function addFunction(builder, k) {
   let m = builder.addFunction("", kSig_i_v)
       .addBody([...wasmI32Const(k)]);
   return m;
 }
 
-function addFunctions(builder, count) {
-  let o = {};
-  for (var i = 0; i < count; i++) {
-    o[`f${i}`] = addFunction(builder, i);
-  }
-  return o;
-}
-
-function assertTable(obj, ...elems) {
-  for (var i = 0; i < elems.length; i++) {
-    assertEquals(elems[i], obj.get(i));
-  }
-}
-
-(function TestTableCopyElems() {
-  print(arguments.callee.name);
-
-  let builder = new WasmModuleBuilder();
-  let sig_v_iii = builder.addType(kSig_v_iii);
-  let kTableSize = 5;
-
-  builder.setTableBounds(kTableSize, kTableSize);
-
-  {
-    let o = addFunctions(builder, kTableSize);
-    builder.addElementSegment(0, 0, false,
-       [o.f0.index, o.f1.index, o.f2.index, o.f3.index, o.f4.index]);
-  }
-
-  builder.addFunction("copy", sig_v_iii)
-    .addBody([
-      kExprGetLocal, 0,
-      kExprGetLocal, 1,
-      kExprGetLocal, 2,
-      kNumericPrefix, kExprTableCopy, kTableZero, kTableZero])
-    .exportAs("copy");
-
-  builder.addExportOfKind("table", kExternalTable, 0);
-
-  let instance = builder.instantiate();
-  let table = instance.exports.table;
-  let f0 = table.get(0), f1 = table.get(1), f2 = table.get(2),
-      f3 = table.get(3), f4 = table.get(4);
-  let copy = instance.exports.copy;
-
-  assertEquals(0, f0());
-  assertEquals(1, f1());
-  assertEquals(2, f2());
-
-  assertTable(table, f0, f1, f2, f3, f4);
-  copy(0, 1, 1);
-  assertTable(table, f1, f1, f2, f3, f4);
-  copy(0, 1, 2);
-  assertTable(table, f1, f2, f2, f3, f4);
-  copy(3, 0, 2);
-  assertTable(table, f1, f2, f2, f1, f2);
-  copy(1, 0, 2);
-  assertTable(table, f1, f1, f2, f1, f2);
-})();
-
 function assertCall(call, ...elems) {
   for (var i = 0; i < elems.length; i++) {
     assertEquals(elems[i], call(i));
   }
 }
 
-(function TestTableCopyCalls() {
-  print(arguments.callee.name);
-
-  let builder = new WasmModuleBuilder();
-  let sig_v_iii = builder.addType(kSig_v_iii);
-  let sig_i_i = builder.addType(kSig_i_i);
-  let sig_i_v = builder.addType(kSig_i_v);
-  let kTableSize = 5;
-
-  builder.setTableBounds(kTableSize, kTableSize);
-
-  {
-    let o = addFunctions(builder, 5);
-    builder.addElementSegment(0, 0, false,
-       [o.f0.index, o.f1.index, o.f2.index, o.f3.index, o.f4.index]);
-  }
-
-  builder.addFunction("copy", sig_v_iii)
-    .addBody([
-      kExprGetLocal, 0,
-      kExprGetLocal, 1,
-      kExprGetLocal, 2,
-      kNumericPrefix, kExprTableCopy, kTableZero, kTableZero])
-    .exportAs("copy");
-
-  builder.addFunction("call", sig_i_i)
-    .addBody([
-      kExprGetLocal, 0,
-      kExprCallIndirect, sig_i_v, kTableZero])
-    .exportAs("call");
-
-  let instance = builder.instantiate();
-  let copy = instance.exports.copy;
-  let call = instance.exports.call;
-
-  assertCall(call, 0, 1, 2, 3, 4);
-  copy(0, 1, 1);
-  assertCall(call, 1, 1, 2, 3, 4);
-  copy(0, 1, 2);
-  assertCall(call, 1, 2, 2, 3, 4);
-  copy(3, 0, 2);
-  assertCall(call, 1, 2, 2, 1, 2);
-})();
-
-(function TestTableCopyOobWrites() {
-  print(arguments.callee.name);
-
-  let builder = new WasmModuleBuilder();
-  let sig_v_iii = builder.addType(kSig_v_iii);
-  let kTableSize = 5;
-
-  builder.setTableBounds(kTableSize, kTableSize);
-
-  {
-    let o = addFunctions(builder, kTableSize);
-    builder.addElementSegment(0, 0, false,
-       [o.f0.index, o.f1.index, o.f2.index]);
-  }
-
-  builder.addFunction("copy", sig_v_iii)
-    .addBody([
-      kExprGetLocal, 0,
-      kExprGetLocal, 1,
-      kExprGetLocal, 2,
-      kNumericPrefix, kExprTableCopy, kTableZero, kTableZero])
-    .exportAs("copy");
-
-  builder.addExportOfKind("table", kExternalTable, 0);
-
-  let instance = builder.instantiate();
-  let table = instance.exports.table;
-  let f0 = table.get(0), f1 = table.get(1), f2 = table.get(2);
-  let copy = instance.exports.copy;
-
-  // Non-overlapping, src < dst.
-  assertThrows(() => copy(3, 0, 3));
-  assertTable(table, f0, f1, f2, f0, f1);
-
-  // Non-overlapping, dst < src.
-  assertThrows(() => copy(0, 4, 2));
-  assertTable(table, f1, f1, f2, f0, f1);
-
-  // Overlapping, src < dst. This is required to copy backward, but the first
-  // access will be out-of-bounds, so nothing changes.
-  assertThrows(() => copy(3, 0, 99));
-  assertTable(table, f1, f1, f2, f0, f1);
-
-  // Overlapping, dst < src.
-  assertThrows(() => copy(0, 1, 99));
-  assertTable(table, f1, f2, f0, f1, f1);
-})();
-
-(function TestTableCopyOob1() {
-  print(arguments.callee.name);
-
-  let builder = new WasmModuleBuilder();
-  let sig_v_iii = builder.addType(kSig_v_iii);
-  let kTableSize = 5;
-
-  builder.setTableBounds(kTableSize, kTableSize);
-
-  builder.addFunction("copy", sig_v_iii)
-    .addBody([
-      kExprGetLocal, 0,
-      kExprGetLocal, 1,
-      kExprGetLocal, 2,
-      kNumericPrefix, kExprTableCopy, kTableZero, kTableZero])
-    .exportAs("copy");
-
-  let instance = builder.instantiate();
-  let copy = instance.exports.copy;
-  copy(0, 0, 1); // nop
-  copy(0, 0, kTableSize); // nop
-  assertThrows(() => copy(0, 0, kTableSize+1));
-  assertThrows(() => copy(1, 0, kTableSize));
-  assertThrows(() => copy(0, 1, kTableSize));
-
-  {
-    let big = 1000000;
-    assertThrows(() => copy(big, 0, 0));
-    assertThrows(() => copy(0, big, 0));
-  }
-
-
-  for (let big = 4294967295; big > 1000; big >>>= 1) {
-    assertThrows(() => copy(big, 0, 1));
-    assertThrows(() => copy(0, big, 1));
-    assertThrows(() => copy(0, 0, big));
-  }
-
-  for (let big = -1000; big != 0; big <<= 1) {
-    assertThrows(() => copy(big, 0, 1));
-    assertThrows(() => copy(0, big, 1));
-    assertThrows(() => copy(0, 0, big));
-  }
-
-})();
-
 (function TestTableCopyShared() {
   print(arguments.callee.name);
   let kTableSize = 5;