Skip to content

Commit

Permalink
Bug 1856635: Speed up wasm/gc/limits.js test. r=bvisness
Browse files Browse the repository at this point in the history
  • Loading branch information
bvisness committed Mar 12, 2024
1 parent 554129b commit cd5cd03
Show file tree
Hide file tree
Showing 27 changed files with 368 additions and 151 deletions.
71 changes: 71 additions & 0 deletions js/src/jit-test/lib/gen/wasm-gc-limits-gen.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Generates large .wasm files for use in ../limits.js.
// Make sure you are running this script from a release build or you will be sad.

loadRelativeToScript("../wasm-binary.js");

function moduleNRecGroupNTypes(numRecs, numTypes) {
let types = [];
for (let i = 0; i < numTypes; i++) {
types.push({ kind: FuncCode, args: [], ret: [] });
}
let recs = [];
for (let i = 0; i < numRecs; i++) {
recs.push(recGroup(types));
}
return new Uint8Array(compressLZ4(new Uint8Array(moduleWithSections([typeSection(recs)])).buffer));
}

os.file.writeTypedArrayToFile("wasm-gc-limits-r1M-t1.wasm", moduleNRecGroupNTypes(1_000_000, 1));
os.file.writeTypedArrayToFile("wasm-gc-limits-r1M1-t1.wasm", moduleNRecGroupNTypes(1_000_001, 1));
os.file.writeTypedArrayToFile("wasm-gc-limits-r1-t1M.wasm", moduleNRecGroupNTypes(1, 1_000_000));
os.file.writeTypedArrayToFile("wasm-gc-limits-r1-t1M1.wasm", moduleNRecGroupNTypes(1, 1_000_001));
os.file.writeTypedArrayToFile("wasm-gc-limits-r2-t500K.wasm", moduleNRecGroupNTypes(2, 500_000));
os.file.writeTypedArrayToFile("wasm-gc-limits-r2-t500K1.wasm", moduleNRecGroupNTypes(2, 500_001));

function moduleLargeStruct(size) {
let structInitializer = [];
for (let i = 0; i < size; i++) {
structInitializer.push(I64ConstCode);
structInitializer.push(...varU32(0));
}
return new Uint8Array(compressLZ4(new Uint8Array(moduleWithSections([
typeSection([
{
kind: StructCode,
fields: Array(size).fill(I64Code)
},
{
kind: FuncCode,
args: [],
ret: [AnyRefCode]
}
]),
declSection([1, 1]),
exportSection([
{name: "makeLargeStructDefault", funcIndex: 0},
{name: "makeLargeStruct", funcIndex: 1}
]),
bodySection([
funcBody({
locals: [],
body: [
GcPrefix,
StructNewDefault,
...varU32(0)
],
}),
funcBody({
locals: [],
body: [
...structInitializer,
GcPrefix,
StructNew,
...varU32(0)
],
}),
]),
])).buffer));
}

os.file.writeTypedArrayToFile("wasm-gc-limits-s10K.wasm", moduleLargeStruct(10_000));
os.file.writeTypedArrayToFile("wasm-gc-limits-s10K1.wasm", moduleLargeStruct(10_001));
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added js/src/jit-test/lib/gen/wasm-gc-limits-s10K.wasm
Binary file not shown.
Binary file added js/src/jit-test/lib/gen/wasm-gc-limits-s10K1.wasm
Binary file not shown.
38 changes: 26 additions & 12 deletions js/src/jit-test/lib/wasm-binary.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const F64Code = 0x7c;
const V128Code = 0x7b;
const AnyFuncCode = 0x70;
const ExternRefCode = 0x6f;
const AnyRefCode = 0x6e;
const EqRefCode = 0x6d;
const OptRefCode = 0x63; // (ref null $t), needs heap type immediate
const RefCode = 0x64; // (ref $t), needs heap type immediate
Expand All @@ -52,6 +53,9 @@ const StructCode = 0x5f;
const ArrayCode = 0x5e;
const VoidCode = 0x40;
const BadType = 0x79; // reserved for testing
const RecGroupCode = 0x4e;
const SubFinalTypeCode = 0x4f;
const SubNoFinalTypeCode = 0x50;

// Opcodes
const UnreachableCode = 0x00
Expand Down Expand Up @@ -220,6 +224,7 @@ const ElemDropCode = 0x0d; // Pending
const TableCopyCode = 0x0e; // Pending

const StructNew = 0x00; // UNOFFICIAL
const StructNewDefault = 0x01; // UNOFFICIAL
const StructGet = 0x03; // UNOFFICIAL
const StructSet = 0x06; // UNOFFICIAL

Expand All @@ -234,8 +239,9 @@ const TagCode = 0x04;
const HasMaximumFlag = 0x1;

