@fluffylabs/anan-as 1.2.0 → 1.3.0-0eb791a

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,482 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Inst } from "./instructions/utils";
8
+ import { IntMath } from "./math";
9
+ import { Access, Arena, PAGE_SIZE, PAGE_SIZE_SHIFT, Page, RawPage, RESERVED_MEMORY, RESERVED_PAGES, } from "./memory-page";
10
+ import { portable } from "./portable";
11
+ // @unmanaged
12
+ export class MaybePageFault {
13
+ constructor() {
14
+ /** Accessing memory triggered a page fault. */
15
+ this.isFault = false;
16
+ /** The page fault was caused by invalid memory access (i.e. writing to read-only memory). */
17
+ this.isAccess = false;
18
+ /** Start memory index of a page that triggered the fault. */
19
+ this.fault = 0;
20
+ }
21
+ }
22
+ const EMPTY_UINT8ARRAY = new Uint8Array(0);
23
+ const EMPTY_PAGE = new Page(Access.None, new RawPage(-1, EMPTY_UINT8ARRAY));
24
+ class Chunks {
25
+ constructor() {
26
+ this.firstPageData = EMPTY_UINT8ARRAY;
27
+ this.firstPageOffset = 0;
28
+ this.secondPageData = EMPTY_UINT8ARRAY;
29
+ this.secondPageEnd = 0;
30
+ }
31
+ }
32
+ class PageResult {
33
+ constructor() {
34
+ this.page = EMPTY_PAGE;
35
+ this.relativeAddress = 0;
36
+ }
37
+ }
38
+ const MEMORY_SIZE = 4294967296;
39
+ const MAX_MEMORY_ADDRESS = 4294967295;
40
+ // Direct-mapped page cache for fast lookups.
41
+ // Cache size must be a power of 2. 256 entries covers most working sets.
42
+ const PAGE_CACHE_SHIFT = 8;
43
+ const PAGE_CACHE_SIZE = 1 << PAGE_CACHE_SHIFT; // 256
44
+ const PAGE_CACHE_MASK = PAGE_CACHE_SIZE - 1;
45
+ class PageCache {
46
+ constructor() {
47
+ // Parallel arrays for cache: tags store the page index, entries store the page.
48
+ // A tag of 0xFFFFFFFF means empty (no valid page).
49
+ this.tags = new StaticArray(PAGE_CACHE_SIZE);
50
+ this.entries = new StaticArray(PAGE_CACHE_SIZE);
51
+ const empty = EMPTY_PAGE;
52
+ for (let i = 0; i < PAGE_CACHE_SIZE; i++) {
53
+ this.tags[i] = 0xffffffff;
54
+ this.entries[i] = empty;
55
+ }
56
+ }
57
+ lookup(pageIdx) {
58
+ const slot = pageIdx & PAGE_CACHE_MASK;
59
+ if (unchecked(this.tags[slot]) === pageIdx) {
60
+ return unchecked(this.entries[slot]);
61
+ }
62
+ return null;
63
+ }
64
+ insert(pageIdx, page) {
65
+ const slot = pageIdx & PAGE_CACHE_MASK;
66
+ // biome-ignore lint/suspicious/noAssignInExpressions: intentional AS pattern
67
+ unchecked((this.tags[slot] = pageIdx));
68
+ // biome-ignore lint/suspicious/noAssignInExpressions: intentional AS pattern
69
+ unchecked((this.entries[slot] = page));
70
+ }
71
+ clear() {
72
+ for (let i = 0; i < PAGE_CACHE_SIZE; i++) {
73
+ this.tags[i] = 0xffffffff;
74
+ this.entries[i] = EMPTY_PAGE;
75
+ }
76
+ }
77
+ }
78
+ __decorate([
79
+ inline
80
+ ], PageCache.prototype, "lookup", null);
81
+ __decorate([
82
+ inline
83
+ ], PageCache.prototype, "insert", null);
84
+ export class MemoryBuilder {
85
+ constructor(preAllocatePages = 0) {
86
+ this.pages = new Map();
87
+ this.arena = new Arena(preAllocatePages);
88
+ }
89
+ /** Allocates memory pages with given `access`, for given `address` and initialize with `zeroes` */
90
+ setEmpty(access, address, len) {
91
+ const endAddress = address + len;
92
+ for (let currentAddress = address; currentAddress < endAddress; currentAddress += PAGE_SIZE) {
93
+ this.getOrCreatePageForAddress(access, currentAddress);
94
+ }
95
+ return this;
96
+ }
97
+ /** Allocates memory pages with given `access`, for given `address` and writes there `data` */
98
+ setData(access, address, data) {
99
+ let currentAddress = address;
100
+ let currentData = data;
101
+ while (currentData.length > 0) {
102
+ const page = this.getOrCreatePageForAddress(access, currentAddress);
103
+ const relAddress = currentAddress % PAGE_SIZE;
104
+ const spaceInPage = PAGE_SIZE - relAddress;
105
+ const end = u32(currentData.length) < spaceInPage ? currentData.length : spaceInPage;
106
+ page.raw.data.set(currentData.subarray(0, end), relAddress);
107
+ // move to the next address to write
108
+ currentAddress = currentAddress + end;
109
+ currentData = currentData.subarray(end);
110
+ }
111
+ return this;
112
+ }
113
+ /** Returns memory page for given address (creates if not exists) */
114
+ getOrCreatePageForAddress(access, address) {
115
+ const pageIdx = u32(address >> PAGE_SIZE_SHIFT);
116
+ if (pageIdx < RESERVED_PAGES) {
117
+ throw new Error(`Attempting to allocate reserved page: ${pageIdx}`);
118
+ }
119
+ if (!this.pages.has(pageIdx)) {
120
+ const page = this.arena.acquire();
121
+ this.pages.set(pageIdx, new Page(access, page));
122
+ }
123
+ return this.pages.get(pageIdx);
124
+ }
125
+ build(sbrkAddress = RESERVED_MEMORY, maxHeapPointer = MAX_MEMORY_ADDRESS) {
126
+ return new Memory(this.arena, this.pages, sbrkAddress, maxHeapPointer);
127
+ }
128
+ }
129
+ export class Memory {
130
+ constructor(arena, pages = new Map(), sbrkAddress = 0, maxHeapPointer = MAX_MEMORY_ADDRESS) {
131
+ this.arena = arena;
132
+ this.pages = pages;
133
+ this.sbrkAddress = sbrkAddress;
134
+ this.pageResult = new PageResult();
135
+ this.chunksResult = new Chunks();
136
+ this.cache = new PageCache();
137
+ const sbrkPage = u32(sbrkAddress >> PAGE_SIZE_SHIFT);
138
+ if (sbrkPage < RESERVED_PAGES) {
139
+ throw new Error("sbrk within reserved memory is not allowed!");
140
+ }
141
+ this.lastAllocatedPage = pages.has(sbrkPage) ? sbrkPage : sbrkPage - 1;
142
+ this.maxHeapPointer = u64(maxHeapPointer);
143
+ // Pre-populate cache with all existing pages
144
+ // @ts-ignore: AS Map iterator has array-like behavior
145
+ const keys = pages.keys();
146
+ // @ts-ignore: AS Map iterator has array-like behavior
147
+ for (let i = 0; i < keys.length; i++) {
148
+ // @ts-ignore: AS Map iterator has array-like behavior
149
+ const key = keys[i];
150
+ this.cache.insert(key, pages.get(key));
151
+ }
152
+ }
153
+ pageDump(index) {
154
+ const cached = this.cache.lookup(index);
155
+ if (cached !== null) {
156
+ return cached.raw.data;
157
+ }
158
+ if (!this.pages.has(index)) {
159
+ return null;
160
+ }
161
+ const page = this.pages.get(index);
162
+ this.cache.insert(index, page);
163
+ return page.raw.data;
164
+ }
165
+ /**
166
+ * Returns the WASM linear memory pointer (byte offset) for the backing buffer of the page at `pageIndex`.
167
+ *
168
+ * Returns `0` if the page does not exist or is not readable (page/access fault).
169
+ *
170
+ * This enables efficient memory reading on the JS side without extra WASM allocations:
171
+ * ```ts
172
+ * let pagesRead = 0;
173
+ * for (let address = start; address < end; address += PAGE_SIZE) {
174
+ * const page = address >> PAGE_SIZE_SHIFT;
175
+ * const ptr = getPagePointer(page);
176
+ * if (ptr === 0) {
177
+ * throw new Error(`Page fault at ${page << PAGE_SIZE_SHIFT}`);
178
+ * }
179
+ * destination.set(
180
+ * new Uint8Array(wasm.instance.exports.memory.buffer, ptr, Math.min(end - address, PAGE_SIZE)),
181
+ * pagesRead << PAGE_SIZE_SHIFT,
182
+ * );
183
+ * pagesRead += 1;
184
+ * }
185
+ * ```
186
+ */
187
+ getPagePointer(pageIndex) {
188
+ let page = this.cache.lookup(pageIndex);
189
+ if (page === null) {
190
+ if (!this.pages.has(pageIndex)) {
191
+ return 0;
192
+ }
193
+ page = this.pages.get(pageIndex);
194
+ this.cache.insert(pageIndex, page);
195
+ }
196
+ if (!page.can(Access.Read)) {
197
+ return 0;
198
+ }
199
+ // Trigger lazy allocation if the backing buffer has not been created yet.
200
+ // @ts-ignore: dataStart is an AS-specific property on Uint8Array
201
+ return page.raw.data.dataStart;
202
+ }
203
+ free() {
204
+ // @ts-ignore: AS returns T[], JS returns iterator - asArray handles both
205
+ const pages = portable.asArray(this.pages.values());
206
+ for (let i = 0; i < pages.length; i++) {
207
+ this.arena.release(pages[i].raw);
208
+ }
209
+ this.pages.clear();
210
+ this.cache.clear();
211
+ }
212
+ sbrk(faultRes, amount) {
213
+ const freeMemoryStart = u64(this.sbrkAddress);
214
+ if (amount === 0) {
215
+ faultRes.isFault = false;
216
+ return freeMemoryStart;
217
+ }
218
+ const newSbrk = portable.u64_add(freeMemoryStart, u64(amount));
219
+ if (newSbrk > this.maxHeapPointer) {
220
+ faultRes.isFault = true;
221
+ return freeMemoryStart;
222
+ }
223
+ this.sbrkAddress = u32(newSbrk);
224
+ const pageIdx = i32(portable.u64_sub(newSbrk, u64(1)) >> u64(PAGE_SIZE_SHIFT));
225
+ if (pageIdx === this.lastAllocatedPage) {
226
+ faultRes.isFault = false;
227
+ return freeMemoryStart;
228
+ }
229
+ for (let i = this.lastAllocatedPage + 1; i <= pageIdx; i++) {
230
+ const rawPage = this.arena.acquire();
231
+ const page = new Page(Access.Write, rawPage);
232
+ this.pages.set(i, page);
233
+ this.cache.insert(i, page);
234
+ }
235
+ this.lastAllocatedPage = pageIdx;
236
+ faultRes.isFault = false;
237
+ return freeMemoryStart;
238
+ }
239
+ getU8(faultRes, address) {
240
+ return u64(u8(this.getBytesReversed(faultRes, Access.Read, address, 1)));
241
+ }
242
+ getU16(faultRes, address) {
243
+ return u64(portable.bswap_u16(u16(this.getBytesReversed(faultRes, Access.Read, address, 2))));
244
+ }
245
+ getU32(faultRes, address) {
246
+ return u64(portable.bswap_u32(u32(this.getBytesReversed(faultRes, Access.Read, address, 4))));
247
+ }
248
+ getU64(faultRes, address) {
249
+ return portable.bswap_u64(this.getBytesReversed(faultRes, Access.Read, address, 8));
250
+ }
251
+ getI8(faultRes, address) {
252
+ return Inst.u8SignExtend(u8(this.getU8(faultRes, address)));
253
+ }
254
+ getI16(faultRes, address) {
255
+ return Inst.u16SignExtend(u16(this.getU16(faultRes, address)));
256
+ }
257
+ getI32(faultRes, address) {
258
+ return Inst.u32SignExtend(u32(this.getU32(faultRes, address)));
259
+ }
260
+ setU8(faultRes, address, value) {
261
+ this.setBytes(faultRes, address, value, 1);
262
+ }
263
+ setU16(faultRes, address, value) {
264
+ this.setBytes(faultRes, address, value, 2);
265
+ }
266
+ setU32(faultRes, address, value) {
267
+ this.setBytes(faultRes, address, value, 4);
268
+ }
269
+ setU64(faultRes, address, value) {
270
+ this.setBytes(faultRes, address, value, 8);
271
+ }
272
+ /**
273
+ * DO NOT USE.
274
+ *
275
+ * @deprecated exposed temporarily for debugger/typeberry API.
276
+ */
277
+ getMemory(fault, address, length) {
278
+ // first traverse memory and see if we don't page fault
279
+ if (length > 0) {
280
+ let nextAddress = address;
281
+ const pagesToCheck = i32(portable.u64_add(u64(length), u64(PAGE_SIZE - 1)) >> u64(PAGE_SIZE_SHIFT));
282
+ for (let page = 0; page < pagesToCheck; page++) {
283
+ const pageData = this.pageResult;
284
+ this.getPage(fault, pageData, Access.Read, nextAddress);
285
+ if (fault.isFault) {
286
+ return null;
287
+ }
288
+ nextAddress += PAGE_SIZE;
289
+ }
290
+ }
291
+ // only after, actually allocate and read the bytes.
292
+ const destination = new Uint8Array(length);
293
+ this.bytesRead(fault, address, destination, 0);
294
+ if (fault.isFault) {
295
+ return null;
296
+ }
297
+ return destination;
298
+ }
299
+ bytesRead(faultRes, address, destination, destinationOffset) {
300
+ let nextAddress = address;
301
+ let destinationIndex = i32(destinationOffset);
302
+ while (destinationIndex < destination.length) {
303
+ const bytesLeft = destination.length - destinationIndex;
304
+ const pageData = this.pageResult;
305
+ this.getPage(faultRes, pageData, Access.Read, nextAddress);
306
+ if (faultRes.isFault) {
307
+ return;
308
+ }
309
+ const relAddress = pageData.relativeAddress;
310
+ const bytesToRead = relAddress + bytesLeft < PAGE_SIZE ? bytesLeft : PAGE_SIZE - pageData.relativeAddress;
311
+ // actually copy the bytes
312
+ const pageEnd = relAddress + bytesToRead;
313
+ const data = pageData.page.raw.data;
314
+ for (let i = relAddress; i < pageEnd; i++) {
315
+ destination[destinationIndex] = data[i];
316
+ destinationIndex++;
317
+ }
318
+ // move the pointers
319
+ nextAddress += bytesToRead;
320
+ }
321
+ return;
322
+ }
323
+ /** Write bytes from given `source` (with `sourceOffset`) at given `address`. */
324
+ bytesWrite(faultRes, address, source, sourceOffset) {
325
+ let nextAddress = address;
326
+ let sourceIndex = i32(sourceOffset);
327
+ while (sourceIndex < source.length) {
328
+ const bytesLeft = source.length - sourceIndex;
329
+ const pageData = this.pageResult;
330
+ this.getPage(faultRes, pageData, Access.Write, nextAddress);
331
+ if (faultRes.isFault) {
332
+ return;
333
+ }
334
+ const relAddress = pageData.relativeAddress;
335
+ const bytesToWrite = relAddress + bytesLeft < PAGE_SIZE ? bytesLeft : PAGE_SIZE - pageData.relativeAddress;
336
+ // actually copy the bytes
337
+ const pageEnd = relAddress + bytesToWrite;
338
+ const data = pageData.page.raw.data;
339
+ for (let i = relAddress; i < pageEnd; i++) {
340
+ data[i] = source[sourceIndex];
341
+ sourceIndex++;
342
+ }
343
+ // move the pointers
344
+ nextAddress += bytesToWrite;
345
+ }
346
+ return;
347
+ }
348
+ getPage(faultRes, pageData, access, address) {
349
+ const pageIdx = u32(address >> PAGE_SIZE_SHIFT);
350
+ const relAddress = address & (PAGE_SIZE - 1);
351
+ // Fast path: check cache first
352
+ const cached = this.cache.lookup(pageIdx);
353
+ if (cached !== null) {
354
+ if (!cached.can(access)) {
355
+ fault(faultRes, pageIdx << PAGE_SIZE_SHIFT);
356
+ faultRes.isAccess = true;
357
+ pageData.page = EMPTY_PAGE;
358
+ pageData.relativeAddress = relAddress;
359
+ return;
360
+ }
361
+ faultRes.isFault = false;
362
+ pageData.page = cached;
363
+ pageData.relativeAddress = relAddress;
364
+ return;
365
+ }
366
+ // Slow path: check Map
367
+ if (!this.pages.has(pageIdx)) {
368
+ fault(faultRes, pageIdx << PAGE_SIZE_SHIFT);
369
+ pageData.page = EMPTY_PAGE;
370
+ pageData.relativeAddress = relAddress;
371
+ return;
372
+ }
373
+ const page = this.pages.get(pageIdx);
374
+ // Insert into cache for next time
375
+ this.cache.insert(pageIdx, page);
376
+ if (!page.can(access)) {
377
+ fault(faultRes, pageIdx << PAGE_SIZE_SHIFT);
378
+ faultRes.isAccess = true;
379
+ pageData.page = EMPTY_PAGE;
380
+ pageData.relativeAddress = relAddress;
381
+ return;
382
+ }
383
+ faultRes.isFault = false;
384
+ pageData.page = page;
385
+ pageData.relativeAddress = relAddress;
386
+ return;
387
+ }
388
+ getChunks(faultRes, chunks, access, address, bytes) {
389
+ /**
390
+ * Accessing empty set of bytes is always valid.
391
+ * https://graypaper.fluffylabs.dev/#/68eaa1f/24a80024a800?v=0.6.4
392
+ */
393
+ if (bytes === 0) {
394
+ faultRes.isFault = false;
395
+ chunks.firstPageData = EMPTY_UINT8ARRAY;
396
+ chunks.firstPageOffset = 0;
397
+ chunks.secondPageData = EMPTY_UINT8ARRAY;
398
+ chunks.secondPageEnd = 0;
399
+ return;
400
+ }
401
+ const pageData = this.pageResult;
402
+ this.getPage(faultRes, pageData, access, address);
403
+ if (faultRes.isFault) {
404
+ return;
405
+ }
406
+ const page = pageData.page;
407
+ const relativeAddress = pageData.relativeAddress;
408
+ const endAddress = relativeAddress + u32(bytes);
409
+ const needSecondPage = endAddress > PAGE_SIZE;
410
+ // everything is on one page - easy case
411
+ if (!needSecondPage) {
412
+ chunks.firstPageData = page.raw.data;
413
+ chunks.firstPageOffset = relativeAddress;
414
+ return;
415
+ }
416
+ const secondPageIdx = u32((address + u32(bytes)) % MEMORY_SIZE) >> PAGE_SIZE_SHIFT;
417
+ const secondPageStart = secondPageIdx << PAGE_SIZE_SHIFT;
418
+ // Try cache first for second page
419
+ let secondPage = this.cache.lookup(secondPageIdx);
420
+ if (secondPage === null) {
421
+ if (!this.pages.has(secondPageIdx)) {
422
+ fault(faultRes, secondPageStart);
423
+ return;
424
+ }
425
+ secondPage = this.pages.get(secondPageIdx);
426
+ this.cache.insert(secondPageIdx, secondPage);
427
+ }
428
+ if (!secondPage.can(access)) {
429
+ fault(faultRes, secondPageStart);
430
+ faultRes.isAccess = true;
431
+ return;
432
+ }
433
+ chunks.firstPageData = page.raw.data;
434
+ chunks.firstPageOffset = relativeAddress;
435
+ chunks.secondPageData = secondPage.raw.data;
436
+ chunks.secondPageEnd = relativeAddress + u32(bytes) - PAGE_SIZE;
437
+ return;
438
+ }
439
+ /** Write some bytes to at most 2 pages. */
440
+ setBytes(faultRes, address, value, bytes) {
441
+ const r = this.chunksResult;
442
+ this.getChunks(faultRes, r, Access.Write, address, bytes);
443
+ if (faultRes.isFault) {
444
+ return;
445
+ }
446
+ let bytesLeft = u64(value);
447
+ // write to first page
448
+ const firstPageEnd = IntMath.minU32(PAGE_SIZE, r.firstPageOffset + bytes);
449
+ for (let i = r.firstPageOffset; i < firstPageEnd; i++) {
450
+ r.firstPageData[i] = u8(bytesLeft);
451
+ bytesLeft >>= u64(8);
452
+ }
453
+ // write rest to the second page
454
+ for (let i = 0; i < r.secondPageEnd; i++) {
455
+ r.secondPageData[i] = u8(bytesLeft);
456
+ bytesLeft >>= u64(8);
457
+ }
458
+ }
459
+ getBytesReversed(faultRes, access, address, bytes) {
460
+ this.getChunks(faultRes, this.chunksResult, access, address, bytes);
461
+ if (faultRes.isFault) {
462
+ return u64(0);
463
+ }
464
+ // result (bytes in reverse order)
465
+ let r = u64(0);
466
+ const firstPageEnd = IntMath.minU32(PAGE_SIZE, this.chunksResult.firstPageOffset + bytes);
467
+ // read from first page
468
+ for (let i = this.chunksResult.firstPageOffset; i < firstPageEnd; i++) {
469
+ r = (r << u64(8)) | u64(this.chunksResult.firstPageData[i]);
470
+ }
471
+ // read from the second page
472
+ for (let i = 0; i < this.chunksResult.secondPageEnd; i++) {
473
+ r = (r << u64(8)) | u64(this.chunksResult.secondPageData[i]);
474
+ }
475
+ return r;
476
+ }
477
+ }
478
+ function fault(r, address) {
479
+ r.isFault = true;
480
+ r.isAccess = false;
481
+ r.fault = address;
482
+ }
@@ -0,0 +1,24 @@
1
+ export declare class portable {
2
+ static installPolyfills(): void;
3
+ static asArray<T>(v: T[]): T[];
4
+ static arrayAt<T>(v: T[], i: u32): T;
5
+ static staticArrayAt<T>(v: StaticArray<T>, i: u32): T;
6
+ static asU32(v: u32): u32;
7
+ static uint8ArrayView(data: ArrayBuffer, offset: i32, length: i32): Uint8Array;
8
+ static bswap_u16(v: u16): u16;
9
+ static bswap_u32(v: u32): u32;
10
+ static bswap_u64(v: u64): u64;
11
+ static popcnt_u32(v: u32): u32;
12
+ static popcnt_u64(v: u64): u64;
13
+ static clz_u32(v: u32): u32;
14
+ static clz_u64(v: u64): u64;
15
+ static ctz_u32(v: u32): u32;
16
+ static ctz_u64(v: u64): u64;
17
+ static rotr_u32(v: u32, shift: u32): u32;
18
+ static rotr_u64(v: u64, shift: u64): u64;
19
+ static rotl_u32(v: u32, shift: u32): u32;
20
+ static rotl_u64(v: u64, shift: u64): u64;
21
+ static u64_add(a: u64, b: u64): u64;
22
+ static u64_sub(a: u64, b: u64): u64;
23
+ static u64_mul(a: u64, b: u64): u64;
24
+ }