Commit 2ec2bda8 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

[wasm][test] Improve initializer expressions in mjsunit

Changes:
- Add WasmInitExpr class which knows how to create initializer
  expressions as pairs of {type, value}. Also define a default for every
  type. Emit such pairs to a byte array with emit_init_expr().
- Add an initializer expression to every global (addGlobal() uses the
  default if the argument is absent).
- Introduce wasmI64Const();
- Update tests as needed.

Change-Id: I75ffe96604891506ad78bd3677ce1efe5e0cee07
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2851892
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74231}
parent 6b982244
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
load('test/mjsunit/wasm/wasm-module-builder.js'); load('test/mjsunit/wasm/wasm-module-builder.js');
const builder = new WasmModuleBuilder(); const builder = new WasmModuleBuilder();
builder.addGlobal(kWasmI32, 1).init = 35; builder.addGlobal(kWasmI32, true, WasmInitExpr.I32Const(35));
builder.addType(makeSig([], [kWasmI32])); builder.addType(makeSig([], [kWasmI32]));
builder.addType(makeSig([kWasmI32, kWasmI32], [kWasmI32])); builder.addType(makeSig([kWasmI32, kWasmI32], [kWasmI32]));
// Generate function 1 (out of 3). // Generate function 1 (out of 3).
......
...@@ -38,7 +38,7 @@ function GlobalImportedInitTest(pad) { ...@@ -38,7 +38,7 @@ function GlobalImportedInitTest(pad) {
var g = builder.addImportedGlobal("mod", "offset", kWasmI32); var g = builder.addImportedGlobal("mod", "offset", kWasmI32);
while (pad-- > 0) builder.addGlobal(kWasmI32); // pad while (pad-- > 0) builder.addGlobal(kWasmI32, false); // pad
builder.addFunction("load", kSig_i_i) builder.addFunction("load", kSig_i_i)
.addBody([kExprLocalGet, 0, kExprI32LoadMem, 0, 0]) .addBody([kExprLocalGet, 0, kExprI32LoadMem, 0, 0])
......
...@@ -7,16 +7,12 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -7,16 +7,12 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(function exportImmutableGlobal() { (function exportImmutableGlobal() {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
let globals = [ let globals = [
[kWasmI32, 'i32_noinit'], [kWasmI32, 'i32', WasmInitExpr.I32Const(4711)],
[kWasmI32, 'i32', 4711], [kWasmF32, 'f32', WasmInitExpr.F32Const(Math.fround(3.14))],
[kWasmF32, 'f32_noinit'], [kWasmF64, 'f64', WasmInitExpr.F64Const(1 / 7)]
[kWasmF32, 'f32', Math.fround(3.14)],
[kWasmF64, 'f64_noinit'],
[kWasmF64, 'f64', 1 / 7]
]; ];
for (let [type, name, value] of globals) { for (let [type, name, value] of globals) {
let global_builder = builder.addGlobal(type, false).exportAs(name); builder.addGlobal(type, false, value).exportAs(name);
if (value) global_builder.init = value;
} }
var instance = builder.instantiate(); var instance = builder.instantiate();
...@@ -24,7 +20,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -24,7 +20,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
let obj = instance.exports[name]; let obj = instance.exports[name];
assertEquals("object", typeof obj, name); assertEquals("object", typeof obj, name);
assertTrue(obj instanceof WebAssembly.Global, name); assertTrue(obj instanceof WebAssembly.Global, name);
assertEquals(value || 0, obj.value, name); assertEquals(value.value || 0, obj.value, name);
assertThrows(() => obj.value = 0); assertThrows(() => obj.value = 0);
} }
})(); })();
...@@ -48,16 +44,12 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -48,16 +44,12 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(function exportMutableGlobal() { (function exportMutableGlobal() {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
let globals = [ let globals = [
[kWasmI32, 'i32_noinit'], // - [kWasmI32, 'i32', WasmInitExpr.I32Const(4711)], // -
[kWasmI32, 'i32', 4711], // - [kWasmF32, 'f32', WasmInitExpr.F32Const(Math.fround(3.14))], // -
[kWasmF32, 'f32_noinit'], // - [kWasmF64, 'f64', WasmInitExpr.F64Const(1 / 7)] // -
[kWasmF32, 'f32', Math.fround(3.14)], // -
[kWasmF64, 'f64_noinit'], // -
[kWasmF64, 'f64', 1 / 7] // -
]; ];
for (let [index, [type, name, value]] of globals.entries()) { for (let [index, [type, name, value]] of globals.entries()) {
let global_builder = builder.addGlobal(type, true).exportAs(name); builder.addGlobal(type, true, value).exportAs(name);
if (value) global_builder.init = value;
builder.addFunction("get " + name, makeSig([], [type])) builder.addFunction("get " + name, makeSig([], [type]))
.addBody([kExprGlobalGet, index]) .addBody([kExprGlobalGet, index])
.exportFunc(); .exportFunc();
...@@ -70,7 +62,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -70,7 +62,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
for (let [type, name, value] of globals) { for (let [type, name, value] of globals) {
let obj = instance.exports[name]; let obj = instance.exports[name];
assertEquals(value || 0, obj.value, name); assertEquals(value.value || 0, obj.value, name);
// Changing the exported global should change the instance's global. // Changing the exported global should change the instance's global.
obj.value = 1001; obj.value = 1001;
......
...@@ -546,12 +546,13 @@ function dummy_func() { ...@@ -546,12 +546,13 @@ function dummy_func() {
(function TestRefFuncGlobalInit() { (function TestRefFuncGlobalInit() {
print(arguments.callee.name); print(arguments.callee.name);
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
const g_func = builder.addGlobal(kWasmAnyFunc, true);
const f_func = builder.addFunction('get_anyfunc_global', kSig_a_v) const f_func = builder.addFunction('get_anyfunc_global', kSig_a_v)
.addBody([kExprGlobalGet, g_func.index])
.exportAs('get_anyfunc_global');
builder.addDeclarativeElementSegment([f_func.index]); builder.addDeclarativeElementSegment([f_func.index]);
g_func.function_index = f_func.index; const g_func = builder.addGlobal(kWasmAnyFunc, true,
WasmInitExpr.RefFunc(f_func.index));
// Doing this here to break the cyclic dependency with g_func.
f_func.addBody([kExprGlobalGet, g_func.index])
.exportAs('get_anyfunc_global');
const instance = builder.instantiate(); const instance = builder.instantiate();
assertEquals( assertEquals(
...@@ -565,11 +566,11 @@ function dummy_func() { ...@@ -565,11 +566,11 @@ function dummy_func() {
const sig_index = builder.addType(kSig_i_v); const sig_index = builder.addType(kSig_i_v);
const import_wasm = builder.addImport('m', 'wasm', sig_index); const import_wasm = builder.addImport('m', 'wasm', sig_index);
const import_js = builder.addImport('m', 'js', sig_index); const import_js = builder.addImport('m', 'js', sig_index);
const g_wasm = builder.addGlobal(kWasmAnyFunc, true); const g_wasm = builder.addGlobal(kWasmAnyFunc, true,
const g_js = builder.addGlobal(kWasmAnyFunc, true); WasmInitExpr.RefFunc(import_wasm));
const g_js = builder.addGlobal(kWasmAnyFunc, true,
WasmInitExpr.RefFunc(import_js));
builder.addDeclarativeElementSegment([import_wasm, import_js]); builder.addDeclarativeElementSegment([import_wasm, import_js]);
g_wasm.function_index = import_wasm;
g_js.function_index = import_js;
builder.addFunction('get_global_wasm', kSig_a_v) builder.addFunction('get_global_wasm', kSig_a_v)
.addBody([kExprGlobalGet, g_wasm.index]) .addBody([kExprGlobalGet, g_wasm.index])
.exportFunc(); .exportFunc();
......
...@@ -93,28 +93,24 @@ TestImported(kWasmF64, 77777.88888, 77777.88888); ...@@ -93,28 +93,24 @@ TestImported(kWasmF64, 77777.88888, 77777.88888);
function TestExported(type, val, expected) { function TestExported(type, val, expected) {
print("TestExported " + type + "(" + val +")" + " = " + expected); print("TestExported " + type + "(" + val +")" + " = " + expected);
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
var sig = makeSig([type], []);
builder.addGlobal(kWasmI32); // pad builder.addGlobal(kWasmI32); // pad
var g = builder.addGlobal(type, false) builder.addGlobal(type, false, val).exportAs("foo");
.exportAs("foo");
g.init = val;
builder.addGlobal(kWasmI32); // pad builder.addGlobal(kWasmI32); // pad
var instance = builder.instantiate(); var instance = builder.instantiate();
assertEquals(expected, instance.exports.foo.value); assertEquals(expected, instance.exports.foo.value);
} }
TestExported(kWasmI32, 455.5, 455); TestExported(kWasmI32, WasmInitExpr.I32Const(455.5), 455);
TestExported(kWasmF32, -999.34343, Math.fround(-999.34343)); TestExported(kWasmF32, WasmInitExpr.F32Const(-999.34343),
TestExported(kWasmF64, 87347.66666, 87347.66666); Math.fround(-999.34343));
TestExported(kWasmF64, WasmInitExpr.F64Const(87347.66666), 87347.66666);
(function TestI64Exported() { (function TestI64Exported() {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
var sig = makeSig([kWasmI64], []);
builder.addGlobal(kWasmI32); // pad builder.addGlobal(kWasmI32); // pad
var g = builder.addGlobal(kWasmI64, false) builder.addGlobal(kWasmI64, false, WasmInitExpr.I64Const(1234))
.exportAs("foo"); .exportAs("foo");
g.init = 1234;
builder.addGlobal(kWasmI32); // pad builder.addGlobal(kWasmI32); // pad
var instance = builder.instantiate(); var instance = builder.instantiate();
...@@ -123,14 +119,12 @@ TestExported(kWasmF64, 87347.66666, 87347.66666); ...@@ -123,14 +119,12 @@ TestExported(kWasmF64, 87347.66666, 87347.66666);
})(); })();
function TestImportedExported(type, val, expected) { function TestImportedExported(type, val, expected) {
print("TestImportedExported " + type + "(" + val +")" + " = " + expected); print("TestImportedExported " + type + "(" + val + ")" + " = " + expected);
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
var sig = makeSig([type], []);
var i = builder.addImportedGlobal("ttt", "foo", type); var i = builder.addImportedGlobal("ttt", "foo", type);
builder.addGlobal(kWasmI32); // pad builder.addGlobal(kWasmI32); // pad
var o = builder.addGlobal(type, false) builder.addGlobal(type, false, WasmInitExpr.GlobalGet(i))
.exportAs("bar"); .exportAs("bar");
o.init_index = i;
builder.addGlobal(kWasmI32); // pad builder.addGlobal(kWasmI32); // pad
var instance = builder.instantiate({ttt: {foo: val}}); var instance = builder.instantiate({ttt: {foo: val}});
...@@ -146,9 +140,8 @@ function TestGlobalIndexSpace(type, val) { ...@@ -146,9 +140,8 @@ function TestGlobalIndexSpace(type, val) {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
var im = builder.addImportedGlobal("nnn", "foo", type); var im = builder.addImportedGlobal("nnn", "foo", type);
assertEquals(0, im); assertEquals(0, im);
var def = builder.addGlobal(type, false); var def = builder.addGlobal(type, false, WasmInitExpr.GlobalGet(im));
assertEquals(1, def.index); assertEquals(1, def.index);
def.init_index = im;
var sig = makeSig([], [type]); var sig = makeSig([], [type]);
builder.addFunction("main", sig) builder.addFunction("main", sig)
......
...@@ -89,8 +89,7 @@ let kTableSize = 50; ...@@ -89,8 +89,7 @@ let kTableSize = 50;
})(); })();
function addConstFuncUsingGlobal(builder, val) { function addConstFuncUsingGlobal(builder, val) {
let g = builder.addGlobal(kWasmI32, false); let g = builder.addGlobal(kWasmI32, false, WasmInitExpr.I32Const(val));
g.init = val;
return builder.addFunction("global" + val, kSig_i_v) return builder.addFunction("global" + val, kSig_i_v)
.addBody([kExprGlobalGet, g.index]).index; .addBody([kExprGlobalGet, g.index]).index;
} }
......
...@@ -17,9 +17,9 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -17,9 +17,9 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
.addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32Add]) .addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32Add])
.exportFunc(); .exportFunc();
var global = builder.addGlobal(wasmRefType(sig_index), false); builder.addGlobal(wasmRefType(sig_index), false,
global.function_index = addition_index; WasmInitExpr.RefFunc(addition_index))
global.exportAs("global"); .exportAs("global");
builder.addGlobal(wasmOptRefType(wrong_sig_index), false) builder.addGlobal(wasmOptRefType(wrong_sig_index), false)
.exportAs("mistyped_global"); .exportAs("mistyped_global");
......
...@@ -11,8 +11,9 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -11,8 +11,9 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
// initialization expression into the globals area of the module. // initialization expression into the globals area of the module.
(function TestS128GlobalInitialization() { (function TestS128GlobalInitialization() {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
var g = builder.addGlobal(kWasmS128); var g = builder.addGlobal(
g.init = [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]; kWasmS128, false, WasmInitExpr.S128Const(
[1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]));
// Check that all lanes have the right values by creating 4 functions that // Check that all lanes have the right values by creating 4 functions that
// extract each lane. // extract each lane.
......
...@@ -939,6 +939,39 @@ class Binary { ...@@ -939,6 +939,39 @@ class Binary {
} }
} }
emit_init_expr(expr) {
switch (expr.type) {
case kExprGlobalGet:
this.emit_u8(kExprGlobalGet);
this.emit_u32v(expr.value);
break;
case kExprI32Const:
this.emit_bytes(wasmI32Const(expr.value));
break;
case kExprI64Const:
this.emit_bytes(wasmI64Const(expr.value));
break;
case kExprF32Const:
this.emit_bytes(wasmF32Const(expr.value));
break;
case kExprF64Const:
this.emit_bytes(wasmF64Const(expr.value));
break;
case kSimdPrefix:
this.emit_bytes(wasmS128Const(expr.value));
break;
case kExprRefFunc:
this.emit_u8(kExprRefFunc);
this.emit_u32v(expr.value);
break;
case kExprRefNull:
this.emit_u8(kExprRefNull);
this.emit_u32v(expr.value);
break;
}
this.emit_u8(kExprEnd); // end of init expression
}
emit_header() { emit_header() {
this.emit_bytes([ this.emit_bytes([
kWasmH0, kWasmH1, kWasmH2, kWasmH3, kWasmV0, kWasmV1, kWasmV2, kWasmV3 kWasmH0, kWasmH1, kWasmH2, kWasmH3, kWasmV0, kWasmV1, kWasmV2, kWasmV3
...@@ -1035,12 +1068,58 @@ class WasmFunctionBuilder { ...@@ -1035,12 +1068,58 @@ class WasmFunctionBuilder {
} }
} }
class WasmInitExpr {
static I32Const(value) {
return {type: kExprI32Const, value: value};
}
static I64Const(value) {
return {type: kExprI64Const, value: value};
}
static F32Const(value) {
return {type: kExprF32Const, value: value};
}
static F64Const(value) {
return {type: kExprF64Const, value: value};
}
static S128Const(value) {
return {type: kSimdPrefix, value: value};
}
static GlobalGet(index) {
return {type: kExprGlobalGet, value: index};
}
static RefFunc(index) {
return {type: kExprRefFunc, value: index};
}
static RefNull(type) {
return {type: kExprRefNull, value: type};
}
static defaultFor(type) {
switch (type) {
case kWasmI32:
return this.I32Const(0);
case kWasmI64:
return this.I64Const(0);
case kWasmF32:
return this.F32Const(0);
case kWasmF64:
return this.F64Const(0);
case kWasmS128:
return this.S128Const(new Array(16).fill(0));
default:
let heap_type = (typeof type) == 'number' ? type : type.index;
return this.RefNull(heap_type);
}
}
}
class WasmGlobalBuilder { class WasmGlobalBuilder {
constructor(module, type, mutable) { // {init} a pair {type, immediate}. Construct it with WasmInitExpr.
constructor(module, type, mutable, init) {
this.module = module; this.module = module;
this.type = type; this.type = type;
this.mutable = mutable; this.mutable = mutable;
this.init = 0; this.init = init;
} }
exportAs(name) { exportAs(name) {
...@@ -1179,8 +1258,9 @@ class WasmModuleBuilder { ...@@ -1179,8 +1258,9 @@ class WasmModuleBuilder {
return this.types.length - 1; return this.types.length - 1;
} }
addGlobal(type, mutable) { addGlobal(type, mutable, init) {
let glob = new WasmGlobalBuilder(this, type, mutable); if (init == undefined) init = WasmInitExpr.defaultFor(type);
let glob = new WasmGlobalBuilder(this, type, mutable, init);
glob.index = this.globals.length + this.num_imported_globals; glob.index = this.globals.length + this.num_imported_globals;
this.globals.push(glob); this.globals.push(glob);
return glob; return glob;
...@@ -1545,56 +1625,7 @@ class WasmModuleBuilder { ...@@ -1545,56 +1625,7 @@ class WasmModuleBuilder {
for (let global of wasm.globals) { for (let global of wasm.globals) {
section.emit_type(global.type); section.emit_type(global.type);
section.emit_u8(global.mutable); section.emit_u8(global.mutable);
if ((typeof global.init_index) == 'undefined') { section.emit_init_expr(global.init);
// Emit a constant initializer.
switch (global.type) {
case kWasmI32:
section.emit_u8(kExprI32Const);
section.emit_u32v(global.init);
break;
case kWasmI64:
section.emit_u8(kExprI64Const);
section.emit_u64v(global.init);
break;
case kWasmF32:
section.emit_bytes(wasmF32Const(global.init));
break;
case kWasmF64:
section.emit_bytes(wasmF64Const(global.init));
break;
case kWasmS128:
section.emit_bytes(wasmS128Const(global.init));
break;
case kWasmExternRef:
section.emit_u8(kExprRefNull);
section.emit_u8(kWasmExternRef);
assertEquals(global.function_index, undefined);
break;
case kWasmAnyFunc:
if (global.function_index !== undefined) {
section.emit_u8(kExprRefFunc);
section.emit_u32v(global.function_index);
} else {
section.emit_u8(kExprRefNull);
section.emit_u8(kWasmAnyFunc);
}
break;
default:
if (global.function_index !== undefined) {
section.emit_u8(kExprRefFunc);
section.emit_u32v(global.function_index);
} else {
section.emit_u8(kExprRefNull);
section.emit_u32v(global.type.index);
}
break;
}
} else {
// Emit a global-index initializer.
section.emit_u8(kExprGlobalGet);
section.emit_u32v(global.init_index);
}
section.emit_u8(kExprEnd); // end of init expression
} }
}); });
} }
...@@ -1889,6 +1920,12 @@ function wasmI32Const(val) { ...@@ -1889,6 +1920,12 @@ function wasmI32Const(val) {
return [kExprI32Const, ...wasmSignedLeb(val, 5)]; return [kExprI32Const, ...wasmSignedLeb(val, 5)];
} }
// Note: Since {val} is a JS number, the generated constant only has 53 bits of
// precision.
function wasmI64Const(val) {
return [kExprI64Const, ...wasmSignedLeb(val, 10)];
}
function wasmF32Const(f) { function wasmF32Const(f) {
// Write in little-endian order at offset 0. // Write in little-endian order at offset 0.
data_view.setFloat32(0, f, true); data_view.setFloat32(0, f, true);
......
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