From 21719af9ae5d6b2092ad126937eb4ef1c2301e2a Mon Sep 17 00:00:00 2001 From: Andreas Haas Date: Fri, 21 Jun 2019 15:02:01 +0200 Subject: [PATCH] [wasm] Support table.copy for anyref tables The table.copy instruction used the indirect_function_table_size field of the instance for bounds-checks. However, when Table 0 is of type anyref, this field is not set. Now we use the actual size of the table instead. R=clemensh@chromium.org Bug: chromium:977101 Change-Id: Idda9cfe228141877747ed9a824936a1232f58cf8 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669695 Commit-Queue: Andreas Haas Reviewed-by: Clemens Hammacher Cr-Commit-Position: refs/heads/master@{#62315} --- src/wasm/wasm-objects.cc | 7 ++- test/mjsunit/wasm/table-copy-anyref.js | 72 ++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 test/mjsunit/wasm/table-copy-anyref.js diff --git a/src/wasm/wasm-objects.cc b/src/wasm/wasm-objects.cc index 71dafcb9ec..f6d721f629 100644 --- a/src/wasm/wasm-objects.cc +++ b/src/wasm/wasm-objects.cc @@ -1778,7 +1778,9 @@ bool WasmInstanceObject::CopyTableEntries(Isolate* isolate, // TODO(titzer): multiple tables in TableCopy CHECK_EQ(0, table_src_index); CHECK_EQ(0, table_dst_index); - auto max = instance->indirect_function_table_size(); + auto table = handle( + WasmTableObject::cast(instance->tables().get(table_src_index)), isolate); + uint32_t max = static_cast(table->entries().length()); bool copy_backward = src < dst && dst - src < count; bool ok = ClampToBounds(dst, &count, max); // Use & instead of && so the clamp is not short-circuited. @@ -1790,9 +1792,6 @@ bool WasmInstanceObject::CopyTableEntries(Isolate* isolate, if (dst == src || count == 0) return ok; // no-op - // TODO(titzer): multiple tables in TableCopy - auto table = handle( - WasmTableObject::cast(instance->tables().get(table_src_index)), isolate); // Broadcast table copy operation to all instances that import this table. Handle dispatch_tables(table->dispatch_tables(), isolate); for (int i = 0; i < dispatch_tables->length(); diff --git a/test/mjsunit/wasm/table-copy-anyref.js b/test/mjsunit/wasm/table-copy-anyref.js new file mode 100644 index 0000000000..453296a64b --- /dev/null +++ b/test/mjsunit/wasm/table-copy-anyref.js @@ -0,0 +1,72 @@ +// Copyright 2019 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. + +// Flags: --experimental-wasm-bulk-memory --experimental-wasm-anyref + +load('test/mjsunit/wasm/wasm-module-builder.js'); + +let kTableSize = 5; + +let table = new WebAssembly.Table( + {element: 'anyref', initial: kTableSize, maximum: kTableSize}); + +let builder = new WasmModuleBuilder(); +builder.addImportedTable('m', 'table', kTableSize, kTableSize, kWasmAnyRef); +builder.addTable(kWasmAnyFunc, 1000); + +builder.addFunction('copy', kSig_v_iii) + .addBody([ + kExprGetLocal, 0, kExprGetLocal, 1, kExprGetLocal, 2, kNumericPrefix, + kExprTableCopy, kTableZero, kTableZero + ]) + .exportFunc(); + +const instance = builder.instantiate({m: {table: table}}); + +function resetTable() { + table.set(0, 1000); + table.set(1, 1001); + table.set(2, 1002); + table.set(3, 1003); + table.set(4, 1004); +} + +function assertTable(values) { + for (let i = 0; i < kTableSize; ++i) { + assertEquals(table.get(i), values[i]); + } +} + +resetTable(); +instance.exports.copy(0, 1, 1); +assertTable([1001, 1001, 1002, 1003, 1004]); + +resetTable(); +instance.exports.copy(0, 1, 2); +assertTable([1001, 1002, 1002, 1003, 1004]); + +resetTable(); +instance.exports.copy(3, 0, 2); +assertTable([1000, 1001, 1002, 1000, 1001]); + +// Non-overlapping, src < dst. +resetTable(); +assertTraps(kTrapTableOutOfBounds, () => instance.exports.copy(3, 0, 3)); +assertTable([1000, 1001, 1002, 1000, 1001]); + +// Non-overlapping, dst < src. +resetTable(); +assertTraps(kTrapTableOutOfBounds, () => instance.exports.copy(0, 4, 2)); +assertTable([1004, 1001, 1002, 1003, 1004]); + +// Overlapping, src < dst. This is required to copy backward, but the first +// access will be out-of-bounds, so nothing changes. +resetTable(); +assertTraps(kTrapTableOutOfBounds, () => instance.exports.copy(3, 0, 99)); +assertTable([1000, 1001, 1002, 1003, 1004]); + +// Overlapping, dst < src. +resetTable(); +assertTraps(kTrapTableOutOfBounds, () => instance.exports.copy(0, 1, 99)); +assertTable([1001, 1002, 1003, 1004, 1004]);