406f4ffaca
This correctly serializes {RelocInfo::INTERNAL_REFERENCE} addresses in a position-independent form, so that they can be properly relocated when the code is deserialized again. We store the offset within the code in the serialized stream. R=clemensh@chromium.org TEST=mjsunit/wasm/compiled-module-serialization BUG=chromium:857049 Change-Id: Ie8c84ee67bdfc17a65faa159a21cc1f2a78ac924 Reviewed-on: https://chromium-review.googlesource.com/1122414 Reviewed-by: Clemens Hammacher <clemensh@chromium.org> Commit-Queue: Michael Starzinger <mstarzinger@chromium.org> Cr-Commit-Position: refs/heads/master@{#54140}
407 lines
14 KiB
JavaScript
407 lines
14 KiB
JavaScript
// 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.
|
|
|
|
// Flags: --expose-wasm --allow-natives-syntax --expose-gc
|
|
|
|
load("test/mjsunit/wasm/wasm-constants.js");
|
|
load("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([
|
|
kExprGetLocal, 0,
|
|
kExprI32LoadMem, 0, 0,
|
|
kExprI32Const, 1,
|
|
kExprCallIndirect, signature, kTableZero,
|
|
kExprGetLocal,0,
|
|
kExprI32LoadMem,0, 0,
|
|
kExprCallFunction, 0,
|
|
kExprI32Add
|
|
]).exportFunc();
|
|
|
|
// writer(mem[i]);
|
|
// return mem[i] + some_value();
|
|
builder.addFunction("_wrap_writer", signature)
|
|
.addBody([
|
|
kExprGetLocal, 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);
|
|
var invalid_buffer = new ArrayBuffer(10);
|
|
|
|
module = %DeserializeWasmModule(invalid_buffer, invalid_buffer);
|
|
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([
|
|
kExprGetGlobal, 0])
|
|
.exportFunc();
|
|
|
|
builder.addFunction("write", kSig_v_i)
|
|
.addBody([
|
|
kExprGetLocal, 0,
|
|
kExprSetGlobal, 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([
|
|
kExprGetLocal, 0, // --
|
|
kExprCallIndirect, sig_index1, kTableZero]) // --
|
|
.exportAs("main");
|
|
|
|
builder.setFunctionTableBounds(kTableSize, kTableSize);
|
|
builder.addFunctionTableInit(0, false, [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([
|
|
kExprGetLocal, 0, // --
|
|
kExprCallIndirect, sig_index2, kTableZero]) // --
|
|
.exportAs("main");
|
|
|
|
builder.addImportedTable("z", "table", kTableSize, kTableSize);
|
|
builder.addFunctionTableInit(1, false, [f2.index], true);
|
|
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([kExprGetLocal, 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, kWasmStmt,
|
|
kExprBlock, kWasmStmt,
|
|
kExprBlock, kWasmStmt,
|
|
kExprBlock, kWasmStmt,
|
|
kExprBlock, kWasmStmt,
|
|
kExprBlock, kWasmStmt,
|
|
kExprBlock, kWasmStmt,
|
|
kExprGetLocal, 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));
|
|
})();
|