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