[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:
Jakob Kummerow 2019-08-21 14:43:23 +02:00 committed by Commit Bot
parent 3ec1036526
commit 2d17bf79d5
6 changed files with 126 additions and 65 deletions

View File

@ -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();
}
};

View File

@ -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);

View File

@ -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);

View File

@ -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());

Binary file not shown.

View File

@ -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))