[wasm-c-api] Roll 3094fe2: Implement Global::get/set for refs
Change-Id: Ibab34553f1499bd5dee7cf7477284783cc0660fc Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1763534 Reviewed-by: Andreas Haas <ahaas@chromium.org> Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#63318}
This commit is contained in:
parent
3ec1036526
commit
2d17bf79d5
@ -1340,6 +1340,17 @@ auto Func::result_arity() const -> size_t {
|
||||
|
||||
namespace {
|
||||
|
||||
own<Ref> V8RefValueToWasm(StoreImpl* store, i::Handle<i::Object> value) {
|
||||
if (value->IsNull(store->i_isolate())) return nullptr;
|
||||
return implement<Ref>::type::make(store,
|
||||
i::Handle<i::JSReceiver>::cast(value));
|
||||
}
|
||||
|
||||
i::Handle<i::Object> WasmRefToV8(i::Isolate* isolate, const Ref* ref) {
|
||||
if (ref == nullptr) return i::ReadOnlyRoots(isolate).null_value_handle();
|
||||
return impl(ref)->v8_object();
|
||||
}
|
||||
|
||||
void PrepareFunctionData(i::Isolate* isolate,
|
||||
i::Handle<i::WasmExportedFunctionData> function_data,
|
||||
i::wasm::FunctionSig* sig) {
|
||||
@ -1378,15 +1389,9 @@ void PushArgs(i::wasm::FunctionSig* sig, const Val args[],
|
||||
packer->Push(args[i].f64());
|
||||
break;
|
||||
case i::wasm::kWasmAnyRef:
|
||||
case i::wasm::kWasmFuncRef: {
|
||||
Ref* ref = args[i].ref();
|
||||
if (ref == nullptr) {
|
||||
packer->Push(store->i_isolate()->factory()->null_value()->ptr());
|
||||
} else {
|
||||
packer->Push(impl(ref)->v8_object()->ptr());
|
||||
}
|
||||
case i::wasm::kWasmFuncRef:
|
||||
packer->Push(WasmRefToV8(store->i_isolate(), args[i].ref())->ptr());
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmExnRef:
|
||||
// TODO(jkummerow): Implement these.
|
||||
UNIMPLEMENTED();
|
||||
@ -1418,14 +1423,8 @@ void PopArgs(i::wasm::FunctionSig* sig, Val results[],
|
||||
case i::wasm::kWasmAnyRef:
|
||||
case i::wasm::kWasmFuncRef: {
|
||||
i::Address raw = packer->Pop<i::Address>();
|
||||
if (raw == i::kNullAddress ||
|
||||
i::Object(raw).IsNull(store->i_isolate())) {
|
||||
results[i] = Val(nullptr);
|
||||
} else {
|
||||
i::JSReceiver raw_obj = i::JSReceiver::cast(i::Object(raw));
|
||||
i::Handle<i::JSReceiver> obj(raw_obj, store->i_isolate());
|
||||
results[i] = Val(implement<Ref>::type::make(store, obj));
|
||||
}
|
||||
i::Handle<i::Object> obj(i::Object(raw), store->i_isolate());
|
||||
results[i] = Val(V8RefValueToWasm(store, obj));
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmExnRef:
|
||||
@ -1527,7 +1526,8 @@ auto Func::call(const Val args[], Val results[]) const -> own<Trap> {
|
||||
|
||||
i::Address FuncData::v8_callback(void* data, i::Address argv) {
|
||||
FuncData* self = reinterpret_cast<FuncData*>(data);
|
||||
i::Isolate* isolate = impl(self->store)->i_isolate();
|
||||
StoreImpl* store = impl(self->store);
|
||||
i::Isolate* isolate = store->i_isolate();
|
||||
i::HandleScope scope(isolate);
|
||||
|
||||
const ownvec<ValType>& param_types = self->type->params();
|
||||
@ -1561,13 +1561,8 @@ i::Address FuncData::v8_callback(void* data, i::Address argv) {
|
||||
case FUNCREF: {
|
||||
i::Address raw = v8::base::ReadUnalignedValue<i::Address>(p);
|
||||
p += sizeof(raw);
|
||||
if (raw == i::kNullAddress || i::Object(raw).IsNull(isolate)) {
|
||||
params[i] = Val(nullptr);
|
||||
} else {
|
||||
i::JSReceiver raw_obj = i::JSReceiver::cast(i::Object(raw));
|
||||
i::Handle<i::JSReceiver> obj(raw_obj, isolate);
|
||||
params[i] = Val(implement<Ref>::type::make(impl(self->store), obj));
|
||||
}
|
||||
i::Handle<i::Object> obj(i::Object(raw), isolate);
|
||||
params[i] = Val(V8RefValueToWasm(store, obj));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1608,12 +1603,8 @@ i::Address FuncData::v8_callback(void* data, i::Address argv) {
|
||||
break;
|
||||
case ANYREF:
|
||||
case FUNCREF: {
|
||||
if (results[i].ref() == nullptr) {
|
||||
v8::base::WriteUnalignedValue(p, i::kNullAddress);
|
||||
} else {
|
||||
v8::base::WriteUnalignedValue(
|
||||
p, impl(results[i].ref())->v8_object()->ptr());
|
||||
}
|
||||
v8::base::WriteUnalignedValue(
|
||||
p, WasmRefToV8(isolate, results[i].ref())->ptr());
|
||||
p += sizeof(i::Address);
|
||||
break;
|
||||
}
|
||||
@ -1678,15 +1669,11 @@ auto Global::get() const -> Val {
|
||||
return Val(v8_global->GetF32());
|
||||
case F64:
|
||||
return Val(v8_global->GetF64());
|
||||
case ANYREF: {
|
||||
i::Handle<i::JSReceiver> obj =
|
||||
i::Handle<i::JSReceiver>::cast(v8_global->GetRef());
|
||||
return Val(RefImpl<Ref, i::JSReceiver>::make(impl(this)->store(), obj));
|
||||
}
|
||||
case ANYREF:
|
||||
case FUNCREF: {
|
||||
i::Handle<i::JSFunction> obj =
|
||||
i::Handle<i::JSFunction>::cast(v8_global->GetRef());
|
||||
return Val(implement<Func>::type::make(impl(this)->store(), obj));
|
||||
StoreImpl* store = impl(this)->store();
|
||||
i::HandleScope scope(store->i_isolate());
|
||||
return Val(V8RefValueToWasm(store, v8_global->GetRef()));
|
||||
}
|
||||
default:
|
||||
// TODO(wasm+): support new value types
|
||||
@ -1706,10 +1693,12 @@ void Global::set(const Val& val) {
|
||||
case F64:
|
||||
return v8_global->SetF64(val.f64());
|
||||
case ANYREF:
|
||||
return v8_global->SetAnyRef(impl(val.ref())->v8_object());
|
||||
return v8_global->SetAnyRef(
|
||||
WasmRefToV8(impl(this)->store()->i_isolate(), val.ref()));
|
||||
case FUNCREF: {
|
||||
bool result = v8_global->SetFuncRef(impl(this)->store()->i_isolate(),
|
||||
impl(val.ref())->v8_object());
|
||||
i::Isolate* isolate = impl(this)->store()->i_isolate();
|
||||
bool result =
|
||||
v8_global->SetFuncRef(isolate, WasmRefToV8(isolate, val.ref()));
|
||||
DCHECK(result);
|
||||
USE(result);
|
||||
return;
|
||||
@ -1807,12 +1796,10 @@ auto Table::get(size_t index) const -> own<Ref> {
|
||||
i::HandleScope handle_scope(isolate);
|
||||
i::Handle<i::Object> result =
|
||||
i::WasmTableObject::Get(isolate, table, static_cast<uint32_t>(index));
|
||||
if (result->IsNull(isolate)) return own<Ref>();
|
||||
// TODO(jkummerow): If we support both JavaScript and the C-API at the same
|
||||
// time, we need to handle Smis and other JS primitives here.
|
||||
DCHECK(result->IsJSReceiver());
|
||||
return implement<Ref>::type::make(impl(this)->store(),
|
||||
i::Handle<i::JSReceiver>::cast(result));
|
||||
DCHECK(result->IsNull(isolate) || result->IsJSReceiver());
|
||||
return V8RefValueToWasm(impl(this)->store(), result);
|
||||
}
|
||||
|
||||
auto Table::set(size_t index, const Ref* ref) -> bool {
|
||||
@ -1820,10 +1807,7 @@ auto Table::set(size_t index, const Ref* ref) -> bool {
|
||||
if (index >= table->current_length()) return false;
|
||||
i::Isolate* isolate = table->GetIsolate();
|
||||
i::HandleScope handle_scope(isolate);
|
||||
i::Handle<i::Object> obj =
|
||||
ref ? i::Handle<i::Object>::cast(impl(ref)->v8_object())
|
||||
: i::Handle<i::Object>::cast(
|
||||
i::ReadOnlyRoots(isolate).null_value_handle());
|
||||
i::Handle<i::Object> obj = WasmRefToV8(isolate, ref);
|
||||
i::WasmTableObject::Set(isolate, table, static_cast<uint32_t>(index), obj);
|
||||
return true;
|
||||
}
|
||||
@ -1837,10 +1821,7 @@ auto Table::grow(size_t delta, const Ref* ref) -> bool {
|
||||
i::Handle<i::WasmTableObject> table = impl(this)->v8_object();
|
||||
i::Isolate* isolate = table->GetIsolate();
|
||||
i::HandleScope scope(isolate);
|
||||
i::Handle<i::Object> init_value =
|
||||
ref == nullptr
|
||||
? i::Handle<i::Object>::cast(isolate->factory()->null_value())
|
||||
: i::Handle<i::Object>::cast(impl(ref)->v8_object());
|
||||
i::Handle<i::Object> init_value = WasmRefToV8(isolate, ref);
|
||||
int result = i::WasmTableObject::Grow(
|
||||
isolate, table, static_cast<uint32_t>(delta), init_value);
|
||||
return result >= 0;
|
||||
@ -2629,7 +2610,7 @@ struct borrowed_val {
|
||||
explicit borrowed_val(wasm::Val&& v) : it(std::move(v)) {}
|
||||
borrowed_val(borrowed_val&& that) : it(std::move(that.it)) {}
|
||||
~borrowed_val() {
|
||||
if (it.is_ref()) it.release_ref();
|
||||
if (it.is_ref()) it.release_ref().release();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -35,9 +35,10 @@ TEST_F(WasmCapiTest, HostRef) {
|
||||
uint32_t func_index = builder()->AddImport(CStrVector("f"), &r_r_sig);
|
||||
const bool kMutable = true;
|
||||
const WasmInitExpr global_init(WasmInitExpr::kRefNullConst, 0);
|
||||
uint32_t global_index =
|
||||
builder()->AddGlobal(kWasmAnyRef, kMutable, global_init);
|
||||
uint32_t global_index = builder()->AddExportedGlobal(
|
||||
kWasmAnyRef, kMutable, global_init, CStrVector("global"));
|
||||
uint32_t table_index = builder()->AddTable(kWasmAnyRef, 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);
|
||||
@ -62,11 +63,13 @@ TEST_F(WasmCapiTest, HostRef) {
|
||||
Extern* imports[] = {callback.get()};
|
||||
Instantiate(imports);
|
||||
|
||||
const Func* global_set = GetExportedFunction(0);
|
||||
const Func* global_get = GetExportedFunction(1);
|
||||
const Func* table_set = GetExportedFunction(2);
|
||||
const Func* table_get = GetExportedFunction(3);
|
||||
const Func* func_call = GetExportedFunction(4);
|
||||
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());
|
||||
@ -107,6 +110,13 @@ TEST_F(WasmCapiTest, HostRef) {
|
||||
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);
|
||||
@ -140,6 +150,14 @@ TEST_F(WasmCapiTest, HostRef) {
|
||||
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);
|
||||
|
37
third_party/wasm-api/example/hostref.c
vendored
37
third_party/wasm-api/example/hostref.c
vendored
@ -28,6 +28,23 @@ wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) {
|
||||
return wasm_extern_as_func(exports->data[i]);
|
||||
}
|
||||
|
||||
wasm_global_t* get_export_global(const wasm_extern_vec_t* exports, size_t i) {
|
||||
if (exports->size <= i || !wasm_extern_as_global(exports->data[i])) {
|
||||
printf("> Error accessing global export %zu!\n", i);
|
||||
exit(1);
|
||||
}
|
||||
return wasm_extern_as_global(exports->data[i]);
|
||||
}
|
||||
|
||||
wasm_table_t* get_export_table(const wasm_extern_vec_t* exports, size_t i) {
|
||||
if (exports->size <= i || !wasm_extern_as_table(exports->data[i])) {
|
||||
printf("> Error accessing table export %zu!\n", i);
|
||||
exit(1);
|
||||
}
|
||||
return wasm_extern_as_table(exports->data[i]);
|
||||
}
|
||||
|
||||
|
||||
own wasm_ref_t* call_v_r(const wasm_func_t* func) {
|
||||
printf("call_v_r... "); fflush(stdout);
|
||||
wasm_val_t results[1];
|
||||
@ -165,6 +182,8 @@ int main(int argc, const char* argv[]) {
|
||||
own wasm_extern_vec_t exports;
|
||||
wasm_instance_exports(instance, &exports);
|
||||
size_t i = 0;
|
||||
wasm_global_t* global = get_export_global(&exports, i++);
|
||||
wasm_table_t* table = get_export_table(&exports, i++);
|
||||
wasm_func_t* global_set = get_export_func(&exports, i++);
|
||||
wasm_func_t* global_get = get_export_func(&exports, i++);
|
||||
wasm_func_t* table_set = get_export_func(&exports, i++);
|
||||
@ -190,9 +209,8 @@ int main(int argc, const char* argv[]) {
|
||||
val.of.ref = wasm_ref_copy(host1);
|
||||
check(wasm_ref_copy(val.of.ref), host1);
|
||||
own wasm_ref_t* ref = val.of.ref;
|
||||
val.of.ref = NULL;
|
||||
check(wasm_ref_copy(ref), host1);
|
||||
wasm_ref_delete(ref);
|
||||
wasm_val_delete(&val);
|
||||
|
||||
// Interact.
|
||||
printf("Accessing global...\n");
|
||||
@ -204,6 +222,16 @@ int main(int argc, const char* argv[]) {
|
||||
call_r_v(global_set, NULL);
|
||||
check(call_v_r(global_get), NULL);
|
||||
|
||||
wasm_global_get(global, &val);
|
||||
assert(val.kind == WASM_ANYREF);
|
||||
check(val.of.ref, NULL);
|
||||
val.of.ref = host2;
|
||||
wasm_global_set(global, &val);
|
||||
check(call_v_r(global_get), host2);
|
||||
wasm_global_get(global, &val);
|
||||
assert(val.kind == WASM_ANYREF);
|
||||
check(val.of.ref, host2);
|
||||
|
||||
printf("Accessing table...\n");
|
||||
check(call_i_r(table_get, 0), NULL);
|
||||
check(call_i_r(table_get, 1), NULL);
|
||||
@ -214,6 +242,11 @@ int main(int argc, const char* argv[]) {
|
||||
call_ir_v(table_set, 0, NULL);
|
||||
check(call_i_r(table_get, 0), NULL);
|
||||
|
||||
check(wasm_table_get(table, 2), NULL);
|
||||
wasm_table_set(table, 2, host1);
|
||||
check(call_i_r(table_get, 2), host1);
|
||||
check(wasm_table_get(table, 2), host1);
|
||||
|
||||
printf("Accessing function...\n");
|
||||
check(call_r_r(func_call, NULL), NULL);
|
||||
check(call_r_r(func_call, host1), host1);
|
||||
|
29
third_party/wasm-api/example/hostref.cc
vendored
29
third_party/wasm-api/example/hostref.cc
vendored
@ -26,6 +26,23 @@ auto get_export_func(const wasm::ownvec<wasm::Extern>& exports, size_t i) -> con
|
||||
return exports[i]->func();
|
||||
}
|
||||
|
||||
auto get_export_global(wasm::ownvec<wasm::Extern>& exports, size_t i) -> wasm::Global* {
|
||||
if (exports.size() <= i || !exports[i]->global()) {
|
||||
std::cout << "> Error accessing global export " << i << "!" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
return exports[i]->global();
|
||||
}
|
||||
|
||||
auto get_export_table(wasm::ownvec<wasm::Extern>& exports, size_t i) -> wasm::Table* {
|
||||
if (exports.size() <= i || !exports[i]->table()) {
|
||||
std::cout << "> Error accessing table export " << i << "!" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
return exports[i]->table();
|
||||
}
|
||||
|
||||
|
||||
void call_r_v(const wasm::Func* func, const wasm::Ref* ref) {
|
||||
std::cout << "call_r_v... " << std::flush;
|
||||
wasm::Val args[1] = {wasm::Val::ref(ref ? ref->copy() : wasm::own<wasm::Ref>())};
|
||||
@ -141,6 +158,8 @@ void run() {
|
||||
std::cout << "Extracting exports..." << std::endl;
|
||||
auto exports = instance->exports();
|
||||
size_t i = 0;
|
||||
auto global = get_export_global(exports, i++);
|
||||
auto table = get_export_table(exports, i++);
|
||||
auto global_set = get_export_func(exports, i++);
|
||||
auto global_get = get_export_func(exports, i++);
|
||||
auto table_set = get_export_func(exports, i++);
|
||||
@ -175,6 +194,11 @@ void run() {
|
||||
call_r_v(global_set, nullptr);
|
||||
check(call_v_r(global_get), nullptr);
|
||||
|
||||
check(global->get().release_ref(), nullptr);
|
||||
global->set(wasm::Val(host2->copy()));
|
||||
check(call_v_r(global_get), host2.get());
|
||||
check(global->get().release_ref(), host2.get());
|
||||
|
||||
std::cout << "Accessing table..." << std::endl;
|
||||
check(call_i_r(table_get, 0), nullptr);
|
||||
check(call_i_r(table_get, 1), nullptr);
|
||||
@ -185,6 +209,11 @@ void run() {
|
||||
call_ir_v(table_set, 0, nullptr);
|
||||
check(call_i_r(table_get, 0), nullptr);
|
||||
|
||||
check(table->get(2), nullptr);
|
||||
table->set(2, host1.get());
|
||||
check(call_i_r(table_get, 2), host1.get());
|
||||
check(table->get(2), host1.get());
|
||||
|
||||
std::cout << "Accessing function..." << std::endl;
|
||||
check(call_r_r(func_call, nullptr), nullptr);
|
||||
check(call_r_r(func_call, host1.get()), host1.get());
|
||||
|
BIN
third_party/wasm-api/example/hostref.wasm
vendored
BIN
third_party/wasm-api/example/hostref.wasm
vendored
Binary file not shown.
4
third_party/wasm-api/example/hostref.wat
vendored
4
third_party/wasm-api/example/hostref.wat
vendored
@ -1,8 +1,8 @@
|
||||
(module
|
||||
(import "" "f" (func $fun (param anyref) (result anyref)))
|
||||
|
||||
(global $glob (mut anyref) (ref.null))
|
||||
(table $tab 10 anyref)
|
||||
(global $glob (export "global") (mut anyref) (ref.null))
|
||||
(table $tab (export "table") 10 anyref)
|
||||
|
||||
(func (export "global.set") (param $r anyref)
|
||||
(global.set $glob (local.get $r))
|
||||
|
Loading…
Reference in New Issue
Block a user