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 @@
load('test/mjsunit/wasm/wasm-module-builder.js');
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, kWasmI32], [kWasmI32]));
// Generate function 1 (out of 3).
......
......@@ -38,7 +38,7 @@ function GlobalImportedInitTest(pad) {
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)
.addBody([kExprLocalGet, 0, kExprI32LoadMem, 0, 0])
......
......@@ -7,16 +7,12 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(function exportImmutableGlobal() {
var builder = new WasmModuleBuilder();
let globals = [
[kWasmI32, 'i32_noinit'],
[kWasmI32, 'i32', 4711],
[kWasmF32, 'f32_noinit'],
[kWasmF32, 'f32', Math.fround(3.14)],
[kWasmF64, 'f64_noinit'],
[kWasmF64, 'f64', 1 / 7]
[kWasmI32, 'i32', WasmInitExpr.I32Const(4711)],
[kWasmF32, 'f32', WasmInitExpr.F32Const(Math.fround(3.14))],
[kWasmF64, 'f64', WasmInitExpr.F64Const(1 / 7)]
];
for (let [type, name, value] of globals) {
let global_builder = builder.addGlobal(type, false).exportAs(name);
if (value) global_builder.init = value;
builder.addGlobal(type, false, value).exportAs(name);
}
var instance = builder.instantiate();
......@@ -24,7 +20,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
let obj = instance.exports[name];
assertEquals("object", typeof obj, name);
assertTrue(obj instanceof WebAssembly.Global, name);
assertEquals(value || 0, obj.value, name);
assertEquals(value.value || 0, obj.value, name);
assertThrows(() => obj.value = 0);
}
})();
......@@ -48,16 +44,12 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(function exportMutableGlobal() {
var builder = new WasmModuleBuilder();
let globals = [
[kWasmI32, 'i32_noinit'], // -
[kWasmI32, 'i32', 4711], // -
[kWasmF32, 'f32_noinit'], // -
[kWasmF32, 'f32', Math.fround(3.14)], // -
[kWasmF64, 'f64_noinit'], // -
[kWasmF64, 'f64', 1 / 7] // -
[kWasmI32, 'i32', WasmInitExpr.I32Const(4711)], // -
[kWasmF32, 'f32', WasmInitExpr.F32Const(Math.fround(3.14))], // -
[kWasmF64, 'f64', WasmInitExpr.F64Const(1 / 7)] // -
];
for (let [index, [type, name, value]] of globals.entries()) {
let global_builder = builder.addGlobal(type, true).exportAs(name);
if (value) global_builder.init = value;
builder.addGlobal(type, true, value).exportAs(name);
builder.addFunction("get " + name, makeSig([], [type]))
.addBody([kExprGlobalGet, index])
.exportFunc();
......@@ -70,7 +62,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
for (let [type, name, value] of globals) {
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.
obj.value = 1001;
......
......@@ -546,12 +546,13 @@ function dummy_func() {
(function TestRefFuncGlobalInit() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
const g_func = builder.addGlobal(kWasmAnyFunc, true);
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]);
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();
assertEquals(
......@@ -565,11 +566,11 @@ function dummy_func() {
const sig_index = builder.addType(kSig_i_v);
const import_wasm = builder.addImport('m', 'wasm', sig_index);
const import_js = builder.addImport('m', 'js', sig_index);
const g_wasm = builder.addGlobal(kWasmAnyFunc, true);
const g_js = builder.addGlobal(kWasmAnyFunc, true);
const g_wasm = 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]);
g_wasm.function_index = import_wasm;
g_js.function_index = import_js;
builder.addFunction('get_global_wasm', kSig_a_v)
.addBody([kExprGlobalGet, g_wasm.index])
.exportFunc();
......
......@@ -93,28 +93,24 @@ TestImported(kWasmF64, 77777.88888, 77777.88888);
function TestExported(type, val, expected) {
print("TestExported " + type + "(" + val +")" + " = " + expected);
var builder = new WasmModuleBuilder();
var sig = makeSig([type], []);
builder.addGlobal(kWasmI32); // pad
var g = builder.addGlobal(type, false)
.exportAs("foo");
g.init = val;
builder.addGlobal(type, false, val).exportAs("foo");
builder.addGlobal(kWasmI32); // pad
var instance = builder.instantiate();
assertEquals(expected, instance.exports.foo.value);
}
TestExported(kWasmI32, 455.5, 455);
TestExported(kWasmF32, -999.34343, Math.fround(-999.34343));
TestExported(kWasmF64, 87347.66666, 87347.66666);
TestExported(kWasmI32, WasmInitExpr.I32Const(455.5), 455);
TestExported(kWasmF32, WasmInitExpr.F32Const(-999.34343),
Math.fround(-999.34343));
TestExported(kWasmF64, WasmInitExpr.F64Const(87347.66666), 87347.66666);
(function TestI64Exported() {
var builder = new WasmModuleBuilder();
var sig = makeSig([kWasmI64], []);
builder.addGlobal(kWasmI32); // pad
var g = builder.addGlobal(kWasmI64, false)
builder.addGlobal(kWasmI64, false, WasmInitExpr.I64Const(1234))
.exportAs("foo");
g.init = 1234;
builder.addGlobal(kWasmI32); // pad
var instance = builder.instantiate();
......@@ -123,14 +119,12 @@ TestExported(kWasmF64, 87347.66666, 87347.66666);
})();
function TestImportedExported(type, val, expected) {
print("TestImportedExported " + type + "(" + val +")" + " = " + expected);
print("TestImportedExported " + type + "(" + val + ")" + " = " + expected);
var builder = new WasmModuleBuilder();
var sig = makeSig([type], []);
var i = builder.addImportedGlobal("ttt", "foo", type);
builder.addGlobal(kWasmI32); // pad
var o = builder.addGlobal(type, false)
builder.addGlobal(type, false, WasmInitExpr.GlobalGet(i))
.exportAs("bar");
o.init_index = i;
builder.addGlobal(kWasmI32); // pad
var instance = builder.instantiate({ttt: {foo: val}});
......@@ -146,9 +140,8 @@ function TestGlobalIndexSpace(type, val) {
var builder = new WasmModuleBuilder();
var im = builder.addImportedGlobal("nnn", "foo", type);
assertEquals(0, im);
var def = builder.addGlobal(type, false);
var def = builder.addGlobal(type, false, WasmInitExpr.GlobalGet(im));
assertEquals(1, def.index);
def.init_index = im;
var sig = makeSig([], [type]);
builder.addFunction("main", sig)
......
......@@ -89,8 +89,7 @@ let kTableSize = 50;
})();
function addConstFuncUsingGlobal(builder, val) {
let g = builder.addGlobal(kWasmI32, false);
g.init = val;
let g = builder.addGlobal(kWasmI32, false, WasmInitExpr.I32Const(val));
return builder.addFunction("global" + val, kSig_i_v)
.addBody([kExprGlobalGet, g.index]).index;
}
......
......@@ -17,9 +17,9 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
.addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32Add])
.exportFunc();
var global = builder.addGlobal(wasmRefType(sig_index), false);
global.function_index = addition_index;
global.exportAs("global");
builder.addGlobal(wasmRefType(sig_index), false,
WasmInitExpr.RefFunc(addition_index))
.exportAs("global");
builder.addGlobal(wasmOptRefType(wrong_sig_index), false)
.exportAs("mistyped_global");
......
......@@ -11,8 +11,9 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
// initialization expression into the globals area of the module.
(function TestS128GlobalInitialization() {
var builder = new WasmModuleBuilder();
var g = builder.addGlobal(kWasmS128);
g.init = [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0];
var g = builder.addGlobal(
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
// extract each lane.
......
......@@ -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() {
this.emit_bytes([
kWasmH0, kWasmH1, kWasmH2, kWasmH3, kWasmV0, kWasmV1, kWasmV2, kWasmV3
......@@ -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 {
constructor(module, type, mutable) {
// {init} a pair {type, immediate}. Construct it with WasmInitExpr.
constructor(module, type, mutable, init) {
this.module = module;
this.type = type;
this.mutable = mutable;
this.init = 0;
this.init = init;
}
exportAs(name) {
......@@ -1179,8 +1258,9 @@ class WasmModuleBuilder {
return this.types.length - 1;
}
addGlobal(type, mutable) {
let glob = new WasmGlobalBuilder(this, type, mutable);
addGlobal(type, mutable, init) {
if (init == undefined) init = WasmInitExpr.defaultFor(type);
let glob = new WasmGlobalBuilder(this, type, mutable, init);
glob.index = this.globals.length + this.num_imported_globals;
this.globals.push(glob);
return glob;
......@@ -1545,56 +1625,7 @@ class WasmModuleBuilder {
for (let global of wasm.globals) {
section.emit_type(global.type);
section.emit_u8(global.mutable);
if ((typeof global.init_index) == 'undefined') {
// 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
section.emit_init_expr(global.init);
}
});
}
......@@ -1889,6 +1920,12 @@ function wasmI32Const(val) {
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) {
// Write in little-endian order at offset 0.
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