blob: e61a7c655df633f8773e4e92f7f75ab6ec64e5dc [file] [log] [blame]
// 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 <iostream>
#include "test/wasm-api-tests/wasm-api-test.h"
namespace v8 {
namespace internal {
namespace wasm {
using ::wasm::Frame;
using ::wasm::Message;
namespace {
own<Trap> IdentityCallback(const Val args[], Val results[]) {
results[0] = args[0].copy();
return nullptr;
}
} // namespace
TEST_F(WasmCapiTest, HostRef) {
ValueType rr_reps[] = {kWasmExternRef, kWasmExternRef};
ValueType ri_reps[] = {kWasmExternRef, kWasmI32};
ValueType ir_reps[] = {kWasmI32, kWasmExternRef};
// Naming convention: result_params_sig.
FunctionSig r_r_sig(1, 1, rr_reps);
FunctionSig v_r_sig(0, 1, rr_reps);
FunctionSig r_v_sig(1, 0, rr_reps);
FunctionSig v_ir_sig(0, 2, ir_reps);
FunctionSig r_i_sig(1, 1, ri_reps);
uint32_t func_index = builder()->AddImport(CStrVector("f"), &r_r_sig);
const bool kMutable = true;
uint32_t global_index = builder()->AddExportedGlobal(
kWasmExternRef, kMutable, WasmInitExpr::RefNullConst(HeapType::kExtern),
CStrVector("global"));
uint32_t table_index = builder()->AddTable(kWasmExternRef, 10);
builder()->AddExport(CStrVector("table"), kExternalTable, table_index);
byte global_set_code[] = {WASM_SET_GLOBAL(global_index, WASM_GET_LOCAL(0))};
AddExportedFunction(CStrVector("global.set"), global_set_code,
sizeof(global_set_code), &v_r_sig);
byte global_get_code[] = {WASM_GET_GLOBAL(global_index)};
AddExportedFunction(CStrVector("global.get"), global_get_code,
sizeof(global_get_code), &r_v_sig);
byte table_set_code[] = {
WASM_TABLE_SET(table_index, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))};
AddExportedFunction(CStrVector("table.set"), table_set_code,
sizeof(table_set_code), &v_ir_sig);
byte table_get_code[] = {WASM_TABLE_GET(table_index, WASM_GET_LOCAL(0))};
AddExportedFunction(CStrVector("table.get"), table_get_code,
sizeof(table_get_code), &r_i_sig);
byte func_call_code[] = {WASM_CALL_FUNCTION(func_index, WASM_GET_LOCAL(0))};
AddExportedFunction(CStrVector("func.call"), func_call_code,
sizeof(func_call_code), &r_r_sig);
own<FuncType> func_type =
FuncType::make(ownvec<ValType>::make(ValType::make(::wasm::ANYREF)),
ownvec<ValType>::make(ValType::make(::wasm::ANYREF)));
own<Func> callback = Func::make(store(), func_type.get(), IdentityCallback);
Extern* imports[] = {callback.get()};
Instantiate(imports);
Global* global = GetExportedGlobal(0);
Table* table = GetExportedTable(1);
const Func* global_set = GetExportedFunction(2);
const Func* global_get = GetExportedFunction(3);
const Func* table_set = GetExportedFunction(4);
const Func* table_get = GetExportedFunction(5);
const Func* func_call = GetExportedFunction(6);
own<Foreign> host1 = Foreign::make(store());
own<Foreign> host2 = Foreign::make(store());
host1->set_host_info(reinterpret_cast<void*>(1));
host2->set_host_info(reinterpret_cast<void*>(2));
// Basic checks.
EXPECT_TRUE(host1->copy()->same(host1.get()));
EXPECT_TRUE(host2->copy()->same(host2.get()));
Val val = Val::ref(host1->copy());
EXPECT_TRUE(val.ref()->copy()->same(host1.get()));
own<Ref> ref = val.release_ref();
EXPECT_EQ(nullptr, val.ref());
EXPECT_TRUE(ref->copy()->same(host1.get()));
// Interact with the Global.
Val args[2];
Val results[1];
own<Trap> trap = global_get->call(nullptr, results);
EXPECT_EQ(nullptr, trap);
EXPECT_EQ(nullptr, results[0].release_ref());
args[0] = Val::ref(host1.get()->copy());
trap = global_set->call(args, nullptr);
EXPECT_EQ(nullptr, trap);
trap = global_get->call(nullptr, results);
EXPECT_EQ(nullptr, trap);
EXPECT_TRUE(results[0].release_ref()->same(host1.get()));
args[0] = Val::ref(host2.get()->copy());
trap = global_set->call(args, nullptr);
EXPECT_EQ(nullptr, trap);
trap = global_get->call(nullptr, results);
EXPECT_EQ(nullptr, trap);
EXPECT_TRUE(results[0].release_ref()->same(host2.get()));
args[0] = Val::ref(own<Ref>());
trap = global_set->call(args, nullptr);
EXPECT_EQ(nullptr, trap);
trap = global_get->call(nullptr, results);
EXPECT_EQ(nullptr, trap);
EXPECT_EQ(nullptr, results[0].release_ref());
EXPECT_EQ(nullptr, global->get().release_ref());
global->set(Val(host2->copy()));
trap = global_get->call(nullptr, results);
EXPECT_EQ(nullptr, trap);
EXPECT_TRUE(results[0].release_ref()->same(host2.get()));
EXPECT_TRUE(global->get().release_ref()->same(host2.get()));
// Interact with the Table.
args[0] = Val::i32(0);
trap = table_get->call(args, results);
EXPECT_EQ(nullptr, trap);
EXPECT_EQ(nullptr, results[0].release_ref());
args[0] = Val::i32(1);
trap = table_get->call(args, results);
EXPECT_EQ(nullptr, trap);
EXPECT_EQ(nullptr, results[0].release_ref());
args[0] = Val::i32(0);
args[1] = Val::ref(host1.get()->copy());
trap = table_set->call(args, nullptr);
EXPECT_EQ(nullptr, trap);
args[0] = Val::i32(1);
args[1] = Val::ref(host2.get()->copy());
trap = table_set->call(args, nullptr);
EXPECT_EQ(nullptr, trap);
args[0] = Val::i32(0);
trap = table_get->call(args, results);
EXPECT_EQ(nullptr, trap);
EXPECT_TRUE(results[0].release_ref()->same(host1.get()));
args[0] = Val::i32(1);
trap = table_get->call(args, results);
EXPECT_EQ(nullptr, trap);
EXPECT_TRUE(results[0].release_ref()->same(host2.get()));
args[0] = Val::i32(0);
args[1] = Val::ref(own<Ref>());
trap = table_set->call(args, nullptr);
EXPECT_EQ(nullptr, trap);
trap = table_get->call(args, results);
EXPECT_EQ(nullptr, trap);
EXPECT_EQ(nullptr, results[0].release_ref());
EXPECT_EQ(nullptr, table->get(2));
table->set(2, host1.get());
args[0] = Val::i32(2);
trap = table_get->call(args, results);
EXPECT_EQ(nullptr, trap);
EXPECT_TRUE(results[0].release_ref()->same(host1.get()));
EXPECT_TRUE(table->get(2)->same(host1.get()));
// Interact with the Function.
args[0] = Val::ref(own<Ref>());
trap = func_call->call(args, results);
EXPECT_EQ(nullptr, trap);
EXPECT_EQ(nullptr, results[0].release_ref());
args[0] = Val::ref(host1.get()->copy());
trap = func_call->call(args, results);
EXPECT_EQ(nullptr, trap);
EXPECT_TRUE(results[0].release_ref()->same(host1.get()));
args[0] = Val::ref(host2.get()->copy());
trap = func_call->call(args, results);
EXPECT_EQ(nullptr, trap);
EXPECT_TRUE(results[0].release_ref()->same(host2.get()));
}
} // namespace wasm
} // namespace internal
} // namespace v8