You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

377 lines
9.3 KiB

4 years ago
  1. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  2. function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
  3. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  4. // TODO(sven): add flow in here
  5. import { isSignature, isNumberLiteral } from "@webassemblyjs/ast";
  6. export function moduleContextFromModuleAST(m) {
  7. var moduleContext = new ModuleContext();
  8. if (!(m.type === "Module")) {
  9. throw new Error('m.type === "Module"' + " error: " + (undefined || "unknown"));
  10. }
  11. m.fields.forEach(function (field) {
  12. switch (field.type) {
  13. case "Start":
  14. {
  15. moduleContext.setStart(field.index);
  16. break;
  17. }
  18. case "TypeInstruction":
  19. {
  20. moduleContext.addType(field);
  21. break;
  22. }
  23. case "Func":
  24. {
  25. moduleContext.addFunction(field);
  26. break;
  27. }
  28. case "Global":
  29. {
  30. moduleContext.defineGlobal(field);
  31. break;
  32. }
  33. case "ModuleImport":
  34. {
  35. switch (field.descr.type) {
  36. case "GlobalType":
  37. {
  38. moduleContext.importGlobal(field.descr.valtype, field.descr.mutability);
  39. break;
  40. }
  41. case "Memory":
  42. {
  43. moduleContext.addMemory(field.descr.limits.min, field.descr.limits.max);
  44. break;
  45. }
  46. case "FuncImportDescr":
  47. {
  48. moduleContext.importFunction(field.descr);
  49. break;
  50. }
  51. case "Table":
  52. {
  53. // FIXME(sven): not implemented yet
  54. break;
  55. }
  56. default:
  57. throw new Error("Unsupported ModuleImport of type " + JSON.stringify(field.descr.type));
  58. }
  59. break;
  60. }
  61. case "Memory":
  62. {
  63. moduleContext.addMemory(field.limits.min, field.limits.max);
  64. break;
  65. }
  66. }
  67. });
  68. return moduleContext;
  69. }
  70. /**
  71. * Module context for type checking
  72. */
  73. export var ModuleContext =
  74. /*#__PURE__*/
  75. function () {
  76. function ModuleContext() {
  77. _classCallCheck(this, ModuleContext);
  78. this.funcs = [];
  79. this.funcsOffsetByIdentifier = [];
  80. this.types = [];
  81. this.globals = [];
  82. this.globalsOffsetByIdentifier = [];
  83. this.mems = []; // Current stack frame
  84. this.locals = [];
  85. this.labels = [];
  86. this.return = [];
  87. this.debugName = "unknown";
  88. this.start = null;
  89. }
  90. /**
  91. * Set start segment
  92. */
  93. _createClass(ModuleContext, [{
  94. key: "setStart",
  95. value: function setStart(index) {
  96. this.start = index.value;
  97. }
  98. /**
  99. * Get start function
  100. */
  101. }, {
  102. key: "getStart",
  103. value: function getStart() {
  104. return this.start;
  105. }
  106. /**
  107. * Reset the active stack frame
  108. */
  109. }, {
  110. key: "newContext",
  111. value: function newContext(debugName, expectedResult) {
  112. this.locals = [];
  113. this.labels = [expectedResult];
  114. this.return = expectedResult;
  115. this.debugName = debugName;
  116. }
  117. /**
  118. * Functions
  119. */
  120. }, {
  121. key: "addFunction",
  122. value: function addFunction(func
  123. /*: Func*/
  124. ) {
  125. // eslint-disable-next-line prefer-const
  126. var _ref = func.signature || {},
  127. _ref$params = _ref.params,
  128. args = _ref$params === void 0 ? [] : _ref$params,
  129. _ref$results = _ref.results,
  130. result = _ref$results === void 0 ? [] : _ref$results;
  131. args = args.map(function (arg) {
  132. return arg.valtype;
  133. });
  134. this.funcs.push({
  135. args: args,
  136. result: result
  137. });
  138. if (typeof func.name !== "undefined") {
  139. this.funcsOffsetByIdentifier[func.name.value] = this.funcs.length - 1;
  140. }
  141. }
  142. }, {
  143. key: "importFunction",
  144. value: function importFunction(funcimport) {
  145. if (isSignature(funcimport.signature)) {
  146. // eslint-disable-next-line prefer-const
  147. var _funcimport$signature = funcimport.signature,
  148. args = _funcimport$signature.params,
  149. result = _funcimport$signature.results;
  150. args = args.map(function (arg) {
  151. return arg.valtype;
  152. });
  153. this.funcs.push({
  154. args: args,
  155. result: result
  156. });
  157. } else {
  158. if (!isNumberLiteral(funcimport.signature)) {
  159. throw new Error('isNumberLiteral(funcimport.signature)' + " error: " + (undefined || "unknown"));
  160. }
  161. var typeId = funcimport.signature.value;
  162. if (!this.hasType(typeId)) {
  163. throw new Error('this.hasType(typeId)' + " error: " + (undefined || "unknown"));
  164. }
  165. var signature = this.getType(typeId);
  166. this.funcs.push({
  167. args: signature.params.map(function (arg) {
  168. return arg.valtype;
  169. }),
  170. result: signature.results
  171. });
  172. }
  173. if (typeof funcimport.id !== "undefined") {
  174. // imports are first, we can assume their index in the array
  175. this.funcsOffsetByIdentifier[funcimport.id.value] = this.funcs.length - 1;
  176. }
  177. }
  178. }, {
  179. key: "hasFunction",
  180. value: function hasFunction(index) {
  181. return typeof this.getFunction(index) !== "undefined";
  182. }
  183. }, {
  184. key: "getFunction",
  185. value: function getFunction(index) {
  186. if (typeof index !== "number") {
  187. throw new Error("getFunction only supported for number index");
  188. }
  189. return this.funcs[index];
  190. }
  191. }, {
  192. key: "getFunctionOffsetByIdentifier",
  193. value: function getFunctionOffsetByIdentifier(name) {
  194. if (!(typeof name === "string")) {
  195. throw new Error('typeof name === "string"' + " error: " + (undefined || "unknown"));
  196. }
  197. return this.funcsOffsetByIdentifier[name];
  198. }
  199. /**
  200. * Labels
  201. */
  202. }, {
  203. key: "addLabel",
  204. value: function addLabel(result) {
  205. this.labels.unshift(result);
  206. }
  207. }, {
  208. key: "hasLabel",
  209. value: function hasLabel(index) {
  210. return this.labels.length > index && index >= 0;
  211. }
  212. }, {
  213. key: "getLabel",
  214. value: function getLabel(index) {
  215. return this.labels[index];
  216. }
  217. }, {
  218. key: "popLabel",
  219. value: function popLabel() {
  220. this.labels.shift();
  221. }
  222. /**
  223. * Locals
  224. */
  225. }, {
  226. key: "hasLocal",
  227. value: function hasLocal(index) {
  228. return typeof this.getLocal(index) !== "undefined";
  229. }
  230. }, {
  231. key: "getLocal",
  232. value: function getLocal(index) {
  233. return this.locals[index];
  234. }
  235. }, {
  236. key: "addLocal",
  237. value: function addLocal(type) {
  238. this.locals.push(type);
  239. }
  240. /**
  241. * Types
  242. */
  243. }, {
  244. key: "addType",
  245. value: function addType(type) {
  246. if (!(type.functype.type === "Signature")) {
  247. throw new Error('type.functype.type === "Signature"' + " error: " + (undefined || "unknown"));
  248. }
  249. this.types.push(type.functype);
  250. }
  251. }, {
  252. key: "hasType",
  253. value: function hasType(index) {
  254. return this.types[index] !== undefined;
  255. }
  256. }, {
  257. key: "getType",
  258. value: function getType(index) {
  259. return this.types[index];
  260. }
  261. /**
  262. * Globals
  263. */
  264. }, {
  265. key: "hasGlobal",
  266. value: function hasGlobal(index) {
  267. return this.globals.length > index && index >= 0;
  268. }
  269. }, {
  270. key: "getGlobal",
  271. value: function getGlobal(index) {
  272. return this.globals[index].type;
  273. }
  274. }, {
  275. key: "getGlobalOffsetByIdentifier",
  276. value: function getGlobalOffsetByIdentifier(name) {
  277. if (!(typeof name === "string")) {
  278. throw new Error('typeof name === "string"' + " error: " + (undefined || "unknown"));
  279. }
  280. return this.globalsOffsetByIdentifier[name];
  281. }
  282. }, {
  283. key: "defineGlobal",
  284. value: function defineGlobal(global
  285. /*: Global*/
  286. ) {
  287. var type = global.globalType.valtype;
  288. var mutability = global.globalType.mutability;
  289. this.globals.push({
  290. type: type,
  291. mutability: mutability
  292. });
  293. if (typeof global.name !== "undefined") {
  294. this.globalsOffsetByIdentifier[global.name.value] = this.globals.length - 1;
  295. }
  296. }
  297. }, {
  298. key: "importGlobal",
  299. value: function importGlobal(type, mutability) {
  300. this.globals.push({
  301. type: type,
  302. mutability: mutability
  303. });
  304. }
  305. }, {
  306. key: "isMutableGlobal",
  307. value: function isMutableGlobal(index) {
  308. return this.globals[index].mutability === "var";
  309. }
  310. }, {
  311. key: "isImmutableGlobal",
  312. value: function isImmutableGlobal(index) {
  313. return this.globals[index].mutability === "const";
  314. }
  315. /**
  316. * Memories
  317. */
  318. }, {
  319. key: "hasMemory",
  320. value: function hasMemory(index) {
  321. return this.mems.length > index && index >= 0;
  322. }
  323. }, {
  324. key: "addMemory",
  325. value: function addMemory(min, max) {
  326. this.mems.push({
  327. min: min,
  328. max: max
  329. });
  330. }
  331. }, {
  332. key: "getMemory",
  333. value: function getMemory(index) {
  334. return this.mems[index];
  335. }
  336. }]);
  337. return ModuleContext;
  338. }();