@fraczak/k 6.5.0 → 6.6.0
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/backends/arm64/src/runtime.c +20 -4
- package/backends/arm64/tests/integration.sh +1 -1
- package/backends/llvm/runtime/krt.c +387 -2
- package/backends/llvm/runtime/krt.h +1 -0
- package/backends/llvm/src/kvm2llvm.mjs +98 -29
- package/backends/llvm/tests/perf-support.mjs +1 -1
- package/browser/repl-browser.mjs +24 -7
- package/browser/tree-view.mjs +599 -0
- package/package.json +1 -1
- package/repl.mjs +4 -0
- package/scripts/build-repl-html.mjs +301 -0
- package/scripts/perf-ieee.mjs +5 -2
- package/scripts/perf-int.mjs +331 -0
- package/scripts/run-tests.mjs +1 -0
- package/tests/test-repl-html.mjs +141 -0
- package/tests/test-tree-view.mjs +185 -0
|
@@ -5,7 +5,21 @@
|
|
|
5
5
|
#include <string.h>
|
|
6
6
|
#include <time.h>
|
|
7
7
|
|
|
8
|
-
#define
|
|
8
|
+
#define DEFAULT_ARENA_CAPACITY (256 * 1024 * 1024)
|
|
9
|
+
|
|
10
|
+
static int parse_size_arg(const char *text, size_t *out);
|
|
11
|
+
|
|
12
|
+
static size_t get_arena_capacity(void) {
|
|
13
|
+
const char *env = getenv("K_ARENA_CAPACITY_MB");
|
|
14
|
+
if (!env || !*env) env = getenv("K_ARENA_MB");
|
|
15
|
+
if (env && *env) {
|
|
16
|
+
size_t mb = 0;
|
|
17
|
+
if (parse_size_arg(env, &mb) && mb > 0) {
|
|
18
|
+
return mb * 1024 * 1024;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return DEFAULT_ARENA_CAPACITY;
|
|
22
|
+
}
|
|
9
23
|
|
|
10
24
|
typedef enum {
|
|
11
25
|
K_VALUE_UNIT,
|
|
@@ -601,8 +615,10 @@ static int run_bench_main(void *arena_mem, const char *count_text) {
|
|
|
601
615
|
int main(int argc, char **argv) {
|
|
602
616
|
init_tag_registry();
|
|
603
617
|
|
|
618
|
+
size_t arena_capacity = get_arena_capacity();
|
|
619
|
+
|
|
604
620
|
if (argc == 2 && strcmp(argv[1], "--server") == 0) {
|
|
605
|
-
void *arena_mem = malloc(
|
|
621
|
+
void *arena_mem = malloc(arena_capacity);
|
|
606
622
|
if (!arena_mem) return 1;
|
|
607
623
|
int rc = run_server(arena_mem);
|
|
608
624
|
free(arena_mem);
|
|
@@ -610,7 +626,7 @@ int main(int argc, char **argv) {
|
|
|
610
626
|
}
|
|
611
627
|
|
|
612
628
|
if (argc == 3 && strcmp(argv[1], "--bench-main") == 0) {
|
|
613
|
-
void *arena_mem = malloc(
|
|
629
|
+
void *arena_mem = malloc(arena_capacity);
|
|
614
630
|
if (!arena_mem) return 1;
|
|
615
631
|
int rc = run_bench_main(arena_mem, argv[2]);
|
|
616
632
|
free(arena_mem);
|
|
@@ -647,7 +663,7 @@ int main(int argc, char **argv) {
|
|
|
647
663
|
}
|
|
648
664
|
}
|
|
649
665
|
|
|
650
|
-
void *arena_mem = malloc(
|
|
666
|
+
void *arena_mem = malloc(arena_capacity);
|
|
651
667
|
if (!arena_mem) {
|
|
652
668
|
if (in_fp != stdin) fclose(in_fp);
|
|
653
669
|
return 1;
|
|
@@ -105,7 +105,7 @@ node "$K_ROOT/backends/arm64/bin/k-arm64-compile.mjs" \
|
|
|
105
105
|
'{succ int x,int y}+' \
|
|
106
106
|
-o "$TMP_DIR/lib-add"
|
|
107
107
|
|
|
108
|
-
node "$K_ROOT/codecs/k-parse.mjs" <<< '{"x":{"
|
|
108
|
+
node "$K_ROOT/codecs/k-parse.mjs" <<< '{"x":{"0":"_"},"y":{"+":{"0":"_"}}}' |
|
|
109
109
|
"$TMP_DIR/lib-add" --json |
|
|
110
110
|
grep -Fxq '{"+":{"1":"_"}}'
|
|
111
111
|
|
|
@@ -5,13 +5,14 @@
|
|
|
5
5
|
#include <string.h>
|
|
6
6
|
|
|
7
7
|
enum {
|
|
8
|
-
K_ARENA_BLOCK_SIZE =
|
|
8
|
+
K_ARENA_BLOCK_SIZE = 4194304
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
typedef enum {
|
|
12
12
|
K_VALUE_UNIT,
|
|
13
13
|
K_VALUE_PRODUCT,
|
|
14
|
-
K_VALUE_VARIANT
|
|
14
|
+
K_VALUE_VARIANT,
|
|
15
|
+
K_VALUE_FORWARDED = 99
|
|
15
16
|
} k_value_kind;
|
|
16
17
|
|
|
17
18
|
typedef struct {
|
|
@@ -221,6 +222,390 @@ void k_rt_rewind(k_rt *rt, k_rt_checkpoint mark) {
|
|
|
221
222
|
rt->has_reusable_blocks = has_reusable;
|
|
222
223
|
}
|
|
223
224
|
|
|
225
|
+
typedef struct {
|
|
226
|
+
size_t *offsets;
|
|
227
|
+
size_t count;
|
|
228
|
+
size_t capacity;
|
|
229
|
+
} k_fixup_list;
|
|
230
|
+
|
|
231
|
+
static void fixup_add(k_fixup_list *list, size_t offset) {
|
|
232
|
+
if (list->count == list->capacity) {
|
|
233
|
+
size_t new_cap = list->capacity == 0 ? 1024 : list->capacity * 2;
|
|
234
|
+
size_t *new_offsets = (size_t *)realloc(list->offsets, new_cap * sizeof(size_t));
|
|
235
|
+
if (new_offsets == NULL) abort();
|
|
236
|
+
list->offsets = new_offsets;
|
|
237
|
+
list->capacity = new_cap;
|
|
238
|
+
}
|
|
239
|
+
list->offsets[list->count++] = offset;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
static int is_after_mark(k_rt *rt, const void *ptr, k_rt_checkpoint mark) {
|
|
243
|
+
if (rt == NULL || ptr == NULL) return 0;
|
|
244
|
+
const unsigned char *p = (const unsigned char *)ptr;
|
|
245
|
+
k_arena_block *mb = (k_arena_block *)mark.block;
|
|
246
|
+
if (mb == NULL) {
|
|
247
|
+
for (k_arena_block *b = rt->blocks; b != NULL; b = b->next) {
|
|
248
|
+
if (p >= b->data && p < b->data + b->capacity) {
|
|
249
|
+
return 1;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return 0;
|
|
253
|
+
}
|
|
254
|
+
if (rt->blocks == mb) {
|
|
255
|
+
return (p >= mb->data + mark.used && p < mb->data + mb->capacity);
|
|
256
|
+
}
|
|
257
|
+
for (k_arena_block *b = rt->blocks; b != NULL; b = b->next) {
|
|
258
|
+
if (b == mb) {
|
|
259
|
+
return (p >= b->data + mark.used && p < b->data + b->capacity);
|
|
260
|
+
}
|
|
261
|
+
if (p >= b->data && p < b->data + b->capacity) {
|
|
262
|
+
return 1;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return 0;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
static size_t bytes_since_mark(k_rt *rt, k_rt_checkpoint mark) {
|
|
269
|
+
if (rt == NULL || rt->blocks == NULL) return 0;
|
|
270
|
+
k_arena_block *mb = (k_arena_block *)mark.block;
|
|
271
|
+
if (rt->blocks == mb) {
|
|
272
|
+
return rt->blocks->used >= mark.used ? rt->blocks->used - mark.used : 0;
|
|
273
|
+
}
|
|
274
|
+
size_t total = 0;
|
|
275
|
+
if (mb == NULL) {
|
|
276
|
+
for (k_arena_block *b = rt->blocks; b != NULL; b = b->next) {
|
|
277
|
+
total += b->used;
|
|
278
|
+
}
|
|
279
|
+
return total;
|
|
280
|
+
}
|
|
281
|
+
for (k_arena_block *b = rt->blocks; b != NULL; b = b->next) {
|
|
282
|
+
if (b == mb) {
|
|
283
|
+
if (b->used > mark.used) {
|
|
284
|
+
total += (b->used - mark.used);
|
|
285
|
+
}
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
total += b->used;
|
|
289
|
+
}
|
|
290
|
+
return total;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
static void *staging_alloc(unsigned char **staging_ptr, size_t *used, size_t *capacity, size_t size, k_fixup_list *fixups) {
|
|
294
|
+
size = align_size(size == 0 ? 1 : size);
|
|
295
|
+
if (*used + size > *capacity) {
|
|
296
|
+
size_t old_cap = *capacity;
|
|
297
|
+
size_t new_cap = (old_cap + size) * 2;
|
|
298
|
+
unsigned char *old_buf = *staging_ptr;
|
|
299
|
+
unsigned char *new_buf = (unsigned char *)realloc(old_buf, new_cap);
|
|
300
|
+
if (new_buf == NULL) abort();
|
|
301
|
+
if (new_buf != old_buf) {
|
|
302
|
+
ptrdiff_t realloc_diff = new_buf - old_buf;
|
|
303
|
+
for (size_t i = 0; i < fixups->count; i++) {
|
|
304
|
+
size_t off = fixups->offsets[i];
|
|
305
|
+
unsigned char **p = (unsigned char **)(new_buf + off);
|
|
306
|
+
*p += realloc_diff;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
*staging_ptr = new_buf;
|
|
310
|
+
*capacity = new_cap;
|
|
311
|
+
}
|
|
312
|
+
void *p = *staging_ptr + *used;
|
|
313
|
+
*used += size;
|
|
314
|
+
return p;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
static k_value *copy_value(k_rt *rt, k_value *root, unsigned char **staging_ptr, size_t *staging_used, size_t *staging_cap, k_fixup_list *fixups, k_rt_checkpoint mark) {
|
|
318
|
+
if (root == NULL || !is_after_mark(rt, root, mark)) {
|
|
319
|
+
return root;
|
|
320
|
+
}
|
|
321
|
+
if ((int)root->kind == K_VALUE_FORWARDED) {
|
|
322
|
+
return root->as.variant.payload;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (root->kind == K_VALUE_VARIANT) {
|
|
326
|
+
k_value *first_staged = NULL;
|
|
327
|
+
k_value *prev_staged = NULL;
|
|
328
|
+
k_value *curr = root;
|
|
329
|
+
|
|
330
|
+
while (curr != NULL) {
|
|
331
|
+
if (!is_after_mark(rt, curr, mark)) {
|
|
332
|
+
if (prev_staged != NULL) {
|
|
333
|
+
prev_staged->as.variant.payload = curr;
|
|
334
|
+
}
|
|
335
|
+
if (first_staged == NULL) {
|
|
336
|
+
first_staged = curr;
|
|
337
|
+
}
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if ((int)curr->kind == K_VALUE_FORWARDED) {
|
|
342
|
+
k_value *staged_target = curr->as.variant.payload;
|
|
343
|
+
if (prev_staged != NULL) {
|
|
344
|
+
prev_staged->as.variant.payload = staged_target;
|
|
345
|
+
fixup_add(fixups, (unsigned char *)&prev_staged->as.variant.payload - *staging_ptr);
|
|
346
|
+
}
|
|
347
|
+
if (first_staged == NULL) {
|
|
348
|
+
first_staged = staged_target;
|
|
349
|
+
}
|
|
350
|
+
break;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (curr->as.variant.tag != NULL) {
|
|
354
|
+
if (bytes_equal(curr->as.variant.tag, curr->as.variant.tag_length, "Float64", 7)) {
|
|
355
|
+
k_value *staged_v = (k_value *)staging_alloc(staging_ptr, staging_used, staging_cap, sizeof(k_value), fixups);
|
|
356
|
+
staged_v->kind = K_VALUE_VARIANT;
|
|
357
|
+
staged_v->rt = rt;
|
|
358
|
+
staged_v->as.variant.tag = curr->as.variant.tag;
|
|
359
|
+
staged_v->as.variant.tag_length = curr->as.variant.tag_length;
|
|
360
|
+
staged_v->as.variant.payload = NULL;
|
|
361
|
+
|
|
362
|
+
if (is_after_mark(rt, curr->as.variant.tag, mark)) {
|
|
363
|
+
char *staged_tag = (char *)staging_alloc(staging_ptr, staging_used, staging_cap, curr->as.variant.tag_length + 1, fixups);
|
|
364
|
+
memcpy(staged_tag, curr->as.variant.tag, curr->as.variant.tag_length);
|
|
365
|
+
staged_tag[curr->as.variant.tag_length] = 0;
|
|
366
|
+
staged_v->as.variant.tag = staged_tag;
|
|
367
|
+
fixup_add(fixups, (unsigned char *)&staged_v->as.variant.tag - *staging_ptr);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (curr->as.variant.payload != NULL && is_after_mark(rt, curr->as.variant.payload, mark)) {
|
|
371
|
+
void *raw = staging_alloc(staging_ptr, staging_used, staging_cap, sizeof(double), fixups);
|
|
372
|
+
memcpy(raw, curr->as.variant.payload, sizeof(double));
|
|
373
|
+
staged_v->as.variant.payload = (k_value *)raw;
|
|
374
|
+
fixup_add(fixups, (unsigned char *)&staged_v->as.variant.payload - *staging_ptr);
|
|
375
|
+
} else {
|
|
376
|
+
staged_v->as.variant.payload = curr->as.variant.payload;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (prev_staged != NULL) {
|
|
380
|
+
prev_staged->as.variant.payload = staged_v;
|
|
381
|
+
fixup_add(fixups, (unsigned char *)&prev_staged->as.variant.payload - *staging_ptr);
|
|
382
|
+
}
|
|
383
|
+
if (first_staged == NULL) {
|
|
384
|
+
first_staged = staged_v;
|
|
385
|
+
}
|
|
386
|
+
curr->kind = (k_value_kind)K_VALUE_FORWARDED;
|
|
387
|
+
curr->as.variant.payload = staged_v;
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (bytes_equal(curr->as.variant.tag, curr->as.variant.tag_length, "Int32", 5)) {
|
|
392
|
+
k_value *staged_v = (k_value *)staging_alloc(staging_ptr, staging_used, staging_cap, sizeof(k_value), fixups);
|
|
393
|
+
staged_v->kind = K_VALUE_VARIANT;
|
|
394
|
+
staged_v->rt = rt;
|
|
395
|
+
staged_v->as.variant.tag = curr->as.variant.tag;
|
|
396
|
+
staged_v->as.variant.tag_length = curr->as.variant.tag_length;
|
|
397
|
+
staged_v->as.variant.payload = NULL;
|
|
398
|
+
|
|
399
|
+
if (is_after_mark(rt, curr->as.variant.tag, mark)) {
|
|
400
|
+
char *staged_tag = (char *)staging_alloc(staging_ptr, staging_used, staging_cap, curr->as.variant.tag_length + 1, fixups);
|
|
401
|
+
memcpy(staged_tag, curr->as.variant.tag, curr->as.variant.tag_length);
|
|
402
|
+
staged_tag[curr->as.variant.tag_length] = 0;
|
|
403
|
+
staged_v->as.variant.tag = staged_tag;
|
|
404
|
+
fixup_add(fixups, (unsigned char *)&staged_v->as.variant.tag - *staging_ptr);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (curr->as.variant.payload != NULL && is_after_mark(rt, curr->as.variant.payload, mark)) {
|
|
408
|
+
void *raw = staging_alloc(staging_ptr, staging_used, staging_cap, sizeof(int32_t), fixups);
|
|
409
|
+
memcpy(raw, curr->as.variant.payload, sizeof(int32_t));
|
|
410
|
+
staged_v->as.variant.payload = (k_value *)raw;
|
|
411
|
+
fixup_add(fixups, (unsigned char *)&staged_v->as.variant.payload - *staging_ptr);
|
|
412
|
+
} else {
|
|
413
|
+
staged_v->as.variant.payload = curr->as.variant.payload;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (prev_staged != NULL) {
|
|
417
|
+
prev_staged->as.variant.payload = staged_v;
|
|
418
|
+
fixup_add(fixups, (unsigned char *)&prev_staged->as.variant.payload - *staging_ptr);
|
|
419
|
+
}
|
|
420
|
+
if (first_staged == NULL) {
|
|
421
|
+
first_staged = staged_v;
|
|
422
|
+
}
|
|
423
|
+
curr->kind = (k_value_kind)K_VALUE_FORWARDED;
|
|
424
|
+
curr->as.variant.payload = staged_v;
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (curr->kind != K_VALUE_VARIANT) {
|
|
430
|
+
k_value *staged_child = copy_value(rt, curr, staging_ptr, staging_used, staging_cap, fixups, mark);
|
|
431
|
+
if (prev_staged != NULL) {
|
|
432
|
+
prev_staged->as.variant.payload = staged_child;
|
|
433
|
+
if (staged_child != NULL && (unsigned char *)staged_child >= *staging_ptr && (unsigned char *)staged_child < *staging_ptr + *staging_used) {
|
|
434
|
+
fixup_add(fixups, (unsigned char *)&prev_staged->as.variant.payload - *staging_ptr);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
if (first_staged == NULL) {
|
|
438
|
+
first_staged = staged_child;
|
|
439
|
+
}
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
k_value *staged_v = (k_value *)staging_alloc(staging_ptr, staging_used, staging_cap, sizeof(k_value), fixups);
|
|
444
|
+
staged_v->kind = K_VALUE_VARIANT;
|
|
445
|
+
staged_v->rt = rt;
|
|
446
|
+
staged_v->as.variant.tag = curr->as.variant.tag;
|
|
447
|
+
staged_v->as.variant.tag_length = curr->as.variant.tag_length;
|
|
448
|
+
staged_v->as.variant.payload = NULL;
|
|
449
|
+
|
|
450
|
+
if (curr->as.variant.tag != NULL && is_after_mark(rt, curr->as.variant.tag, mark)) {
|
|
451
|
+
char *staged_tag = (char *)staging_alloc(staging_ptr, staging_used, staging_cap, curr->as.variant.tag_length + 1, fixups);
|
|
452
|
+
memcpy(staged_tag, curr->as.variant.tag, curr->as.variant.tag_length);
|
|
453
|
+
staged_tag[curr->as.variant.tag_length] = 0;
|
|
454
|
+
staged_v->as.variant.tag = staged_tag;
|
|
455
|
+
fixup_add(fixups, (unsigned char *)&staged_v->as.variant.tag - *staging_ptr);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (prev_staged != NULL) {
|
|
459
|
+
prev_staged->as.variant.payload = staged_v;
|
|
460
|
+
fixup_add(fixups, (unsigned char *)&prev_staged->as.variant.payload - *staging_ptr);
|
|
461
|
+
}
|
|
462
|
+
if (first_staged == NULL) {
|
|
463
|
+
first_staged = staged_v;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
k_value *next = curr->as.variant.payload;
|
|
467
|
+
curr->kind = (k_value_kind)K_VALUE_FORWARDED;
|
|
468
|
+
curr->as.variant.payload = staged_v;
|
|
469
|
+
|
|
470
|
+
prev_staged = staged_v;
|
|
471
|
+
curr = next;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return first_staged;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
size_t header_size = align_size(sizeof(k_value));
|
|
478
|
+
size_t fields_size = root->as.product.count * sizeof(k_field);
|
|
479
|
+
size_t total_size = header_size + fields_size;
|
|
480
|
+
|
|
481
|
+
k_value *staged_p = (k_value *)staging_alloc(staging_ptr, staging_used, staging_cap, total_size, fixups);
|
|
482
|
+
staged_p->kind = root->kind;
|
|
483
|
+
staged_p->rt = rt;
|
|
484
|
+
staged_p->as.product.count = root->as.product.count;
|
|
485
|
+
staged_p->as.product.capacity = root->as.product.count;
|
|
486
|
+
|
|
487
|
+
if (root->as.product.count > 0) {
|
|
488
|
+
k_field *staged_fields = (k_field *)((unsigned char *)staged_p + header_size);
|
|
489
|
+
staged_p->as.product.fields = staged_fields;
|
|
490
|
+
fixup_add(fixups, (unsigned char *)&staged_p->as.product.fields - *staging_ptr);
|
|
491
|
+
|
|
492
|
+
k_field *old_fields = root->as.product.fields;
|
|
493
|
+
size_t count = root->as.product.count;
|
|
494
|
+
|
|
495
|
+
root->kind = (k_value_kind)K_VALUE_FORWARDED;
|
|
496
|
+
root->as.variant.payload = staged_p;
|
|
497
|
+
|
|
498
|
+
for (size_t i = 0; i < count; i++) {
|
|
499
|
+
staged_fields[i].label_length = old_fields[i].label_length;
|
|
500
|
+
staged_fields[i].label = old_fields[i].label;
|
|
501
|
+
if (old_fields[i].label != NULL && is_after_mark(rt, old_fields[i].label, mark)) {
|
|
502
|
+
char *staged_label = (char *)staging_alloc(staging_ptr, staging_used, staging_cap, old_fields[i].label_length + 1, fixups);
|
|
503
|
+
memcpy(staged_label, old_fields[i].label, old_fields[i].label_length);
|
|
504
|
+
staged_label[old_fields[i].label_length] = 0;
|
|
505
|
+
staged_fields[i].label = staged_label;
|
|
506
|
+
fixup_add(fixups, (unsigned char *)&staged_fields[i].label - *staging_ptr);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
k_value *child = copy_value(rt, old_fields[i].value, staging_ptr, staging_used, staging_cap, fixups, mark);
|
|
510
|
+
staged_fields[i].value = child;
|
|
511
|
+
if (child != NULL && (unsigned char *)child >= *staging_ptr && (unsigned char *)child < *staging_ptr + *staging_used) {
|
|
512
|
+
fixup_add(fixups, (unsigned char *)&staged_fields[i].value - *staging_ptr);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
} else {
|
|
516
|
+
staged_p->as.product.fields = NULL;
|
|
517
|
+
root->kind = (k_value_kind)K_VALUE_FORWARDED;
|
|
518
|
+
root->as.variant.payload = staged_p;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
return staged_p;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
static void rt_rewind_and_free(k_rt *rt, k_rt_checkpoint mark) {
|
|
525
|
+
if (rt == NULL) return;
|
|
526
|
+
if (mark.block == NULL) {
|
|
527
|
+
k_arena_block *b = rt->blocks;
|
|
528
|
+
while (b != NULL) {
|
|
529
|
+
k_arena_block *next = b->next;
|
|
530
|
+
free(b);
|
|
531
|
+
b = next;
|
|
532
|
+
}
|
|
533
|
+
rt->blocks = NULL;
|
|
534
|
+
rt->unit_cache = NULL;
|
|
535
|
+
rt->bit0_cache = NULL;
|
|
536
|
+
rt->bit1_cache = NULL;
|
|
537
|
+
rt->has_reusable_blocks = 0;
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
k_arena_block *b = rt->blocks;
|
|
541
|
+
while (b != NULL && b != (k_arena_block *)mark.block) {
|
|
542
|
+
k_arena_block *next = b->next;
|
|
543
|
+
free(b);
|
|
544
|
+
b = next;
|
|
545
|
+
}
|
|
546
|
+
rt->blocks = (k_arena_block *)mark.block;
|
|
547
|
+
if (rt->blocks != NULL) {
|
|
548
|
+
rt->blocks->used = mark.used;
|
|
549
|
+
}
|
|
550
|
+
rt->unit_cache = NULL;
|
|
551
|
+
rt->bit0_cache = NULL;
|
|
552
|
+
rt->bit1_cache = NULL;
|
|
553
|
+
rt->has_reusable_blocks = 0;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
k_value *k_rt_compact(k_rt *rt, k_value *root, k_rt_checkpoint *mark_ptr) {
|
|
557
|
+
if (rt == NULL || root == NULL || mark_ptr == NULL) return root;
|
|
558
|
+
|
|
559
|
+
size_t bytes = bytes_since_mark(rt, *mark_ptr);
|
|
560
|
+
if (bytes < 4194304) {
|
|
561
|
+
return root;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
if (!is_after_mark(rt, root, *mark_ptr)) {
|
|
565
|
+
rt_rewind_and_free(rt, *mark_ptr);
|
|
566
|
+
return root;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
size_t staging_cap = bytes + 65536;
|
|
570
|
+
unsigned char *staging = (unsigned char *)malloc(staging_cap);
|
|
571
|
+
if (staging == NULL) abort();
|
|
572
|
+
size_t staging_used = 0;
|
|
573
|
+
|
|
574
|
+
k_fixup_list fixups = {NULL, 0, 0};
|
|
575
|
+
|
|
576
|
+
k_value *staged_root = copy_value(rt, root, &staging, &staging_used, &staging_cap, &fixups, *mark_ptr);
|
|
577
|
+
|
|
578
|
+
rt_rewind_and_free(rt, *mark_ptr);
|
|
579
|
+
|
|
580
|
+
if (staging_used == 0) {
|
|
581
|
+
free(staging);
|
|
582
|
+
if (fixups.offsets != NULL) free(fixups.offsets);
|
|
583
|
+
return staged_root;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
void *arena_dest = rt_alloc(rt, staging_used);
|
|
587
|
+
if (arena_dest == NULL) abort();
|
|
588
|
+
|
|
589
|
+
ptrdiff_t diff = (unsigned char *)arena_dest - staging;
|
|
590
|
+
|
|
591
|
+
for (size_t i = 0; i < fixups.count; i++) {
|
|
592
|
+
size_t off = fixups.offsets[i];
|
|
593
|
+
unsigned char **p = (unsigned char **)(staging + off);
|
|
594
|
+
*p += diff;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
memcpy(arena_dest, staging, staging_used);
|
|
598
|
+
|
|
599
|
+
k_value *new_root = (staged_root != NULL && (unsigned char *)staged_root >= staging && (unsigned char *)staged_root < staging + staging_used)
|
|
600
|
+
? (k_value *)((unsigned char *)staged_root + diff)
|
|
601
|
+
: staged_root;
|
|
602
|
+
|
|
603
|
+
free(staging);
|
|
604
|
+
if (fixups.offsets != NULL) free(fixups.offsets);
|
|
605
|
+
|
|
606
|
+
return new_root;
|
|
607
|
+
}
|
|
608
|
+
|
|
224
609
|
void k_rt_free(k_rt *rt) {
|
|
225
610
|
if (rt == NULL) return;
|
|
226
611
|
k_arena_block *block = rt->blocks;
|
|
@@ -66,6 +66,7 @@ k_rt *k_rt_new(void);
|
|
|
66
66
|
void k_rt_reset(k_rt *rt);
|
|
67
67
|
k_rt_checkpoint k_rt_mark(k_rt *rt);
|
|
68
68
|
void k_rt_rewind(k_rt *rt, k_rt_checkpoint mark);
|
|
69
|
+
k_value *k_rt_compact(k_rt *rt, k_value *root, k_rt_checkpoint *mark_ptr);
|
|
69
70
|
void *k_rt_alloc(k_rt *rt, size_t size);
|
|
70
71
|
void k_rt_free(k_rt *rt);
|
|
71
72
|
|