| // 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 |