diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /js/src/jit-test/lib/wasm-binary.js | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit-test/lib/wasm-binary.js')
-rw-r--r-- | js/src/jit-test/lib/wasm-binary.js | 736 |
1 files changed, 736 insertions, 0 deletions
diff --git a/js/src/jit-test/lib/wasm-binary.js b/js/src/jit-test/lib/wasm-binary.js new file mode 100644 index 0000000000..c55c8185f5 --- /dev/null +++ b/js/src/jit-test/lib/wasm-binary.js @@ -0,0 +1,736 @@ +// MagicNumber = 0x6d736100; +const magic0 = 0x00; // '\0' +const magic1 = 0x61; // 'a' +const magic2 = 0x73; // 's' +const magic3 = 0x6d; // 'm' + +// EncodingVersion +const encodingVersion = 0x1; +const ver0 = (encodingVersion >>> 0) & 0xff; +const ver1 = (encodingVersion >>> 8) & 0xff; +const ver2 = (encodingVersion >>> 16) & 0xff; +const ver3 = (encodingVersion >>> 24) & 0xff; + +// Section opcodes +const userDefinedId = 0; +const typeId = 1; +const importId = 2; +const functionId = 3; +const tableId = 4; +const memoryId = 5; +const globalId = 6; +const exportId = 7; +const startId = 8; +const elemId = 9; +const codeId = 10; +const dataId = 11; +const dataCountId = 12; +const tagId = 13; + +// User-defined section names +const nameName = "name"; + +// Name section name types +const nameTypeModule = 0; +const nameTypeFunction = 1; +const nameTypeLocal = 2; +const nameTypeTag = 3; + +// Type codes +const I32Code = 0x7f; +const I64Code = 0x7e; +const F32Code = 0x7d; +const F64Code = 0x7c; +const V128Code = 0x7b; +const AnyFuncCode = 0x70; +const ExternRefCode = 0x6f; +const EqRefCode = 0x6d; +const OptRefCode = 0x63; // (ref null $t), needs heap type immediate +const RefCode = 0x64; // (ref $t), needs heap type immediate +const FuncCode = 0x60; +const StructCode = 0x5f; +const ArrayCode = 0x5e; +const VoidCode = 0x40; +const BadType = 0x79; // reserved for testing + +// Opcodes +const UnreachableCode = 0x00 +const BlockCode = 0x02; +const TryCode = 0x06; +const CatchCode = 0x07; +const ThrowCode = 0x08; +const RethrowCode = 0x09; +const EndCode = 0x0b; +const ReturnCode = 0x0f; +const CallCode = 0x10; +const CallIndirectCode = 0x11; +const ReturnCallCode = 0x12; +const ReturnCallIndirectCode = 0x13; +const ReturnCallRefCode = 0x15; +const DelegateCode = 0x18; +const DropCode = 0x1a; +const SelectCode = 0x1b; +const LocalGetCode = 0x20; +const I32Load = 0x28; +const I64Load = 0x29; +const F32Load = 0x2a; +const F64Load = 0x2b; +const I32Load8S = 0x2c; +const I32Load8U = 0x2d; +const I32Load16S = 0x2e; +const I32Load16U = 0x2f; +const I64Load8S = 0x30; +const I64Load8U = 0x31; +const I64Load16S = 0x32; +const I64Load16U = 0x33; +const I64Load32S = 0x34; +const I64Load32U = 0x35; +const I32Store = 0x36; +const I64Store = 0x37; +const F32Store = 0x38; +const F64Store = 0x39; +const I32Store8 = 0x3a; +const I32Store16 = 0x3b; +const I64Store8 = 0x3c; +const I64Store16 = 0x3d; +const I64Store32 = 0x3e; +const GrowMemoryCode = 0x40; +const I32ConstCode = 0x41; +const I64ConstCode = 0x42; +const F32ConstCode = 0x43; +const F64ConstCode = 0x44; +const I32AddCode = 0x6a; +const I32DivSCode = 0x6d; +const I32DivUCode = 0x6e; +const I32RemSCode = 0x6f; +const I32RemUCode = 0x70; +const I32TruncSF32Code = 0xa8; +const I32TruncUF32Code = 0xa9; +const I32TruncSF64Code = 0xaa; +const I32TruncUF64Code = 0xab; +const I64TruncSF32Code = 0xae; +const I64TruncUF32Code = 0xaf; +const I64TruncSF64Code = 0xb0; +const I64TruncUF64Code = 0xb1; +const I64DivSCode = 0x7f; +const I64DivUCode = 0x80; +const I64RemSCode = 0x81; +const I64RemUCode = 0x82; +const RefNullCode = 0xd0; +const RefIsNullCode = 0xd1; +const RefFuncCode = 0xd2; + +// SIMD opcodes +const V128LoadCode = 0x00; +const V128StoreCode = 0x0b; + +// Relaxed SIMD opcodes. +const I8x16RelaxedSwizzleCode = 0x100; +const I32x4RelaxedTruncSSatF32x4Code = 0x101; +const I32x4RelaxedTruncUSatF32x4Code = 0x102; +const I32x4RelaxedTruncSatF64x2SZeroCode = 0x103; +const I32x4RelaxedTruncSatF64x2UZeroCode = 0x104; +const F32x4RelaxedMaddCode = 0x105; +const F32x4RelaxedNmaddCode = 0x106; +const F64x2RelaxedMaddCode = 0x107; +const F64x2RelaxedNmaddCode = 0x108; +const I8x16RelaxedLaneSelectCode = 0x109; +const I16x8RelaxedLaneSelectCode = 0x10a; +const I32x4RelaxedLaneSelectCode = 0x10b; +const I64x2RelaxedLaneSelectCode = 0x10c; +const F32x4RelaxedMinCode = 0x10d; +const F32x4RelaxedMaxCode = 0x10e; +const F64x2RelaxedMinCode = 0x10f; +const F64x2RelaxedMaxCode = 0x110; +const I16x8RelaxedQ15MulrSCode = 0x111; +const I16x8DotI8x16I7x16SCode = 0x112; +const I32x4DotI8x16I7x16AddSCode = 0x113; + +const FirstInvalidOpcode = 0xc5; +const LastInvalidOpcode = 0xfa; +const GcPrefix = 0xfb; +const MiscPrefix = 0xfc; +const SimdPrefix = 0xfd; +const ThreadPrefix = 0xfe; +const MozPrefix = 0xff; + +// See WasmConstants.h for documentation. +// Limit this to a group of 8 per line. + +const definedOpcodes = + [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + ...(wasmExceptionsEnabled() ? [0x06, 0x07, 0x08, 0x09] : []), + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, + ...(wasmTailCallsEnabled() ? [0x12, 0x13] : []), + ...(wasmFunctionReferencesEnabled() ? [0x14] : []), + ...(wasmTailCallsEnabled() && + wasmFunctionReferencesEnabled() ? [0x15] : []), + ...(wasmExceptionsEnabled() ? [0x18, 0x19] : []), + 0x1a, 0x1b, 0x1c, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, + 0xf0, + 0xfb, 0xfc, 0xfd, 0xfe, 0xff ]; + +const undefinedOpcodes = (function () { + let a = []; + let j = 0; + let i = 0; + while (i < 256) { + while (definedOpcodes[j] > i) + a.push(i++); + assertEq(definedOpcodes[j], i); + i++; + j++; + } + assertEq(definedOpcodes.length + a.length, 256); + return a; +})(); + +// Secondary opcode bytes for misc prefix +const MemoryInitCode = 0x08; // Pending +const DataDropCode = 0x09; // Pending +const MemoryCopyCode = 0x0a; // Pending +const MemoryFillCode = 0x0b; // Pending +const TableInitCode = 0x0c; // Pending +const ElemDropCode = 0x0d; // Pending +const TableCopyCode = 0x0e; // Pending + +const StructNew = 0x00; // UNOFFICIAL +const StructGet = 0x03; // UNOFFICIAL +const StructSet = 0x06; // UNOFFICIAL + +// DefinitionKind +const FunctionCode = 0x00; +const TableCode = 0x01; +const MemoryCode = 0x02; +const GlobalCode = 0x03; +const TagCode = 0x04; + +// ResizableFlags +const HasMaximumFlag = 0x1; + +function toU8(array) { + for (let b of array) + assertEq(b < 256, true); + return Uint8Array.from(array); +} + +function varU32(u32) { + assertEq(u32 >= 0, true, `varU32 input must be number between 0 and 2^32-1, got ${u32}`); + assertEq(u32 < Math.pow(2,32), true, `varU32 input must be number between 0 and 2^32-1, got ${u32}`); + var bytes = []; + do { + var byte = u32 & 0x7f; + u32 >>>= 7; + if (u32 != 0) + byte |= 0x80; + bytes.push(byte); + } while (u32 != 0); + return bytes; +} + +function varS32(s32) { + assertEq(s32 >= -Math.pow(2,31), true, `varS32 input must be number between -2^31 and 2^31-1, got ${s32}`); + assertEq(s32 < Math.pow(2,31), true, `varS32 input must be number between -2^31 and 2^31-1, got ${s32}`); + var bytes = []; + do { + var byte = s32 & 0x7f; + s32 >>= 7; + if (s32 != 0 && s32 != -1) + byte |= 0x80; + bytes.push(byte); + } while (s32 != 0 && s32 != -1); + return bytes; +} + +function moduleHeaderThen(...rest) { + return [magic0, magic1, magic2, magic3, ver0, ver1, ver2, ver3, ...rest]; +} + +function string(name) { + var nameBytes = name.split('').map(c => { + var code = c.charCodeAt(0); + assertEq(code < 128, true); // TODO + return code + }); + return varU32(nameBytes.length).concat(nameBytes); +} + +function encodedString(name, len) { + var name = unescape(encodeURIComponent(name)); // break into string of utf8 code points + var nameBytes = name.split('').map(c => c.charCodeAt(0)); // map to array of numbers + return varU32(len === undefined ? nameBytes.length : len).concat(nameBytes); +} + +function moduleWithSections(sectionArray) { + var bytes = moduleHeaderThen(); + for (let section of sectionArray) { + bytes.push(section.name); + bytes.push(...varU32(section.body.length)); + bytes.push(...section.body); + } + return toU8(bytes); +} + +/** + * Creates a type section for a module. Example: + * + * typeSection([ + * // (type (func (param i32 i64))) + * { kind: FuncCode, args: [I32Code, I64Code], ret: [] }, + * // (type (func (result (ref 123)))) + * { kind: FuncCode, args: [], ret: [[RefCode, ...varS32(123)]] }, + * + * // GC types are supported: + * { kind: StructCode, fields: [I32Code, { mut: true, type: [RefCode, ...varS32(123)] }] }, + * { kind: ArrayCode, elem: { mut: true, type: I32Code } }] }, + * { kind: ArrayCode, elem: { mut: true, type: [RefCode, ...varS32(123)] } }] }, + * + * // Recursion groups can be created with the recGroup function + * recGroup([ + * { kind: StructCode, fields: [I32Code, I64Code] }, + * { kind: StructCode, sub: 5, fields: [I32Code, I64Code, I32Code] }, + * ]), + * ]) + * + * ## Full documentation + * + * This function takes an array of type objects in one of the following formats: + * + * { kind: FuncCode, args: <ResultType>, ret: <ResultType> } + * { kind: StructCode, fields: [<FieldType>] } + * { kind: ArrayCode, elem: <FieldType> } + * + * Each type object can also have the following optional fields: + * + * - `sub: <number>`: Makes the type a subtype of the given type index. + * By default it will not have any parent types. + * - `final: <boolean>`: Controls whether the type is final. Default `true`. + * + * And finally, types can be placed in a recursion group by wrapping them + * with the `recGroup` function. + * + * ### ResultType + * + * A result type is a vector of value types. You provide this as an array + * where each entry is the bytes for the type. For example, for a function + * with `(return i32 (ref 123))`, you might provide: + * + * [[I32Code], [RefCode, ...varS32(123)]] + * + * If a value type is only a single byte, you can pass it directly instead of + * passing an array: + * + * [I32Code, [RefCode, ...varS32(123)]] + * + * If there is only a single value type, you can omit the outer array too: + * + * I32Code // same as [I32Code], same as [[I32Code]] + * + * And finally, `VoidCode` is a special case that results in an empty vector. + * + * VoidCode // same as [] + * + * Note that if you want to encode a single type, but that type has multiple + * bytes, you will need to keep the outermost array. + * + * [I32Code, I64Code] // sugar for [[I32Code], [I64Code]], so two types + * [RefCode, ...varS32(123)] // will be interpreted as [[RefCode], [123]], + * // i.e. two types - not what you want + * + * ### FieldType + * + * A field type is used for struct and array values, and is a value type plus + * mutability info. The general form looks like: + * + * { mut: <boolean>, type: <bytes> } + * + * For example, `(mut i32)` would look like: + * + * { mut: true, type: [I32Code] } + * + * If the type is a single byte, you can omit the array: + * + * { mut: true, type: I32Code } + * + * And if you wish for the field to be immutable, you can provide the type only: + * + * I32Code // same as { mut: false, type: I32Code } + * + */ +function typeSection(types) { + var body = []; + body.push(...varU32(types.length)); // technically a count of recursion groups + for (const type of types) { + if (type.isRecursionGroup) { + body.push(0x4f); + body.push(...varU32(type.types.length)); + for (const t of type.types) { + body.push(..._encodeType(t)); + } + } else { + body.push(..._encodeType(type)); + } + } + return { name: typeId, body }; +} + +function recGroup(types) { + return { isRecursionGroup: true, types }; +} + +/** + * Returns a "normalized" version of all the ResultType stuff from `typeSection`, + * i.e. an array of array of bytes for each value type. + */ +function _resultType(input) { + if (input === VoidCode) { + return []; + } + if (typeof input === "number") { + input = [input]; + } + input = input.map(valType => Array.isArray(valType) ? valType : [valType]); + return input; +} + +/** + * Returns a "normalized" version of FieldType from `typeSection`, i.e. an object + * of the form `{ mut: <boolean>, type: <bytes> }`. + */ +function _fieldType(input) { + if (typeof input !== "object" || Array.isArray(input)) { + input = { mut: false, type: input }; + } + if (!Array.isArray(input.type)) { + input.type = [input.type]; + } + return input; +} + +/** + * Encodes a type object from `typeSection`. This basically corresponds to `subtypeDef` + * in the GC spec doc. + */ +function _encodeType(typeObj) { + const typeBytes = []; + // Types are now final by default. + const final = typeObj.final ?? true; + if (typeObj.sub !== undefined) { + typeBytes.push(final ? 0x4e : 0x50); + 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(0x00); + } + typeBytes.push(typeObj.kind); + switch (typeObj.kind) { + case FuncCode: { + const args = _resultType(typeObj.args); + const ret = _resultType(typeObj.ret); + typeBytes.push(...varU32(args.length)); + for (const t of args) { + typeBytes.push(...t); + } + typeBytes.push(...varU32(ret.length)); + for (const t of ret) { + typeBytes.push(...t); + } + } break; + case StructCode: { + // fields + typeBytes.push(...varU32(typeObj.fields.length)); + for (const f of typeObj.fields) { + typeBytes.push(..._encodeFieldType(f)); + } + } break; + case ArrayCode: { + // elem + typeBytes.push(..._encodeFieldType(typeObj.elem)); + } break; + default: + throw new Error(`unknown type kind ${typeObj.kind} in type section`); + } + return typeBytes; +} + +function _encodeFieldType(fieldTypeObj) { + fieldTypeObj = _fieldType(fieldTypeObj); + return [...fieldTypeObj.type, fieldTypeObj.mut ? 0x01 : 0x00]; +} + +/** + * A convenience function to create a type section containing only function + * types. This is basically sugar for `typeSection`, although you do not have + * to provide `kind: FuncCode` on each definition as you would there. + * + * Example: + * + * sigSection([ + * // (type (func (param i32 i64))) + * { args: [I32Code, I64Code], ret: [] }, + * // (type (func (result (ref 123)))) + * { args: [], ret: [[RefCode, ...varS32(123)]] }, + * ]) + * + */ +function sigSection(sigs) { + return typeSection(sigs.map(sig => ({ kind: FuncCode, ...sig }))); +} + +function declSection(decls) { + var body = []; + body.push(...varU32(decls.length)); + for (let decl of decls) + body.push(...varU32(decl)); + return { name: functionId, body }; +} + +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); + if (withEndCode) + body.push(EndCode); + body.splice(0, 0, ...varU32(body.length)); + return body; +} + +function bodySection(bodies) { + var body = varU32(bodies.length).concat(...bodies); + return { name: codeId, body }; +} + +function importSection(imports) { + var body = []; + body.push(...varU32(imports.length)); + for (let imp of imports) { + body.push(...string(imp.module)); + body.push(...string(imp.func)); + body.push(...varU32(FunctionCode)); + body.push(...varU32(imp.sigIndex)); + } + return { name: importId, body }; +} + +function exportSection(exports) { + var body = []; + body.push(...varU32(exports.length)); + for (let exp of exports) { + body.push(...string(exp.name)); + if (exp.hasOwnProperty("funcIndex")) { + body.push(...varU32(FunctionCode)); + body.push(...varU32(exp.funcIndex)); + } else if (exp.hasOwnProperty("memIndex")) { + body.push(...varU32(MemoryCode)); + body.push(...varU32(exp.memIndex)); + } else if (exp.hasOwnProperty("tagIndex")) { + body.push(...varU32(TagCode)); + body.push(...varU32(exp.tagIndex)); + } else { + throw "Bad export " + exp; + } + } + return { name: exportId, body }; +} + +function tableSection(initialSize) { + var body = []; + body.push(...varU32(1)); // number of tables + body.push(...varU32(AnyFuncCode)); + body.push(...varU32(0x0)); // for now, no maximum + body.push(...varU32(initialSize)); + return { name: tableId, body }; +} + +function memorySection(initialSize) { + var body = []; + body.push(...varU32(1)); // number of memories + body.push(...varU32(0x0)); // for now, no maximum + body.push(...varU32(initialSize)); + return { name: memoryId, body }; +} + +function tagSection(tags) { + var body = []; + body.push(...varU32(tags.length)); + for (let tag of tags) { + body.push(...varU32(0)); // exception attribute + body.push(...varU32(tag.type)); + } + return { name: tagId, body }; +} + +function dataSection(segmentArrays) { + var body = []; + body.push(...varU32(segmentArrays.length)); + for (let array of segmentArrays) { + body.push(...varU32(0)); // table index + body.push(...varU32(I32ConstCode)); + body.push(...varS32(array.offset)); + body.push(...varU32(EndCode)); + body.push(...varU32(array.elems.length)); + for (let elem of array.elems) + body.push(...varU32(elem)); + } + return { name: dataId, body }; +} + +function dataCountSection(count) { + var body = []; + body.push(...varU32(count)); + return { name: dataCountId, body }; +} + +function globalSection(globalArray) { + var body = []; + body.push(...varU32(globalArray.length)); + for (let globalObj of globalArray) { + // Value type + body.push(...varU32(globalObj.valType)); + // Flags + body.push(globalObj.flags & 255); + // Initializer expression + body.push(...globalObj.initExpr); + } + return { name: globalId, body }; +} + +function elemSection(elemArrays) { + var body = []; + body.push(...varU32(elemArrays.length)); + for (let array of elemArrays) { + body.push(...varU32(0)); // table index + body.push(...varU32(I32ConstCode)); + body.push(...varS32(array.offset)); + body.push(...varU32(EndCode)); + body.push(...varU32(array.elems.length)); + for (let elem of array.elems) + body.push(...varU32(elem)); + } + return { name: elemId, body }; +} + +// For now, the encoding spec is here: +// https://github.com/WebAssembly/bulk-memory-operations/issues/98#issuecomment-507330729 + +const LegacyActiveExternVal = 0; +const PassiveExternVal = 1; +const ActiveExternVal = 2; +const DeclaredExternVal = 3; +const LegacyActiveElemExpr = 4; +const PassiveElemExpr = 5; +const ActiveElemExpr = 6; +const DeclaredElemExpr = 7; + +function generalElemSection(elemObjs) { + let body = []; + body.push(...varU32(elemObjs.length)); + for (let elemObj of elemObjs) { + body.push(elemObj.flag); + if ((elemObj.flag & 3) == 2) + body.push(...varU32(elemObj.table)); + // TODO: This is not very flexible + if ((elemObj.flag & 1) == 0) { + body.push(...varU32(I32ConstCode)); + body.push(...varS32(elemObj.offset)); + body.push(...varU32(EndCode)); + } + if (elemObj.flag & 4) { + if (elemObj.flag & 3) + body.push(elemObj.typeCode & 255); + // Each element is an array of bytes + body.push(...varU32(elemObj.elems.length)); + for (let elemBytes of elemObj.elems) + body.push(...elemBytes); + } else { + if (elemObj.flag & 3) + body.push(elemObj.externKind & 255); + // Each element is a putative function index + body.push(...varU32(elemObj.elems.length)); + for (let elem of elemObj.elems) + body.push(...varU32(elem)); + } + } + return { name: elemId, body }; +} + +function moduleNameSubsection(moduleName) { + var body = []; + body.push(...varU32(nameTypeModule)); + + var subsection = encodedString(moduleName); + body.push(...varU32(subsection.length)); + body.push(...subsection); + + return body; +} + +function funcNameSubsection(funcNames) { + var body = []; + body.push(...varU32(nameTypeFunction)); + + var subsection = varU32(funcNames.length); + + var funcIndex = 0; + for (let f of funcNames) { + subsection.push(...varU32(f.index ? f.index : funcIndex)); + subsection.push(...encodedString(f.name, f.nameLen)); + funcIndex++; + } + + body.push(...varU32(subsection.length)); + body.push(...subsection); + return body; +} + +function nameSection(subsections) { + var body = []; + body.push(...string(nameName)); + + for (let ss of subsections) + body.push(...ss); + + return { name: userDefinedId, body }; +} + +function customSection(name, ...body) { + return { name: userDefinedId, body: [...string(name), ...body] }; +} + +function tableSection0() { + var body = []; + body.push(...varU32(0)); // number of tables + return { name: tableId, body }; +} + +function memorySection0() { + var body = []; + body.push(...varU32(0)); // number of memories + return { name: memoryId, body }; +} |