@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.
@@ -5,7 +5,21 @@
5
5
  #include <string.h>
6
6
  #include <time.h>
7
7
 
8
- #define ARENA_CAPACITY (64 * 1024 * 1024)
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(ARENA_CAPACITY);
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(ARENA_CAPACITY);
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(ARENA_CAPACITY);
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":{"succ":"zero"},"y":{"succ":{"succ":"zero"}}}' |
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 = 262144
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