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

[wasm-c-api] Add test for Memory

Change-Id: Ide762b9af9bd23d376025e9b3e6f5ccab7b0f1a5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1691026Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62600}
parent 25e7c919
......@@ -233,6 +233,7 @@ WasmModuleBuilder::WasmModuleBuilder(Zone* zone)
function_exports_(zone),
global_imports_(zone),
global_exports_(zone),
memory_exports_(zone),
functions_(zone),
data_segments_(zone),
indirect_functions_(zone),
......@@ -342,6 +343,11 @@ void WasmModuleBuilder::SetMaxMemorySize(uint32_t value) {
max_memory_size_ = value;
}
void WasmModuleBuilder::AddExportedMemory(Vector<const char> name,
uint32_t index) {
memory_exports_.push_back({name, index});
}
void WasmModuleBuilder::SetHasSharedMemory() { has_shared_memory_ = true; }
void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
......@@ -494,9 +500,11 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
}
// == emit exports ===========================================================
if (global_exports_.size() + function_exports_.size() > 0) {
size_t num_exports = global_exports_.size() + function_exports_.size() +
memory_exports_.size();
if (num_exports > 0) {
size_t start = EmitSection(kExportSectionCode, buffer);
buffer->write_size(global_exports_.size() + function_exports_.size());
buffer->write_size(num_exports);
for (auto global_export : global_exports_) {
buffer->write_string(global_export.name);
buffer->write_u8(kExternalGlobal);
......@@ -508,6 +516,11 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
buffer->write_size(function_export.function_index +
function_imports_.size());
}
for (auto memory_export : memory_exports_) {
buffer->write_string(memory_export.name);
buffer->write_u8(kExternalMemory);
buffer->write_size(memory_export.memory_index);
}
FixupSection(buffer, start);
}
......
......@@ -244,6 +244,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
uint32_t AddExportedGlobal(ValueType type, bool mutability,
const WasmInitExpr& init, Vector<const char> name);
void AddExportedImport(Vector<const char> name, int import_index);
void AddExportedMemory(Vector<const char> name, uint32_t memory_index);
void SetMinMemorySize(uint32_t value);
void SetMaxMemorySize(uint32_t value);
void SetHasSharedMemory();
......@@ -286,6 +287,11 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
WasmInitExpr init;
};
struct WasmMemoryExport {
Vector<const char> name;
uint32_t memory_index;
};
struct WasmDataSegment {
ZoneVector<byte> data;
uint32_t dest;
......@@ -298,6 +304,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
ZoneVector<WasmFunctionExport> function_exports_;
ZoneVector<WasmGlobalImport> global_imports_;
ZoneVector<WasmGlobalExport> global_exports_;
ZoneVector<WasmMemoryExport> memory_exports_;
ZoneVector<WasmFunctionBuilder*> functions_;
ZoneVector<WasmDataSegment> data_segments_;
ZoneVector<uint32_t> indirect_functions_;
......
......@@ -32,6 +32,7 @@ v8_executable("wasm_api_tests") {
"callbacks.cc",
"finalize.cc",
"globals.cc",
"memory.cc",
"run-all-wasm-api-tests.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::Limits;
using ::wasm::MemoryType;
TEST_F(WasmCapiTest, Memory) {
builder()->SetMinMemorySize(2);
builder()->SetMaxMemorySize(3);
builder()->AddExportedMemory(CStrVector("memory"), 0);
ValueType i32_type[] = {kWasmI32, kWasmI32};
FunctionSig return_i32(1, 0, i32_type);
FunctionSig param_i32_return_i32(1, 1, i32_type);
FunctionSig param_i32_i32(0, 2, i32_type);
byte size_code[] = {WASM_MEMORY_SIZE};
AddExportedFunction(CStrVector("size"), size_code, sizeof(size_code),
&return_i32);
byte load_code[] = {WASM_LOAD_MEM(MachineType::Int8(), WASM_GET_LOCAL(0))};
AddExportedFunction(CStrVector("load"), load_code, sizeof(load_code),
&param_i32_return_i32);
byte store_code[] = {WASM_STORE_MEM(MachineType::Int8(), WASM_GET_LOCAL(0),
WASM_GET_LOCAL(1))};
AddExportedFunction(CStrVector("store"), store_code, sizeof(store_code),
&param_i32_i32);
byte data[] = {0x1, 0x2, 0x3, 0x4};
builder()->AddDataSegment(data, sizeof(data), 0x1000);
Instantiate(nullptr);
// TODO(jkummerow): Getting exports by index leaks implementation details
// of the module builder. It would be nicer to get exports by name instead.
Func* size_func = GetExportedFunction(0);
Func* load_func = GetExportedFunction(1);
Func* store_func = GetExportedFunction(2);
Memory* memory = GetExportedMemory(3);
// Check initial state.
EXPECT_EQ(2u, memory->size());
EXPECT_EQ(0x20000u, memory->data_size());
EXPECT_EQ(0, memory->data()[0]);
EXPECT_EQ(1, memory->data()[0x1000]);
EXPECT_EQ(4, memory->data()[0x1003]);
Val args[2];
Val result[1];
// size == 2
size_func->call(nullptr, result);
EXPECT_EQ(2, result[0].i32());
// load(0) == 0
args[0] = Val::i32(0x0);
load_func->call(args, result);
EXPECT_EQ(0, result[0].i32());
// load(0x1000) == 1
args[0] = Val::i32(0x1000);
load_func->call(args, result);
EXPECT_EQ(1, result[0].i32());
// load(0x1003) == 4
args[0] = Val::i32(0x1003);
load_func->call(args, result);
EXPECT_EQ(4, result[0].i32());
// load(0x1FFFF) == 0
args[0] = Val::i32(0x1FFFF);
load_func->call(args, result);
EXPECT_EQ(0, result[0].i32());
// load(0x20000) -> trap
args[0] = Val::i32(0x20000);
own<Trap*> trap = load_func->call(args, result);
EXPECT_NE(nullptr, trap.get());
// Mutate memory.
memory->data()[0x1003] = 5;
args[0] = Val::i32(0x1002);
args[1] = Val::i32(6);
trap = store_func->call(args, nullptr);
EXPECT_EQ(nullptr, trap.get());
args[0] = Val::i32(0x20000);
trap = store_func->call(args, nullptr);
EXPECT_NE(nullptr, trap.get());
EXPECT_EQ(6, memory->data()[0x1002]);
EXPECT_EQ(5, memory->data()[0x1003]);
args[0] = Val::i32(0x1002);
load_func->call(args, result);
EXPECT_EQ(6, result[0].i32());
args[0] = Val::i32(0x1003);
load_func->call(args, result);
EXPECT_EQ(5, result[0].i32());
// Grow memory.
EXPECT_EQ(true, memory->grow(1));
EXPECT_EQ(3u, memory->size());
EXPECT_EQ(0x30000u, memory->data_size());
args[0] = Val::i32(0x20000);
trap = load_func->call(args, result);
EXPECT_EQ(nullptr, trap.get());
EXPECT_EQ(0, result[0].i32());
trap = store_func->call(args, nullptr);
EXPECT_EQ(nullptr, trap.get());
args[0] = Val::i32(0x30000);
trap = load_func->call(args, result);
EXPECT_NE(nullptr, trap.get());
trap = store_func->call(args, nullptr);
EXPECT_NE(nullptr, trap.get());
EXPECT_EQ(false, memory->grow(1));
EXPECT_EQ(true, memory->grow(0));
// Create standalone memory.
// TODO(wasm): Once Wasm allows multiple memories, turn this into an import.
own<MemoryType*> mem_type = MemoryType::make(Limits(5, 5));
own<Memory*> memory2 = Memory::make(store(), mem_type.get());
EXPECT_EQ(5u, memory2->size());
EXPECT_EQ(false, memory2->grow(1));
EXPECT_EQ(true, memory2->grow(0));
}
} // namespace wasm
} // namespace internal
} // namespace v8
......@@ -37,6 +37,7 @@ using ::wasm::Func;
using ::wasm::FuncType;
using ::wasm::Global;
using ::wasm::Instance;
using ::wasm::Memory;
using ::wasm::Module;
using ::wasm::own;
using ::wasm::Ref;
......@@ -105,6 +106,15 @@ class WasmCapiTest : public ::testing::Test {
return global;
}
Memory* GetExportedMemory(size_t index) {
DCHECK_GT(exports_.size(), index);
Extern* exported = exports_[index];
DCHECK_EQ(exported->kind(), ::wasm::EXTERN_MEMORY);
Memory* memory = exported->memory();
DCHECK_NE(memory, nullptr);
return memory;
}
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