xbintsc 0.3.35 → 0.3.46
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/README.md +6 -3
- package/dist/src/codegen/generator/module.js +10 -0
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.js +4 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/tests/e2e/gc.test.d.ts +1 -0
- package/dist/tests/e2e/gc.test.js +168 -0
- package/dist/tests/e2e/gc.test.js.map +1 -0
- package/dist/tests/e2e/harness.d.ts +2 -0
- package/dist/tests/e2e/harness.js +1 -0
- package/dist/tests/e2e/harness.js.map +1 -1
- package/package.json +3 -2
- package/runtime/ext_gui/dom_api_proto.cpp +5 -0
- package/runtime/ext_gui/window.cpp +1 -0
- package/runtime/ext_node/buffer/parts/prototype.inc +1 -0
- package/runtime/ext_node/dgram/dgram.c +1 -0
- package/runtime/ext_node/events/events.c +1 -0
- package/runtime/ext_node/fs/fs_ops.c +10 -25
- package/runtime/ext_node/fs/glob.c +13 -30
- package/runtime/ext_node/fs/promises.c +1 -0
- package/runtime/ext_node/http/parts/prototypes.inc +5 -0
- package/runtime/ext_node/net/parts/prototypes.inc +2 -0
- package/runtime/ext_node/process/process.c +9 -7
- package/runtime/ext_node/stream/stream.c +1 -0
- package/runtime/ext_node/util/util.c +6 -6
- package/runtime/rt.h +10 -0
- package/runtime/rt_internal.h +63 -2
- package/runtime/xt_alloc.c +442 -5
- package/runtime/xt_generator.c +95 -1
- package/runtime/xt_loop.c +35 -1
- package/runtime/xt_promise.c +46 -0
- package/runtime/xt_stdlib2/error.inc +1 -0
- package/runtime/xt_stdlib2/regexp-match.inc +8 -7
- package/runtime/xt_symbol.c +2 -0
- package/runtime/xt_typed_array/construction.inc +142 -0
- package/runtime/xt_typed_array/elements.inc +92 -0
- package/runtime/xt_typed_array/methods.inc +329 -0
- package/runtime/xt_typed_array.c +6 -548
- package/runtime/xt_values/number-format.inc +26 -0
- package/scripts/check-file-length.ts +85 -0
- package/src/codegen/generator/module.ts +10 -0
- package/src/codegen/generator/state.ts +4 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
static xt_value xt_http_server_proto(void) {
|
|
4
4
|
static xt_value proto = 0;
|
|
5
|
+
xt_gc_add_root(&proto);
|
|
5
6
|
if (proto) return proto;
|
|
6
7
|
proto = xt_object_new();
|
|
7
8
|
xt_node_install_emitter(proto);
|
|
@@ -13,6 +14,7 @@ static xt_value xt_http_server_proto(void) {
|
|
|
13
14
|
|
|
14
15
|
static xt_value xt_http_response_proto(void) {
|
|
15
16
|
static xt_value proto = 0;
|
|
17
|
+
xt_gc_add_root(&proto);
|
|
16
18
|
if (proto) return proto;
|
|
17
19
|
proto = xt_object_new();
|
|
18
20
|
xt_node_install_emitter(proto);
|
|
@@ -28,6 +30,7 @@ static xt_value xt_http_response_proto(void) {
|
|
|
28
30
|
|
|
29
31
|
static xt_value xt_http_request_proto(void) {
|
|
30
32
|
static xt_value proto = 0;
|
|
33
|
+
xt_gc_add_root(&proto);
|
|
31
34
|
if (proto) return proto;
|
|
32
35
|
proto = xt_object_new();
|
|
33
36
|
xt_node_install_emitter(proto);
|
|
@@ -37,6 +40,7 @@ static xt_value xt_http_request_proto(void) {
|
|
|
37
40
|
|
|
38
41
|
static xt_value xt_http_client_proto(void) {
|
|
39
42
|
static xt_value proto = 0;
|
|
43
|
+
xt_gc_add_root(&proto);
|
|
40
44
|
if (proto) return proto;
|
|
41
45
|
proto = xt_object_new();
|
|
42
46
|
xt_node_install_emitter(proto);
|
|
@@ -49,6 +53,7 @@ static xt_value xt_http_client_proto(void) {
|
|
|
49
53
|
|
|
50
54
|
static xt_value xt_http_client_response_proto(void) {
|
|
51
55
|
static xt_value proto = 0;
|
|
56
|
+
xt_gc_add_root(&proto);
|
|
52
57
|
if (proto) return proto;
|
|
53
58
|
proto = xt_object_new();
|
|
54
59
|
xt_node_install_emitter(proto);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
static xt_value xt_net_socket_proto(void) {
|
|
4
4
|
static xt_value proto = 0;
|
|
5
|
+
xt_gc_add_root(&proto);
|
|
5
6
|
if (proto) return proto;
|
|
6
7
|
proto = xt_object_new();
|
|
7
8
|
xt_node_install_emitter(proto);
|
|
@@ -22,6 +23,7 @@ static xt_value xt_net_socket_proto(void) {
|
|
|
22
23
|
|
|
23
24
|
static xt_value xt_net_server_proto(void) {
|
|
24
25
|
static xt_value proto = 0;
|
|
26
|
+
xt_gc_add_root(&proto);
|
|
25
27
|
if (proto) return proto;
|
|
26
28
|
proto = xt_object_new();
|
|
27
29
|
xt_node_install_emitter(proto);
|
|
@@ -70,16 +70,18 @@ static xt_value xt_process_env(void) {
|
|
|
70
70
|
|
|
71
71
|
static xt_value xt_process_argv(void) {
|
|
72
72
|
int32_t count = xt_program_argc;
|
|
73
|
-
|
|
73
|
+
/* Fill an `xt_array` element by element rather than a raw `xt_value` buffer:
|
|
74
|
+
the collector cannot see a plain malloc'd buffer, so strings created here
|
|
75
|
+
would be swept as soon as a later element allocates (demonstrated by
|
|
76
|
+
`process.argv` returning recycled strings under GC stress). The array is a
|
|
77
|
+
stack local, so the conservative scan keeps it and its elements alive. */
|
|
78
|
+
xt_value result = xt_array_new(0, NULL);
|
|
79
|
+
if (count <= 0 || !xt_program_argv) return result;
|
|
74
80
|
/* Node semantics: `[execPath, scriptPath, ...args]`. A standalone binary is
|
|
75
81
|
both the executable and the script, so the executable path is repeated;
|
|
76
82
|
user arguments therefore start at index 2, matching `node script.js a b`. */
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
items[0] = xt_string_from_cstr(xt_program_argv[0]);
|
|
80
|
-
for (int32_t i = 0; i < count; i++) items[i + 1] = xt_string_from_cstr(xt_program_argv[i]);
|
|
81
|
-
xt_value result = xt_array_new(count + 1, items);
|
|
82
|
-
free(items);
|
|
83
|
+
xt_array_push(result, xt_string_from_cstr(xt_program_argv[0]));
|
|
84
|
+
for (int32_t i = 0; i < count; i++) xt_array_push(result, xt_string_from_cstr(xt_program_argv[i]));
|
|
83
85
|
return result;
|
|
84
86
|
}
|
|
85
87
|
|
|
@@ -363,6 +363,7 @@ xt_value xt_stream_static(xt_value name, int32_t argc, xt_value *argv) {
|
|
|
363
363
|
|
|
364
364
|
static xt_value xt_stream_proto(void) {
|
|
365
365
|
static xt_value proto = 0;
|
|
366
|
+
xt_gc_add_root(&proto);
|
|
366
367
|
if (proto) return proto;
|
|
367
368
|
proto = xt_object_new();
|
|
368
369
|
xt_node_install_emitter(proto);
|
|
@@ -363,13 +363,13 @@ static xt_value util_promisify_executor(xt_value thisValue, xt_value env, int32_
|
|
|
363
363
|
xt_value resolve = xt_arg(argc, argv, 0);
|
|
364
364
|
xt_value reject = xt_arg(argc, argv, 1);
|
|
365
365
|
int32_t count = (int32_t)xt_to_number(xt_array_length(args));
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
366
|
+
/* An `xt_array` keeps the arguments, and the freshly created callback
|
|
367
|
+
closure, reachable if the call below triggers a collection. */
|
|
368
|
+
xt_value argArray = xt_array_new(0, NULL);
|
|
369
|
+
for (int32_t i = 0; i < count; i++) xt_array_push(argArray, xt_array_get(args, xt_number((double)i)));
|
|
369
370
|
xt_value callbackEnv[2] = {resolve, reject};
|
|
370
|
-
|
|
371
|
-
if (XT_IS_FUNCTION(fn)) xt_closure_call(fn, count + 1,
|
|
372
|
-
free(callArgs);
|
|
371
|
+
xt_array_push(argArray, xt_closure_new((void *)util_promisify_callback, 2, callbackEnv));
|
|
372
|
+
if (XT_IS_FUNCTION(fn)) xt_closure_call(fn, count + 1, xt_as_array(argArray)->items);
|
|
373
373
|
return xt_undefined();
|
|
374
374
|
}
|
|
375
375
|
|
package/runtime/rt.h
CHANGED
|
@@ -362,6 +362,16 @@ void xt_println(xt_value v);
|
|
|
362
362
|
size_t xt_heap_bytes(void);
|
|
363
363
|
size_t xt_heap_allocations(void);
|
|
364
364
|
|
|
365
|
+
/* -- garbage collector ---------------------------------------------------- */
|
|
366
|
+
/**
|
|
367
|
+
* Register `slot` as a GC root: a static prototype cache or any value cell
|
|
368
|
+
* that lives outside the heap graph. The slot may be registered before it
|
|
369
|
+
* holds a value; it is marked on every collection and registration is
|
|
370
|
+
* idempotent. `xt_gc_add_root_range` registers `count` consecutive cells.
|
|
371
|
+
*/
|
|
372
|
+
void xt_gc_add_root(xt_value *slot);
|
|
373
|
+
void xt_gc_add_root_range(xt_value *base, size_t count);
|
|
374
|
+
|
|
365
375
|
#ifdef __cplusplus
|
|
366
376
|
}
|
|
367
377
|
#endif
|
package/runtime/rt_internal.h
CHANGED
|
@@ -52,7 +52,8 @@
|
|
|
52
52
|
#define XT_OBJECT_KIND_GENERATOR 13
|
|
53
53
|
#define XT_OBJECT_KIND_ITERATOR 14
|
|
54
54
|
|
|
55
|
-
/* Common header for every heap object.
|
|
55
|
+
/* Common header for every heap object. `flags` bit 0 is the collector's mark
|
|
56
|
+
* bit; it is cleared on every surviving object at the end of a sweep. */
|
|
56
57
|
typedef struct xt_header {
|
|
57
58
|
uint8_t kind;
|
|
58
59
|
uint8_t flags;
|
|
@@ -61,6 +62,8 @@ typedef struct xt_header {
|
|
|
61
62
|
struct xt_header *gc_next;
|
|
62
63
|
} xt_header;
|
|
63
64
|
|
|
65
|
+
#define XT_GC_MARK 0x01u
|
|
66
|
+
|
|
64
67
|
typedef struct {
|
|
65
68
|
xt_header header;
|
|
66
69
|
uint32_t length;
|
|
@@ -122,9 +125,67 @@ typedef struct {
|
|
|
122
125
|
uint8_t is_generator;
|
|
123
126
|
} xt_function;
|
|
124
127
|
|
|
125
|
-
/* Allocation (xt_alloc.c).
|
|
128
|
+
/* Allocation and garbage collection (xt_alloc.c).
|
|
129
|
+
*
|
|
130
|
+
* The collector is a non-moving mark-sweep over the linked list of every
|
|
131
|
+
* allocation. Roots are (a) explicitly registered value slots, (b) root
|
|
132
|
+
* providers registered by runtime subsystems and extensions, and (c) a
|
|
133
|
+
* conservative scan of the active C stack (plus a setjmp buffer for the
|
|
134
|
+
* callee-saved registers). Heap objects are traced precisely for their own
|
|
135
|
+
* value fields, with a conservative scan of their payload for the raw pointer
|
|
136
|
+
* fields that older code still stores directly. */
|
|
126
137
|
void *xt_alloc(size_t size, int kind);
|
|
127
138
|
|
|
139
|
+
/* Record the current stack as the base of the root set. Call once, as early as
|
|
140
|
+
* possible, before any allocation (generated `main` does this). */
|
|
141
|
+
void xt_gc_init(void);
|
|
142
|
+
/* Record the high bound of the main stack. The generated `main` passes the
|
|
143
|
+
* address of one of its own locals, which lives above every frame its callees
|
|
144
|
+
* ever use, so the conservative scan reaches spilled roots. Without this the
|
|
145
|
+
* bound would be taken from inside the runtime and would cut off the top of
|
|
146
|
+
* the caller's frame. Safe to call before `xt_gc_init`. */
|
|
147
|
+
void xt_gc_set_stack_base(void *base);
|
|
148
|
+
/* Enable automatic collection once the heap crosses the threshold. Programs
|
|
149
|
+
* that never arm the collector still get `xt_gc_collect()` on demand. */
|
|
150
|
+
void xt_gc_arm(void);
|
|
151
|
+
/* Run a full collection now. Re-entrant calls are ignored. */
|
|
152
|
+
void xt_gc_collect(void);
|
|
153
|
+
/* Override the automatic trigger threshold (bytes of live heap). */
|
|
154
|
+
void xt_gc_set_threshold(size_t bytes);
|
|
155
|
+
|
|
156
|
+
/* Explicit roots: the address of a slot that always holds a live value (a
|
|
157
|
+
* module global, a runtime prototype cache, ...). */
|
|
158
|
+
void xt_gc_add_root(xt_value *slot);
|
|
159
|
+
void xt_gc_add_root_range(xt_value *base, size_t count);
|
|
160
|
+
/* Subsystems whose live set is not reachable through value slots (the event
|
|
161
|
+
* loop's timers, the promise microtask queue, ...) register a provider that
|
|
162
|
+
* marks its reachable objects. Providers run during every collection. */
|
|
163
|
+
void xt_gc_register_root_provider(void (*provider)(void));
|
|
164
|
+
|
|
165
|
+
/* Track the active C stack so the conservative scan has an upper bound. The
|
|
166
|
+
* initial region is installed by `xt_gc_init`; each generator pushes its own
|
|
167
|
+
* private stack while it runs. Before switching to a deeper region the caller
|
|
168
|
+
* records where its own stack was suspended, so every active region is scanned
|
|
169
|
+
* and suspended callers stay reachable. */
|
|
170
|
+
void xt_gc_push_stack(uintptr_t low, uintptr_t high);
|
|
171
|
+
/* Mark the currently-executing region as suspended at `sp` (its frames above
|
|
172
|
+
* `sp` stay live while a deeper generator region runs). */
|
|
173
|
+
void xt_gc_suspend(uintptr_t sp);
|
|
174
|
+
void xt_gc_pop_stack(void);
|
|
175
|
+
|
|
176
|
+
/* Marking primitives used by root providers and per-kind trace hooks. */
|
|
177
|
+
void xt_gc_mark_value(xt_value value);
|
|
178
|
+
void xt_gc_mark_header(xt_header *header);
|
|
179
|
+
/* Conservatively mark every pointer-sized word in `[base, base + bytes)`. */
|
|
180
|
+
void xt_gc_scan_region(const void *base, size_t bytes);
|
|
181
|
+
|
|
182
|
+
/* Kind-specific hooks for allocations with separately allocated sub-objects.
|
|
183
|
+
* Implemented by the translation unit that owns the representation. */
|
|
184
|
+
void xt_promise_gc_trace(xt_header *header);
|
|
185
|
+
void xt_promise_gc_release(xt_header *header);
|
|
186
|
+
void xt_generator_gc_trace(xt_header *header);
|
|
187
|
+
void xt_generator_gc_release(xt_header *header);
|
|
188
|
+
|
|
128
189
|
/* Value / string helpers shared across translation units (xt_values.c). */
|
|
129
190
|
xt_string *xt_string_alloc(size_t length);
|
|
130
191
|
xt_string *xt_as_string(xt_value value);
|