toilscript 0.0.1 → 0.1.1
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.
- package/LICENSE +201 -201
- package/NOTICE +94 -94
- package/README.md +101 -114
- package/bin/asc.js +0 -0
- package/bin/asinit.js +6 -6
- package/dist/asc.generated.d.ts +10027 -0
- package/dist/asc.js +24474 -0
- package/dist/asc.js.map +7 -0
- package/dist/importmap.json +9 -0
- package/dist/toilscript.generated.d.ts +11242 -0
- package/dist/toilscript.js +337 -0
- package/dist/toilscript.js.map +7 -0
- package/dist/web.js +22 -0
- package/lib/binaryen.d.ts +2 -2
- package/lib/binaryen.js +2 -2
- package/package.json +115 -114
- package/std/README.md +6 -6
- package/std/assembly/array.ts +550 -550
- package/std/assembly/arraybuffer.ts +77 -77
- package/std/assembly/atomics.ts +127 -127
- package/std/assembly/bindings/asyncify.ts +16 -16
- package/std/assembly/bindings/dom.ts +291 -291
- package/std/assembly/bindings/node.ts +6 -6
- package/std/assembly/bitflags.ts +53 -53
- package/std/assembly/builtins.ts +2650 -2650
- package/std/assembly/byteslice.ts +177 -177
- package/std/assembly/compat.ts +2 -2
- package/std/assembly/console.ts +42 -42
- package/std/assembly/crypto.ts +9 -9
- package/std/assembly/dataview.ts +181 -181
- package/std/assembly/date.ts +375 -375
- package/std/assembly/diagnostics.ts +11 -11
- package/std/assembly/encoding.ts +151 -151
- package/std/assembly/endian.ts +45 -45
- package/std/assembly/error.ts +44 -44
- package/std/assembly/fixedarray.ts +173 -173
- package/std/assembly/fixedmap.ts +326 -326
- package/std/assembly/fixedset.ts +275 -275
- package/std/assembly/function.ts +42 -42
- package/std/assembly/index.d.ts +2892 -2891
- package/std/assembly/iterator.ts +35 -35
- package/std/assembly/map.ts +269 -269
- package/std/assembly/math.ts +3289 -3289
- package/std/assembly/memory.ts +123 -123
- package/std/assembly/number.ts +388 -388
- package/std/assembly/object.ts +36 -36
- package/std/assembly/performance.ts +9 -9
- package/std/assembly/pointer.ts +80 -80
- package/std/assembly/polyfills.ts +27 -27
- package/std/assembly/process.ts +50 -50
- package/std/assembly/reference.ts +48 -48
- package/std/assembly/regexp.ts +12 -12
- package/std/assembly/rt/README.md +83 -83
- package/std/assembly/rt/common.ts +81 -81
- package/std/assembly/rt/index-incremental.ts +2 -2
- package/std/assembly/rt/index-memory.ts +1 -1
- package/std/assembly/rt/index-minimal.ts +2 -2
- package/std/assembly/rt/index-stub.ts +1 -1
- package/std/assembly/rt/index.d.ts +37 -37
- package/std/assembly/rt/itcms.ts +419 -419
- package/std/assembly/rt/memory-runtime.ts +94 -94
- package/std/assembly/rt/rtrace.ts +15 -15
- package/std/assembly/rt/stub.ts +133 -133
- package/std/assembly/rt/tcms.ts +254 -254
- package/std/assembly/rt/tlsf.ts +592 -592
- package/std/assembly/rt.ts +90 -90
- package/std/assembly/set.ts +225 -225
- package/std/assembly/shared/feature.ts +68 -68
- package/std/assembly/shared/runtime.ts +13 -13
- package/std/assembly/shared/target.ts +11 -11
- package/std/assembly/shared/tsconfig.json +11 -11
- package/std/assembly/shared/typeinfo.ts +72 -72
- package/std/assembly/staticarray.ts +423 -423
- package/std/assembly/string.ts +850 -850
- package/std/assembly/symbol.ts +114 -114
- package/std/assembly/table.ts +16 -16
- package/std/assembly/toilscript.ts +16 -0
- package/std/assembly/tsconfig.json +6 -6
- package/std/assembly/typedarray.ts +1954 -1954
- package/std/assembly/uri.ts +17 -17
- package/std/assembly/util/bytes.ts +107 -107
- package/std/assembly/util/casemap.ts +497 -497
- package/std/assembly/util/error.ts +58 -58
- package/std/assembly/util/hash.ts +117 -117
- package/std/assembly/util/math.ts +1922 -1922
- package/std/assembly/util/memory.ts +290 -290
- package/std/assembly/util/number.ts +873 -873
- package/std/assembly/util/sort.ts +313 -313
- package/std/assembly/util/string.ts +1202 -1202
- package/std/assembly/util/uri.ts +275 -275
- package/std/assembly/vector.ts +4 -4
- package/std/assembly.json +16 -16
- package/std/portable/index.d.ts +461 -461
- package/std/portable/index.js +416 -416
- package/std/portable.json +11 -11
- package/std/types/assembly/index.d.ts +1 -1
- package/std/types/assembly/package.json +2 -2
- package/std/types/portable/index.d.ts +1 -1
- package/std/types/portable/package.json +2 -2
- package/tsconfig-base.json +13 -13
- package/util/README.md +23 -23
- package/util/browser/fs.js +1 -1
- package/util/browser/module.js +5 -5
- package/util/browser/path.js +520 -520
- package/util/browser/process.js +59 -59
- package/util/browser/url.js +23 -23
- package/util/cpu.d.ts +9 -9
- package/util/cpu.js +42 -42
- package/util/find.d.ts +6 -6
- package/util/find.js +20 -20
- package/util/node.d.ts +21 -21
- package/util/node.js +34 -34
- package/util/options.d.ts +70 -70
- package/util/options.js +262 -262
- package/util/terminal.d.ts +52 -52
- package/util/terminal.js +35 -35
- package/util/text.d.ts +26 -26
- package/util/text.js +114 -114
- package/util/tsconfig.json +9 -9
- package/util/web.d.ts +11 -11
- package/util/web.js +33 -33
package/std/assembly/rt/tcms.ts
CHANGED
|
@@ -1,254 +1,254 @@
|
|
|
1
|
-
import { BLOCK, BLOCK_OVERHEAD, OBJECT_OVERHEAD, OBJECT_MAXSIZE, TOTAL_OVERHEAD, DEBUG, TRACE, RTRACE } from "./common";
|
|
2
|
-
import { onvisit, oncollect } from "./rtrace";
|
|
3
|
-
import { E_ALLOCATION_TOO_LARGE, E_ALREADY_PINNED, E_NOT_PINNED } from "../util/error";
|
|
4
|
-
|
|
5
|
-
// === TCMS: A Two-Color Mark & Sweep garbage collector ===
|
|
6
|
-
|
|
7
|
-
// ╒═════════════╤══════════════ Colors ═══════════════════════════╕
|
|
8
|
-
// │ Color │ Meaning │
|
|
9
|
-
// ├─────────────┼─────────────────────────────────────────────────┤
|
|
10
|
-
// │ WHITE* │ Unreachable │
|
|
11
|
-
// │ BLACK* │ Reachable │
|
|
12
|
-
// │ TRANSPARENT │ Manually pinned (always reachable) │
|
|
13
|
-
// └─────────────┴─────────────────────────────────────────────────┘
|
|
14
|
-
// * flipped between cycles
|
|
15
|
-
|
|
16
|
-
// @ts-ignore: decorator
|
|
17
|
-
@lazy let white = 0;
|
|
18
|
-
// @ts-ignore: decorator
|
|
19
|
-
@inline const transparent = 3;
|
|
20
|
-
// @ts-ignore: decorator
|
|
21
|
-
@inline const COLOR_MASK = 3;
|
|
22
|
-
|
|
23
|
-
/** Size in memory of all objects currently managed by the GC. */
|
|
24
|
-
// @ts-ignore: decorator
|
|
25
|
-
@lazy let total: usize = 0;
|
|
26
|
-
|
|
27
|
-
// @ts-ignore: decorator
|
|
28
|
-
@lazy let fromSpace = initLazy(changetype<Object>(memory.data(offsetof<Object>())));
|
|
29
|
-
// @ts-ignore: decorator
|
|
30
|
-
@lazy let toSpace = initLazy(changetype<Object>(memory.data(offsetof<Object>())));
|
|
31
|
-
// @ts-ignore: decorator
|
|
32
|
-
@lazy let pinSpace = initLazy(changetype<Object>(memory.data(offsetof<Object>())));
|
|
33
|
-
|
|
34
|
-
function initLazy(space: Object): Object {
|
|
35
|
-
space.nextWithColor = changetype<usize>(space);
|
|
36
|
-
space.prev = space;
|
|
37
|
-
return space;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Visit cookie indicating scanning of an object. */
|
|
41
|
-
// @ts-ignore: decorator
|
|
42
|
-
@inline const VISIT_SCAN = 0;
|
|
43
|
-
|
|
44
|
-
// ╒═══════════════ Managed object layout (32-bit) ════════════════╕
|
|
45
|
-
// 3 2 1
|
|
46
|
-
// 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
|
|
47
|
-
// ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤
|
|
48
|
-
// │ Memory manager block │
|
|
49
|
-
// ╞═══════════════════════════════════════════════════════════╤═══╡
|
|
50
|
-
// │ next │ C │ = nextWithColor
|
|
51
|
-
// ├───────────────────────────────────────────────────────────┴───┤
|
|
52
|
-
// │ prev │
|
|
53
|
-
// ├───────────────────────────────────────────────────────────────┤
|
|
54
|
-
// │ rtId │
|
|
55
|
-
// ├───────────────────────────────────────────────────────────────┤
|
|
56
|
-
// │ rtSize │
|
|
57
|
-
// ╞>ptr═══════════════════════════════════════════════════════════╡
|
|
58
|
-
// │ ... │
|
|
59
|
-
// C: color
|
|
60
|
-
|
|
61
|
-
/** Represents a managed object in memory, consisting of a header followed by the object's data. */
|
|
62
|
-
@unmanaged class Object extends BLOCK {
|
|
63
|
-
/** Pointer to the next object with color flags stored in the alignment bits. */
|
|
64
|
-
nextWithColor: usize; // *u32
|
|
65
|
-
/** Pointer to the previous object. */
|
|
66
|
-
prev: Object; // *u32
|
|
67
|
-
/** Runtime id. */
|
|
68
|
-
rtId: u32;
|
|
69
|
-
/** Runtime size. */
|
|
70
|
-
rtSize: u32;
|
|
71
|
-
|
|
72
|
-
/** Gets the pointer to the next object. */
|
|
73
|
-
get next(): Object {
|
|
74
|
-
return changetype<Object>(this.nextWithColor & ~COLOR_MASK);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** Sets the pointer to the next object. */
|
|
78
|
-
set next(obj: Object) {
|
|
79
|
-
this.nextWithColor = changetype<usize>(obj) | (this.nextWithColor & COLOR_MASK);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** Gets this object's color. */
|
|
83
|
-
get color(): i32 {
|
|
84
|
-
return i32(this.nextWithColor & COLOR_MASK);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/** Sets this object's color. */
|
|
88
|
-
set color(color: i32) {
|
|
89
|
-
this.nextWithColor = (this.nextWithColor & ~COLOR_MASK) | color;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/** Gets the size of this object in memory. */
|
|
93
|
-
get size(): usize {
|
|
94
|
-
return BLOCK_OVERHEAD + (this.mmInfo & ~3);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/** Unlinks this object from its list. */
|
|
98
|
-
unlink(): void {
|
|
99
|
-
let next = this.next;
|
|
100
|
-
if (next == null) {
|
|
101
|
-
if (DEBUG) assert(this.prev == null && changetype<usize>(this) < __heap_base);
|
|
102
|
-
return; // static data not yet linked
|
|
103
|
-
}
|
|
104
|
-
let prev = this.prev;
|
|
105
|
-
if (DEBUG) assert(prev);
|
|
106
|
-
next.prev = prev;
|
|
107
|
-
prev.next = next;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/** Links this object to the specified list, with the given color. */
|
|
111
|
-
linkTo(list: Object, withColor: i32): void {
|
|
112
|
-
let prev = list.prev;
|
|
113
|
-
this.nextWithColor = changetype<usize>(list) | withColor;
|
|
114
|
-
this.prev = prev;
|
|
115
|
-
prev.next = this;
|
|
116
|
-
list.prev = this;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Garbage collector interface
|
|
121
|
-
|
|
122
|
-
// @ts-ignore: decorator
|
|
123
|
-
@global @unsafe
|
|
124
|
-
export function __new(size: usize, id: i32): usize {
|
|
125
|
-
if (size > OBJECT_MAXSIZE) throw new Error(E_ALLOCATION_TOO_LARGE);
|
|
126
|
-
let obj = changetype<Object>(__alloc(OBJECT_OVERHEAD + size) - BLOCK_OVERHEAD);
|
|
127
|
-
obj.rtId = id;
|
|
128
|
-
obj.rtSize = <u32>size;
|
|
129
|
-
obj.linkTo(fromSpace, white);
|
|
130
|
-
total += obj.size;
|
|
131
|
-
return changetype<usize>(obj) + TOTAL_OVERHEAD;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// @ts-ignore: decorator
|
|
135
|
-
@global @unsafe
|
|
136
|
-
export function __renew(oldPtr: usize, size: usize): usize {
|
|
137
|
-
let oldObj = changetype<Object>(oldPtr - TOTAL_OVERHEAD);
|
|
138
|
-
if (oldPtr < __heap_base) { // move to heap for simplicity
|
|
139
|
-
let newPtr = __new(size, oldObj.rtId);
|
|
140
|
-
memory.copy(newPtr, oldPtr, min(size, oldObj.rtSize));
|
|
141
|
-
return newPtr;
|
|
142
|
-
}
|
|
143
|
-
if (size > OBJECT_MAXSIZE) throw new Error(E_ALLOCATION_TOO_LARGE);
|
|
144
|
-
total -= oldObj.size;
|
|
145
|
-
let newPtr = __realloc(oldPtr - OBJECT_OVERHEAD, OBJECT_OVERHEAD + size) + OBJECT_OVERHEAD;
|
|
146
|
-
let newObj = changetype<Object>(newPtr - TOTAL_OVERHEAD);
|
|
147
|
-
newObj.rtSize = <u32>size;
|
|
148
|
-
|
|
149
|
-
// Replace with new object
|
|
150
|
-
newObj.next.prev = newObj;
|
|
151
|
-
newObj.prev.next = newObj;
|
|
152
|
-
|
|
153
|
-
total += newObj.size;
|
|
154
|
-
return newPtr;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// @ts-ignore: decorator
|
|
158
|
-
@global @unsafe
|
|
159
|
-
export function __link(parentPtr: usize, childPtr: usize, expectMultiple: bool): void {
|
|
160
|
-
// nop
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// @ts-ignore: decorator
|
|
164
|
-
@global @unsafe
|
|
165
|
-
export function __visit(ptr: usize, cookie: i32): void {
|
|
166
|
-
if (!ptr) return;
|
|
167
|
-
let obj = changetype<Object>(ptr - TOTAL_OVERHEAD);
|
|
168
|
-
if (RTRACE) if (!onvisit(obj)) return;
|
|
169
|
-
if (obj.color == white) {
|
|
170
|
-
obj.unlink(); // from fromSpace
|
|
171
|
-
obj.linkTo(toSpace, i32(!white));
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// @ts-ignore: decorator
|
|
176
|
-
@global @unsafe
|
|
177
|
-
export function __pin(ptr: usize): usize {
|
|
178
|
-
if (ptr) {
|
|
179
|
-
let obj = changetype<Object>(ptr - TOTAL_OVERHEAD);
|
|
180
|
-
if (obj.color == transparent) {
|
|
181
|
-
throw new Error(E_ALREADY_PINNED);
|
|
182
|
-
}
|
|
183
|
-
obj.unlink(); // from fromSpace
|
|
184
|
-
obj.linkTo(pinSpace, transparent);
|
|
185
|
-
}
|
|
186
|
-
return ptr;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// @ts-ignore: decorator
|
|
190
|
-
@global @unsafe
|
|
191
|
-
export function __unpin(ptr: usize): void {
|
|
192
|
-
if (!ptr) return;
|
|
193
|
-
let obj = changetype<Object>(ptr - TOTAL_OVERHEAD);
|
|
194
|
-
if (obj.color != transparent) {
|
|
195
|
-
throw new Error(E_NOT_PINNED);
|
|
196
|
-
}
|
|
197
|
-
obj.unlink(); // from pinSpace
|
|
198
|
-
obj.linkTo(fromSpace, white);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// @ts-ignore: decorator
|
|
202
|
-
@global @unsafe
|
|
203
|
-
export function __collect(): void {
|
|
204
|
-
if (TRACE) trace("GC at", 1, total);
|
|
205
|
-
|
|
206
|
-
// Mark roots (add to toSpace)
|
|
207
|
-
__visit_globals(VISIT_SCAN);
|
|
208
|
-
|
|
209
|
-
// Mark direct members of pinned objects (add to toSpace)
|
|
210
|
-
let pn = pinSpace;
|
|
211
|
-
let iter = pn.next;
|
|
212
|
-
while (iter != pn) {
|
|
213
|
-
if (DEBUG) assert(iter.color == transparent);
|
|
214
|
-
__visit_members(changetype<usize>(iter) + TOTAL_OVERHEAD, VISIT_SCAN);
|
|
215
|
-
iter = iter.next;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// Mark what's reachable from toSpace
|
|
219
|
-
let black = i32(!white);
|
|
220
|
-
let to = toSpace;
|
|
221
|
-
iter = to.next;
|
|
222
|
-
while (iter != to) {
|
|
223
|
-
if (DEBUG) assert(iter.color == black);
|
|
224
|
-
__visit_members(changetype<usize>(iter) + TOTAL_OVERHEAD, VISIT_SCAN);
|
|
225
|
-
iter = iter.next;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// Sweep what's left in fromSpace
|
|
229
|
-
let from = fromSpace;
|
|
230
|
-
iter = from.next;
|
|
231
|
-
while (iter != from) {
|
|
232
|
-
if (DEBUG) assert(iter.color == white);
|
|
233
|
-
let newNext = iter.next;
|
|
234
|
-
if (changetype<usize>(iter) < __heap_base) {
|
|
235
|
-
iter.nextWithColor = 0; // may become linked again
|
|
236
|
-
iter.prev = changetype<Object>(0);
|
|
237
|
-
} else {
|
|
238
|
-
total -= iter.size;
|
|
239
|
-
if (isDefined(__finalize)) __finalize(changetype<usize>(iter) + TOTAL_OVERHEAD);
|
|
240
|
-
__free(changetype<usize>(iter) + BLOCK_OVERHEAD);
|
|
241
|
-
}
|
|
242
|
-
iter = newNext;
|
|
243
|
-
}
|
|
244
|
-
from.nextWithColor = changetype<usize>(from);
|
|
245
|
-
from.prev = from;
|
|
246
|
-
|
|
247
|
-
// Flip spaces and colors
|
|
248
|
-
fromSpace = to;
|
|
249
|
-
toSpace = from;
|
|
250
|
-
white = black;
|
|
251
|
-
|
|
252
|
-
if (TRACE) trace("GC done at", 1, total);
|
|
253
|
-
if (RTRACE) oncollect(total);
|
|
254
|
-
}
|
|
1
|
+
import { BLOCK, BLOCK_OVERHEAD, OBJECT_OVERHEAD, OBJECT_MAXSIZE, TOTAL_OVERHEAD, DEBUG, TRACE, RTRACE } from "./common";
|
|
2
|
+
import { onvisit, oncollect } from "./rtrace";
|
|
3
|
+
import { E_ALLOCATION_TOO_LARGE, E_ALREADY_PINNED, E_NOT_PINNED } from "../util/error";
|
|
4
|
+
|
|
5
|
+
// === TCMS: A Two-Color Mark & Sweep garbage collector ===
|
|
6
|
+
|
|
7
|
+
// ╒═════════════╤══════════════ Colors ═══════════════════════════╕
|
|
8
|
+
// │ Color │ Meaning │
|
|
9
|
+
// ├─────────────┼─────────────────────────────────────────────────┤
|
|
10
|
+
// │ WHITE* │ Unreachable │
|
|
11
|
+
// │ BLACK* │ Reachable │
|
|
12
|
+
// │ TRANSPARENT │ Manually pinned (always reachable) │
|
|
13
|
+
// └─────────────┴─────────────────────────────────────────────────┘
|
|
14
|
+
// * flipped between cycles
|
|
15
|
+
|
|
16
|
+
// @ts-ignore: decorator
|
|
17
|
+
@lazy let white = 0;
|
|
18
|
+
// @ts-ignore: decorator
|
|
19
|
+
@inline const transparent = 3;
|
|
20
|
+
// @ts-ignore: decorator
|
|
21
|
+
@inline const COLOR_MASK = 3;
|
|
22
|
+
|
|
23
|
+
/** Size in memory of all objects currently managed by the GC. */
|
|
24
|
+
// @ts-ignore: decorator
|
|
25
|
+
@lazy let total: usize = 0;
|
|
26
|
+
|
|
27
|
+
// @ts-ignore: decorator
|
|
28
|
+
@lazy let fromSpace = initLazy(changetype<Object>(memory.data(offsetof<Object>())));
|
|
29
|
+
// @ts-ignore: decorator
|
|
30
|
+
@lazy let toSpace = initLazy(changetype<Object>(memory.data(offsetof<Object>())));
|
|
31
|
+
// @ts-ignore: decorator
|
|
32
|
+
@lazy let pinSpace = initLazy(changetype<Object>(memory.data(offsetof<Object>())));
|
|
33
|
+
|
|
34
|
+
function initLazy(space: Object): Object {
|
|
35
|
+
space.nextWithColor = changetype<usize>(space);
|
|
36
|
+
space.prev = space;
|
|
37
|
+
return space;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Visit cookie indicating scanning of an object. */
|
|
41
|
+
// @ts-ignore: decorator
|
|
42
|
+
@inline const VISIT_SCAN = 0;
|
|
43
|
+
|
|
44
|
+
// ╒═══════════════ Managed object layout (32-bit) ════════════════╕
|
|
45
|
+
// 3 2 1
|
|
46
|
+
// 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
|
|
47
|
+
// ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤
|
|
48
|
+
// │ Memory manager block │
|
|
49
|
+
// ╞═══════════════════════════════════════════════════════════╤═══╡
|
|
50
|
+
// │ next │ C │ = nextWithColor
|
|
51
|
+
// ├───────────────────────────────────────────────────────────┴───┤
|
|
52
|
+
// │ prev │
|
|
53
|
+
// ├───────────────────────────────────────────────────────────────┤
|
|
54
|
+
// │ rtId │
|
|
55
|
+
// ├───────────────────────────────────────────────────────────────┤
|
|
56
|
+
// │ rtSize │
|
|
57
|
+
// ╞>ptr═══════════════════════════════════════════════════════════╡
|
|
58
|
+
// │ ... │
|
|
59
|
+
// C: color
|
|
60
|
+
|
|
61
|
+
/** Represents a managed object in memory, consisting of a header followed by the object's data. */
|
|
62
|
+
@unmanaged class Object extends BLOCK {
|
|
63
|
+
/** Pointer to the next object with color flags stored in the alignment bits. */
|
|
64
|
+
nextWithColor: usize; // *u32
|
|
65
|
+
/** Pointer to the previous object. */
|
|
66
|
+
prev: Object; // *u32
|
|
67
|
+
/** Runtime id. */
|
|
68
|
+
rtId: u32;
|
|
69
|
+
/** Runtime size. */
|
|
70
|
+
rtSize: u32;
|
|
71
|
+
|
|
72
|
+
/** Gets the pointer to the next object. */
|
|
73
|
+
get next(): Object {
|
|
74
|
+
return changetype<Object>(this.nextWithColor & ~COLOR_MASK);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Sets the pointer to the next object. */
|
|
78
|
+
set next(obj: Object) {
|
|
79
|
+
this.nextWithColor = changetype<usize>(obj) | (this.nextWithColor & COLOR_MASK);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Gets this object's color. */
|
|
83
|
+
get color(): i32 {
|
|
84
|
+
return i32(this.nextWithColor & COLOR_MASK);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Sets this object's color. */
|
|
88
|
+
set color(color: i32) {
|
|
89
|
+
this.nextWithColor = (this.nextWithColor & ~COLOR_MASK) | color;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Gets the size of this object in memory. */
|
|
93
|
+
get size(): usize {
|
|
94
|
+
return BLOCK_OVERHEAD + (this.mmInfo & ~3);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Unlinks this object from its list. */
|
|
98
|
+
unlink(): void {
|
|
99
|
+
let next = this.next;
|
|
100
|
+
if (next == null) {
|
|
101
|
+
if (DEBUG) assert(this.prev == null && changetype<usize>(this) < __heap_base);
|
|
102
|
+
return; // static data not yet linked
|
|
103
|
+
}
|
|
104
|
+
let prev = this.prev;
|
|
105
|
+
if (DEBUG) assert(prev);
|
|
106
|
+
next.prev = prev;
|
|
107
|
+
prev.next = next;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Links this object to the specified list, with the given color. */
|
|
111
|
+
linkTo(list: Object, withColor: i32): void {
|
|
112
|
+
let prev = list.prev;
|
|
113
|
+
this.nextWithColor = changetype<usize>(list) | withColor;
|
|
114
|
+
this.prev = prev;
|
|
115
|
+
prev.next = this;
|
|
116
|
+
list.prev = this;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Garbage collector interface
|
|
121
|
+
|
|
122
|
+
// @ts-ignore: decorator
|
|
123
|
+
@global @unsafe
|
|
124
|
+
export function __new(size: usize, id: i32): usize {
|
|
125
|
+
if (size > OBJECT_MAXSIZE) throw new Error(E_ALLOCATION_TOO_LARGE);
|
|
126
|
+
let obj = changetype<Object>(__alloc(OBJECT_OVERHEAD + size) - BLOCK_OVERHEAD);
|
|
127
|
+
obj.rtId = id;
|
|
128
|
+
obj.rtSize = <u32>size;
|
|
129
|
+
obj.linkTo(fromSpace, white);
|
|
130
|
+
total += obj.size;
|
|
131
|
+
return changetype<usize>(obj) + TOTAL_OVERHEAD;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// @ts-ignore: decorator
|
|
135
|
+
@global @unsafe
|
|
136
|
+
export function __renew(oldPtr: usize, size: usize): usize {
|
|
137
|
+
let oldObj = changetype<Object>(oldPtr - TOTAL_OVERHEAD);
|
|
138
|
+
if (oldPtr < __heap_base) { // move to heap for simplicity
|
|
139
|
+
let newPtr = __new(size, oldObj.rtId);
|
|
140
|
+
memory.copy(newPtr, oldPtr, min(size, oldObj.rtSize));
|
|
141
|
+
return newPtr;
|
|
142
|
+
}
|
|
143
|
+
if (size > OBJECT_MAXSIZE) throw new Error(E_ALLOCATION_TOO_LARGE);
|
|
144
|
+
total -= oldObj.size;
|
|
145
|
+
let newPtr = __realloc(oldPtr - OBJECT_OVERHEAD, OBJECT_OVERHEAD + size) + OBJECT_OVERHEAD;
|
|
146
|
+
let newObj = changetype<Object>(newPtr - TOTAL_OVERHEAD);
|
|
147
|
+
newObj.rtSize = <u32>size;
|
|
148
|
+
|
|
149
|
+
// Replace with new object
|
|
150
|
+
newObj.next.prev = newObj;
|
|
151
|
+
newObj.prev.next = newObj;
|
|
152
|
+
|
|
153
|
+
total += newObj.size;
|
|
154
|
+
return newPtr;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// @ts-ignore: decorator
|
|
158
|
+
@global @unsafe
|
|
159
|
+
export function __link(parentPtr: usize, childPtr: usize, expectMultiple: bool): void {
|
|
160
|
+
// nop
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// @ts-ignore: decorator
|
|
164
|
+
@global @unsafe
|
|
165
|
+
export function __visit(ptr: usize, cookie: i32): void {
|
|
166
|
+
if (!ptr) return;
|
|
167
|
+
let obj = changetype<Object>(ptr - TOTAL_OVERHEAD);
|
|
168
|
+
if (RTRACE) if (!onvisit(obj)) return;
|
|
169
|
+
if (obj.color == white) {
|
|
170
|
+
obj.unlink(); // from fromSpace
|
|
171
|
+
obj.linkTo(toSpace, i32(!white));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// @ts-ignore: decorator
|
|
176
|
+
@global @unsafe
|
|
177
|
+
export function __pin(ptr: usize): usize {
|
|
178
|
+
if (ptr) {
|
|
179
|
+
let obj = changetype<Object>(ptr - TOTAL_OVERHEAD);
|
|
180
|
+
if (obj.color == transparent) {
|
|
181
|
+
throw new Error(E_ALREADY_PINNED);
|
|
182
|
+
}
|
|
183
|
+
obj.unlink(); // from fromSpace
|
|
184
|
+
obj.linkTo(pinSpace, transparent);
|
|
185
|
+
}
|
|
186
|
+
return ptr;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// @ts-ignore: decorator
|
|
190
|
+
@global @unsafe
|
|
191
|
+
export function __unpin(ptr: usize): void {
|
|
192
|
+
if (!ptr) return;
|
|
193
|
+
let obj = changetype<Object>(ptr - TOTAL_OVERHEAD);
|
|
194
|
+
if (obj.color != transparent) {
|
|
195
|
+
throw new Error(E_NOT_PINNED);
|
|
196
|
+
}
|
|
197
|
+
obj.unlink(); // from pinSpace
|
|
198
|
+
obj.linkTo(fromSpace, white);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// @ts-ignore: decorator
|
|
202
|
+
@global @unsafe
|
|
203
|
+
export function __collect(): void {
|
|
204
|
+
if (TRACE) trace("GC at", 1, total);
|
|
205
|
+
|
|
206
|
+
// Mark roots (add to toSpace)
|
|
207
|
+
__visit_globals(VISIT_SCAN);
|
|
208
|
+
|
|
209
|
+
// Mark direct members of pinned objects (add to toSpace)
|
|
210
|
+
let pn = pinSpace;
|
|
211
|
+
let iter = pn.next;
|
|
212
|
+
while (iter != pn) {
|
|
213
|
+
if (DEBUG) assert(iter.color == transparent);
|
|
214
|
+
__visit_members(changetype<usize>(iter) + TOTAL_OVERHEAD, VISIT_SCAN);
|
|
215
|
+
iter = iter.next;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Mark what's reachable from toSpace
|
|
219
|
+
let black = i32(!white);
|
|
220
|
+
let to = toSpace;
|
|
221
|
+
iter = to.next;
|
|
222
|
+
while (iter != to) {
|
|
223
|
+
if (DEBUG) assert(iter.color == black);
|
|
224
|
+
__visit_members(changetype<usize>(iter) + TOTAL_OVERHEAD, VISIT_SCAN);
|
|
225
|
+
iter = iter.next;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Sweep what's left in fromSpace
|
|
229
|
+
let from = fromSpace;
|
|
230
|
+
iter = from.next;
|
|
231
|
+
while (iter != from) {
|
|
232
|
+
if (DEBUG) assert(iter.color == white);
|
|
233
|
+
let newNext = iter.next;
|
|
234
|
+
if (changetype<usize>(iter) < __heap_base) {
|
|
235
|
+
iter.nextWithColor = 0; // may become linked again
|
|
236
|
+
iter.prev = changetype<Object>(0);
|
|
237
|
+
} else {
|
|
238
|
+
total -= iter.size;
|
|
239
|
+
if (isDefined(__finalize)) __finalize(changetype<usize>(iter) + TOTAL_OVERHEAD);
|
|
240
|
+
__free(changetype<usize>(iter) + BLOCK_OVERHEAD);
|
|
241
|
+
}
|
|
242
|
+
iter = newNext;
|
|
243
|
+
}
|
|
244
|
+
from.nextWithColor = changetype<usize>(from);
|
|
245
|
+
from.prev = from;
|
|
246
|
+
|
|
247
|
+
// Flip spaces and colors
|
|
248
|
+
fromSpace = to;
|
|
249
|
+
toSpace = from;
|
|
250
|
+
white = black;
|
|
251
|
+
|
|
252
|
+
if (TRACE) trace("GC done at", 1, total);
|
|
253
|
+
if (RTRACE) oncollect(total);
|
|
254
|
+
}
|