Commit b86a506d authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[wasm-c-api] Add test for Table operations

Change-Id: Id1c46ca22002c358155823e3caae18f0ed9c47f5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1691033
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62651}
parent 44da77fc
......@@ -277,7 +277,10 @@ uint32_t WasmModuleBuilder::AllocateIndirectFunctions(uint32_t count) {
if (count > FLAG_wasm_max_table_size - index) {
return std::numeric_limits<uint32_t>::max();
}
indirect_functions_.resize(indirect_functions_.size() + count);
DCHECK(max_table_size_ == 0 ||
indirect_functions_.size() + count <= max_table_size_);
indirect_functions_.resize(indirect_functions_.size() + count,
WasmElemSegment::kNullIndex);
return index;
}
......@@ -286,6 +289,12 @@ void WasmModuleBuilder::SetIndirectFunction(uint32_t indirect,
indirect_functions_[indirect] = direct;
}
void WasmModuleBuilder::SetMaxTableSize(uint32_t max) {
DCHECK_GE(FLAG_wasm_max_table_size, max);
DCHECK_GE(max, indirect_functions_.size());
max_table_size_ = max;
}
uint32_t WasmModuleBuilder::AddImport(Vector<const char> name,
FunctionSig* sig) {
DCHECK(adding_imports_allowed_);
......@@ -419,7 +428,10 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
buffer->write_u8(kLocalFuncRef);
buffer->write_u8(kHasMaximumFlag);
buffer->write_size(indirect_functions_.size());
buffer->write_size(indirect_functions_.size());
size_t max =
max_table_size_ > 0 ? max_table_size_ : indirect_functions_.size();
DCHECK_GE(max, indirect_functions_.size());
buffer->write_size(max);
FixupSection(buffer, start);
}
......@@ -547,13 +559,24 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
size_t start = EmitSection(kElementSectionCode, buffer);
buffer->write_u8(1); // count of entries
buffer->write_u8(0); // table index
uint32_t first_element = 0;
while (first_element < indirect_functions_.size() &&
indirect_functions_[first_element] == WasmElemSegment::kNullIndex) {
first_element++;
}
uint32_t last_element =
static_cast<uint32_t>(indirect_functions_.size() - 1);
while (last_element >= first_element &&
indirect_functions_[last_element] == WasmElemSegment::kNullIndex) {
last_element--;
}
buffer->write_u8(kExprI32Const); // offset
buffer->write_u32v(0);
buffer->write_u32v(first_element);
buffer->write_u8(kExprEnd);
buffer->write_size(indirect_functions_.size()); // element count
for (auto index : indirect_functions_) {
buffer->write_size(index + function_imports_.size());
uint32_t element_count = last_element - first_element + 1;
buffer->write_size(element_count);
for (uint32_t i = first_element; i <= last_element; i++) {
buffer->write_size(indirect_functions_[i] + function_imports_.size());
}
FixupSection(buffer, start);
......
......@@ -237,8 +237,12 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
bool mutability);
void AddDataSegment(const byte* data, uint32_t size, uint32_t dest);
uint32_t AddSignature(FunctionSig* sig);
// In the current implementation, it's supported to have uninitialized slots
// at the beginning and/or end of the indirect function table, as long as
// the filled slots form a contiguous block in the middle.
uint32_t AllocateIndirectFunctions(uint32_t count);
void SetIndirectFunction(uint32_t indirect, uint32_t direct);
void SetMaxTableSize(uint32_t max);
void MarkStartFunction(WasmFunctionBuilder* builder);
void AddExport(Vector<const char> name, WasmFunctionBuilder* builder);
uint32_t AddExportedGlobal(ValueType type, bool mutability,
......@@ -318,6 +322,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
ZoneVector<WasmGlobal> globals_;
ZoneUnorderedMap<FunctionSig, uint32_t> signature_map_;
int start_function_index_;
uint32_t max_table_size_ = 0;
uint32_t min_memory_size_;
uint32_t max_memory_size_;
bool has_max_memory_size_;
......
......@@ -36,6 +36,7 @@ v8_executable("wasm_api_tests") {
"reflect.cc",
"run-all-wasm-api-tests.cc",
"serialize.cc",
"table.cc",
"wasm-api-test.h",
]
}
// 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.
#include "test/wasm-api-tests/wasm-api-test.h"
namespace v8 {
namespace internal {
namespace wasm {
using ::wasm::FUNCREF;
using ::wasm::Limits;
using ::wasm::TableType;
namespace {
own<Trap*> Negate(const Val args[], Val results[]) {
results[0] = Val(-args[0].i32());
return nullptr;
}
void ExpectTrap(const Func* func, int arg1, int arg2) {
Val args[2] = {Val::i32(arg1), Val::i32(arg2)};
Val results[1];
own<Trap*> trap = func->call(args, results);
EXPECT_NE(nullptr, trap);
}
void ExpectResult(int expected, const Func* func, int arg1, int arg2) {
Val args[2] = {Val::i32(arg1), Val::i32(arg2)};
Val results[1];
own<Trap*> trap = func->call(args, results);
EXPECT_EQ(nullptr, trap);
EXPECT_EQ(expected, results[0].i32());
}
} // namespace
TEST_F(WasmCapiTest, Table) {
builder()->AllocateIndirectFunctions(2);
builder()->SetMaxTableSize(10);
builder()->AddExportedTable(CStrVector("table"), 0);
const uint32_t sig_i_i_index = builder()->AddSignature(wasm_i_i_sig());
ValueType reps[] = {kWasmI32, kWasmI32, kWasmI32};
FunctionSig call_sig(1, 2, reps);
byte call_code[] = {
WASM_CALL_INDIRECT1(sig_i_i_index, WASM_GET_LOCAL(1), WASM_GET_LOCAL(0))};
AddExportedFunction(CStrVector("call_indirect"), call_code, sizeof(call_code),
&call_sig);
byte f_code[] = {WASM_GET_LOCAL(0)};
AddExportedFunction(CStrVector("f"), f_code, sizeof(f_code), wasm_i_i_sig());
byte g_code[] = {WASM_I32V_1(42)};
AddExportedFunction(CStrVector("g"), g_code, sizeof(g_code), wasm_i_i_sig());
// Set table[1] to {f}, which has function index 1.
builder()->SetIndirectFunction(1, 1);
Instantiate(nullptr);
Func* call_indirect = GetExportedFunction(0);
Func* f = GetExportedFunction(1);
Func* g = GetExportedFunction(2);
Table* table = GetExportedTable(3);
own<Func*> h = Func::make(store(), cpp_i_i_sig(), Negate);
// Check initial table state.
EXPECT_EQ(2u, table->size());
EXPECT_EQ(nullptr, table->get(0));
EXPECT_NE(nullptr, table->get(1));
ExpectTrap(call_indirect, 0, 0);
ExpectResult(7, call_indirect, 7, 1);
ExpectTrap(call_indirect, 0, 2);
// Mutate table.
EXPECT_TRUE(table->set(0, g));
EXPECT_TRUE(table->set(1, nullptr));
EXPECT_FALSE(table->set(2, f));
EXPECT_NE(nullptr, table->get(0));
EXPECT_EQ(nullptr, table->get(1));
ExpectResult(42, call_indirect, 7, 0);
ExpectTrap(call_indirect, 0, 1);
ExpectTrap(call_indirect, 0, 2);
// Grow table.
EXPECT_TRUE(table->grow(3));
EXPECT_EQ(5u, table->size());
EXPECT_TRUE(table->set(2, f));
EXPECT_TRUE(table->set(3, h.get()));
EXPECT_FALSE(table->set(5, nullptr));
EXPECT_NE(nullptr, table->get(2));
EXPECT_NE(nullptr, table->get(3));
EXPECT_EQ(nullptr, table->get(4));
ExpectResult(5, call_indirect, 5, 2);
ExpectResult(-6, call_indirect, 6, 3);
ExpectTrap(call_indirect, 0, 4);
ExpectTrap(call_indirect, 0, 5);
EXPECT_TRUE(table->grow(2, f));
EXPECT_EQ(7u, table->size());
EXPECT_NE(nullptr, table->get(5));
EXPECT_NE(nullptr, table->get(6));
EXPECT_FALSE(table->grow(5));
EXPECT_TRUE(table->grow(3));
EXPECT_TRUE(table->grow(0));
// Create standalone table.
// TODO(wasm+): Once Wasm allows multiple tables, turn this into import.
own<TableType*> tabletype =
TableType::make(ValType::make(FUNCREF), Limits(5, 5));
own<Table*> table2 = Table::make(store(), tabletype.get());
EXPECT_EQ(5u, table2->size());
EXPECT_FALSE(table2->grow(1));
EXPECT_TRUE(table2->grow(0));
}
} // namespace wasm
} // namespace internal
} // namespace v8
......@@ -42,6 +42,7 @@ using ::wasm::Module;
using ::wasm::own;
using ::wasm::Ref;
using ::wasm::Store;
using ::wasm::Table;
using ::wasm::Trap;
using ::wasm::Val;
using ::wasm::ValType;
......@@ -115,6 +116,15 @@ class WasmCapiTest : public ::testing::Test {
return memory;
}
Table* GetExportedTable(size_t index) {
DCHECK_GT(exports_.size(), index);
Extern* exported = exports_[index];
DCHECK_EQ(exported->kind(), ::wasm::EXTERN_TABLE);
Table* table = exported->table();
DCHECK_NE(table, nullptr);
return table;
}
void Shutdown() {
instance_.reset();
module_.reset();
......
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