@fluffylabs/anan-as 1.2.0 → 1.3.0-1ebcf8f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/dist/bin/index.js +138 -5
  2. package/dist/bin/src/fuzz.js +2 -2
  3. package/dist/bin/src/test-json.js +2 -6
  4. package/dist/bin/src/trace-parse.js +1 -0
  5. package/dist/bin/src/trace-replay.js +14 -9
  6. package/dist/bin/src/tracer.js +16 -13
  7. package/dist/bin/src/utils.js +2 -2
  8. package/dist/build/compiler-inline.js +1 -1
  9. package/dist/build/compiler.d.ts +17 -13
  10. package/dist/build/compiler.js +13 -21
  11. package/dist/build/compiler.wasm +0 -0
  12. package/dist/build/debug-inline.js +1 -1
  13. package/dist/build/debug-raw-inline.js +1 -1
  14. package/dist/build/debug-raw.d.ts +50 -112
  15. package/dist/build/debug-raw.js +78 -139
  16. package/dist/build/debug-raw.wasm +0 -0
  17. package/dist/build/debug.d.ts +50 -112
  18. package/dist/build/debug.js +81 -147
  19. package/dist/build/debug.wasm +0 -0
  20. package/dist/build/js/assembly/api-debugger.d.ts +55 -0
  21. package/dist/build/js/assembly/api-debugger.js +245 -0
  22. package/dist/build/js/assembly/api-internal.d.ts +13 -0
  23. package/dist/build/js/assembly/api-internal.js +191 -0
  24. package/dist/build/js/assembly/api-types.d.ts +45 -0
  25. package/dist/build/js/assembly/api-types.js +52 -0
  26. package/dist/build/js/assembly/api-utils.d.ts +79 -0
  27. package/dist/build/js/assembly/api-utils.js +221 -0
  28. package/dist/build/js/assembly/arguments.d.ts +44 -0
  29. package/dist/build/js/assembly/arguments.js +164 -0
  30. package/dist/build/js/assembly/codec.d.ts +24 -0
  31. package/dist/build/js/assembly/codec.js +139 -0
  32. package/dist/build/js/assembly/gas.d.ts +11 -0
  33. package/dist/build/js/assembly/gas.js +33 -0
  34. package/dist/build/js/assembly/index-shared.d.ts +4 -0
  35. package/dist/build/js/assembly/index-shared.js +4 -0
  36. package/dist/build/js/assembly/instructions/bit.d.ts +11 -0
  37. package/dist/build/js/assembly/instructions/bit.js +53 -0
  38. package/dist/build/js/assembly/instructions/branch.d.ts +17 -0
  39. package/dist/build/js/assembly/instructions/branch.js +120 -0
  40. package/dist/build/js/assembly/instructions/jump.d.ts +5 -0
  41. package/dist/build/js/assembly/instructions/jump.js +21 -0
  42. package/dist/build/js/assembly/instructions/load.d.ts +17 -0
  43. package/dist/build/js/assembly/instructions/load.js +134 -0
  44. package/dist/build/js/assembly/instructions/logic.d.ts +10 -0
  45. package/dist/build/js/assembly/instructions/logic.js +47 -0
  46. package/dist/build/js/assembly/instructions/math.d.ts +28 -0
  47. package/dist/build/js/assembly/instructions/math.js +225 -0
  48. package/dist/build/js/assembly/instructions/misc.d.ts +6 -0
  49. package/dist/build/js/assembly/instructions/misc.js +22 -0
  50. package/dist/build/js/assembly/instructions/mov.d.ts +6 -0
  51. package/dist/build/js/assembly/instructions/mov.js +35 -0
  52. package/dist/build/js/assembly/instructions/outcome.d.ts +30 -0
  53. package/dist/build/js/assembly/instructions/outcome.js +88 -0
  54. package/dist/build/js/assembly/instructions/rot.d.ts +15 -0
  55. package/dist/build/js/assembly/instructions/rot.js +66 -0
  56. package/dist/build/js/assembly/instructions/set.d.ts +7 -0
  57. package/dist/build/js/assembly/instructions/set.js +36 -0
  58. package/dist/build/js/assembly/instructions/shift.d.ts +19 -0
  59. package/dist/build/js/assembly/instructions/shift.js +121 -0
  60. package/dist/build/js/assembly/instructions/store.d.ts +17 -0
  61. package/dist/build/js/assembly/instructions/store.js +101 -0
  62. package/dist/build/js/assembly/instructions/utils.d.ts +25 -0
  63. package/dist/build/js/assembly/instructions/utils.js +91 -0
  64. package/dist/build/js/assembly/instructions-exe.d.ts +2 -0
  65. package/dist/build/js/assembly/instructions-exe.js +245 -0
  66. package/dist/build/js/assembly/instructions.d.ts +10 -0
  67. package/dist/build/js/assembly/instructions.js +252 -0
  68. package/dist/build/js/assembly/interpreter.d.ts +28 -0
  69. package/dist/build/js/assembly/interpreter.js +221 -0
  70. package/dist/build/js/assembly/math.d.ts +6 -0
  71. package/dist/build/js/assembly/math.js +22 -0
  72. package/dist/build/js/assembly/memory-page.d.ts +36 -0
  73. package/dist/build/js/assembly/memory-page.js +74 -0
  74. package/dist/build/js/assembly/memory.d.ts +83 -0
  75. package/dist/build/js/assembly/memory.js +482 -0
  76. package/dist/build/js/assembly/portable.d.ts +24 -0
  77. package/dist/build/js/assembly/portable.js +363 -0
  78. package/dist/build/js/assembly/program-build.d.ts +2 -0
  79. package/dist/build/js/assembly/program-build.js +104 -0
  80. package/dist/build/js/assembly/program.d.ts +85 -0
  81. package/dist/build/js/assembly/program.js +340 -0
  82. package/dist/build/js/assembly/registers.d.ts +6 -0
  83. package/dist/build/js/assembly/registers.js +9 -0
  84. package/dist/build/js/assembly/spi.d.ts +92 -0
  85. package/dist/build/js/assembly/spi.js +152 -0
  86. package/dist/build/js/portable/bootstrap.d.ts +1 -0
  87. package/dist/build/js/portable/bootstrap.js +6 -0
  88. package/dist/build/js/portable/index.d.ts +4 -0
  89. package/dist/build/js/portable/index.js +6 -0
  90. package/dist/build/js/portable-bundle.js +4497 -0
  91. package/dist/build/release-inline.js +1 -1
  92. package/dist/build/release-mini-inline.js +1 -1
  93. package/dist/build/release-mini.d.ts +50 -112
  94. package/dist/build/release-mini.js +81 -147
  95. package/dist/build/release-mini.wasm +0 -0
  96. package/dist/build/release-stub-inline.js +1 -1
  97. package/dist/build/release-stub.d.ts +50 -112
  98. package/dist/build/release-stub.js +81 -147
  99. package/dist/build/release-stub.wasm +0 -0
  100. package/dist/build/release.d.ts +50 -112
  101. package/dist/build/release.js +81 -147
  102. package/dist/build/release.wasm +0 -0
  103. package/dist/build/test-inline.js +1 -1
  104. package/dist/build/test.wasm +0 -0
  105. package/dist/test/test-gas-cost.js +2 -3
  106. package/dist/test/test-trace-format.js +166 -0
  107. package/dist/test/test-w3f-common.js +125 -0
  108. package/dist/test/test-w3f-portable.js +5 -0
  109. package/dist/test/test-w3f.js +3 -120
  110. package/package.json +22 -11
