[wasm] Add WebAssembly.Module type reflection of globals.
This adds type reflection support to the {WebAssembly.Module.exports} as well as {WebAssembly.Module.imports} method. It also refactors existing reflective code to use the internal instead of the public embedder API, which is slightly more efficient anyways. R=ahaas@chromium.org TEST=mjsunit/wasm/type-reflection BUG=v8:7742 Change-Id: I5f20ea57261f6433b8d86f55054216bf96b41382 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1760826 Commit-Queue: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/master@{#63273}
This commit is contained in:
parent
9460101cdb
commit
017a68c0ee
@ -1497,6 +1497,8 @@ void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
|
||||
// Converts the given {type} into a string representation that can be used in
|
||||
// reflective functions. Should be kept in sync with the {GetValueType} helper.
|
||||
// TODO(mstarzinger): Remove once {WebAssemblyFunctionType} has been ported to
|
||||
// use the internal API instead.
|
||||
Local<String> ToValueTypeString(Isolate* isolate, i::wasm::ValueType type) {
|
||||
Local<String> string;
|
||||
switch (type) {
|
||||
@ -1981,24 +1983,9 @@ void WebAssemblyGlobalType(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
auto maybe_global = GetFirstArgumentAsGlobal(args, &thrower);
|
||||
if (thrower.error()) return;
|
||||
i::Handle<i::WasmGlobalObject> global = maybe_global.ToHandleChecked();
|
||||
v8::Local<v8::Object> ret = v8::Object::New(isolate);
|
||||
|
||||
if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
|
||||
v8_str(isolate, "mutable"),
|
||||
v8::Boolean::New(isolate, global->is_mutable()))
|
||||
.IsJust()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Local<String> type = ToValueTypeString(isolate, global->type());
|
||||
if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
|
||||
v8_str(isolate, "value"), type)
|
||||
.IsJust()) {
|
||||
return;
|
||||
}
|
||||
|
||||
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
|
||||
return_value.Set(ret);
|
||||
auto type = i::wasm::GetTypeForGlobal(i_isolate, global->is_mutable(),
|
||||
global->type());
|
||||
args.GetReturnValue().Set(Utils::ToLocal(type));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -113,13 +113,69 @@ bool IsWasmCodegenAllowed(Isolate* isolate, Handle<Context> context) {
|
||||
v8::Utils::ToLocal(isolate->factory()->empty_string()));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Converts the given {type} into a string representation that can be used in
|
||||
// reflective functions. Should be kept in sync with the {GetValueType} helper.
|
||||
Handle<String> ToValueTypeString(Isolate* isolate, ValueType type) {
|
||||
Factory* factory = isolate->factory();
|
||||
Handle<String> string;
|
||||
switch (type) {
|
||||
case i::wasm::kWasmI32: {
|
||||
string = factory->InternalizeUtf8String("i32");
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmI64: {
|
||||
string = factory->InternalizeUtf8String("i64");
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmF32: {
|
||||
string = factory->InternalizeUtf8String("f32");
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmF64: {
|
||||
string = factory->InternalizeUtf8String("f64");
|
||||
break;
|
||||
}
|
||||
// TODO(mstarzinger): Add support and tests for exnref and funcref.
|
||||
case i::wasm::kWasmAnyRef: {
|
||||
string = factory->InternalizeUtf8String("anyref");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Handle<JSObject> GetTypeForGlobal(Isolate* isolate, bool is_mutable,
|
||||
ValueType type) {
|
||||
Factory* factory = isolate->factory();
|
||||
|
||||
Handle<String> mutable_string = factory->InternalizeUtf8String("mutable");
|
||||
Handle<String> value_string = factory->InternalizeUtf8String("value");
|
||||
|
||||
Handle<JSFunction> object_function = isolate->object_function();
|
||||
Handle<JSObject> object = factory->NewJSObject(object_function);
|
||||
JSObject::AddProperty(isolate, object, mutable_string,
|
||||
factory->ToBoolean(is_mutable), NONE);
|
||||
JSObject::AddProperty(isolate, object, value_string,
|
||||
ToValueTypeString(isolate, type), NONE);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
Handle<JSArray> GetImports(Isolate* isolate,
|
||||
Handle<WasmModuleObject> module_object) {
|
||||
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(isolate);
|
||||
Factory* factory = isolate->factory();
|
||||
|
||||
Handle<String> module_string = factory->InternalizeUtf8String("module");
|
||||
Handle<String> name_string = factory->InternalizeUtf8String("name");
|
||||
Handle<String> kind_string = factory->InternalizeUtf8String("kind");
|
||||
Handle<String> type_string = factory->InternalizeUtf8String("type");
|
||||
|
||||
Handle<String> function_string = factory->InternalizeUtf8String("function");
|
||||
Handle<String> table_string = factory->InternalizeUtf8String("table");
|
||||
@ -145,6 +201,7 @@ Handle<JSArray> GetImports(Isolate* isolate,
|
||||
Handle<JSObject> entry = factory->NewJSObject(object_function);
|
||||
|
||||
Handle<String> import_kind;
|
||||
Handle<JSObject> type_value;
|
||||
switch (import.kind) {
|
||||
case kExternalFunction:
|
||||
import_kind = function_string;
|
||||
@ -156,6 +213,11 @@ Handle<JSArray> GetImports(Isolate* isolate,
|
||||
import_kind = memory_string;
|
||||
break;
|
||||
case kExternalGlobal:
|
||||
if (enabled_features.type_reflection) {
|
||||
auto& global = module->globals[import.index];
|
||||
type_value =
|
||||
GetTypeForGlobal(isolate, global.mutability, global.type);
|
||||
}
|
||||
import_kind = global_string;
|
||||
break;
|
||||
case kExternalException:
|
||||
@ -178,6 +240,9 @@ Handle<JSArray> GetImports(Isolate* isolate,
|
||||
JSObject::AddProperty(isolate, entry, name_string,
|
||||
import_name.ToHandleChecked(), NONE);
|
||||
JSObject::AddProperty(isolate, entry, kind_string, import_kind, NONE);
|
||||
if (!type_value.is_null()) {
|
||||
JSObject::AddProperty(isolate, entry, type_string, type_value, NONE);
|
||||
}
|
||||
|
||||
storage->set(index, *entry);
|
||||
}
|
||||
@ -187,10 +252,12 @@ Handle<JSArray> GetImports(Isolate* isolate,
|
||||
|
||||
Handle<JSArray> GetExports(Isolate* isolate,
|
||||
Handle<WasmModuleObject> module_object) {
|
||||
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(isolate);
|
||||
Factory* factory = isolate->factory();
|
||||
|
||||
Handle<String> name_string = factory->InternalizeUtf8String("name");
|
||||
Handle<String> kind_string = factory->InternalizeUtf8String("kind");
|
||||
Handle<String> type_string = factory->InternalizeUtf8String("type");
|
||||
|
||||
Handle<String> function_string = factory->InternalizeUtf8String("function");
|
||||
Handle<String> table_string = factory->InternalizeUtf8String("table");
|
||||
@ -214,6 +281,7 @@ Handle<JSArray> GetExports(Isolate* isolate,
|
||||
const WasmExport& exp = module->export_table[index];
|
||||
|
||||
Handle<String> export_kind;
|
||||
Handle<JSObject> type_value;
|
||||
switch (exp.kind) {
|
||||
case kExternalFunction:
|
||||
export_kind = function_string;
|
||||
@ -225,6 +293,11 @@ Handle<JSArray> GetExports(Isolate* isolate,
|
||||
export_kind = memory_string;
|
||||
break;
|
||||
case kExternalGlobal:
|
||||
if (enabled_features.type_reflection) {
|
||||
auto& global = module->globals[exp.index];
|
||||
type_value =
|
||||
GetTypeForGlobal(isolate, global.mutability, global.type);
|
||||
}
|
||||
export_kind = global_string;
|
||||
break;
|
||||
case kExternalException:
|
||||
@ -243,6 +316,9 @@ Handle<JSArray> GetExports(Isolate* isolate,
|
||||
JSObject::AddProperty(isolate, entry, name_string,
|
||||
export_name.ToHandleChecked(), NONE);
|
||||
JSObject::AddProperty(isolate, entry, kind_string, export_kind, NONE);
|
||||
if (!type_value.is_null()) {
|
||||
JSObject::AddProperty(isolate, entry, type_string, type_value, NONE);
|
||||
}
|
||||
|
||||
storage->set(index, *entry);
|
||||
}
|
||||
|
@ -301,13 +301,13 @@ V8_EXPORT_PRIVATE MaybeHandle<WasmModuleObject> CreateModuleObjectFromBytes(
|
||||
V8_EXPORT_PRIVATE bool IsWasmCodegenAllowed(Isolate* isolate,
|
||||
Handle<Context> context);
|
||||
|
||||
V8_EXPORT_PRIVATE Handle<JSArray> GetImports(Isolate* isolate,
|
||||
Handle<WasmModuleObject> module);
|
||||
V8_EXPORT_PRIVATE Handle<JSArray> GetExports(Isolate* isolate,
|
||||
Handle<WasmModuleObject> module);
|
||||
V8_EXPORT_PRIVATE Handle<JSArray> GetCustomSections(
|
||||
Isolate* isolate, Handle<WasmModuleObject> module, Handle<String> name,
|
||||
ErrorThrower* thrower);
|
||||
Handle<JSObject> GetTypeForGlobal(Isolate* isolate, bool is_mutable,
|
||||
ValueType type);
|
||||
Handle<JSArray> GetImports(Isolate* isolate, Handle<WasmModuleObject> module);
|
||||
Handle<JSArray> GetExports(Isolate* isolate, Handle<WasmModuleObject> module);
|
||||
Handle<JSArray> GetCustomSections(Isolate* isolate,
|
||||
Handle<WasmModuleObject> module,
|
||||
Handle<String> name, ErrorThrower* thrower);
|
||||
|
||||
// Decode local variable names from the names section. Return FixedArray of
|
||||
// FixedArray of <undefined|String>. The outer fixed array is indexed by the
|
||||
|
@ -105,6 +105,42 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
|
||||
assertEquals(2, Object.getOwnPropertyNames(type).length);
|
||||
})();
|
||||
|
||||
(function TestGlobalExports() {
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addGlobal(kWasmI32).exportAs("a");
|
||||
builder.addGlobal(kWasmF64, true).exportAs("b");
|
||||
let module = new WebAssembly.Module(builder.toBuffer());
|
||||
let exports = WebAssembly.Module.exports(module);
|
||||
|
||||
assertEquals("a", exports[0].name);
|
||||
assertTrue("type" in exports[0]);
|
||||
assertEquals("i32", exports[0].type.value);
|
||||
assertEquals(false, exports[0].type.mutable);
|
||||
|
||||
assertEquals("b", exports[1].name);
|
||||
assertTrue("type" in exports[1]);
|
||||
assertEquals("f64", exports[1].type.value);
|
||||
assertEquals(true, exports[1].type.mutable);
|
||||
})();
|
||||
|
||||
(function TestGlobalImports() {
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addImportedGlobal("m", "a", kWasmI32);
|
||||
builder.addImportedGlobal("m", "b", kWasmF64, true);
|
||||
let module = new WebAssembly.Module(builder.toBuffer());
|
||||
let imports = WebAssembly.Module.imports(module);
|
||||
|
||||
assertEquals("a", imports[0].name);
|
||||
assertTrue("type" in imports[0]);
|
||||
assertEquals("i32", imports[0].type.value);
|
||||
assertEquals(false, imports[0].type.mutable);
|
||||
|
||||
assertEquals("b", imports[1].name);
|
||||
assertTrue("type" in imports[1]);
|
||||
assertEquals("f64", imports[1].type.value);
|
||||
assertEquals(true, imports[1].type.mutable);
|
||||
})();
|
||||
|
||||
(function TestMemoryConstructorWithMinimum() {
|
||||
let mem = new WebAssembly.Memory({minimum: 1});
|
||||
assertTrue(mem instanceof WebAssembly.Memory);
|
||||
|
Loading…
Reference in New Issue
Block a user