@scriptc/cli-darwin-x64 0.2.3 → 0.2.4
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/dist/THIRD_PARTY_NOTICES +1 -1
- package/dist/bin/scriptc +0 -0
- package/dist/bin/scriptc.json +1 -1
- package/dist/lib/llvm/bin/scriptc-llvm-codegen +0 -0
- package/dist/lib/llvm/package.json +1 -1
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/package.json +1 -1
- package/dist/lib/runtime-darwin-x64/runtime-pack.json +129 -129
- package/dist/lib/runtime-sources/package.json +1 -1
- package/dist/lib/runtime-sources/src/scr_array.c +50 -34
- package/dist/lib/runtime-sources/src/scr_bigint.c +15 -0
- package/dist/lib/runtime-sources/src/scr_cycle.c +84 -60
- package/dist/lib/runtime-sources/src/scr_json.c +15 -11
- package/dist/lib/runtime-sources/src/scr_lib.c +45 -16
- package/dist/lib/runtime-sources/src/scr_map.c +228 -40
- package/dist/lib/runtime-sources/src/scr_regex.c +47 -8
- package/dist/lib/runtime-sources/src/scr_runtime.h +39 -13
- package/dist/lib/runtime-sources/src/scr_string.c +29 -0
- package/package.json +1 -1
|
@@ -434,8 +434,10 @@ ScrArr *scr_arr_new(ScrElemKind elem, size_t initial_cap) {
|
|
|
434
434
|
* below releases none — the complement contract in scr_runtime.h. */
|
|
435
435
|
void scr_arr_trace_v(void *a0, ScrTraceVisit visit, void *ctx) {
|
|
436
436
|
ScrArr *a = (ScrArr *)a0;
|
|
437
|
-
visit(a->metadata, ctx);
|
|
438
|
-
|
|
437
|
+
if (a->metadata) visit(a->metadata, ctx);
|
|
438
|
+
/* Growth and truncation leave spare capacity empty. Sparse slots and
|
|
439
|
+
* named properties are separate edges, independent of dense length. */
|
|
440
|
+
for (size_t i = 0, end = a->len < a->cap ? a->len : a->cap; i < end; i++) {
|
|
439
441
|
if (a->present[i] == SCR_ARR_VALUE) visit(scr_slot_to_ptr(a->data[i]), ctx);
|
|
440
442
|
}
|
|
441
443
|
for (size_t i = 0; i < a->sparse_len; i++) {
|
|
@@ -503,7 +505,7 @@ void scr_arr_release(ScrArr *a) {
|
|
|
503
505
|
scr_dyn_release(a->metadata);
|
|
504
506
|
a->metadata = NULL;
|
|
505
507
|
if (scr_elem_is_ref(a->elem)) {
|
|
506
|
-
for (size_t i = 0
|
|
508
|
+
for (size_t i = 0, end = a->len < a->cap ? a->len : a->cap; i < end; i++) {
|
|
507
509
|
if (a->present[i] != SCR_ARR_HOLE) {
|
|
508
510
|
uint64_t old = a->data[i];
|
|
509
511
|
uint8_t state = a->present[i];
|
|
@@ -1333,21 +1335,26 @@ bool scr_arr_includes_ref(ScrArr *a, void *v) {
|
|
|
1333
1335
|
|
|
1334
1336
|
/* ── join ──────────────────────────────────────────────────────────────── */
|
|
1335
1337
|
|
|
1336
|
-
static
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1338
|
+
static size_t scr_join_size(size_t len, size_t extra) {
|
|
1339
|
+
if (extra > SIZE_MAX - sizeof(ScrStr) - 1 - len) scr_arr_oom();
|
|
1340
|
+
return len + extra;
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
/* The builder owns the final string allocation throughout construction.
|
|
1344
|
+
* It has no aliases or index-cache entries, and no user callbacks run while
|
|
1345
|
+
* appending primitive array values. Finish by publishing the terminator. */
|
|
1346
|
+
static void scr_join_append(ScrStr **out, const char *bytes, size_t n) {
|
|
1347
|
+
ScrStr *s = *out;
|
|
1348
|
+
size_t need = scr_join_size(s->len, n);
|
|
1349
|
+
if (need > s->cap) {
|
|
1350
|
+
const size_t limit = SIZE_MAX - sizeof(ScrStr) - 1;
|
|
1351
|
+
size_t cap = s->cap;
|
|
1352
|
+
while (cap < need) cap = cap > limit / 2 ? need : cap * 2;
|
|
1353
|
+
s = scr_str_regrow(s, cap);
|
|
1354
|
+
*out = s;
|
|
1348
1355
|
}
|
|
1349
|
-
memcpy(
|
|
1350
|
-
|
|
1356
|
+
memcpy(s->data + s->len, bytes, n);
|
|
1357
|
+
s->len = need;
|
|
1351
1358
|
}
|
|
1352
1359
|
|
|
1353
1360
|
/* `a.slice(start?, end?)` — a fresh shallow copy of the index range,
|
|
@@ -1390,11 +1397,24 @@ ScrArr *scr_arr_slice(ScrArr *a, double start, double end) {
|
|
|
1390
1397
|
}
|
|
1391
1398
|
|
|
1392
1399
|
ScrStr *scr_arr_join(ScrArr *a, ScrStr *sep) {
|
|
1393
|
-
size_t cap = 64
|
|
1394
|
-
|
|
1395
|
-
|
|
1400
|
+
size_t cap = 64;
|
|
1401
|
+
/* String widths are already known. Size once to avoid growth and copying
|
|
1402
|
+
* even when the array holds holes, explicit undefined or sparse slots.
|
|
1403
|
+
* Numeric formatting stays single-pass rather than formatting twice. */
|
|
1404
|
+
if (a->elem == SCR_ELEM_STR) {
|
|
1405
|
+
const size_t limit = SIZE_MAX - sizeof(ScrStr) - 1;
|
|
1406
|
+
if (a->len > 1 && sep->len > limit / (a->len - 1)) scr_arr_oom();
|
|
1407
|
+
cap = a->len > 1 ? (a->len - 1) * sep->len : 0;
|
|
1408
|
+
for (size_t i = 0; i < a->len; i++) {
|
|
1409
|
+
uint64_t slot;
|
|
1410
|
+
if (scr_arr_state_at(a, i, &slot) != SCR_ARR_VALUE) continue;
|
|
1411
|
+
const ScrStr *s = (const ScrStr *)scr_slot_to_ptr(slot);
|
|
1412
|
+
if (s) cap = scr_join_size(cap, s->len);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
ScrStr *out = scr_str_alloc_raw(0, cap);
|
|
1396
1416
|
for (size_t i = 0; i < a->len; i++) {
|
|
1397
|
-
if (i > 0) scr_join_append(&
|
|
1417
|
+
if (i > 0) scr_join_append(&out, sep->data, sep->len);
|
|
1398
1418
|
uint64_t slot;
|
|
1399
1419
|
uint8_t state = scr_arr_state_at(a, i, &slot);
|
|
1400
1420
|
if (state != SCR_ARR_VALUE) continue;
|
|
@@ -1402,16 +1422,16 @@ ScrStr *scr_arr_join(ScrArr *a, ScrStr *sep) {
|
|
|
1402
1422
|
case SCR_ELEM_F64: {
|
|
1403
1423
|
char nb[32];
|
|
1404
1424
|
size_t n = scr_f64_to_str(scr_slot_to_f64(slot), nb);
|
|
1405
|
-
scr_join_append(&
|
|
1425
|
+
scr_join_append(&out, nb, n);
|
|
1406
1426
|
break;
|
|
1407
1427
|
}
|
|
1408
1428
|
case SCR_ELEM_BOOL:
|
|
1409
|
-
if (slot != 0) scr_join_append(&
|
|
1410
|
-
else scr_join_append(&
|
|
1429
|
+
if (slot != 0) scr_join_append(&out, "true", 4);
|
|
1430
|
+
else scr_join_append(&out, "false", 5);
|
|
1411
1431
|
break;
|
|
1412
1432
|
case SCR_ELEM_STR: {
|
|
1413
1433
|
const ScrStr *s = (const ScrStr *)scr_slot_to_ptr(slot);
|
|
1414
|
-
if (s) scr_join_append(&
|
|
1434
|
+
if (s) scr_join_append(&out, s->data, s->len);
|
|
1415
1435
|
break;
|
|
1416
1436
|
}
|
|
1417
1437
|
case SCR_ELEM_ARR:
|
|
@@ -1421,8 +1441,7 @@ ScrStr *scr_arr_join(ScrArr *a, ScrStr *sep) {
|
|
|
1421
1441
|
scr_trap("scriptc: internal error: join on a ref-element array\n");
|
|
1422
1442
|
}
|
|
1423
1443
|
}
|
|
1424
|
-
|
|
1425
|
-
free(buf);
|
|
1444
|
+
out->data[out->len] = '\0';
|
|
1426
1445
|
return out;
|
|
1427
1446
|
}
|
|
1428
1447
|
|
|
@@ -1432,25 +1451,22 @@ ScrStr *scr_arr_join(ScrArr *a, ScrStr *sep) {
|
|
|
1432
1451
|
* missing ones skip, exactly the spec's loop. Both arrays are
|
|
1433
1452
|
* SCR_ELEM_STR; borrows both; +1 result. Never throws. */
|
|
1434
1453
|
ScrStr *scr_str_raw(ScrArr *raw, ScrArr *subs) {
|
|
1435
|
-
|
|
1436
|
-
char *buf = malloc(cap);
|
|
1437
|
-
if (!buf) scr_arr_oom();
|
|
1454
|
+
ScrStr *out = scr_str_alloc_raw(0, 64);
|
|
1438
1455
|
for (size_t i = 0; i < raw->len; i++) {
|
|
1439
1456
|
uint64_t raw_slot;
|
|
1440
1457
|
if (scr_arr_slot_at(raw, i, &raw_slot)) {
|
|
1441
1458
|
const ScrStr *s = (const ScrStr *)scr_slot_to_ptr(raw_slot);
|
|
1442
|
-
if (s) scr_join_append(&
|
|
1459
|
+
if (s) scr_join_append(&out, s->data, s->len);
|
|
1443
1460
|
}
|
|
1444
1461
|
if (i + 1 < raw->len && i < subs->len) {
|
|
1445
1462
|
uint64_t sub_slot;
|
|
1446
1463
|
if (scr_arr_slot_at(subs, i, &sub_slot)) {
|
|
1447
1464
|
const ScrStr *v = (const ScrStr *)scr_slot_to_ptr(sub_slot);
|
|
1448
|
-
if (v) scr_join_append(&
|
|
1465
|
+
if (v) scr_join_append(&out, v->data, v->len);
|
|
1449
1466
|
}
|
|
1450
1467
|
}
|
|
1451
1468
|
}
|
|
1452
|
-
|
|
1453
|
-
free(buf);
|
|
1469
|
+
out->data[out->len] = '\0';
|
|
1454
1470
|
return out;
|
|
1455
1471
|
}
|
|
1456
1472
|
|
|
@@ -132,6 +132,21 @@ static int bi_cmp(const ScrBigInt *a, const ScrBigInt *b) {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
bool scr_bigint_eq(ScrBigInt *a, ScrBigInt *b) { return bi_cmp(a, b) == 0; }
|
|
135
|
+
|
|
136
|
+
uint64_t scr_bigint_hash(const ScrBigInt *value) {
|
|
137
|
+
/* BigInts are immutable and normalized. Ignore capacity and ownership;
|
|
138
|
+
* equal values made by parsing, arithmetic or conversion hash alike. */
|
|
139
|
+
uint64_t hash = UINT64_C(0xcbf29ce484222325) ^ (uint64_t)(value->sign + 1);
|
|
140
|
+
for (size_t i = 0; i < value->len; i++) {
|
|
141
|
+
hash ^= value->limb[i];
|
|
142
|
+
hash *= UINT64_C(0x100000001b3);
|
|
143
|
+
}
|
|
144
|
+
hash ^= hash >> 30;
|
|
145
|
+
hash *= UINT64_C(0xbf58476d1ce4e5b9);
|
|
146
|
+
hash ^= hash >> 27;
|
|
147
|
+
hash *= UINT64_C(0x94d049bb133111eb);
|
|
148
|
+
return hash ^ (hash >> 31);
|
|
149
|
+
}
|
|
135
150
|
double scr_bigint_cmp_f64(ScrBigInt *a, ScrBigInt *b) { return (double)bi_cmp(a, b); }
|
|
136
151
|
bool scr_bigint_truthy(ScrBigInt *v) { return v->sign != 0; }
|
|
137
152
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* markGray trial-delete: decrement rc once per internal edge;
|
|
10
10
|
* scan nodes still rc > 0 are externally referenced — re-blacken
|
|
11
11
|
* their subgraph and restore the trial decrements;
|
|
12
|
-
*
|
|
12
|
+
* gather filter the scanned white set, then free it, releasing
|
|
13
13
|
* only edges that LEAVE the white set (each member's
|
|
14
14
|
* teardown releases its untraced children; traced edges were
|
|
15
15
|
* already accounted by markGray).
|
|
@@ -26,9 +26,10 @@
|
|
|
26
26
|
* count was already given up (which would over-decrement and free live
|
|
27
27
|
* data).
|
|
28
28
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
29
|
+
* The main graph phases keep a bounded depth-first walk and defer deeper
|
|
30
|
+
* traces to reusable worklists. Ordinary RC destruction and cross-generation
|
|
31
|
+
* releases are separate paths. White candidates are recorded during scan
|
|
32
|
+
* and filtered after outside roots settle, avoiding a separate gather walk.
|
|
32
33
|
*
|
|
33
34
|
* ── generations ──────────────────────────────────────────────────────
|
|
34
35
|
* A pass costs O(objects reachable from its candidates), and a candidate
|
|
@@ -154,6 +155,12 @@ static SCR_TL ScrVec scr_cands;
|
|
|
154
155
|
/* Nursery survivors awaiting promotion (see scr_scan_black). */
|
|
155
156
|
static SCR_TL ScrVec scr_promote;
|
|
156
157
|
|
|
158
|
+
/* Deferred traces cap recursive traversal without changing the common
|
|
159
|
+
* depth-first walk. Restore can run inside scan, so it has its own stack. */
|
|
160
|
+
static SCR_TL ScrVec scr_pending;
|
|
161
|
+
static SCR_TL ScrVec scr_restore_pending;
|
|
162
|
+
#define SCR_CYC_WALK_DEPTH 64
|
|
163
|
+
|
|
157
164
|
/* The gathered white set (freed after the walk completes). */
|
|
158
165
|
static SCR_TL ScrVec scr_white;
|
|
159
166
|
|
|
@@ -281,14 +288,15 @@ void scr_cyc_on_dead(void *obj) {
|
|
|
281
288
|
void scr_cyc_on_release(void *obj) {
|
|
282
289
|
ScrCycHdr *h = scr_cyc_hdr(obj);
|
|
283
290
|
h->color = SCR_CYC_PURPLE;
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
291
|
+
/* Releasing an existing candidate cannot advance the trigger. A pass
|
|
292
|
+
* always re-arms after its teardowns, including any candidates they add. */
|
|
293
|
+
if (h->buffered) return;
|
|
294
|
+
ScrVec *b = &scr_roots[h->gen];
|
|
295
|
+
if (b->n == b->cap) scr_cyc_grow(b);
|
|
296
|
+
h->buffered = 1;
|
|
297
|
+
h->buf_index = b->n;
|
|
298
|
+
b->v[b->n++] = obj;
|
|
299
|
+
scr_cyc_nbuffered++;
|
|
292
300
|
/* Never re-entered: a teardown's releases of untraced children can buffer
|
|
293
301
|
* new candidates mid-collection, but they only wait for the next pass. */
|
|
294
302
|
if (!scr_collecting && scr_cyc_nbuffered >= scr_cyc_trigger)
|
|
@@ -306,69 +314,68 @@ void scr_cyc_on_release(void *obj) {
|
|
|
306
314
|
((child) == NULL || SCR_RC(child) == SIZE_MAX \
|
|
307
315
|
|| scr_cyc_hdr(child)->gen > scr_gen_limit)
|
|
308
316
|
|
|
309
|
-
|
|
317
|
+
/* Trace callbacks forward an integer depth through their opaque context;
|
|
318
|
+
* it is never dereferenced. The ABI already carries it through every edge. */
|
|
319
|
+
static void scr_mark_gray(void *obj, uintptr_t depth);
|
|
310
320
|
static void scr_mg_visit(void *child, void *ctx) {
|
|
311
|
-
(void)ctx;
|
|
312
321
|
if (SCR_CYC_SKIP(child)) return;
|
|
313
|
-
SCR_RC(child) -= 1;
|
|
314
|
-
scr_mark_gray(child);
|
|
322
|
+
SCR_RC(child) -= 1;
|
|
323
|
+
scr_mark_gray(child, (uintptr_t)ctx);
|
|
315
324
|
}
|
|
316
|
-
static void scr_mark_gray(void *obj) {
|
|
325
|
+
static void scr_mark_gray(void *obj, uintptr_t depth) {
|
|
317
326
|
ScrCycHdr *h = scr_cyc_hdr(obj);
|
|
318
327
|
if (h->color == SCR_CYC_GRAY) return;
|
|
319
328
|
h->color = SCR_CYC_GRAY;
|
|
320
|
-
|
|
329
|
+
if (depth == SCR_CYC_WALK_DEPTH) {
|
|
330
|
+
scr_cyc_push(&scr_pending, obj);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
h->trace(obj, scr_mg_visit, (void *)(depth + 1));
|
|
321
334
|
}
|
|
322
335
|
|
|
323
|
-
static void scr_scan_black(void *obj);
|
|
336
|
+
static void scr_scan_black(void *obj, uintptr_t depth);
|
|
324
337
|
static void scr_sb_visit(void *child, void *ctx) {
|
|
325
|
-
(void)ctx;
|
|
326
338
|
if (SCR_CYC_SKIP(child)) return;
|
|
327
|
-
SCR_RC(child) += 1;
|
|
328
|
-
if (scr_cyc_hdr(child)->color != SCR_CYC_BLACK)
|
|
339
|
+
SCR_RC(child) += 1;
|
|
340
|
+
if (scr_cyc_hdr(child)->color != SCR_CYC_BLACK)
|
|
341
|
+
scr_scan_black(child, (uintptr_t)ctx);
|
|
329
342
|
}
|
|
330
|
-
static void scr_scan_black(void *obj) {
|
|
343
|
+
static void scr_scan_black(void *obj, uintptr_t depth) {
|
|
331
344
|
ScrCycHdr *h = scr_cyc_hdr(obj);
|
|
332
345
|
h->color = SCR_CYC_BLACK;
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
h->trace(obj, scr_sb_visit, NULL);
|
|
346
|
+
if (h->gen < SCR_CYC_MATURE) scr_cyc_push(&scr_promote, obj);
|
|
347
|
+
if (depth == SCR_CYC_WALK_DEPTH) {
|
|
348
|
+
scr_cyc_push(&scr_restore_pending, obj);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
h->trace(obj, scr_sb_visit, (void *)(depth + 1));
|
|
340
352
|
}
|
|
341
353
|
|
|
342
|
-
static void scr_scan(void *obj);
|
|
354
|
+
static void scr_scan(void *obj, uintptr_t depth);
|
|
343
355
|
static void scr_scan_visit(void *child, void *ctx) {
|
|
344
|
-
(void)ctx;
|
|
345
356
|
if (SCR_CYC_SKIP(child)) return;
|
|
346
|
-
scr_scan(child);
|
|
357
|
+
scr_scan(child, (uintptr_t)ctx);
|
|
347
358
|
}
|
|
348
|
-
static void scr_scan(void *obj) {
|
|
359
|
+
static void scr_scan(void *obj, uintptr_t depth) {
|
|
349
360
|
ScrCycHdr *h = scr_cyc_hdr(obj);
|
|
350
361
|
if (h->color != SCR_CYC_GRAY) return;
|
|
351
362
|
if (SCR_RC(obj) > 0) {
|
|
352
|
-
|
|
353
|
-
|
|
363
|
+
scr_scan_black(obj, 0);
|
|
364
|
+
while (scr_restore_pending.n) {
|
|
365
|
+
void *next = scr_restore_pending.v[--scr_restore_pending.n];
|
|
366
|
+
scr_cyc_hdr(next)->trace(next, scr_sb_visit, NULL);
|
|
367
|
+
}
|
|
354
368
|
return;
|
|
355
369
|
}
|
|
356
370
|
h->color = SCR_CYC_WHITE;
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
static void scr_collect_white(void *obj);
|
|
361
|
-
static void scr_cw_visit(void *child, void *ctx) {
|
|
362
|
-
(void)ctx;
|
|
363
|
-
if (SCR_CYC_SKIP(child)) return;
|
|
364
|
-
scr_collect_white(child);
|
|
365
|
-
}
|
|
366
|
-
static void scr_collect_white(void *obj) {
|
|
367
|
-
ScrCycHdr *h = scr_cyc_hdr(obj);
|
|
368
|
-
if (h->color != SCR_CYC_WHITE || h->buffered) return;
|
|
369
|
-
h->color = SCR_CYC_DOOMED; /* gathered — don't gather twice */
|
|
370
|
-
h->trace(obj, scr_cw_visit, NULL);
|
|
371
|
+
/* Record each whitened object once. A later outside root can restore it;
|
|
372
|
+
* filter the list only after every scan finishes. No gather trace needed. */
|
|
371
373
|
scr_cyc_push(&scr_white, obj);
|
|
374
|
+
if (depth == SCR_CYC_WALK_DEPTH) {
|
|
375
|
+
scr_cyc_push(&scr_pending, obj);
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
h->trace(obj, scr_scan_visit, (void *)(depth + 1));
|
|
372
379
|
}
|
|
373
380
|
|
|
374
381
|
/* ── cross-generation edges ───────────────────────────────────────────── */
|
|
@@ -443,12 +450,10 @@ static size_t scr_cyc_pass(unsigned gen_limit) {
|
|
|
443
450
|
scr_gen_limit = gen_limit;
|
|
444
451
|
|
|
445
452
|
/* markRoots: keep live candidates (still purple), drop the rest — an
|
|
446
|
-
* object re-retained since buffering is black
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
* to gather members of an earlier root's cycle. Candidates ABOVE the
|
|
451
|
-
* limit keep their buffer slots and wait for a full pass. */
|
|
453
|
+
* object re-retained since buffering is black. Drain the buffers before
|
|
454
|
+
* walking: tracing only adjusts counts and worklists, so nothing can
|
|
455
|
+
* re-buffer underneath us. Candidates ABOVE the limit keep their slots
|
|
456
|
+
* and wait for a full pass. */
|
|
452
457
|
scr_cands.n = 0;
|
|
453
458
|
for (unsigned g = 0; g <= gen_limit; g++) {
|
|
454
459
|
for (size_t i = 0; i < scr_roots[g].n; i++) {
|
|
@@ -460,12 +465,31 @@ static size_t scr_cyc_pass(unsigned gen_limit) {
|
|
|
460
465
|
}
|
|
461
466
|
scr_roots[g].n = 0;
|
|
462
467
|
}
|
|
463
|
-
for (size_t i = 0; i < scr_cands.n; i++) scr_mark_gray(scr_cands.v[i]);
|
|
464
|
-
|
|
465
|
-
|
|
468
|
+
for (size_t i = 0; i < scr_cands.n; i++) scr_mark_gray(scr_cands.v[i], 0);
|
|
469
|
+
while (scr_pending.n) {
|
|
470
|
+
void *obj = scr_pending.v[--scr_pending.n];
|
|
471
|
+
scr_cyc_hdr(obj)->trace(obj, scr_mg_visit, NULL);
|
|
472
|
+
}
|
|
466
473
|
|
|
467
474
|
scr_white.n = 0;
|
|
468
|
-
for (size_t i = 0; i < scr_cands.n; i++)
|
|
475
|
+
for (size_t i = 0; i < scr_cands.n; i++) scr_scan(scr_cands.v[i], 0);
|
|
476
|
+
while (scr_pending.n) {
|
|
477
|
+
void *obj = scr_pending.v[--scr_pending.n];
|
|
478
|
+
/* A later outside root may have restored this deferred white node and
|
|
479
|
+
* its descendants already. Never scan a black node's edges again. */
|
|
480
|
+
if (scr_cyc_hdr(obj)->color == SCR_CYC_WHITE)
|
|
481
|
+
scr_cyc_hdr(obj)->trace(obj, scr_scan_visit, NULL);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
size_t dead = 0;
|
|
485
|
+
for (size_t i = 0; i < scr_white.n; i++) {
|
|
486
|
+
void *obj = scr_white.v[i];
|
|
487
|
+
ScrCycHdr *h = scr_cyc_hdr(obj);
|
|
488
|
+
if (h->color != SCR_CYC_WHITE) continue;
|
|
489
|
+
h->color = SCR_CYC_DOOMED;
|
|
490
|
+
scr_white.v[dead++] = obj;
|
|
491
|
+
}
|
|
492
|
+
scr_white.n = dead;
|
|
469
493
|
|
|
470
494
|
/* Pin the cross-generation targets of everything about to be freed, while
|
|
471
495
|
* `gen` still holds the values the walk filtered on (promotion below is
|
|
@@ -1039,12 +1039,20 @@ ScrDyn *scr_dyn_undefined(void) {
|
|
|
1039
1039
|
return &undef;
|
|
1040
1040
|
}
|
|
1041
1041
|
|
|
1042
|
-
|
|
1042
|
+
/* Primitive nodes have no mutable properties or observable box identity.
|
|
1043
|
+
* As with undefined, SIZE_MAX keeps them out of RC and cycle bookkeeping;
|
|
1044
|
+
* callers retain the ordinary owned-result and ownership-transfer contracts. */
|
|
1045
|
+
ScrDyn *scr_dyn_new_null(void) {
|
|
1046
|
+
static ScrDyn value = { .rc = SIZE_MAX, .kind = SCR_DYN_NULL };
|
|
1047
|
+
return &value;
|
|
1048
|
+
}
|
|
1043
1049
|
|
|
1044
1050
|
ScrDyn *scr_dyn_new_bool(bool b) {
|
|
1045
|
-
ScrDyn
|
|
1046
|
-
|
|
1047
|
-
|
|
1051
|
+
static ScrDyn values[2] = {
|
|
1052
|
+
{ .rc = SIZE_MAX, .kind = SCR_DYN_BOOL, .v.b = false },
|
|
1053
|
+
{ .rc = SIZE_MAX, .kind = SCR_DYN_BOOL, .v.b = true },
|
|
1054
|
+
};
|
|
1055
|
+
return &values[b ? 1 : 0];
|
|
1048
1056
|
}
|
|
1049
1057
|
|
|
1050
1058
|
ScrDyn *scr_dyn_new_bigint(ScrBigInt *value) {
|
|
@@ -6013,19 +6021,15 @@ static ScrDyn *scr_json_value(ScrJsonP *p) {
|
|
|
6013
6021
|
}
|
|
6014
6022
|
if (c == 't') {
|
|
6015
6023
|
if (!scr_json_lit(p, "true", 4)) return NULL;
|
|
6016
|
-
|
|
6017
|
-
d->v.b = true;
|
|
6018
|
-
return d;
|
|
6024
|
+
return scr_dyn_new_bool(true);
|
|
6019
6025
|
}
|
|
6020
6026
|
if (c == 'f') {
|
|
6021
6027
|
if (!scr_json_lit(p, "false", 5)) return NULL;
|
|
6022
|
-
|
|
6023
|
-
d->v.b = false;
|
|
6024
|
-
return d;
|
|
6028
|
+
return scr_dyn_new_bool(false);
|
|
6025
6029
|
}
|
|
6026
6030
|
if (c == 'n') {
|
|
6027
6031
|
if (!scr_json_lit(p, "null", 4)) return NULL;
|
|
6028
|
-
return
|
|
6032
|
+
return scr_dyn_new_null();
|
|
6029
6033
|
}
|
|
6030
6034
|
if (c == '-' || (c >= '0' && c <= '9')) return scr_json_number(p);
|
|
6031
6035
|
scr_json_throw_token(p);
|
|
@@ -7345,33 +7345,62 @@ void *scr_caught_check_obj(const ScrCaught *c, size_t pre, size_t post,
|
|
|
7345
7345
|
* walk folded into one call; no user code runs mid-drain, so the
|
|
7346
7346
|
* live-iteration rules are moot). Borrows the set; the array is +1,
|
|
7347
7347
|
* string elements retained into it by the iter_key read. */
|
|
7348
|
+
static bool scr_set_to_arr_sparse(const ScrMap *s, ScrArr *out) {
|
|
7349
|
+
if (out->cap >= s->nlive) return false;
|
|
7350
|
+
/* Large capacities deliberately use sparse array storage. Keep the
|
|
7351
|
+
* ordinary append path when the allocator declined dense storage. */
|
|
7352
|
+
for (size_t i = 0; i < s->nentries; i++) {
|
|
7353
|
+
if (!s->entries[i].hash) continue;
|
|
7354
|
+
if (out->elem == SCR_ELEM_F64) scr_arr_push_f64(out, scr_map_iter_key_f64(s, (double)i));
|
|
7355
|
+
else if (out->elem == SCR_ELEM_BOOL) scr_arr_push_bool(out, scr_map_iter_key_bool(s, (double)i));
|
|
7356
|
+
else if (out->elem == SCR_ELEM_STR) scr_arr_push_ref(out, scr_map_iter_key_str(s, (double)i));
|
|
7357
|
+
else scr_arr_push_ref(out, scr_map_iter_key_ref(s, (double)i));
|
|
7358
|
+
}
|
|
7359
|
+
return true;
|
|
7360
|
+
}
|
|
7361
|
+
|
|
7348
7362
|
ScrArr *scr_set_to_arr_f64(const ScrMap *s) {
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
for (size_t i = 0; i <
|
|
7352
|
-
if (!
|
|
7353
|
-
|
|
7363
|
+
ScrArr *out = scr_arr_new(SCR_ELEM_F64, s->nlive);
|
|
7364
|
+
if (scr_set_to_arr_sparse(s, out)) return out;
|
|
7365
|
+
for (size_t i = 0; i < s->nentries; i++) {
|
|
7366
|
+
if (!s->entries[i].hash) continue;
|
|
7367
|
+
out->data[out->len] = s->entries[i].key;
|
|
7368
|
+
out->present[out->len++] = SCR_ARR_VALUE;
|
|
7369
|
+
}
|
|
7370
|
+
return out;
|
|
7371
|
+
}
|
|
7372
|
+
|
|
7373
|
+
ScrArr *scr_set_to_arr_bool(const ScrMap *s) {
|
|
7374
|
+
ScrArr *out = scr_arr_new(SCR_ELEM_BOOL, s->nlive);
|
|
7375
|
+
if (scr_set_to_arr_sparse(s, out)) return out;
|
|
7376
|
+
for (size_t i = 0; i < s->nentries; i++) {
|
|
7377
|
+
if (!s->entries[i].hash) continue;
|
|
7378
|
+
out->data[out->len] = s->entries[i].key;
|
|
7379
|
+
out->present[out->len++] = SCR_ARR_VALUE;
|
|
7354
7380
|
}
|
|
7355
7381
|
return out;
|
|
7356
7382
|
}
|
|
7357
7383
|
|
|
7358
7384
|
ScrArr *scr_set_to_arr_str(const ScrMap *s) {
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
for (size_t i = 0; i <
|
|
7362
|
-
if (!
|
|
7363
|
-
|
|
7385
|
+
ScrArr *out = scr_arr_new(SCR_ELEM_STR, s->nlive);
|
|
7386
|
+
if (scr_set_to_arr_sparse(s, out)) return out;
|
|
7387
|
+
for (size_t i = 0; i < s->nentries; i++) {
|
|
7388
|
+
if (!s->entries[i].hash) continue;
|
|
7389
|
+
scr_str_retain((ScrStr *)(uintptr_t)s->entries[i].key);
|
|
7390
|
+
out->data[out->len] = s->entries[i].key;
|
|
7391
|
+
out->present[out->len++] = SCR_ARR_VALUE;
|
|
7364
7392
|
}
|
|
7365
7393
|
return out;
|
|
7366
7394
|
}
|
|
7367
7395
|
|
|
7368
7396
|
ScrArr *scr_set_to_arr_ref(const ScrMap *s) {
|
|
7369
|
-
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
7397
|
+
ScrArr *out = scr_arr_new_ref(s->key_retain, s->key_release, s->key_trace, s->nlive);
|
|
7398
|
+
if (scr_set_to_arr_sparse(s, out)) return out;
|
|
7399
|
+
for (size_t i = 0; i < s->nentries; i++) {
|
|
7400
|
+
if (!s->entries[i].hash) continue;
|
|
7401
|
+
s->key_retain((void *)(uintptr_t)s->entries[i].key);
|
|
7402
|
+
out->data[out->len] = s->entries[i].key;
|
|
7403
|
+
out->present[out->len++] = SCR_ARR_VALUE;
|
|
7375
7404
|
}
|
|
7376
7405
|
return out;
|
|
7377
7406
|
}
|