123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- function _sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
- function _slicedToArray(arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return _sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }
- import { encodeNode } from "@webassemblyjs/wasm-gen";
- import { encodeU32 } from "@webassemblyjs/wasm-gen/lib/encoder";
- import { isFunc, isGlobal, assertHasLoc, orderedInsertNode, getSectionMetadata, traverse, getEndOfSection } from "@webassemblyjs/ast";
- import { resizeSectionByteSize, resizeSectionVecSize, createEmptySection, removeSections } from "@webassemblyjs/helper-wasm-section";
- import { overrideBytesInBuffer } from "@webassemblyjs/helper-buffer";
- import { getSectionForNode } from "@webassemblyjs/helper-wasm-bytecode";
- function shiftLocNodeByDelta(node, delta) {
- assertHasLoc(node); // $FlowIgnore: assertHasLoc ensures that
- node.loc.start.column += delta; // $FlowIgnore: assertHasLoc ensures that
- node.loc.end.column += delta;
- }
- function applyUpdate(ast, uint8Buffer, _ref) {
- var _ref2 = _slicedToArray(_ref, 2),
- oldNode = _ref2[0],
- newNode = _ref2[1];
- var deltaElements = 0;
- assertHasLoc(oldNode);
- var sectionName = getSectionForNode(newNode);
- var replacementByteArray = encodeNode(newNode);
- /**
- * Replace new node as bytes
- */
- uint8Buffer = overrideBytesInBuffer(uint8Buffer, // $FlowIgnore: assertHasLoc ensures that
- oldNode.loc.start.column, // $FlowIgnore: assertHasLoc ensures that
- oldNode.loc.end.column, replacementByteArray);
- /**
- * Update function body size if needed
- */
- if (sectionName === "code") {
- // Find the parent func
- traverse(ast, {
- Func: function Func(_ref3) {
- var node = _ref3.node;
- var funcHasThisIntr = node.body.find(function (n) {
- return n === newNode;
- }) !== undefined; // Update func's body size if needed
- if (funcHasThisIntr === true) {
- // These are the old functions locations informations
- assertHasLoc(node);
- var oldNodeSize = encodeNode(oldNode).length;
- var bodySizeDeltaBytes = replacementByteArray.length - oldNodeSize;
- if (bodySizeDeltaBytes !== 0) {
- var newValue = node.metadata.bodySize + bodySizeDeltaBytes;
- var newByteArray = encodeU32(newValue); // function body size byte
- // FIXME(sven): only handles one byte u32
- var start = node.loc.start.column;
- var end = start + 1;
- uint8Buffer = overrideBytesInBuffer(uint8Buffer, start, end, newByteArray);
- }
- }
- }
- });
- }
- /**
- * Update section size
- */
- var deltaBytes = replacementByteArray.length - ( // $FlowIgnore: assertHasLoc ensures that
- oldNode.loc.end.column - oldNode.loc.start.column); // Init location informations
- newNode.loc = {
- start: {
- line: -1,
- column: -1
- },
- end: {
- line: -1,
- column: -1
- }
- }; // Update new node end position
- // $FlowIgnore: assertHasLoc ensures that
- newNode.loc.start.column = oldNode.loc.start.column; // $FlowIgnore: assertHasLoc ensures that
- newNode.loc.end.column = // $FlowIgnore: assertHasLoc ensures that
- oldNode.loc.start.column + replacementByteArray.length;
- return {
- uint8Buffer: uint8Buffer,
- deltaBytes: deltaBytes,
- deltaElements: deltaElements
- };
- }
- function applyDelete(ast, uint8Buffer, node) {
- var deltaElements = -1; // since we removed an element
- assertHasLoc(node);
- var sectionName = getSectionForNode(node);
- if (sectionName === "start") {
- var sectionMetadata = getSectionMetadata(ast, "start");
- /**
- * The start section only contains one element,
- * we need to remove the whole section
- */
- uint8Buffer = removeSections(ast, uint8Buffer, "start");
- var _deltaBytes = -(sectionMetadata.size.value + 1);
- /* section id */
- return {
- uint8Buffer: uint8Buffer,
- deltaBytes: _deltaBytes,
- deltaElements: deltaElements
- };
- } // replacement is nothing
- var replacement = [];
- uint8Buffer = overrideBytesInBuffer(uint8Buffer, // $FlowIgnore: assertHasLoc ensures that
- node.loc.start.column, // $FlowIgnore: assertHasLoc ensures that
- node.loc.end.column, replacement);
- /**
- * Update section
- */
- // $FlowIgnore: assertHasLoc ensures that
- var deltaBytes = -(node.loc.end.column - node.loc.start.column);
- return {
- uint8Buffer: uint8Buffer,
- deltaBytes: deltaBytes,
- deltaElements: deltaElements
- };
- }
- function applyAdd(ast, uint8Buffer, node) {
- var deltaElements = +1; // since we added an element
- var sectionName = getSectionForNode(node);
- var sectionMetadata = getSectionMetadata(ast, sectionName); // Section doesn't exists, we create an empty one
- if (typeof sectionMetadata === "undefined") {
- var res = createEmptySection(ast, uint8Buffer, sectionName);
- uint8Buffer = res.uint8Buffer;
- sectionMetadata = res.sectionMetadata;
- }
- /**
- * check that the expressions were ended
- */
- if (isFunc(node)) {
- // $FlowIgnore
- var body = node.body;
- if (body.length === 0 || body[body.length - 1].id !== "end") {
- throw new Error("expressions must be ended");
- }
- }
- if (isGlobal(node)) {
- // $FlowIgnore
- var body = node.init;
- if (body.length === 0 || body[body.length - 1].id !== "end") {
- throw new Error("expressions must be ended");
- }
- }
- /**
- * Add nodes
- */
- var newByteArray = encodeNode(node); // The size of the section doesn't include the storage of the size itself
- // we need to manually add it here
- var start = getEndOfSection(sectionMetadata);
- var end = start;
- /**
- * Update section
- */
- var deltaBytes = newByteArray.length;
- uint8Buffer = overrideBytesInBuffer(uint8Buffer, start, end, newByteArray);
- node.loc = {
- start: {
- line: -1,
- column: start
- },
- end: {
- line: -1,
- column: start + deltaBytes
- }
- }; // for func add the additional metadata in the AST
- if (node.type === "Func") {
- // the size is the first byte
- // FIXME(sven): handle LEB128 correctly here
- var bodySize = newByteArray[0];
- node.metadata = {
- bodySize: bodySize
- };
- }
- if (node.type !== "IndexInFuncSection") {
- orderedInsertNode(ast.body[0], node);
- }
- return {
- uint8Buffer: uint8Buffer,
- deltaBytes: deltaBytes,
- deltaElements: deltaElements
- };
- }
- export function applyOperations(ast, uint8Buffer, ops) {
- ops.forEach(function (op) {
- var state;
- var sectionName;
- switch (op.kind) {
- case "update":
- state = applyUpdate(ast, uint8Buffer, [op.oldNode, op.node]);
- sectionName = getSectionForNode(op.node);
- break;
- case "delete":
- state = applyDelete(ast, uint8Buffer, op.node);
- sectionName = getSectionForNode(op.node);
- break;
- case "add":
- state = applyAdd(ast, uint8Buffer, op.node);
- sectionName = getSectionForNode(op.node);
- break;
- default:
- throw new Error("Unknown operation");
- }
- /**
- * Resize section vec size.
- * If the length of the LEB-encoded size changes, this can change
- * the byte length of the section and the offset for nodes in the
- * section. So we do this first before resizing section byte size
- * or shifting following operations' nodes.
- */
- if (state.deltaElements !== 0 && sectionName !== "start") {
- var oldBufferLength = state.uint8Buffer.length;
- state.uint8Buffer = resizeSectionVecSize(ast, state.uint8Buffer, sectionName, state.deltaElements); // Infer bytes added/removed by comparing buffer lengths
- state.deltaBytes += state.uint8Buffer.length - oldBufferLength;
- }
- /**
- * Resize section byte size.
- * If the length of the LEB-encoded size changes, this can change
- * the offset for nodes in the section. So we do this before
- * shifting following operations' nodes.
- */
- if (state.deltaBytes !== 0 && sectionName !== "start") {
- var _oldBufferLength = state.uint8Buffer.length;
- state.uint8Buffer = resizeSectionByteSize(ast, state.uint8Buffer, sectionName, state.deltaBytes); // Infer bytes added/removed by comparing buffer lengths
- state.deltaBytes += state.uint8Buffer.length - _oldBufferLength;
- }
- /**
- * Shift following operation's nodes
- */
- if (state.deltaBytes !== 0) {
- ops.forEach(function (op) {
- // We don't need to handle add ops, they are positioning independent
- switch (op.kind) {
- case "update":
- shiftLocNodeByDelta(op.oldNode, state.deltaBytes);
- break;
- case "delete":
- shiftLocNodeByDelta(op.node, state.deltaBytes);
- break;
- }
- });
- }
- uint8Buffer = state.uint8Buffer;
- });
- return uint8Buffer;
- }
|