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;
})();
function toU8(array) { for (const [i, b] of array.entries()) {
assertEq(b < 256, true, `expected byte at index ${i} but got ${b}`);
} return Uint8Array.from(array);
}
function toResizableU8(array) {
let sab = new ArrayBuffer(array.length, { maxByteLength: array.length });
let view = new Uint8Array(sab); for (const [i, b] of array.entries()) {
assertEq(b < 256, true, `expected byte at index ${i} but got ${b}`);
view[i] = b;
} return view;
}
function toSharedU8(array) {
let sab = new SharedArrayBuffer(array.length);
let view = new Uint8Array(sab); for (const [i, b] of array.entries()) {
assertEq(b < 256, true, `expected byte at index ${i} but got ${b}`);
view[i] = b;
} return view;
}
function toGrowableSharedU8(array) {
let sab = new SharedArrayBuffer(array.length, { maxByteLength: array.length });
let view = new Uint8Array(sab); for (const [i, b] of array.entries()) {
assertEq(b < 256, true, `expected byte at index ${i} but got ${b}`);
view[i] = b;
} return view;
}
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 { varbyte = 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 { varbyte = s32 & 0x7f;
s32 >>= 7; if (s32 != 0 && s32 != -1) byte |= 0x80;
bytes.push(byte);
} while (s32 != 0 && s32 != -1); return bytes;
}
function varU64(u64) {
u64 = BigInt(u64);
assertEq(u64 >= 0n, true, `varU64 input must be number between 0 and 2^64-1, got ${u64}`);
assertEq(u64 < 2n**64n, true, `varU64 input must be number between 0 and 2^64-1, got ${u64}`); var bytes = []; do { varbyte = Number(u64 & 0x7fn);
u64 >>= 7n; if (u64 !== 0n) byte |= 0x80;
bytes.push(byte);
} while (u64 !== 0n); return bytes;
}
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(sections, toBuffer=toU8) { const bytes = moduleHeaderThen(); for (const section of sections) {
bytes.push(section.name);
bytes.push(...varU32(section.length ?? section.body.length)); for (let byte of section.body) {
bytes.push(byte);
}
} return toBuffer(bytes);
}
/** *Createsatypesectionforamodule.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]}, *]), *]) * *##Fulldocumentation * *Thisfunctiontakesanarrayoftypeobjectsinoneofthefollowingformats: * *{kind:FuncCode,args:<ResultType>,ret:<ResultType>} *{kind:StructCode,fields:[<FieldType>]} *{kind:ArrayCode,elem:<FieldType>} * *Eachtypeobjectcanalsohavethefollowingoptionalfields: * *-`sub:<number>`:Makesthetypeasubtypeofthegiventypeindex. *Bydefaultitwillnothaveanyparenttypes. *-`final:<boolean>`:Controlswhetherthetypeisfinal.Default`true`. * *Andfinally,typescanbeplacedinarecursiongroupbywrappingthem *withthe`recGroup`function. * *###ResultType * *Aresulttypeisavectorofvaluetypes.Youprovidethisasanarray *whereeachentryisthebytesforthetype.Forexample,forafunction *with`(returni32(ref123))`,youmightprovide: * *[[I32Code],[RefCode,...varS32(123)]] * *Ifavaluetypeisonlyasinglebyte,youcanpassitdirectlyinsteadof *passinganarray: * *[I32Code,[RefCode,...varS32(123)]] * *Ifthereisonlyasinglevaluetype,youcanomittheouterarraytoo: * *I32Code// same as [I32Code], same as [[I32Code]] * *Andfinally,`VoidCode`isaspecialcasethatresultsinanemptyvector. * *VoidCode// same as [] * *Notethatifyouwanttoencodeasingletype,butthattypehasmultiple *bytes,youwillneedtokeeptheoutermostarray. * *[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 * *Afieldtypeisusedforstructandarrayvalues,andisavaluetypeplus *mutabilityinfo.Thegeneralformlookslike: * *{mut:<boolean>,type:<bytes>} * *Forexample,`(muti32)`wouldlooklike: * *{mut:true,type:[I32Code]} * *Ifthetypeisasinglebyte,youcanomitthearray: * *{mut:true,type:I32Code} * *Andifyouwishforthefieldtobeimmutable,youcanprovidethetypeonly: * *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(RecGroupCode);
body.push(...varU32(type.types.length)); for (const t of type.types) { for (constbyte of _encodeType(t)) {
body.push(byte);
}
}
} else { for (constbyte of _encodeType(type)) {
body.push(byte);
}
}
} return { name: typeId, body };
}
function recGroup(types) { return { isRecursionGroup: true, types };
}
/** *Encodesatypeobjectfrom`typeSection`.Thisbasicallycorrespondsto`subtypeDef` *intheGCspecdoc.
*/ function _encodeType(typeObj) { const typeBytes = []; // Types are now final by default. constfinal = typeObj.final ?? true; if (typeObj.sub !== undefined) {
typeBytes.push(final ? SubFinalTypeCode : SubNoFinalTypeCode);
typeBytes.push(...varU32(1), ...varU32(typeObj.sub));
} elseif (final == false) { // This type is extensible even if no supertype is defined.
typeBytes.push(SubNoFinalTypeCode);
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: thrownew Error(`unknown type kind ${typeObj.kind} in type section`);
} return typeBytes;
}
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)); for (let byte of func.body) {
body.push(byte);
} 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 };
}
/** *Encodeanimportsection: *https://webassembly.github.io/spec/core/binary/modules.html#binary-importsec * *importSection([ *// Normal encoding *{module:"a",item:"b",type:externtype({funcTypeIndex:123})}, * *// Compact encoding 1 *{module:"a",items:[ *{item:"c",type:externtype({globalType:globalType({valType:I32Code,mut:true})})}, *{item:"d",type:externtype({memType:limits({min:0})})}, *]}, * *// Compact encoding 2 *{ *module:"a", *type:externtype({globalType:globalType({valType:[RefCode,ExternRefCode]})}), *items:["e","f","g"], *}, *]);
*/ function importSection(importGroups) { var body = [];
body.push(...varU32(importGroups.length)); for (let group of importGroups) {
body.push(...string(group.module)); if (group.items) { if (group.type) { // Compact encoding (one module/type, many item names)
body.push(...string(""));
body.push(0x7E);
body.push(...group.type);
body.push(...varU32(group.numItems ?? group.items.length)); for (const item of group.items) {
body.push(...string(item));
}
} else { // Compact encoding (one module, many name/type pairs)
body.push(...string(""));
body.push(0x7F);
body.push(...varU32(group.numItems ?? group.items.length)); for (const item of group.items) {
body.push(...string(item.item));
body.push(...item.type);
}
}
} else { // Single-item encoding
body.push(...string(group.item));
body.push(...group.type);
}
} 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(ExternFuncCode));
body.push(...varU32(exp.funcIndex));
} elseif (exp.hasOwnProperty("memIndex")) {
body.push(...varU32(ExternMemCode));
body.push(...varU32(exp.memIndex));
} elseif (exp.hasOwnProperty("tagIndex")) {
body.push(...varU32(ExternTagCode));
body.push(...varU32(exp.tagIndex));
} else { throw"Bad export " + exp;
}
} return { name: exportId, body };
}
/** *Encodeatablesection: *https://wasm-dsl.github.io/spectec/core/binary/modules.html#table-section * *tableSection([ *// (table 10 100 funcref), two ways *{type:tableType(FuncRefCode,{min:10,max:100})}, *{elemType:FuncRefCode,min:10,max:100}, * *// (table i64 10 (ref func) ref.func 123), two ways *{ *type:tableType([RefCode,FuncRefCode],{addrType:"i64",min:10n}), *init:[RefFuncCode,...varU32(123),EndCode], *}, *{ *elemType:[RefCode,FuncRefCode], *addrType:"i64",min:10n, *init:[RefFuncCode,...varU32(123),EndCode], *}, *]);
*/ function tableSection(tables) { var body = [];
body.push(...varU32(tables.length)); for (const table of tables) { if (table.init) {
body.push(0x40, 0x00);
} if (table.type) {
body.push(...table.type);
} else {
body.push(...tableType(table.elemType, limits({
addrType: table.addrType ?? "i32",
min: table.min, max: table.max,
})));
} if (table.init) {
body.push(...table.init);
}
} return { name: tableId, body };
}
/** *Createlimits: *https://wasm-dsl.github.io/spectec/core/binary/types.html#binary-limits * *limits({min:0}) *limits({addrType:"i64",min:0n,max:10n})
*/ function limits({ addrType = "i32", min, max }) { var body = [];
body.push((addrType === "i64" ? 0x04 : 0x00) & (max === undefined ? 0x00 : 0x01));
body.push(...varU64(min)); if (max !== undefined) {
body.push(...varU64(max));
} return body;
}
/** *Createatabletype: *https://wasm-dsl.github.io/spectec/core/binary/types.html#table-types * *tableType(FuncRefCode,limits({min:0})) *tableType([RefCode,...varS32(123)],limits({addrType:"i64",min:0n,max:10n}))
*/ function tableType(elemType, limits) { var body = []; if (typeof elemType === "number") {
elemType = [elemType];
}
body.push(...elemType);
body.push(...limits); return 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)); // memory 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 };
}
/** *Encodeaglobaltype: * *globalType({valType:I32Code,mut:true}); *globalType({valType:FuncRefCode,mut:false}); *globalType({valType:[RefCode,FuncRefCode],mut:false}); *globalType({valType:[RefCode,...varS32(123)],mut:true});
*/ function globalType(global) { var body = [];
body.push(...(Array.isArray(global.valType) ? global.valType : varU32(global.valType)));
body.push(global.mut ? 0x01 : 0x00); return body;
}
/** *Encodeanelementsection: *https://webassembly.github.io/spec/core/binary/modules.html#element-section * *Thisiscomplicatedbecausetheencodingis *complicated:active/passive/declarative,explicittableindexorno,indices *vs.expressions. * *Theeightvariantsdefinedbythespeccanbeexpressedlikeso: * *elemSection([{mode:"active",offset:0,indices:[1,2,3]}]); *elemSection([{mode:"passive",indices:[1,2,3]}]); *elemSection([{mode:"active",table:1,offset:0,indices:[1,2,3]}]); *elemSection([{mode:"declarative",indices:[1,2,3]}]); *elemSection([{mode:"active",offset:0,exprs:[[RefFuncCode,...varU32(123),EndCode]]}]); *elemSection([{mode:"passive",elemType:[FuncRefCode],exprs:[[RefFuncCode,...varU32(123),EndCode]]}]); *elemSection([{mode:"active",table:1,offset:0,exprs:[[RefFuncCode,...varU32(123),EndCode]]}]); *elemSection([{mode:"declarative",elemType:[FuncRefCode],exprs:[[RefFuncCode,...varU32(123),EndCode]]}]);
*/ function elemSection(elemSegments) { const body = [];
body.push(...varU32(elemSegments.length)); for (const segment of elemSegments) { if (!["active", "passive", "declarative"].includes(segment.mode)) { thrownew Error(`segment mode must be "active", "passive", or "declarative", but got ${segment.mode}`);
} if (!segment.indices && !segment.exprs) { thrownew Error("segment must have either .indices or .exprs");
} if (segment.mode === "active" && segment.offset === undefined) { thrownew Error("active element segment must have .offset");
} if (segment.mode !== "active" && segment.exprs && segment.elemType === undefined) { thrownew Error("non-active element segment with expression encoding must have .elemType");
}
body.push(flag); if (segment.table !== undefined) {
body.push(...varU32(segment.table));
} if (segment.mode === "active") {
body.push(...varU32(I32ConstCode));
body.push(...varS32(segment.offset));
body.push(...varU32(EndCode));
} if (segment.exprs === undefined) { // Function index encoding if (segment.mode !== "active" || segment.table !== undefined) {
body.push(0x00); // elemkind
}
body.push(...varU32(segment.indices.length)); for (const idx of segment.indices) {
body.push(...varU32(idx));
}
} else { // Elem expression encoding if (segment.mode !== "active") {
body.push(...segment.elemType);
}
body.push(...varU32(segment.exprs.length)); for (const elemExpr of segment.exprs) {
body.push(...elemExpr);
}
}
} 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, subsectionLen = null) { 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++;
}
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 };
}
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.21Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.