warpo 3.2.0 → 3.2.2

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 (93) hide show
  1. package/assemblyscript/std/README.md +5 -0
  2. package/assemblyscript/std/assembly/array.ts +542 -0
  3. package/assemblyscript/std/assembly/arraybuffer.ts +72 -0
  4. package/assemblyscript/std/assembly/builtins.ts +2312 -0
  5. package/assemblyscript/std/assembly/compat.ts +2 -0
  6. package/assemblyscript/std/assembly/dataview.ts +144 -0
  7. package/assemblyscript/std/assembly/date.ts +383 -0
  8. package/assemblyscript/std/assembly/diagnostics.ts +11 -0
  9. package/assemblyscript/std/assembly/error.ts +39 -0
  10. package/assemblyscript/std/assembly/function.ts +44 -0
  11. package/assemblyscript/std/assembly/iterator.ts +24 -0
  12. package/assemblyscript/std/assembly/map.ts +304 -0
  13. package/assemblyscript/std/assembly/math.ts +3401 -0
  14. package/assemblyscript/std/assembly/memory.ts +110 -0
  15. package/assemblyscript/std/assembly/number.ts +388 -0
  16. package/assemblyscript/std/assembly/object.ts +30 -0
  17. package/assemblyscript/std/assembly/polyfills.ts +24 -0
  18. package/assemblyscript/std/assembly/process.ts +7 -0
  19. package/assemblyscript/std/assembly/promise.ts +172 -0
  20. package/assemblyscript/std/assembly/reference.ts +48 -0
  21. package/assemblyscript/std/assembly/regexp.ts +16 -0
  22. package/assemblyscript/std/assembly/rt/common.ts +79 -0
  23. package/assemblyscript/std/assembly/rt/index-incremental.ts +4 -0
  24. package/assemblyscript/std/assembly/rt/index-radical.ts +4 -0
  25. package/assemblyscript/std/assembly/rt/index.d.ts +37 -0
  26. package/assemblyscript/std/assembly/rt/itcms.ts +415 -0
  27. package/assemblyscript/std/assembly/rt/tcms.ts +276 -0
  28. package/assemblyscript/std/assembly/rt/tlsf.ts +564 -0
  29. package/assemblyscript/std/assembly/rt.ts +71 -0
  30. package/assemblyscript/std/assembly/set.ts +261 -0
  31. package/assemblyscript/std/assembly/shared/feature.ts +69 -0
  32. package/assemblyscript/std/assembly/shared/host.ts +12 -0
  33. package/assemblyscript/std/assembly/shared/runtime.ts +9 -0
  34. package/assemblyscript/std/assembly/shared/target.ts +9 -0
  35. package/assemblyscript/std/assembly/shared/tsconfig.json +9 -0
  36. package/assemblyscript/std/assembly/shared/typeinfo.ts +72 -0
  37. package/assemblyscript/std/assembly/staticarray.ts +446 -0
  38. package/assemblyscript/std/assembly/string.ts +892 -0
  39. package/assemblyscript/std/assembly/symbol.ts +61 -0
  40. package/assemblyscript/std/assembly/table.ts +15 -0
  41. package/assemblyscript/std/assembly/tsconfig.json +4 -0
  42. package/assemblyscript/std/assembly/tuple.ts +36 -0
  43. package/assemblyscript/std/assembly/typedarray.ts +2000 -0
  44. package/assemblyscript/std/assembly/uri.ts +17 -0
  45. package/assemblyscript/std/assembly/util/bytes.ts +90 -0
  46. package/assemblyscript/std/assembly/util/casemap.ts +264 -0
  47. package/assemblyscript/std/assembly/util/error.ts +54 -0
  48. package/assemblyscript/std/assembly/util/hash.ts +117 -0
  49. package/assemblyscript/std/assembly/util/math.ts +1922 -0
  50. package/assemblyscript/std/assembly/util/memory.ts +309 -0
  51. package/assemblyscript/std/assembly/util/number.ts +884 -0
  52. package/assemblyscript/std/assembly/util/sort.ts +282 -0
  53. package/assemblyscript/std/assembly/util/string.ts +1075 -0
  54. package/assemblyscript/std/assembly/util/uri.ts +251 -0
  55. package/assemblyscript/std/assembly/vector.ts +3 -0
  56. package/dist/debug_server/debugSession.d.ts +1 -0
  57. package/dist/debug_server/debugSession.js +15 -6
  58. package/dist/debug_server/debugSession.js.map +1 -1
  59. package/dist/debug_server/debuggerWasmModule.d.ts +3 -0
  60. package/dist/debug_server/debuggerWasmModule.js +47 -2
  61. package/dist/debug_server/debuggerWasmModule.js.map +1 -1
  62. package/dist/debug_server/tests/debugSession.test.js +96 -0
  63. package/dist/debug_server/tests/debugSession.test.js.map +1 -1
  64. package/dist/debug_server/tests/testModule/debugger_closure_stepping.d.ts +1 -0
  65. package/dist/debug_server/tests/testModule/debugger_closure_stepping.js +12 -0
  66. package/dist/debug_server/tests/testModule/debugger_closure_stepping.js.map +1 -0
  67. package/dist/debug_server/tests/testModule/debugger_std_array.d.ts +1 -0
  68. package/dist/debug_server/tests/testModule/debugger_std_array.js +6 -0
  69. package/dist/debug_server/tests/testModule/debugger_std_array.js.map +1 -0
  70. package/dist/debug_server/tests/testModule/debugger_string_stepping.d.ts +1 -0
  71. package/dist/debug_server/tests/testModule/debugger_string_stepping.js +9 -0
  72. package/dist/debug_server/tests/testModule/debugger_string_stepping.js.map +1 -0
  73. package/package.json +7 -7
  74. package/warpo_extension/std/tsconfig.json +4 -0
  75. package/warpo_extension/std/warpo/ffi.ts +16 -0
  76. package/warpo_extension/std/warpo/test/comparison.ts +122 -0
  77. package/warpo_extension/std/warpo/test/env.ts +33 -0
  78. package/warpo_extension/std/warpo/test/expect.ts +101 -0
  79. package/warpo_extension/std/warpo/test/formatPrint.ts +99 -0
  80. package/warpo_extension/std/warpo/test/implement.ts +41 -0
  81. package/warpo_extension/std/warpo/test/index.d.ts +0 -0
  82. package/warpo_extension/std/warpo/test/index.ts +39 -0
  83. package/warpo_extension/std/warpo/test/mockInstrument.ts +26 -0
  84. package/warpo_extension/std/warpo/utf8/const_str.ts +17 -0
  85. package/warpo_extension/std/wasi_snapshot_preview1/LICENSE +202 -0
  86. package/warpo_extension/std/wasi_snapshot_preview1/README.md +1 -0
  87. package/warpo_extension/std/wasi_snapshot_preview1/bindings/wasi_snapshot_preview1.ts +1731 -0
  88. package/warpo_extension/std/wasi_snapshot_preview1/wasi_console.ts +96 -0
  89. package/warpo_extension/std/wasi_snapshot_preview1/wasi_crypto.ts +8 -0
  90. package/warpo_extension/std/wasi_snapshot_preview1/wasi_date.ts +13 -0
  91. package/warpo_extension/std/wasi_snapshot_preview1/wasi_internal.ts +119 -0
  92. package/warpo_extension/std/wasi_snapshot_preview1/wasi_performance.ts +11 -0
  93. package/warpo_extension/std/wasi_snapshot_preview1/wasi_process.ts +191 -0
@@ -0,0 +1,564 @@
1
+ import { AL_BITS, AL_SIZE, AL_MASK, DEBUG, BLOCK, BLOCK_OVERHEAD, BLOCK_MAXSIZE } from "./common";
2
+ import { E_ALLOCATION_TOO_LARGE } from "../util/error";
3
+
4
+ // === The TLSF (Two-Level Segregate Fit) memory allocator ===
5
+ // see: http://www.gii.upv.es/tlsf/
6
+
7
+ // - `ffs(x)` is equivalent to `ctz(x)` with x != 0
8
+ // - `fls(x)` is equivalent to `sizeof(x) * 8 - clz(x) - 1`
9
+
10
+ // ╒══════════════ Block size interpretation (32-bit) ═════════════╕
11
+ // 3 2 1
12
+ // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 bits
13
+ // ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┼─┴─┴─┴─╫─┴─┴─┴─┤
14
+ // │ | FL │ SB = SL + AL │ ◄─ usize
15
+ // └───────────────────────────────────────────────┴───────╨───────┘
16
+ // FL: first level, SL: second level, AL: alignment, SB: small block
17
+
18
+ // @ts-ignore: decorator
19
+ @inline const SL_BITS: u32 = 4;
20
+ // @ts-ignore: decorator
21
+ @inline const SL_SIZE: u32 = 1 << SL_BITS;
22
+
23
+ // @ts-ignore: decorator
24
+ @inline const SB_BITS: u32 = SL_BITS + AL_BITS;
25
+ // @ts-ignore: decorator
26
+ @inline const SB_SIZE: u32 = 1 << SB_BITS;
27
+
28
+ // @ts-ignore: decorator
29
+ @inline const FL_BITS: u32 = 31 - SB_BITS;
30
+
31
+ // [00]: < 256B (SB) [12]: < 1M
32
+ // [01]: < 512B [13]: < 2M
33
+ // [02]: < 1K [14]: < 4M
34
+ // [03]: < 2K [15]: < 8M
35
+ // [04]: < 4K [16]: < 16M
36
+ // [05]: < 8K [17]: < 32M
37
+ // [06]: < 16K [18]: < 64M
38
+ // [07]: < 32K [19]: < 128M
39
+ // [08]: < 64K [20]: < 256M
40
+ // [09]: < 128K [21]: < 512M
41
+ // [10]: < 256K [22]: <= 1G - OVERHEAD
42
+ // [11]: < 512K
43
+ // VMs limit to 2GB total (currently), making one 1G block max (or three 512M etc.) due to block overhead
44
+
45
+ // Tags stored in otherwise unused alignment bits
46
+
47
+ // @ts-ignore: decorator
48
+ @inline const FREE: usize = 1 << 0;
49
+ // @ts-ignore: decorator
50
+ @inline const LEFTFREE: usize = 1 << 1;
51
+ // @ts-ignore: decorator
52
+ @inline const TAGS_MASK: usize = FREE | LEFTFREE; // <= AL_MASK
53
+
54
+ // ╒════════════════════ Block layout (32-bit) ════════════════════╕
55
+ // 3 2 1
56
+ // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 bits
57
+ // ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┼─┼─┤ ┐
58
+ // │ size │L│F│ ◄─┐ info overhead
59
+ // ╞>ptr═══════════════════════════════════════════════════════╧═╧═╡ │ ┘
60
+ // │ if free: ◄ prev │ ◄─┤ usize
61
+ // ├───────────────────────────────────────────────────────────────┤ │
62
+ // │ if free: next ► │ ◄─┤
63
+ // ├───────────────────────────────────────────────────────────────┤ │
64
+ // │ ... │ │ >= 0
65
+ // ├───────────────────────────────────────────────────────────────┤ │
66
+ // │ if free: back ▲ │ ◄─┘
67
+ // └───────────────────────────────────────────────────────────────┘ >= MIN SIZE
68
+ // F: FREE, L: LEFTFREE
69
+ @unmanaged export class Block extends BLOCK {
70
+ /** @ts-ignore:no initializer. Previous free block, if any. Only valid if free, otherwise part of payload. */
71
+ prev: Block | null;
72
+ /** @ts-ignore:no initializer. Next free block, if any. Only valid if free, otherwise part of payload. */
73
+ next: Block | null;
74
+
75
+ // If the block is free, there is a 'back'reference at its end pointing at its start.
76
+ }
77
+
78
+ // Block constants. A block must have a minimum size of three pointers so it can hold `prev`,
79
+ // `next` and `back` if free.
80
+
81
+ // @ts-ignore: decorator
82
+ @inline const BLOCK_MINSIZE: usize = ((3 * sizeof<usize>() + BLOCK_OVERHEAD + AL_MASK) & ~AL_MASK) - BLOCK_OVERHEAD; // prev + next + back
83
+ // @ts-ignore: decorator
84
+ // @inline const BLOCK_MAXSIZE: usize = 1 << (FL_BITS + SB_BITS - 1); // exclusive, lives in common.ts
85
+
86
+ /** Gets the left block of a block. Only valid if the left block is free. */
87
+ // @ts-ignore: decorator
88
+ @inline function GETFREELEFT(block: Block): Block {
89
+ return load<Block>(changetype<usize>(block) - sizeof<usize>());
90
+ }
91
+
92
+ /** Gets the right block of a block by advancing to the right by its size. */
93
+ // @ts-ignore: decorator
94
+ @inline function GETRIGHT(block: Block): Block {
95
+ return changetype<Block>(changetype<usize>(block) + BLOCK_OVERHEAD + (block.mmInfo & ~TAGS_MASK));
96
+ }
97
+
98
+ // ╒═════════════════════ Root layout (32-bit) ════════════════════╕
99
+ // 3 2 1
100
+ // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 bits
101
+ // ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤ ┐
102
+ // │ 0 | flMap S│ ◄────┐
103
+ // ╞═══════════════════════════════════════════════════════════════╡ │
104
+ // │ slMap[0] S │ ◄─┐ │
105
+ // ├───────────────────────────────────────────────────────────────┤ │ │
106
+ // │ slMap[1] │ ◄─┤ │
107
+ // ├───────────────────────────────────────────────────────────────┤ u32 │
108
+ // │ slMap[22] │ ◄─┘ │
109
+ // ╞═══════════════════════════════════════════════════════════════╡ usize
110
+ // │ head[0] │ ◄────┤
111
+ // ├───────────────────────────────────────────────────────────────┤ │
112
+ // │ ... │ ◄────┤
113
+ // ├───────────────────────────────────────────────────────────────┤ │
114
+ // │ head[367] │ ◄────┤
115
+ // ╞═══════════════════════════════════════════════════════════════╡ │
116
+ // │ tail │ ◄────┘
117
+ // └───────────────────────────────────────────────────────────────┘ SIZE ┘
118
+ // S: Small blocks map
119
+ @unmanaged class Root {
120
+ /** @ts-ignore:no initializer. First level bitmap. */
121
+ flMap: usize;
122
+ }
123
+
124
+ // Root constants. Where stuff is stored inside of the root structure.
125
+
126
+ // @ts-ignore: decorator
127
+ @inline const SL_START: usize = sizeof<usize>();
128
+ // @ts-ignore: decorator
129
+ @inline const SL_END: usize = SL_START + (FL_BITS << alignof<u32>());
130
+ // @ts-ignore: decorator
131
+ @inline const HL_START: usize = (SL_END + AL_MASK) & ~AL_MASK;
132
+ // @ts-ignore: decorator
133
+ @inline const HL_END: usize = HL_START + FL_BITS * SL_SIZE * sizeof<usize>();
134
+ // @ts-ignore: decorator
135
+ @inline const ROOT_SIZE: usize = HL_END + sizeof<usize>();
136
+
137
+ // @ts-ignore: decorator
138
+ @lazy export let ROOT: Root = changetype<Root>(0); // unsafe initializion below
139
+
140
+ /** Gets the second level map of the specified first level. */
141
+ // @ts-ignore: decorator
142
+ @inline function GETSL(root: Root, fl: usize): u32 {
143
+ return load<u32>(changetype<usize>(root) + (fl << alignof<u32>()), SL_START);
144
+ }
145
+
146
+ /** Sets the second level map of the specified first level. */
147
+ // @ts-ignore: decorator
148
+ @inline function SETSL(root: Root, fl: usize, slMap: u32): void {
149
+ store<u32>(changetype<usize>(root) + (fl << alignof<u32>()), slMap, SL_START);
150
+ }
151
+
152
+ /** Gets the head of the free list for the specified combination of first and second level. */
153
+ // @ts-ignore: decorator
154
+ @inline function GETHEAD(root: Root, fl: usize, sl: u32): Block | null {
155
+ return load<Block>(changetype<usize>(root) + (((fl << SL_BITS) + <usize>sl) << alignof<usize>()), HL_START);
156
+ }
157
+
158
+ /** Sets the head of the free list for the specified combination of first and second level. */
159
+ // @ts-ignore: decorator
160
+ @inline function SETHEAD(root: Root, fl: usize, sl: u32, head: Block | null): void {
161
+ store<Block | null>(changetype<usize>(root) + (((fl << SL_BITS) + <usize>sl) << alignof<usize>()), head, HL_START);
162
+ }
163
+
164
+ /** Gets the tail block.. */
165
+ // @ts-ignore: decorator
166
+ @inline function GETTAIL(root: Root): Block {
167
+ return load<Block>(changetype<usize>(root), HL_END);
168
+ }
169
+
170
+ /** Sets the tail block. */
171
+ // @ts-ignore: decorator
172
+ @inline function SETTAIL(root: Root, tail: Block): void {
173
+ store<Block>(changetype<usize>(root), tail, HL_END);
174
+ }
175
+
176
+ /** Inserts a previously used block back into the free list. */
177
+ function insertBlock(root: Root, block: Block): void {
178
+ if (DEBUG) assert(block); // cannot be null
179
+ let blockInfo = block.mmInfo;
180
+ if (DEBUG) assert(blockInfo & FREE); // must be free
181
+
182
+ let right = GETRIGHT(block);
183
+ let rightInfo = right.mmInfo;
184
+
185
+ // merge with right block if also free
186
+ if (rightInfo & FREE) {
187
+ removeBlock(root, right);
188
+ block.mmInfo = blockInfo = blockInfo + BLOCK_OVERHEAD + (rightInfo & ~TAGS_MASK); // keep block tags
189
+ right = GETRIGHT(block);
190
+ rightInfo = right.mmInfo;
191
+ // 'back' is set below
192
+ }
193
+
194
+ // merge with left block if also free
195
+ if (blockInfo & LEFTFREE) {
196
+ let left = GETFREELEFT(block);
197
+ let leftInfo = left.mmInfo;
198
+ if (DEBUG) assert(leftInfo & FREE); // must be free according to right tags
199
+ removeBlock(root, left);
200
+ block = left;
201
+ block.mmInfo = blockInfo = leftInfo + BLOCK_OVERHEAD + (blockInfo & ~TAGS_MASK); // keep left tags
202
+ // 'back' is set below
203
+ }
204
+
205
+ right.mmInfo = rightInfo | LEFTFREE;
206
+ // reference to right is no longer used now, hence rightInfo is not synced
207
+
208
+ // we now know the size of the block
209
+ let size = blockInfo & ~TAGS_MASK;
210
+ if (DEBUG) assert(size >= BLOCK_MINSIZE); // must be a valid size
211
+ if (DEBUG) assert(changetype<usize>(block) + BLOCK_OVERHEAD + size == changetype<usize>(right)); // must match
212
+
213
+ // set 'back' to itself at the end of block
214
+ store<Block>(changetype<usize>(right) - sizeof<usize>(), block);
215
+
216
+ // mapping_insert
217
+ let fl: usize, sl: u32;
218
+ if (size < SB_SIZE) {
219
+ fl = 0;
220
+ sl = <u32>(size >> AL_BITS);
221
+ } else {
222
+ const inv: usize = sizeof<usize>() * 8 - 1;
223
+ let boundedSize = min(size, BLOCK_MAXSIZE);
224
+ fl = inv - clz<usize>(boundedSize);
225
+ sl = <u32>((boundedSize >> (fl - SL_BITS)) ^ (1 << SL_BITS));
226
+ fl -= SB_BITS - 1;
227
+ }
228
+ if (DEBUG) assert(fl < FL_BITS && sl < SL_SIZE); // fl/sl out of range
229
+
230
+ // perform insertion
231
+ let head = GETHEAD(root, fl, sl);
232
+ block.prev = null;
233
+ block.next = head;
234
+ if (head) head.prev = block;
235
+ SETHEAD(root, fl, sl, block);
236
+
237
+ // update first and second level maps
238
+ root.flMap |= 1 << fl;
239
+ SETSL(root, fl, GETSL(root, fl) | (1 << sl));
240
+ }
241
+
242
+ /** Removes a free block from internal lists. */
243
+ function removeBlock(root: Root, block: Block): void {
244
+ let blockInfo = block.mmInfo;
245
+ if (DEBUG) assert(blockInfo & FREE); // must be free
246
+ let size = blockInfo & ~TAGS_MASK;
247
+ if (DEBUG) assert(size >= BLOCK_MINSIZE); // must be valid
248
+
249
+ // mapping_insert
250
+ let fl: usize, sl: u32;
251
+ if (size < SB_SIZE) {
252
+ fl = 0;
253
+ sl = <u32>(size >> AL_BITS);
254
+ } else {
255
+ const inv: usize = sizeof<usize>() * 8 - 1;
256
+ let boundedSize = min(size, BLOCK_MAXSIZE);
257
+ fl = inv - clz<usize>(boundedSize);
258
+ sl = <u32>((boundedSize >> (fl - SL_BITS)) ^ (1 << SL_BITS));
259
+ fl -= SB_BITS - 1;
260
+ }
261
+ if (DEBUG) assert(fl < FL_BITS && sl < SL_SIZE); // fl/sl out of range
262
+
263
+ // link previous and next free block
264
+ let prev = block.prev;
265
+ let next = block.next;
266
+ if (prev) prev.next = next;
267
+ if (next) next.prev = prev;
268
+
269
+ // update head if we are removing it
270
+ if (block == GETHEAD(root, fl, sl)) {
271
+ SETHEAD(root, fl, sl, next);
272
+
273
+ // clear second level map if head is empty now
274
+ if (!next) {
275
+ let slMap = GETSL(root, fl);
276
+ SETSL(root, fl, (slMap &= ~(1 << sl)));
277
+
278
+ // clear first level map if second level is empty now
279
+ if (!slMap) root.flMap &= ~(1 << fl);
280
+ }
281
+ }
282
+ // note: does not alter left/back because it is likely that splitting
283
+ // is performed afterwards, invalidating those changes. so, the caller
284
+ // must perform those updates.
285
+ }
286
+
287
+ function roundSize(size: usize): usize {
288
+ const halfMaxSize = BLOCK_MAXSIZE >> 1; // don't round last fl
289
+ const inv: usize = sizeof<usize>() * 8 - 1;
290
+ const invRound = inv - SL_BITS;
291
+ return size < halfMaxSize ? size + (1 << (invRound - clz<usize>(size))) - 1 : size;
292
+ }
293
+
294
+ /** Searches for a free block of at least the specified size. */
295
+ function searchBlock(root: Root, size: usize): Block | null {
296
+ // size was already asserted by caller
297
+
298
+ // mapping_search
299
+ let fl: usize, sl: u32;
300
+ if (size < SB_SIZE) {
301
+ fl = 0;
302
+ sl = <u32>(size >> AL_BITS);
303
+ } else {
304
+ const requestSize = roundSize(size);
305
+ fl = sizeof<usize>() * 8 - 1 - clz<usize>(requestSize);
306
+ sl = <u32>((requestSize >> (fl - SL_BITS)) ^ (1 << SL_BITS));
307
+ fl -= SB_BITS - 1;
308
+ }
309
+ if (DEBUG) assert(fl < FL_BITS && sl < SL_SIZE); // fl/sl out of range
310
+
311
+ // search second level
312
+ let slMap = GETSL(root, fl) & (~0 << sl);
313
+ let head: Block | null = null;
314
+ if (!slMap) {
315
+ // search next larger first level
316
+ let flMap = root.flMap & (~0 << (fl + 1));
317
+ if (!flMap) {
318
+ head = null;
319
+ } else {
320
+ fl = ctz<usize>(flMap);
321
+ slMap = GETSL(root, fl);
322
+ if (DEBUG) assert(slMap); // can't be zero if fl points here
323
+ head = GETHEAD(root, fl, ctz<u32>(slMap));
324
+ }
325
+ } else {
326
+ head = GETHEAD(root, fl, ctz<u32>(slMap));
327
+ }
328
+ return head;
329
+ }
330
+
331
+ /** Prepares the specified block before (re-)use, possibly splitting it. */
332
+ function prepareBlock(root: Root, block: Block, size: usize): void {
333
+ // size was already asserted by caller
334
+
335
+ let blockInfo = block.mmInfo;
336
+ if (DEBUG) assert(!((size + BLOCK_OVERHEAD) & AL_MASK)); // size must be aligned so the new block is
337
+
338
+ // split if the block can hold another MINSIZE block incl. overhead
339
+ let remaining = (blockInfo & ~TAGS_MASK) - size;
340
+ if (remaining >= BLOCK_OVERHEAD + BLOCK_MINSIZE) {
341
+ block.mmInfo = size | (blockInfo & LEFTFREE); // also discards FREE
342
+
343
+ let spare = changetype<Block>(changetype<usize>(block) + BLOCK_OVERHEAD + size);
344
+ spare.mmInfo = (remaining - BLOCK_OVERHEAD) | FREE; // not LEFTFREE
345
+ insertBlock(root, spare); // also sets 'back'
346
+
347
+ // otherwise tag block as no longer FREE and right as no longer LEFTFREE
348
+ } else {
349
+ block.mmInfo = blockInfo & ~FREE;
350
+ GETRIGHT(block).mmInfo &= ~LEFTFREE;
351
+ }
352
+ }
353
+
354
+ /** Adds more memory to the pool. */
355
+ function addMemory(root: Root, start: usize, endU64: u64): bool {
356
+ let end = <usize>endU64;
357
+ if (DEBUG) assert(<u64>start <= endU64); // must be valid
358
+ start = ((start + BLOCK_OVERHEAD + AL_MASK) & ~AL_MASK) - BLOCK_OVERHEAD;
359
+ end &= ~AL_MASK;
360
+
361
+ let tail = GETTAIL(root);
362
+ let tailInfo: usize = 0;
363
+ if (tail) {
364
+ // more memory
365
+ if (DEBUG) assert(start >= changetype<usize>(tail) + BLOCK_OVERHEAD);
366
+
367
+ // merge with current tail if adjacent
368
+ const offsetToTail = AL_SIZE;
369
+ if (start - offsetToTail == changetype<usize>(tail)) {
370
+ start -= offsetToTail;
371
+ tailInfo = tail.mmInfo;
372
+ } else {
373
+ // We don't do this, but a user might `memory.grow` manually
374
+ // leading to non-adjacent pages managed by TLSF.
375
+ }
376
+ } else if (DEBUG) {
377
+ // first memory
378
+ assert(start >= changetype<usize>(root) + ROOT_SIZE); // starts after root
379
+ }
380
+
381
+ // check if size is large enough for a free block and the tail block
382
+ let size = end - start;
383
+ if (size < BLOCK_OVERHEAD + BLOCK_MINSIZE + BLOCK_OVERHEAD) {
384
+ return false;
385
+ }
386
+
387
+ // left size is total minus its own and the zero-length tail's header
388
+ let leftSize = size - 2 * BLOCK_OVERHEAD;
389
+ let left = changetype<Block>(start);
390
+ left.mmInfo = leftSize | FREE | (tailInfo & LEFTFREE);
391
+ left.prev = null;
392
+ left.next = null;
393
+
394
+ // tail is a zero-length used block
395
+ tail = changetype<Block>(start + BLOCK_OVERHEAD + leftSize);
396
+ tail.mmInfo = 0 | LEFTFREE;
397
+ SETTAIL(root, tail);
398
+
399
+ insertBlock(root, left); // also merges with free left before tail / sets 'back'
400
+
401
+ return true;
402
+ }
403
+
404
+ /** Grows memory to fit at least another block of the specified size. */
405
+ function growMemory(root: Root, size: usize): void {
406
+ if (ASC_LOW_MEMORY_LIMIT) {
407
+ unreachable();
408
+ return;
409
+ }
410
+ // Here, both rounding performed in searchBlock ...
411
+ if (size >= SB_SIZE) {
412
+ size = roundSize(size);
413
+ }
414
+ // and additional BLOCK_OVERHEAD must be taken into account. If we are going
415
+ // to merge with the tail block, that's one time, otherwise it's two times.
416
+ let pagesBefore = memory.size();
417
+ size += BLOCK_OVERHEAD << usize(((<usize>pagesBefore) << 16) - BLOCK_OVERHEAD != changetype<usize>(GETTAIL(root)));
418
+ let pagesNeeded = <i32>(((size + 0xffff) & ~0xffff) >>> 16);
419
+ let pagesWanted = max(pagesBefore, pagesNeeded); // double memory
420
+ if (memory.grow(pagesWanted) < 0) {
421
+ if (memory.grow(pagesNeeded) < 0) unreachable();
422
+ }
423
+ let pagesAfter = memory.size();
424
+ addMemory(root, (<usize>pagesBefore) << 16, (<u64>pagesAfter) << 16);
425
+ }
426
+
427
+ /** Computes the size (excl. header) of a block. */
428
+ function computeSize(size: usize): usize {
429
+ // Size must be large enough and aligned minus preceding overhead
430
+ return size <= BLOCK_MINSIZE ? BLOCK_MINSIZE : ((size + BLOCK_OVERHEAD + AL_MASK) & ~AL_MASK) - BLOCK_OVERHEAD;
431
+ }
432
+
433
+ /** Prepares and checks an allocation size. */
434
+ function prepareSize(size: usize): usize {
435
+ if (size > BLOCK_MAXSIZE) throw new Error(E_ALLOCATION_TOO_LARGE);
436
+ return computeSize(size);
437
+ }
438
+
439
+ /** Initializes the root structure. */
440
+ function initialize(): void {
441
+ let rootOffset = (__heap_base + AL_MASK) & ~AL_MASK;
442
+ let pagesBefore = memory.size();
443
+ let pagesNeeded = <i32>(((rootOffset + ROOT_SIZE + 0xffff) & ~0xffff) >>> 16);
444
+ if (pagesNeeded > pagesBefore && memory.grow(pagesNeeded - pagesBefore) < 0) unreachable();
445
+ let root = changetype<Root>(rootOffset);
446
+ root.flMap = 0;
447
+ SETTAIL(root, changetype<Block>(0));
448
+ for (let fl: usize = 0; fl < FL_BITS; ++fl) {
449
+ SETSL(root, fl, 0);
450
+ for (let sl: u32 = 0; sl < SL_SIZE; ++sl) {
451
+ SETHEAD(root, fl, sl, null);
452
+ }
453
+ }
454
+ let memStart = rootOffset + ROOT_SIZE;
455
+ if (ASC_LOW_MEMORY_LIMIT) {
456
+ const memEnd = (<u64>ASC_LOW_MEMORY_LIMIT) & ~AL_MASK;
457
+ if (memStart <= memEnd) addMemory(root, memStart, memEnd);
458
+ else unreachable(); // low memory limit already exceeded
459
+ } else {
460
+ addMemory(root, memStart, (<u64>memory.size()) << 16);
461
+ }
462
+ ROOT = root;
463
+ }
464
+
465
+ /** Allocates a block of the specified size. */
466
+ export function allocateBlock(root: Root, size: usize): Block {
467
+ let payloadSize = prepareSize(size);
468
+ let block = searchBlock(root, payloadSize);
469
+ if (!block) {
470
+ growMemory(root, payloadSize);
471
+ block = changetype<Block>(searchBlock(root, payloadSize));
472
+ if (DEBUG) assert(block); // must be found now
473
+ }
474
+ if (DEBUG) assert((block.mmInfo & ~TAGS_MASK) >= payloadSize); // must fit
475
+ removeBlock(root, block);
476
+ prepareBlock(root, block, payloadSize);
477
+ return block;
478
+ }
479
+
480
+ /** Reallocates a block to the specified size. */
481
+ export function reallocateBlock(root: Root, block: Block, size: usize): Block {
482
+ let payloadSize = prepareSize(size);
483
+ let blockInfo = block.mmInfo;
484
+ let blockSize = blockInfo & ~TAGS_MASK;
485
+
486
+ // possibly split and update runtime size if it still fits
487
+ if (payloadSize <= blockSize) {
488
+ prepareBlock(root, block, payloadSize);
489
+ return block;
490
+ }
491
+
492
+ // merge with right free block if merger is large enough
493
+ let right = GETRIGHT(block);
494
+ let rightInfo = right.mmInfo;
495
+ if (rightInfo & FREE) {
496
+ let mergeSize = blockSize + BLOCK_OVERHEAD + (rightInfo & ~TAGS_MASK);
497
+ if (mergeSize >= payloadSize) {
498
+ removeBlock(root, right);
499
+ block.mmInfo = (blockInfo & TAGS_MASK) | mergeSize;
500
+ prepareBlock(root, block, payloadSize);
501
+ return block;
502
+ }
503
+ }
504
+
505
+ // otherwise move the block
506
+ return moveBlock(root, block, size);
507
+ }
508
+
509
+ /** Moves a block to a new one of the specified size. */
510
+ function moveBlock(root: Root, block: Block, newSize: usize): Block {
511
+ let newBlock = allocateBlock(root, newSize);
512
+ memory.copy(
513
+ changetype<usize>(newBlock) + BLOCK_OVERHEAD,
514
+ changetype<usize>(block) + BLOCK_OVERHEAD,
515
+ block.mmInfo & ~TAGS_MASK
516
+ );
517
+ if (changetype<usize>(block) >= __heap_base) {
518
+ freeBlock(root, block);
519
+ }
520
+ return newBlock;
521
+ }
522
+
523
+ /** Frees a block. */
524
+ export function freeBlock(root: Root, block: Block): void {
525
+ block.mmInfo = block.mmInfo | FREE;
526
+ insertBlock(root, block);
527
+ }
528
+
529
+ /** Checks that a used block is valid to be freed or reallocated. */
530
+ function checkUsedBlock(ptr: usize): Block {
531
+ let block = changetype<Block>(ptr - BLOCK_OVERHEAD);
532
+ assert(
533
+ ptr != 0 &&
534
+ !(ptr & AL_MASK) && // must exist and be aligned
535
+ !(block.mmInfo & FREE) // must be used
536
+ );
537
+ return block;
538
+ }
539
+
540
+ // @ts-ignore: decorator
541
+ @global @unsafe
542
+ export function __alloc(size: usize): usize {
543
+ if (!ROOT) initialize();
544
+ return changetype<usize>(allocateBlock(ROOT, size)) + BLOCK_OVERHEAD;
545
+ }
546
+
547
+ // @ts-ignore: decorator
548
+ @global @unsafe
549
+ export function __realloc(ptr: usize, size: usize): usize {
550
+ if (!ROOT) initialize();
551
+ return (
552
+ (ptr < __heap_base
553
+ ? changetype<usize>(moveBlock(ROOT, checkUsedBlock(ptr), size))
554
+ : changetype<usize>(reallocateBlock(ROOT, checkUsedBlock(ptr), size))) + BLOCK_OVERHEAD
555
+ );
556
+ }
557
+
558
+ // @ts-ignore: decorator
559
+ @global @unsafe
560
+ export function __free(ptr: usize): void {
561
+ if (ptr < __heap_base) return;
562
+ if (!ROOT) initialize();
563
+ freeBlock(ROOT, checkUsedBlock(ptr));
564
+ }
@@ -0,0 +1,71 @@
1
+ import { Typeinfo, TypeinfoFlags } from "./shared/typeinfo";
2
+ import { E_INDEXOUTOFRANGE } from "./util/error";
3
+ import { ArrayBufferView } from "./arraybuffer";
4
+ import { SmallTuple } from "./tuple";
5
+
6
+ // @ts-ignore: decorator
7
+ @builtin
8
+ export declare const __rtti_base: usize;
9
+
10
+ // @ts-ignore: decorator
11
+ @builtin @unsafe
12
+ export declare function __visit_globals(cookie: u32): void;
13
+
14
+ // @ts-ignore: decorator
15
+ @builtin @unsafe
16
+ export declare function __visit_members(ref: usize, cookie: u32): void;
17
+
18
+ // @ts-ignore: decorator
19
+ @unsafe
20
+ export function __typeinfo(id: u32): TypeinfoFlags {
21
+ let ptr = __rtti_base;
22
+ if (id > load<u32>(ptr)) throw new Error(E_INDEXOUTOFRANGE);
23
+ return changetype<Typeinfo>(ptr + sizeof<u32>() + id * offsetof<Typeinfo>()).flags;
24
+ }
25
+
26
+ // @ts-ignore: decorator
27
+ @unsafe
28
+ export function __newBuffer(size: usize, id: u32, data: usize = 0): usize {
29
+ let buffer = __new(size, id);
30
+ if (data) memory.copy(buffer, data, size);
31
+ return buffer;
32
+ }
33
+
34
+ // @ts-ignore: decorator
35
+ @unsafe
36
+ export function __newArray(length: i32, alignLog2: usize, id: u32, data: usize = 0): usize {
37
+ let bufferSize = (<usize>length) << alignLog2;
38
+ // make sure `buffer` is tracked by the shadow stack
39
+ let buffer = changetype<ArrayBuffer>(__newBuffer(bufferSize, idof<ArrayBuffer>(), data));
40
+ // ...since allocating the array may trigger GC steps
41
+ let array = __new(offsetof<i32[]>(), id);
42
+ store<usize>(array, changetype<usize>(buffer), offsetof<ArrayBufferView>("buffer"));
43
+ __link(array, changetype<usize>(buffer), false);
44
+ store<usize>(array, changetype<usize>(buffer), offsetof<ArrayBufferView>("dataStart"));
45
+ store<i32>(array, bufferSize, offsetof<ArrayBufferView>("byteLength"));
46
+ store<i32>(array, length, offsetof<i32[]>("length_"));
47
+ return array;
48
+ }
49
+
50
+ /**
51
+ * {@link elementSize} is the byte size of all elements in the tuple
52
+ * {@link elementSize} must be <= 64
53
+ */
54
+ // @ts-ignore: decorator
55
+ @unsafe
56
+ export function __newTuple(elementSize: usize, bitmap: u64): usize {
57
+ const bitmapSize = sizeof<u64>();
58
+ const totalSize = elementSize + bitmapSize;
59
+ const ptr = __new(totalSize, idof<SmallTuple>());
60
+ store<u64>(changetype<usize>(ptr) + elementSize, bitmap);
61
+ return ptr;
62
+ }
63
+
64
+ // @ts-ignore: decorator
65
+ @unsafe
66
+ export function __newFunction(functionIdnex: usize, env: usize, rtid: u32): usize {
67
+ const ptr = __new(8, rtid);
68
+ store<usize>(ptr, functionIdnex);
69
+ store<usize>(ptr + 4, env);
70
+ return ptr;
71
+ }