index.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
  2. 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; }
  3. 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"); } }
  4. import { isBlock, isFunc, isIdentifier, numberLiteralFromRaw, traverse } from "../../index";
  5. import { moduleContextFromModuleAST } from "@webassemblyjs/helper-module-context"; // FIXME(sven): do the same with all block instructions, must be more generic here
  6. function newUnexpectedFunction(i) {
  7. return new Error("unknown function at offset: " + i);
  8. }
  9. export function transform(ast) {
  10. var module;
  11. traverse(ast, {
  12. Module: function (_Module) {
  13. function Module(_x) {
  14. return _Module.apply(this, arguments);
  15. }
  16. Module.toString = function () {
  17. return _Module.toString();
  18. };
  19. return Module;
  20. }(function (path) {
  21. module = path.node;
  22. })
  23. });
  24. var moduleContext = moduleContextFromModuleAST(module); // Transform the actual instruction in function bodies
  25. traverse(ast, {
  26. Func: function (_Func) {
  27. function Func(_x2) {
  28. return _Func.apply(this, arguments);
  29. }
  30. Func.toString = function () {
  31. return _Func.toString();
  32. };
  33. return Func;
  34. }(function (path) {
  35. transformFuncPath(path, moduleContext);
  36. }),
  37. Start: function (_Start) {
  38. function Start(_x3) {
  39. return _Start.apply(this, arguments);
  40. }
  41. Start.toString = function () {
  42. return _Start.toString();
  43. };
  44. return Start;
  45. }(function (path) {
  46. var index = path.node.index;
  47. if (isIdentifier(index) === true) {
  48. var offsetInModule = moduleContext.getFunctionOffsetByIdentifier(index.value);
  49. if (typeof offsetInModule === "undefined") {
  50. throw newUnexpectedFunction(index.value);
  51. } // Replace the index Identifier
  52. // $FlowIgnore: reference?
  53. path.node.index = numberLiteralFromRaw(offsetInModule);
  54. }
  55. })
  56. });
  57. }
  58. function transformFuncPath(funcPath, moduleContext) {
  59. var funcNode = funcPath.node;
  60. var signature = funcNode.signature;
  61. if (signature.type !== "Signature") {
  62. throw new Error("Function signatures must be denormalised before execution");
  63. }
  64. var params = signature.params; // Add func locals in the context
  65. params.forEach(function (p) {
  66. return moduleContext.addLocal(p.valtype);
  67. });
  68. traverse(funcNode, {
  69. Instr: function (_Instr) {
  70. function Instr(_x4) {
  71. return _Instr.apply(this, arguments);
  72. }
  73. Instr.toString = function () {
  74. return _Instr.toString();
  75. };
  76. return Instr;
  77. }(function (instrPath) {
  78. var instrNode = instrPath.node;
  79. /**
  80. * Local access
  81. */
  82. if (instrNode.id === "get_local" || instrNode.id === "set_local" || instrNode.id === "tee_local") {
  83. var _instrNode$args = _slicedToArray(instrNode.args, 1),
  84. firstArg = _instrNode$args[0];
  85. if (firstArg.type === "Identifier") {
  86. var offsetInParams = params.findIndex(function (_ref) {
  87. var id = _ref.id;
  88. return id === firstArg.value;
  89. });
  90. if (offsetInParams === -1) {
  91. throw new Error("".concat(firstArg.value, " not found in ").concat(instrNode.id, ": not declared in func params"));
  92. } // Replace the Identifer node by our new NumberLiteral node
  93. instrNode.args[0] = numberLiteralFromRaw(offsetInParams);
  94. }
  95. }
  96. /**
  97. * Global access
  98. */
  99. if (instrNode.id === "get_global" || instrNode.id === "set_global") {
  100. var _instrNode$args2 = _slicedToArray(instrNode.args, 1),
  101. _firstArg = _instrNode$args2[0];
  102. if (isIdentifier(_firstArg) === true) {
  103. var globalOffset = moduleContext.getGlobalOffsetByIdentifier( // $FlowIgnore: reference?
  104. _firstArg.value);
  105. if (typeof globalOffset === "undefined") {
  106. // $FlowIgnore: reference?
  107. throw new Error("global ".concat(_firstArg.value, " not found in module"));
  108. } // Replace the Identifer node by our new NumberLiteral node
  109. instrNode.args[0] = numberLiteralFromRaw(globalOffset);
  110. }
  111. }
  112. /**
  113. * Labels lookup
  114. */
  115. if (instrNode.id === "br") {
  116. var _instrNode$args3 = _slicedToArray(instrNode.args, 1),
  117. _firstArg2 = _instrNode$args3[0];
  118. if (isIdentifier(_firstArg2) === true) {
  119. // if the labels is not found it is going to be replaced with -1
  120. // which is invalid.
  121. var relativeBlockCount = -1; // $FlowIgnore: reference?
  122. instrPath.findParent(function (_ref2) {
  123. var node = _ref2.node;
  124. if (isBlock(node)) {
  125. relativeBlockCount++; // $FlowIgnore: reference?
  126. var name = node.label || node.name;
  127. if (_typeof(name) === "object") {
  128. // $FlowIgnore: isIdentifier ensures that
  129. if (name.value === _firstArg2.value) {
  130. // Found it
  131. return false;
  132. }
  133. }
  134. }
  135. if (isFunc(node)) {
  136. return false;
  137. }
  138. }); // Replace the Identifer node by our new NumberLiteral node
  139. instrNode.args[0] = numberLiteralFromRaw(relativeBlockCount);
  140. }
  141. }
  142. }),
  143. /**
  144. * Func lookup
  145. */
  146. CallInstruction: function (_CallInstruction) {
  147. function CallInstruction(_x5) {
  148. return _CallInstruction.apply(this, arguments);
  149. }
  150. CallInstruction.toString = function () {
  151. return _CallInstruction.toString();
  152. };
  153. return CallInstruction;
  154. }(function (_ref3) {
  155. var node = _ref3.node;
  156. var index = node.index;
  157. if (isIdentifier(index) === true) {
  158. var offsetInModule = moduleContext.getFunctionOffsetByIdentifier(index.value);
  159. if (typeof offsetInModule === "undefined") {
  160. throw newUnexpectedFunction(index.value);
  161. } // Replace the index Identifier
  162. // $FlowIgnore: reference?
  163. node.index = numberLiteralFromRaw(offsetInModule);
  164. }
  165. })
  166. });
  167. }