Commit a0bdda24 authored by Aseem Garg's avatar Aseem Garg Committed by Commit Bot

[wasm] Add type function to WebAssembly.Table

This CL also changes the constructor for WasmTableObject so that the
maximum_length is set to undefined instead of a default value if there's
no maximum provided.

R=binji@chromium.org,adamk@chromium.org
Bug=v8:7742

Change-Id: I6310224e9997464bf69c198e2694a6cd76e01e8f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1513156
Commit-Queue: Aseem Garg <aseemgarg@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarBen Smith <binji@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60250}
parent aa420efe
......@@ -393,7 +393,8 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
for (int i = module_->num_imported_tables; i < table_count; i++) {
const WasmTable& table = module_->tables[i];
Handle<WasmTableObject> table_obj = WasmTableObject::New(
isolate_, table.type, table.initial_size, table.maximum_size, nullptr);
isolate_, table.type, table.initial_size, table.has_maximum_size,
table.maximum_size, nullptr);
tables->set(i, *table_obj);
}
instance->set_tables(*tables);
......@@ -841,6 +842,11 @@ bool InstanceBuilder::ProcessImportedTable(Handle<WasmInstanceObject> instance,
}
if (table.has_maximum_size) {
if (table_object->maximum_length()->IsUndefined(isolate_)) {
thrower_->LinkError("table import %d has no maximum length, expected %d",
import_index, table.maximum_size);
return false;
}
int64_t imported_maximum_size = table_object->maximum_length()->Number();
if (imported_maximum_size < 0) {
thrower_->LinkError("table import %d has no maximum length, expected %d",
......
......@@ -192,6 +192,7 @@ Local<String> v8_str(Isolate* isolate, const char* str) {
GET_FIRST_ARGUMENT_AS(Module)
GET_FIRST_ARGUMENT_AS(Memory)
GET_FIRST_ARGUMENT_AS(Table)
#undef GET_FIRST_ARGUMENT_AS
......@@ -992,8 +993,9 @@ bool GetRequiredIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
bool GetOptionalIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
Local<Context> context,
Local<v8::Object> object,
Local<String> property, int64_t* result,
int64_t lower_bound, uint64_t upper_bound) {
Local<String> property, bool* has_property,
int64_t* result, int64_t lower_bound,
uint64_t upper_bound) {
v8::Local<v8::Value> value;
if (!object->Get(context, property).ToLocal(&value)) {
return false;
......@@ -1002,9 +1004,11 @@ bool GetOptionalIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
// Web IDL: dictionary presence
// https://heycam.github.io/webidl/#dfn-present
if (value->IsUndefined()) {
if (has_property != nullptr) *has_property = false;
return true;
}
if (has_property != nullptr) *has_property = true;
i::Handle<i::String> property_name = v8::Utils::OpenHandle(*property);
return GetIntegerProperty(isolate, thrower, context, value, property_name,
......@@ -1056,16 +1060,17 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
}
// The descriptor's 'maximum'.
int64_t maximum = -1;
if (!GetOptionalIntegerProperty(isolate, &thrower, context, descriptor,
v8_str(isolate, "maximum"), &maximum, initial,
i::wasm::max_table_init_entries())) {
bool has_maximum = true;
if (!GetOptionalIntegerProperty(
isolate, &thrower, context, descriptor, v8_str(isolate, "maximum"),
&has_maximum, &maximum, initial, i::wasm::max_table_init_entries())) {
return;
}
i::Handle<i::FixedArray> fixed_array;
i::Handle<i::JSObject> table_obj =
i::WasmTableObject::New(i_isolate, type, static_cast<uint32_t>(initial),
static_cast<uint32_t>(maximum), &fixed_array);
i::Handle<i::JSObject> table_obj = i::WasmTableObject::New(
i_isolate, type, static_cast<uint32_t>(initial), has_maximum,
static_cast<uint32_t>(maximum), &fixed_array);
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
return_value.Set(Utils::ToLocal(table_obj));
}
......@@ -1095,8 +1100,8 @@ void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
// The descriptor's 'maximum'.
int64_t maximum = -1;
if (!GetOptionalIntegerProperty(isolate, &thrower, context, descriptor,
v8_str(isolate, "maximum"), &maximum, initial,
i::wasm::kSpecMaxWasmMemoryPages)) {
v8_str(isolate, "maximum"), nullptr, &maximum,
initial, i::wasm::kSpecMaxWasmMemoryPages)) {
return;
}
......@@ -1345,7 +1350,9 @@ void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
i::Handle<i::FixedArray> old_array(receiver->elements(), i_isolate);
uint32_t old_size = static_cast<uint32_t>(old_array->length());
uint64_t max_size64 = receiver->maximum_length()->Number();
uint64_t max_size64 = receiver->maximum_length().IsUndefined(i_isolate)
? i::FLAG_wasm_max_table_size
: receiver->maximum_length()->Number();
if (max_size64 > i::FLAG_wasm_max_table_size) {
max_size64 = i::FLAG_wasm_max_table_size;
}
......@@ -1430,6 +1437,61 @@ void WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value>& args) {
i::WasmTableObject::Set(i_isolate, table_object, index, element);
}
// WebAssembly.Table.type(WebAssembly.Table) -> TableType
void WebAssemblyTableGetType(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
HandleScope scope(isolate);
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.type()");
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::kWasmAnyFunc) {
element = v8_str(isolate, "anyfunc");
} else if (enabled_features.anyref &&
table->type() == i::wasm::ValueType::kWasmAnyRef) {
element = v8_str(isolate, "anyref");
} else {
UNREACHABLE();
}
// TODO(aseemgarg): update anyfunc to funcref
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;
}
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;
}
}
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
return_value.Set(ret);
}
// WebAssembly.Memory.grow(num) -> num
void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
......@@ -1843,6 +1905,9 @@ void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) {
InstallFunc(isolate, table_proto, "grow", WebAssemblyTableGrow, 1);
InstallFunc(isolate, table_proto, "get", WebAssemblyTableGet, 1);
InstallFunc(isolate, table_proto, "set", WebAssemblyTableSet, 2);
if (enabled_features.type_reflection) {
InstallFunc(isolate, table_constructor, "type", WebAssemblyTableGetType, 1);
}
JSObject::AddProperty(isolate, table_proto, factory->to_string_tag_symbol(),
v8_str(isolate, "WebAssembly.Table"), ro_attributes);
......
......@@ -780,7 +780,8 @@ bool WasmModuleObject::GetPositionInfo(uint32_t position,
Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate,
wasm::ValueType type,
uint32_t initial, uint32_t maximum,
uint32_t initial, bool has_maximum,
uint32_t maximum,
Handle<FixedArray>* elements) {
Handle<JSFunction> table_ctor(
isolate->native_context()->wasm_table_constructor(), isolate);
......@@ -795,7 +796,12 @@ Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate,
table_obj->set_raw_type(static_cast<int>(type));
table_obj->set_elements(*backing_store);
Handle<Object> max = isolate->factory()->NewNumberFromUint(maximum);
Handle<Object> max;
if (has_maximum) {
max = isolate->factory()->NewNumberFromUint(maximum);
} else {
max = isolate->factory()->undefined_value();
}
table_obj->set_maximum_length(*max);
table_obj->set_dispatch_tables(ReadOnlyRoots(isolate).empty_fixed_array());
......
......@@ -276,8 +276,10 @@ class WasmTableObject : public JSObject {
void Grow(Isolate* isolate, uint32_t count);
static Handle<WasmTableObject> New(Isolate* isolate, wasm::ValueType type,
uint32_t initial, uint32_t maximum,
uint32_t initial, bool has_maximum,
uint32_t maximum,
Handle<FixedArray>* elements);
static void AddDispatchTable(Isolate* isolate, Handle<WasmTableObject> table,
Handle<WasmInstanceObject> instance,
int table_index);
......
// 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.
// Flags: --experimental-wasm-type-reflection --experimental-wasm-anyref
load('test/mjsunit/wasm/wasm-module-builder.js');
(function TestTableType() {
let table = new WebAssembly.Table({initial: 1, element: "anyref"});
let type = WebAssembly.Table.type(table);
assertEquals(1, type.minimum);
assertEquals("anyref", type.element);
assertEquals(2, Object.getOwnPropertyNames(type).length);
table = new WebAssembly.Table({initial: 2, maximum: 15, element: "anyref"});
type = WebAssembly.Table.type(table);
assertEquals(2, type.minimum);
assertEquals(15, type.maximum);
assertEquals("anyref", type.element);
assertEquals(3, Object.getOwnPropertyNames(type).length);
})();
......@@ -11,13 +11,21 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
assertThrows(
() => WebAssembly.Memory.type(invalidInput), TypeError,
"WebAssembly.Memory.type(): Argument 0 must be a WebAssembly.Memory");
assertThrows(
() => WebAssembly.Table.type(invalidInput), TypeError,
"WebAssembly.Table.type(): Argument 0 must be a WebAssembly.Table");
});
assertThrows(
() => WebAssembly.Memory.type(
new WebAssembly.Table({initial:1, element: "anyfunc"})),
TypeError,
"WebAssembly.Memory.type(): Argument 0 must be a WebAssembly.Memory");
TypeError,
"WebAssembly.Memory.type(): Argument 0 must be a WebAssembly.Memory");
assertThrows(
() => WebAssembly.Table.type(
new WebAssembly.Memory({initial:1})), TypeError,
"WebAssembly.Table.type(): Argument 0 must be a WebAssembly.Table");
})();
(function TestMemoryType() {
......@@ -25,9 +33,26 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
let type = WebAssembly.Memory.type(mem);
assertEquals(1, type.minimum);
assertEquals(1, Object.getOwnPropertyNames(type).length);
mem = new WebAssembly.Memory({initial: 2, maximum: 15});
type = WebAssembly.Memory.type(mem);
assertEquals(2, type.minimum);
assertEquals(15, type.maximum);
assertEquals(2, Object.getOwnPropertyNames(type).length);
})();
(function TestTableType() {
let table = new WebAssembly.Table({initial: 1, element: "anyfunc"});
let type = WebAssembly.Table.type(table);
assertEquals(1, type.minimum);
assertEquals("anyfunc", type.element);
assertEquals(undefined, type.maximum);
assertEquals(2, Object.getOwnPropertyNames(type).length);
table = new WebAssembly.Table({initial: 2, maximum: 15, element: "anyfunc"});
type = WebAssembly.Table.type(table);
assertEquals(2, type.minimum);
assertEquals(15, type.maximum);
assertEquals("anyfunc", type.element);
assertEquals(3, Object.getOwnPropertyNames(type).length);
})();
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