v8/test/mjsunit/wasm/compiled-module-serialization.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

409 lines
14 KiB
JavaScript
Raw Normal View History

// Copyright 2015 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.
Reland "[wasm] Ensure that only TurboFan code is serialized" This is a reland of 60ee70bb40efea6f05476dc19f7a5b490193a107. The wasm c-api flakes were fixed in https://crrev.com/c/2349293. Original change's description: > [wasm] Ensure that only TurboFan code is serialized > > We have the implicit assumption that Liftoff code will never be > serialized, and we start relying on that when implementing new features > (debugging, dynamic tiering). > > This CL makes the serializer fail if the module contains any Liftoff > code. Existing tests are changed to ensure that we fully tiered up > before serializing a module (similar to the logic in Chromium). > The "wasm-clone-module" test needs to serialize the module before > enabling the debugger. > > Note that chrome currently only serializes a module after it fully > tiered up, so that should be fine. If other embedders need the ability > to serialize a module in an arbitrary state, we will have to fix this > later. With this CL we will be on the safe side though and (gracefully) > fail serialization instead of accidentally serializing Liftoff code. > > R=ahaas@chromium.org > > Bug: v8:10777 > Change-Id: I1245e5f7fda3447a544c1e3525e1239cde759174 > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2336799 > Commit-Queue: Clemens Backes <clemensb@chromium.org> > Reviewed-by: Andreas Haas <ahaas@chromium.org> > Cr-Commit-Position: refs/heads/master@{#69276} Bug: v8:10777 Change-Id: I2a7c1429812ca46d88a2902b8e0a7b7e3d638b56 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2349290 Reviewed-by: Andreas Haas <ahaas@chromium.org> Commit-Queue: Clemens Backes <clemensb@chromium.org> Cr-Commit-Position: refs/heads/master@{#69335}
2020-08-11 11:36:55 +00:00
// The test needs --wasm-tier-up because we can't serialize and deserialize
// Liftoff code.
// Flags: --expose-wasm --allow-natives-syntax --expose-gc --wasm-tier-up
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
(function SerializeAndDeserializeModule() {
print(arguments.callee.name);
var builder = new WasmModuleBuilder();
builder.addImportedMemory("", "memory", 1);
var kSig_v_i = makeSig([kWasmI32], []);
var signature = builder.addType(kSig_v_i);
builder.addImport("", "some_value", kSig_i_v);
builder.addImport("", "writer", signature);
builder.addFunction("main", kSig_i_i)
.addBody([
kExprLocalGet, 0,
kExprI32LoadMem, 0, 0,
kExprI32Const, 1,
kExprCallIndirect, signature, kTableZero,
kExprLocalGet,0,
kExprI32LoadMem,0, 0,
kExprCallFunction, 0,
kExprI32Add
]).exportFunc();
// writer(mem[i]);
// return mem[i] + some_value();
builder.addFunction("_wrap_writer", signature)
.addBody([
kExprLocalGet, 0,
kExprCallFunction, 1]);
builder.appendToTable([2, 3]);
var wire_bytes = builder.toBuffer();
var module = new WebAssembly.Module(wire_bytes);
var mem_1 = new WebAssembly.Memory({initial: 1});
var view_1 = new Int32Array(mem_1.buffer);
view_1[0] = 42;
var outval_1;
var i1 = new WebAssembly.Instance(module, {"":
{some_value: () => 1,
writer: (x) => outval_1 = x ,
memory: mem_1}
});
assertEquals(43, i1.exports.main(0));
assertEquals(42, outval_1);
var buff = %SerializeWasmModule(module);
module = null;
gc();
module = %DeserializeWasmModule(buff, wire_bytes);
var mem_2 = new WebAssembly.Memory({initial: 2});
var view_2 = new Int32Array(mem_2.buffer);
view_2[0] = 50;
var outval_2;
var i2 = new WebAssembly.Instance(module, {"":
{some_value: () => 1,
writer: (x) => outval_2 = x ,
memory: mem_2}
});
assertEquals(51, i2.exports.main(0));
assertEquals(50, outval_2);
// The instances don't share memory through deserialization.
assertEquals(43, i1.exports.main(0));
})();
(function DeserializeInvalidObject() {
print(arguments.callee.name);
const invalid_buffer = new ArrayBuffer(10);
const invalid_buffer_view = new Uint8Array(10);
module = %DeserializeWasmModule(invalid_buffer, invalid_buffer_view);
assertEquals(module, undefined);
})();
(function RelationBetweenModuleAndClone() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i_v)
.addBody([kExprI32Const, 42])
.exportFunc();
var wire_bytes = builder.toBuffer();
var compiled_module = new WebAssembly.Module(wire_bytes);
var serialized = %SerializeWasmModule(compiled_module);
var clone = %DeserializeWasmModule(serialized, wire_bytes);
assertNotNull(clone);
assertFalse(clone == undefined);
assertFalse(clone == compiled_module);
assertEquals(clone.constructor, compiled_module.constructor);
})();
(function SerializeWrappersWithSameSignature() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i_v)
.addBody([kExprI32Const, 42])
.exportFunc();
builder.addFunction("main_same_signature", kSig_i_v)
.addBody([kExprI32Const, 23])
.exportFunc();
var wire_bytes = builder.toBuffer();
var compiled_module = new WebAssembly.Module(wire_bytes);
var serialized = %SerializeWasmModule(compiled_module);
var clone = %DeserializeWasmModule(serialized, wire_bytes);
assertNotNull(clone);
assertFalse(clone == undefined);
assertFalse(clone == compiled_module);
assertEquals(clone.constructor, compiled_module.constructor);
})();
(function SerializeAfterInstantiation() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i_v)
.addBody([kExprI32Const, 42])
.exportFunc();
var wire_bytes = builder.toBuffer()
var compiled_module = new WebAssembly.Module(wire_bytes);
var instance1 = new WebAssembly.Instance(compiled_module);
var instance2 = new WebAssembly.Instance(compiled_module);
var serialized = %SerializeWasmModule(compiled_module);
var clone = %DeserializeWasmModule(serialized, wire_bytes);
assertNotNull(clone);
assertFalse(clone == undefined);
assertFalse(clone == compiled_module);
assertEquals(clone.constructor, compiled_module.constructor);
var instance3 = new WebAssembly.Instance(clone);
assertFalse(instance3 == undefined);
})();
(function SerializeAfterInstantiationWithMemory() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addImportedMemory("", "memory", 1);
builder.addFunction("main", kSig_i_v)
.addBody([kExprI32Const, 42])
.exportFunc();
var wire_bytes = builder.toBuffer()
var compiled_module = new WebAssembly.Module(wire_bytes);
var mem_1 = new WebAssembly.Memory({initial: 1});
var ffi = {"":{memory:mem_1}};
var instance1 = new WebAssembly.Instance(compiled_module, ffi);
var serialized = %SerializeWasmModule(compiled_module);
var clone = %DeserializeWasmModule(serialized, wire_bytes);
assertNotNull(clone);
assertFalse(clone == undefined);
assertFalse(clone == compiled_module);
assertEquals(clone.constructor, compiled_module.constructor);
var instance2 = new WebAssembly.Instance(clone, ffi);
assertFalse(instance2 == undefined);
})();
(function GlobalsArePrivateBetweenClones() {
print(arguments.callee.name);
var builder = new WasmModuleBuilder();
builder.addGlobal(kWasmI32, true);
builder.addFunction("read", kSig_i_v)
.addBody([
kExprGlobalGet, 0])
.exportFunc();
builder.addFunction("write", kSig_v_i)
.addBody([
kExprLocalGet, 0,
kExprGlobalSet, 0])
.exportFunc();
var wire_bytes = builder.toBuffer();
var module = new WebAssembly.Module(wire_bytes);
var i1 = new WebAssembly.Instance(module);
// serialize and replace module
var buff = %SerializeWasmModule(module);
var module_clone = %DeserializeWasmModule(buff, wire_bytes);
var i2 = new WebAssembly.Instance(module_clone);
i1.exports.write(1);
i2.exports.write(2);
assertEquals(1, i1.exports.read());
assertEquals(2, i2.exports.read());
})();
(function SharedTableTest() {
print(arguments.callee.name);
let kTableSize = 3;
var sig_index1;
function MakeTableExportingModule(constant) {
// A module that defines a table and exports it.
var builder = new WasmModuleBuilder();
builder.addType(kSig_i_i);
builder.addType(kSig_i_ii);
sig_index1 = builder.addType(kSig_i_v);
var f1 = builder.addFunction("f1", sig_index1)
.addBody([kExprI32Const, constant]);
builder.addFunction("main", kSig_i_ii)
.addBody([
kExprLocalGet, 0, // --
kExprCallIndirect, sig_index1, kTableZero]) // --
.exportAs("main");
builder.setTableBounds(kTableSize, kTableSize);
builder.addActiveElementSegment(0, WasmInitExpr.I32Const(0), [f1.index]);
builder.addExportOfKind("table", kExternalTable, 0);
return new WebAssembly.Module(builder.toBuffer());
}
var m1 = MakeTableExportingModule(11);
// Module {m2} imports the table and adds {f2}.
var builder = new WasmModuleBuilder();
builder.addType(kSig_i_ii);
var sig_index2 = builder.addType(kSig_i_v);
var f2 = builder.addFunction("f2", sig_index2)
.addBody([kExprI32Const, 22]);
builder.addFunction("main", kSig_i_ii)
.addBody([
kExprLocalGet, 0, // --
kExprCallIndirect, sig_index2, kTableZero]) // --
.exportAs("main");
builder.addImportedTable("z", "table", kTableSize, kTableSize);
builder.addActiveElementSegment(0, WasmInitExpr.I32Const(1), [f2.index]);
var m2_bytes = builder.toBuffer();
var m2 = new WebAssembly.Module(m2_bytes);
assertFalse(sig_index1 == sig_index2);
var i1 = new WebAssembly.Instance(m1);
var i2 = new WebAssembly.Instance(m2, {z: {table: i1.exports.table}});
var serialized_m2 = %SerializeWasmModule(m2);
var m2_clone = %DeserializeWasmModule(serialized_m2, m2_bytes);
var m3 = MakeTableExportingModule(33);
var i3 = new WebAssembly.Instance(m3);
var i2_prime = new WebAssembly.Instance(m2_clone,
{z: {table: i3.exports.table}});
assertEquals(11, i1.exports.main(0));
assertEquals(11, i2.exports.main(0));
assertEquals(22, i1.exports.main(1));
assertEquals(22, i2.exports.main(1));
assertEquals(33, i3.exports.main(0));
assertEquals(33, i2_prime.exports.main(0));
assertThrows(() => i1.exports.main(2));
assertThrows(() => i2.exports.main(2));
assertThrows(() => i1.exports.main(3));
assertThrows(() => i2.exports.main(3));
})();
(function StackOverflowAfterSerialization() {
print(arguments.callee.name);
const builder = new WasmModuleBuilder();
var fun = builder.addFunction('main', kSig_v_v);
fun.addBody([kExprCallFunction, fun.index]);
fun.exportFunc();
var wire_bytes = builder.toBuffer();
var module = new WebAssembly.Module(wire_bytes);
var buffer = %SerializeWasmModule(module);
module = %DeserializeWasmModule(buffer, wire_bytes);
var instance = new WebAssembly.Instance(module);
assertThrows(instance.exports.main, RangeError);
})();
(function TrapAfterDeserialization() {
print(arguments.callee.name);
function GenerateSerializedModule() {
const builder = new WasmModuleBuilder();
builder.addMemory(1, 1);
builder.addFunction('main', kSig_i_i)
.addBody([kExprLocalGet, 0, kExprI32LoadMem, 0, 0])
.exportFunc();
const wire_bytes = builder.toBuffer();
const module = new WebAssembly.Module(wire_bytes);
const buffer = %SerializeWasmModule(module);
return [wire_bytes, buffer];
}
const [wire_bytes, buffer] = GenerateSerializedModule();
module = %DeserializeWasmModule(buffer, wire_bytes);
const instance = new WebAssembly.Instance(module);
assertEquals(0, instance.exports.main(0));
assertEquals(0, instance.exports.main(kPageSize - 4));
assertTraps(
kTrapMemOutOfBounds, _ => instance.exports.main(kPageSize - 3));
})();
(function DirectCallAfterSerialization() {
print(arguments.callee.name);
const builder = new WasmModuleBuilder();
var fun1 = builder.addFunction('fun1', kSig_i_v)
.addBody([kExprI32Const, 23]);
var fun2 = builder.addFunction('fun2', kSig_i_v)
.addBody([kExprI32Const, 42]);
builder.addFunction('main', kSig_i_v)
.addBody([kExprCallFunction, fun1.index,
kExprCallFunction, fun2.index,
kExprI32Add])
.exportFunc();
var wire_bytes = builder.toBuffer();
var module = new WebAssembly.Module(wire_bytes);
var buffer = %SerializeWasmModule(module);
module = %DeserializeWasmModule(buffer, wire_bytes);
var instance = new WebAssembly.Instance(module);
assertEquals(65, instance.exports.main());
})();
(function ImportCallAfterSerialization() {
print(arguments.callee.name);
const builder = new WasmModuleBuilder();
var fun_import = builder.addImport("", "my_import", kSig_i_v);
var fun = builder.addFunction('fun', kSig_i_v)
.addBody([kExprI32Const, 23]);
builder.addFunction('main', kSig_i_v)
.addBody([kExprCallFunction, fun.index,
kExprCallFunction, fun_import,
kExprI32Add])
.exportFunc();
var wire_bytes = builder.toBuffer();
var module = new WebAssembly.Module(wire_bytes);
var buffer = %SerializeWasmModule(module);
module = %DeserializeWasmModule(buffer, wire_bytes);
var instance = new WebAssembly.Instance(module, {"": {my_import: () => 42 }});
assertEquals(65, instance.exports.main());
})();
(function BranchTableAfterSerialization() {
print(arguments.callee.name);
const builder = new WasmModuleBuilder();
builder.addFunction('main', kSig_i_i)
.addBody([kExprBlock, kWasmVoid,
kExprBlock, kWasmVoid,
kExprBlock, kWasmVoid,
kExprBlock, kWasmVoid,
kExprBlock, kWasmVoid,
kExprBlock, kWasmVoid,
kExprBlock, kWasmVoid,
kExprLocalGet, 0,
kExprBrTable, 6, 0, 1, 2, 3, 4, 5, 6,
kExprEnd,
kExprI32Const, 3,
kExprReturn,
kExprEnd,
kExprI32Const, 7,
kExprReturn,
kExprEnd,
kExprI32Const, 9,
kExprReturn,
kExprEnd,
kExprI32Const, 11,
kExprReturn,
kExprEnd,
kExprI32Const, 23,
kExprReturn,
kExprEnd,
kExprI32Const, 35,
kExprReturn,
kExprEnd,
kExprI32Const, 42,
kExprReturn])
.exportFunc();
var wire_bytes = builder.toBuffer();
var module = new WebAssembly.Module(wire_bytes);
var buffer = %SerializeWasmModule(module);
module = %DeserializeWasmModule(buffer, wire_bytes);
var instance = new WebAssembly.Instance(module);
assertEquals(3, instance.exports.main(0));
assertEquals(7, instance.exports.main(1));
assertEquals(9, instance.exports.main(2));
assertEquals(11, instance.exports.main(3));
assertEquals(23, instance.exports.main(4));
assertEquals(35, instance.exports.main(5));
assertEquals(42, instance.exports.main(6));
assertEquals(42, instance.exports.main(9));
})();