@@ -0,0 +1,245 @@
1
+ import { buildMemory } from "./api-internal";
2
+ import { InitialChunk, InitialPage } from "./api-types";
3
+ import { Decoder } from "./codec";
4
+ import { Interpreter, Status } from "./interpreter";
5
+ import { MaybePageFault, MemoryBuilder } from "./memory";
6
+ import { Access, PAGE_SIZE } from "./memory-page";
7
+ import { deblob, extractCodeAndMetadata, liftBytes } from "./program";
8
+ import { NO_OF_REGISTERS, newRegisters, REG_SIZE_BYTES } from "./registers";
9
+ import { decodeSpi } from "./spi";
10
+ let interpreter = null;
11
+ export function resetJAM(program, pc, initialGas, args, hasMetadata = false, useBlockGas = false) {
12
+ const code = hasMetadata ? extractCodeAndMetadata(liftBytes(program)).code : liftBytes(program);
13
+ const p = decodeSpi(code, liftBytes(args), 128, useBlockGas);
14
+ const int = new Interpreter(p.program, p.registers, p.memory);
15
+ int.nextPc = pc;
16
+ int.gas.set(initialGas);
17
+ if (interpreter !== null) {
18
+ interpreter.memory.free();
19
+ }
20
+ interpreter = int;
21
+ }
22
+ export function resetGeneric(program, flatRegisters, initialGas, hasMetadata = false, useBlockGas = false) {
23
+ const code = hasMetadata ? extractCodeAndMetadata(liftBytes(program)).code : liftBytes(program);
24
+ const p = deblob(code, useBlockGas);
25
+ const registers = newRegisters();
26
+ fillRegisters(registers, flatRegisters);
27
+ const int = new Interpreter(p, registers);
28
+ int.gas.set(initialGas);
29
+ if (interpreter !== null) {
30
+ interpreter.memory.free();
31
+ }
32
+ interpreter = int;
33
+ }
34
+ export function resetGenericWithMemory(program, flatRegisters, pageMap, chunks, initialGas, hasMetadata = false, useBlockGas = false) {
35
+ const code = hasMetadata ? extractCodeAndMetadata(liftBytes(program)).code : liftBytes(program);
36
+ const p = deblob(code, useBlockGas);
37
+ const registers = newRegisters();
38
+ fillRegisters(registers, flatRegisters);
39
+ const builder = new MemoryBuilder();
40
+ const memory = buildMemory(builder, readPages(pageMap), readChunks(chunks));
41
+ const int = new Interpreter(p, registers, memory);
42
+ int.gas.set(initialGas);
43
+ interpreter = int;
44
+ }
45
+ export function nextStep() {
46
+ if (interpreter !== null) {
47
+ const int = interpreter;
48
+ return int.nextSteps();
49
+ }
50
+ return false;
51
+ }
52
+ export function nSteps(steps) {
53
+ if (interpreter !== null) {
54
+ const int = interpreter;
55
+ return int.nextSteps(steps);
56
+ }
57
+ return false;
58
+ }
59
+ export function getProgramCounter() {
60
+ if (interpreter === null) {
61
+ return 0;
62
+ }
63
+ const int = interpreter;
64
+ return u32(int.pc);
65
+ }
66
+ export function setNextProgramCounter(pc) {
67
+ if (interpreter === null) {
68
+ return;
69
+ }
70
+ const int = interpreter;
71
+ int.nextPc = pc;
72
+ }
73
+ export function getStatus() {
74
+ if (interpreter === null) {
75
+ return Status.PANIC;
76
+ }
77
+ const int = interpreter;
78
+ return int.status;
79
+ }
80
+ export function getExitArg() {
81
+ if (interpreter === null) {
82
+ return 0;
83
+ }
84
+ const int = interpreter;
85
+ return int.exitCode || 0;
86
+ }
87
+ export function getGasLeft() {
88
+ if (interpreter === null) {
89
+ return i64(0);
90
+ }
91
+ const int = interpreter;
92
+ return int.gas.get();
93
+ }
94
+ export function setGasLeft(gas) {
95
+ if (interpreter !== null) {
96
+ const int = interpreter;
97
+ int.gas.set(gas);
98
+ }
99
+ }
100
+ export function getRegisters() {
101
+ const flat = new Uint8Array(NO_OF_REGISTERS * REG_SIZE_BYTES).fill(0);
102
+ if (interpreter === null) {
103
+ return flat;
104
+ }
105
+ const int = interpreter;
106
+ for (let i = 0; i < int.registers.length; i++) {
107
+ let val = int.registers[i];
108
+ for (let j = 0; j < REG_SIZE_BYTES; j++) {
109
+ const index = i * REG_SIZE_BYTES + j;
110
+ flat[index] = (val & u64(0xff));
111
+ val = val >> u64(8);
112
+ }
113
+ }
114
+ return flat;
115
+ }
116
+ export function setRegisters(flatRegisters) {
117
+ if (interpreter === null) {
118
+ return;
119
+ }
120
+ const int = interpreter;
121
+ fillRegisters(int.registers, flatRegisters);
122
+ }
123
+ export function getPageDump(index) {
124
+ if (interpreter === null) {
125
+ return new Uint8Array(PAGE_SIZE).fill(0);
126
+ }
127
+ const int = interpreter;
128
+ const page = int.memory.pageDump(index);
129
+ if (page === null) {
130
+ return new Uint8Array(PAGE_SIZE).fill(0);
131
+ }
132
+ return page;
133
+ }
134
+ /**
135
+ * Returns the WASM linear memory pointer (byte offset) for the backing buffer of the page at `page`.
136
+ *
137
+ * Returns `0` if the page does not exist or is not readable (page/access fault).
138
+ *
139
+ * Use this instead of `getMemory` to read memory efficiently from the JS side:
140
+ * ```ts
141
+ * let pagesRead = 0;
142
+ * for (let address = start; address < end; address += PAGE_SIZE) {
143
+ * const page = address >> PAGE_SIZE_SHIFT;
144
+ * const ptr = getPagePointer(page);
145
+ * if (ptr === 0) {
146
+ * throw new Error(`Page fault at ${page << PAGE_SIZE_SHIFT}`);
147
+ * }
148
+ * destination.set(
149
+ * new Uint8Array(wasm.instance.exports.memory.buffer, ptr, Math.min(end - address, PAGE_SIZE)),
150
+ * pagesRead << PAGE_SIZE_SHIFT,
151
+ * );
152
+ * pagesRead += 1;
153
+ * }
154
+ * ```
155
+ */
156
+ export function getPagePointer(page) {
157
+ if (interpreter === null) {
158
+ return 0;
159
+ }
160
+ const int = interpreter;
161
+ return int.memory.getPagePointer(page);
162
+ }
163
+ /**
164
+ * Read a chunk of memory at `[address, address + length)`.
165
+ *
166
+ * Returns the requested memory chunk or `null` if reading triggered a page fault.
167
+ *
168
+ * @deprecated Getting memory like that is extremely inefficient (copying mulitple times)
169
+ * and error prone (we may not be able to allocate).
170
+ * Use `getPagePointer` instead to read memory directly from WASM linear memory on the JS side
171
+ * with no additional WASM-side allocations.
172
+ */
173
+ export function getMemory(address, length) {
174
+ if (interpreter === null) {
175
+ return null;
176
+ }
177
+ const int = interpreter;
178
+ const faultRes = new MaybePageFault();
179
+ const result = int.memory.getMemory(faultRes, address, length);
180
+ if (faultRes.isFault) {
181
+ return null;
182
+ }
183
+ return result;
184
+ }
185
+ /**
186
+ * Write given `data` under memory indices `[address, address + data.length)`.
187
+ *
188
+ * Returns `true` if the write was successful and `false` if page fault has been triggered.
189
+ */
190
+ export function setMemory(address, data) {
191
+ if (interpreter === null) {
192
+ return false;
193
+ }
194
+ const int = interpreter;
195
+ const end = address + data.length;
196
+ const faultRes = new MaybePageFault();
197
+ for (let i = address; i < end; i++) {
198
+ int.memory.setU8(faultRes, i, data[i - address]);
199
+ if (faultRes.isFault) {
200
+ return false;
201
+ }
202
+ }
203
+ return true;
204
+ }
205
+ function fillRegisters(registers, flat) {
206
+ const len = registers.length * REG_SIZE_BYTES;
207
+ if (len !== flat.length) {
208
+ throw new Error(`Mismatching registers size, got: ${flat.length}, expected: ${len}`);
209
+ }
210
+ for (let i = 0; i < registers.length; i++) {
211
+ let num = u64(0);
212
+ for (let j = 0; j < REG_SIZE_BYTES; j++) {
213
+ const index = i * REG_SIZE_BYTES + j;
214
+ num |= flat[index] << u64(j * 8);
215
+ }
216
+ registers[i] = num;
217
+ }
218
+ }
219
+ function readPages(pageMap) {
220
+ const pages = [];
221
+ const codec = new Decoder(pageMap);
222
+ while (!codec.isExhausted()) {
223
+ const p = new InitialPage();
224
+ p.address = codec.u32();
225
+ p.length = codec.u32();
226
+ p.access = codec.u8() > 0 ? Access.Write : Access.Read;
227
+ pages.push(p);
228
+ }
229
+ return pages;
230
+ }
231
+ function readChunks(chunks) {
232
+ const res = [];
233
+ const codec = new Decoder(chunks);
234
+ while (!codec.isExhausted()) {
235
+ const c = new InitialChunk();
236
+ c.address = codec.u32();
237
+ const len = codec.u32();
238
+ const data = codec.bytes(len);
239
+ for (let i = 0; i < len; i++) {
240
+ c.data.push(data[i]);
241
+ }
242
+ res.push(c);
243
+ }
244
+ return res;
245
+ }
@@ -0,0 +1,13 @@
1
+ import { InitialChunk, InitialPage, VmInput, VmOutput, VmRunOptions } from "./api-types";
2
+ import { Interpreter } from "./interpreter";
3
+ import { Memory, MemoryBuilder } from "./memory";
4
+ import { Program } from "./program";
5
+ export declare function getAssembly(p: Program): string;
6
+ export declare function buildMemory(builder: MemoryBuilder, pages: InitialPage[], chunks: InitialChunk[]): Memory;
7
+ /** Initialize new VM for execution. */
8
+ export declare function vmInit(input: VmInput): Interpreter;
9
+ /** Initialize & run & destroy a VM in a single go. */
10
+ export declare function vmRunOnce(input: VmInput, options: VmRunOptions): VmOutput;
11
+ export declare function vmExecute(int: Interpreter, logs?: boolean): void;
12
+ /** Destroy a running VM and consume the output. */
13
+ export declare function vmDestroy(int: Interpreter, dumpMemory?: boolean): VmOutput;
@@ -0,0 +1,191 @@
1
+ import { InitialChunk, VmOutput } from "./api-types";
2
+ import { Args, RELEVANT_ARGS } from "./arguments";
3
+ import { INSTRUCTIONS, MISSING_INSTRUCTION } from "./instructions";
4
+ import { Interpreter, Status } from "./interpreter";
5
+ import { MaybePageFault } from "./memory";
6
+ import { Access, PAGE_SIZE, RESERVED_MEMORY } from "./memory-page";
7
+ import { portable } from "./portable";
8
+ import { decodeArguments, resolveArguments } from "./program";
9
+ export function getAssembly(p) {
10
+ const len = p.code.length;
11
+ if (len === 0) {
12
+ return "<seems that there is no code>";
13
+ }
14
+ let v = "";
15
+ const argsRes = new Args();
16
+ for (let i = 0; i < len; i++) {
17
+ if (!p.mask.isInstruction(i)) {
18
+ throw new Error("We should iterate only over instructions!");
19
+ }
20
+ const instruction = p.code[i];
21
+ const iData = instruction >= INSTRUCTIONS.length ? MISSING_INSTRUCTION : INSTRUCTIONS[instruction];
22
+ v += "\n";
23
+ v += `${i}: `;
24
+ v += iData.name;
25
+ v += `(${instruction})`;
26
+ const skipBytes = p.mask.skipBytesToNextInstruction(i);
27
+ const args = decodeArguments(argsRes, iData.kind, p.code, i + 1, skipBytes);
28
+ const argsArray = [args.a, args.b, args.c, args.d];
29
+ const relevantArgs = RELEVANT_ARGS[iData.kind];
30
+ for (let i = 0; i < relevantArgs; i++) {
31
+ v += ` ${argsArray[i]}, `;
32
+ }
33
+ i += skipBytes;
34
+ }
35
+ return v;
36
+ }
37
+ export function buildMemory(builder, pages, chunks) {
38
+ let sbrkIndex = RESERVED_MEMORY;
39
+ for (let i = 0; i < pages.length; i++) {
40
+ const initPage = pages[i];
41
+ builder.setData(initPage.access, initPage.address, new Uint8Array(initPage.length));
42
+ // find the highest writeable page and set the sbrk index to the end of that range.
43
+ if (initPage.access === Access.Write) {
44
+ const pageEnd = initPage.address + initPage.length;
45
+ sbrkIndex = pageEnd < sbrkIndex ? sbrkIndex : pageEnd;
46
+ }
47
+ }
48
+ for (let i = 0; i < chunks.length; i++) {
49
+ const initChunk = chunks[i];
50
+ // access should not matter now, since we created the pages already.
51
+ const data = new Uint8Array(initChunk.data.length);
52
+ for (let j = 0; j < data.length; j++) {
53
+ data[j] = initChunk.data[j];
54
+ }
55
+ builder.setData(Access.None, initChunk.address, data);
56
+ // consider initialized chunk lengths when setting sbrk index
57
+ const chunkEnd = initChunk.address + initChunk.data.length;
58
+ sbrkIndex = chunkEnd < sbrkIndex ? sbrkIndex : chunkEnd;
59
+ }
60
+ return builder.build(sbrkIndex);
61
+ }
62
+ /** Initialize new VM for execution. */
63
+ export function vmInit(input) {
64
+ const int = new Interpreter(input.program, input.registers, input.memory);
65
+ int.nextPc = input.pc;
66
+ int.gas.set(input.gas);
67
+ return int;
68
+ }
69
+ /** Initialize & run & destroy a VM in a single go. */
70
+ export function vmRunOnce(input, options) {
71
+ const int = vmInit(input);
72
+ vmExecute(int, options.logs);
73
+ return vmDestroy(int, options.dumpMemory);
74
+ }
75
+ export function vmExecute(int, logs = false) {
76
+ let isOk = true;
77
+ const argsRes = new Args();
78
+ for (;;) {
79
+ if (!isOk) {
80
+ if (logs)
81
+ console.log(`REGISTERS (final) = [${int.registers.map((x) => `${x} (0x${x.toString(16)})`).join(", ")}]`);
82
+ if (logs)
83
+ console.log(`Finished with status: ${int.status}`);
84
+ if (logs)
85
+ console.log(`Exit code: ${int.exitCode}`);
86
+ break;
87
+ }
88
+ if (logs)
89
+ console.log(`PC = ${int.pc}`);
90
+ if (logs)
91
+ console.log(`GAS = ${int.gas.get()}`);
92
+ if (logs)
93
+ console.log(`STATUS = ${int.status}`);
94
+ if (logs)
95
+ console.log(`REGISTERS = [${int.registers.map((x) => `${x} (0x${x.toString(16)})`).join(", ")}]`);
96
+ if (logs && int.pc < u32(int.program.code.length)) {
97
+ const instruction = int.program.code[int.pc];
98
+ const iData = instruction >= INSTRUCTIONS.length ? MISSING_INSTRUCTION : INSTRUCTIONS[instruction];
99
+ const skipBytes = int.program.mask.skipBytesToNextInstruction(int.pc);
100
+ const args = resolveArguments(argsRes, iData.kind, int.program.code, int.pc + 1, skipBytes, int.registers);
101
+ if (args !== null) {
102
+ console.log(`ARGUMENTS:
103
+ ${args.a} (${args.decoded.a}) = 0x${u64(args.a).toString(16)},
104
+ ${args.b} (${args.decoded.b}) = 0x${u64(args.b).toString(16)},
105
+ ${args.c} (${args.decoded.c}) = 0x${u64(args.c).toString(16)},
106
+ ${args.d} (${args.decoded.d}) = 0x${u64(args.d).toString(16)}`);
107
+ }
108
+ }
109
+ isOk = int.nextSteps();
110
+ }
111
+ }
112
+ /** Destroy a running VM and consume the output. */
113
+ export function vmDestroy(int, dumpMemory = false) {
114
+ const output = new VmOutput();
115
+ output.status = int.status;
116
+ output.registers = int.registers.slice(0);
117
+ output.pc = int.pc;
118
+ output.gas = int.gas.get();
119
+ if (dumpMemory) {
120
+ output.memory = getOutputChunks(int.memory);
121
+ }
122
+ output.exitCode = int.exitCode;
123
+ output.result = readResult(int);
124
+ int.memory.free();
125
+ return output;
126
+ }
127
+ function readResult(int) {
128
+ if (int.status !== Status.HALT) {
129
+ return [];
130
+ }
131
+ // JAM return convention
132
+ const ptr_start = u32(int.registers[7] & u64(4294967295));
133
+ const ptr_end = u32(int.registers[8] & u64(4294967295));
134
+ // invalid output result
135
+ if (ptr_start >= ptr_end) {
136
+ return [];
137
+ }
138
+ // attempt to read the output memory (up to 1MB)
139
+ const totalLength = ptr_end - ptr_start;
140
+ if (totalLength > 1024 * 1024) {
141
+ return [];
142
+ }
143
+ const result = new Uint8Array(totalLength);
144
+ const faultRes = new MaybePageFault();
145
+ int.memory.bytesRead(faultRes, ptr_start, result, 0);
146
+ // we couldn't access the mem - i.e. no output
147
+ if (faultRes.isFault) {
148
+ return [];
149
+ }
150
+ // copy the Uint8Array to a regular array
151
+ const out = new Array(totalLength);
152
+ for (let i = 0; i < totalLength; i++) {
153
+ out[i] = result[i];
154
+ }
155
+ return out;
156
+ }
157
+ function getOutputChunks(memory) {
158
+ const chunks = [];
159
+ // @ts-ignore: AS returns T[], JS returns iterator - asArray handles both
160
+ const pages = portable.asArray(memory.pages.keys());
161
+ let currentChunk = null;
162
+ for (let i = 0; i < pages.length; i++) {
163
+ const pageIdx = pages[i];
164
+ const page = memory.pages.get(pageIdx);
165
+ // skip empty pages
166
+ if (page.raw.page === null) {
167
+ continue;
168
+ }
169
+ for (let n = 0; n < page.raw.data.length; n++) {
170
+ const v = page.raw.data[n];
171
+ if (v !== 0) {
172
+ if (currentChunk !== null) {
173
+ currentChunk.data.push(v);
174
+ }
175
+ else {
176
+ currentChunk = new InitialChunk();
177
+ currentChunk.address = pageIdx * PAGE_SIZE + n;
178
+ currentChunk.data = [v];
179
+ }
180
+ }
181
+ else if (currentChunk !== null) {
182
+ chunks.push(currentChunk);
183
+ currentChunk = null;
184
+ }
185
+ }
186
+ }
187
+ if (currentChunk !== null) {
188
+ chunks.push(currentChunk);
189
+ }
190
+ return chunks;
191
+ }
@@ -0,0 +1,45 @@
1
+ /** We split out type definitions, because they can't be exported from WASM. */
2
+ import { Gas } from "./gas";
3
+ import { Status } from "./interpreter";
4
+ import { Memory } from "./memory";
5
+ import { Access } from "./memory-page";
6
+ import { Program } from "./program";
7
+ import { Registers } from "./registers";
8
+ export declare class InitialPage {
9
+ address: u32;
10
+ length: u32;
11
+ access: Access;
12
+ }
13
+ export declare class InitialChunk {
14
+ address: u32;
15
+ data: u8[];
16
+ }
17
+ export declare class VmRunOptions {
18
+ logs: boolean;
19
+ dumpMemory: boolean;
20
+ }
21
+ export declare class VmInput {
22
+ readonly program: Program;
23
+ readonly memory: Memory;
24
+ readonly registers: Registers;
25
+ pc: u32;
26
+ gas: Gas;
27
+ constructor(program: Program, memory: Memory, registers: Registers);
28
+ }
29
+ export declare class VmPause {
30
+ status: Status;
31
+ exitCode: u32;
32
+ pc: u32;
33
+ nextPc: u32;
34
+ gas: Gas;
35
+ registers: u64[];
36
+ }
37
+ export declare class VmOutput {
38
+ status: Status;
39
+ exitCode: u32;
40
+ pc: u32;
41
+ gas: Gas;
42
+ result: u8[];
43
+ registers: u64[];
44
+ memory: InitialChunk[];
45
+ }
@@ -0,0 +1,52 @@
1
+ /** We split out type definitions, because they can't be exported from WASM. */
2
+ import { Status } from "./interpreter";
3
+ import { Access } from "./memory-page";
4
+ export class InitialPage {
5
+ constructor() {
6
+ this.address = 0;
7
+ this.length = 0;
8
+ this.access = Access.None;
9
+ }
10
+ }
11
+ export class InitialChunk {
12
+ constructor() {
13
+ this.address = 0;
14
+ this.data = [];
15
+ }
16
+ }
17
+ export class VmRunOptions {
18
+ constructor() {
19
+ this.logs = false;
20
+ this.dumpMemory = false;
21
+ }
22
+ }
23
+ export class VmInput {
24
+ constructor(program, memory, registers) {
25
+ this.program = program;
26
+ this.memory = memory;
27
+ this.registers = registers;
28
+ this.pc = 0;
29
+ this.gas = u64(0);
30
+ }
31
+ }
32
+ export class VmPause {
33
+ constructor() {
34
+ this.status = Status.OK;
35
+ this.exitCode = 0;
36
+ this.pc = 0;
37
+ this.nextPc = 0;
38
+ this.gas = u64(0);
39
+ this.registers = [];
40
+ }
41
+ }
42
+ export class VmOutput {
43
+ constructor() {
44
+ this.status = Status.OK;
45
+ this.exitCode = 0;
46
+ this.pc = 0;
47
+ this.gas = u64(0);
48
+ this.result = [];
49
+ this.registers = [];
50
+ this.memory = [];
51
+ }
52
+ }
@@ -0,0 +1,79 @@
1
+ import { InitialChunk, InitialPage, VmOutput, VmPause } from "./api-types";
2
+ import { Gas } from "./gas";
3
+ import { ProgramCounter } from "./program";
4
+ import { StandardProgram } from "./spi";
5
+ export declare enum InputKind {
6
+ Generic = 0,
7
+ SPI = 1
8
+ }
9
+ export declare enum HasMetadata {
10
+ Yes = 0,
11
+ No = 1
12
+ }
13
+ declare class BlockGasCost {
14
+ pc: ProgramCounter;
15
+ gas: Gas;
16
+ }
17
+ export declare function getBlockGasCosts(input: u8[], kind: InputKind, withMetadata: HasMetadata): BlockGasCost[];
18
+ export declare function disassemble(input: u8[], kind: InputKind, withMetadata: HasMetadata): string;
19
+ export declare function prepareProgram(kind: InputKind, hasMetadata: HasMetadata, program: u8[],
20
+ /** NOTE: ignored in case of SPI. */
21
+ initialRegisters: u64[],
22
+ /** NOTE: ignored in case of SPI. */
23
+ initialPageMap: InitialPage[],
24
+ /** NOTE: ignored in case of SPI. */
25
+ initialMemory: InitialChunk[],
26
+ /** NOTE: ONLY needed for SPI. */
27
+ args: u8[],
28
+ /** Preallocate a bunch of memory pages for faster execution. */
29
+ preallocateMemoryPages: u32,
30
+ /** Compute gas per-block instead of per-instruction. */
31
+ useBlockGas: boolean): StandardProgram;
32
+ /** Execute PVM program and stop. */
33
+ export declare function runProgram(program: StandardProgram, initialGas?: i64, programCounter?: u32, logs?: boolean, dumpMemory?: boolean): VmOutput;
34
+ /**
35
+ * Allocate new PVM instance to execute given program.
36
+ *
37
+ * NOTE: the PVM MUST be de-allocated using `pvmDestroy`.
38
+ */
39
+ export declare function pvmStart(program: StandardProgram): u32;
40
+ /** Deallocate PVM resources. */
41
+ export declare function pvmDestroy(pvmId: u32): VmOutput | null;
42
+ /** Set register values of a paused PVM. */
43
+ export declare function pvmSetRegisters(pvmId: u32, registers: u64[]): void;
44
+ /**
45
+ * Read a continuous chunk of memory from given PVM instance.
46
+ *
47
+ * @deprecated Use `pvmGetPagePointer` instead to read memory directly from WASM linear memory
48
+ * on the JS side with no additional WASM-side allocations.
49
+ */
50
+ export declare function pvmReadMemory(pvmId: u32, address: u32, length: u32): Uint8Array | null;
51
+ /**
52
+ * Returns the WASM linear memory pointer (byte offset) for the backing buffer of the page at `page`
53
+ * in the given PVM instance.
54
+ *
55
+ * Returns `0` if the PVM does not exist, the page does not exist, or the page is not readable.
56
+ *
57
+ * Use this instead of `pvmReadMemory` to read memory efficiently from the JS side:
58
+ * ```ts
59
+ * let pagesRead = 0;
60
+ * for (let address = start; address < end; address += PAGE_SIZE) {
61
+ * const page = address >> PAGE_SIZE_SHIFT;
62
+ * const ptr = pvmGetPagePointer(pvmId, page);
63
+ * if (ptr === 0) {
64
+ * throw new Error(`Page fault at ${page << PAGE_SIZE_SHIFT}`);
65
+ * }
66
+ * destination.set(
67
+ * new Uint8Array(wasm.instance.exports.memory.buffer, ptr, Math.min(end - address, PAGE_SIZE)),
68
+ * pagesRead << PAGE_SIZE_SHIFT,
69
+ * );
70
+ * pagesRead += 1;
71
+ * }
72
+ * ```
73
+ */
74
+ export declare function pvmGetPagePointer(pvmId: u32, page: u32): usize;
75
+ /** Write a chunk of memory to given PVM instance. */
76
+ export declare function pvmWriteMemory(pvmId: u32, address: u32, data: Uint8Array): boolean;
77
+ /** Resume execution of paused VM. */
78
+ export declare function pvmResume(pvmId: u32, gas: Gas, pc: u32, logs?: boolean): VmPause | null;
79
+ export {};