@shd101wyy/yo 0.1.24 → 0.1.26

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 (104) hide show
  1. package/.github/skills/yo-async-effects/async-effects-recipes.md +6 -6
  2. package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +34 -0
  3. package/.github/skills/yo-syntax/syntax-cheatsheet.md +441 -2
  4. package/out/cjs/index.cjs +563 -567
  5. package/out/cjs/yo-cli.cjs +656 -651
  6. package/out/cjs/yo-lsp.cjs +614 -618
  7. package/out/esm/index.mjs +582 -586
  8. package/out/types/src/codegen/codegen-c.d.ts +2 -2
  9. package/out/types/src/codegen/functions/collection.d.ts +2 -2
  10. package/out/types/src/codegen/functions/context.d.ts +3 -2
  11. package/out/types/src/codegen/types/collection.d.ts +2 -2
  12. package/out/types/src/codegen/utils/index.d.ts +4 -1
  13. package/out/types/src/doc/builder.d.ts +2 -2
  14. package/out/types/src/evaluator/calls/closure-type.d.ts +2 -2
  15. package/out/types/src/evaluator/calls/record-type.d.ts +11 -0
  16. package/out/types/src/evaluator/context.d.ts +8 -9
  17. package/out/types/src/evaluator/index.d.ts +3 -3
  18. package/out/types/src/evaluator/types/record.d.ts +14 -0
  19. package/out/types/src/evaluator/types/validation.d.ts +2 -2
  20. package/out/types/src/evaluator/values/anonymous-module.d.ts +5 -5
  21. package/out/types/src/evaluator/values/impl.d.ts +1 -1
  22. package/out/types/src/expr.d.ts +2 -4
  23. package/out/types/src/function-value.d.ts +1 -1
  24. package/out/types/src/lsp/document-manager.d.ts +1 -1
  25. package/out/types/src/module-manager.d.ts +3 -3
  26. package/out/types/src/test-runner.d.ts +1 -0
  27. package/out/types/src/types/creators.d.ts +3 -4
  28. package/out/types/src/types/definitions.d.ts +8 -19
  29. package/out/types/src/types/guards.d.ts +3 -3
  30. package/out/types/src/types/tags.d.ts +0 -1
  31. package/out/types/src/types/utils.d.ts +1 -1
  32. package/out/types/src/value-tag.d.ts +0 -1
  33. package/out/types/src/value.d.ts +6 -13
  34. package/out/types/tsconfig.tsbuildinfo +1 -1
  35. package/package.json +1 -1
  36. package/std/error.yo +6 -6
  37. package/std/prelude.yo +1 -7
  38. package/vendor/mimalloc/.github/workflows/release.yaml +55 -0
  39. package/vendor/mimalloc/.github/workflows/stale.yaml +27 -0
  40. package/vendor/mimalloc/.github/workflows/test.yaml +163 -0
  41. package/vendor/mimalloc/CMakeLists.txt +52 -33
  42. package/vendor/mimalloc/azure-pipelines.yml +4 -3
  43. package/vendor/mimalloc/bin/bundle.bat +74 -0
  44. package/vendor/mimalloc/bin/bundle.sh +232 -0
  45. package/vendor/mimalloc/cmake/mimalloc-config-version.cmake +2 -2
  46. package/vendor/mimalloc/contrib/docker/alpine/Dockerfile +1 -1
  47. package/vendor/mimalloc/contrib/docker/alpine-arm32v7/Dockerfile +2 -2
  48. package/vendor/mimalloc/contrib/docker/alpine-x86/Dockerfile +1 -1
  49. package/vendor/mimalloc/contrib/docker/manylinux-x64/Dockerfile +1 -1
  50. package/vendor/mimalloc/contrib/vcpkg/portfile.cmake +4 -3
  51. package/vendor/mimalloc/contrib/vcpkg/vcpkg.json +1 -1
  52. package/vendor/mimalloc/doc/mimalloc-doc.h +42 -4
  53. package/vendor/mimalloc/doc/release-notes.md +15 -0
  54. package/vendor/mimalloc/ide/vs2022/mimalloc-lib.vcxproj +3 -3
  55. package/vendor/mimalloc/ide/vs2022/mimalloc-override-static-lib.vcxproj +511 -0
  56. package/vendor/mimalloc/ide/vs2022/mimalloc-override-static-lib.vcxproj.filters +117 -0
  57. package/vendor/mimalloc/ide/vs2022/mimalloc-test-dep.vcxproj +360 -0
  58. package/vendor/mimalloc/ide/vs2022/mimalloc-test-override-static.vcxproj +310 -0
  59. package/vendor/mimalloc/ide/vs2022/mimalloc.sln +92 -35
  60. package/vendor/mimalloc/include/mimalloc/atomic.h +178 -182
  61. package/vendor/mimalloc/include/mimalloc/bits.h +8 -10
  62. package/vendor/mimalloc/include/mimalloc/internal.h +76 -32
  63. package/vendor/mimalloc/include/mimalloc/prim.h +25 -18
  64. package/vendor/mimalloc/include/mimalloc/track.h +7 -2
  65. package/vendor/mimalloc/include/mimalloc/types.h +57 -29
  66. package/vendor/mimalloc/include/mimalloc-override.h +10 -10
  67. package/vendor/mimalloc/include/mimalloc-stats.h +18 -6
  68. package/vendor/mimalloc/include/mimalloc.h +22 -12
  69. package/vendor/mimalloc/readme.md +42 -17
  70. package/vendor/mimalloc/src/alloc-aligned.c +13 -11
  71. package/vendor/mimalloc/src/alloc-override.c +97 -17
  72. package/vendor/mimalloc/src/alloc-posix.c +44 -27
  73. package/vendor/mimalloc/src/alloc.c +73 -23
  74. package/vendor/mimalloc/src/arena-meta.c +3 -3
  75. package/vendor/mimalloc/src/arena.c +380 -192
  76. package/vendor/mimalloc/src/bitmap.c +68 -18
  77. package/vendor/mimalloc/src/bitmap.h +8 -4
  78. package/vendor/mimalloc/src/free.c +83 -47
  79. package/vendor/mimalloc/src/heap.c +94 -40
  80. package/vendor/mimalloc/src/init.c +273 -102
  81. package/vendor/mimalloc/src/libc.c +53 -8
  82. package/vendor/mimalloc/src/options.c +43 -40
  83. package/vendor/mimalloc/src/os.c +110 -45
  84. package/vendor/mimalloc/src/page-map.c +14 -8
  85. package/vendor/mimalloc/src/page-queue.c +9 -6
  86. package/vendor/mimalloc/src/page.c +26 -16
  87. package/vendor/mimalloc/src/prim/emscripten/prim.c +10 -1
  88. package/vendor/mimalloc/src/prim/osx/alloc-override-zone.c +35 -16
  89. package/vendor/mimalloc/src/prim/unix/prim.c +26 -22
  90. package/vendor/mimalloc/src/prim/wasi/prim.c +7 -4
  91. package/vendor/mimalloc/src/prim/windows/prim.c +247 -44
  92. package/vendor/mimalloc/src/random.c +8 -3
  93. package/vendor/mimalloc/src/stats.c +59 -48
  94. package/vendor/mimalloc/src/theap.c +85 -44
  95. package/vendor/mimalloc/src/threadlocal.c +102 -41
  96. package/vendor/mimalloc/test/main-override-static.c +31 -2
  97. package/vendor/mimalloc/test/main-override.c +27 -14
  98. package/vendor/mimalloc/test/main-static-dep.cpp +46 -0
  99. package/vendor/mimalloc/test/main-static-dep.h +11 -0
  100. package/vendor/mimalloc/test/test-api-fill.c +2 -2
  101. package/vendor/mimalloc/test/test-stress.c +3 -3
  102. package/vendor/mimalloc/test/test-wrong.c +11 -7
  103. package/out/types/src/evaluator/calls/module-type.d.ts +0 -11
  104. package/out/types/src/evaluator/types/module.d.ts +0 -19
@@ -22,6 +22,7 @@ char _mi_toupper(char c) {
22
22
  }
23
23
 
24
24
  int _mi_strnicmp(const char* s, const char* t, size_t n) {
25
+ mi_assert_internal(s!=NULL && t!=NULL);
25
26
  if (n == 0) return 0;
26
27
  for (; *s != 0 && *t != 0 && n > 0; s++, t++, n--) {
27
28
  if (_mi_toupper(*s) != _mi_toupper(*t)) break;
@@ -29,6 +30,15 @@ int _mi_strnicmp(const char* s, const char* t, size_t n) {
29
30
  return (n == 0 ? 0 : *s - *t);
30
31
  }
31
32
 
33
+ bool _mi_streq(const char* s, const char* t) {
34
+ if (s==NULL && t==NULL) return true;
35
+ if (s==NULL || t==NULL) return false;
36
+ for (; *s != 0 && *t != 0; s++, t++) {
37
+ if (*s != *t) break;
38
+ }
39
+ return (*s == *t);
40
+ }
41
+
32
42
  void _mi_strlcpy(char* dest, const char* src, size_t dest_size) {
33
43
  if (dest==NULL || src==NULL || dest_size == 0) return;
34
44
  // copy until end of src, or when dest is (almost) full
@@ -51,13 +61,6 @@ void _mi_strlcat(char* dest, const char* src, size_t dest_size) {
51
61
  _mi_strlcpy(dest, src, dest_size);
52
62
  }
53
63
 
54
- size_t _mi_strlen(const char* s) {
55
- if (s==NULL) return 0;
56
- size_t len = 0;
57
- while(s[len] != 0) { len++; }
58
- return len;
59
- }
60
-
61
64
  size_t _mi_strnlen(const char* s, size_t max_len) {
62
65
  if (s==NULL) return 0;
63
66
  size_t len = 0;
@@ -65,6 +68,10 @@ size_t _mi_strnlen(const char* s, size_t max_len) {
65
68
  return len;
66
69
  }
67
70
 
71
+ size_t _mi_strlen(const char* s) {
72
+ return _mi_strnlen(s,PTRDIFF_MAX);
73
+ }
74
+
68
75
  char* _mi_strnstr(char* s, size_t max_len, const char* pat) {
69
76
  if (s==NULL) return NULL;
70
77
  if (pat==NULL) return s;
@@ -94,6 +101,43 @@ bool _mi_getenv(const char* name, char* result, size_t result_size) {
94
101
  }
95
102
  #endif
96
103
 
104
+
105
+ // --------------------------------------------------------
106
+ // Define our own primitives for doing an action once
107
+ // --------------------------------------------------------
108
+
109
+ // Returns `true` only on the first invocation, signifying we can execute an action once.
110
+ // If it returns `true`, the caller should call `_mi_atomic_once_release` after performing the action.
111
+ // Other threads (than the initial thread that entered) will block until `_mi_atomic_once_release` has been called.
112
+ bool _mi_atomic_once_enter(mi_atomic_once_t* once) {
113
+ const uintptr_t once_tid = mi_atomic_load_acquire(&once->tid);
114
+ if mi_likely(once_tid == 1) {
115
+ return false; // already executed
116
+ }
117
+ const mi_threadid_t current_tid = _mi_thread_id();
118
+ if (once_tid == current_tid) {
119
+ return false; // recursive invocation; we need this for process_init for example
120
+ }
121
+
122
+ mi_lock_acquire(&once->lock);
123
+ uintptr_t expected = 0;
124
+ if (mi_atomic_cas_strong_acq_rel(&once->tid, &expected, current_tid)) { // could use atomic_load/store as well
125
+ return true; // should execute and release
126
+ }
127
+ else {
128
+ mi_lock_release(&once->lock);
129
+ return false; // already another thread entered and released
130
+ }
131
+ }
132
+
133
+ void _mi_atomic_once_release(mi_atomic_once_t* once) {
134
+ if (mi_atomic_load_acquire(&once->tid)>1) { // paranoia
135
+ mi_atomic_store_release(&once->tid,1); // done executing
136
+ mi_lock_release(&once->lock);
137
+ }
138
+ }
139
+
140
+
97
141
  // --------------------------------------------------------
98
142
  // Define our own limited `_mi_vsnprintf` and `_mi_snprintf`
99
143
  // This is mostly to avoid calling these when libc is not yet
@@ -244,7 +288,8 @@ int _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args) {
244
288
  else x = va_arg(args, unsigned int);
245
289
  }
246
290
  else if (c == 'p') {
247
- x = va_arg(args, uintptr_t);
291
+ void* const p = va_arg(args, void*);
292
+ x = (uintptr_t)p;
248
293
  mi_outs("0x", &out, end);
249
294
  start = out;
250
295
  width = (width >= 2 ? width - 2 : 0);
@@ -77,7 +77,7 @@ int mi_version(void) mi_attr_noexcept {
77
77
  #endif
78
78
 
79
79
  #ifndef MI_DEFAULT_GUARDED_SAMPLE_RATE
80
- #if MI_GUARDED
80
+ #if MI_GUARDED && !MI_DEBUG
81
81
  #define MI_DEFAULT_GUARDED_SAMPLE_RATE 4000
82
82
  #else
83
83
  #define MI_DEFAULT_GUARDED_SAMPLE_RATE 0
@@ -136,11 +136,7 @@ static mi_option_desc_t mi_options[_mi_option_last] =
136
136
  { 0, MI_OPTION_UNINIT, MI_OPTION(deprecated_page_reset) }, // reset page memory on free
137
137
  { 0, MI_OPTION_UNINIT, MI_OPTION(deprecated_abandoned_page_purge) },
138
138
  { 0, MI_OPTION_UNINIT, MI_OPTION(deprecated_segment_reset) }, // reset segment memory on free (needs eager commit)
139
- #if defined(__NetBSD__)
140
- { 0, MI_OPTION_UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed
141
- #else
142
139
  { 1, MI_OPTION_UNINIT, MI_OPTION(deprecated_eager_commit_delay) },
143
- #endif
144
140
  { 1000,MI_OPTION_UNINIT, MI_OPTION_LEGACY(purge_delay,reset_delay) }, // purge delay in milli-seconds
145
141
  { 0, MI_OPTION_UNINIT, MI_OPTION(use_numa_nodes) }, // 0 = use available numa nodes, otherwise use at most N nodes.
146
142
  { 0, MI_OPTION_UNINIT, MI_OPTION_LEGACY(disallow_os_alloc,limit_os_alloc) }, // 1 = do not use OS memory for allocation (but only reserved arenas)
@@ -179,9 +175,10 @@ static mi_option_desc_t mi_options[_mi_option_last] =
179
175
  MI_OPTION_UNINIT, MI_OPTION(page_cross_thread_max_reclaim) }, // don't reclaim (small) pages across threads if we already own N pages in that size class
180
176
  { MI_DEFAULT_ALLOW_THP,
181
177
  MI_OPTION_UNINIT, MI_OPTION(allow_thp) }, // allow transparent huge pages? (=1) (on Android =0 by default). Set to 0 to disable THP for the process.
182
- { 0, MI_OPTION_UNINIT, MI_OPTION(minimal_purge_size) }, // set minimal purge size (in KiB) (=0). By default set to either 64 or 2048 if THP is enabled.
178
+ { 0, MI_OPTION_UNINIT, MI_OPTION(minimal_purge_size) }, // set minimal purge size (in KiB) (=0). Using 0 resolves to either 64 (or 2048 if `mi_option_allow_thp==2`).
183
179
  { MI_DEFAULT_ARENA_MAX_OBJECT_SIZE,
184
180
  MI_OPTION_UNINIT, MI_OPTION(arena_max_object_size) }, // set maximal object size that can be allocated in an arena (in KiB) (=2GiB on 64-bit).
181
+ { 0, MI_OPTION_UNINIT, MI_OPTION(arena_is_numa_local) }, // associate local numa node with an initial arena allocation
185
182
  };
186
183
 
187
184
  static void mi_option_init(mi_option_desc_t* desc);
@@ -221,8 +218,8 @@ void _mi_options_post_init(void) {
221
218
  mi_decl_export void mi_options_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept
222
219
  {
223
220
  // show version
224
- const int vermajor = MI_MALLOC_VERSION/1000;
225
- const int verminor = (MI_MALLOC_VERSION%1000)/100;
221
+ const int vermajor = MI_MALLOC_VERSION/10000;
222
+ const int verminor = (MI_MALLOC_VERSION%10000)/100;
226
223
  const int verpatch = (MI_MALLOC_VERSION%100);
227
224
  _mi_fprintf(out, arg, "v%i.%i.%i%s%s (built on %s, %s)\n", vermajor, verminor, verpatch,
228
225
  #if defined(MI_CMAKE_BUILD_TYPE)
@@ -291,7 +288,9 @@ mi_decl_nodiscard size_t mi_option_get_size(mi_option_t option) {
291
288
  const long x = mi_option_get(option);
292
289
  size_t size = (x < 0 ? 0 : (size_t)x);
293
290
  if (mi_option_has_size_in_kib(option)) {
294
- size *= MI_KiB;
291
+ if (mi_mul_overflow(size, MI_KiB, &size)) {
292
+ size = MI_MAX_ALLOC_SIZE;
293
+ }
295
294
  }
296
295
  return size;
297
296
  }
@@ -355,36 +354,41 @@ static void mi_cdecl mi_out_stderr(const char* msg, void* arg) {
355
354
  #ifndef MI_MAX_DELAY_OUTPUT
356
355
  #define MI_MAX_DELAY_OUTPUT ((size_t)(16*1024))
357
356
  #endif
358
- static char mi_output_buffer[MI_MAX_DELAY_OUTPUT+1];
357
+ static char out_buf[MI_MAX_DELAY_OUTPUT+1];
359
358
  static _Atomic(size_t) out_len;
359
+ static mi_lock_t out_buf_lock = MI_LOCK_INITIALIZER;
360
360
 
361
361
  static void mi_cdecl mi_out_buf(const char* msg, void* arg) {
362
362
  MI_UNUSED(arg);
363
363
  if (msg==NULL) return;
364
- if (mi_atomic_load_relaxed(&out_len)>=MI_MAX_DELAY_OUTPUT) return;
364
+ if (mi_atomic_load_acquire(&out_len)>=MI_MAX_DELAY_OUTPUT) return;
365
365
  size_t n = _mi_strlen(msg);
366
- if (n==0) return;
367
- // claim space
368
- size_t start = mi_atomic_add_acq_rel(&out_len, n);
369
- if (start >= MI_MAX_DELAY_OUTPUT) return;
370
- // check bound
371
- if (start+n >= MI_MAX_DELAY_OUTPUT) {
372
- n = MI_MAX_DELAY_OUTPUT-start-1;
366
+ if (n==0 || n >= MI_MAX_DELAY_OUTPUT) return;
367
+ // copy msg into the buffer
368
+ mi_lock(&out_buf_lock) {
369
+ const size_t start = mi_atomic_add_acq_rel(&out_len, n);
370
+ if (start < MI_MAX_DELAY_OUTPUT) {
371
+ // check bound
372
+ if (start+n >= MI_MAX_DELAY_OUTPUT) {
373
+ n = MI_MAX_DELAY_OUTPUT-start-1;
374
+ }
375
+ _mi_memcpy(&out_buf[start], msg, n);
376
+ }
373
377
  }
374
- mi_assert_internal(start + n <= MI_MAX_DELAY_OUTPUT);
375
- _mi_memcpy(&mi_output_buffer[start], msg, n);
376
378
  }
377
379
 
378
380
  static void mi_out_buf_flush(mi_output_fun* out, bool no_more_buf, void* arg) {
379
381
  if (out==NULL) return;
380
382
  // claim (if `no_more_buf == true`, no more output will be added after this point)
381
- size_t count = mi_atomic_add_acq_rel(&out_len, (no_more_buf ? MI_MAX_DELAY_OUTPUT : 1));
382
- // and output the current contents
383
- if (count>MI_MAX_DELAY_OUTPUT) count = MI_MAX_DELAY_OUTPUT;
384
- mi_output_buffer[count] = 0;
385
- out(mi_output_buffer,arg);
386
- if (!no_more_buf) {
387
- mi_output_buffer[count] = '\n'; // if continue with the buffer, insert a newline
383
+ mi_lock(&out_buf_lock) {
384
+ size_t count = mi_atomic_add_acq_rel(&out_len, (no_more_buf ? MI_MAX_DELAY_OUTPUT : 1));
385
+ // and output the current contents
386
+ if (count>MI_MAX_DELAY_OUTPUT) count = MI_MAX_DELAY_OUTPUT;
387
+ out_buf[count] = 0;
388
+ out(out_buf,arg);
389
+ if (!no_more_buf) {
390
+ out_buf[count] = '\n'; // if continue with the buffer, insert a newline
391
+ }
388
392
  }
389
393
  }
390
394
 
@@ -402,30 +406,29 @@ static void mi_cdecl mi_out_buf_stderr(const char* msg, void* arg) {
402
406
  // Default output handler
403
407
  // --------------------------------------------------------
404
408
 
405
- // Should be atomic but gives errors on many platforms as generally we cannot cast a function pointer to a uintptr_t.
406
- // For now, don't register output from multiple threads.
407
- static mi_output_fun* volatile mi_out_default; // = NULL
409
+ // The program should only install a single output handler from a single thread
410
+ // since otherwise the argument and output function may not match.
411
+ static _Atomic(void*) mi_out_default; // = // is `mi_output_fun*` (but some platforms don't support atomic function pointers)
408
412
  static _Atomic(void*) mi_out_arg; // = NULL
409
413
 
410
414
  static mi_output_fun* mi_out_get_default(void** parg) {
415
+ mi_output_fun* const out = (mi_output_fun*)mi_atomic_load_ptr_acquire(void,&mi_out_default);
411
416
  if (parg != NULL) { *parg = mi_atomic_load_ptr_acquire(void,&mi_out_arg); }
412
- mi_output_fun* out = mi_out_default;
413
417
  return (out == NULL ? &mi_out_buf : out);
414
418
  }
415
419
 
416
420
  void mi_register_output(mi_output_fun* out, void* arg) mi_attr_noexcept {
417
- mi_out_default = (out == NULL ? &mi_out_stderr : out); // stop using the delayed output buffer
421
+ mi_atomic_store_ptr_release(void,&mi_out_default, (void*)(out == NULL ? &mi_out_stderr : out)); // stop using the delayed output buffer
418
422
  mi_atomic_store_ptr_release(void,&mi_out_arg, arg);
419
- if (out!=NULL) mi_out_buf_flush(out,true,arg); // output all the delayed output now
423
+ if (out!=NULL) { mi_out_buf_flush(out,true,arg); } // output all the delayed output now
420
424
  }
421
425
 
422
426
  // add stderr to the delayed output after the module is loaded
423
427
  static void mi_add_stderr_output(void) {
424
428
  mi_assert_internal(mi_out_default == NULL);
425
- if (mi_out_default==NULL) {
426
- mi_out_buf_flush(&mi_out_stderr, false, NULL); // flush current contents to stderr
427
- mi_out_default = &mi_out_buf_stderr; // and add stderr to the delayed output
428
- }
429
+ mi_out_buf_flush(&mi_out_stderr, false, NULL); // flush current contents to stderr
430
+ mi_atomic_store_ptr_release(void,&mi_out_default,(void*)&mi_out_buf_stderr); // and add stderr to the delayed output
431
+ mi_atomic_store_ptr_release(void,&mi_out_arg,NULL);
429
432
  }
430
433
 
431
434
  // --------------------------------------------------------
@@ -649,11 +652,11 @@ static void mi_option_init(mi_option_desc_t* desc) {
649
652
  buf[i] = _mi_toupper(s[i]);
650
653
  }
651
654
  buf[len] = 0;
652
- if (buf[0] == 0 || strstr("1;TRUE;YES;ON", buf) != NULL) {
655
+ if (buf[0] == 0 || _mi_streq(buf,"1") || _mi_streq(buf,"TRUE") || _mi_streq(buf,"YES") || _mi_streq(buf,"ON")) {
653
656
  desc->value = 1;
654
657
  desc->init = MI_OPTION_INITIALIZED;
655
658
  }
656
- else if (strstr("0;FALSE;NO;OFF", buf) != NULL) {
659
+ else if (_mi_streq(buf,"0") || _mi_streq(buf,"FALSE") || _mi_streq(buf,"NO") || _mi_streq(buf,"OFF")) {
657
660
  desc->value = 0;
658
661
  desc->init = MI_OPTION_INITIALIZED;
659
662
  }
@@ -672,7 +675,7 @@ static void mi_option_init(mi_option_desc_t* desc) {
672
675
  else { size = (size + MI_KiB - 1) / MI_KiB; }
673
676
  if (end[0] == 'I' && end[1] == 'B') { end += 2; } // KiB, MiB, GiB, TiB
674
677
  else if (*end == 'B') { end++; } // Kb, Mb, Gb, Tb
675
- if (overflow || size > MI_MAX_ALLOC_SIZE) { size = (MI_MAX_ALLOC_SIZE / MI_KiB); }
678
+ if (overflow || size > (MI_MAX_ALLOC_SIZE / MI_KiB)) { size = (MI_MAX_ALLOC_SIZE / MI_KiB); }
676
679
  value = (size > LONG_MAX ? LONG_MAX : (long)size);
677
680
  }
678
681
  if (*end == 0) {
@@ -57,7 +57,7 @@ size_t _mi_os_minimal_purge_size(void) {
57
57
  if (minsize != 0) {
58
58
  return _mi_align_up(minsize, _mi_os_page_size());
59
59
  }
60
- else if (mi_os_mem_config.has_transparent_huge_pages && mi_option_is_enabled(mi_option_allow_thp)) {
60
+ else if (mi_os_mem_config.has_transparent_huge_pages && mi_option_get(mi_option_allow_thp) == 2) {
61
61
  return _mi_os_large_page_size();
62
62
  }
63
63
  else {
@@ -106,10 +106,57 @@ void _mi_os_init(void) {
106
106
  bool _mi_os_decommit(void* addr, size_t size);
107
107
  bool _mi_os_commit(void* addr, size_t size, bool* is_zero);
108
108
 
109
+ // On systems with enough virtual address bits, we can do efficient aligned allocation by using
110
+ // the 2TiB to 30TiB area to allocate those. If we have at least 46 bits of virtual address
111
+ // space (64TiB) we use this technique. (but see issue #939)
112
+ #if (MI_INTPTR_SIZE >= 8) && !defined(MI_NO_ALIGNED_HINT) // && !defined(WIN32) && !defined(ANDROID)
113
+
114
+ // Return a MI_HINT_ALIGN (4MiB) aligned address that is probably available.
115
+ // If this returns NULL, the OS will determine the address but on some OS's that may not be
116
+ // properly aligned which can be more costly as it needs to be adjusted afterwards.
117
+ // For a size > 16GiB this always returns NULL in order to guarantee good ASLR randomization;
118
+ // (otherwise an initial large allocation of say 2TiB has a 50% chance to include (known) addresses
119
+ // in the middle of the 2TiB - 6TiB address range (see issue #372))
120
+
121
+ #define MI_HINT_ALIGN ((uintptr_t)4 << 20) // 4MiB alignment
122
+ #define MI_HINT_BASE ((uintptr_t)2 << 40) // 2TiB start
123
+ #define MI_HINT_AREA ((uintptr_t)4 << 40) // upto (2+4) 6TiB (since before win8 there is "only" 8TiB available to processes)
124
+ #define MI_HINT_MAX ((uintptr_t)30 << 40) // wrap after 30TiB (area after 32TiB is used for huge OS pages)
125
+
126
+ void* _mi_os_get_aligned_hint(size_t try_alignment, size_t size)
127
+ {
128
+ static mi_decl_cache_align _Atomic(uintptr_t) aligned_base; // = 0
129
+
130
+ // todo: perhaps only do alignment hints if THP is enabled?
131
+ if (try_alignment <= mi_os_mem_config.alloc_granularity || try_alignment > MI_HINT_ALIGN) return NULL;
132
+ if (mi_os_mem_config.virtual_address_bits < 46) return NULL; // < 64TiB virtual address space
133
+ size = _mi_align_up(size, MI_HINT_ALIGN);
134
+ if (size > 16*MI_GiB) return NULL; // guarantee the chance of fixed valid address is at least 1/(MI_HINT_AREA / 1<<34)
135
+ size += MI_HINT_ALIGN; // put in virtual gaps between hinted blocks; this splits VLA's but increases guarded areas.
136
+
137
+ uintptr_t hint = mi_atomic_add_acq_rel(&aligned_base, size);
138
+ if (hint == 0 || hint > MI_HINT_MAX) { // wrap or initialize
139
+ uintptr_t init = MI_HINT_BASE;
140
+ #if (MI_SECURE>=1 || defined(NDEBUG)) // security: randomize start of aligned allocations unless in debug mode
141
+ mi_theap_t* const theap = _mi_theap_default(); // don't use `mi_theap_get_default()` as that can cause allocation recursively (issue #1267)
142
+ if (!mi_theap_is_initialized(theap)) return NULL; // no hint as we lack randomness at this point
143
+ const uintptr_t r = _mi_theap_random_next(theap);
144
+ init = init + ((MI_HINT_ALIGN * ((r>>17) & 0xFFFFF)) % MI_HINT_AREA); // (randomly 20 bits)*4MiB == 0 to 4TiB
145
+ #endif
146
+ uintptr_t expected = hint + size;
147
+ mi_atomic_cas_strong_acq_rel(&aligned_base, &expected, init);
148
+ hint = mi_atomic_add_acq_rel(&aligned_base, size); // this may still give 0 or > MI_HINT_MAX but that is ok, it is a hint after all
149
+ }
150
+ mi_assert_internal(hint%MI_HINT_ALIGN == 0);
151
+ if (hint%try_alignment != 0) return NULL;
152
+ return (void*)hint;
153
+ }
154
+ #else
109
155
  void* _mi_os_get_aligned_hint(size_t try_alignment, size_t size) {
110
- MI_UNUSED(try_alignment); MI_UNUSED(size);
111
- return NULL;
156
+ MI_UNUSED(try_alignment); MI_UNUSED(size);
157
+ return NULL;
112
158
  }
159
+ #endif
113
160
 
114
161
 
115
162
  /* -----------------------------------------------------------
@@ -251,6 +298,13 @@ static void* mi_os_prim_alloc_at(void* hint_addr, size_t size, size_t try_alignm
251
298
  if (size == 0) return NULL;
252
299
  if (!commit) { allow_large = false; }
253
300
  if (try_alignment == 0) { try_alignment = 1; } // avoid 0 to ensure there will be no divide by zero when aligning
301
+
302
+ // try to align along large OS page size for larger allocations
303
+ const size_t large_page_size = mi_os_mem_config.large_page_size;
304
+ if (large_page_size > 0 && hint_addr == NULL && size >= 8*large_page_size && _mi_is_power_of_two(try_alignment) && try_alignment < large_page_size) {
305
+ try_alignment = large_page_size;
306
+ }
307
+
254
308
  *is_zero = false;
255
309
  void* p = NULL;
256
310
  int err = _mi_prim_alloc(hint_addr, size, try_alignment, commit, allow_large, is_large, is_zero, &p);
@@ -280,27 +334,30 @@ static void* mi_os_prim_alloc(size_t size, size_t try_alignment, bool commit, bo
280
334
 
281
335
  // Primitive aligned allocation from the OS.
282
336
  // This function guarantees the allocated memory is aligned.
283
- static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** base) {
337
+ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, mi_memid_t* memid) {
338
+ mi_assert_internal(memid!=NULL);
284
339
  mi_assert_internal(alignment >= _mi_os_page_size() && ((alignment & (alignment - 1)) == 0));
285
340
  mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0);
286
- mi_assert_internal(is_large != NULL);
287
- mi_assert_internal(is_zero != NULL);
288
- mi_assert_internal(base != NULL);
341
+ *memid = _mi_memid_none();
289
342
  if (!commit) allow_large = false;
290
343
  if (!(alignment >= _mi_os_page_size() && ((alignment & (alignment - 1)) == 0))) return NULL;
291
344
  size = _mi_align_up(size, _mi_os_page_size());
292
345
 
293
- // try a direct allocation if the alignment is below the default, or if larger than 1/8 fraction of the size.
294
- const bool try_direct_alloc = (alignment <= mi_os_mem_config.alloc_granularity || alignment > size/8);
346
+ // try a direct allocation if the alignment is below the default, or less than or equal to 1/4 fraction of the size.
347
+ const bool try_direct_alloc = (alignment <= mi_os_mem_config.alloc_granularity || alignment <= size/4);
295
348
 
349
+ bool os_is_large = false;
350
+ bool os_is_zero = false;
351
+ void* os_base = NULL;
352
+ size_t os_size = size;
296
353
  void* p = NULL;
297
354
  if (try_direct_alloc) {
298
- p = mi_os_prim_alloc(size, alignment, commit, allow_large, is_large, is_zero);
355
+ p = mi_os_prim_alloc(size, alignment, commit, allow_large, &os_is_large, &os_is_zero);
299
356
  }
300
357
 
301
358
  // aligned already?
302
- if (p != NULL && ((uintptr_t)p % alignment) == 0) {
303
- *base = p;
359
+ if (p != NULL && _mi_is_aligned(p,alignment)) {
360
+ os_base = p;
304
361
  }
305
362
  else {
306
363
  // if not aligned, free it, overallocate, and unmap around it
@@ -315,43 +372,47 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit
315
372
 
316
373
  if (!mi_os_mem_config.has_partial_free) { // win32 virtualAlloc cannot free parts of an allocated block
317
374
  // over-allocate uncommitted (virtual) memory
318
- p = mi_os_prim_alloc(over_size, 1 /*alignment*/, false /* commit? */, false /* allow_large */, is_large, is_zero);
375
+ p = mi_os_prim_alloc(over_size, 1 /*alignment*/, false /* commit? */, false /* allow_large */, &os_is_large, &os_is_zero);
319
376
  if (p == NULL) return NULL;
320
377
 
321
378
  // set p to the aligned part in the full region
322
- // note: on Windows VirtualFree needs the actual base pointer
323
- // this is handledby having the `base` field in the memid.
324
- *base = p; // remember the base
379
+ // note: Windows VirtualFree needs the actual base pointer
380
+ // this is handled though by having the `base` field in the memid
381
+ os_base = p; // remember the base
382
+ os_size = over_size;
325
383
  p = _mi_align_up_ptr(p, alignment);
326
384
 
327
385
  // explicitly commit only the aligned part
328
386
  if (commit) {
329
387
  if (!_mi_os_commit(p, size, NULL)) {
330
- mi_os_prim_free(*base, over_size, 0, NULL);
388
+ mi_os_prim_free(os_base, over_size, 0, NULL);
331
389
  return NULL;
332
390
  }
333
391
  }
334
392
  }
335
393
  else { // mmap can free inside an allocation
336
394
  // overallocate...
337
- p = mi_os_prim_alloc(over_size, 1, commit, false, is_large, is_zero);
395
+ p = mi_os_prim_alloc(over_size, 1, commit, false, &os_is_large, &os_is_zero);
338
396
  if (p == NULL) return NULL;
339
397
 
340
398
  // and selectively unmap parts around the over-allocated area.
341
- void* aligned_p = _mi_align_up_ptr(p, alignment);
342
- size_t pre_size = (uint8_t*)aligned_p - (uint8_t*)p;
343
- size_t mid_size = _mi_align_up(size, _mi_os_page_size());
344
- size_t post_size = over_size - pre_size - mid_size;
399
+ void* const aligned_p = _mi_align_up_ptr(p, alignment);
400
+ const size_t pre_size = (uint8_t*)aligned_p - (uint8_t*)p;
401
+ const size_t mid_size = _mi_align_up(size, _mi_os_page_size());
402
+ const size_t post_size = over_size - pre_size - mid_size;
345
403
  mi_assert_internal(pre_size < over_size&& post_size < over_size&& mid_size >= size);
346
404
  if (pre_size > 0) { mi_os_prim_free(p, pre_size, (commit ? pre_size : 0), NULL); }
347
405
  if (post_size > 0) { mi_os_prim_free((uint8_t*)aligned_p + mid_size, post_size, (commit ? post_size : 0), NULL); }
348
406
  // we can return the aligned pointer on `mmap` systems
349
407
  p = aligned_p;
350
- *base = aligned_p; // since we freed the pre part, `*base == p`.
408
+ os_base = aligned_p; // since we freed the pre part, `*base == p`.
409
+ os_size = mid_size;
351
410
  }
352
411
  }
353
412
 
354
- mi_assert_internal(p == NULL || (p != NULL && *base != NULL && ((uintptr_t)p % alignment) == 0));
413
+ mi_assert_internal(p != NULL && os_base != NULL && _mi_is_aligned(p,alignment));
414
+ mi_assert_internal(os_base <= p && size <= os_size);
415
+ *memid = _mi_memid_create_os(os_base,os_size,commit,os_is_zero,os_is_large);
355
416
  return p;
356
417
  }
357
418
 
@@ -383,16 +444,9 @@ void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool allo
383
444
  size = _mi_os_good_alloc_size(size);
384
445
  alignment = _mi_align_up(alignment, _mi_os_page_size());
385
446
 
386
- bool os_is_large = false;
387
- bool os_is_zero = false;
388
- void* os_base = NULL;
389
- void* p = mi_os_prim_alloc_aligned(size, alignment, commit, allow_large, &os_is_large, &os_is_zero, &os_base );
447
+ void* p = mi_os_prim_alloc_aligned(size, alignment, commit, allow_large, memid );
390
448
  if (p == NULL) return NULL;
391
449
 
392
- *memid = _mi_memid_create_os(p, size, commit, os_is_zero, os_is_large);
393
- memid->mem.os.base = os_base;
394
- memid->mem.os.size += ((uint8_t*)p - (uint8_t*)os_base); // todo: return from prim_alloc_aligned?
395
-
396
450
  mi_assert_internal(memid->mem.os.size >= size);
397
451
  mi_assert_internal(_mi_is_aligned(p,alignment));
398
452
  if (commit) { mi_assert_internal(memid->initially_committed); }
@@ -435,6 +489,7 @@ void* _mi_os_alloc_aligned_at_offset(size_t size, size_t alignment, size_t offse
435
489
  mi_assert(offset <= size);
436
490
  mi_assert((alignment % _mi_os_page_size()) == 0);
437
491
  *memid = _mi_memid_none();
492
+ if (offset > size) return NULL;
438
493
  if (offset == 0) {
439
494
  // regular aligned allocation
440
495
  return _mi_os_alloc_aligned(size, alignment, commit, allow_large, memid);
@@ -442,6 +497,7 @@ void* _mi_os_alloc_aligned_at_offset(size_t size, size_t alignment, size_t offse
442
497
  else {
443
498
  // overallocate to align at an offset
444
499
  const size_t extra = _mi_align_up(offset, alignment) - offset;
500
+ if (size >= SIZE_MAX - extra) return NULL; // too large
445
501
  const size_t oversize = size + extra;
446
502
  void* const start = _mi_os_alloc_aligned(oversize, alignment, commit, allow_large, memid);
447
503
  if (start == NULL) return NULL;
@@ -449,7 +505,7 @@ void* _mi_os_alloc_aligned_at_offset(size_t size, size_t alignment, size_t offse
449
505
  void* const p = (uint8_t*)start + extra;
450
506
  mi_assert(_mi_is_aligned((uint8_t*)p + offset, alignment));
451
507
  // decommit the overallocation at the start
452
- if (commit && extra > _mi_os_page_size()) {
508
+ if (commit && extra >= _mi_os_page_size()) {
453
509
  _mi_os_decommit(start, extra);
454
510
  }
455
511
  return p;
@@ -469,9 +525,9 @@ static void* mi_os_page_align_areax(bool conservative, void* addr, size_t size,
469
525
 
470
526
  // page align conservatively within the range, or liberally straddling pages outside the range
471
527
  void* start = (conservative ? _mi_align_up_ptr(addr, _mi_os_page_size())
472
- : mi_align_down_ptr(addr, _mi_os_page_size()));
473
- void* end = (conservative ? mi_align_down_ptr((uint8_t*)addr + size, _mi_os_page_size())
474
- : _mi_align_up_ptr((uint8_t*)addr + size, _mi_os_page_size()));
528
+ : _mi_align_down_ptr(addr, _mi_os_page_size()));
529
+ void* end = (conservative ? _mi_align_down_ptr((uint8_t*)addr + size, _mi_os_page_size())
530
+ : _mi_align_up_ptr((uint8_t*)addr + size, _mi_os_page_size()));
475
531
  ptrdiff_t diff = (uint8_t*)end - (uint8_t*)start;
476
532
  if (diff <= 0) return NULL;
477
533
 
@@ -519,7 +575,6 @@ bool _mi_os_commit(void* addr, size_t size, bool* is_zero) {
519
575
 
520
576
  static bool mi_os_decommit_ex(void* addr, size_t size, bool* needs_recommit, size_t stat_size) {
521
577
  mi_assert_internal(needs_recommit!=NULL);
522
- mi_os_stat_decrease(committed, stat_size);
523
578
 
524
579
  // page align
525
580
  size_t csize;
@@ -532,6 +587,9 @@ static bool mi_os_decommit_ex(void* addr, size_t size, bool* needs_recommit, siz
532
587
  if (err != 0) {
533
588
  _mi_warning_message("cannot decommit OS memory (error: %d (0x%x), address: %p, size: 0x%zx bytes)\n", err, err, start, csize);
534
589
  }
590
+ else if (*needs_recommit) {
591
+ mi_os_stat_decrease(committed, stat_size);
592
+ }
535
593
  mi_assert_internal(err == 0);
536
594
  return (err == 0);
537
595
  }
@@ -663,10 +721,16 @@ static uint8_t* mi_os_claim_huge_pages(size_t pages, size_t* total_size) {
663
721
  if (start == 0) {
664
722
  // Initialize the start address after the 32TiB area
665
723
  start = ((uintptr_t)8 << 40); // 8TiB virtual start address
666
- #if (MI_SECURE>0 || MI_DEBUG==0) // security: randomize start of huge pages unless in debug mode
667
- uintptr_t r = _mi_theap_random_next(_mi_theap_default());
668
- start = start + ((uintptr_t)MI_HUGE_OS_PAGE_SIZE * ((r>>17) & 0x0FFF)); // (randomly 12bits)*1GiB == between 0 to 4TiB
669
- #endif
724
+ #if (MI_SECURE>0 || MI_DEBUG==0) // security: randomize start of huge pages unless in debug mode
725
+ mi_theap_t* const theap = _mi_theap_default(); // don't use `mi_theap_get_default()` as that can cause allocation recursively (issue #1267)
726
+ if (mi_theap_is_initialized(theap)) { // todo: or no hint at all if we lack randomness?
727
+ const uintptr_t r = _mi_theap_random_next(theap);
728
+ start = start + ((uintptr_t)MI_HUGE_OS_PAGE_SIZE * ((r>>17) & 0x0FFF)); // (randomly 12bits)*1GiB == between 0 to 4TiB
729
+ }
730
+ else {
731
+ _mi_warning_message("failed to randomize the start address of huge pages allocation (%zu bytes at %p)", size, start);
732
+ }
733
+ #endif
670
734
  }
671
735
  end = start + size;
672
736
  } while (!mi_atomic_cas_weak_acq_rel(&mi_huge_start, &huge_start, end));
@@ -739,16 +803,17 @@ void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_mse
739
803
  }
740
804
  }
741
805
  }
742
- mi_assert_internal(page*MI_HUGE_OS_PAGE_SIZE <= size);
806
+ const size_t allocated = page * MI_HUGE_OS_PAGE_SIZE;
807
+ mi_assert_internal(allocated <= size);
743
808
  if (pages_reserved != NULL) { *pages_reserved = page; }
744
- if (psize != NULL) { *psize = page * MI_HUGE_OS_PAGE_SIZE; }
809
+ if (psize != NULL) { *psize = allocated; }
745
810
  if (page != 0) {
746
811
  mi_assert(start != NULL);
747
- *memid = _mi_memid_create_os(start, size, true /* is committed */, all_zero, true /* is_large */);
812
+ *memid = _mi_memid_create_os(start, allocated, true /* is committed */, all_zero, true /* is_large */);
748
813
  memid->memkind = MI_MEM_OS_HUGE;
749
814
  mi_assert(memid->is_pinned);
750
815
  #ifdef MI_TRACK_ASAN
751
- if (all_zero) { mi_track_mem_defined(start,size); }
816
+ if (all_zero) { mi_track_mem_defined(start,allocated); }
752
817
  #endif
753
818
  }
754
819
  return (page == 0 ? NULL : start);
@@ -42,6 +42,9 @@ bool _mi_page_map_init(void) {
42
42
  if (vbits >= 48) { vbits = 47; }
43
43
  #endif
44
44
  }
45
+ if (vbits < MI_ARENA_SLICE_SHIFT) {
46
+ vbits = MI_ARENA_SLICE_SHIFT;
47
+ }
45
48
 
46
49
  // Allocate the page map and commit bits
47
50
  mi_page_map_max_address = (void*)(vbits >= MI_SIZE_BITS ? (SIZE_MAX - MI_ARENA_SLICE_SIZE + 1) : (MI_PU(1) << vbits));
@@ -127,13 +130,13 @@ static size_t mi_page_map_get_idx(mi_page_t* page, uint8_t** page_start, size_t*
127
130
  size_t page_size;
128
131
  *page_start = mi_page_area(page, &page_size);
129
132
  if (page_size > MI_LARGE_PAGE_SIZE) { page_size = MI_LARGE_PAGE_SIZE - MI_ARENA_SLICE_SIZE; } // furthest interior pointer
130
- *slice_count = mi_slice_count_of_size(page_size) + (((uint8_t*)*page_start - (uint8_t*)page)/MI_ARENA_SLICE_SIZE); // add for large aligned blocks
133
+ *slice_count = mi_slice_count_of_size(page_size) + ((*page_start - mi_page_slice_start(page))/MI_ARENA_SLICE_SIZE); // add for large aligned blocks
131
134
  return _mi_page_map_index(page);
132
135
  }
133
136
 
134
137
  bool _mi_page_map_register(mi_page_t* page) {
135
138
  mi_assert_internal(page != NULL);
136
- mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN));
139
+ mi_assert_internal(_mi_is_aligned(mi_page_slice_start(page), MI_PAGE_ALIGN));
137
140
  mi_assert_internal(_mi_page_map != NULL); // should be initialized before multi-thread access!
138
141
  if mi_unlikely(_mi_page_map == NULL) {
139
142
  if (!_mi_page_map_init()) return false;
@@ -193,7 +196,7 @@ mi_decl_nodiscard mi_decl_export bool mi_is_in_heap_region(const void* p) mi_att
193
196
 
194
197
  // A 2-level page map
195
198
  #define MI_PAGE_MAP_SUB_SIZE (MI_PAGE_MAP_SUB_COUNT * sizeof(mi_page_t*))
196
- #define MI_PAGE_MAP_ENTRIES_PER_CBIT (MI_PAGE_MAP_COUNT / MI_BFIELD_BITS)
199
+ #define MI_PAGE_MAP_ENTRIES_PER_CBIT (MI_PAGE_MAP_COUNT < MI_BFIELD_BITS ? 1 : (MI_PAGE_MAP_COUNT / MI_BFIELD_BITS))
197
200
 
198
201
  mi_decl_cache_align _Atomic(mi_submap_t)* _mi_page_map;
199
202
  static size_t mi_page_map_count;
@@ -236,6 +239,9 @@ bool _mi_page_map_init(void) {
236
239
  if (vbits >= 48) { vbits = 47; }
237
240
  #endif
238
241
  }
242
+ if (vbits < MI_PAGE_MAP_SUB_SHIFT + MI_ARENA_SLICE_SHIFT) {
243
+ vbits = MI_PAGE_MAP_SUB_SHIFT + MI_ARENA_SLICE_SHIFT;
244
+ }
239
245
 
240
246
  // Allocate the page map and commit bits
241
247
  mi_assert(MI_MAX_VABITS >= vbits);
@@ -308,7 +314,7 @@ void _mi_page_map_unsafe_destroy(mi_subproc_t* subproc) {
308
314
  mi_page_map_count = 0;
309
315
  mi_page_map_memid = _mi_memid_none();
310
316
  mi_page_map_max_address = NULL;
311
- mi_atomic_store_release(&mi_page_map_commit, 0);
317
+ mi_atomic_store_release(&mi_page_map_commit, (mi_bfield_t)0);
312
318
  }
313
319
 
314
320
 
@@ -383,13 +389,13 @@ static size_t mi_page_map_get_idx(mi_page_t* page, size_t* sub_idx, size_t* slic
383
389
  size_t page_size;
384
390
  uint8_t* page_start = mi_page_area(page, &page_size);
385
391
  if (page_size > MI_LARGE_PAGE_SIZE) { page_size = MI_LARGE_PAGE_SIZE - MI_ARENA_SLICE_SIZE; } // furthest interior pointer
386
- *slice_count = mi_slice_count_of_size(page_size) + ((page_start - (uint8_t*)page)/MI_ARENA_SLICE_SIZE); // add for large aligned blocks
387
- return _mi_page_map_index(page, sub_idx);
392
+ *slice_count = mi_slice_count_of_size(page_size) + ((page_start - mi_page_slice_start(page))/MI_ARENA_SLICE_SIZE); // add for large aligned blocks
393
+ return _mi_page_map_index(page_start, sub_idx);
388
394
  }
389
395
 
390
396
  bool _mi_page_map_register(mi_page_t* page) {
391
397
  mi_assert_internal(page != NULL);
392
- mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN));
398
+ mi_assert_internal(_mi_is_aligned(mi_page_slice_start(page), MI_PAGE_ALIGN));
393
399
  mi_assert_internal(_mi_page_map != NULL); // should be initialized before multi-thread access!
394
400
  if mi_unlikely(_mi_page_map == NULL) {
395
401
  if (!_mi_page_map_init()) return false;
@@ -404,7 +410,7 @@ bool _mi_page_map_register(mi_page_t* page) {
404
410
  void _mi_page_map_unregister(mi_page_t* page) {
405
411
  mi_assert_internal(_mi_page_map != NULL);
406
412
  mi_assert_internal(page != NULL);
407
- mi_assert_internal(_mi_is_aligned(page, MI_PAGE_ALIGN));
413
+ mi_assert_internal(_mi_is_aligned(mi_page_slice_start(page), MI_PAGE_ALIGN));
408
414
  if mi_unlikely(_mi_page_map == NULL) return;
409
415
  // get index and count
410
416
  size_t slice_count;