| function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } |
| |
| import { CompileError } from "@webassemblyjs/helper-api-error"; |
| import * as ieee754 from "@webassemblyjs/ieee754"; |
| import * as utf8 from "@webassemblyjs/utf8"; |
| import * as t from "@webassemblyjs/ast"; |
| import { decodeInt32, decodeUInt32, MAX_NUMBER_OF_BYTE_U32, decodeInt64, decodeUInt64, MAX_NUMBER_OF_BYTE_U64 } from "@webassemblyjs/leb128"; |
| import constants from "@webassemblyjs/helper-wasm-bytecode"; |
| |
| function toHex(n) { |
| return "0x" + Number(n).toString(16); |
| } |
| |
| function byteArrayEq(l, r) { |
| if (l.length !== r.length) { |
| return false; |
| } |
| |
| for (var i = 0; i < l.length; i++) { |
| if (l[i] !== r[i]) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| export function decode(ab, opts) { |
| var buf = new Uint8Array(ab); |
| var getUniqueName = t.getUniqueNameGenerator(); |
| var offset = 0; |
| |
| function getPosition() { |
| return { |
| line: -1, |
| column: offset |
| }; |
| } |
| |
| function dump(b, msg) { |
| if (opts.dump === false) return; |
| var pad = "\t\t\t\t\t\t\t\t\t\t"; |
| var str = ""; |
| |
| if (b.length < 5) { |
| str = b.map(toHex).join(" "); |
| } else { |
| str = "..."; |
| } |
| |
| console.log(toHex(offset) + ":\t", str, pad, ";", msg); |
| } |
| |
| function dumpSep(msg) { |
| if (opts.dump === false) return; |
| console.log(";", msg); |
| } |
| /** |
| * TODO(sven): we can atually use a same structure |
| * we are adding incrementally new features |
| */ |
| |
| |
| var state = { |
| elementsInFuncSection: [], |
| elementsInExportSection: [], |
| elementsInCodeSection: [], |
| |
| /** |
| * Decode memory from: |
| * - Memory section |
| */ |
| memoriesInModule: [], |
| |
| /** |
| * Decoded types from: |
| * - Type section |
| */ |
| typesInModule: [], |
| |
| /** |
| * Decoded functions from: |
| * - Function section |
| * - Import section |
| */ |
| functionsInModule: [], |
| |
| /** |
| * Decoded tables from: |
| * - Table section |
| */ |
| tablesInModule: [], |
| |
| /** |
| * Decoded globals from: |
| * - Global section |
| */ |
| globalsInModule: [] |
| }; |
| |
| function isEOF() { |
| return offset >= buf.length; |
| } |
| |
| function eatBytes(n) { |
| offset = offset + n; |
| } |
| |
| function readBytesAtOffset(_offset, numberOfBytes) { |
| var arr = []; |
| |
| for (var i = 0; i < numberOfBytes; i++) { |
| arr.push(buf[_offset + i]); |
| } |
| |
| return arr; |
| } |
| |
| function readBytes(numberOfBytes) { |
| return readBytesAtOffset(offset, numberOfBytes); |
| } |
| |
| function readF64() { |
| var bytes = readBytes(ieee754.NUMBER_OF_BYTE_F64); |
| var value = ieee754.decodeF64(bytes); |
| |
| if (Math.sign(value) * value === Infinity) { |
| return { |
| value: Math.sign(value), |
| inf: true, |
| nextIndex: ieee754.NUMBER_OF_BYTE_F64 |
| }; |
| } |
| |
| if (isNaN(value)) { |
| var sign = bytes[bytes.length - 1] >> 7 ? -1 : 1; |
| var mantissa = 0; |
| |
| for (var i = 0; i < bytes.length - 2; ++i) { |
| mantissa += bytes[i] * Math.pow(256, i); |
| } |
| |
| mantissa += bytes[bytes.length - 2] % 16 * Math.pow(256, bytes.length - 2); |
| return { |
| value: sign * mantissa, |
| nan: true, |
| nextIndex: ieee754.NUMBER_OF_BYTE_F64 |
| }; |
| } |
| |
| return { |
| value: value, |
| nextIndex: ieee754.NUMBER_OF_BYTE_F64 |
| }; |
| } |
| |
| function readF32() { |
| var bytes = readBytes(ieee754.NUMBER_OF_BYTE_F32); |
| var value = ieee754.decodeF32(bytes); |
| |
| if (Math.sign(value) * value === Infinity) { |
| return { |
| value: Math.sign(value), |
| inf: true, |
| nextIndex: ieee754.NUMBER_OF_BYTE_F32 |
| }; |
| } |
| |
| if (isNaN(value)) { |
| var sign = bytes[bytes.length - 1] >> 7 ? -1 : 1; |
| var mantissa = 0; |
| |
| for (var i = 0; i < bytes.length - 2; ++i) { |
| mantissa += bytes[i] * Math.pow(256, i); |
| } |
| |
| mantissa += bytes[bytes.length - 2] % 128 * Math.pow(256, bytes.length - 2); |
| return { |
| value: sign * mantissa, |
| nan: true, |
| nextIndex: ieee754.NUMBER_OF_BYTE_F32 |
| }; |
| } |
| |
| return { |
| value: value, |
| nextIndex: ieee754.NUMBER_OF_BYTE_F32 |
| }; |
| } |
| |
| function readUTF8String() { |
| var lenu32 = readU32(); // Don't eat any bytes. Instead, peek ahead of the current offset using |
| // readBytesAtOffset below. This keeps readUTF8String neutral with respect |
| // to the current offset, just like the other readX functions. |
| |
| var strlen = lenu32.value; |
| dump([strlen], "string length"); |
| var bytes = readBytesAtOffset(offset + lenu32.nextIndex, strlen); |
| var value = utf8.decode(bytes); |
| return { |
| value: value, |
| nextIndex: strlen + lenu32.nextIndex |
| }; |
| } |
| /** |
| * Decode an unsigned 32bits integer |
| * |
| * The length will be handled by the leb librairy, we pass the max number of |
| * byte. |
| */ |
| |
| |
| function readU32() { |
| var bytes = readBytes(MAX_NUMBER_OF_BYTE_U32); |
| var buffer = Buffer.from(bytes); |
| return decodeUInt32(buffer); |
| } |
| |
| function readVaruint32() { |
| // where 32 bits = max 4 bytes |
| var bytes = readBytes(4); |
| var buffer = Buffer.from(bytes); |
| return decodeUInt32(buffer); |
| } |
| |
| function readVaruint7() { |
| // where 7 bits = max 1 bytes |
| var bytes = readBytes(1); |
| var buffer = Buffer.from(bytes); |
| return decodeUInt32(buffer); |
| } |
| /** |
| * Decode a signed 32bits interger |
| */ |
| |
| |
| function read32() { |
| var bytes = readBytes(MAX_NUMBER_OF_BYTE_U32); |
| var buffer = Buffer.from(bytes); |
| return decodeInt32(buffer); |
| } |
| /** |
| * Decode a signed 64bits integer |
| */ |
| |
| |
| function read64() { |
| var bytes = readBytes(MAX_NUMBER_OF_BYTE_U64); |
| var buffer = Buffer.from(bytes); |
| return decodeInt64(buffer); |
| } |
| |
| function readU64() { |
| var bytes = readBytes(MAX_NUMBER_OF_BYTE_U64); |
| var buffer = Buffer.from(bytes); |
| return decodeUInt64(buffer); |
| } |
| |
| function readByte() { |
| return readBytes(1)[0]; |
| } |
| |
| function parseModuleHeader() { |
| if (isEOF() === true || offset + 4 > buf.length) { |
| throw new Error("unexpected end"); |
| } |
| |
| var header = readBytes(4); |
| |
| if (byteArrayEq(constants.magicModuleHeader, header) === false) { |
| throw new CompileError("magic header not detected"); |
| } |
| |
| dump(header, "wasm magic header"); |
| eatBytes(4); |
| } |
| |
| function parseVersion() { |
| if (isEOF() === true || offset + 4 > buf.length) { |
| throw new Error("unexpected end"); |
| } |
| |
| var version = readBytes(4); |
| |
| if (byteArrayEq(constants.moduleVersion, version) === false) { |
| throw new CompileError("unknown binary version"); |
| } |
| |
| dump(version, "wasm version"); |
| eatBytes(4); |
| } |
| |
| function parseVec(cast) { |
| var u32 = readU32(); |
| var length = u32.value; |
| eatBytes(u32.nextIndex); |
| dump([length], "number"); |
| |
| if (length === 0) { |
| return []; |
| } |
| |
| var elements = []; |
| |
| for (var i = 0; i < length; i++) { |
| var byte = readByte(); |
| eatBytes(1); |
| var value = cast(byte); |
| dump([byte], value); |
| |
| if (typeof value === "undefined") { |
| throw new CompileError("Internal failure: parseVec could not cast the value"); |
| } |
| |
| elements.push(value); |
| } |
| |
| return elements; |
| } // Type section |
| // https://webassembly.github.io/spec/binary/modules.html#binary-typesec |
| |
| |
| function parseTypeSection(numberOfTypes) { |
| var typeInstructionNodes = []; |
| dump([numberOfTypes], "num types"); |
| |
| for (var i = 0; i < numberOfTypes; i++) { |
| var _startLoc = getPosition(); |
| |
| dumpSep("type " + i); |
| var type = readByte(); |
| eatBytes(1); |
| |
| if (type == constants.types.func) { |
| dump([type], "func"); |
| var paramValtypes = parseVec(function (b) { |
| return constants.valtypes[b]; |
| }); |
| var params = paramValtypes.map(function (v) { |
| return t.funcParam( |
| /*valtype*/ |
| v); |
| }); |
| var result = parseVec(function (b) { |
| return constants.valtypes[b]; |
| }); |
| typeInstructionNodes.push(function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.typeInstruction(undefined, t.signature(params, result)), endLoc, _startLoc); |
| }()); |
| state.typesInModule.push({ |
| params: params, |
| result: result |
| }); |
| } else { |
| throw new Error("Unsupported type: " + toHex(type)); |
| } |
| } |
| |
| return typeInstructionNodes; |
| } // Import section |
| // https://webassembly.github.io/spec/binary/modules.html#binary-importsec |
| |
| |
| function parseImportSection(numberOfImports) { |
| var imports = []; |
| |
| for (var i = 0; i < numberOfImports; i++) { |
| dumpSep("import header " + i); |
| |
| var _startLoc2 = getPosition(); |
| /** |
| * Module name |
| */ |
| |
| |
| var moduleName = readUTF8String(); |
| eatBytes(moduleName.nextIndex); |
| dump([], "module name (".concat(moduleName.value, ")")); |
| /** |
| * Name |
| */ |
| |
| var name = readUTF8String(); |
| eatBytes(name.nextIndex); |
| dump([], "name (".concat(name.value, ")")); |
| /** |
| * Import descr |
| */ |
| |
| var descrTypeByte = readByte(); |
| eatBytes(1); |
| var descrType = constants.importTypes[descrTypeByte]; |
| dump([descrTypeByte], "import kind"); |
| |
| if (typeof descrType === "undefined") { |
| throw new CompileError("Unknown import description type: " + toHex(descrTypeByte)); |
| } |
| |
| var importDescr = void 0; |
| |
| if (descrType === "func") { |
| var indexU32 = readU32(); |
| var typeindex = indexU32.value; |
| eatBytes(indexU32.nextIndex); |
| dump([typeindex], "type index"); |
| var signature = state.typesInModule[typeindex]; |
| |
| if (typeof signature === "undefined") { |
| throw new CompileError("function signature not found (".concat(typeindex, ")")); |
| } |
| |
| var id = getUniqueName("func"); |
| importDescr = t.funcImportDescr(id, t.signature(signature.params, signature.result)); |
| state.functionsInModule.push({ |
| id: t.identifier(name.value), |
| signature: signature, |
| isExternal: true |
| }); |
| } else if (descrType === "global") { |
| importDescr = parseGlobalType(); |
| var globalNode = t.global(importDescr, []); |
| state.globalsInModule.push(globalNode); |
| } else if (descrType === "table") { |
| importDescr = parseTableType(i); |
| } else if (descrType === "mem") { |
| var memoryNode = parseMemoryType(0); |
| state.memoriesInModule.push(memoryNode); |
| importDescr = memoryNode; |
| } else { |
| throw new CompileError("Unsupported import of type: " + descrType); |
| } |
| |
| imports.push(function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.moduleImport(moduleName.value, name.value, importDescr), endLoc, _startLoc2); |
| }()); |
| } |
| |
| return imports; |
| } // Function section |
| // https://webassembly.github.io/spec/binary/modules.html#function-section |
| |
| |
| function parseFuncSection(numberOfFunctions) { |
| dump([numberOfFunctions], "num funcs"); |
| |
| for (var i = 0; i < numberOfFunctions; i++) { |
| var indexU32 = readU32(); |
| var typeindex = indexU32.value; |
| eatBytes(indexU32.nextIndex); |
| dump([typeindex], "type index"); |
| var signature = state.typesInModule[typeindex]; |
| |
| if (typeof signature === "undefined") { |
| throw new CompileError("function signature not found (".concat(typeindex, ")")); |
| } // preserve anonymous, a name might be resolved later |
| |
| |
| var id = t.withRaw(t.identifier(getUniqueName("func")), ""); |
| state.functionsInModule.push({ |
| id: id, |
| signature: signature, |
| isExternal: false |
| }); |
| } |
| } // Export section |
| // https://webassembly.github.io/spec/binary/modules.html#export-section |
| |
| |
| function parseExportSection(numberOfExport) { |
| dump([numberOfExport], "num exports"); // Parse vector of exports |
| |
| for (var i = 0; i < numberOfExport; i++) { |
| var _startLoc3 = getPosition(); |
| /** |
| * Name |
| */ |
| |
| |
| var name = readUTF8String(); |
| eatBytes(name.nextIndex); |
| dump([], "export name (".concat(name.value, ")")); |
| /** |
| * exportdescr |
| */ |
| |
| var typeIndex = readByte(); |
| eatBytes(1); |
| dump([typeIndex], "export kind"); |
| var indexu32 = readU32(); |
| var index = indexu32.value; |
| eatBytes(indexu32.nextIndex); |
| dump([index], "export index"); |
| var id = void 0, |
| signature = void 0; |
| |
| if (constants.exportTypes[typeIndex] === "Func") { |
| var func = state.functionsInModule[index]; |
| |
| if (typeof func === "undefined") { |
| throw new CompileError("unknown function (".concat(index, ")")); |
| } |
| |
| id = t.numberLiteralFromRaw(index, String(index)); |
| signature = func.signature; |
| } else if (constants.exportTypes[typeIndex] === "Table") { |
| var table = state.tablesInModule[index]; |
| |
| if (typeof table === "undefined") { |
| throw new CompileError("unknown table ".concat(index)); |
| } |
| |
| id = t.numberLiteralFromRaw(index, String(index)); |
| signature = null; |
| } else if (constants.exportTypes[typeIndex] === "Mem") { |
| var memNode = state.memoriesInModule[index]; |
| |
| if (typeof memNode === "undefined") { |
| throw new CompileError("unknown memory ".concat(index)); |
| } |
| |
| id = t.numberLiteralFromRaw(index, String(index)); |
| signature = null; |
| } else if (constants.exportTypes[typeIndex] === "Global") { |
| var global = state.globalsInModule[index]; |
| |
| if (typeof global === "undefined") { |
| throw new CompileError("unknown global ".concat(index)); |
| } |
| |
| id = t.numberLiteralFromRaw(index, String(index)); |
| signature = null; |
| } else { |
| console.warn("Unsupported export type: " + toHex(typeIndex)); |
| return; |
| } |
| |
| var endLoc = getPosition(); |
| state.elementsInExportSection.push({ |
| name: name.value, |
| type: constants.exportTypes[typeIndex], |
| signature: signature, |
| id: id, |
| index: index, |
| endLoc: endLoc, |
| startLoc: _startLoc3 |
| }); |
| } |
| } // Code section |
| // https://webassembly.github.io/spec/binary/modules.html#code-section |
| |
| |
| function parseCodeSection(numberOfFuncs) { |
| dump([numberOfFuncs], "number functions"); // Parse vector of function |
| |
| for (var i = 0; i < numberOfFuncs; i++) { |
| var _startLoc4 = getPosition(); |
| |
| dumpSep("function body " + i); // the u32 size of the function code in bytes |
| // Ignore it for now |
| |
| var bodySizeU32 = readU32(); |
| eatBytes(bodySizeU32.nextIndex); |
| dump([bodySizeU32.value], "function body size"); |
| var code = []; |
| /** |
| * Parse locals |
| */ |
| |
| var funcLocalNumU32 = readU32(); |
| var funcLocalNum = funcLocalNumU32.value; |
| eatBytes(funcLocalNumU32.nextIndex); |
| dump([funcLocalNum], "num locals"); |
| var locals = []; |
| |
| for (var _i = 0; _i < funcLocalNum; _i++) { |
| var _startLoc5 = getPosition(); |
| |
| var localCountU32 = readU32(); |
| var localCount = localCountU32.value; |
| eatBytes(localCountU32.nextIndex); |
| dump([localCount], "num local"); |
| var valtypeByte = readByte(); |
| eatBytes(1); |
| var type = constants.valtypes[valtypeByte]; |
| var args = []; |
| |
| for (var _i2 = 0; _i2 < localCount; _i2++) { |
| args.push(t.valtypeLiteral(type)); |
| } |
| |
| var localNode = function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.instruction("local", args), endLoc, _startLoc5); |
| }(); |
| |
| locals.push(localNode); |
| dump([valtypeByte], type); |
| |
| if (typeof type === "undefined") { |
| throw new CompileError("Unexpected valtype: " + toHex(valtypeByte)); |
| } |
| } |
| |
| code.push.apply(code, locals); // Decode instructions until the end |
| |
| parseInstructionBlock(code); |
| var endLoc = getPosition(); |
| state.elementsInCodeSection.push({ |
| code: code, |
| locals: locals, |
| endLoc: endLoc, |
| startLoc: _startLoc4, |
| bodySize: bodySizeU32.value |
| }); |
| } |
| } |
| |
| function parseInstructionBlock(code) { |
| while (true) { |
| var _startLoc6 = getPosition(); |
| |
| var instructionAlreadyCreated = false; |
| var instructionByte = readByte(); |
| eatBytes(1); |
| |
| if (instructionByte === 0xfe) { |
| throw new CompileError("Atomic instructions are not implemented"); |
| } |
| |
| var instruction = constants.symbolsByByte[instructionByte]; |
| |
| if (typeof instruction === "undefined") { |
| throw new CompileError("Unexpected instruction: " + toHex(instructionByte)); |
| } |
| |
| if (typeof instruction.object === "string") { |
| dump([instructionByte], "".concat(instruction.object, ".").concat(instruction.name)); |
| } else { |
| dump([instructionByte], instruction.name); |
| } |
| /** |
| * End of the function |
| */ |
| |
| |
| if (instruction.name === "end") { |
| var node = function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.instruction(instruction.name), endLoc, _startLoc6); |
| }(); |
| |
| code.push(node); |
| break; |
| } |
| |
| var args = []; |
| |
| if (instruction.name === "loop") { |
| var _startLoc7 = getPosition(); |
| |
| var blocktypeByte = readByte(); |
| eatBytes(1); |
| var blocktype = constants.blockTypes[blocktypeByte]; |
| dump([blocktypeByte], "blocktype"); |
| |
| if (typeof blocktype === "undefined") { |
| throw new CompileError("Unexpected blocktype: " + toHex(blocktypeByte)); |
| } |
| |
| var instr = []; |
| parseInstructionBlock(instr); // preserve anonymous |
| |
| var label = t.withRaw(t.identifier(getUniqueName("loop")), ""); |
| |
| var loopNode = function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.loopInstruction(label, blocktype, instr), endLoc, _startLoc7); |
| }(); |
| |
| code.push(loopNode); |
| instructionAlreadyCreated = true; |
| } else if (instruction.name === "if") { |
| var _startLoc8 = getPosition(); |
| |
| var _blocktypeByte = readByte(); |
| |
| eatBytes(1); |
| var _blocktype = constants.blockTypes[_blocktypeByte]; |
| dump([_blocktypeByte], "blocktype"); |
| |
| if (typeof _blocktype === "undefined") { |
| throw new CompileError("Unexpected blocktype: " + toHex(_blocktypeByte)); |
| } |
| |
| var testIndex = t.withRaw(t.identifier(getUniqueName("if")), ""); |
| var ifBody = []; |
| parseInstructionBlock(ifBody); // Defaults to no alternate |
| |
| var elseIndex = 0; |
| |
| for (elseIndex = 0; elseIndex < ifBody.length; ++elseIndex) { |
| var _instr = ifBody[elseIndex]; |
| |
| if (_instr.type === "Instr" && _instr.id === "else") { |
| break; |
| } |
| } |
| |
| var consequentInstr = ifBody.slice(0, elseIndex); |
| var alternate = ifBody.slice(elseIndex + 1); // wast sugar |
| |
| var testInstrs = []; |
| |
| var ifNode = function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.ifInstruction(testIndex, testInstrs, _blocktype, consequentInstr, alternate), endLoc, _startLoc8); |
| }(); |
| |
| code.push(ifNode); |
| instructionAlreadyCreated = true; |
| } else if (instruction.name === "block") { |
| var _startLoc9 = getPosition(); |
| |
| var _blocktypeByte2 = readByte(); |
| |
| eatBytes(1); |
| var _blocktype2 = constants.blockTypes[_blocktypeByte2]; |
| dump([_blocktypeByte2], "blocktype"); |
| |
| if (typeof _blocktype2 === "undefined") { |
| throw new CompileError("Unexpected blocktype: " + toHex(_blocktypeByte2)); |
| } |
| |
| var _instr2 = []; |
| parseInstructionBlock(_instr2); // preserve anonymous |
| |
| var _label = t.withRaw(t.identifier(getUniqueName("block")), ""); |
| |
| var blockNode = function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.blockInstruction(_label, _instr2, _blocktype2), endLoc, _startLoc9); |
| }(); |
| |
| code.push(blockNode); |
| instructionAlreadyCreated = true; |
| } else if (instruction.name === "call") { |
| var indexu32 = readU32(); |
| var index = indexu32.value; |
| eatBytes(indexu32.nextIndex); |
| dump([index], "index"); |
| |
| var callNode = function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.callInstruction(t.indexLiteral(index)), endLoc, _startLoc6); |
| }(); |
| |
| code.push(callNode); |
| instructionAlreadyCreated = true; |
| } else if (instruction.name === "call_indirect") { |
| var _startLoc10 = getPosition(); |
| |
| var indexU32 = readU32(); |
| var typeindex = indexU32.value; |
| eatBytes(indexU32.nextIndex); |
| dump([typeindex], "type index"); |
| var signature = state.typesInModule[typeindex]; |
| |
| if (typeof signature === "undefined") { |
| throw new CompileError("call_indirect signature not found (".concat(typeindex, ")")); |
| } |
| |
| var _callNode = t.callIndirectInstruction(t.signature(signature.params, signature.result), []); |
| |
| var flagU32 = readU32(); |
| var flag = flagU32.value; // 0x00 - reserved byte |
| |
| eatBytes(flagU32.nextIndex); |
| |
| if (flag !== 0) { |
| throw new CompileError("zero flag expected"); |
| } |
| |
| code.push(function () { |
| var endLoc = getPosition(); |
| return t.withLoc(_callNode, endLoc, _startLoc10); |
| }()); |
| instructionAlreadyCreated = true; |
| } else if (instruction.name === "br_table") { |
| var indicesu32 = readU32(); |
| var indices = indicesu32.value; |
| eatBytes(indicesu32.nextIndex); |
| dump([indices], "num indices"); |
| |
| for (var i = 0; i <= indices; i++) { |
| var _indexu = readU32(); |
| |
| var _index = _indexu.value; |
| eatBytes(_indexu.nextIndex); |
| dump([_index], "index"); |
| args.push(t.numberLiteralFromRaw(_indexu.value.toString(), "u32")); |
| } |
| } else if (instructionByte >= 0x28 && instructionByte <= 0x40) { |
| /** |
| * Memory instructions |
| */ |
| if (instruction.name === "grow_memory" || instruction.name === "current_memory") { |
| var _indexU = readU32(); |
| |
| var _index2 = _indexU.value; |
| eatBytes(_indexU.nextIndex); |
| |
| if (_index2 !== 0) { |
| throw new Error("zero flag expected"); |
| } |
| |
| dump([_index2], "index"); |
| } else { |
| var aligun32 = readU32(); |
| var align = aligun32.value; |
| eatBytes(aligun32.nextIndex); |
| dump([align], "align"); |
| var offsetu32 = readU32(); |
| var _offset2 = offsetu32.value; |
| eatBytes(offsetu32.nextIndex); |
| dump([_offset2], "offset"); |
| } |
| } else if (instructionByte >= 0x41 && instructionByte <= 0x44) { |
| /** |
| * Numeric instructions |
| */ |
| if (instruction.object === "i32") { |
| var value32 = read32(); |
| var value = value32.value; |
| eatBytes(value32.nextIndex); |
| dump([value], "i32 value"); |
| args.push(t.numberLiteralFromRaw(value)); |
| } |
| |
| if (instruction.object === "u32") { |
| var valueu32 = readU32(); |
| var _value = valueu32.value; |
| eatBytes(valueu32.nextIndex); |
| dump([_value], "u32 value"); |
| args.push(t.numberLiteralFromRaw(_value)); |
| } |
| |
| if (instruction.object === "i64") { |
| var value64 = read64(); |
| var _value2 = value64.value; |
| eatBytes(value64.nextIndex); |
| dump([Number(_value2.toString())], "i64 value"); |
| var high = _value2.high, |
| low = _value2.low; |
| var _node = { |
| type: "LongNumberLiteral", |
| value: { |
| high: high, |
| low: low |
| } |
| }; |
| args.push(_node); |
| } |
| |
| if (instruction.object === "u64") { |
| var valueu64 = readU64(); |
| var _value3 = valueu64.value; |
| eatBytes(valueu64.nextIndex); |
| dump([Number(_value3.toString())], "u64 value"); |
| var _high = _value3.high, |
| _low = _value3.low; |
| var _node2 = { |
| type: "LongNumberLiteral", |
| value: { |
| high: _high, |
| low: _low |
| } |
| }; |
| args.push(_node2); |
| } |
| |
| if (instruction.object === "f32") { |
| var valuef32 = readF32(); |
| var _value4 = valuef32.value; |
| eatBytes(valuef32.nextIndex); |
| dump([_value4], "f32 value"); |
| args.push( // $FlowIgnore |
| t.floatLiteral(_value4, valuef32.nan, valuef32.inf, String(_value4))); |
| } |
| |
| if (instruction.object === "f64") { |
| var valuef64 = readF64(); |
| var _value5 = valuef64.value; |
| eatBytes(valuef64.nextIndex); |
| dump([_value5], "f64 value"); |
| args.push( // $FlowIgnore |
| t.floatLiteral(_value5, valuef64.nan, valuef64.inf, String(_value5))); |
| } |
| } else { |
| for (var _i3 = 0; _i3 < instruction.numberOfArgs; _i3++) { |
| var u32 = readU32(); |
| eatBytes(u32.nextIndex); |
| dump([u32.value], "argument " + _i3); |
| args.push(t.numberLiteralFromRaw(u32.value)); |
| } |
| } |
| |
| if (instructionAlreadyCreated === false) { |
| if (typeof instruction.object === "string") { |
| var _node3 = function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.objectInstruction(instruction.name, instruction.object, args), endLoc, _startLoc6); |
| }(); |
| |
| code.push(_node3); |
| } else { |
| var _node4 = function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.instruction(instruction.name, args), endLoc, _startLoc6); |
| }(); |
| |
| code.push(_node4); |
| } |
| } |
| } |
| } // https://webassembly.github.io/spec/core/binary/types.html#limits |
| |
| |
| function parseLimits() { |
| var limitType = readByte(); |
| eatBytes(1); |
| dump([limitType], "limit type"); |
| var min, max; |
| |
| if (limitType === 0x01 || limitType === 0x03 // shared limits |
| ) { |
| var u32min = readU32(); |
| min = parseInt(u32min.value); |
| eatBytes(u32min.nextIndex); |
| dump([min], "min"); |
| var u32max = readU32(); |
| max = parseInt(u32max.value); |
| eatBytes(u32max.nextIndex); |
| dump([max], "max"); |
| } |
| |
| if (limitType === 0x00) { |
| var _u32min = readU32(); |
| |
| min = parseInt(_u32min.value); |
| eatBytes(_u32min.nextIndex); |
| dump([min], "min"); |
| } |
| |
| return t.limit(min, max); |
| } // https://webassembly.github.io/spec/core/binary/types.html#binary-tabletype |
| |
| |
| function parseTableType(index) { |
| var name = t.withRaw(t.identifier(getUniqueName("table")), String(index)); |
| var elementTypeByte = readByte(); |
| eatBytes(1); |
| dump([elementTypeByte], "element type"); |
| var elementType = constants.tableTypes[elementTypeByte]; |
| |
| if (typeof elementType === "undefined") { |
| throw new CompileError("Unknown element type in table: " + toHex(elementType)); |
| } |
| |
| var limits = parseLimits(); |
| return t.table(elementType, limits, name); |
| } // https://webassembly.github.io/spec/binary/types.html#global-types |
| |
| |
| function parseGlobalType() { |
| var valtypeByte = readByte(); |
| eatBytes(1); |
| var type = constants.valtypes[valtypeByte]; |
| dump([valtypeByte], type); |
| |
| if (typeof type === "undefined") { |
| throw new CompileError("Unknown valtype: " + toHex(valtypeByte)); |
| } |
| |
| var globalTypeByte = readByte(); |
| eatBytes(1); |
| var globalType = constants.globalTypes[globalTypeByte]; |
| dump([globalTypeByte], "global type (".concat(globalType, ")")); |
| |
| if (typeof globalType === "undefined") { |
| throw new CompileError("Invalid mutability: " + toHex(globalTypeByte)); |
| } |
| |
| return t.globalType(type, globalType); |
| } // function parseNameModule() { |
| // const lenu32 = readVaruint32(); |
| // eatBytes(lenu32.nextIndex); |
| // console.log("len", lenu32); |
| // const strlen = lenu32.value; |
| // dump([strlen], "string length"); |
| // const bytes = readBytes(strlen); |
| // eatBytes(strlen); |
| // const value = utf8.decode(bytes); |
| // return [t.moduleNameMetadata(value)]; |
| // } |
| // this section contains an array of function names and indices |
| |
| |
| function parseNameSectionFunctions() { |
| var functionNames = []; |
| var numberOfFunctionsu32 = readU32(); |
| var numbeOfFunctions = numberOfFunctionsu32.value; |
| eatBytes(numberOfFunctionsu32.nextIndex); |
| |
| for (var i = 0; i < numbeOfFunctions; i++) { |
| var indexu32 = readU32(); |
| var index = indexu32.value; |
| eatBytes(indexu32.nextIndex); |
| var name = readUTF8String(); |
| eatBytes(name.nextIndex); |
| functionNames.push(t.functionNameMetadata(name.value, index)); |
| } |
| |
| return functionNames; |
| } |
| |
| function parseNameSectionLocals() { |
| var localNames = []; |
| var numbeOfFunctionsu32 = readU32(); |
| var numbeOfFunctions = numbeOfFunctionsu32.value; |
| eatBytes(numbeOfFunctionsu32.nextIndex); |
| |
| for (var i = 0; i < numbeOfFunctions; i++) { |
| var functionIndexu32 = readU32(); |
| var functionIndex = functionIndexu32.value; |
| eatBytes(functionIndexu32.nextIndex); |
| var numLocalsu32 = readU32(); |
| var numLocals = numLocalsu32.value; |
| eatBytes(numLocalsu32.nextIndex); |
| |
| for (var _i4 = 0; _i4 < numLocals; _i4++) { |
| var localIndexu32 = readU32(); |
| var localIndex = localIndexu32.value; |
| eatBytes(localIndexu32.nextIndex); |
| var name = readUTF8String(); |
| eatBytes(name.nextIndex); |
| localNames.push(t.localNameMetadata(name.value, localIndex, functionIndex)); |
| } |
| } |
| |
| return localNames; |
| } // this is a custom section used for name resolution |
| // https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#name-section |
| |
| |
| function parseNameSection(remainingBytes) { |
| var nameMetadata = []; |
| var initialOffset = offset; |
| |
| while (offset - initialOffset < remainingBytes) { |
| // name_type |
| var sectionTypeByte = readVaruint7(); |
| eatBytes(sectionTypeByte.nextIndex); // name_payload_len |
| |
| var subSectionSizeInBytesu32 = readVaruint32(); |
| eatBytes(subSectionSizeInBytesu32.nextIndex); |
| |
| switch (sectionTypeByte.value) { |
| // case 0: { |
| // TODO(sven): re-enable that |
| // Current status: it seems that when we decode the module's name |
| // no name_payload_len is used. |
| // |
| // See https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#name-section |
| // |
| // nameMetadata.push(...parseNameModule()); |
| // break; |
| // } |
| case 1: |
| { |
| nameMetadata.push.apply(nameMetadata, _toConsumableArray(parseNameSectionFunctions())); |
| break; |
| } |
| |
| case 2: |
| { |
| nameMetadata.push.apply(nameMetadata, _toConsumableArray(parseNameSectionLocals())); |
| break; |
| } |
| |
| default: |
| { |
| // skip unknown subsection |
| eatBytes(subSectionSizeInBytesu32.value); |
| } |
| } |
| } |
| |
| return nameMetadata; |
| } // this is a custom setion used for information about the producers |
| // https://github.com/WebAssembly/tool-conventions/blob/master/ProducersSection.md |
| |
| |
| function parseProducersSection() { |
| var metadata = t.producersSectionMetadata([]); // field_count |
| |
| var sectionTypeByte = readVaruint32(); |
| eatBytes(sectionTypeByte.nextIndex); |
| dump([sectionTypeByte.value], "num of producers"); |
| var fields = { |
| language: [], |
| "processed-by": [], |
| sdk: [] |
| }; // fields |
| |
| for (var fieldI = 0; fieldI < sectionTypeByte.value; fieldI++) { |
| // field_name |
| var fieldName = readUTF8String(); |
| eatBytes(fieldName.nextIndex); // field_value_count |
| |
| var valueCount = readVaruint32(); |
| eatBytes(valueCount.nextIndex); // field_values |
| |
| for (var producerI = 0; producerI < valueCount.value; producerI++) { |
| var producerName = readUTF8String(); |
| eatBytes(producerName.nextIndex); |
| var producerVersion = readUTF8String(); |
| eatBytes(producerVersion.nextIndex); |
| fields[fieldName.value].push(t.producerMetadataVersionedName(producerName.value, producerVersion.value)); |
| } |
| |
| metadata.producers.push(fields[fieldName.value]); |
| } |
| |
| return metadata; |
| } |
| |
| function parseGlobalSection(numberOfGlobals) { |
| var globals = []; |
| dump([numberOfGlobals], "num globals"); |
| |
| for (var i = 0; i < numberOfGlobals; i++) { |
| var _startLoc11 = getPosition(); |
| |
| var globalType = parseGlobalType(); |
| /** |
| * Global expressions |
| */ |
| |
| var init = []; |
| parseInstructionBlock(init); |
| |
| var node = function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.global(globalType, init), endLoc, _startLoc11); |
| }(); |
| |
| globals.push(node); |
| state.globalsInModule.push(node); |
| } |
| |
| return globals; |
| } |
| |
| function parseElemSection(numberOfElements) { |
| var elems = []; |
| dump([numberOfElements], "num elements"); |
| |
| for (var i = 0; i < numberOfElements; i++) { |
| var _startLoc12 = getPosition(); |
| |
| var tableindexu32 = readU32(); |
| var tableindex = tableindexu32.value; |
| eatBytes(tableindexu32.nextIndex); |
| dump([tableindex], "table index"); |
| /** |
| * Parse instructions |
| */ |
| |
| var instr = []; |
| parseInstructionBlock(instr); |
| /** |
| * Parse ( vector function index ) * |
| */ |
| |
| var indicesu32 = readU32(); |
| var indices = indicesu32.value; |
| eatBytes(indicesu32.nextIndex); |
| dump([indices], "num indices"); |
| var indexValues = []; |
| |
| for (var _i5 = 0; _i5 < indices; _i5++) { |
| var indexu32 = readU32(); |
| var index = indexu32.value; |
| eatBytes(indexu32.nextIndex); |
| dump([index], "index"); |
| indexValues.push(t.indexLiteral(index)); |
| } |
| |
| var elemNode = function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.elem(t.indexLiteral(tableindex), instr, indexValues), endLoc, _startLoc12); |
| }(); |
| |
| elems.push(elemNode); |
| } |
| |
| return elems; |
| } // https://webassembly.github.io/spec/core/binary/types.html#memory-types |
| |
| |
| function parseMemoryType(i) { |
| var limits = parseLimits(); |
| return t.memory(limits, t.indexLiteral(i)); |
| } // https://webassembly.github.io/spec/binary/modules.html#table-section |
| |
| |
| function parseTableSection(numberOfElements) { |
| var tables = []; |
| dump([numberOfElements], "num elements"); |
| |
| for (var i = 0; i < numberOfElements; i++) { |
| var tablesNode = parseTableType(i); |
| state.tablesInModule.push(tablesNode); |
| tables.push(tablesNode); |
| } |
| |
| return tables; |
| } // https://webassembly.github.io/spec/binary/modules.html#memory-section |
| |
| |
| function parseMemorySection(numberOfElements) { |
| var memories = []; |
| dump([numberOfElements], "num elements"); |
| |
| for (var i = 0; i < numberOfElements; i++) { |
| var memoryNode = parseMemoryType(i); |
| state.memoriesInModule.push(memoryNode); |
| memories.push(memoryNode); |
| } |
| |
| return memories; |
| } // https://webassembly.github.io/spec/binary/modules.html#binary-startsec |
| |
| |
| function parseStartSection() { |
| var startLoc = getPosition(); |
| var u32 = readU32(); |
| var startFuncIndex = u32.value; |
| eatBytes(u32.nextIndex); |
| dump([startFuncIndex], "index"); |
| return function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.start(t.indexLiteral(startFuncIndex)), endLoc, startLoc); |
| }(); |
| } // https://webassembly.github.io/spec/binary/modules.html#data-section |
| |
| |
| function parseDataSection(numberOfElements) { |
| var dataEntries = []; |
| dump([numberOfElements], "num elements"); |
| |
| for (var i = 0; i < numberOfElements; i++) { |
| var memoryIndexu32 = readU32(); |
| var memoryIndex = memoryIndexu32.value; |
| eatBytes(memoryIndexu32.nextIndex); |
| dump([memoryIndex], "memory index"); |
| var instrs = []; |
| parseInstructionBlock(instrs); |
| var hasExtraInstrs = instrs.filter(function (i) { |
| return i.id !== "end"; |
| }).length !== 1; |
| |
| if (hasExtraInstrs) { |
| throw new CompileError("data section offset must be a single instruction"); |
| } |
| |
| var bytes = parseVec(function (b) { |
| return b; |
| }); |
| dump([], "init"); |
| dataEntries.push(t.data(t.memIndexLiteral(memoryIndex), instrs[0], t.byteArray(bytes))); |
| } |
| |
| return dataEntries; |
| } // https://webassembly.github.io/spec/binary/modules.html#binary-section |
| |
| |
| function parseSection(sectionIndex) { |
| var sectionId = readByte(); |
| eatBytes(1); |
| |
| if (sectionId >= sectionIndex || sectionIndex === constants.sections.custom) { |
| sectionIndex = sectionId + 1; |
| } else { |
| if (sectionId !== constants.sections.custom) throw new CompileError("Unexpected section: " + toHex(sectionId)); |
| } |
| |
| var nextSectionIndex = sectionIndex; |
| var startOffset = offset; |
| var startLoc = getPosition(); |
| var u32 = readU32(); |
| var sectionSizeInBytes = u32.value; |
| eatBytes(u32.nextIndex); |
| |
| var sectionSizeInBytesNode = function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.numberLiteralFromRaw(sectionSizeInBytes), endLoc, startLoc); |
| }(); |
| |
| switch (sectionId) { |
| case constants.sections.type: |
| { |
| dumpSep("section Type"); |
| dump([sectionId], "section code"); |
| dump([sectionSizeInBytes], "section size"); |
| |
| var _startLoc13 = getPosition(); |
| |
| var _u = readU32(); |
| |
| var numberOfTypes = _u.value; |
| eatBytes(_u.nextIndex); |
| |
| var _metadata = t.sectionMetadata("type", startOffset, sectionSizeInBytesNode, function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.numberLiteralFromRaw(numberOfTypes), endLoc, _startLoc13); |
| }()); |
| |
| var _nodes = parseTypeSection(numberOfTypes); |
| |
| return { |
| nodes: _nodes, |
| metadata: _metadata, |
| nextSectionIndex: nextSectionIndex |
| }; |
| } |
| |
| case constants.sections.table: |
| { |
| dumpSep("section Table"); |
| dump([sectionId], "section code"); |
| dump([sectionSizeInBytes], "section size"); |
| |
| var _startLoc14 = getPosition(); |
| |
| var _u2 = readU32(); |
| |
| var numberOfTable = _u2.value; |
| eatBytes(_u2.nextIndex); |
| dump([numberOfTable], "num tables"); |
| |
| var _metadata2 = t.sectionMetadata("table", startOffset, sectionSizeInBytesNode, function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.numberLiteralFromRaw(numberOfTable), endLoc, _startLoc14); |
| }()); |
| |
| var _nodes2 = parseTableSection(numberOfTable); |
| |
| return { |
| nodes: _nodes2, |
| metadata: _metadata2, |
| nextSectionIndex: nextSectionIndex |
| }; |
| } |
| |
| case constants.sections.import: |
| { |
| dumpSep("section Import"); |
| dump([sectionId], "section code"); |
| dump([sectionSizeInBytes], "section size"); |
| |
| var _startLoc15 = getPosition(); |
| |
| var numberOfImportsu32 = readU32(); |
| var numberOfImports = numberOfImportsu32.value; |
| eatBytes(numberOfImportsu32.nextIndex); |
| dump([numberOfImports], "number of imports"); |
| |
| var _metadata3 = t.sectionMetadata("import", startOffset, sectionSizeInBytesNode, function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.numberLiteralFromRaw(numberOfImports), endLoc, _startLoc15); |
| }()); |
| |
| var _nodes3 = parseImportSection(numberOfImports); |
| |
| return { |
| nodes: _nodes3, |
| metadata: _metadata3, |
| nextSectionIndex: nextSectionIndex |
| }; |
| } |
| |
| case constants.sections.func: |
| { |
| dumpSep("section Function"); |
| dump([sectionId], "section code"); |
| dump([sectionSizeInBytes], "section size"); |
| |
| var _startLoc16 = getPosition(); |
| |
| var numberOfFunctionsu32 = readU32(); |
| var numberOfFunctions = numberOfFunctionsu32.value; |
| eatBytes(numberOfFunctionsu32.nextIndex); |
| |
| var _metadata4 = t.sectionMetadata("func", startOffset, sectionSizeInBytesNode, function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.numberLiteralFromRaw(numberOfFunctions), endLoc, _startLoc16); |
| }()); |
| |
| parseFuncSection(numberOfFunctions); |
| var _nodes4 = []; |
| return { |
| nodes: _nodes4, |
| metadata: _metadata4, |
| nextSectionIndex: nextSectionIndex |
| }; |
| } |
| |
| case constants.sections.export: |
| { |
| dumpSep("section Export"); |
| dump([sectionId], "section code"); |
| dump([sectionSizeInBytes], "section size"); |
| |
| var _startLoc17 = getPosition(); |
| |
| var _u3 = readU32(); |
| |
| var numberOfExport = _u3.value; |
| eatBytes(_u3.nextIndex); |
| |
| var _metadata5 = t.sectionMetadata("export", startOffset, sectionSizeInBytesNode, function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.numberLiteralFromRaw(numberOfExport), endLoc, _startLoc17); |
| }()); |
| |
| parseExportSection(numberOfExport); |
| var _nodes5 = []; |
| return { |
| nodes: _nodes5, |
| metadata: _metadata5, |
| nextSectionIndex: nextSectionIndex |
| }; |
| } |
| |
| case constants.sections.code: |
| { |
| dumpSep("section Code"); |
| dump([sectionId], "section code"); |
| dump([sectionSizeInBytes], "section size"); |
| |
| var _startLoc18 = getPosition(); |
| |
| var _u4 = readU32(); |
| |
| var numberOfFuncs = _u4.value; |
| eatBytes(_u4.nextIndex); |
| |
| var _metadata6 = t.sectionMetadata("code", startOffset, sectionSizeInBytesNode, function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.numberLiteralFromRaw(numberOfFuncs), endLoc, _startLoc18); |
| }()); |
| |
| if (opts.ignoreCodeSection === true) { |
| var remainingBytes = sectionSizeInBytes - _u4.nextIndex; |
| eatBytes(remainingBytes); // eat the entire section |
| } else { |
| parseCodeSection(numberOfFuncs); |
| } |
| |
| var _nodes6 = []; |
| return { |
| nodes: _nodes6, |
| metadata: _metadata6, |
| nextSectionIndex: nextSectionIndex |
| }; |
| } |
| |
| case constants.sections.start: |
| { |
| dumpSep("section Start"); |
| dump([sectionId], "section code"); |
| dump([sectionSizeInBytes], "section size"); |
| |
| var _metadata7 = t.sectionMetadata("start", startOffset, sectionSizeInBytesNode); |
| |
| var _nodes7 = [parseStartSection()]; |
| return { |
| nodes: _nodes7, |
| metadata: _metadata7, |
| nextSectionIndex: nextSectionIndex |
| }; |
| } |
| |
| case constants.sections.element: |
| { |
| dumpSep("section Element"); |
| dump([sectionId], "section code"); |
| dump([sectionSizeInBytes], "section size"); |
| |
| var _startLoc19 = getPosition(); |
| |
| var numberOfElementsu32 = readU32(); |
| var numberOfElements = numberOfElementsu32.value; |
| eatBytes(numberOfElementsu32.nextIndex); |
| |
| var _metadata8 = t.sectionMetadata("element", startOffset, sectionSizeInBytesNode, function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.numberLiteralFromRaw(numberOfElements), endLoc, _startLoc19); |
| }()); |
| |
| var _nodes8 = parseElemSection(numberOfElements); |
| |
| return { |
| nodes: _nodes8, |
| metadata: _metadata8, |
| nextSectionIndex: nextSectionIndex |
| }; |
| } |
| |
| case constants.sections.global: |
| { |
| dumpSep("section Global"); |
| dump([sectionId], "section code"); |
| dump([sectionSizeInBytes], "section size"); |
| |
| var _startLoc20 = getPosition(); |
| |
| var numberOfGlobalsu32 = readU32(); |
| var numberOfGlobals = numberOfGlobalsu32.value; |
| eatBytes(numberOfGlobalsu32.nextIndex); |
| |
| var _metadata9 = t.sectionMetadata("global", startOffset, sectionSizeInBytesNode, function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.numberLiteralFromRaw(numberOfGlobals), endLoc, _startLoc20); |
| }()); |
| |
| var _nodes9 = parseGlobalSection(numberOfGlobals); |
| |
| return { |
| nodes: _nodes9, |
| metadata: _metadata9, |
| nextSectionIndex: nextSectionIndex |
| }; |
| } |
| |
| case constants.sections.memory: |
| { |
| dumpSep("section Memory"); |
| dump([sectionId], "section code"); |
| dump([sectionSizeInBytes], "section size"); |
| |
| var _startLoc21 = getPosition(); |
| |
| var _numberOfElementsu = readU32(); |
| |
| var _numberOfElements = _numberOfElementsu.value; |
| eatBytes(_numberOfElementsu.nextIndex); |
| |
| var _metadata10 = t.sectionMetadata("memory", startOffset, sectionSizeInBytesNode, function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.numberLiteralFromRaw(_numberOfElements), endLoc, _startLoc21); |
| }()); |
| |
| var _nodes10 = parseMemorySection(_numberOfElements); |
| |
| return { |
| nodes: _nodes10, |
| metadata: _metadata10, |
| nextSectionIndex: nextSectionIndex |
| }; |
| } |
| |
| case constants.sections.data: |
| { |
| dumpSep("section Data"); |
| dump([sectionId], "section code"); |
| dump([sectionSizeInBytes], "section size"); |
| |
| var _metadata11 = t.sectionMetadata("data", startOffset, sectionSizeInBytesNode); |
| |
| var _startLoc22 = getPosition(); |
| |
| var _numberOfElementsu2 = readU32(); |
| |
| var _numberOfElements2 = _numberOfElementsu2.value; |
| eatBytes(_numberOfElementsu2.nextIndex); |
| |
| _metadata11.vectorOfSize = function () { |
| var endLoc = getPosition(); |
| return t.withLoc(t.numberLiteralFromRaw(_numberOfElements2), endLoc, _startLoc22); |
| }(); |
| |
| if (opts.ignoreDataSection === true) { |
| var _remainingBytes = sectionSizeInBytes - _numberOfElementsu2.nextIndex; |
| |
| eatBytes(_remainingBytes); // eat the entire section |
| |
| dumpSep("ignore data (" + sectionSizeInBytes + " bytes)"); |
| return { |
| nodes: [], |
| metadata: _metadata11, |
| nextSectionIndex: nextSectionIndex |
| }; |
| } else { |
| var _nodes11 = parseDataSection(_numberOfElements2); |
| |
| return { |
| nodes: _nodes11, |
| metadata: _metadata11, |
| nextSectionIndex: nextSectionIndex |
| }; |
| } |
| } |
| |
| case constants.sections.custom: |
| { |
| dumpSep("section Custom"); |
| dump([sectionId], "section code"); |
| dump([sectionSizeInBytes], "section size"); |
| var _metadata12 = [t.sectionMetadata("custom", startOffset, sectionSizeInBytesNode)]; |
| var sectionName = readUTF8String(); |
| eatBytes(sectionName.nextIndex); |
| dump([], "section name (".concat(sectionName.value, ")")); |
| |
| var _remainingBytes2 = sectionSizeInBytes - sectionName.nextIndex; |
| |
| if (sectionName.value === "name") { |
| var initialOffset = offset; |
| |
| try { |
| _metadata12.push.apply(_metadata12, _toConsumableArray(parseNameSection(_remainingBytes2))); |
| } catch (e) { |
| console.warn("Failed to decode custom \"name\" section @".concat(offset, "; ignoring (").concat(e.message, ").")); |
| eatBytes(offset - (initialOffset + _remainingBytes2)); |
| } |
| } else if (sectionName.value === "producers") { |
| var _initialOffset = offset; |
| |
| try { |
| _metadata12.push(parseProducersSection()); |
| } catch (e) { |
| console.warn("Failed to decode custom \"producers\" section @".concat(offset, "; ignoring (").concat(e.message, ").")); |
| eatBytes(offset - (_initialOffset + _remainingBytes2)); |
| } |
| } else { |
| // We don't parse the custom section |
| eatBytes(_remainingBytes2); |
| dumpSep("ignore custom " + JSON.stringify(sectionName.value) + " section (" + _remainingBytes2 + " bytes)"); |
| } |
| |
| return { |
| nodes: [], |
| metadata: _metadata12, |
| nextSectionIndex: nextSectionIndex |
| }; |
| } |
| } |
| |
| throw new CompileError("Unexpected section: " + toHex(sectionId)); |
| } |
| |
| parseModuleHeader(); |
| parseVersion(); |
| var moduleFields = []; |
| var sectionIndex = 0; |
| var moduleMetadata = { |
| sections: [], |
| functionNames: [], |
| localNames: [], |
| producers: [] |
| }; |
| /** |
| * All the generate declaration are going to be stored in our state |
| */ |
| |
| while (offset < buf.length) { |
| var _parseSection = parseSection(sectionIndex), |
| _nodes12 = _parseSection.nodes, |
| _metadata13 = _parseSection.metadata, |
| nextSectionIndex = _parseSection.nextSectionIndex; |
| |
| moduleFields.push.apply(moduleFields, _toConsumableArray(_nodes12)); |
| var metadataArray = Array.isArray(_metadata13) ? _metadata13 : [_metadata13]; |
| metadataArray.forEach(function (metadataItem) { |
| if (metadataItem.type === "FunctionNameMetadata") { |
| moduleMetadata.functionNames.push(metadataItem); |
| } else if (metadataItem.type === "LocalNameMetadata") { |
| moduleMetadata.localNames.push(metadataItem); |
| } else if (metadataItem.type === "ProducersSectionMetadata") { |
| moduleMetadata.producers.push(metadataItem); |
| } else { |
| moduleMetadata.sections.push(metadataItem); |
| } |
| }); // Ignore custom section |
| |
| if (nextSectionIndex) { |
| sectionIndex = nextSectionIndex; |
| } |
| } |
| /** |
| * Transform the state into AST nodes |
| */ |
| |
| |
| var funcIndex = 0; |
| state.functionsInModule.forEach(function (func) { |
| var params = func.signature.params; |
| var result = func.signature.result; |
| var body = []; // External functions doesn't provide any code, can skip it here |
| |
| if (func.isExternal === true) { |
| return; |
| } |
| |
| var decodedElementInCodeSection = state.elementsInCodeSection[funcIndex]; |
| |
| if (opts.ignoreCodeSection === false) { |
| if (typeof decodedElementInCodeSection === "undefined") { |
| throw new CompileError("func " + toHex(funcIndex) + " code not found"); |
| } |
| |
| body = decodedElementInCodeSection.code; |
| } |
| |
| funcIndex++; |
| var funcNode = t.func(func.id, t.signature(params, result), body); |
| |
| if (func.isExternal === true) { |
| funcNode.isExternal = func.isExternal; |
| } // Add function position in the binary if possible |
| |
| |
| if (opts.ignoreCodeSection === false) { |
| var _startLoc23 = decodedElementInCodeSection.startLoc, |
| endLoc = decodedElementInCodeSection.endLoc, |
| bodySize = decodedElementInCodeSection.bodySize; |
| funcNode = t.withLoc(funcNode, endLoc, _startLoc23); |
| funcNode.metadata = { |
| bodySize: bodySize |
| }; |
| } |
| |
| moduleFields.push(funcNode); |
| }); |
| state.elementsInExportSection.forEach(function (moduleExport) { |
| /** |
| * If the export has no id, we won't be able to call it from the outside |
| * so we can omit it |
| */ |
| if (moduleExport.id != null) { |
| moduleFields.push(t.withLoc(t.moduleExport(moduleExport.name, t.moduleExportDescr(moduleExport.type, moduleExport.id)), moduleExport.endLoc, moduleExport.startLoc)); |
| } |
| }); |
| dumpSep("end of program"); |
| var module = t.module(null, moduleFields, t.moduleMetadata(moduleMetadata.sections, moduleMetadata.functionNames, moduleMetadata.localNames, moduleMetadata.producers)); |
| return t.program([module]); |
| } |