Commit 3ef75272 authored by Andreas Haas's avatar Andreas Haas Committed by V8 LUCI CQ

[wasm] Change default value of tables

The default value for table entries in WebAssembly tables is null when
the table gets allocated from WebAssembly, but when the table gets
allocated from JavaScript, the default value is undefined when the
table type is externref. With this CL V8 handles the JavaScript case
spec-compliant.

R=manoskouk@chromium.org

Bug: v8:12227
Change-Id: Ic8a1361629d8e5dfb59e2ee22a5e0ae0f6de936d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3162045
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarManos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#76892}
parent a01a02fe
......@@ -1951,7 +1951,7 @@ auto Table::make(Store* store_abs, const TableType* type, const Ref* ref)
i::Handle<i::FixedArray> backing_store;
i::Handle<i::WasmTableObject> table_obj = i::WasmTableObject::New(
isolate, i::Handle<i::WasmInstanceObject>(), i_type, minimum, has_maximum,
maximum, &backing_store);
maximum, &backing_store, isolate->factory()->null_value());
if (ref) {
i::Handle<i::JSReceiver> init = impl(ref)->v8_object();
......
......@@ -653,9 +653,11 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
Handle<FixedArray> tables = isolate_->factory()->NewFixedArray(table_count);
for (int i = module_->num_imported_tables; i < table_count; i++) {
const WasmTable& table = module_->tables[i];
// TODO(9495): Initialize with initializer from module if present.
Handle<WasmTableObject> table_obj = WasmTableObject::New(
isolate_, instance, table.type, table.initial_size,
table.has_maximum_size, table.maximum_size, nullptr);
table.has_maximum_size, table.maximum_size, nullptr,
isolate_->factory()->null_value());
tables->set(i, *table_obj);
}
instance->set_tables(*tables);
......
......@@ -1058,6 +1058,19 @@ bool GetInitialOrMinimumProperty(v8::Isolate* isolate, ErrorThrower* thrower,
return true;
}
namespace {
i::Handle<i::Object> DefaultReferenceValue(i::Isolate* isolate,
i::wasm::ValueType type) {
if (type == i::wasm::kWasmFuncRef) {
return isolate->factory()->null_value();
}
if (type.is_reference()) {
return isolate->factory()->undefined_value();
}
UNREACHABLE();
}
} // namespace
// new WebAssembly.Table(args) -> WebAssembly.Table
void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
......@@ -1117,7 +1130,8 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
i::Handle<i::WasmTableObject> table_obj =
i::WasmTableObject::New(i_isolate, i::Handle<i::WasmInstanceObject>(),
type, static_cast<uint32_t>(initial), has_maximum,
static_cast<uint32_t>(maximum), &fixed_array);
static_cast<uint32_t>(maximum), &fixed_array,
DefaultReferenceValue(i_isolate, type));
if (initial > 0 && args.Length() >= 2 && !args[1]->IsUndefined()) {
i::Handle<i::Object> element = Utils::OpenHandle(*args[1]);
......@@ -1903,7 +1917,7 @@ void WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() >= 2) {
element = Utils::OpenHandle(*args[1]);
} else {
element = i_isolate->factory()->null_value();
element = DefaultReferenceValue(i_isolate, table_object->type());
}
if (!i::WasmTableObject::IsValidElement(i_isolate, table_object, element)) {
thrower.TypeError(
......
......@@ -251,7 +251,7 @@ base::Vector<const uint8_t> WasmModuleObject::GetRawFunctionName(
Handle<WasmTableObject> WasmTableObject::New(
Isolate* isolate, Handle<WasmInstanceObject> instance, wasm::ValueType type,
uint32_t initial, bool has_maximum, uint32_t maximum,
Handle<FixedArray>* entries) {
Handle<FixedArray>* entries, Handle<Object> initial_value) {
// TODO(7748): Make this work with other types when spec clears up.
{
const WasmModule* module =
......@@ -260,9 +260,8 @@ Handle<WasmTableObject> WasmTableObject::New(
}
Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(initial);
Object null = ReadOnlyRoots(isolate).null_value();
for (int i = 0; i < static_cast<int>(initial); ++i) {
backing_store->set(i, null);
backing_store->set(i, *initial_value);
}
Handle<Object> max;
......
......@@ -194,7 +194,8 @@ class WasmTableObject
V8_EXPORT_PRIVATE static Handle<WasmTableObject> New(
Isolate* isolate, Handle<WasmInstanceObject> instance,
wasm::ValueType type, uint32_t initial, bool has_maximum,
uint32_t maximum, Handle<FixedArray>* entries);
uint32_t maximum, Handle<FixedArray>* entries,
Handle<Object> initial_value);
V8_EXPORT_PRIVATE static void AddDispatchTable(
Isolate* isolate, Handle<WasmTableObject> table,
......
......@@ -220,7 +220,8 @@ void TestingModuleBuilder::AddIndirectFunctionTable(
instance_object(), table_index, table_size);
Handle<WasmTableObject> table_obj =
WasmTableObject::New(isolate_, instance, table.type, table.initial_size,
table.has_maximum_size, table.maximum_size, nullptr);
table.has_maximum_size, table.maximum_size, nullptr,
isolate_->factory()->null_value());
WasmTableObject::AddDispatchTable(isolate_, table_obj, instance_object_,
table_index);
......
......@@ -10,8 +10,8 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
print(arguments.callee.name);
let table = new WebAssembly.Table({element: "externref", initial: 10});
// Table should be initialized with null.
assertEquals(null, table.get(1));
// Table should be initialized with undefined.
assertEquals(undefined, table.get(1));
let obj = {'hello' : 'world'};
table.set(2, obj);
assertSame(obj, table.get(2));
......@@ -119,7 +119,7 @@ function getDummy(val) {
const expected = 6;
const dummy = getDummy(expected);
const argument = { "element": "externref", "initial": 3 };
const argument = { "element": "anyfunc", "initial": 3 };
const table = new WebAssembly.Table(argument, dummy);
assertEquals(table.get(1)(), expected);
table.set(1);
......@@ -134,5 +134,5 @@ function getDummy(val) {
const table = new WebAssembly.Table(argument, testObject);
assertEquals(table.get(1), testObject);
table.set(1);
assertEquals(table.get(1), null);
assertEquals(table.get(1), undefined);
})();
......@@ -74,7 +74,7 @@ function checkExternRefTable(getter, start, count, value) {
(function testExternRefTableIsUninitialized() {
print(arguments.callee.name);
checkExternRefTable(instance.exports[`get${import_ref}`], 0, size, null);
checkExternRefTable(instance.exports[`get${import_ref}`], 0, size, undefined);
checkExternRefTable(instance.exports[`get${internal_ref}`], 0, size, null);
})();
......@@ -102,7 +102,7 @@ function checkExternRefTable(getter, start, count, value) {
kTrapTableOutOfBounds,
() => instance.exports[`fill${import_ref}`](start, value, count));
checkExternRefTable(
instance.exports[`get${import_ref}`], start, size - start, null);
instance.exports[`get${import_ref}`], start, size - start, undefined);
value = 45;
assertTraps(
......
......@@ -130,7 +130,7 @@ testGrowInternalAnyFuncTable(9);
const table = new WebAssembly.Table({element: "externref", initial: size});
const instance = builder.instantiate({imp: {table: table}});
assertEquals(null, table.get(size - 2));
assertEquals(undefined, table.get(size - 2));
function growAndCheck(element, grow_by) {
assertEquals(size, instance.exports.size());
......
......@@ -5,7 +5,6 @@
[
[ALWAYS, {
'table/get-set': [FAIL],
'table/constructor': [FAIL],
'table/grow': [FAIL],
# This test can only be executed in the browser
......
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