Commit 4786c5c8 authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[wasm] Support table.copy for multiple tables

Even though this is not spec'ed yet, it's good to have an implementation
so that we can use clusterfuzz on it.

I changed the parameter order (hopefully) everywhere to
(table_dst_index, table_src_index, ...). This corresponds to the
(dst, src, ...) parameter order for the entry indices.

R=binji@chromium.org

Bug: v8:7581 chromium:980475
Change-Id: I2fb36ffd4bb2f2be5b22c8366732295fa6759236
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1698386Reviewed-by: 's avatarBen Smith <binji@chromium.org>
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62661}
parent 13a04aba
......@@ -4837,13 +4837,13 @@ Node* WasmGraphBuilder::ElemDrop(uint32_t elem_segment_index,
mcgraph()->Int32Constant(1), Effect(), Control()));
}
Node* WasmGraphBuilder::TableCopy(uint32_t table_src_index,
uint32_t table_dst_index, Node* dst,
Node* WasmGraphBuilder::TableCopy(uint32_t table_dst_index,
uint32_t table_src_index, Node* dst,
Node* src, Node* size,
wasm::WasmCodePosition position) {
Node* args[] = {
graph()->NewNode(mcgraph()->common()->NumberConstant(table_src_index)),
graph()->NewNode(mcgraph()->common()->NumberConstant(table_dst_index)),
graph()->NewNode(mcgraph()->common()->NumberConstant(table_src_index)),
BuildConvertUint32ToSmiWithSaturation(dst, FLAG_wasm_max_table_size),
BuildConvertUint32ToSmiWithSaturation(src, FLAG_wasm_max_table_size),
BuildConvertUint32ToSmiWithSaturation(size, FLAG_wasm_max_table_size)};
......
......@@ -405,7 +405,7 @@ class WasmGraphBuilder {
Node* TableInit(uint32_t table_index, uint32_t elem_segment_index, Node* dst,
Node* src, Node* size, wasm::WasmCodePosition position);
Node* ElemDrop(uint32_t elem_segment_index, wasm::WasmCodePosition position);
Node* TableCopy(uint32_t table_src_index, uint32_t table_dst_index, Node* dst,
Node* TableCopy(uint32_t table_dst_index, uint32_t table_src_index, Node* dst,
Node* src, Node* size, wasm::WasmCodePosition position);
Node* TableGrow(uint32_t table_index, Node* value, Node* delta);
Node* TableSize(uint32_t table_index);
......
......@@ -502,16 +502,18 @@ RUNTIME_FUNCTION(Runtime_WasmTableInit) {
RUNTIME_FUNCTION(Runtime_WasmTableCopy) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
DCHECK(isolate->context().is_null());
isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate));
auto instance =
Handle<WasmInstanceObject>(GetWasmInstanceOnStackTop(isolate), isolate);
CONVERT_UINT32_ARG_CHECKED(table_src_index, 0);
CONVERT_UINT32_ARG_CHECKED(table_dst_index, 1);
CONVERT_UINT32_ARG_CHECKED(table_dst_index, 0);
CONVERT_UINT32_ARG_CHECKED(table_src_index, 1);
CONVERT_UINT32_ARG_CHECKED(dst, 2);
CONVERT_UINT32_ARG_CHECKED(src, 3);
CONVERT_UINT32_ARG_CHECKED(count, 4);
bool oob = !WasmInstanceObject::CopyTableEntries(
isolate, instance, table_src_index, table_dst_index, dst, src, count);
isolate, instance, table_dst_index, table_src_index, dst, src, count);
if (oob) return ThrowTableOutOfBounds(isolate, instance);
return ReadOnlyRoots(isolate).undefined_value();
}
......
......@@ -574,14 +574,14 @@ struct ElemDropImmediate {
template <Decoder::ValidateFlag validate>
struct TableCopyImmediate {
TableIndexImmediate<validate> table_src;
TableIndexImmediate<validate> table_dst;
TableIndexImmediate<validate> table_src;
unsigned length = 0;
inline TableCopyImmediate(Decoder* decoder, const byte* pc) {
table_src = TableIndexImmediate<validate>(decoder, pc + 1);
table_dst =
TableIndexImmediate<validate>(decoder, pc + 1 + table_src.length);
table_dst = TableIndexImmediate<validate>(decoder, pc + 1);
table_src =
TableIndexImmediate<validate>(decoder, pc + 1 + table_dst.length);
length = table_src.length + table_dst.length;
}
};
......
......@@ -567,7 +567,7 @@ class WasmGraphBuildingInterface {
void TableCopy(FullDecoder* decoder, const TableCopyImmediate<validate>& imm,
Vector<Value> args) {
BUILD(TableCopy, imm.table_src.index, imm.table_dst.index, args[0].node,
BUILD(TableCopy, imm.table_dst.index, imm.table_src.index, args[0].node,
args[1].node, args[2].node, decoder->position());
}
......
......@@ -1589,11 +1589,6 @@ Address IndirectFunctionTableEntry::target() const {
: table_->targets()[index_];
}
void IndirectFunctionTableEntry::CopyFrom(
const IndirectFunctionTableEntry& that) {
Set(that.sig_id(), that.target(), that.object_ref());
}
void ImportedFunctionEntry::SetWasmToJs(
Isolate* isolate, Handle<JSReceiver> callable,
const wasm::WasmCode* wasm_to_js_wrapper) {
......@@ -1830,86 +1825,40 @@ int WasmInstanceObject::IndirectFunctionTableSize(
return table->size();
}
namespace {
void CopyTableEntriesImpl(Handle<WasmInstanceObject> instance, uint32_t dst,
uint32_t src, uint32_t count, bool copy_backward) {
DCHECK(IsInBounds(dst, count, instance->indirect_function_table_size()));
if (copy_backward) {
for (uint32_t i = count; i > 0; i--) {
// TODO(ahaas): Use a table index here once table.copy supports multiple
// tables.
auto to_entry = IndirectFunctionTableEntry(instance, 0, dst + i - 1);
auto from_entry = IndirectFunctionTableEntry(instance, 0, src + i - 1);
to_entry.CopyFrom(from_entry);
}
} else {
for (uint32_t i = 0; i < count; i++) {
// TODO(ahaas): Use a table index here once table.copy supports multiple
// tables.
auto to_entry = IndirectFunctionTableEntry(instance, 0, dst + i);
auto from_entry = IndirectFunctionTableEntry(instance, 0, src + i);
to_entry.CopyFrom(from_entry);
}
}
}
} // namespace
// static
bool WasmInstanceObject::CopyTableEntries(Isolate* isolate,
Handle<WasmInstanceObject> instance,
uint32_t table_src_index,
uint32_t table_dst_index,
uint32_t table_src_index,
uint32_t dst, uint32_t src,
uint32_t count) {
if (static_cast<int>(table_dst_index) >= instance->tables().length()) {
return false;
}
if (static_cast<int>(table_src_index) >= instance->tables().length()) {
return false;
}
// TODO(titzer): multiple tables in TableCopy
CHECK_EQ(0, table_src_index);
CHECK_EQ(0, table_dst_index);
auto table = handle(
CHECK_LT(table_dst_index, instance->tables().length());
CHECK_LT(table_src_index, instance->tables().length());
auto table_dst = handle(
WasmTableObject::cast(instance->tables().get(table_dst_index)), isolate);
auto table_src = handle(
WasmTableObject::cast(instance->tables().get(table_src_index)), isolate);
uint32_t max = static_cast<uint32_t>(table->entries().length());
uint32_t max_dst = static_cast<uint32_t>(table_dst->entries().length());
uint32_t max_src = static_cast<uint32_t>(table_src->entries().length());
bool copy_backward = src < dst && dst - src < count;
bool ok = ClampToBounds(dst, &count, max);
bool ok = ClampToBounds(dst, &count, max_dst);
// Use & instead of && so the clamp is not short-circuited.
ok &= ClampToBounds(src, &count, max);
ok &= ClampToBounds(src, &count, max_src);
// If performing a partial copy when copying backward, then the first access
// will be out-of-bounds, so no entries should be copied.
if (copy_backward && !ok) return ok;
if (dst == src || count == 0) return ok; // no-op
// Broadcast table copy operation to all instances that import this table.
Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate);
for (int i = 0; i < dispatch_tables->length();
i += kDispatchTableNumElements) {
Handle<WasmInstanceObject> target_instance(
WasmInstanceObject::cast(
dispatch_tables->get(i + kDispatchTableInstanceOffset)),
isolate);
CopyTableEntriesImpl(target_instance, dst, src, count, copy_backward);
// no-op
if ((dst == src && table_dst_index == table_src_index) || count == 0) {
return ok;
}
// Copy the function entries.
auto dst_table = handle(
WasmTableObject::cast(instance->tables().get(table_dst_index)), isolate);
auto src_table = handle(
WasmTableObject::cast(instance->tables().get(table_src_index)), isolate);
if (copy_backward) {
for (uint32_t i = count; i > 0; i--) {
dst_table->entries().set(dst + i - 1,
src_table->entries().get(src + i - 1));
}
} else {
for (uint32_t i = 0; i < count; i++) {
dst_table->entries().set(dst + i, src_table->entries().get(src + i));
}
for (uint32_t i = 0; i < count; ++i) {
uint32_t src_index = copy_backward ? (src + count - i - 1) : src + i;
uint32_t dst_index = copy_backward ? (dst + count - i - 1) : dst + i;
auto value = WasmTableObject::Get(isolate, table_src, src_index);
WasmTableObject::Set(isolate, table_dst, dst_index, value);
}
return ok;
}
......
......@@ -74,8 +74,6 @@ class IndirectFunctionTableEntry {
int target_func_index);
void Set(int sig_id, Address call_target, Object ref);
void CopyFrom(const IndirectFunctionTableEntry& that);
Object object_ref() const;
int sig_id() const;
Address target() const;
......@@ -580,8 +578,8 @@ class WasmInstanceObject : public JSObject {
// Copies table entries. Returns {false} if the ranges are out-of-bounds.
static bool CopyTableEntries(Isolate* isolate,
Handle<WasmInstanceObject> instance,
uint32_t table_src_index,
uint32_t table_dst_index, uint32_t dst,
uint32_t table_dst_index,
uint32_t table_src_index, uint32_t dst,
uint32_t src,
uint32_t count) V8_WARN_UNUSED_RESULT;
......
......@@ -354,14 +354,18 @@ WASM_EXEC_TEST(DataDropThenMemoryInit) {
CHECK_EQ(0xDEADBEEF, r.Call());
}
WASM_EXEC_TEST(TableCopyInbounds) {
void TestTableCopyInbounds(ExecutionTier execution_tier, int table_dst,
int table_src) {
EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
const uint32_t kTableSize = 5;
// Add 10 function tables, even though we only test one table.
for (int i = 0; i < 10; ++i) {
r.builder().AddIndirectFunctionTable(nullptr, kTableSize);
BUILD(
r,
WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
}
BUILD(r,
WASM_TABLE_COPY(table_dst, table_src, WASM_GET_LOCAL(0),
WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
kExprI32Const, 0);
for (uint32_t i = 0; i <= kTableSize; ++i) {
......@@ -371,6 +375,25 @@ WASM_EXEC_TEST(TableCopyInbounds) {
}
}
WASM_EXEC_TEST(TableCopyInboundsFrom0To0) {
TestTableCopyInbounds(execution_tier, 0, 0);
}
WASM_EXEC_TEST(TableCopyInboundsFrom3To0) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
TestTableCopyInbounds(execution_tier, 3, 0);
}
WASM_EXEC_TEST(TableCopyInboundsFrom5To9) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
TestTableCopyInbounds(execution_tier, 5, 9);
}
WASM_EXEC_TEST(TableCopyInboundsFrom6To6) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
TestTableCopyInbounds(execution_tier, 6, 6);
}
namespace {
template <typename... Args>
void CheckTable(Isolate* isolate, Handle<WasmTableObject> table, Args... args) {
......@@ -552,7 +575,8 @@ WASM_EXEC_TEST(TableInitOob9) {
TestTableInitOob(execution_tier, 9);
}
WASM_EXEC_TEST(TableCopyElems) {
void TestTableCopyElems(ExecutionTier execution_tier, int table_dst,
int table_src) {
EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
Isolate* isolate = CcTest::InitIsolateOnce();
HandleScope scope(isolate);
......@@ -569,24 +593,29 @@ WASM_EXEC_TEST(TableCopyElems) {
function_indexes[i] = fn.function_index();
}
for (int i = 0; i < 10; ++i) {
r.builder().AddIndirectFunctionTable(function_indexes, kTableSize);
}
BUILD(
r,
WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
BUILD(r,
WASM_TABLE_COPY(table_dst, table_src, WASM_GET_LOCAL(0),
WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
kExprI32Const, 0);
r.builder().FreezeSignatureMapAndInitializeWrapperCache();
auto table = handle(
WasmTableObject::cast(r.builder().instance_object()->tables().get(0)),
auto table =
handle(WasmTableObject::cast(
r.builder().instance_object()->tables().get(table_dst)),
isolate);
r.CheckCallViaJS(0, 0, 0, kTableSize);
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);
if (table_dst == table_src) {
CheckTable(isolate, table, f0, f1, f2, f3, f4);
r.CheckCallViaJS(0, 0, 1, 1);
CheckTable(isolate, table, f1, f1, f2, f3, f4);
......@@ -596,9 +625,40 @@ WASM_EXEC_TEST(TableCopyElems) {
CheckTable(isolate, table, f1, f2, f2, f1, f2);
r.CheckCallViaJS(0, 1, 0, 2);
CheckTable(isolate, table, f1, f1, f2, f1, f2);
} else {
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, f0, f1);
r.CheckCallViaJS(0, 1, 0, 2);
CheckTable(isolate, table, f1, f0, f1, f0, f1);
}
}
WASM_EXEC_TEST(TableCopyElemsFrom0To0) {
TestTableCopyElems(execution_tier, 0, 0);
}
WASM_EXEC_TEST(TableCopyElemsFrom3To0) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
TestTableCopyElems(execution_tier, 3, 0);
}
WASM_EXEC_TEST(TableCopyElemsFrom5To9) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
TestTableCopyElems(execution_tier, 5, 9);
}
WASM_EXEC_TEST(TableCopyCalls) {
WASM_EXEC_TEST(TableCopyElemsFrom6To6) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
TestTableCopyElems(execution_tier, 6, 6);
}
void TestTableCopyCalls(ExecutionTier execution_tier, int table_dst,
int table_src) {
EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
Isolate* isolate = CcTest::InitIsolateOnce();
HandleScope scope(isolate);
......@@ -615,21 +675,26 @@ WASM_EXEC_TEST(TableCopyCalls) {
function_indexes[i] = fn.function_index();
}
for (int i = 0; i < 10; ++i) {
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)));
BUILD(call,
WASM_CALL_INDIRECT_TABLE0(table_dst, 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)),
BUILD(r,
WASM_TABLE_COPY(table_dst, table_src, 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)),
auto table =
handle(WasmTableObject::cast(
r.builder().instance_object()->tables().get(table_dst)),
isolate);
if (table_dst == table_src) {
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);
......@@ -637,9 +702,38 @@ WASM_EXEC_TEST(TableCopyCalls) {
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);
} else {
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, 0, 1);
}
}
WASM_EXEC_TEST(TableCopyCallsFrom0To0) {
TestTableCopyCalls(execution_tier, 0, 0);
}
WASM_EXEC_TEST(TableCopyOobWrites) {
WASM_EXEC_TEST(TableCopyCallsFrom3To0) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
TestTableCopyCalls(execution_tier, 3, 0);
}
WASM_EXEC_TEST(TableCopyCallsFrom5To9) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
TestTableCopyCalls(execution_tier, 5, 9);
}
WASM_EXEC_TEST(TableCopyCallsFrom6To6) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
TestTableCopyCalls(execution_tier, 6, 6);
}
void TestTableCopyOobWrites(ExecutionTier execution_tier, int table_dst,
int table_src) {
EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
Isolate* isolate = CcTest::InitIsolateOnce();
HandleScope scope(isolate);
......@@ -656,18 +750,23 @@ WASM_EXEC_TEST(TableCopyOobWrites) {
function_indexes[i] = fn.function_index();
}
for (int i = 0; i < 10; ++i) {
r.builder().AddIndirectFunctionTable(function_indexes, kTableSize);
}
BUILD(
r,
WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
BUILD(r,
WASM_TABLE_COPY(table_dst, table_src, WASM_GET_LOCAL(0),
WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
kExprI32Const, 0);
r.builder().FreezeSignatureMapAndInitializeWrapperCache();
auto table = handle(
WasmTableObject::cast(r.builder().instance_object()->tables().get(0)),
auto table =
handle(WasmTableObject::cast(
r.builder().instance_object()->tables().get(table_dst)),
isolate);
// Fill the dst table with values from the src table, to make checks easier.
r.CheckCallViaJS(0, 0, 0, kTableSize);
auto f0 = WasmTableObject::Get(isolate, table, 0);
auto f1 = WasmTableObject::Get(isolate, table, 1);
auto f2 = WasmTableObject::Get(isolate, table, 2);
......@@ -682,28 +781,62 @@ WASM_EXEC_TEST(TableCopyOobWrites) {
// Non-overlapping, dst < src.
r.CheckCallViaJS(0xDEADBEEF, 0, 4, 2);
if (table_dst == table_src) {
CheckTable(isolate, table, f1, f1, f2, f0, f1);
} else {
CheckTable(isolate, table, f4, 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);
if (table_dst == table_src) {
CheckTable(isolate, table, f1, f1, f2, f0, f1);
} else {
CheckTable(isolate, table, f4, f1, f2, f0, f1);
}
// Overlapping, dst < src.
r.CheckCallViaJS(0xDEADBEEF, 0, 1, 99);
if (table_dst == table_src) {
CheckTable(isolate, table, f1, f2, f0, f1, f1);
} else {
CheckTable(isolate, table, f1, f2, f3, f4, f1);
}
}
WASM_EXEC_TEST(TableCopyOob1) {
WASM_EXEC_TEST(TableCopyOobWritesFrom0To0) {
TestTableCopyOobWrites(execution_tier, 0, 0);
}
WASM_EXEC_TEST(TableCopyOobWritesFrom3To0) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
TestTableCopyOobWrites(execution_tier, 3, 0);
}
WASM_EXEC_TEST(TableCopyOobWritesFrom5To9) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
TestTableCopyOobWrites(execution_tier, 5, 9);
}
WASM_EXEC_TEST(TableCopyOobWritesFrom6To6) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
TestTableCopyOobWrites(execution_tier, 6, 6);
}
void TestTableCopyOob1(ExecutionTier execution_tier, int table_dst,
int table_src) {
EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
const uint32_t kTableSize = 5;
for (int i = 0; i < 10; ++i) {
r.builder().AddIndirectFunctionTable(nullptr, kTableSize);
}
BUILD(
r,
WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
BUILD(r,
WASM_TABLE_COPY(table_dst, table_src, WASM_GET_LOCAL(0),
WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
kExprI32Const, 0);
r.CheckCallViaJS(0, 0, 0, 1); // nop
......@@ -731,6 +864,25 @@ WASM_EXEC_TEST(TableCopyOob1) {
}
}
WASM_EXEC_TEST(TableCopyOob1From0To0) {
TestTableCopyOob1(execution_tier, 0, 0);
}
WASM_EXEC_TEST(TableCopyOob1From3To0) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
TestTableCopyOob1(execution_tier, 3, 0);
}
WASM_EXEC_TEST(TableCopyOob1From5To9) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
TestTableCopyOob1(execution_tier, 5, 9);
}
WASM_EXEC_TEST(TableCopyOob1From6To6) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
TestTableCopyOob1(execution_tier, 6, 6);
}
WASM_EXEC_TEST(ElemDropTwice) {
EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
WasmRunner<uint32_t> r(execution_tier);
......
......@@ -201,7 +201,7 @@ void TestingModuleBuilder::AddIndirectFunctionTable(
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, 0, i)
IndirectFunctionTableEntry(instance, table_index, i)
.Set(sig_id, instance, function.func_index);
WasmTableObject::SetFunctionTablePlaceholder(
isolate_, table_obj, i, instance_object_, function_indexes[i]);
......
......@@ -632,8 +632,9 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
dst, src, size, WASM_NUMERIC_OP(kExprTableInit), U32V_1(seg), \
static_cast<byte>(table)
#define WASM_ELEM_DROP(seg) WASM_NUMERIC_OP(kExprElemDrop), U32V_1(seg)
#define WASM_TABLE_COPY(dst, src, size) \
dst, src, size, WASM_NUMERIC_OP(kExprTableCopy), TABLE_ZERO, TABLE_ZERO
#define WASM_TABLE_COPY(table_dst, table_src, dst, src, size) \
dst, src, size, WASM_NUMERIC_OP(kExprTableCopy), \
static_cast<byte>(table_dst), static_cast<byte>(table_src)
#define WASM_TABLE_GROW(table, initial_value, delta) \
initial_value, delta, WASM_NUMERIC_OP(kExprTableGrow), \
static_cast<byte>(table)
......
......@@ -3218,10 +3218,11 @@ TEST_F(FunctionBodyDecoderTest, TableCopy) {
builder.InitializeTable();
module = builder.module();
ExpectFailure(sigs.v_v(), {WASM_TABLE_COPY(WASM_ZERO, WASM_ZERO, WASM_ZERO)});
ExpectFailure(sigs.v_v(),
{WASM_TABLE_COPY(0, 0, WASM_ZERO, WASM_ZERO, WASM_ZERO)});
WASM_FEATURE_SCOPE(bulk_memory);
ExpectValidates(sigs.v_v(),
{WASM_TABLE_COPY(WASM_ZERO, WASM_ZERO, WASM_ZERO)});
{WASM_TABLE_COPY(0, 0, WASM_ZERO, WASM_ZERO, WASM_ZERO)});
}
TEST_F(FunctionBodyDecoderTest, TableGrow) {
......@@ -3302,7 +3303,57 @@ TEST_F(FunctionBodyDecoderTest, TableOpsWithoutTable) {
ExpectFailure(sigs.v_v(),
{WASM_TABLE_INIT(0, 0, WASM_ZERO, WASM_ZERO, WASM_ZERO)});
ExpectFailure(sigs.v_v(),
{WASM_TABLE_COPY(WASM_ZERO, WASM_ZERO, WASM_ZERO)});
{WASM_TABLE_COPY(0, 0, WASM_ZERO, WASM_ZERO, WASM_ZERO)});
}
}
TEST_F(FunctionBodyDecoderTest, TableCopyMultiTable) {
WASM_FEATURE_SCOPE(bulk_memory);
WASM_FEATURE_SCOPE(anyref);
{
TestModuleBuilder builder;
builder.AddTable(kWasmAnyRef, 10, true, 20);
builder.AddPassiveElementSegment();
module = builder.module();
// We added one table, therefore table.copy on table 0 should work.
int table_src = 0;
int table_dst = 0;
ExpectValidates(sigs.v_v(),
{WASM_TABLE_COPY(table_dst, table_src, WASM_ZERO, WASM_ZERO,
WASM_ZERO)});
// There is only one table, so table.copy on table 1 should fail.
table_src = 0;
table_dst = 1;
ExpectFailure(sigs.v_v(), {WASM_TABLE_COPY(table_dst, table_src, WASM_ZERO,
WASM_ZERO, WASM_ZERO)});
table_src = 1;
table_dst = 0;
ExpectFailure(sigs.v_v(), {WASM_TABLE_COPY(table_dst, table_src, WASM_ZERO,
WASM_ZERO, WASM_ZERO)});
}
{
TestModuleBuilder builder;
builder.AddTable(kWasmAnyRef, 10, true, 20);
builder.AddTable(kWasmAnyRef, 10, true, 20);
builder.AddPassiveElementSegment();
module = builder.module();
// We added two tables, therefore table.copy on table 0 should work.
int table_src = 0;
int table_dst = 0;
ExpectValidates(sigs.v_v(),
{WASM_TABLE_COPY(table_dst, table_src, WASM_ZERO, WASM_ZERO,
WASM_ZERO)});
// Also table.copy on table 1 should work now.
table_src = 1;
table_dst = 0;
ExpectValidates(sigs.v_v(),
{WASM_TABLE_COPY(table_dst, table_src, WASM_ZERO, WASM_ZERO,
WASM_ZERO)});
table_src = 0;
table_dst = 1;
ExpectValidates(sigs.v_v(),
{WASM_TABLE_COPY(table_dst, table_src, WASM_ZERO, WASM_ZERO,
WASM_ZERO)});
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment