@shd101wyy/yo 0.1.24 → 0.1.25

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.
Files changed (76) hide show
  1. package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +30 -0
  2. package/.github/skills/yo-syntax/syntax-cheatsheet.md +436 -2
  3. package/out/cjs/index.cjs +551 -553
  4. package/out/cjs/yo-cli.cjs +638 -632
  5. package/out/cjs/yo-lsp.cjs +595 -597
  6. package/out/esm/index.mjs +487 -489
  7. package/out/types/src/codegen/utils/index.d.ts +1 -0
  8. package/out/types/src/expr.d.ts +1 -0
  9. package/out/types/src/test-runner.d.ts +1 -0
  10. package/out/types/tsconfig.tsbuildinfo +1 -1
  11. package/package.json +1 -1
  12. package/vendor/mimalloc/.github/workflows/release.yaml +55 -0
  13. package/vendor/mimalloc/.github/workflows/stale.yaml +27 -0
  14. package/vendor/mimalloc/.github/workflows/test.yaml +163 -0
  15. package/vendor/mimalloc/CMakeLists.txt +52 -33
  16. package/vendor/mimalloc/azure-pipelines.yml +4 -3
  17. package/vendor/mimalloc/bin/bundle.bat +74 -0
  18. package/vendor/mimalloc/bin/bundle.sh +232 -0
  19. package/vendor/mimalloc/cmake/mimalloc-config-version.cmake +2 -2
  20. package/vendor/mimalloc/contrib/docker/alpine/Dockerfile +1 -1
  21. package/vendor/mimalloc/contrib/docker/alpine-arm32v7/Dockerfile +2 -2
  22. package/vendor/mimalloc/contrib/docker/alpine-x86/Dockerfile +1 -1
  23. package/vendor/mimalloc/contrib/docker/manylinux-x64/Dockerfile +1 -1
  24. package/vendor/mimalloc/contrib/vcpkg/portfile.cmake +4 -3
  25. package/vendor/mimalloc/contrib/vcpkg/vcpkg.json +1 -1
  26. package/vendor/mimalloc/doc/mimalloc-doc.h +42 -4
  27. package/vendor/mimalloc/doc/release-notes.md +15 -0
  28. package/vendor/mimalloc/ide/vs2022/mimalloc-lib.vcxproj +3 -3
  29. package/vendor/mimalloc/ide/vs2022/mimalloc-override-static-lib.vcxproj +511 -0
  30. package/vendor/mimalloc/ide/vs2022/mimalloc-override-static-lib.vcxproj.filters +117 -0
  31. package/vendor/mimalloc/ide/vs2022/mimalloc-test-dep.vcxproj +360 -0
  32. package/vendor/mimalloc/ide/vs2022/mimalloc-test-override-static.vcxproj +310 -0
  33. package/vendor/mimalloc/ide/vs2022/mimalloc.sln +92 -35
  34. package/vendor/mimalloc/include/mimalloc/atomic.h +178 -182
  35. package/vendor/mimalloc/include/mimalloc/bits.h +8 -10
  36. package/vendor/mimalloc/include/mimalloc/internal.h +76 -32
  37. package/vendor/mimalloc/include/mimalloc/prim.h +25 -18
  38. package/vendor/mimalloc/include/mimalloc/track.h +7 -2
  39. package/vendor/mimalloc/include/mimalloc/types.h +57 -29
  40. package/vendor/mimalloc/include/mimalloc-override.h +10 -10
  41. package/vendor/mimalloc/include/mimalloc-stats.h +18 -6
  42. package/vendor/mimalloc/include/mimalloc.h +22 -12
  43. package/vendor/mimalloc/readme.md +42 -17
  44. package/vendor/mimalloc/src/alloc-aligned.c +13 -11
  45. package/vendor/mimalloc/src/alloc-override.c +97 -17
  46. package/vendor/mimalloc/src/alloc-posix.c +44 -27
  47. package/vendor/mimalloc/src/alloc.c +73 -23
  48. package/vendor/mimalloc/src/arena-meta.c +3 -3
  49. package/vendor/mimalloc/src/arena.c +380 -192
  50. package/vendor/mimalloc/src/bitmap.c +68 -18
  51. package/vendor/mimalloc/src/bitmap.h +8 -4
  52. package/vendor/mimalloc/src/free.c +83 -47
  53. package/vendor/mimalloc/src/heap.c +94 -40
  54. package/vendor/mimalloc/src/init.c +273 -102
  55. package/vendor/mimalloc/src/libc.c +53 -8
  56. package/vendor/mimalloc/src/options.c +43 -40
  57. package/vendor/mimalloc/src/os.c +110 -45
  58. package/vendor/mimalloc/src/page-map.c +14 -8
  59. package/vendor/mimalloc/src/page-queue.c +9 -6
  60. package/vendor/mimalloc/src/page.c +26 -16
  61. package/vendor/mimalloc/src/prim/emscripten/prim.c +10 -1
  62. package/vendor/mimalloc/src/prim/osx/alloc-override-zone.c +35 -16
  63. package/vendor/mimalloc/src/prim/unix/prim.c +26 -22
  64. package/vendor/mimalloc/src/prim/wasi/prim.c +7 -4
  65. package/vendor/mimalloc/src/prim/windows/prim.c +247 -44
  66. package/vendor/mimalloc/src/random.c +8 -3
  67. package/vendor/mimalloc/src/stats.c +59 -48
  68. package/vendor/mimalloc/src/theap.c +85 -44
  69. package/vendor/mimalloc/src/threadlocal.c +102 -41
  70. package/vendor/mimalloc/test/main-override-static.c +31 -2
  71. package/vendor/mimalloc/test/main-override.c +27 -14
  72. package/vendor/mimalloc/test/main-static-dep.cpp +46 -0
  73. package/vendor/mimalloc/test/main-static-dep.h +11 -0
  74. package/vendor/mimalloc/test/test-api-fill.c +2 -2
  75. package/vendor/mimalloc/test/test-stress.c +3 -3
  76. package/vendor/mimalloc/test/test-wrong.c +11 -7
@@ -117,7 +117,7 @@ static void mi_stat_counter_add_mt(mi_stat_counter_t* stat, const mi_stat_counte
117
117
 
118
118
  // must be thread safe as it is called from stats_merge
119
119
  static void mi_stats_add(mi_stats_t* stats, const mi_stats_t* src) {
120
- if (stats==src) return;
120
+ if (stats==NULL || src==NULL || stats==src) return;
121
121
 
122
122
  // copy all fields
123
123
  MI_STAT_FIELDS()
@@ -214,10 +214,9 @@ static void mi_stat_print_ex(const mi_stat_count_t* stat, const char* msg, int64
214
214
  }
215
215
  }
216
216
  else {
217
- mi_print_amount(stat->peak, 1, out, arg);
218
- mi_print_amount(stat->total, 1, out, arg);
219
- _mi_fprintf(out, arg, "%11s", " "); // no freed
220
- mi_print_amount(stat->current, 1, out, arg);
217
+ mi_print_amount(stat->peak, 0, out, arg);
218
+ mi_print_amount(stat->total, 0, out, arg);
219
+ mi_print_amount(stat->current, 0, out, arg);
221
220
  _mi_fprintf(out, arg, "\n");
222
221
  }
223
222
  }
@@ -237,16 +236,21 @@ static void mi_stat_total_print(const mi_stat_count_t* stat, const char* msg, in
237
236
 
238
237
  static void mi_stat_counter_print(const mi_stat_counter_t* stat, const char* msg, mi_output_fun* out, void* arg ) {
239
238
  _mi_fprintf(out, arg, " %-10s:", msg);
240
- mi_print_amount(stat->total, -1, out, arg);
239
+ mi_print_amount(stat->total, 0, out, arg);
241
240
  _mi_fprintf(out, arg, "\n");
242
241
  }
243
242
 
243
+ static void mi_stat_counter_print_size(const mi_stat_counter_t* stat, const char* msg, mi_output_fun* out, void* arg ) {
244
+ _mi_fprintf(out, arg, " %-10s:", msg);
245
+ mi_print_amount(stat->total, 1, out, arg);
246
+ _mi_fprintf(out, arg, "\n");
247
+ }
244
248
 
245
- static void mi_stat_average_print(size_t count, size_t total, const char* msg, mi_output_fun* out, void* arg) {
249
+ static void mi_stat_average_print(int64_t count, int64_t total, const char* msg, mi_output_fun* out, void* arg) {
246
250
  const int64_t avg_tens = (count == 0 ? 0 : (total*10 / count));
247
- const long avg_whole = (long)(avg_tens/10);
248
- const long avg_frac1 = (long)(avg_tens%10);
249
- _mi_fprintf(out, arg, " %-10s: %5ld.%ld avg\n", msg, avg_whole, avg_frac1);
251
+ const int64_t avg_whole = avg_tens/10;
252
+ const int64_t avg_frac1 = avg_tens%10;
253
+ _mi_fprintf(out, arg, " %-10s: %5lld.%lld avg\n", msg, avg_whole, avg_frac1);
250
254
  }
251
255
 
252
256
 
@@ -335,7 +339,7 @@ mi_decl_export void mi_process_info_print_out(mi_output_fun* out, void* arg) mi_
335
339
  _mi_fprintf(out, arg, "\n");
336
340
  }
337
341
 
338
- void _mi_stats_print(const char* name, size_t id, mi_stats_t* stats, mi_output_fun* out0, void* arg0) mi_attr_noexcept {
342
+ void _mi_stats_print(const char* name, size_t id, const mi_stats_t* stats, mi_output_fun* out0, void* arg0) mi_attr_noexcept {
339
343
  // wrap the output function to be line buffered
340
344
  char buf[256]; _mi_memzero_var(buf);
341
345
  buffered_t buffer = { out0, arg0, NULL, 0, 255 };
@@ -352,8 +356,8 @@ void _mi_stats_print(const char* name, size_t id, mi_stats_t* stats, mi_output_f
352
356
  mi_stats_print_bins(stats->malloc_bins, MI_BIN_HUGE, out, arg);
353
357
  #endif
354
358
  #if MI_STAT
355
- mi_stat_print(&stats->malloc_normal, "binned", (stats->malloc_normal_count.total == 0 ? 1 : -1), out, arg);
356
- mi_stat_print(&stats->malloc_huge, "huge", (stats->malloc_huge_count.total == 0 ? 1 : -1), out, arg);
359
+ mi_stat_print(&stats->malloc_normal, "binned", (stats->malloc_normal_count.total == 0 ? -1 : 1), out, arg);
360
+ mi_stat_print(&stats->malloc_huge, "huge", (stats->malloc_huge_count.total == 0 ? -1 : 1), out, arg);
357
361
  mi_stat_count_t total = { 0,0,0 };
358
362
  mi_stat_count_add_mt(&total, &stats->malloc_normal);
359
363
  mi_stat_count_add_mt(&total, &stats->malloc_huge);
@@ -371,8 +375,8 @@ void _mi_stats_print(const char* name, size_t id, mi_stats_t* stats, mi_output_f
371
375
  // mi_stat_print(&stats->segments, "segments", -1, out, arg);
372
376
  // mi_stat_print(&stats->segments_abandoned, "-abandoned", -1, out, arg);
373
377
  // mi_stat_print(&stats->segments_cache, "-cached", -1, out, arg);
374
- mi_stat_print(&stats->pages, "pages", -1, out, arg);
375
- mi_stat_print(&stats->pages_abandoned, "abandoned", -1, out, arg);
378
+ mi_stat_print(&stats->pages, "pages", 0, out, arg);
379
+ mi_stat_print(&stats->pages_abandoned, "abandoned", 0, out, arg);
376
380
  mi_stat_counter_print(&stats->pages_reclaim_on_alloc, "reclaima", out, arg);
377
381
  mi_stat_counter_print(&stats->pages_reclaim_on_free, "reclaimf", out, arg);
378
382
  mi_stat_counter_print(&stats->pages_reabandon_full, "reabandon", out, arg);
@@ -387,8 +391,8 @@ void _mi_stats_print(const char* name, size_t id, mi_stats_t* stats, mi_output_f
387
391
  mi_print_header("arenas", out, arg);
388
392
  mi_stat_print_ex(&stats->reserved, "reserved", 1, out, arg, "");
389
393
  mi_stat_print_ex(&stats->committed, "committed", 1, out, arg, "");
390
- mi_stat_counter_print(&stats->reset, "reset", out, arg);
391
- mi_stat_counter_print(&stats->purged, "purged", out, arg);
394
+ mi_stat_counter_print_size(&stats->reset, "reset", out, arg);
395
+ mi_stat_counter_print_size(&stats->purged, "purged", out, arg);
392
396
 
393
397
  mi_stat_counter_print(&stats->arena_count, "arenas", out, arg);
394
398
  mi_stat_counter_print(&stats->arena_rollback_count, "rollback", out, arg);
@@ -397,11 +401,13 @@ void _mi_stats_print(const char* name, size_t id, mi_stats_t* stats, mi_output_f
397
401
  mi_stat_counter_print(&stats->reset_calls, "resets", out, arg);
398
402
  mi_stat_counter_print(&stats->purge_calls, "purges", out, arg);
399
403
  mi_stat_counter_print(&stats->malloc_guarded_count, "guarded", out, arg);
400
- mi_stat_print_ex(&stats->heaps, "heaps", -1, out, arg, "");
404
+ mi_stat_print_ex(&stats->theaps, "theaps", 0, out, arg, "");
405
+ mi_stat_print_ex(&stats->heaps, "heaps", 0, out, arg, "");
406
+ mi_stat_counter_print(&stats->heaps_delete_wait, "heap waits", out, arg);
401
407
  _mi_fprintf(out, arg, "\n");
402
408
 
403
409
  mi_print_header("process", out, arg);
404
- mi_stat_print_ex(&stats->threads, "threads", -1, out, arg, "");
410
+ mi_stat_print_ex(&stats->threads, "threads", 0, out, arg, "");
405
411
  _mi_fprintf(out, arg, " %-10s: %5i\n", "numa nodes", _mi_os_numa_node_count());
406
412
  mi_process_info_print_out(out, arg);
407
413
  }
@@ -416,7 +422,7 @@ void _mi_stats_init(void) {
416
422
  if (mi_process_start == 0) { mi_process_start = _mi_clock_start(); };
417
423
  }
418
424
 
419
- static void mi_stats_add_into(mi_stats_t* to, mi_stats_t* from) {
425
+ static void mi_stats_add_into(mi_stats_t* to, const mi_stats_t* from) {
420
426
  mi_assert_internal(to != NULL && from != NULL);
421
427
  if (to == from) return;
422
428
  mi_stats_add(to, from);
@@ -429,14 +435,14 @@ void _mi_stats_merge_into(mi_stats_t* to, mi_stats_t* from) {
429
435
  _mi_memzero(from, sizeof(mi_stats_t));
430
436
  }
431
437
 
432
- static mi_stats_t* mi_stats_merge_theap_to_heap(mi_theap_t* theap) mi_attr_noexcept {
438
+ static const mi_stats_t* mi_stats_merge_theap_to_heap(mi_theap_t* theap) mi_attr_noexcept {
433
439
  mi_stats_t* stats = &theap->stats;
434
- mi_stats_t* heap_stats = &theap->heap->stats;
440
+ mi_stats_t* heap_stats = &_mi_theap_heap(theap)->stats;
435
441
  _mi_stats_merge_into( heap_stats, stats );
436
442
  return heap_stats;
437
443
  }
438
444
 
439
- static mi_stats_t* mi_heap_get_stats(mi_heap_t* heap) {
445
+ static const mi_stats_t* mi_heap_get_stats(mi_heap_t* heap) {
440
446
  if (heap==NULL) { heap = mi_heap_main(); }
441
447
  mi_theap_t* theap = _mi_heap_theap_peek(heap);
442
448
  if (theap==NULL) return &heap->stats;
@@ -473,7 +479,7 @@ void mi_subproc_heap_stats_print_out(mi_subproc_id_t subproc_id, mi_output_fun*
473
479
  mi_subproc_t* subproc = _mi_subproc_from_id(subproc_id);
474
480
  if (subproc==NULL) return;
475
481
  mi_heap_print_visit_info_t vinfo = { out, arg };
476
- mi_subproc_visit_heaps(subproc, &mi_heap_print_visitor, &vinfo);
482
+ mi_subproc_visit_heaps(subproc_id, &mi_heap_print_visitor, &vinfo);
477
483
  _mi_stats_print("subproc", subproc->subproc_seq, &subproc->stats, out, arg);
478
484
  }
479
485
 
@@ -482,7 +488,7 @@ void mi_subproc_heap_stats_print_out(mi_subproc_id_t subproc_id, mi_output_fun*
482
488
  void mi_subproc_stats_print_out(mi_subproc_id_t subproc_id, mi_output_fun* out, void* arg) mi_attr_noexcept {
483
489
  mi_subproc_t* subproc = _mi_subproc_from_id(subproc_id);
484
490
  if (subproc==NULL) return;
485
- mi_stats_t_decl(stats);
491
+ mi_stats_t_decl(stats);
486
492
  if (mi_subproc_stats_get(subproc_id, &stats)) {
487
493
  _mi_stats_print("subproc", subproc->subproc_seq, &stats, out, arg);
488
494
  }
@@ -502,7 +508,7 @@ void mi_stats_print(void* out) mi_attr_noexcept {
502
508
  void mi_thread_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept {
503
509
  mi_theap_t* theap = _mi_theap_default();
504
510
  if (theap==NULL || !mi_theap_is_initialized(theap)) return;
505
- _mi_stats_print("heap", theap->heap->heap_seq, &theap->stats, out, arg);
511
+ _mi_stats_print("heap", _mi_theap_heap(theap)->heap_seq, &theap->stats, out, arg);
506
512
  mi_stats_merge_theap_to_heap(_mi_theap_default());
507
513
  }
508
514
 
@@ -537,12 +543,15 @@ mi_msecs_t _mi_clock_end(mi_msecs_t start) {
537
543
 
538
544
  mi_decl_export void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) mi_attr_noexcept
539
545
  {
540
- mi_subproc_t* subproc = _mi_subproc_main();
541
546
  mi_process_info_t pinfo;
542
547
  _mi_memzero_var(pinfo);
543
548
  pinfo.elapsed = _mi_clock_end(mi_process_start);
544
- pinfo.current_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)(&subproc->stats.committed.current)));
545
- pinfo.peak_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)(&subproc->stats.committed.peak)));
549
+ { const mi_subproc_t* subproc = _mi_subproc_main();
550
+ if (subproc!=NULL) {
551
+ pinfo.current_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)(&subproc->stats.committed.current)));
552
+ pinfo.peak_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)(&subproc->stats.committed.peak)));
553
+ }
554
+ }
546
555
  pinfo.current_rss = pinfo.current_commit;
547
556
  pinfo.peak_rss = pinfo.peak_commit;
548
557
  pinfo.utime = 0;
@@ -575,34 +584,36 @@ size_t mi_stats_get_bin_size(size_t bin) mi_attr_noexcept {
575
584
  return _mi_bin_size(bin);
576
585
  }
577
586
 
578
- static bool _mi_stats_get(mi_stats_t* stats_in, mi_stats_t* stats_out) mi_attr_noexcept {
579
- if (stats_out == NULL || stats_out->size != sizeof(mi_stats_t) || stats_out->version != MI_STAT_VERSION) return false;
580
- if (stats_in == NULL || stats_in->size != stats_out->size) return false;
581
- _mi_memcpy(stats_out, stats_in, stats_out->size);
587
+ static bool mi_stats_copy(mi_stats_t* stats_to, const mi_stats_t* stats_from) mi_attr_noexcept {
588
+ if (stats_to == NULL || stats_to->size != sizeof(mi_stats_t) || stats_to->version != MI_STAT_VERSION) return false;
589
+ if (stats_from == NULL || stats_from->size != stats_to->size) return false;
590
+ _mi_memcpy(stats_to, stats_from, stats_to->size);
582
591
  return true;
583
592
  }
584
593
 
585
594
  bool mi_subproc_stats_get_exclusive(mi_subproc_id_t subproc_id, mi_stats_t* stats) mi_attr_noexcept {
586
- return _mi_stats_get(&_mi_subproc_from_id(subproc_id)->stats, stats);
595
+ const mi_subproc_t* subproc = _mi_subproc_from_id(subproc_id);
596
+ if (subproc==NULL) return false;
597
+ return mi_stats_copy(stats,&subproc->stats);
587
598
  }
588
599
 
589
600
  bool mi_heap_stats_get(mi_heap_t* heap, mi_stats_t* stats) mi_attr_noexcept {
590
- return _mi_stats_get(mi_heap_get_stats(heap), stats);
601
+ return mi_stats_copy(stats, mi_heap_get_stats(heap));
591
602
  }
592
603
 
593
604
 
594
605
  static bool mi_cdecl mi_heap_aggregate_visitor(mi_heap_t* heap, void* arg) {
595
606
  mi_stats_t* stats = (mi_stats_t*)arg;
596
- mi_stats_add_into(stats, &heap->stats);
607
+ mi_stats_add_into(stats, mi_heap_get_stats(heap));
597
608
  return true;
598
609
  }
599
610
 
600
611
  bool mi_subproc_stats_get(mi_subproc_id_t subproc_id, mi_stats_t* stats) mi_attr_noexcept {
612
+ if (stats==NULL) return false;
601
613
  mi_subproc_t* subproc = _mi_subproc_from_id(subproc_id);
602
- if (stats == NULL || stats->size != sizeof(mi_stats_t) || stats->version != MI_STAT_VERSION) return false;
603
- _mi_memzero(stats,stats->size);
604
- mi_subproc_visit_heaps(subproc, &mi_heap_aggregate_visitor, stats);
605
- mi_stats_add_into(stats, &subproc->stats);
614
+ if (subproc == NULL) return false;
615
+ if (!mi_stats_copy(stats, &subproc->stats)) return false;
616
+ mi_subproc_visit_heaps(subproc_id, &mi_heap_aggregate_visitor, stats);
606
617
  return true;
607
618
  }
608
619
 
@@ -651,7 +662,7 @@ static void mi_json_buf_print(mi_json_buf_t* hbuf, const char* msg) {
651
662
  hbuf->buf[hbuf->used] = 0;
652
663
  }
653
664
 
654
- static void mi_json_buf_print_count_bin(mi_json_buf_t* hbuf, const char* prefix, mi_stat_count_t* stat, size_t bin, bool add_comma) {
665
+ static void mi_json_buf_print_count_bin(mi_json_buf_t* hbuf, const char* prefix, const mi_stat_count_t* stat, size_t bin, bool add_comma) {
655
666
  const size_t binsize = mi_stats_get_bin_size(bin);
656
667
  const size_t pagesize = (binsize <= MI_SMALL_MAX_OBJ_SIZE ? MI_SMALL_PAGE_SIZE :
657
668
  (binsize <= MI_MEDIUM_MAX_OBJ_SIZE ? MI_MEDIUM_PAGE_SIZE :
@@ -662,7 +673,7 @@ static void mi_json_buf_print_count_bin(mi_json_buf_t* hbuf, const char* prefix,
662
673
  mi_json_buf_print(hbuf, buf);
663
674
  }
664
675
 
665
- static void mi_json_buf_print_count_cbin(mi_json_buf_t* hbuf, const char* prefix, mi_stat_count_t* stat, mi_chunkbin_t bin, bool add_comma) {
676
+ static void mi_json_buf_print_count_cbin(mi_json_buf_t* hbuf, const char* prefix, const mi_stat_count_t* stat, mi_chunkbin_t bin, bool add_comma) {
666
677
  const char* cbin = " ";
667
678
  switch(bin) {
668
679
  case MI_CBIN_SMALL: cbin = "S"; break;
@@ -678,14 +689,14 @@ static void mi_json_buf_print_count_cbin(mi_json_buf_t* hbuf, const char* prefix
678
689
  mi_json_buf_print(hbuf, buf);
679
690
  }
680
691
 
681
- static void mi_json_buf_print_count(mi_json_buf_t* hbuf, const char* prefix, mi_stat_count_t* stat, bool add_comma) {
692
+ static void mi_json_buf_print_count(mi_json_buf_t* hbuf, const char* prefix, const mi_stat_count_t* stat, bool add_comma) {
682
693
  char buf[128];
683
694
  _mi_snprintf(buf, 128, "%s{ \"total\": %lld, \"peak\": %lld, \"current\": %lld }%s\n", prefix, stat->total, stat->peak, stat->current, (add_comma ? "," : ""));
684
695
  buf[127] = 0;
685
696
  mi_json_buf_print(hbuf, buf);
686
697
  }
687
698
 
688
- static void mi_json_buf_print_count_value(mi_json_buf_t* hbuf, const char* name, mi_stat_count_t* stat) {
699
+ static void mi_json_buf_print_count_value(mi_json_buf_t* hbuf, const char* name, const mi_stat_count_t* stat) {
689
700
  char buf[128];
690
701
  _mi_snprintf(buf, 128, " \"%s\": ", name);
691
702
  buf[127] = 0;
@@ -707,14 +718,14 @@ static void mi_json_buf_print_size(mi_json_buf_t* hbuf, const char* name, size_t
707
718
  mi_json_buf_print(hbuf, buf);
708
719
  }
709
720
 
710
- static void mi_json_buf_print_counter_value(mi_json_buf_t* hbuf, const char* name, mi_stat_counter_t* stat) {
721
+ static void mi_json_buf_print_counter_value(mi_json_buf_t* hbuf, const char* name, const mi_stat_counter_t* stat) {
711
722
  mi_json_buf_print_value(hbuf, name, stat->total);
712
723
  }
713
724
 
714
725
  #define MI_STAT_COUNT(stat) mi_json_buf_print_count_value(&hbuf, #stat, &stats->stat);
715
726
  #define MI_STAT_COUNTER(stat) mi_json_buf_print_counter_value(&hbuf, #stat, &stats->stat);
716
727
 
717
- static char* mi_stats_get_json_from(mi_stats_t* stats, size_t output_size, char* output_buf) mi_attr_noexcept {
728
+ static char* mi_stats_get_json_from(const mi_stats_t* stats, size_t output_size, char* output_buf) mi_attr_noexcept {
718
729
  if (stats==NULL || stats->size!=sizeof(mi_stats_t) || stats->version!=MI_STAT_VERSION) return NULL;
719
730
  mi_json_buf_t hbuf = { NULL, 0, 0, true };
720
731
  if (output_size > 0 && output_buf != NULL) {
@@ -769,7 +780,7 @@ static char* mi_stats_get_json_from(mi_stats_t* stats, size_t output_size, char*
769
780
  for (size_t i = 0; i < MI_CBIN_COUNT; i++) {
770
781
  mi_json_buf_print_count_cbin(&hbuf, " ", &stats->chunk_bins[i], (mi_chunkbin_t)i, i!=MI_CBIN_COUNT-1);
771
782
  }
772
- mi_json_buf_print(&hbuf, " ]\n");
783
+ mi_json_buf_print(&hbuf, " ]\n");
773
784
  mi_json_buf_print(&hbuf, "}\n");
774
785
  if (hbuf.used >= hbuf.size) {
775
786
  // failed
@@ -786,7 +797,7 @@ char* mi_subproc_stats_get_json(mi_subproc_id_t subproc_id, size_t buf_size, cha
786
797
  if (subproc==NULL) return NULL;
787
798
  mi_stats_t_decl(stats);
788
799
  if (!mi_subproc_stats_get(subproc_id,&stats)) return NULL;
789
- return mi_stats_get_json_from(&subproc->stats, buf_size, buf);
800
+ return mi_stats_get_json_from(&stats, buf_size, buf);
790
801
  }
791
802
 
792
803
  char* mi_heap_stats_get_json(mi_heap_t* heap, size_t buf_size, char* buf) mi_attr_noexcept {
@@ -21,7 +21,7 @@ terms of the MIT license. A copy of the license can be found in the file
21
21
  typedef bool (theap_page_visitor_fun)(mi_theap_t* theap, mi_page_queue_t* pq, mi_page_t* page, void* arg1, void* arg2);
22
22
 
23
23
  // Visit all pages in a theap; returns `false` if break was called.
24
- static bool mi_theap_visit_pages(mi_theap_t* theap, theap_page_visitor_fun* fn, void* arg1, void* arg2)
24
+ static bool mi_theap_visit_pages(mi_theap_t* theap, theap_page_visitor_fun* fn, bool include_full, void* arg1, void* arg2)
25
25
  {
26
26
  if (theap==NULL || theap->page_count==0) return 0;
27
27
 
@@ -31,7 +31,8 @@ static bool mi_theap_visit_pages(mi_theap_t* theap, theap_page_visitor_fun* fn,
31
31
  size_t count = 0;
32
32
  #endif
33
33
 
34
- for (size_t i = 0; i <= MI_BIN_FULL; i++) {
34
+ const size_t max_bin = (include_full ? MI_BIN_FULL : MI_BIN_FULL - 1);
35
+ for (size_t i = 0; i <= max_bin; i++) {
35
36
  mi_page_queue_t* pq = &theap->pages[i];
36
37
  mi_page_t* page = pq->first;
37
38
  while(page != NULL) {
@@ -44,7 +45,7 @@ static bool mi_theap_visit_pages(mi_theap_t* theap, theap_page_visitor_fun* fn,
44
45
  page = next; // and continue
45
46
  }
46
47
  }
47
- mi_assert_internal(count == total);
48
+ mi_assert_internal(!include_full || count == total);
48
49
  return true;
49
50
  }
50
51
 
@@ -62,7 +63,7 @@ static bool mi_theap_page_is_valid(mi_theap_t* theap, mi_page_queue_t* pq, mi_pa
62
63
  #if MI_DEBUG>=3
63
64
  static bool mi_theap_is_valid(mi_theap_t* theap) {
64
65
  mi_assert_internal(theap!=NULL);
65
- mi_theap_visit_pages(theap, &mi_theap_page_is_valid, NULL, NULL);
66
+ mi_theap_visit_pages(theap, &mi_theap_page_is_valid, true, NULL, NULL);
66
67
  for (size_t bin = 0; bin < MI_BIN_COUNT; bin++) {
67
68
  mi_assert_internal(_mi_page_queue_is_valid(theap, &theap->pages[bin]));
68
69
  }
@@ -109,7 +110,7 @@ static bool mi_theap_page_collect(mi_theap_t* theap, mi_page_queue_t* pq, mi_pag
109
110
 
110
111
  static void mi_theap_merge_stats(mi_theap_t* theap) {
111
112
  mi_assert_internal(mi_theap_is_initialized(theap));
112
- _mi_stats_merge_into(&theap->heap->stats, &theap->stats);
113
+ _mi_stats_merge_into(&_mi_theap_heap(theap)->stats, &theap->stats);
113
114
  }
114
115
 
115
116
  static void mi_theap_collect_ex(mi_theap_t* theap, mi_collect_t collect)
@@ -127,7 +128,7 @@ static void mi_theap_collect_ex(mi_theap_t* theap, mi_collect_t collect)
127
128
  _mi_theap_collect_retired(theap, force);
128
129
 
129
130
  // collect all pages owned by this thread
130
- mi_theap_visit_pages(theap, &mi_theap_page_collect, &collect, NULL);
131
+ mi_theap_visit_pages(theap, &mi_theap_page_collect, (collect!=MI_NORMAL), &collect, NULL); // dont normally visit full pages, see issue #1220
131
132
 
132
133
  // collect arenas (this is program wide so don't force purges on abandonment of threads)
133
134
  //mi_atomic_storei64_release(&theap->tld->subproc->purge_expire, 1);
@@ -173,11 +174,14 @@ mi_theap_t* mi_theap_get_default(void) {
173
174
  void _mi_theap_init(mi_theap_t* theap, mi_heap_t* heap, mi_tld_t* tld)
174
175
  {
175
176
  mi_assert_internal(theap!=NULL);
177
+ mi_assert_internal(heap!=NULL);
176
178
  mi_memid_t memid = theap->memid;
177
179
  _mi_memcpy_aligned(theap, &_mi_theap_empty, sizeof(mi_theap_t));
178
180
  theap->memid = memid;
179
- theap->heap = heap;
181
+ theap->refcount = 1;
180
182
  theap->tld = tld; // avoid reading the thread-local tld during initialization
183
+ mi_atomic_store_ptr_relaxed(mi_heap_t,&theap->heap,heap);
184
+ mi_assert_internal(theap->stats.size == sizeof(mi_stats_t));
181
185
 
182
186
  _mi_theap_options_init(theap);
183
187
  if (theap->tld->is_in_threadpool) {
@@ -191,11 +195,14 @@ void _mi_theap_init(mi_theap_t* theap, mi_heap_t* heap, mi_tld_t* tld)
191
195
  }
192
196
 
193
197
  // push on the thread local theaps list
194
- mi_theap_t* head = theap->tld->theaps;
195
- theap->tprev = NULL;
196
- theap->tnext = head;
197
- if (head!=NULL) { head->tprev = theap; }
198
- theap->tld->theaps = theap;
198
+ mi_theap_t* head = NULL;
199
+ mi_lock(&theap->tld->theaps_lock) {
200
+ head = theap->tld->theaps;
201
+ theap->tprev = NULL;
202
+ theap->tnext = head;
203
+ if (head!=NULL) { head->tprev = theap; }
204
+ theap->tld->theaps = theap;
205
+ }
199
206
 
200
207
  // initialize random
201
208
  if (head == NULL) { // first theap in this thread?
@@ -210,6 +217,7 @@ void _mi_theap_init(mi_theap_t* theap, mi_heap_t* heap, mi_tld_t* tld)
210
217
  }
211
218
  theap->cookie = _mi_theap_random_next(theap) | 1;
212
219
  _mi_theap_guarded_init(theap);
220
+ mi_subproc_stat_increase(_mi_subproc(),theaps,1);
213
221
 
214
222
  // push on the heap's theap list
215
223
  mi_lock(&heap->theaps_lock) {
@@ -256,37 +264,70 @@ uintptr_t _mi_theap_random_next(mi_theap_t* theap) {
256
264
  return _mi_random_next(&theap->random);
257
265
  }
258
266
 
259
- // called from `mi_theap_delete` to free the internal theap resources.
260
- void _mi_theap_free(mi_theap_t* theap) {
261
- mi_assert(theap != NULL);
262
- mi_assert_internal(mi_theap_is_initialized(theap));
263
- if (theap==NULL || !mi_theap_is_initialized(theap)) return;
267
+ static void mi_theap_free_mem(mi_theap_t* theap) {
268
+ if (theap!=NULL) {
269
+ mi_subproc_stat_decrease(_mi_subproc(),theaps,1);
270
+ // free the used memory
271
+ if (theap->memid.memkind == MI_MEM_HEAP_MAIN) { // note: for now unused as it would access theap_default stats in mi_free of the current theap
272
+ mi_assert_internal(_mi_is_heap_main(mi_heap_of(theap)));
273
+ mi_free(theap);
274
+ }
275
+ else if (theap->memid.memkind == MI_MEM_META) {
276
+ _mi_meta_free(theap, sizeof(*theap), theap->memid);
277
+ }
278
+ else {
279
+ _mi_arenas_free(theap, _mi_align_up(sizeof(*theap),MI_ARENA_MIN_OBJ_SIZE), theap->memid ); // issue #1168, avoid assertion failure
280
+ }
281
+ }
282
+ }
264
283
 
265
- // merge stats to the owning heap
266
- mi_theap_merge_stats(theap);
284
+ void _mi_theap_incref(mi_theap_t* theap) {
285
+ if (theap!=NULL && theap->memid.memkind > MI_MEM_STATIC) {
286
+ mi_atomic_increment_acq_rel(&theap->refcount);
287
+ }
288
+ }
267
289
 
268
- // remove ourselves from the heap theaps list
269
- mi_lock(&theap->heap->theaps_lock) {
270
- if (theap->hnext != NULL) { theap->hnext->hprev = theap->hprev; }
271
- if (theap->hprev != NULL) { theap->hprev->hnext = theap->hnext; }
272
- else { mi_assert_internal(theap->heap->theaps == theap); theap->heap->theaps = theap->hnext; }
290
+ void _mi_theap_decref(mi_theap_t* theap) {
291
+ if (theap!=NULL && theap->memid.memkind > MI_MEM_STATIC) {
292
+ if (mi_atomic_decrement_acq_rel(&theap->refcount) == 1) {
293
+ mi_theap_free_mem(theap);
294
+ }
273
295
  }
296
+ }
274
297
 
275
- // remove ourselves from the thread local theaps list
276
- if (theap->tnext != NULL) { theap->tnext->tprev = theap->tprev; }
277
- if (theap->tprev != NULL) { theap->tprev->tnext = theap->tnext; }
278
- else { mi_assert_internal(theap->tld->theaps == theap); theap->tld->theaps = theap->tnext; }
279
298
 
280
- // and free the used memory
281
- if (theap->memid.memkind == MI_MEM_HEAP_MAIN) { // note: for now unused as it would access theap_default stats in mi_free of the current theap
282
- mi_assert_internal(_mi_is_heap_main(mi_heap_of(theap)));
283
- mi_free(theap);
284
- }
285
- else if (theap->memid.memkind == MI_MEM_META) {
286
- _mi_meta_free(theap, sizeof(*theap), theap->memid);
299
+ // called from `mi_theap_delete` to free the internal theap resources.
300
+ bool _mi_theap_free(mi_theap_t* theap, bool acquire_heap_theaps_lock, bool acquire_tld_theaps_lock) {
301
+ mi_assert(theap != NULL);
302
+ if (theap==NULL) return true;
303
+
304
+ mi_heap_t* const heap = mi_atomic_exchange_ptr_acq_rel(mi_heap_t, &theap->heap, NULL);
305
+ if (heap==NULL) {
306
+ // concurrent interaction, retry in an outer loop (as the other thread may be blocked on our lock)
307
+ return false;
287
308
  }
288
309
  else {
289
- _mi_arenas_free(theap, _mi_align_up(sizeof(*theap),MI_ARENA_MIN_OBJ_SIZE), theap->memid ); // issue #1168, avoid assertion failure
310
+ // merge stats to the owning heap
311
+ _mi_stats_merge_into(&heap->stats, &theap->stats);
312
+
313
+ // remove ourselves from the heap theaps list
314
+ mi_lock_maybe(&heap->theaps_lock, acquire_heap_theaps_lock) {
315
+ if (theap->hnext != NULL) { theap->hnext->hprev = theap->hprev; }
316
+ if (theap->hprev != NULL) { theap->hprev->hnext = theap->hnext; }
317
+ else { mi_assert_internal(heap->theaps == theap); heap->theaps = theap->hnext; }
318
+ theap->hnext = theap->hprev = NULL;
319
+ }
320
+
321
+ // remove ourselves from the thread local theaps list
322
+ mi_lock_maybe(&theap->tld->theaps_lock, acquire_tld_theaps_lock) {
323
+ if (theap->tnext != NULL) { theap->tnext->tprev = theap->tprev; }
324
+ if (theap->tprev != NULL) { theap->tprev->tnext = theap->tnext; }
325
+ else { mi_assert_internal(theap->tld->theaps == theap); theap->tld->theaps = theap->tnext; }
326
+ theap->tnext = theap->tprev = NULL;
327
+ }
328
+ theap->tld = NULL;
329
+ _mi_theap_decref(theap);
330
+ return true;
290
331
  }
291
332
  }
292
333
 
@@ -411,7 +452,7 @@ void _mi_theap_unsafe_destroy_all(mi_theap_t* theap) {
411
452
  ----------------------------------------------------------- */
412
453
 
413
454
  // Safe delete a theap without freeing any still allocated blocks in that theap.
414
- void _mi_theap_delete(mi_theap_t* theap)
455
+ void _mi_theap_delete(mi_theap_t* theap, bool acquire_tld_theaps_lock)
415
456
  {
416
457
  mi_assert(theap != NULL);
417
458
  mi_assert(mi_theap_is_initialized(theap));
@@ -422,7 +463,7 @@ void _mi_theap_delete(mi_theap_t* theap)
422
463
  _mi_theap_collect_abandon(theap);
423
464
 
424
465
  mi_assert_internal(theap->page_count==0);
425
- _mi_theap_free(theap);
466
+ _mi_theap_free(theap, true /* acquire heap->theaps_lock */, acquire_tld_theaps_lock);
426
467
  }
427
468
 
428
469
 
@@ -435,7 +476,7 @@ void mi_theap_unload(mi_theap_t* theap) {
435
476
  mi_assert(mi_theap_is_initialized(theap));
436
477
  mi_assert_expensive(mi_theap_is_valid(theap));
437
478
  if (theap==NULL || !mi_theap_is_initialized(theap)) return;
438
- if (theap->heap->exclusive_arena == NULL) {
479
+ if (_mi_theap_heap(theap)->exclusive_arena == NULL) {
439
480
  _mi_warning_message("cannot unload theaps that are not associated with an exclusive arena\n");
440
481
  return;
441
482
  }
@@ -455,7 +496,7 @@ void mi_theap_unload(mi_theap_t* theap) {
455
496
  bool mi_theap_reload(mi_theap_t* theap, mi_arena_id_t arena_id) {
456
497
  mi_assert(mi_theap_is_initialized(theap));
457
498
  if (theap==NULL || !mi_theap_is_initialized(theap)) return false;
458
- if (theap->heap->exclusive_arena == NULL) {
499
+ if (_mi_theap_heap(theap)->exclusive_arena == NULL) {
459
500
  _mi_warning_message("cannot reload theaps that were not associated with an exclusive arena\n");
460
501
  return false;
461
502
  }
@@ -464,8 +505,8 @@ bool mi_theap_reload(mi_theap_t* theap, mi_arena_id_t arena_id) {
464
505
  return false;
465
506
  }
466
507
  mi_arena_t* arena = _mi_arena_from_id(arena_id);
467
- if (theap->heap->exclusive_arena != arena) {
468
- _mi_warning_message("trying to reload a theap at a different arena address: %p vs %p\n", theap->heap->exclusive_arena, arena);
508
+ if (_mi_theap_heap(theap)->exclusive_arena != arena) {
509
+ _mi_warning_message("trying to reload a theap at a different arena address: %p vs %p\n", _mi_theap_heap(theap)->exclusive_arena, arena);
469
510
  return false;
470
511
  }
471
512
 
@@ -645,7 +686,7 @@ static bool mi_theap_visit_areas_page(mi_theap_t* theap, mi_page_queue_t* pq, mi
645
686
  // Visit all theap pages as areas
646
687
  static bool mi_theap_visit_areas(const mi_theap_t* theap, mi_theap_area_visit_fun* visitor, void* arg) {
647
688
  if (visitor == NULL) return false;
648
- return mi_theap_visit_pages((mi_theap_t*)theap, &mi_theap_visit_areas_page, (void*)(visitor), arg); // note: function pointer to void* :-{
689
+ return mi_theap_visit_pages((mi_theap_t*)theap, &mi_theap_visit_areas_page, true, (void*)(visitor), arg); // note: function pointer to void* :-{
649
690
  }
650
691
 
651
692
  // Just to pass arguments
@@ -657,7 +698,7 @@ typedef struct mi_visit_blocks_args_s {
657
698
 
658
699
  static bool mi_theap_area_visitor(const mi_theap_t* theap, const mi_theap_area_ex_t* xarea, void* arg) {
659
700
  mi_visit_blocks_args_t* args = (mi_visit_blocks_args_t*)arg;
660
- if (!args->visitor(theap->heap, &xarea->area, NULL, xarea->area.block_size, args->arg)) return false;
701
+ if (!args->visitor(_mi_theap_heap(theap), &xarea->area, NULL, xarea->area.block_size, args->arg)) return false;
661
702
  if (args->visit_blocks) {
662
703
  return _mi_theap_area_visit_blocks(&xarea->area, xarea->page, args->visitor, args->arg);
663
704
  }