Commit 97c75d37 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[wasm-c-api] Add test for globals

Change-Id: I05bfc6eb98ea31b559d4195364e722ddf472afee
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1687677Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62571}
parent 5f97de9b
......@@ -385,7 +385,8 @@ void AsmJsParser::ValidateModule() {
module_builder_->MarkStartFunction(start);
for (auto& global_import : global_imports_) {
uint32_t import_index = module_builder_->AddGlobalImport(
global_import.import_name, global_import.value_type);
global_import.import_name, global_import.value_type,
false /* mutability */);
start->EmitWithI32V(kExprGetGlobal, import_index);
start->EmitWithI32V(kExprSetGlobal, VarIndex(global_import.var_info));
}
......
......@@ -232,6 +232,7 @@ WasmModuleBuilder::WasmModuleBuilder(Zone* zone)
function_imports_(zone),
function_exports_(zone),
global_imports_(zone),
global_exports_(zone),
functions_(zone),
data_segments_(zone),
indirect_functions_(zone),
......@@ -291,8 +292,9 @@ uint32_t WasmModuleBuilder::AddImport(Vector<const char> name,
}
uint32_t WasmModuleBuilder::AddGlobalImport(Vector<const char> name,
ValueType type) {
global_imports_.push_back({name, ValueTypes::ValueTypeCodeFor(type)});
ValueType type, bool mutability) {
global_imports_.push_back(
{name, ValueTypes::ValueTypeCodeFor(type), mutability});
return static_cast<uint32_t>(global_imports_.size() - 1);
}
......@@ -306,6 +308,14 @@ void WasmModuleBuilder::AddExport(Vector<const char> name,
function_exports_.push_back({name, static_cast<int>(function->func_index())});
}
uint32_t WasmModuleBuilder::AddExportedGlobal(ValueType type, bool mutability,
const WasmInitExpr& init,
Vector<const char> name) {
uint32_t index = AddGlobal(type, true, mutability, init);
global_exports_.push_back({name, index});
return index;
}
void WasmModuleBuilder::AddExportedImport(Vector<const char> name,
int import_index) {
#if DEBUG
......@@ -367,7 +377,7 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
buffer->write_string(import.name); // field name
buffer->write_u8(kExternalGlobal);
buffer->write_u8(import.type_code);
buffer->write_u8(0); // immutable
buffer->write_u8(import.mutability ? 1 : 0);
}
for (auto import : function_imports_) {
buffer->write_u32v(0); // module name (length)
......@@ -484,9 +494,14 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
}
// == emit exports ===========================================================
if (!function_exports_.empty()) {
if (global_exports_.size() + function_exports_.size() > 0) {
size_t start = EmitSection(kExportSectionCode, buffer);
buffer->write_size(function_exports_.size());
buffer->write_size(global_exports_.size() + function_exports_.size());
for (auto global_export : global_exports_) {
buffer->write_string(global_export.name);
buffer->write_u8(kExternalGlobal);
buffer->write_size(global_export.global_index + global_imports_.size());
}
for (auto function_export : function_exports_) {
buffer->write_string(function_export.name);
buffer->write_u8(kExternalFunction);
......
......@@ -233,13 +233,16 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
WasmFunctionBuilder* AddFunction(FunctionSig* sig = nullptr);
uint32_t AddGlobal(ValueType type, bool exported, bool mutability = true,
const WasmInitExpr& init = WasmInitExpr());
uint32_t AddGlobalImport(Vector<const char> name, ValueType type);
uint32_t AddGlobalImport(Vector<const char> name, ValueType type,
bool mutability);
void AddDataSegment(const byte* data, uint32_t size, uint32_t dest);
uint32_t AddSignature(FunctionSig* sig);
uint32_t AllocateIndirectFunctions(uint32_t count);
void SetIndirectFunction(uint32_t indirect, uint32_t direct);
void MarkStartFunction(WasmFunctionBuilder* builder);
void AddExport(Vector<const char> name, WasmFunctionBuilder* builder);
uint32_t AddExportedGlobal(ValueType type, bool mutability,
const WasmInitExpr& init, Vector<const char> name);
void AddExportedImport(Vector<const char> name, int import_index);
void SetMinMemorySize(uint32_t value);
void SetMaxMemorySize(uint32_t value);
......@@ -268,6 +271,12 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
struct WasmGlobalImport {
Vector<const char> name;
ValueTypeCode type_code;
bool mutability;
};
struct WasmGlobalExport {
Vector<const char> name;
uint32_t global_index;
};
struct WasmGlobal {
......@@ -288,6 +297,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
ZoneVector<WasmFunctionImport> function_imports_;
ZoneVector<WasmFunctionExport> function_exports_;
ZoneVector<WasmGlobalImport> global_imports_;
ZoneVector<WasmGlobalExport> global_exports_;
ZoneVector<WasmFunctionBuilder*> functions_;
ZoneVector<WasmDataSegment> data_segments_;
ZoneVector<uint32_t> indirect_functions_;
......
......@@ -31,6 +31,7 @@ v8_executable("wasm_api_tests") {
"../../testing/gtest-support.h",
"callbacks.cc",
"finalize.cc",
"globals.cc",
"run-all-wasm-api-tests.cc",
"wasm-api-test.h",
]
......
......@@ -51,6 +51,10 @@ class WasmCapiCallbacksTest : public WasmCapiTest {
}
Func* stage2() { return stage2_.get(); }
void AddExportedFunction(Vector<const char> name, byte code[],
size_t code_size) {
WasmCapiTest::AddExportedFunction(name, code, code_size, wasm_i_i_sig());
}
private:
own<Func*> stage2_;
......@@ -142,7 +146,7 @@ TEST_F(WasmCapiTest, Recursion) {
WASM_CALL_FUNCTION(fibo_c_index,
WASM_I32_SUB(WASM_GET_LOCAL(0), WASM_ONE))))};
AddExportedFunction(CStrVector("fibonacci_wasm"), code_fibo,
sizeof(code_fibo));
sizeof(code_fibo), wasm_i_i_sig());
own<Func*> fibonacci = Func::make(store(), cpp_i_i_sig(), FibonacciC, this);
Extern* imports[] = {fibonacci.get()};
......
......@@ -16,15 +16,18 @@ int g_foreigns_finalized = 0;
int g_modules_finalized = 0;
void FinalizeInstance(void* data) {
g_instances_finalized += static_cast<int>(reinterpret_cast<intptr_t>(data));
int iteration = static_cast<int>(reinterpret_cast<intptr_t>(data));
g_instances_finalized += iteration;
}
void FinalizeFunction(void* data) {
g_functions_finalized += static_cast<int>(reinterpret_cast<intptr_t>(data));
int iteration = static_cast<int>(reinterpret_cast<intptr_t>(data));
g_functions_finalized += iteration;
}
void FinalizeForeign(void* data) {
g_foreigns_finalized += static_cast<int>(reinterpret_cast<intptr_t>(data));
int iteration = static_cast<int>(reinterpret_cast<intptr_t>(data));
g_foreigns_finalized += iteration;
}
void FinalizeModule(void* data) {
......@@ -36,7 +39,7 @@ void FinalizeModule(void* data) {
TEST_F(WasmCapiTest, InstanceFinalization) {
// Add a dummy function: f(x) { return x; }
byte code[] = {WASM_RETURN1(WASM_GET_LOCAL(0))};
AddExportedFunction(CStrVector("f"), code, sizeof(code));
AddExportedFunction(CStrVector("f"), code, sizeof(code), wasm_i_i_sig());
Compile();
g_instances_finalized = 0;
g_functions_finalized = 0;
......@@ -44,17 +47,18 @@ TEST_F(WasmCapiTest, InstanceFinalization) {
g_modules_finalized = 0;
module()->set_host_info(reinterpret_cast<void*>(42), &FinalizeModule);
static const int kIterations = 10;
for (int i = 0; i < kIterations; i++) {
for (int iteration = 0; iteration < kIterations; iteration++) {
void* finalizer_data = reinterpret_cast<void*>(iteration);
own<Instance*> instance = Instance::make(store(), module(), nullptr);
EXPECT_NE(nullptr, instance.get());
instance->set_host_info(reinterpret_cast<void*>(i), &FinalizeInstance);
instance->set_host_info(finalizer_data, &FinalizeInstance);
own<Func*> func = instance->exports()[0]->func()->copy();
ASSERT_NE(func, nullptr);
func->set_host_info(reinterpret_cast<void*>(i), &FinalizeFunction);
func->set_host_info(finalizer_data, &FinalizeFunction);
own<Foreign*> foreign = Foreign::make(store());
foreign->set_host_info(reinterpret_cast<void*>(i), &FinalizeForeign);
foreign->set_host_info(finalizer_data, &FinalizeForeign);
}
Shutdown();
// Verify that (1) all finalizers were called, and (2) they passed the
......
// 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::GlobalType;
TEST_F(WasmCapiTest, Globals) {
const bool kMutable = true;
const bool kImmutable = false;
// Define imported and exported globals in the module.
const uint32_t cfi_index =
builder()->AddGlobalImport(CStrVector("const f32"), kWasmF32, kImmutable);
const uint32_t cii_index =
builder()->AddGlobalImport(CStrVector("const i64"), kWasmI64, kImmutable);
const uint32_t vfi_index =
builder()->AddGlobalImport(CStrVector("var f32"), kWasmF32, kMutable);
const uint32_t vii_index =
builder()->AddGlobalImport(CStrVector("var i64"), kWasmI64, kMutable);
const int kNumImported = 4;
const uint32_t cfe_index =
kNumImported + builder()->AddExportedGlobal(kWasmF32, kImmutable,
WasmInitExpr(5.f),
CStrVector("const f32"));
const uint32_t cie_index =
kNumImported + builder()->AddExportedGlobal(kWasmI64, kImmutable,
WasmInitExpr(int64_t{6}),
CStrVector("const i64"));
const uint32_t vfe_index =
kNumImported + builder()->AddExportedGlobal(kWasmF32, kMutable,
WasmInitExpr(7.f),
CStrVector("var f32"));
const uint32_t vie_index =
kNumImported + builder()->AddExportedGlobal(kWasmI64, kMutable,
WasmInitExpr(int64_t{8}),
CStrVector("var i64"));
// Define functions for inspecting globals.
ValueType f32_type[] = {kWasmF32};
ValueType i64_type[] = {kWasmI64};
FunctionSig return_f32(1, 0, f32_type);
FunctionSig return_i64(1, 0, i64_type);
byte gcfi[] = {WASM_GET_GLOBAL(cfi_index)};
AddExportedFunction(CStrVector("get const f32 import"), gcfi, sizeof(gcfi),
&return_f32);
byte gcii[] = {WASM_GET_GLOBAL(cii_index)};
AddExportedFunction(CStrVector("get const i64 import"), gcii, sizeof(gcii),
&return_i64);
byte gvfi[] = {WASM_GET_GLOBAL(vfi_index)};
AddExportedFunction(CStrVector("get var f32 import"), gvfi, sizeof(gvfi),
&return_f32);
byte gvii[] = {WASM_GET_GLOBAL(vii_index)};
AddExportedFunction(CStrVector("get var i64 import"), gvii, sizeof(gvii),
&return_i64);
byte gcfe[] = {WASM_GET_GLOBAL(cfe_index)};
AddExportedFunction(CStrVector("get const f32 export"), gcfe, sizeof(gcfe),
&return_f32);
byte gcie[] = {WASM_GET_GLOBAL(cie_index)};
AddExportedFunction(CStrVector("get const i64 export"), gcie, sizeof(gcie),
&return_i64);
byte gvfe[] = {WASM_GET_GLOBAL(vfe_index)};
AddExportedFunction(CStrVector("get var f32 export"), gvfe, sizeof(gvfe),
&return_f32);
byte gvie[] = {WASM_GET_GLOBAL(vie_index)};
AddExportedFunction(CStrVector("get var i64 export"), gvie, sizeof(gvie),
&return_i64);
// Define functions for manipulating globals.
FunctionSig param_f32(0, 1, f32_type);
FunctionSig param_i64(0, 1, i64_type);
byte svfi[] = {WASM_SET_GLOBAL(vfi_index, WASM_GET_LOCAL(0))};
AddExportedFunction(CStrVector("set var f32 import"), svfi, sizeof(svfi),
&param_f32);
byte svii[] = {WASM_SET_GLOBAL(vii_index, WASM_GET_LOCAL(0))};
AddExportedFunction(CStrVector("set var i64 import"), svii, sizeof(svii),
&param_i64);
byte svfe[] = {WASM_SET_GLOBAL(vfe_index, WASM_GET_LOCAL(0))};
AddExportedFunction(CStrVector("set var f32 export"), svfe, sizeof(svfe),
&param_f32);
byte svie[] = {WASM_SET_GLOBAL(vie_index, WASM_GET_LOCAL(0))};
AddExportedFunction(CStrVector("set var i64 export"), svie, sizeof(svie),
&param_i64);
// Create imported globals.
own<GlobalType*> const_f32_type =
GlobalType::make(ValType::make(::wasm::F32), ::wasm::CONST);
own<GlobalType*> const_i64_type =
GlobalType::make(ValType::make(::wasm::I64), ::wasm::CONST);
own<GlobalType*> var_f32_type =
GlobalType::make(ValType::make(::wasm::F32), ::wasm::VAR);
own<GlobalType*> var_i64_type =
GlobalType::make(ValType::make(::wasm::I64), ::wasm::VAR);
own<Global*> const_f32_import =
Global::make(store(), const_f32_type.get(), Val::f32(1));
own<Global*> const_i64_import =
Global::make(store(), const_i64_type.get(), Val::i64(2));
own<Global*> var_f32_import =
Global::make(store(), var_f32_type.get(), Val::f32(3));
own<Global*> var_i64_import =
Global::make(store(), var_i64_type.get(), Val::i64(4));
Extern* imports[] = {const_f32_import.get(), const_i64_import.get(),
var_f32_import.get(), var_i64_import.get()};
Instantiate(imports);
// Extract exports.
size_t i = 0;
Global* const_f32_export = GetExportedGlobal(i++);
Global* const_i64_export = GetExportedGlobal(i++);
Global* var_f32_export = GetExportedGlobal(i++);
Global* var_i64_export = GetExportedGlobal(i++);
Func* get_const_f32_import = GetExportedFunction(i++);
Func* get_const_i64_import = GetExportedFunction(i++);
Func* get_var_f32_import = GetExportedFunction(i++);
Func* get_var_i64_import = GetExportedFunction(i++);
Func* get_const_f32_export = GetExportedFunction(i++);
Func* get_const_i64_export = GetExportedFunction(i++);
Func* get_var_f32_export = GetExportedFunction(i++);
Func* get_var_i64_export = GetExportedFunction(i++);
Func* set_var_f32_import = GetExportedFunction(i++);
Func* set_var_i64_import = GetExportedFunction(i++);
Func* set_var_f32_export = GetExportedFunction(i++);
Func* set_var_i64_export = GetExportedFunction(i++);
// Check initial values.
EXPECT_EQ(1.f, const_f32_import->get().f32());
EXPECT_EQ(2, const_i64_import->get().i64());
EXPECT_EQ(3.f, var_f32_import->get().f32());
EXPECT_EQ(4, var_i64_import->get().i64());
EXPECT_EQ(5.f, const_f32_export->get().f32());
EXPECT_EQ(6, const_i64_export->get().i64());
EXPECT_EQ(7.f, var_f32_export->get().f32());
EXPECT_EQ(8, var_i64_export->get().i64());
Val result[1];
get_const_f32_import->call(nullptr, result);
EXPECT_EQ(1.f, result[0].f32());
get_const_i64_import->call(nullptr, result);
EXPECT_EQ(2, result[0].i64());
get_var_f32_import->call(nullptr, result);
EXPECT_EQ(3.f, result[0].f32());
get_var_i64_import->call(nullptr, result);
EXPECT_EQ(4, result[0].i64());
get_const_f32_export->call(nullptr, result);
EXPECT_EQ(5.f, result[0].f32());
get_const_i64_export->call(nullptr, result);
EXPECT_EQ(6, result[0].i64());
get_var_f32_export->call(nullptr, result);
EXPECT_EQ(7.f, result[0].f32());
get_var_i64_export->call(nullptr, result);
EXPECT_EQ(8, result[0].i64());
// Modify variables through the API and check again.
var_f32_import->set(Val::f32(33));
var_i64_import->set(Val::i64(34));
var_f32_export->set(Val::f32(35));
var_i64_export->set(Val::i64(36));
EXPECT_EQ(33.f, var_f32_import->get().f32());
EXPECT_EQ(34, var_i64_import->get().i64());
EXPECT_EQ(35.f, var_f32_export->get().f32());
EXPECT_EQ(36, var_i64_export->get().i64());
get_var_f32_import->call(nullptr, result);
EXPECT_EQ(33.f, result[0].f32());
get_var_i64_import->call(nullptr, result);
EXPECT_EQ(34, result[0].i64());
get_var_f32_export->call(nullptr, result);
EXPECT_EQ(35.f, result[0].f32());
get_var_i64_export->call(nullptr, result);
EXPECT_EQ(36, result[0].i64());
// Modify variables through calls and check again.
Val args[1];
args[0] = Val::f32(73);
set_var_f32_import->call(args, nullptr);
args[0] = Val::i64(74);
set_var_i64_import->call(args, nullptr);
args[0] = Val::f32(75);
set_var_f32_export->call(args, nullptr);
args[0] = Val::i64(76);
set_var_i64_export->call(args, nullptr);
EXPECT_EQ(73.f, var_f32_import->get().f32());
EXPECT_EQ(74, var_i64_import->get().i64());
EXPECT_EQ(75.f, var_f32_export->get().f32());
EXPECT_EQ(76, var_i64_export->get().i64());
get_var_f32_import->call(nullptr, result);
EXPECT_EQ(73.f, result[0].f32());
get_var_i64_import->call(nullptr, result);
EXPECT_EQ(74, result[0].i64());
get_var_f32_export->call(nullptr, result);
EXPECT_EQ(75.f, result[0].f32());
get_var_i64_export->call(nullptr, result);
EXPECT_EQ(76, result[0].i64());
}
} // namespace wasm
} // namespace internal
} // namespace v8
......@@ -35,6 +35,7 @@ using ::wasm::Extern;
using ::wasm::Foreign;
using ::wasm::Func;
using ::wasm::FuncType;
using ::wasm::Global;
using ::wasm::Instance;
using ::wasm::Module;
using ::wasm::own;
......@@ -79,8 +80,8 @@ class WasmCapiTest : public ::testing::Test {
}
void AddExportedFunction(Vector<const char> name, byte code[],
size_t code_size) {
WasmFunctionBuilder* fun = builder()->AddFunction(wasm_i_i_sig());
size_t code_size, FunctionSig* sig) {
WasmFunctionBuilder* fun = builder()->AddFunction(sig);
fun->EmitCode(code, static_cast<uint32_t>(code_size));
fun->Emit(kExprEnd);
builder()->AddExport(name, fun);
......@@ -95,6 +96,15 @@ class WasmCapiTest : public ::testing::Test {
return func;
}
Global* GetExportedGlobal(size_t index) {
DCHECK_GT(exports_.size(), index);
Extern* exported = exports_[index];
DCHECK_EQ(exported->kind(), ::wasm::EXTERN_GLOBAL);
Global* global = exported->global();
DCHECK_NE(global, nullptr);
return global;
}
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