function toU8(array) {
for (let b of array)
assertEq(b < 256, true);
for (const [i, b] of array.entries()) {
assertEq(b < 256, true, `expected byte at index ${i} but got ${b}`);
}
return Uint8Array.from(array);
}

Expand Down Expand Up @@ -286,12 +292,14 @@ function encodedString(name, len) {
return varU32(len === undefined ? nameBytes.length : len).concat(nameBytes);
}

function moduleWithSections(sectionArray) {
var bytes = moduleHeaderThen();
for (let section of sectionArray) {
function moduleWithSections(sections) {
const bytes = moduleHeaderThen();
for (const section of sections) {
bytes.push(section.name);
bytes.push(...varU32(section.body.length));
bytes.push(...section.body);
for (let byte of section.body) {
bytes.push(byte);
}
}
return toU8(bytes);
}
Expand Down Expand Up @@ -387,13 +395,17 @@ function typeSection(types) {
body.push(...varU32(types.length)); // technically a count of recursion groups
for (const type of types) {
if (type.isRecursionGroup) {
body.push(0x4f);
body.push(RecGroupCode);
body.push(...varU32(type.types.length));
for (const t of type.types) {
body.push(..._encodeType(t));
for (const byte of _encodeType(t)) {
body.push(byte);
}
}
} else {
body.push(..._encodeType(type));
for (const byte of _encodeType(type)) {
body.push(byte);
}
}
}
return { name: typeId, body };
Expand Down Expand Up @@ -441,12 +453,12 @@ function _encodeType(typeObj) {
// Types are now final by default.
const final = typeObj.final ?? true;
if (typeObj.sub !== undefined) {
typeBytes.push(final ? 0x4e : 0x50);
typeBytes.push(final ? SubFinalTypeCode : SubNoFinalTypeCode);
typeBytes.push(...varU32(1), ...varU32(typeObj.sub));
}
else if (final == false) {
// This type is extensible even if no supertype is defined.
typeBytes.push(0x50);
typeBytes.push(SubNoFinalTypeCode);
typeBytes.push(0x00);
}
typeBytes.push(typeObj.kind);
Expand Down Expand Up @@ -516,7 +528,9 @@ function funcBody(func, withEndCode=true) {
var body = varU32(func.locals.length);
for (let local of func.locals)
body.push(...varU32(local));
body = body.concat(...func.body);
for (let byte of func.body) {
body.push(byte);
}
if (withEndCode)
body.push(EndCode);
body.splice(0, 0, ...varU32(body.length));
Expand Down
21 changes: 15 additions & 6 deletions js/src/jit-test/lib/wasm.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ if (largeArrayBufferSupported()) {
}
var MaxPagesIn32BitMemory = Math.floor(MaxBytesIn32BitMemory / PageSizeInBytes);

function wasmEvalText(str, imports, compileOptions) {
let binary = wasmTextToBinary(str);
function wasmEvalBinary(binary, imports, compileOptions) {
let valid = WebAssembly.validate(binary, compileOptions);

let m;
Expand All @@ -60,8 +59,11 @@ function wasmEvalText(str, imports, compileOptions) {
return new WebAssembly.Instance(m, imports);
}

function wasmValidateText(str) {
let binary = wasmTextToBinary(str);
function wasmEvalText(str, imports, compileOptions) {
return wasmEvalBinary(wasmTextToBinary(str), imports, compileOptions);
}

function wasmValidateBinary(binary) {
let valid = WebAssembly.validate(binary);
if (!valid) {
new WebAssembly.Module(binary);
Expand All @@ -70,12 +72,19 @@ function wasmValidateText(str) {
assertEq(valid, true, "wasm module was invalid");
}

function wasmFailValidateText(str, pattern) {
let binary = wasmTextToBinary(str);
function wasmFailValidateBinary(binary, pattern) {
assertEq(WebAssembly.validate(binary), false, "module passed WebAssembly.validate when it should not have");
assertErrorMessage(() => new WebAssembly.Module(binary), WebAssembly.CompileError, pattern, "module failed WebAssembly.validate but did not fail to compile as expected");
}

function wasmValidateText(str) {
return wasmValidateBinary(wasmTextToBinary(str));
}

function wasmFailValidateText(str, pattern) {
return wasmFailValidateBinary(wasmTextToBinary(str), pattern);
}

// Expected compilation failure can happen in a couple of ways:
//
// - The compiler can be available but not capable of recognizing some opcodes:
Expand Down
16 changes: 9 additions & 7 deletions js/src/jit-test/tests/wasm/gc/binary.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

load(libdir + "wasm-binary.js");

const v2vSig = {args:[], ret:VoidCode};
const v2vSigSection = sigSection([v2vSig]);

function checkInvalid(body, errorMessage) {
assertErrorMessage(() => new WebAssembly.Module(
moduleWithSections([v2vSigSection, declSection([0]), bodySection([body])])),
WebAssembly.CompileError,
errorMessage);
moduleWithSections([
typeSection([
{ kind: FuncCode, args: [], ret: [] },
]),
declSection([0]),
bodySection([body]),
])
), WebAssembly.CompileError, errorMessage);
}

const invalidRefBlockType = funcBody({locals:[], body:[
Expand All @@ -23,7 +25,7 @@ checkInvalid(invalidRefBlockType, /heap type/);
const invalidTooBigRefType = funcBody({locals:[], body:[
BlockCode,
OptRefCode,
varU32(1000000),
...varU32(1000000),
EndCode,
]});
checkInvalid(invalidTooBigRefType, /heap type/);
69 changes: 0 additions & 69 deletions js/src/jit-test/tests/wasm/gc/limits.js

This file was deleted.

9 changes: 9 additions & 0 deletions js/src/jit-test/tests/wasm/gc/limits/array-new-fixed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// |jit-test| --setpref=wasm_gc; include:wasm.js;

// array.new_fixed has limit of 10_000 operands
wasmFailValidateText(`(module
(type $a (array i32))
(func
array.new_fixed $a 10001
)
)`, /too many/);
5 changes: 5 additions & 0 deletions js/src/jit-test/tests/wasm/gc/limits/load-mod.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Files for some of these tests are pre-generated and located in js/src/jit-test/lib/gen.
// There you will also find the script to update these files.
function loadMod(name) {
return decompressLZ4(os.file.readFile(libdir + "gen/" + name, "binary").buffer)
}
6 changes: 6 additions & 0 deletions js/src/jit-test/tests/wasm/gc/limits/rec-groups-1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// |jit-test| --setpref=wasm_gc; include:wasm.js;

loadRelativeToScript("load-mod.js");

// Limit of 1 million recursion groups
wasmValidateBinary(loadMod("wasm-gc-limits-r1M-t1.wasm"));
6 changes: 6 additions & 0 deletions js/src/jit-test/tests/wasm/gc/limits/rec-groups-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// |jit-test| --setpref=wasm_gc; include:wasm.js;

loadRelativeToScript("load-mod.js");

// Limit of 1 million recursion groups
wasmFailValidateBinary(loadMod("wasm-gc-limits-r1M1-t1.wasm"), /too many/);
11 changes: 11 additions & 0 deletions js/src/jit-test/tests/wasm/gc/limits/struct-fields.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// |jit-test| --setpref=wasm_gc; test-also=--wasm-compiler=optimizing; test-also=--wasm-compiler=baseline; include:wasm.js;

loadRelativeToScript("load-mod.js");

// Limit of 10_000 struct fields
wasmFailValidateBinary(loadMod("wasm-gc-limits-s10K1.wasm"), /too many/);
{
let {makeLargeStructDefault, makeLargeStruct} = wasmEvalBinary(loadMod("wasm-gc-limits-s10K.wasm")).exports;
let largeStructDefault = makeLargeStructDefault();
let largeStruct = makeLargeStruct();
}
13 changes: 13 additions & 0 deletions js/src/jit-test/tests/wasm/gc/limits/subtyping-depth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// |jit-test| --setpref=wasm_gc; include:wasm.js; include: wasm-binary.js;

// Limit of subtyping hierarchy 63 deep
function moduleSubtypingDepth(depth) {
let types = [];
types.push({final: false, kind: FuncCode, args: [], ret: []});
for (let i = 1; i <= depth; i++) {
types.push({final: false, sub: i - 1, kind: FuncCode, args: [], ret: []});
}
return moduleWithSections([typeSection(types)]);
}
wasmValidateBinary(moduleSubtypingDepth(63));
wasmFailValidateBinary(moduleSubtypingDepth(64), /too deep/);
6 changes: 6 additions & 0 deletions js/src/jit-test/tests/wasm/gc/limits/types-1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// |jit-test| --setpref=wasm_gc; include:wasm.js;

loadRelativeToScript("load-mod.js");

// Limit of 1 million types (across all recursion groups)
wasmValidateBinary(loadMod("wasm-gc-limits-r1-t1M.wasm"));
6 changes: 6 additions & 0 deletions js/src/jit-test/tests/wasm/gc/limits/types-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// |jit-test| --setpref=wasm_gc; include:wasm.js;

loadRelativeToScript("load-mod.js");

// Limit of 1 million types (across all recursion groups)
wasmValidateBinary(loadMod("wasm-gc-limits-r2-t500K.wasm"));
Loading

0 comments on commit cd5cd03

Please sign in to comment.