Commit 431cfbc4 authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[wasm] Add WebAssembly.Module type reflection of tables.

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: Ic51b7b4744f7b3ad056a778aecfc4614ca8d6e75
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1762019
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63299}
parent 3be845c7
......@@ -1643,48 +1643,15 @@ void WebAssemblyTableType(const v8::FunctionCallbackInfo<v8::Value>& args) {
auto maybe_table = GetFirstArgumentAsTable(args, &thrower);
if (thrower.error()) return;
i::Handle<i::WasmTableObject> table = maybe_table.ToHandleChecked();
v8::Local<v8::Object> ret = v8::Object::New(isolate);
Local<String> element;
auto enabled_features = i::wasm::WasmFeaturesFromFlags();
if (table->type() == i::wasm::ValueType::kWasmFuncRef) {
element = v8_str(isolate, "anyfunc");
} else if (enabled_features.anyref &&
table->type() == i::wasm::ValueType::kWasmAnyRef) {
element = v8_str(isolate, "anyref");
} else {
UNREACHABLE();
}
if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
v8_str(isolate, "element"), element)
.IsJust()) {
return;
}
uint32_t curr_size = table->current_length();
DCHECK_LE(curr_size, std::numeric_limits<uint32_t>::max());
if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
v8_str(isolate, "minimum"),
v8::Integer::NewFromUnsigned(
isolate, static_cast<uint32_t>(curr_size)))
.IsJust()) {
return;
}
base::Optional<uint32_t> max_size;
if (!table->maximum_length().IsUndefined()) {
uint64_t max_size = table->maximum_length().Number();
DCHECK_LE(max_size, std::numeric_limits<uint32_t>::max());
if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
v8_str(isolate, "maximum"),
v8::Integer::NewFromUnsigned(
isolate, static_cast<uint32_t>(max_size)))
.IsJust()) {
return;
}
uint64_t max_size64 = table->maximum_length().Number();
DCHECK_LE(max_size64, std::numeric_limits<uint32_t>::max());
max_size.emplace(static_cast<uint32_t>(max_size64));
}
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
return_value.Set(ret);
auto type = i::wasm::GetTypeForTable(i_isolate, table->type(),
table->current_length(), max_size);
args.GetReturnValue().Set(Utils::ToLocal(type));
}
// WebAssembly.Memory.grow(num) -> num
......
......@@ -198,6 +198,37 @@ Handle<JSObject> GetTypeForGlobal(Isolate* isolate, bool is_mutable,
return object;
}
Handle<JSObject> GetTypeForTable(Isolate* isolate, ValueType type,
uint32_t min_size,
base::Optional<uint32_t> max_size) {
Factory* factory = isolate->factory();
Handle<String> element;
if (type == ValueType::kWasmFuncRef) {
// TODO(wasm): We should define the "anyfunc" string in one central place
// and then use that constant everywhere.
element = factory->InternalizeUtf8String("anyfunc");
} else {
DCHECK(WasmFeaturesFromFlags().anyref && type == ValueType::kWasmAnyRef);
element = factory->InternalizeUtf8String("anyref");
}
Handle<JSFunction> object_function = isolate->object_function();
Handle<JSObject> object = factory->NewJSObject(object_function);
Handle<String> element_string = factory->InternalizeUtf8String("element");
Handle<String> minimum_string = factory->InternalizeUtf8String("minimum");
Handle<String> maximum_string = factory->InternalizeUtf8String("maximum");
JSObject::AddProperty(isolate, object, element_string, element, NONE);
JSObject::AddProperty(isolate, object, minimum_string,
factory->NewNumberFromUint(min_size), NONE);
if (max_size.has_value()) {
JSObject::AddProperty(isolate, object, maximum_string,
factory->NewNumberFromUint(max_size.value()), NONE);
}
return object;
}
Handle<JSArray> GetImports(Isolate* isolate,
Handle<WasmModuleObject> module_object) {
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(isolate);
......@@ -242,6 +273,13 @@ Handle<JSArray> GetImports(Isolate* isolate,
import_kind = function_string;
break;
case kExternalTable:
if (enabled_features.type_reflection) {
auto& table = module->tables[import.index];
base::Optional<uint32_t> maximum_size;
if (table.has_maximum_size) maximum_size.emplace(table.maximum_size);
type_value = GetTypeForTable(isolate, table.type, table.initial_size,
maximum_size);
}
import_kind = table_string;
break;
case kExternalMemory:
......@@ -326,6 +364,13 @@ Handle<JSArray> GetExports(Isolate* isolate,
export_kind = function_string;
break;
case kExternalTable:
if (enabled_features.type_reflection) {
auto& table = module->tables[exp.index];
base::Optional<uint32_t> maximum_size;
if (table.has_maximum_size) maximum_size.emplace(table.maximum_size);
type_value = GetTypeForTable(isolate, table.type, table.initial_size,
maximum_size);
}
export_kind = table_string;
break;
case kExternalMemory:
......
......@@ -7,6 +7,7 @@
#include <memory>
#include "src/base/optional.h"
#include "src/common/globals.h"
#include "src/handles/handles.h"
#include "src/utils/vector.h"
......@@ -304,6 +305,9 @@ V8_EXPORT_PRIVATE bool IsWasmCodegenAllowed(Isolate* isolate,
Handle<JSObject> GetTypeForFunction(Isolate* isolate, FunctionSig* sig);
Handle<JSObject> GetTypeForGlobal(Isolate* isolate, bool is_mutable,
ValueType type);
Handle<JSObject> GetTypeForTable(Isolate* isolate, ValueType type,
uint32_t min_size,
base::Optional<uint32_t> max_size);
Handle<JSArray> GetImports(Isolate* isolate, Handle<WasmModuleObject> module);
Handle<JSArray> GetExports(Isolate* isolate, Handle<WasmModuleObject> module);
Handle<JSArray> GetCustomSections(Isolate* isolate,
......
......@@ -73,6 +73,56 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
assertEquals(3, Object.getOwnPropertyNames(type).length);
})();
(function TestTableExports() {
let builder = new WasmModuleBuilder();
builder.addTable(kWasmAnyFunc, 20).exportAs("a");
let module = new WebAssembly.Module(builder.toBuffer());
let exports = WebAssembly.Module.exports(module);
assertEquals("a", exports[0].name);
assertTrue("type" in exports[0]);
assertEquals("anyfunc", exports[0].type.element);
assertEquals(20, exports[0].type.minimum);
assertFalse("maximum" in exports[0].type);
builder = new WasmModuleBuilder();
builder.addTable(kWasmAnyFunc, 15, 25).exportAs("b");
module = new WebAssembly.Module(builder.toBuffer());
exports = WebAssembly.Module.exports(module);
assertEquals("b", exports[0].name);
assertTrue("type" in exports[0]);
assertEquals("anyfunc", exports[0].type.element);
assertEquals(15, exports[0].type.minimum);
assertEquals(25, exports[0].type.maximum);
})();
(function TestTableImports() {
let builder = new WasmModuleBuilder();
builder.addImportedTable("m", "a", 20, undefined, kWasmAnyFunc);
let module = new WebAssembly.Module(builder.toBuffer());
let imports = WebAssembly.Module.imports(module);
assertEquals("a", imports[0].name);
assertEquals("m", imports[0].module);
assertTrue("type" in imports[0]);
assertEquals("anyfunc", imports[0].type.element);
assertEquals(20, imports[0].type.minimum);
assertFalse("maximum" in imports[0].type);
builder = new WasmModuleBuilder();
builder.addImportedTable("m", "b", 15, 25, kWasmAnyFunc);
module = new WebAssembly.Module(builder.toBuffer());
imports = WebAssembly.Module.imports(module);
assertEquals("b", imports[0].name);
assertEquals("m", imports[0].module);
assertTrue("type" in imports[0]);
assertEquals("anyfunc", imports[0].type.element);
assertEquals(15, imports[0].type.minimum);
assertEquals(25, imports[0].type.maximum);
})();
(function TestGlobalType() {
let global = new WebAssembly.Global({value: "i32", mutable: true});
let type = WebAssembly.Global.type(global);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment