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,415 @@
1
+ import { BLOCK, BLOCK_OVERHEAD, OBJECT_OVERHEAD, OBJECT_MAXSIZE, TOTAL_OVERHEAD, DEBUG, TRACE, RTRACE } from "./common";
2
+ import { TypeinfoFlags } from "../shared/typeinfo";
3
+ import { E_ALLOCATION_TOO_LARGE, E_ALREADY_PINNED, E_NOT_PINNED } from "../util/error";
4
+
5
+ // === ITCMS: An incremental Tri-Color Mark & Sweep garbage collector ===
6
+ // Adapted from Bach Le's μgc, see: https://github.com/bullno1/ugc
7
+
8
+ // ╒═════════════╤══════════════ Colors ═══════════════════════════╕
9
+ // │ Color │ Meaning │
10
+ // ├─────────────┼─────────────────────────────────────────────────┤
11
+ // │ WHITE* │ Unprocessed │
12
+ // │ BLACK* │ Processed │
13
+ // │ GRAY │ Processed with unprocessed children │
14
+ // │ TRANSPARENT │ Manually pinned (always reachable) │
15
+ // └─────────────┴─────────────────────────────────────────────────┘
16
+ // * flipped between cycles
17
+
18
+ // @ts-ignore: decorator
19
+ @lazy let white = 0;
20
+ // @ts-ignore: decorator
21
+ @inline const gray = 2;
22
+ // @ts-ignore: decorator
23
+ @inline const transparent = 3;
24
+ // @ts-ignore: decorator
25
+ @inline const COLOR_MASK = 3;
26
+
27
+ /** Size in memory of all objects currently managed by the GC. */
28
+ // @ts-ignore: decorator
29
+ @lazy let total: usize = 0;
30
+
31
+ /** Currently transitioning from SWEEP to MARK state. */
32
+ // @ts-ignore: decorator
33
+ @inline const STATE_IDLE = 0;
34
+ /** Currently marking reachable objects. */
35
+ // @ts-ignore: decorator
36
+ @inline const STATE_MARK = 1;
37
+ /** Currently sweeping unreachable objects. */
38
+ // @ts-ignore: decorator
39
+ @inline const STATE_SWEEP = 2;
40
+ /** Current collector state. */
41
+ // @ts-ignore: decorator
42
+ @lazy let state = STATE_IDLE;
43
+
44
+ // @ts-ignore: decorator
45
+ @lazy let fromSpace = initLazy(changetype<Object>(memory.data(offsetof<Object>())));
46
+ // @ts-ignore: decorator
47
+ @lazy let toSpace = initLazy(changetype<Object>(memory.data(offsetof<Object>())));
48
+ // @ts-ignore: decorator
49
+ @lazy let pinSpace = initLazy(changetype<Object>(memory.data(offsetof<Object>())));
50
+ // @ts-ignore: decorator
51
+ @lazy let iter: Object = changetype<Object>(0); // unsafe initializion below
52
+
53
+ function initLazy(space: Object): Object {
54
+ space.nextWithColor = changetype<usize>(space);
55
+ space.prev = space;
56
+ return space;
57
+ }
58
+
59
+ /** Visit cookie indicating scanning of an object. */
60
+ // @ts-ignore: decorator
61
+ @inline const VISIT_SCAN = 0;
62
+
63
+ // ╒═══════════════ Managed object layout (32-bit) ════════════════╕
64
+ // 3 2 1
65
+ // 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
66
+ // ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤
67
+ // │ Memory manager block │
68
+ // ╞═══════════════════════════════════════════════════════════╤═══╡
69
+ // │ next │ C │ = nextWithColor
70
+ // ├───────────────────────────────────────────────────────────┴───┤
71
+ // │ prev │
72
+ // ├───────────────────────────────────────────────────────────────┤
73
+ // │ rtId │
74
+ // ├───────────────────────────────────────────────────────────────┤
75
+ // │ rtSize │
76
+ // ╞>ptr═══════════════════════════════════════════════════════════╡
77
+ // │ ... │
78
+ // C: color
79
+
80
+ /** @ts-ignore: object. Represents a managed object in memory, consisting of a header followed by the object's data. */
81
+ @unmanaged class Object extends BLOCK {
82
+ /** @ts-ignore:no initializer. Pointer to the next object with color flags stored in the alignment bits. */
83
+ nextWithColor: usize; // *u32
84
+ /** @ts-ignore:no initializer. Pointer to the previous object. */
85
+ prev: Object; // *u32
86
+ /** @ts-ignore:no initializer. Runtime id. */
87
+ rtId: u32;
88
+ /** @ts-ignore:no initializer. Runtime size. */
89
+ rtSize: u32;
90
+
91
+ /** Gets the pointer to the next object. */
92
+ get next(): Object {
93
+ return changetype<Object>(this.nextWithColor & ~COLOR_MASK);
94
+ }
95
+
96
+ /** Sets the pointer to the next object. */
97
+ set next(obj: Object) {
98
+ this.nextWithColor = changetype<usize>(obj) | (this.nextWithColor & COLOR_MASK);
99
+ }
100
+
101
+ /** Gets this object's color. */
102
+ get color(): i32 {
103
+ return i32(this.nextWithColor & COLOR_MASK);
104
+ }
105
+
106
+ /** Sets this object's color. */
107
+ set color(color: i32) {
108
+ this.nextWithColor = (this.nextWithColor & ~COLOR_MASK) | color;
109
+ }
110
+
111
+ /** Gets the size of this object in memory. */
112
+ get size(): usize {
113
+ return BLOCK_OVERHEAD + (this.mmInfo & ~3);
114
+ }
115
+
116
+ /** Tests if this object is pointerfree. */
117
+ get isPointerfree(): bool {
118
+ let rtId = this.rtId;
119
+ // 0: Object, 1: ArrayBuffer, 2: String
120
+ return rtId <= idof<string>() || (__typeinfo(rtId) & TypeinfoFlags.POINTERFREE) != 0;
121
+ }
122
+
123
+ /** Unlinks this object from its list. */
124
+ unlink(): void {
125
+ let next = this.next;
126
+ if (next == null) {
127
+ if (DEBUG) assert(this.prev == null && changetype<usize>(this) < __heap_base);
128
+ return; // static data not yet linked
129
+ }
130
+ let prev = this.prev;
131
+ if (DEBUG) assert(prev);
132
+ next.prev = prev;
133
+ prev.next = next;
134
+ }
135
+
136
+ /** Links this object to the specified list, with the given color. */
137
+ linkTo(list: Object, withColor: i32): void {
138
+ let prev = list.prev;
139
+ this.nextWithColor = changetype<usize>(list) | withColor;
140
+ this.prev = prev;
141
+ prev.next = this;
142
+ list.prev = this;
143
+ }
144
+
145
+ /** Marks this object as gray, that is reachable with unscanned children. */
146
+ makeGray(): void {
147
+ if (this == iter) iter = assert(this.prev);
148
+ this.unlink();
149
+ this.linkTo(toSpace, this.isPointerfree ? i32(!white) : gray);
150
+ }
151
+ }
152
+
153
+ /** Visits all objects considered to be program roots. */
154
+ function visitRoots(cookie: u32): void {
155
+ __visit_globals(cookie);
156
+ let pn = pinSpace;
157
+ let iter = pn.next;
158
+ while (iter != pn) {
159
+ if (DEBUG) assert(iter.color == transparent);
160
+ __visit_members(changetype<usize>(iter) + TOTAL_OVERHEAD, cookie);
161
+ iter = iter.next;
162
+ }
163
+ }
164
+
165
+ /** Visits all objects on the stack. */
166
+ function visitStack(cookie: u32): void {
167
+ let ptr = __stack_pointer;
168
+ while (ptr < __heap_base) {
169
+ __visit(load<usize>(ptr), cookie);
170
+ ptr += sizeof<usize>();
171
+ }
172
+ }
173
+
174
+ /** Performs a single step according to the current state. */
175
+ function step(): usize {
176
+ // Magic constants responsible for pause times. Obtained experimentally
177
+ // using the compiler compiling itself. 2048 budget pro run by default.
178
+ const MARKCOST = isDefined(ASC_GC_MARKCOST) ? ASC_GC_MARKCOST : 1;
179
+ const SWEEPCOST = isDefined(ASC_GC_SWEEPCOST) ? ASC_GC_SWEEPCOST : 10;
180
+ let obj: Object;
181
+ switch (state) {
182
+ case STATE_IDLE: {
183
+ state = STATE_MARK;
184
+ visitCount = 0;
185
+ visitRoots(VISIT_SCAN);
186
+ iter = toSpace;
187
+ return visitCount * MARKCOST;
188
+ }
189
+ case STATE_MARK: {
190
+ let black = i32(!white);
191
+ obj = iter.next;
192
+ while (obj != toSpace) {
193
+ iter = obj;
194
+ if (obj.color != black) {
195
+ // skip already-blacks (pointerfree)
196
+ obj.color = black;
197
+ visitCount = 0;
198
+ __visit_members(changetype<usize>(obj) + TOTAL_OVERHEAD, VISIT_SCAN);
199
+ return visitCount * MARKCOST;
200
+ }
201
+ obj = obj.next;
202
+ }
203
+ visitCount = 0;
204
+ visitRoots(VISIT_SCAN);
205
+ obj = iter.next;
206
+ if (obj == toSpace) {
207
+ visitStack(VISIT_SCAN);
208
+ obj = iter.next;
209
+ while (obj != toSpace) {
210
+ if (obj.color != black) {
211
+ obj.color = black;
212
+ __visit_members(changetype<usize>(obj) + TOTAL_OVERHEAD, VISIT_SCAN);
213
+ }
214
+ obj = obj.next;
215
+ }
216
+ let from = fromSpace;
217
+ fromSpace = toSpace;
218
+ toSpace = from;
219
+ white = black;
220
+ iter = from.next;
221
+ state = STATE_SWEEP;
222
+ }
223
+ return visitCount * MARKCOST;
224
+ }
225
+ case STATE_SWEEP: {
226
+ obj = iter;
227
+ if (obj != toSpace) {
228
+ iter = obj.next;
229
+ if (DEBUG) assert(obj.color == i32(!white)); // old white
230
+ free(obj);
231
+ return SWEEPCOST;
232
+ }
233
+ toSpace.nextWithColor = changetype<usize>(toSpace);
234
+ toSpace.prev = toSpace;
235
+ state = STATE_IDLE;
236
+ break;
237
+ }
238
+ }
239
+ return 0;
240
+ }
241
+
242
+ /** Frees an object. */
243
+ function free(obj: Object): void {
244
+ if (changetype<usize>(obj) < __heap_base) {
245
+ obj.nextWithColor = 0; // may become linked again
246
+ obj.prev = changetype<Object>(0);
247
+ } else {
248
+ if (isDefined(ASC_GC_TESTING)) memory.fill(changetype<usize>(obj) + TOTAL_OVERHEAD, 0xde, obj.rtSize);
249
+ total -= obj.size;
250
+ if (isDefined(__finalize)) {
251
+ __finalize(changetype<usize>(obj) + TOTAL_OVERHEAD);
252
+ }
253
+ __free(changetype<usize>(obj) + BLOCK_OVERHEAD);
254
+ }
255
+ }
256
+
257
+ // Garbage collector interface
258
+
259
+ // @ts-ignore: decorator
260
+ @global @unsafe
261
+ export function __new(size: usize, id: i32): usize {
262
+ if (size >= OBJECT_MAXSIZE) throw new Error(E_ALLOCATION_TOO_LARGE);
263
+ if (total >= threshold) interrupt();
264
+ let obj = changetype<Object>(__alloc(OBJECT_OVERHEAD + size) - BLOCK_OVERHEAD);
265
+ obj.rtId = id;
266
+ obj.rtSize = <u32>size;
267
+ obj.linkTo(fromSpace, white); // inits next/prev
268
+ total += obj.size;
269
+ let ptr = changetype<usize>(obj) + TOTAL_OVERHEAD;
270
+ // may be visited before being fully initialized, so must fill
271
+ memory.fill(ptr, 0, size);
272
+ return ptr;
273
+ }
274
+
275
+ // @ts-ignore: decorator
276
+ @global @unsafe
277
+ export function __renew(oldPtr: usize, size: usize): usize {
278
+ let oldObj = changetype<Object>(oldPtr - TOTAL_OVERHEAD);
279
+ // Update object size if its block is large enough
280
+ if (size <= (oldObj.mmInfo & ~3) - OBJECT_OVERHEAD) {
281
+ oldObj.rtSize = <u32>size;
282
+ return oldPtr;
283
+ }
284
+ // We cannot reuse the old object anymore.
285
+ // shadow stack may still contain references to it, so we must not free it yet.
286
+ let newPtr = __new(size, oldObj.rtId);
287
+ memory.copy(newPtr, oldPtr, min(size, oldObj.rtSize));
288
+ return newPtr;
289
+ }
290
+
291
+ // @ts-ignore: decorator
292
+ @global @unsafe
293
+ export function __link(parentPtr: usize, childPtr: usize, expectMultiple: bool): void {
294
+ // Write barrier is unnecessary if non-incremental
295
+ if (!childPtr) return;
296
+ if (DEBUG) assert(parentPtr);
297
+ let child = changetype<Object>(childPtr - TOTAL_OVERHEAD);
298
+ if (child.color == white) {
299
+ let parent = changetype<Object>(parentPtr - TOTAL_OVERHEAD);
300
+ let parentColor = parent.color;
301
+ if (parentColor == i32(!white)) {
302
+ // Maintain the invariant that no black object may point to a white object.
303
+ if (expectMultiple) {
304
+ // Move the barrier "backward". Suitable for containers receiving multiple stores.
305
+ // Avoids a barrier for subsequent objects stored into the same container.
306
+ parent.makeGray();
307
+ } else {
308
+ // Move the barrier "forward". Suitable for objects receiving isolated stores.
309
+ child.makeGray();
310
+ }
311
+ } else if (parentColor == transparent && state == STATE_MARK) {
312
+ // Pinned objects are considered 'black' during the mark phase.
313
+ child.makeGray();
314
+ }
315
+ }
316
+ }
317
+
318
+ // @ts-ignore: decorator
319
+ @lazy let visitCount = 0;
320
+
321
+ // @ts-ignore: decorator
322
+ @global @unsafe
323
+ export function __visit(ptr: usize, cookie: i32): void {
324
+ if (!ptr) return;
325
+ let obj = changetype<Object>(ptr - TOTAL_OVERHEAD);
326
+ if (obj.color == white) {
327
+ obj.makeGray();
328
+ ++visitCount;
329
+ }
330
+ }
331
+
332
+ // @ts-ignore: decorator
333
+ @global @unsafe
334
+ export function __pin(ptr: usize): usize {
335
+ if (ptr) {
336
+ let obj = changetype<Object>(ptr - TOTAL_OVERHEAD);
337
+ if (obj.color == transparent) {
338
+ throw new Error(E_ALREADY_PINNED);
339
+ }
340
+ obj.unlink(); // from fromSpace
341
+ obj.linkTo(pinSpace, transparent);
342
+ }
343
+ return ptr;
344
+ }
345
+
346
+ // @ts-ignore: decorator
347
+ @global @unsafe
348
+ export function __unpin(ptr: usize): void {
349
+ if (!ptr) return;
350
+ let obj = changetype<Object>(ptr - TOTAL_OVERHEAD);
351
+ if (obj.color != transparent) {
352
+ throw new Error(E_NOT_PINNED);
353
+ }
354
+ if (state == STATE_MARK) {
355
+ // We may be right at the point after marking roots for the second time and
356
+ // entering the sweep phase, in which case the object would be missed if it
357
+ // is not only pinned but also a root. Make sure it isn't missed.
358
+ obj.makeGray();
359
+ } else {
360
+ obj.unlink();
361
+ obj.linkTo(fromSpace, white);
362
+ }
363
+ }
364
+
365
+ // @ts-ignore: decorator
366
+ @global @unsafe
367
+ export function __collect(): void {
368
+ if (TRACE) trace("GC (full) at", 1, total);
369
+ if (state > STATE_IDLE) {
370
+ // finish current cycle
371
+ while (state != STATE_IDLE) step();
372
+ }
373
+ // perform a full cycle
374
+ step();
375
+ while (state != STATE_IDLE) step();
376
+ threshold = <usize>((<u64>total * IDLEFACTOR) / 100) + GRANULARITY;
377
+ if (TRACE) trace("GC (full) done at cur/max", 2, total, memory.size() << 16);
378
+ }
379
+
380
+ // Garbage collector automation
381
+
382
+ /** How often to interrupt. The default of 1024 means "interrupt each 1024 bytes allocated". */
383
+ // @ts-ignore: decorator
384
+ @inline const GRANULARITY: usize = isDefined(ASC_GC_GRANULARITY) ? ASC_GC_GRANULARITY : 1024;
385
+ /** How long to interrupt. The default of 200% means "run at double the speed of allocations". */
386
+ // @ts-ignore: decorator
387
+ @inline const STEPFACTOR: usize = isDefined(ASC_GC_SWEEPFACTOR) ? ASC_GC_SWEEPFACTOR : 200;
388
+ /** How long to idle. The default of 200% means "wait for memory to double before kicking in again". */
389
+ // @ts-ignore: decorator
390
+ @inline const IDLEFACTOR: usize = isDefined(ASC_GC_IDLEFACTOR) ? ASC_GC_IDLEFACTOR : 200;
391
+
392
+ /** Threshold of memory used by objects to exceed before interrupting again. */
393
+ // @ts-ignore: decorator
394
+ @lazy let threshold: usize = (((<usize>memory.size()) << 16) - __heap_base) >> 1;
395
+
396
+ /** Performs a reasonable amount of incremental GC steps. */
397
+ function interrupt(): void {
398
+ if (TRACE) trace("GC (auto) at", 1, total);
399
+ let budget: isize = (GRANULARITY * STEPFACTOR) / 100;
400
+ do {
401
+ budget -= step();
402
+ if (state == STATE_IDLE) {
403
+ if (TRACE) trace("└ GC (auto) done at cur/max", 2, total, memory.size() << 16);
404
+ if (IDLEFACTOR % 100 == 0) {
405
+ // optimization for the default GC parameters which idle factor is 200%
406
+ threshold = total * (IDLEFACTOR / 100) + GRANULARITY;
407
+ } else {
408
+ threshold = <usize>((<u64>total * IDLEFACTOR) / 100) + GRANULARITY;
409
+ }
410
+ return;
411
+ }
412
+ } while (budget > 0);
413
+ if (TRACE) trace("└ GC (auto) ongoing at", 1, total);
414
+ threshold = total + GRANULARITY * usize(total - threshold < GRANULARITY);
415
+ }
@@ -0,0 +1,276 @@
1
+ import { BLOCK, BLOCK_OVERHEAD, OBJECT_OVERHEAD, OBJECT_MAXSIZE, TOTAL_OVERHEAD, DEBUG } from "./common";
2
+ import { E_ALLOCATION_TOO_LARGE, E_ALREADY_PINNED, E_NOT_PINNED } from "../util/error";
3
+
4
+ // === TCMS: A Two-Color Mark & Sweep garbage collector ===
5
+
6
+ // ╒═════════════╤══════════════ Colors ═══════════════════════════╕
7
+ // │ Color │ Meaning │
8
+ // ├─────────────┼─────────────────────────────────────────────────┤
9
+ // │ WHITE* │ Unprocessed or Unreachable │
10
+ // │ BLACK* │ Reachable │
11
+ // │ TRANSPARENT │ Manually pinned (always reachable) │
12
+ // └─────────────┴─────────────────────────────────────────────────┘
13
+ // * flipped between cycles
14
+
15
+ // @ts-ignore: decorator
16
+ @lazy let white = 0;
17
+ // @ts-ignore: decorator
18
+ @inline const transparent = 3;
19
+ // @ts-ignore: decorator
20
+ @inline const COLOR_MASK = 3;
21
+
22
+ /** Size in memory of all objects currently managed by the GC. */
23
+ // @ts-ignore: decorator
24
+ @lazy let total: usize = 0;
25
+
26
+ // @ts-ignore: decorator
27
+ @lazy let fromSpace = initLazy(changetype<Object>(memory.data(offsetof<Object>())));
28
+ // @ts-ignore: decorator
29
+ @lazy let toSpace = initLazy(changetype<Object>(memory.data(offsetof<Object>())));
30
+ // @ts-ignore: decorator
31
+ @lazy let pinSpace = initLazy(changetype<Object>(memory.data(offsetof<Object>())));
32
+
33
+ function initLazy(space: Object): Object {
34
+ space.nextWithColor = changetype<usize>(space);
35
+ space.prev = space;
36
+ return space;
37
+ }
38
+
39
+ /** Visit cookie indicating scanning of an object. */
40
+ // @ts-ignore: decorator
41
+ @inline const VISIT_SCAN = 0;
42
+
43
+ // ╒═══════════════ Managed object layout (32-bit) ════════════════╕
44
+ // 3 2 1
45
+ // 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
46
+ // ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤
47
+ // │ Memory manager block │
48
+ // ╞═══════════════════════════════════════════════════════════╤═══╡
49
+ // │ next │ C │ = nextWithColor
50
+ // ├───────────────────────────────────────────────────────────┴───┤
51
+ // │ prev │
52
+ // ├───────────────────────────────────────────────────────────────┤
53
+ // │ rtId │
54
+ // ├───────────────────────────────────────────────────────────────┤
55
+ // │ rtSize │
56
+ // ╞>ptr═══════════════════════════════════════════════════════════╡
57
+ // │ ... │
58
+ // C: color
59
+
60
+ /** @ts-ignore: object. Represents a managed object in memory, consisting of a header followed by the object's data. */
61
+ @unmanaged class Object extends BLOCK {
62
+ /** @ts-ignore:no initializer. Pointer to the next object with color flags stored in the alignment bits. */
63
+ nextWithColor: usize; // *u32
64
+ /** @ts-ignore:no initializer. Pointer to the previous object. */
65
+ prev: Object; // *u32
66
+ /** @ts-ignore:no initializer. Runtime id. */
67
+ rtId: u32;
68
+ /** @ts-ignore:no initializer. Runtime size. */
69
+ rtSize: u32;
70
+
71
+ /** Gets the pointer to the next object. */
72
+ get next(): Object {
73
+ return changetype<Object>(this.nextWithColor & ~COLOR_MASK);
74
+ }
75
+
76
+ /** Sets the pointer to the next object. */
77
+ set next(obj: Object) {
78
+ this.nextWithColor = changetype<usize>(obj) | (this.nextWithColor & COLOR_MASK);
79
+ }
80
+
81
+ /** Gets this object's color. */
82
+ get color(): i32 {
83
+ return i32(this.nextWithColor & COLOR_MASK);
84
+ }
85
+
86
+ /** Sets this object's color. */
87
+ set color(color: i32) {
88
+ this.nextWithColor = (this.nextWithColor & ~COLOR_MASK) | color;
89
+ }
90
+
91
+ /** Gets the size of this object in memory. */
92
+ get size(): usize {
93
+ return BLOCK_OVERHEAD + (this.mmInfo & ~3);
94
+ }
95
+
96
+ /** Unlinks this object from its list. */
97
+ unlink(): void {
98
+ let next = this.next;
99
+ if (next == null) {
100
+ if (DEBUG) assert(this.prev == null && changetype<usize>(this) < __heap_base);
101
+ return; // static data not yet linked
102
+ }
103
+ let prev = this.prev;
104
+ if (DEBUG) assert(prev);
105
+ next.prev = prev;
106
+ prev.next = next;
107
+ }
108
+
109
+ /** Links this object to the specified list, with the given color. */
110
+ linkTo(list: Object, withColor: i32): void {
111
+ let prev = list.prev;
112
+ this.nextWithColor = changetype<usize>(list) | withColor;
113
+ this.prev = prev;
114
+ prev.next = this;
115
+ list.prev = this;
116
+ }
117
+ }
118
+
119
+ /** Frees an object. */
120
+ function free(obj: Object): void {
121
+ if (changetype<usize>(obj) < __heap_base) {
122
+ obj.nextWithColor = 0; // may become linked again
123
+ obj.prev = changetype<Object>(0);
124
+ } else {
125
+ if (isDefined(ASC_GC_TESTING)) memory.fill(changetype<usize>(obj) + TOTAL_OVERHEAD, 0xde, obj.rtSize);
126
+ total -= obj.size;
127
+ __free(changetype<usize>(obj) + BLOCK_OVERHEAD);
128
+ }
129
+ }
130
+
131
+ // Garbage collector interface
132
+
133
+ // @ts-ignore: decorator
134
+ @global @unsafe
135
+ export function __new(size: usize, id: i32): usize {
136
+ if (size >= OBJECT_MAXSIZE) throw new Error(E_ALLOCATION_TOO_LARGE);
137
+ if (total >= threshold) __collect();
138
+ let obj = changetype<Object>(__alloc(OBJECT_OVERHEAD + size) - BLOCK_OVERHEAD);
139
+ obj.rtId = id;
140
+ obj.rtSize = <u32>size;
141
+ obj.linkTo(fromSpace, white);
142
+ total += obj.size;
143
+ let ptr = changetype<usize>(obj) + TOTAL_OVERHEAD;
144
+ // may be visited before being fully initialized, so must fill
145
+ memory.fill(ptr, 0, size);
146
+ return ptr;
147
+ }
148
+
149
+ // @ts-ignore: decorator
150
+ @global @unsafe
151
+ export function __renew(oldPtr: usize, size: usize): usize {
152
+ let oldObj = changetype<Object>(oldPtr - TOTAL_OVERHEAD);
153
+ // Update object size if its block is large enough
154
+ if (size <= (oldObj.mmInfo & ~3) - OBJECT_OVERHEAD) {
155
+ oldObj.rtSize = <u32>size;
156
+ return oldPtr;
157
+ }
158
+ // we cannot reuse the old object anymore.
159
+ // shadow stack may still contain references to it, so we must not free it yet.
160
+ let newPtr = __new(size, oldObj.rtId);
161
+ if (DEBUG) assert(size > oldObj.rtSize);
162
+ memory.copy(newPtr, oldPtr, oldObj.rtSize);
163
+ return newPtr;
164
+ }
165
+
166
+ // @ts-ignore: decorator
167
+ @global @unsafe
168
+ export function __link(parentPtr: usize, childPtr: usize, expectMultiple: bool): void {
169
+ // nop
170
+ }
171
+
172
+ // @ts-ignore: decorator
173
+ @global @unsafe
174
+ export function __visit(ptr: usize, cookie: i32): void {
175
+ if (!ptr) return;
176
+ let obj = changetype<Object>(ptr - TOTAL_OVERHEAD);
177
+ if (obj.color == white) {
178
+ obj.unlink(); // from fromSpace
179
+ obj.linkTo(toSpace, i32(!white));
180
+ }
181
+ }
182
+
183
+ // @ts-ignore: decorator
184
+ @global @unsafe
185
+ export function __pin(ptr: usize): usize {
186
+ if (ptr) {
187
+ let obj = changetype<Object>(ptr - TOTAL_OVERHEAD);
188
+ if (obj.color == transparent) {
189
+ throw new Error(E_ALREADY_PINNED);
190
+ }
191
+ obj.unlink(); // from fromSpace
192
+ obj.linkTo(pinSpace, transparent);
193
+ }
194
+ return ptr;
195
+ }
196
+
197
+ // @ts-ignore: decorator
198
+ @global @unsafe
199
+ export function __unpin(ptr: usize): void {
200
+ if (!ptr) return;
201
+ let obj = changetype<Object>(ptr - TOTAL_OVERHEAD);
202
+ if (obj.color != transparent) {
203
+ throw new Error(E_NOT_PINNED);
204
+ }
205
+ obj.unlink(); // from pinSpace
206
+ obj.linkTo(fromSpace, white);
207
+ }
208
+
209
+ // Garbage collector automation
210
+
211
+ /** How often to interrupt. The default of 16384 means "interrupt each 16KiB allocated". */
212
+ // @ts-ignore: decorator
213
+ @inline const GRANULARITY: usize = isDefined(ASC_GC_GRANULARITY) ? ASC_GC_GRANULARITY : 16 * 1024;
214
+
215
+ /** Threshold of memory used by objects to exceed before interrupting again. */
216
+ // @ts-ignore: decorator
217
+ @lazy let threshold: usize = GRANULARITY;
218
+
219
+ /** Visits all objects on the stack. */
220
+ function visitStack(): void {
221
+ let ptr = __stack_pointer;
222
+ while (ptr < __heap_base) {
223
+ __visit(load<usize>(ptr), VISIT_SCAN);
224
+ ptr += sizeof<usize>();
225
+ }
226
+ }
227
+
228
+ function visitPinned(): void {
229
+ let pn = pinSpace;
230
+ let iter: Object = pn.next;
231
+ while (iter != pn) {
232
+ __visit_members(changetype<usize>(iter) + TOTAL_OVERHEAD, VISIT_SCAN);
233
+ iter = iter.next;
234
+ }
235
+ }
236
+
237
+ // @ts-ignore: decorator
238
+ @global @unsafe
239
+ export function __collect(): void {
240
+ const beforeTotal = total;
241
+
242
+ __visit_globals(VISIT_SCAN);
243
+ visitStack();
244
+ visitPinned();
245
+
246
+ let iter: Object;
247
+ iter = toSpace.next;
248
+ while (iter != toSpace) {
249
+ if (DEBUG) assert(iter.color != white);
250
+ __visit_members(changetype<usize>(iter) + TOTAL_OVERHEAD, VISIT_SCAN);
251
+ // __visit will insert object at the end of toSpace, so we must advance after visiting.
252
+ iter = iter.next;
253
+ }
254
+
255
+ // clean up fromSpace
256
+ iter = fromSpace.next;
257
+ while (iter != fromSpace) {
258
+ const next = iter.next;
259
+ free(iter);
260
+ iter = next;
261
+ }
262
+ fromSpace.nextWithColor = changetype<usize>(fromSpace);
263
+ fromSpace.prev = fromSpace;
264
+
265
+ // Flip spaces and colors
266
+ const tmp = fromSpace;
267
+ fromSpace = toSpace;
268
+ toSpace = tmp;
269
+ white = i32(!white);
270
+
271
+ const collected = beforeTotal - total;
272
+ // when collected > GRANULARITY, we collect more objects than expect.
273
+ // In this case increasing threshold will increase ram usage, otherwise we should increase threshold.
274
+ // Then we will use roughtly real RAM usage + GRANULARITY totally.
275
+ threshold = select(beforeTotal, beforeTotal + GRANULARITY, collected > GRANULARITY);
276
+ }