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.

1003 lines
30 KiB

  1. const streamFromArrayTxt = require("../../src/streamfromarray_txt");
  2. const streamFromArrayBin = require("../../src/streamfromarray_bin");
  3. const bigInt = require("big-integer");
  4. const assert = require("assert");
  5. const ModuleBuilder = require("wasmbuilder").ModuleBuilder;
  6. const ModuleBuilderWat = require("wasmbuilder").ModuleBuilderWat;
  7. const buildRuntime = require("./build_runtime");
  8. const errs = require("./errs");
  9. function hexToBytesR(hex) {
  10. for (var bytes = [], c = hex.length-2; c >=0; c -= 2)
  11. bytes.push(parseInt(hex.substr(c, 2), 16));
  12. return bytes;
  13. }
  14. function intToBytes32(v) {
  15. return [ v &0xFF, (v>>8) & 0xFF, (v>>16) & 0xFF, (v>>24) & 0xFF ];
  16. }
  17. class CodeBuilderWasm {
  18. constructor(fnBuilder) {
  19. this.fnBuilder = fnBuilder;
  20. this.ops = [];
  21. }
  22. addComment(comment) {
  23. this.ops.push({op: "COMMENT", comment});
  24. }
  25. addBlock(block) {
  26. this.ops.push({op: "BLOCK", block});
  27. }
  28. calcOffset(dLabel, offsets) {
  29. this.ops.push({op: "CALCOFFSETS", dLabel, offsets});
  30. }
  31. assign(dLabel, src, sOffset) {
  32. this.ops.push({op: "ASSIGN", dLabel, src, sOffset});
  33. }
  34. getSubComponentOffset(dLabel, component, hash, hashLabel) {
  35. this.ops.push({op: "GETSUBCOMPONENTOFFSET", dLabel, component, hash, hashLabel});
  36. }
  37. getSubComponentSizes(dLabel, component, hash, hashLabel) {
  38. this.ops.push({op: "GETSUBCOMPONENTSIZES", dLabel, component, hash, hashLabel});
  39. }
  40. getSignalOffset(dLabel, component, hash, hashLabel) {
  41. this.ops.push({op: "GETSIGNALOFFSET", dLabel, component, hash, hashLabel});
  42. }
  43. getSignalSizes(dLabel, component, hash, hashLabel) {
  44. this.ops.push({op: "GETSIGNALSIZES", dLabel, component, hash, hashLabel});
  45. }
  46. setSignal(component, signal, value) {
  47. this.ops.push({op: "SETSIGNAL", component, signal, value});
  48. }
  49. getSignal(dLabel, component, signal) {
  50. this.ops.push({op: "GETSIGNAL", dLabel, component, signal});
  51. }
  52. copyN(dLabel, offset, src, n) {
  53. this.ops.push({op: "COPYN", dLabel, offset, src, n});
  54. }
  55. copyNRet(src, n) {
  56. this.ops.push({op: "COPYNRET", src, n});
  57. }
  58. fieldOp(dLabel, fOp, params) {
  59. this.ops.push({op: "FOP", dLabel, fOp, params});
  60. }
  61. ret() {
  62. this.ops.push({op: "RET"});
  63. }
  64. addLoop(condLabel, body) {
  65. this.ops.push({op: "LOOP", condLabel, body});
  66. }
  67. addIf(condLabel, thenCode, elseCode) {
  68. this.ops.push({op: "IF", condLabel, thenCode, elseCode});
  69. }
  70. fnCall(fnName, retLabel, params) {
  71. this.ops.push({op: "FNCALL", fnName, retLabel, params});
  72. }
  73. checkConstraint(a, b, strErr) {
  74. this.ops.push({op: "CHECKCONSTRAINT", a, b, strErr});
  75. }
  76. concat(cb) {
  77. this.ops.push(...cb.ops);
  78. }
  79. hasCode() {
  80. for (let i=0; i<this.ops.length; i++) {
  81. if (this.ops[i].op != "COMMENT") return true;
  82. }
  83. return false;
  84. }
  85. _buildOffset(c, offsets) {
  86. let rN=0;
  87. let S = null;
  88. offsets.forEach((o) => {
  89. if ((o[0][0] == "V") && (o[1][0]== "V")) {
  90. rN += o[0][1]*o[1][1];
  91. return;
  92. }
  93. let f=[];
  94. if (o[0][0] == "V") {
  95. f = c.i32_const(o[0][1]);
  96. } else if (o[0][0] == "RI") {
  97. f = c.i32_load(this.fnBuilder._getPtr(c, o[0][1]));
  98. } else if (o[0][0] == "R") {
  99. f = c.call("Fr_toInt", this.fnBuilder._getPtr(c, o[0][1]));
  100. } else {
  101. assert(false);
  102. }
  103. if (o[1][0] == "V") {
  104. if (o[1][1]==0) return;
  105. if (o[1][1]>1) {
  106. f = c.i32_mul(f, c.i32_const(o[1][1]));
  107. }
  108. } else if (o[1][0] == "RS") {
  109. f = c.i32_mul(
  110. f,
  111. c.i32_load(
  112. c.i32_add(
  113. c.i32_load(this.fnBuilder._getPtr(c, o[1][1])),
  114. c.i32_const(o[1][2]*4)
  115. )
  116. )
  117. );
  118. } else {
  119. assert(false);
  120. }
  121. if (S!=null) {
  122. S = c.i32_add( S, f);
  123. } else {
  124. S = f;
  125. }
  126. });
  127. if (rN>0) {
  128. if (S!=null) {
  129. S = c.i32_add( S, c.i32_const(rN));
  130. } else {
  131. S = c.i32_const(rN);
  132. }
  133. }
  134. return S;
  135. }
  136. build(c) {
  137. const code = [];
  138. this.ops.forEach( (o) => {
  139. if (o.op == "COMMENT") {
  140. code.push(
  141. c.comment(o.comment)
  142. );
  143. // DO nothing
  144. } else if (o.op == "BLOCK") {
  145. code.push(
  146. o.block.build(c)
  147. );
  148. } else if (o.op == "CALCOFFSETS") {
  149. code.push(
  150. c.i32_store(
  151. this.fnBuilder._getPtr(c, o.dLabel),
  152. this._buildOffset(c, o.offsets)
  153. )
  154. );
  155. } else if (o.op == "ASSIGN") {
  156. code.push(
  157. c.i32_store(
  158. this.fnBuilder._getPtr(c, o.dLabel),
  159. c.i32_add(
  160. this.fnBuilder._deRefFr(c, o.src),
  161. c.i32_mul(
  162. this.fnBuilder._deRefInt(c, o.sOffset),
  163. c.i32_const(this.fnBuilder.builder.sizeFr)
  164. )
  165. )
  166. )
  167. );
  168. } else if (o.op == "GETSUBCOMPONENTOFFSET") {
  169. code.push(
  170. c.call(
  171. "getSubComponentOffset",
  172. this.fnBuilder._getPtr(c, o.dLabel),
  173. this.fnBuilder._deRefInt(c, o.component),
  174. c.i64_const("0x" + o.hash)
  175. )
  176. );
  177. } else if (o.op == "GETSUBCOMPONENTSIZES") {
  178. code.push(
  179. c.call(
  180. "getSubComponentSizes",
  181. this.fnBuilder._getPtr(c, o.dLabel),
  182. this.fnBuilder._deRefInt(c, o.component),
  183. c.i64_const("0x" + o.hash)
  184. )
  185. );
  186. } else if (o.op == "GETSIGNALOFFSET") {
  187. code.push(
  188. c.call(
  189. "getSignalOffset",
  190. this.fnBuilder._getPtr(c, o.dLabel),
  191. this.fnBuilder._deRefInt(c, o.component),
  192. c.i64_const("0x" + o.hash)
  193. )
  194. );
  195. } else if (o.op == "GETSIGNALSIZES") {
  196. code.push(
  197. c.call(
  198. "getSignalSizes",
  199. this.fnBuilder._getPtr(c, o.dLabel),
  200. this.fnBuilder._deRefInt(c, o.component),
  201. c.i64_const("0x" + o.hash)
  202. )
  203. );
  204. } else if (o.op == "SETSIGNAL") {
  205. code.push(
  206. c.call(
  207. "setSignal",
  208. c.getLocal("cIdx"),
  209. this.fnBuilder._deRefInt(c, o.component),
  210. this.fnBuilder._deRefInt(c, o.signal),
  211. this.fnBuilder._deRefFr(c, o.value)
  212. )
  213. );
  214. } else if (o.op == "GETSIGNAL") {
  215. code.push(
  216. c.call(
  217. "getSignal",
  218. c.getLocal("cIdx"),
  219. this.fnBuilder._getPtr(c, o.dLabel),
  220. this.fnBuilder._deRefInt(c, o.component),
  221. this.fnBuilder._deRefInt(c, o.signal)
  222. )
  223. );
  224. } else if (o.op == "COPYN") {
  225. code.push(
  226. c.call(
  227. "Fr_copyn",
  228. c.i32_add(
  229. this.fnBuilder._getPtr(c, o.dLabel),
  230. c.i32_mul(
  231. this.fnBuilder._deRefInt(c, o.offset),
  232. c.i32_const(this.fnBuilder.builder.sizeFr)
  233. )
  234. ),
  235. this.fnBuilder._deRefFr(c, o.src),
  236. c.i32_const(o.n)
  237. )
  238. );
  239. } else if (o.op == "COPYNRET") {
  240. code.push(
  241. c.call(
  242. "Fr_copyn",
  243. c.getLocal("pRet"),
  244. this.fnBuilder._deRefFr(c, o.src),
  245. c.i32_const(o.n)
  246. )
  247. );
  248. } else if (o.op == "RET") {
  249. code.push(this.fnBuilder._freeStack(c));
  250. code.push(c.ret([]));
  251. } else if (o.op == "FOP") {
  252. let params = [];
  253. for (let i=0; i<o.params.length; i++) {
  254. params.push( this.fnBuilder._deRefFr(c, o.params[i]));
  255. }
  256. code.push(
  257. c.call(
  258. "Fr_" + o.fOp,
  259. this.fnBuilder._getPtr(c, o.dLabel),
  260. ...params
  261. )
  262. );
  263. } else if (o.op == "LOOP") {
  264. code.push(
  265. c.block(c.loop(
  266. c.br_if(1, c.i32_eqz(c.call("Fr_isTrue", this.fnBuilder._deRefFr(c, ["R", o.condLabel])))),
  267. o.body.build(c),
  268. c.br(0)
  269. ))
  270. );
  271. } else if (o.op == "IF") {
  272. code.push(
  273. c.if(
  274. c.call("Fr_isTrue", this.fnBuilder._deRefFr(c, ["R", o.condLabel])),
  275. o.thenCode.build(c),
  276. o.elseCode ? o.elseCode.build(c) : undefined
  277. )
  278. );
  279. } else if (o.op == "FNCALL") {
  280. const params = [];
  281. for (let i=0; i<o.params.length; i++) {
  282. params.push(this.fnBuilder._deRefFr(c, ["R", o.params[i]]));
  283. }
  284. code.push(
  285. c.call(
  286. o.fnName,
  287. this.fnBuilder._getPtr(c, o.retLabel),
  288. ...params
  289. )
  290. );
  291. } else if (o.op == "CHECKCONSTRAINT") {
  292. code.push(
  293. c.call(
  294. "checkConstraint",
  295. c.getLocal("cIdx"),
  296. this.fnBuilder._deRefFr(c, o.a),
  297. this.fnBuilder._deRefFr(c, o.b),
  298. c.i32_const(this.fnBuilder.builder.module.allocString(o.strErr))
  299. )
  300. );
  301. } else if (o.op == "LOG") {
  302. code.push(
  303. c.call(
  304. "log",
  305. this.fnBuilder._deRefFr(c, o.val)
  306. )
  307. );
  308. }
  309. });
  310. return code;
  311. }
  312. }
  313. class FunctionBuilderWasm {
  314. constructor(builder, name, instanceDef, type, params) {
  315. this.builder = builder;
  316. this.name = name;
  317. this.instanceDef = instanceDef;
  318. this.type = type; // "COMPONENT" or "FUNCTION"
  319. this.definedFrElements = [];
  320. this.definedIntElements = [];
  321. this.definedSizeElements = [];
  322. this.definedPFrElements = [];
  323. this.initializedElements = [];
  324. this.initializedSignalOffset = [];
  325. this.initializedSignalSizes = [];
  326. this.refs = {};
  327. this.nFr = 0;
  328. this.nInt = 0;
  329. this.nSizes = 0;
  330. this.nPFr = 0;
  331. }
  332. defineFrElements(dLabel, size) {
  333. this.refs[dLabel] = {
  334. t: "Fr",
  335. n: size,
  336. idx: this.nFr
  337. };
  338. this.nFr += size;
  339. }
  340. defineIntElement(dLabel) {
  341. this.refs[dLabel] = {
  342. t: "I",
  343. idx: this.nInt
  344. };
  345. this.nInt++;
  346. }
  347. defineSizesElement(dLabel) {
  348. this.refs[dLabel] = {
  349. t: "S",
  350. idx: this.nSizes
  351. };
  352. this.nSizes++;
  353. }
  354. definePFrElement(dLabel) {
  355. this.refs[dLabel] = {
  356. t: "PFr",
  357. idx: this.nPFr
  358. };
  359. this.nPFr++;
  360. }
  361. initializeFrElement(dLabel, offset, idConstant) {
  362. this.initializedElements.push({dLabel, offset, idConstant});
  363. }
  364. initializeSignalOffset(dLabel, component, hash, hashLabel) {
  365. this.initializedSignalOffset.push({dLabel, component, hash, hashLabel});
  366. }
  367. initializeSignalSizes(dLabel, component, hash, hashLabel) {
  368. this.initializedSignalSizes.push({dLabel, component, hash, hashLabel});
  369. }
  370. setParams(params) {
  371. assert(typeof this.params === "undefined");
  372. assert(this.type === "FUNCTION");
  373. this.params=params;
  374. for (let i=0; i<this.params.length; i++) {
  375. assert(typeof this.refs[this.params[i]] === "undefined");
  376. this.refs[this.params[i]] = {
  377. t: "P",
  378. l: this.params[i]
  379. };
  380. }
  381. }
  382. _getPtr(c, label, offset) {
  383. offset = offset || 0;
  384. assert (typeof this.refs[label] !== "undefined");
  385. if (this.refs[label].t == "Fr") {
  386. return c.i32_add(
  387. c.getLocal("sp"),
  388. c.i32_const((this.refs[label].idx + offset) * this.builder.sizeFr)
  389. );
  390. } else if (this.refs[label].t == "I") {
  391. assert(offset == 0);
  392. return c.i32_add(
  393. c.getLocal("sp"),
  394. c.i32_const(
  395. this.nFr * this.builder.sizeFr +
  396. this.refs[label].idx * 4)
  397. );
  398. } else if (this.refs[label].t == "S") {
  399. assert(offset == 0);
  400. return c.i32_add(
  401. c.getLocal("sp"),
  402. c.i32_const(
  403. this.nFr * this.builder.sizeFr +
  404. this.nInt * 4 +
  405. this.refs[label].idx * 4)
  406. );
  407. } else if (this.refs[label].t == "PFr") {
  408. assert(offset == 0);
  409. return c.i32_add(
  410. c.getLocal("sp"),
  411. c.i32_const(
  412. this.nFr * this.builder.sizeFr +
  413. this.nInt * 4 +
  414. this.nSizes * 4 +
  415. this.refs[label].idx * 4)
  416. );
  417. } else if (this.refs[label].t == "P") {
  418. return c.i32_add(
  419. c.getLocal(this.refs[label].l),
  420. c.i32_const( offset * this.builder.sizeFr )
  421. );
  422. }
  423. }
  424. _getPtrConstant(c, idConstant) {
  425. return c.i32_const( this.builder.pConstants + idConstant * this.builder.sizeFr );
  426. }
  427. _deRefInt(c, ref) {
  428. if (ref[0] == "R") {
  429. return c.call(
  430. "Fr_toInt",
  431. this._getPtr(c, ref[1])
  432. );
  433. } else if (ref[0] == "RI") {
  434. return c.i32_load(this._getPtr(c, ref[1]));
  435. } else if (ref[0] == "V") {
  436. return c.i32_const(ref[1]);
  437. } else if (ref[0] == "C") {
  438. return c.call(
  439. "Fr_toInt",
  440. this._getPtrConstant(c, ref[1])
  441. );
  442. } else if (ref[0] == "CC") {
  443. return c.getLocal("cIdx");
  444. } else {
  445. assert(false);
  446. }
  447. }
  448. _deRefFr(c, ref) {
  449. if (ref[0] == "R") {
  450. if (this.refs[ref[1]].t == "Fr") {
  451. return this._getPtr(c, ref[1]);
  452. } else if (this.refs[ref[1]].t == "PFr") {
  453. return c.i32_load(this._getPtr(c, ref[1]));
  454. } else if (this.refs[ref[1]].t == "P") {
  455. return c.getLocal(ref[1]);
  456. } else {
  457. assert(false);
  458. }
  459. } else if (ref[0] == "C") {
  460. return this._getPtrConstant(c, ref[1]);
  461. } else {
  462. assert(false);
  463. }
  464. }
  465. _reserveStack(c) {
  466. const code = [];
  467. code.push(
  468. // Load SP
  469. c.setLocal("sp", c.i32_load(c.i32_const(4))),
  470. // Check we have enough memory
  471. c.if(
  472. c.i32_gt_u(
  473. c.i32_const(this.nStackSize),
  474. c.getLocal("sp")
  475. ),
  476. c.call(
  477. "err",
  478. c.i32_const(errs.STACK_OUT_OF_MEM.code),
  479. c.i32_const(errs.STACK_OUT_OF_MEM.pointer)
  480. )
  481. ),
  482. // Reserve space in sp
  483. c.setLocal(
  484. "sp",
  485. c.i32_sub(
  486. c.getLocal("sp"),
  487. c.i32_const(this.nStackSize)
  488. )
  489. ),
  490. // Check if we have enought free memory
  491. c.if(
  492. c.i32_gt_u(
  493. c.i32_load(c.i32_const(0)),
  494. c.getLocal("sp")
  495. ),
  496. c.call(
  497. "err",
  498. c.i32_const(errs.STACK_TOO_SMALL.code),
  499. c.i32_const(errs.STACK_TOO_SMALL.pointer)
  500. )
  501. ),
  502. // Save sp
  503. c.i32_store(c.i32_const(4), c.getLocal("sp"))
  504. );
  505. return code;
  506. }
  507. _freeStack(c) {
  508. const code = [];
  509. code.push(
  510. c.i32_store(
  511. c.i32_const(4),
  512. c.i32_add(
  513. c.getLocal("sp"),
  514. c.i32_const(this.nStackSize)
  515. )
  516. )
  517. );
  518. return code;
  519. }
  520. _buildHeader(c) {
  521. const code = [];
  522. this.nStackSize =
  523. this.nFr * this.builder.sizeFr +
  524. this.nInt * 4 +
  525. this.nSizes * 4 +
  526. this.nPFr * 4;
  527. code.push( this._reserveStack(c));
  528. this.initializedElements.forEach( (o) => {
  529. code.push(
  530. c.call(
  531. "Fr_copy",
  532. this._getPtr(c, o.dLabel, o.offset),
  533. this._getPtrConstant(c, o.idConstant)
  534. )
  535. );
  536. });
  537. this.initializedSignalOffset.forEach( (o) => {
  538. code.push(
  539. c.call(
  540. "getSignalOffset",
  541. this._getPtr(c, o.dLabel, o.offset),
  542. this._deRefInt(c, o.component),
  543. c.i64_const("0x" + o.hash)
  544. )
  545. );
  546. });
  547. this.initializedSignalSizes.forEach( (o) => {
  548. code.push(
  549. c.call(
  550. "getSignalSizes",
  551. this._getPtr(c, o.dLabel, o.offset),
  552. this._deRefInt(c, o.component),
  553. c.i64_const("0x" + o.hash)
  554. )
  555. );
  556. });
  557. return code;
  558. }
  559. _buildFooter(c) {
  560. return this._freeStack(c);
  561. }
  562. newCodeBuilder() {
  563. return new CodeBuilderWasm(this);
  564. }
  565. setBody(body) {
  566. this.body = body;
  567. }
  568. build(module) {
  569. const f = module.addFunction(this.name, this.instanceDef);
  570. if (this.type=="COMPONENT") {
  571. f.addParam("cIdx", "i32");
  572. } else if (this.type=="FUNCTION") {
  573. f.addParam("pRet", "i32");
  574. for (let i=0;i<this.params.length;i++ ) {
  575. f.addParam(this.params[i], "i32");
  576. }
  577. } else {
  578. assert(false);
  579. }
  580. f.addLocal("sp", "i32");
  581. const c = f.getCodeBuilder();
  582. const code = [];
  583. code.push(this._buildHeader(c));
  584. code.push(this.body.build(c));
  585. if (this.type=="COMPONENT") {
  586. code.push(c.call("componentFinished", c.getLocal("cIdx")));
  587. }
  588. code.push(this._buildFooter(c));
  589. f.addCode(flatArray(code));
  590. function flatArray(c) {
  591. const res=[];
  592. for (let i=0; i<c.length; i++) {
  593. if (Array.isArray(c[i])) {
  594. res.push(...flatArray(c[i]));
  595. } else {
  596. res.push(c[i]);
  597. }
  598. }
  599. return res;
  600. }
  601. }
  602. }
  603. class BuilderWasm {
  604. constructor() {
  605. this.hashMaps={};
  606. this.componentEntriesTables={};
  607. this.sizes ={};
  608. this.constants = [];
  609. this.usedConstants = {};
  610. this.functions = [];
  611. this.components = [];
  612. this.TYPE_SIGNAL = 1;
  613. this.TYPE_COMPONENT = 2;
  614. this.addConstant(bigInt(0)); // constants[0] = 0;
  615. this.addConstant(bigInt(1)); // constants[1] = 1;
  616. this.offsetComponentNInputSignals = 12;
  617. this.sizeofComponent = 20;
  618. }
  619. setHeader(header) {
  620. this.header=header;
  621. this.n64 = Math.floor((this.header.P.bitLength() - 1) / 64)+1;
  622. this.sizeFr = this.n64*8 + 8;
  623. }
  624. // ht is an array of 256 element that can be undefined or [Hash, Idx, KeyName] elements.
  625. addHashMap(name, table) {
  626. this.hashMaps[name] = {table};
  627. }
  628. addComponentEntriesTable(name, cet) {
  629. this.componentEntriesTables[name] = cet;
  630. }
  631. addSizes(name, table) {
  632. this.sizes[name] = {table};
  633. }
  634. addConstant(c) {
  635. c = bigInt(c);
  636. const cS = c.toString();
  637. if (this.usedConstants[cS]) return this.usedConstants[cS];
  638. this.constants.push(c);
  639. this.usedConstants[cS] = this.constants.length - 1;
  640. return this.constants.length - 1;
  641. }
  642. addFunction(fnBuilder) {
  643. this.functions.push(fnBuilder);
  644. }
  645. addComponent(component) {
  646. this.components.push(component);
  647. }
  648. setMapIsInput(map) {
  649. this.mapIsInput = map;
  650. }
  651. setWit2Sig(wit2sig) {
  652. this.wit2sig = wit2sig;
  653. }
  654. newComponentFunctionBuilder(name, instanceDef) {
  655. return new FunctionBuilderWasm(this, name, instanceDef, "COMPONENT");
  656. }
  657. newFunctionBuilder(name, instanceDef, params) {
  658. return new FunctionBuilderWasm(this, name, instanceDef, "FUNCTION", params);
  659. }
  660. // Body functions
  661. _buildHeader(module) {
  662. this.pCircuit = module.alloc(48);
  663. this.pNSignals = this.pCircuit;
  664. this.pNComponents = this.pCircuit + 4;
  665. this.pNInputs = this.pCircuit + 8;
  666. this.pNOutputs = this.pCircuit + 12;
  667. this.pNVars = this.pCircuit + 16;
  668. this.ppWit2sig = this.pCircuit + 20;
  669. this.ppComponents = this.pCircuit + 24;
  670. this.ppMapIsInput = this.pCircuit + 28;
  671. this.ppConstants = this.pCircuit + 32;
  672. this.ppSignals = this.pCircuit + 36;
  673. this.ppInputSignalsToTrigger = this.pCircuit + 40;
  674. this.ppSignalsAssigned = this.pCircuit + 44;
  675. }
  676. _buildSizes(module) {
  677. for (let sName in this.sizes) {
  678. const accSizes = this.sizes[sName];
  679. const bytes = [];
  680. for (let i=0; i<accSizes.table.length; i++) {
  681. bytes.push(intToBytes32(accSizes.table[i]));
  682. }
  683. const fBytes = [].concat(...bytes);
  684. accSizes.pointer = module.alloc(fBytes);
  685. }
  686. }
  687. _buildHashMaps(module) {
  688. for (let hmName in this.hashMaps ) {
  689. const hm = this.hashMaps[hmName];
  690. const bytes = [];
  691. for (let i=0; i<256; i++) {
  692. if (hm.table[i]) {
  693. bytes.push(hexToBytesR(hm.table[i][0]));
  694. bytes.push(intToBytes32(hm.table[i][1]));
  695. } else {
  696. bytes.push([0,0,0,0,0,0,0,0,0,0,0,0]);
  697. }
  698. }
  699. const fBytes = [].concat(...bytes);
  700. hm.pointer = module.alloc(fBytes);
  701. }
  702. }
  703. _buildComponentEntriesTables(module) {
  704. for (let cetName in this.componentEntriesTables) {
  705. const cet = this.componentEntriesTables[cetName];
  706. const bytes = [];
  707. for (let j=0; j<cet.length; j++) {
  708. const ty = cet[j].type == "S" ? this.TYPE_SIGNAL : this.TYPE_COMPONENT;
  709. bytes.push(intToBytes32(cet[j].offset));
  710. bytes.push(intToBytes32(this.sizes[cet[j].sizeName].pointer));
  711. bytes.push(intToBytes32(ty));
  712. }
  713. const fBytes = [].concat(...bytes);
  714. this.componentEntriesTables[cetName].pointer = module.alloc(fBytes);
  715. }
  716. }
  717. _buildConstants(module) {
  718. const self = this;
  719. const R = bigInt.one.shiftLeft(this.n64*64);
  720. const bytes = [];
  721. for (let i=0; i<self.constants.length; i++) {
  722. bytes.push(Fr2Bytes(self.constants[i]));
  723. }
  724. const fBytes = [].concat(...bytes);
  725. this.pConstants = module.alloc(fBytes);
  726. function Fr2Bytes(n) {
  727. if (n.lt(bigInt("80000000", 16)) ) {
  728. return shortMontgomeryPositive(n);
  729. }
  730. if (n.geq(self.header.P.minus(bigInt("80000000", 16))) ) {
  731. return shortMontgomeryNegative(n);
  732. }
  733. return longMontgomery(n);
  734. function shortMontgomeryPositive(a) {
  735. return [
  736. ...intToBytes32(parseInt(a)),
  737. ...intToBytes32(0x40000000),
  738. ...long(toMontgomery(a))
  739. ];
  740. }
  741. function shortMontgomeryNegative(a) {
  742. const b = a.minus(self.header.P);
  743. return [
  744. ...intToBytes32(parseInt(b)),
  745. ...intToBytes32(0x40000000),
  746. ...long(toMontgomery(a))
  747. ];
  748. }
  749. function longMontgomery(a) {
  750. return [
  751. ...intToBytes32(0),
  752. ...intToBytes32(0xC0000000),
  753. ...long(toMontgomery(a))
  754. ];
  755. }
  756. function long(a) {
  757. const bytes = [];
  758. let r = bigInt(a);
  759. let S = "";
  760. let i = 0;
  761. while (!r.isZero()) {
  762. S = ("0000000000000000" + r.and(bigInt("FFFFFFFFFFFFFFFF", 16)).toString(16)).substr(-16);
  763. bytes.push(hexToBytesR(S));
  764. i++;
  765. r = r.shiftRight(64);
  766. }
  767. while (i<self.n64) {
  768. bytes.push(hexToBytesR("0000000000000000"));
  769. i++;
  770. }
  771. const fBytes = [].concat(...bytes);
  772. return fBytes;
  773. }
  774. function toMontgomery(a) {
  775. return a.times(R).mod(self.header.P);
  776. }
  777. }
  778. }
  779. _buildFunctions(module) {
  780. for (let i=0; i<this.functions.length; i++) {
  781. const cfb = this.functions[i];
  782. cfb.build(module);
  783. }
  784. }
  785. _buildComponents(module) {
  786. const bytes = [];
  787. for (let i=0; i<this.components.length; i++) {
  788. const c = this.components[i];
  789. bytes.push(intToBytes32(this.hashMaps[c.hashMapName].pointer));
  790. bytes.push(intToBytes32(this.componentEntriesTables[c.entryTableName].pointer));
  791. bytes.push(intToBytes32(i));
  792. bytes.push(intToBytes32(c.nInSignals));
  793. bytes.push(intToBytes32(c.newThread ? 1 : 0));
  794. module.addFunctionToTable(c.functionName);
  795. }
  796. const fBytes = [].concat(...bytes);
  797. this.pComponents = module.alloc(fBytes);
  798. }
  799. _buildMapIsInput(module) {
  800. const bytes = [];
  801. for (let i=0; i<this.mapIsInput.length; i++) {
  802. bytes.push(intToBytes32(this.mapIsInput[i]));
  803. }
  804. const fBytes = [].concat(...bytes);
  805. this.pMapIsInput = module.alloc(fBytes);
  806. }
  807. _buildWit2Sig(module) {
  808. const bytes = [];
  809. for (let i=0; i<this.wit2sig.length; i++) {
  810. bytes.push(intToBytes32(this.wit2sig[i]));
  811. }
  812. const fBytes = [].concat(...bytes);
  813. this.pWit2sig = module.alloc(fBytes);
  814. }
  815. _buildCircuitVar(module) {
  816. module.addData(this.pNSignals, intToBytes32(this.header.NSignals));
  817. module.addData(this.pNComponents, intToBytes32(this.header.NComponents));
  818. module.addData(this.pNInputs, intToBytes32(this.header.NInputs));
  819. module.addData(this.pNOutputs, intToBytes32(this.header.NOutputs));
  820. module.addData(this.pNVars, intToBytes32(this.header.NVars));
  821. module.addData(this.ppWit2sig, intToBytes32(this.pWit2sig));
  822. module.addData(this.ppComponents, intToBytes32(this.pComponents));
  823. module.addData(this.ppMapIsInput, intToBytes32(this.pMapIsInput));
  824. module.addData(this.ppConstants, intToBytes32(this.pConstants));
  825. module.addData(this.ppSignals, intToBytes32(this.pSignals));
  826. module.addData(this.ppInputSignalsToTrigger, intToBytes32(this.pInputSignalsToTrigger));
  827. module.addData(this.ppSignalsAssigned, intToBytes32(this.pSignalsAssigned));
  828. }
  829. _buildErrors(module) {
  830. for (let e in errs) {
  831. errs[e].pointer = module.allocString(errs[e].str);
  832. }
  833. }
  834. build(outType) {
  835. let module;
  836. if (outType == "wasm") {
  837. module=new ModuleBuilder();
  838. } else if (outType == "wat") {
  839. module=new ModuleBuilderWat();
  840. } else {
  841. assert(false);
  842. }
  843. this.module = module;
  844. // First of all reseve the space for the header so this has a fixed position starting at 8.
  845. this._buildHeader(module);
  846. this._buildErrors(module);
  847. buildRuntime(module, this);
  848. this._buildSizes(module);
  849. this._buildConstants(module);
  850. this._buildHashMaps(module);
  851. this._buildComponentEntriesTables(module);
  852. this._buildFunctions(module);
  853. this._buildComponents(module);
  854. this._buildMapIsInput(module);
  855. this._buildWit2Sig(module);
  856. this._buildCircuitVar(module);
  857. if (outType == "wasm") {
  858. return streamFromArrayBin(module.build());
  859. } else if (outType == "wat") {
  860. return streamFromArrayTxt(module.build());
  861. } else {
  862. assert(false);
  863. }
  864. }
  865. }
  866. module.exports = BuilderWasm;