@shd101wyy/yo 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +17 -0
- package/README.md +80 -0
- package/out/cjs/index.cjs +51 -0
- package/out/cjs/yo-cli.cjs +2158 -0
- package/out/esm/index.mjs +51 -0
- package/out/types/src/codegen/async/runtime.d.ts +2 -0
- package/out/types/src/codegen/async/state-code-gen.d.ts +10 -0
- package/out/types/src/codegen/async/state-machine.d.ts +13 -0
- package/out/types/src/codegen/c/collection.d.ts +3 -0
- package/out/types/src/codegen/codegen-c.d.ts +12 -0
- package/out/types/src/codegen/constants.d.ts +3 -0
- package/out/types/src/codegen/expressions/array.d.ts +4 -0
- package/out/types/src/codegen/expressions/generation.d.ts +11 -0
- package/out/types/src/codegen/expressions/index.d.ts +2 -0
- package/out/types/src/codegen/functions/collection.d.ts +5 -0
- package/out/types/src/codegen/functions/context.d.ts +57 -0
- package/out/types/src/codegen/functions/generation.d.ts +25 -0
- package/out/types/src/codegen/functions/index.d.ts +2 -0
- package/out/types/src/codegen/index.d.ts +20 -0
- package/out/types/src/codegen/parallelism/runtime.d.ts +2 -0
- package/out/types/src/codegen/types/collection.d.ts +8 -0
- package/out/types/src/codegen/types/generation.d.ts +13 -0
- package/out/types/src/codegen/types/index.d.ts +2 -0
- package/out/types/src/codegen/utils/fixup.d.ts +2 -0
- package/out/types/src/codegen/utils/index.d.ts +77 -0
- package/out/types/src/codegen/values/index.d.ts +1 -0
- package/out/types/src/emitter.d.ts +11 -0
- package/out/types/src/env.d.ts +85 -0
- package/out/types/src/error.d.ts +45 -0
- package/out/types/src/evaluator/async/await-analysis-types.d.ts +23 -0
- package/out/types/src/evaluator/async/await-analysis.d.ts +5 -0
- package/out/types/src/evaluator/builtins/alignof.d.ts +8 -0
- package/out/types/src/evaluator/builtins/and_or.d.ts +8 -0
- package/out/types/src/evaluator/builtins/arc_fns.d.ts +58 -0
- package/out/types/src/evaluator/builtins/array_fns.d.ts +0 -0
- package/out/types/src/evaluator/builtins/as.d.ts +8 -0
- package/out/types/src/evaluator/builtins/async_fns.d.ts +8 -0
- package/out/types/src/evaluator/builtins/compt_assert.d.ts +8 -0
- package/out/types/src/evaluator/builtins/compt_boolean_fns.d.ts +8 -0
- package/out/types/src/evaluator/builtins/compt_expect_error.d.ts +8 -0
- package/out/types/src/evaluator/builtins/compt_list_fns.d.ts +33 -0
- package/out/types/src/evaluator/builtins/compt_print.d.ts +8 -0
- package/out/types/src/evaluator/builtins/compt_string_fns.d.ts +8 -0
- package/out/types/src/evaluator/builtins/consume.d.ts +8 -0
- package/out/types/src/evaluator/builtins/drop.d.ts +8 -0
- package/out/types/src/evaluator/builtins/dup.d.ts +8 -0
- package/out/types/src/evaluator/builtins/expr_fns.d.ts +33 -0
- package/out/types/src/evaluator/builtins/future_fns.d.ts +8 -0
- package/out/types/src/evaluator/builtins/gc.d.ts +8 -0
- package/out/types/src/evaluator/builtins/gensym.d.ts +8 -0
- package/out/types/src/evaluator/builtins/impl_constraint.d.ts +8 -0
- package/out/types/src/evaluator/builtins/macro_expand.d.ts +8 -0
- package/out/types/src/evaluator/builtins/numeric_fns.d.ts +8 -0
- package/out/types/src/evaluator/builtins/panic.d.ts +8 -0
- package/out/types/src/evaluator/builtins/ptr_fns.d.ts +8 -0
- package/out/types/src/evaluator/builtins/quote.d.ts +13 -0
- package/out/types/src/evaluator/builtins/rc.d.ts +8 -0
- package/out/types/src/evaluator/builtins/sizeof.d.ts +8 -0
- package/out/types/src/evaluator/builtins/the.d.ts +8 -0
- package/out/types/src/evaluator/builtins/type_fns.d.ts +28 -0
- package/out/types/src/evaluator/builtins/va_start.d.ts +8 -0
- package/out/types/src/evaluator/builtins/var_fns.d.ts +18 -0
- package/out/types/src/evaluator/calls/array.d.ts +13 -0
- package/out/types/src/evaluator/calls/array_type.d.ts +11 -0
- package/out/types/src/evaluator/calls/closure_type.d.ts +11 -0
- package/out/types/src/evaluator/calls/compt_function.d.ts +19 -0
- package/out/types/src/evaluator/calls/compt_list_type.d.ts +11 -0
- package/out/types/src/evaluator/calls/function.d.ts +16 -0
- package/out/types/src/evaluator/calls/function_type.d.ts +15 -0
- package/out/types/src/evaluator/calls/helper.d.ts +42 -0
- package/out/types/src/evaluator/calls/iso.d.ts +15 -0
- package/out/types/src/evaluator/calls/module_type.d.ts +11 -0
- package/out/types/src/evaluator/calls/numeric_type.d.ts +15 -0
- package/out/types/src/evaluator/calls/pointer.d.ts +8 -0
- package/out/types/src/evaluator/calls/pointer_type.d.ts +14 -0
- package/out/types/src/evaluator/calls/type.d.ts +12 -0
- package/out/types/src/evaluator/context.d.ts +169 -0
- package/out/types/src/evaluator/exprs/_expr.d.ts +8 -0
- package/out/types/src/evaluator/exprs/assignment.d.ts +9 -0
- package/out/types/src/evaluator/exprs/begin.d.ts +10 -0
- package/out/types/src/evaluator/exprs/binding.d.ts +12 -0
- package/out/types/src/evaluator/exprs/c_include.d.ts +8 -0
- package/out/types/src/evaluator/exprs/cond.d.ts +8 -0
- package/out/types/src/evaluator/exprs/destructuring_assignment.d.ts +33 -0
- package/out/types/src/evaluator/exprs/exists.d.ts +0 -0
- package/out/types/src/evaluator/exprs/expr.d.ts +9 -0
- package/out/types/src/evaluator/exprs/extern.d.ts +8 -0
- package/out/types/src/evaluator/exprs/identifer_and_operator.d.ts +9 -0
- package/out/types/src/evaluator/exprs/import.d.ts +9 -0
- package/out/types/src/evaluator/exprs/initialization_assignment.d.ts +8 -0
- package/out/types/src/evaluator/exprs/match.d.ts +8 -0
- package/out/types/src/evaluator/exprs/open.d.ts +8 -0
- package/out/types/src/evaluator/exprs/property_access.d.ts +8 -0
- package/out/types/src/evaluator/exprs/recur.d.ts +8 -0
- package/out/types/src/evaluator/exprs/subtype_of.d.ts +21 -0
- package/out/types/src/evaluator/exprs/test.d.ts +8 -0
- package/out/types/src/evaluator/exprs/typeof.d.ts +8 -0
- package/out/types/src/evaluator/exprs/while.d.ts +8 -0
- package/out/types/src/evaluator/index.d.ts +26 -0
- package/out/types/src/evaluator/types/array.d.ts +8 -0
- package/out/types/src/evaluator/types/closure.d.ts +8 -0
- package/out/types/src/evaluator/types/compt_list.d.ts +8 -0
- package/out/types/src/evaluator/types/concrete_module.d.ts +8 -0
- package/out/types/src/evaluator/types/dyn.d.ts +8 -0
- package/out/types/src/evaluator/types/enum.d.ts +8 -0
- package/out/types/src/evaluator/types/expr_synthesizer.d.ts +14 -0
- package/out/types/src/evaluator/types/field.d.ts +14 -0
- package/out/types/src/evaluator/types/fn_module.d.ts +8 -0
- package/out/types/src/evaluator/types/function.d.ts +58 -0
- package/out/types/src/evaluator/types/future_module.d.ts +8 -0
- package/out/types/src/evaluator/types/module.d.ts +19 -0
- package/out/types/src/evaluator/types/newtype.d.ts +8 -0
- package/out/types/src/evaluator/types/object.d.ts +8 -0
- package/out/types/src/evaluator/types/proofs.d.ts +0 -0
- package/out/types/src/evaluator/types/slice.d.ts +8 -0
- package/out/types/src/evaluator/types/struct.d.ts +8 -0
- package/out/types/src/evaluator/types/synthesizer.d.ts +16 -0
- package/out/types/src/evaluator/types/tuple.d.ts +18 -0
- package/out/types/src/evaluator/types/union.d.ts +8 -0
- package/out/types/src/evaluator/types/utils.d.ts +71 -0
- package/out/types/src/evaluator/types/validation.d.ts +3 -0
- package/out/types/src/evaluator/utils/array-utils.d.ts +15 -0
- package/out/types/src/evaluator/utils/closure.d.ts +35 -0
- package/out/types/src/evaluator/utils.d.ts +4 -0
- package/out/types/src/evaluator/values/anonymous_function.d.ts +8 -0
- package/out/types/src/evaluator/values/anonymous_module.d.ts +17 -0
- package/out/types/src/evaluator/values/anonymous_struct.d.ts +8 -0
- package/out/types/src/evaluator/values/array.d.ts +8 -0
- package/out/types/src/evaluator/values/boolean.d.ts +3 -0
- package/out/types/src/evaluator/values/char.d.ts +3 -0
- package/out/types/src/evaluator/values/compt_list.d.ts +8 -0
- package/out/types/src/evaluator/values/dyn.d.ts +8 -0
- package/out/types/src/evaluator/values/float.d.ts +4 -0
- package/out/types/src/evaluator/values/integer.d.ts +4 -0
- package/out/types/src/evaluator/values/module.d.ts +58 -0
- package/out/types/src/evaluator/values/string.d.ts +3 -0
- package/out/types/src/evaluator/values/tuple.d.ts +32 -0
- package/out/types/src/expr.d.ts +456 -0
- package/out/types/src/function-value.d.ts +42 -0
- package/out/types/src/index.d.ts +4 -0
- package/out/types/src/lexer.d.ts +2 -0
- package/out/types/src/logger.d.ts +1 -0
- package/out/types/src/module-manager.d.ts +30 -0
- package/out/types/src/naming-checker.d.ts +4 -0
- package/out/types/src/parser.d.ts +33 -0
- package/out/types/src/test-runner.d.ts +30 -0
- package/out/types/src/tests/codegen.test.d.ts +1 -0
- package/out/types/src/tests/fixme.test.d.ts +1 -0
- package/out/types/src/tests/module-manager.test.d.ts +1 -0
- package/out/types/src/tests/parser.test.d.ts +1 -0
- package/out/types/src/tests/sample.test.d.ts +0 -0
- package/out/types/src/tests/std.test.d.ts +1 -0
- package/out/types/src/token.d.ts +40 -0
- package/out/types/src/type-value.d.ts +7 -0
- package/out/types/src/types/compatibility.d.ts +16 -0
- package/out/types/src/types/creators.d.ts +73 -0
- package/out/types/src/types/definitions.d.ts +218 -0
- package/out/types/src/types/guards.d.ts +70 -0
- package/out/types/src/types/hierarchy.d.ts +4 -0
- package/out/types/src/types/index.d.ts +7 -0
- package/out/types/src/types/module_field.d.ts +2 -0
- package/out/types/src/types/tags.d.ts +45 -0
- package/out/types/src/types/utils.d.ts +50 -0
- package/out/types/src/unit-value.d.ts +7 -0
- package/out/types/src/utils.d.ts +6 -0
- package/out/types/src/value-tag.d.ts +29 -0
- package/out/types/src/value.d.ts +110 -0
- package/out/types/src/yo-cli.d.ts +1 -0
- package/out/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +57 -0
- package/scripts/check-liburing.js +76 -0
- package/std/alg/hash.yo +50 -0
- package/std/allocator.yo +113 -0
- package/std/allocators/c_allocator.yo +118 -0
- package/std/async.yo +13 -0
- package/std/collections/array_list.yo +415 -0
- package/std/collections/hash_map.yo +482 -0
- package/std/collections/hash_set.yo +706 -0
- package/std/collections/index.yo +11 -0
- package/std/collections/linked_list.yo +439 -0
- package/std/error.yo +0 -0
- package/std/gc.yo +10 -0
- package/std/index.yo +12 -0
- package/std/io/file.yo +191 -0
- package/std/io/index.yo +5 -0
- package/std/libc/assert.yo +39 -0
- package/std/libc/ctype.yo +57 -0
- package/std/libc/errno.yo +182 -0
- package/std/libc/float.yo +87 -0
- package/std/libc/index.yo +29 -0
- package/std/libc/limits.yo +65 -0
- package/std/libc/math.yo +679 -0
- package/std/libc/signal.yo +101 -0
- package/std/libc/stdatomic.yo +213 -0
- package/std/libc/stdint.yo +214 -0
- package/std/libc/stdio.yo +225 -0
- package/std/libc/stdlib.yo +204 -0
- package/std/libc/string.yo +151 -0
- package/std/libc/time.yo +92 -0
- package/std/libc/unistd.yo +130 -0
- package/std/monad.yo +152 -0
- package/std/prelude.yo +3094 -0
- package/std/string/index.yo +8 -0
- package/std/string/rune.yo +82 -0
- package/std/string/string.yo +288 -0
- package/std/sync.yo +95 -0
- package/std/thread.yo +36 -0
- package/std/time.yo +13 -0
- package/std/worker.yo +36 -0
- package/vendor/mimalloc/.gitattributes +12 -0
- package/vendor/mimalloc/CMakeLists.txt +763 -0
- package/vendor/mimalloc/LICENSE +21 -0
- package/vendor/mimalloc/SECURITY.md +41 -0
- package/vendor/mimalloc/azure-pipelines.yml +251 -0
- package/vendor/mimalloc/bin/mimalloc-redirect-arm64.dll +0 -0
- package/vendor/mimalloc/bin/mimalloc-redirect-arm64.lib +0 -0
- package/vendor/mimalloc/bin/mimalloc-redirect-arm64ec.dll +0 -0
- package/vendor/mimalloc/bin/mimalloc-redirect-arm64ec.lib +0 -0
- package/vendor/mimalloc/bin/mimalloc-redirect.dll +0 -0
- package/vendor/mimalloc/bin/mimalloc-redirect.lib +0 -0
- package/vendor/mimalloc/bin/mimalloc-redirect32.dll +0 -0
- package/vendor/mimalloc/bin/mimalloc-redirect32.lib +0 -0
- package/vendor/mimalloc/bin/minject-arm64.exe +0 -0
- package/vendor/mimalloc/bin/minject.exe +0 -0
- package/vendor/mimalloc/bin/minject32.exe +0 -0
- package/vendor/mimalloc/bin/readme.md +118 -0
- package/vendor/mimalloc/cmake/JoinPaths.cmake +23 -0
- package/vendor/mimalloc/cmake/mimalloc-config-version.cmake +19 -0
- package/vendor/mimalloc/cmake/mimalloc-config.cmake +14 -0
- package/vendor/mimalloc/contrib/docker/alpine/Dockerfile +23 -0
- package/vendor/mimalloc/contrib/docker/alpine-arm32v7/Dockerfile +28 -0
- package/vendor/mimalloc/contrib/docker/alpine-x86/Dockerfile +28 -0
- package/vendor/mimalloc/contrib/docker/manylinux-x64/Dockerfile +23 -0
- package/vendor/mimalloc/contrib/docker/readme.md +10 -0
- package/vendor/mimalloc/contrib/vcpkg/portfile.cmake +64 -0
- package/vendor/mimalloc/contrib/vcpkg/readme.md +40 -0
- package/vendor/mimalloc/contrib/vcpkg/usage +20 -0
- package/vendor/mimalloc/contrib/vcpkg/vcpkg-cmake-wrapper.cmake +20 -0
- package/vendor/mimalloc/contrib/vcpkg/vcpkg.json +48 -0
- package/vendor/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-a.svg +887 -0
- package/vendor/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-b.svg +1185 -0
- package/vendor/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-a.svg +757 -0
- package/vendor/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-b.svg +1028 -0
- package/vendor/mimalloc/doc/bench-2020/bench-r5a-1.svg +769 -0
- package/vendor/mimalloc/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-a.svg +868 -0
- package/vendor/mimalloc/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-b.svg +1157 -0
- package/vendor/mimalloc/doc/bench-2020/bench-r5a-2.svg +983 -0
- package/vendor/mimalloc/doc/bench-2020/bench-r5a-rss-1.svg +683 -0
- package/vendor/mimalloc/doc/bench-2020/bench-r5a-rss-2.svg +854 -0
- package/vendor/mimalloc/doc/bench-2020/bench-spec-rss.svg +713 -0
- package/vendor/mimalloc/doc/bench-2020/bench-spec.svg +713 -0
- package/vendor/mimalloc/doc/bench-2020/bench-z4-1.svg +890 -0
- package/vendor/mimalloc/doc/bench-2020/bench-z4-2.svg +1146 -0
- package/vendor/mimalloc/doc/bench-2020/bench-z4-rss-1.svg +796 -0
- package/vendor/mimalloc/doc/bench-2020/bench-z4-rss-2.svg +974 -0
- package/vendor/mimalloc/doc/bench-2021/bench-amd5950x-2021-01-30-a.svg +952 -0
- package/vendor/mimalloc/doc/bench-2021/bench-amd5950x-2021-01-30-b.svg +1255 -0
- package/vendor/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-a.svg +955 -0
- package/vendor/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-b.svg +1269 -0
- package/vendor/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-a.svg +836 -0
- package/vendor/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-b.svg +1131 -0
- package/vendor/mimalloc/doc/bench-2021/bench-macmini-2021-01-30.svg +766 -0
- package/vendor/mimalloc/doc/doxyfile +2895 -0
- package/vendor/mimalloc/doc/ds-logo.jpg +0 -0
- package/vendor/mimalloc/doc/ds-logo.png +0 -0
- package/vendor/mimalloc/doc/mimalloc-doc.h +1452 -0
- package/vendor/mimalloc/doc/mimalloc-doxygen.css +60 -0
- package/vendor/mimalloc/doc/mimalloc-logo-100.png +0 -0
- package/vendor/mimalloc/doc/mimalloc-logo.png +0 -0
- package/vendor/mimalloc/doc/mimalloc-logo.svg +161 -0
- package/vendor/mimalloc/doc/spades-logo.png +0 -0
- package/vendor/mimalloc/doc/unreal-logo.svg +43 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-lib.vcxproj +500 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-lib.vcxproj.filters +108 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-override-dll.vcxproj +508 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-override-dll.vcxproj.filters +111 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-override-test-dep.vcxproj +355 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-override-test.vcxproj +360 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-test-api.vcxproj +295 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-test-stress.vcxproj +292 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-test.vcxproj +289 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc.sln +151 -0
- package/vendor/mimalloc/include/mimalloc/atomic.h +557 -0
- package/vendor/mimalloc/include/mimalloc/internal.h +1153 -0
- package/vendor/mimalloc/include/mimalloc/prim.h +421 -0
- package/vendor/mimalloc/include/mimalloc/track.h +145 -0
- package/vendor/mimalloc/include/mimalloc/types.h +685 -0
- package/vendor/mimalloc/include/mimalloc-new-delete.h +66 -0
- package/vendor/mimalloc/include/mimalloc-override.h +68 -0
- package/vendor/mimalloc/include/mimalloc-stats.h +103 -0
- package/vendor/mimalloc/include/mimalloc.h +612 -0
- package/vendor/mimalloc/mimalloc.pc.in +11 -0
- package/vendor/mimalloc/readme.md +946 -0
- package/vendor/mimalloc/src/alloc-aligned.c +360 -0
- package/vendor/mimalloc/src/alloc-override.c +316 -0
- package/vendor/mimalloc/src/alloc-posix.c +185 -0
- package/vendor/mimalloc/src/alloc.c +692 -0
- package/vendor/mimalloc/src/arena-abandon.c +346 -0
- package/vendor/mimalloc/src/arena.c +1043 -0
- package/vendor/mimalloc/src/bitmap.c +441 -0
- package/vendor/mimalloc/src/bitmap.h +119 -0
- package/vendor/mimalloc/src/free.c +572 -0
- package/vendor/mimalloc/src/heap.c +733 -0
- package/vendor/mimalloc/src/init.c +714 -0
- package/vendor/mimalloc/src/libc.c +334 -0
- package/vendor/mimalloc/src/options.c +663 -0
- package/vendor/mimalloc/src/os.c +770 -0
- package/vendor/mimalloc/src/page-queue.c +390 -0
- package/vendor/mimalloc/src/page.c +1049 -0
- package/vendor/mimalloc/src/prim/emscripten/prim.c +249 -0
- package/vendor/mimalloc/src/prim/osx/alloc-override-zone.c +461 -0
- package/vendor/mimalloc/src/prim/osx/prim.c +9 -0
- package/vendor/mimalloc/src/prim/prim.c +76 -0
- package/vendor/mimalloc/src/prim/readme.md +9 -0
- package/vendor/mimalloc/src/prim/unix/prim.c +934 -0
- package/vendor/mimalloc/src/prim/wasi/prim.c +284 -0
- package/vendor/mimalloc/src/prim/windows/etw-mimalloc.wprp +61 -0
- package/vendor/mimalloc/src/prim/windows/etw.h +905 -0
- package/vendor/mimalloc/src/prim/windows/etw.man +0 -0
- package/vendor/mimalloc/src/prim/windows/prim.c +878 -0
- package/vendor/mimalloc/src/prim/windows/readme.md +17 -0
- package/vendor/mimalloc/src/random.c +258 -0
- package/vendor/mimalloc/src/segment-map.c +142 -0
- package/vendor/mimalloc/src/segment.c +1702 -0
- package/vendor/mimalloc/src/static.c +41 -0
- package/vendor/mimalloc/src/stats.c +635 -0
- package/vendor/mimalloc/test/CMakeLists.txt +56 -0
- package/vendor/mimalloc/test/main-override-dep.cpp +51 -0
- package/vendor/mimalloc/test/main-override-dep.h +11 -0
- package/vendor/mimalloc/test/main-override-static.c +539 -0
- package/vendor/mimalloc/test/main-override.c +36 -0
- package/vendor/mimalloc/test/main-override.cpp +497 -0
- package/vendor/mimalloc/test/main.c +46 -0
- package/vendor/mimalloc/test/readme.md +16 -0
- package/vendor/mimalloc/test/test-api-fill.c +343 -0
- package/vendor/mimalloc/test/test-api.c +466 -0
- package/vendor/mimalloc/test/test-stress.c +428 -0
- package/vendor/mimalloc/test/test-wrong.c +92 -0
- package/vendor/mimalloc/test/testhelper.h +49 -0
|
@@ -0,0 +1,714 @@
|
|
|
1
|
+
/* ----------------------------------------------------------------------------
|
|
2
|
+
Copyright (c) 2018-2022, Microsoft Research, Daan Leijen
|
|
3
|
+
This is free software; you can redistribute it and/or modify it under the
|
|
4
|
+
terms of the MIT license. A copy of the license can be found in the file
|
|
5
|
+
"LICENSE" at the root of this distribution.
|
|
6
|
+
-----------------------------------------------------------------------------*/
|
|
7
|
+
#include "mimalloc.h"
|
|
8
|
+
#include "mimalloc/internal.h"
|
|
9
|
+
#include "mimalloc/prim.h"
|
|
10
|
+
|
|
11
|
+
#include <string.h> // memcpy, memset
|
|
12
|
+
#include <stdlib.h> // atexit
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
// Empty page used to initialize the small free pages array
|
|
16
|
+
const mi_page_t _mi_page_empty = {
|
|
17
|
+
0,
|
|
18
|
+
false, false, false, false,
|
|
19
|
+
0, // capacity
|
|
20
|
+
0, // reserved capacity
|
|
21
|
+
{ 0 }, // flags
|
|
22
|
+
false, // is_zero
|
|
23
|
+
0, // retire_expire
|
|
24
|
+
NULL, // free
|
|
25
|
+
NULL, // local_free
|
|
26
|
+
0, // used
|
|
27
|
+
0, // block size shift
|
|
28
|
+
0, // heap tag
|
|
29
|
+
0, // block_size
|
|
30
|
+
NULL, // page_start
|
|
31
|
+
#if (MI_PADDING || MI_ENCODE_FREELIST)
|
|
32
|
+
{ 0, 0 },
|
|
33
|
+
#endif
|
|
34
|
+
MI_ATOMIC_VAR_INIT(0), // xthread_free
|
|
35
|
+
MI_ATOMIC_VAR_INIT(0), // xheap
|
|
36
|
+
NULL, NULL
|
|
37
|
+
, { 0 } // padding
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
#define MI_PAGE_EMPTY() ((mi_page_t*)&_mi_page_empty)
|
|
41
|
+
|
|
42
|
+
#if (MI_SMALL_WSIZE_MAX==128)
|
|
43
|
+
#if (MI_PADDING>0) && (MI_INTPTR_SIZE >= 8)
|
|
44
|
+
#define MI_SMALL_PAGES_EMPTY { MI_INIT128(MI_PAGE_EMPTY), MI_PAGE_EMPTY(), MI_PAGE_EMPTY() }
|
|
45
|
+
#elif (MI_PADDING>0)
|
|
46
|
+
#define MI_SMALL_PAGES_EMPTY { MI_INIT128(MI_PAGE_EMPTY), MI_PAGE_EMPTY(), MI_PAGE_EMPTY(), MI_PAGE_EMPTY() }
|
|
47
|
+
#else
|
|
48
|
+
#define MI_SMALL_PAGES_EMPTY { MI_INIT128(MI_PAGE_EMPTY), MI_PAGE_EMPTY() }
|
|
49
|
+
#endif
|
|
50
|
+
#else
|
|
51
|
+
#error "define right initialization sizes corresponding to MI_SMALL_WSIZE_MAX"
|
|
52
|
+
#endif
|
|
53
|
+
|
|
54
|
+
// Empty page queues for every bin
|
|
55
|
+
#define QNULL(sz) { NULL, NULL, (sz)*sizeof(uintptr_t) }
|
|
56
|
+
#define MI_PAGE_QUEUES_EMPTY \
|
|
57
|
+
{ QNULL(1), \
|
|
58
|
+
QNULL( 1), QNULL( 2), QNULL( 3), QNULL( 4), QNULL( 5), QNULL( 6), QNULL( 7), QNULL( 8), /* 8 */ \
|
|
59
|
+
QNULL( 10), QNULL( 12), QNULL( 14), QNULL( 16), QNULL( 20), QNULL( 24), QNULL( 28), QNULL( 32), /* 16 */ \
|
|
60
|
+
QNULL( 40), QNULL( 48), QNULL( 56), QNULL( 64), QNULL( 80), QNULL( 96), QNULL( 112), QNULL( 128), /* 24 */ \
|
|
61
|
+
QNULL( 160), QNULL( 192), QNULL( 224), QNULL( 256), QNULL( 320), QNULL( 384), QNULL( 448), QNULL( 512), /* 32 */ \
|
|
62
|
+
QNULL( 640), QNULL( 768), QNULL( 896), QNULL( 1024), QNULL( 1280), QNULL( 1536), QNULL( 1792), QNULL( 2048), /* 40 */ \
|
|
63
|
+
QNULL( 2560), QNULL( 3072), QNULL( 3584), QNULL( 4096), QNULL( 5120), QNULL( 6144), QNULL( 7168), QNULL( 8192), /* 48 */ \
|
|
64
|
+
QNULL( 10240), QNULL( 12288), QNULL( 14336), QNULL( 16384), QNULL( 20480), QNULL( 24576), QNULL( 28672), QNULL( 32768), /* 56 */ \
|
|
65
|
+
QNULL( 40960), QNULL( 49152), QNULL( 57344), QNULL( 65536), QNULL( 81920), QNULL( 98304), QNULL(114688), QNULL(131072), /* 64 */ \
|
|
66
|
+
QNULL(163840), QNULL(196608), QNULL(229376), QNULL(262144), QNULL(327680), QNULL(393216), QNULL(458752), QNULL(524288), /* 72 */ \
|
|
67
|
+
QNULL(MI_MEDIUM_OBJ_WSIZE_MAX + 1 /* 655360, Huge queue */), \
|
|
68
|
+
QNULL(MI_MEDIUM_OBJ_WSIZE_MAX + 2) /* Full queue */ }
|
|
69
|
+
|
|
70
|
+
#define MI_STAT_COUNT_NULL() {0,0,0}
|
|
71
|
+
|
|
72
|
+
// Empty statistics
|
|
73
|
+
#define MI_STATS_NULL \
|
|
74
|
+
MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \
|
|
75
|
+
MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \
|
|
76
|
+
MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \
|
|
77
|
+
{ 0 }, { 0 }, { 0 }, { 0 }, \
|
|
78
|
+
{ 0 }, { 0 }, { 0 }, { 0 }, \
|
|
79
|
+
\
|
|
80
|
+
{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, \
|
|
81
|
+
MI_INIT4(MI_STAT_COUNT_NULL), \
|
|
82
|
+
{ 0 }, { 0 }, { 0 }, { 0 }, \
|
|
83
|
+
\
|
|
84
|
+
{ MI_INIT4(MI_STAT_COUNT_NULL) }, \
|
|
85
|
+
{ { 0 }, { 0 }, { 0 }, { 0 } }, \
|
|
86
|
+
\
|
|
87
|
+
{ MI_INIT74(MI_STAT_COUNT_NULL) }, \
|
|
88
|
+
{ MI_INIT74(MI_STAT_COUNT_NULL) }
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
// Empty slice span queues for every bin
|
|
92
|
+
#define SQNULL(sz) { NULL, NULL, sz }
|
|
93
|
+
#define MI_SEGMENT_SPAN_QUEUES_EMPTY \
|
|
94
|
+
{ SQNULL(1), \
|
|
95
|
+
SQNULL( 1), SQNULL( 2), SQNULL( 3), SQNULL( 4), SQNULL( 5), SQNULL( 6), SQNULL( 7), SQNULL( 10), /* 8 */ \
|
|
96
|
+
SQNULL( 12), SQNULL( 14), SQNULL( 16), SQNULL( 20), SQNULL( 24), SQNULL( 28), SQNULL( 32), SQNULL( 40), /* 16 */ \
|
|
97
|
+
SQNULL( 48), SQNULL( 56), SQNULL( 64), SQNULL( 80), SQNULL( 96), SQNULL( 112), SQNULL( 128), SQNULL( 160), /* 24 */ \
|
|
98
|
+
SQNULL( 192), SQNULL( 224), SQNULL( 256), SQNULL( 320), SQNULL( 384), SQNULL( 448), SQNULL( 512), SQNULL( 640), /* 32 */ \
|
|
99
|
+
SQNULL( 768), SQNULL( 896), SQNULL( 1024) /* 35 */ }
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
// --------------------------------------------------------
|
|
103
|
+
// Statically allocate an empty heap as the initial
|
|
104
|
+
// thread local value for the default heap,
|
|
105
|
+
// and statically allocate the backing heap for the main
|
|
106
|
+
// thread so it can function without doing any allocation
|
|
107
|
+
// itself (as accessing a thread local for the first time
|
|
108
|
+
// may lead to allocation itself on some platforms)
|
|
109
|
+
// --------------------------------------------------------
|
|
110
|
+
|
|
111
|
+
mi_decl_cache_align const mi_heap_t _mi_heap_empty = {
|
|
112
|
+
NULL,
|
|
113
|
+
MI_ATOMIC_VAR_INIT(NULL),
|
|
114
|
+
0, // tid
|
|
115
|
+
0, // cookie
|
|
116
|
+
0, // arena id
|
|
117
|
+
{ 0, 0 }, // keys
|
|
118
|
+
{ {0}, {0}, 0, true }, // random
|
|
119
|
+
0, // page count
|
|
120
|
+
MI_BIN_FULL, 0, // page retired min/max
|
|
121
|
+
0, 0, // generic count
|
|
122
|
+
NULL, // next
|
|
123
|
+
false, // can reclaim
|
|
124
|
+
0, // tag
|
|
125
|
+
#if MI_GUARDED
|
|
126
|
+
0, 0, 0, 1, // count is 1 so we never write to it (see `internal.h:mi_heap_malloc_use_guarded`)
|
|
127
|
+
#endif
|
|
128
|
+
MI_SMALL_PAGES_EMPTY,
|
|
129
|
+
MI_PAGE_QUEUES_EMPTY
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
static mi_decl_cache_align mi_subproc_t mi_subproc_default;
|
|
133
|
+
|
|
134
|
+
#define tld_empty_stats ((mi_stats_t*)((uint8_t*)&tld_empty + offsetof(mi_tld_t,stats)))
|
|
135
|
+
|
|
136
|
+
mi_decl_cache_align static const mi_tld_t tld_empty = {
|
|
137
|
+
0,
|
|
138
|
+
false,
|
|
139
|
+
NULL, NULL,
|
|
140
|
+
{ MI_SEGMENT_SPAN_QUEUES_EMPTY, 0, 0, 0, 0, 0, &mi_subproc_default, tld_empty_stats }, // segments
|
|
141
|
+
{ MI_STAT_VERSION, MI_STATS_NULL } // stats
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
mi_threadid_t _mi_thread_id(void) mi_attr_noexcept {
|
|
145
|
+
return _mi_prim_thread_id();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// the thread-local default heap for allocation
|
|
149
|
+
mi_decl_thread mi_heap_t* _mi_heap_default = (mi_heap_t*)&_mi_heap_empty;
|
|
150
|
+
|
|
151
|
+
extern mi_decl_hidden mi_heap_t _mi_heap_main;
|
|
152
|
+
|
|
153
|
+
static mi_decl_cache_align mi_tld_t tld_main = {
|
|
154
|
+
0, false,
|
|
155
|
+
&_mi_heap_main, & _mi_heap_main,
|
|
156
|
+
{ MI_SEGMENT_SPAN_QUEUES_EMPTY, 0, 0, 0, 0, 0, &mi_subproc_default, &tld_main.stats }, // segments
|
|
157
|
+
{ MI_STAT_VERSION, MI_STATS_NULL } // stats
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
mi_decl_cache_align mi_heap_t _mi_heap_main = {
|
|
161
|
+
&tld_main,
|
|
162
|
+
MI_ATOMIC_VAR_INIT(NULL),
|
|
163
|
+
0, // thread id
|
|
164
|
+
0, // initial cookie
|
|
165
|
+
0, // arena id
|
|
166
|
+
{ 0, 0 }, // the key of the main heap can be fixed (unlike page keys that need to be secure!)
|
|
167
|
+
{ {0x846ca68b}, {0}, 0, true }, // random
|
|
168
|
+
0, // page count
|
|
169
|
+
MI_BIN_FULL, 0, // page retired min/max
|
|
170
|
+
0, 0, // generic count
|
|
171
|
+
NULL, // next heap
|
|
172
|
+
false, // can reclaim
|
|
173
|
+
0, // tag
|
|
174
|
+
#if MI_GUARDED
|
|
175
|
+
0, 0, 0, 0,
|
|
176
|
+
#endif
|
|
177
|
+
MI_SMALL_PAGES_EMPTY,
|
|
178
|
+
MI_PAGE_QUEUES_EMPTY
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
bool _mi_process_is_initialized = false; // set to `true` in `mi_process_init`.
|
|
182
|
+
|
|
183
|
+
mi_stats_t _mi_stats_main = { MI_STAT_VERSION, MI_STATS_NULL };
|
|
184
|
+
|
|
185
|
+
#if MI_GUARDED
|
|
186
|
+
mi_decl_export void mi_heap_guarded_set_sample_rate(mi_heap_t* heap, size_t sample_rate, size_t seed) {
|
|
187
|
+
heap->guarded_sample_rate = sample_rate;
|
|
188
|
+
heap->guarded_sample_count = sample_rate; // count down samples
|
|
189
|
+
if (heap->guarded_sample_rate > 1) {
|
|
190
|
+
if (seed == 0) {
|
|
191
|
+
seed = _mi_heap_random_next(heap);
|
|
192
|
+
}
|
|
193
|
+
heap->guarded_sample_count = (seed % heap->guarded_sample_rate) + 1; // start at random count between 1 and `sample_rate`
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
mi_decl_export void mi_heap_guarded_set_size_bound(mi_heap_t* heap, size_t min, size_t max) {
|
|
198
|
+
heap->guarded_size_min = min;
|
|
199
|
+
heap->guarded_size_max = (min > max ? min : max);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
void _mi_heap_guarded_init(mi_heap_t* heap) {
|
|
203
|
+
mi_heap_guarded_set_sample_rate(heap,
|
|
204
|
+
(size_t)mi_option_get_clamp(mi_option_guarded_sample_rate, 0, LONG_MAX),
|
|
205
|
+
(size_t)mi_option_get(mi_option_guarded_sample_seed));
|
|
206
|
+
mi_heap_guarded_set_size_bound(heap,
|
|
207
|
+
(size_t)mi_option_get_clamp(mi_option_guarded_min, 0, LONG_MAX),
|
|
208
|
+
(size_t)mi_option_get_clamp(mi_option_guarded_max, 0, LONG_MAX) );
|
|
209
|
+
}
|
|
210
|
+
#else
|
|
211
|
+
mi_decl_export void mi_heap_guarded_set_sample_rate(mi_heap_t* heap, size_t sample_rate, size_t seed) {
|
|
212
|
+
MI_UNUSED(heap); MI_UNUSED(sample_rate); MI_UNUSED(seed);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
mi_decl_export void mi_heap_guarded_set_size_bound(mi_heap_t* heap, size_t min, size_t max) {
|
|
216
|
+
MI_UNUSED(heap); MI_UNUSED(min); MI_UNUSED(max);
|
|
217
|
+
}
|
|
218
|
+
void _mi_heap_guarded_init(mi_heap_t* heap) {
|
|
219
|
+
MI_UNUSED(heap);
|
|
220
|
+
}
|
|
221
|
+
#endif
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
static void mi_heap_main_init(void) {
|
|
225
|
+
if (_mi_heap_main.cookie == 0) {
|
|
226
|
+
_mi_heap_main.thread_id = _mi_thread_id();
|
|
227
|
+
_mi_heap_main.cookie = 1;
|
|
228
|
+
#if defined(_WIN32) && !defined(MI_SHARED_LIB)
|
|
229
|
+
_mi_random_init_weak(&_mi_heap_main.random); // prevent allocation failure during bcrypt dll initialization with static linking
|
|
230
|
+
#else
|
|
231
|
+
_mi_random_init(&_mi_heap_main.random);
|
|
232
|
+
#endif
|
|
233
|
+
_mi_heap_main.cookie = _mi_heap_random_next(&_mi_heap_main);
|
|
234
|
+
_mi_heap_main.keys[0] = _mi_heap_random_next(&_mi_heap_main);
|
|
235
|
+
_mi_heap_main.keys[1] = _mi_heap_random_next(&_mi_heap_main);
|
|
236
|
+
mi_lock_init(&mi_subproc_default.abandoned_os_lock);
|
|
237
|
+
mi_lock_init(&mi_subproc_default.abandoned_os_visit_lock);
|
|
238
|
+
_mi_heap_guarded_init(&_mi_heap_main);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
mi_heap_t* _mi_heap_main_get(void) {
|
|
243
|
+
mi_heap_main_init();
|
|
244
|
+
return &_mi_heap_main;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* -----------------------------------------------------------
|
|
248
|
+
Sub process
|
|
249
|
+
----------------------------------------------------------- */
|
|
250
|
+
|
|
251
|
+
mi_subproc_id_t mi_subproc_main(void) {
|
|
252
|
+
return NULL;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
mi_subproc_id_t mi_subproc_new(void) {
|
|
256
|
+
mi_memid_t memid = _mi_memid_none();
|
|
257
|
+
mi_subproc_t* subproc = (mi_subproc_t*)_mi_arena_meta_zalloc(sizeof(mi_subproc_t), &memid);
|
|
258
|
+
if (subproc == NULL) return NULL;
|
|
259
|
+
subproc->memid = memid;
|
|
260
|
+
subproc->abandoned_os_list = NULL;
|
|
261
|
+
mi_lock_init(&subproc->abandoned_os_lock);
|
|
262
|
+
mi_lock_init(&subproc->abandoned_os_visit_lock);
|
|
263
|
+
return subproc;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
mi_subproc_t* _mi_subproc_from_id(mi_subproc_id_t subproc_id) {
|
|
267
|
+
return (subproc_id == NULL ? &mi_subproc_default : (mi_subproc_t*)subproc_id);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
void mi_subproc_delete(mi_subproc_id_t subproc_id) {
|
|
271
|
+
if (subproc_id == NULL) return;
|
|
272
|
+
mi_subproc_t* subproc = _mi_subproc_from_id(subproc_id);
|
|
273
|
+
// check if there are no abandoned segments still..
|
|
274
|
+
bool safe_to_delete = false;
|
|
275
|
+
mi_lock(&subproc->abandoned_os_lock) {
|
|
276
|
+
if (subproc->abandoned_os_list == NULL) {
|
|
277
|
+
safe_to_delete = true;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (!safe_to_delete) return;
|
|
281
|
+
// safe to release
|
|
282
|
+
// todo: should we refcount subprocesses?
|
|
283
|
+
mi_lock_done(&subproc->abandoned_os_lock);
|
|
284
|
+
mi_lock_done(&subproc->abandoned_os_visit_lock);
|
|
285
|
+
_mi_arena_meta_free(subproc, subproc->memid, sizeof(mi_subproc_t));
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
void mi_subproc_add_current_thread(mi_subproc_id_t subproc_id) {
|
|
289
|
+
mi_heap_t* heap = mi_heap_get_default();
|
|
290
|
+
if (heap == NULL) return;
|
|
291
|
+
mi_assert(heap->tld->segments.subproc == &mi_subproc_default);
|
|
292
|
+
if (heap->tld->segments.subproc != &mi_subproc_default) return;
|
|
293
|
+
heap->tld->segments.subproc = _mi_subproc_from_id(subproc_id);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
/* -----------------------------------------------------------
|
|
299
|
+
Initialization and freeing of the thread local heaps
|
|
300
|
+
----------------------------------------------------------- */
|
|
301
|
+
|
|
302
|
+
// note: in x64 in release build `sizeof(mi_thread_data_t)` is under 4KiB (= OS page size).
|
|
303
|
+
typedef struct mi_thread_data_s {
|
|
304
|
+
mi_heap_t heap; // must come first due to cast in `_mi_heap_done`
|
|
305
|
+
mi_tld_t tld;
|
|
306
|
+
mi_memid_t memid; // must come last due to zero'ing
|
|
307
|
+
} mi_thread_data_t;
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
// Thread meta-data is allocated directly from the OS. For
|
|
311
|
+
// some programs that do not use thread pools and allocate and
|
|
312
|
+
// destroy many OS threads, this may causes too much overhead
|
|
313
|
+
// per thread so we maintain a small cache of recently freed metadata.
|
|
314
|
+
|
|
315
|
+
#define TD_CACHE_SIZE (32)
|
|
316
|
+
static _Atomic(mi_thread_data_t*) td_cache[TD_CACHE_SIZE];
|
|
317
|
+
|
|
318
|
+
static mi_thread_data_t* mi_thread_data_zalloc(void) {
|
|
319
|
+
// try to find thread metadata in the cache
|
|
320
|
+
mi_thread_data_t* td = NULL;
|
|
321
|
+
for (int i = 0; i < TD_CACHE_SIZE; i++) {
|
|
322
|
+
td = mi_atomic_load_ptr_relaxed(mi_thread_data_t, &td_cache[i]);
|
|
323
|
+
if (td != NULL) {
|
|
324
|
+
// found cached allocation, try use it
|
|
325
|
+
td = mi_atomic_exchange_ptr_acq_rel(mi_thread_data_t, &td_cache[i], NULL);
|
|
326
|
+
if (td != NULL) {
|
|
327
|
+
_mi_memzero(td, offsetof(mi_thread_data_t,memid));
|
|
328
|
+
return td;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// if that fails, allocate as meta data
|
|
334
|
+
mi_memid_t memid;
|
|
335
|
+
td = (mi_thread_data_t*)_mi_os_zalloc(sizeof(mi_thread_data_t), &memid);
|
|
336
|
+
if (td == NULL) {
|
|
337
|
+
// if this fails, try once more. (issue #257)
|
|
338
|
+
td = (mi_thread_data_t*)_mi_os_zalloc(sizeof(mi_thread_data_t), &memid);
|
|
339
|
+
if (td == NULL) {
|
|
340
|
+
// really out of memory
|
|
341
|
+
_mi_error_message(ENOMEM, "unable to allocate thread local heap metadata (%zu bytes)\n", sizeof(mi_thread_data_t));
|
|
342
|
+
return NULL;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
td->memid = memid;
|
|
346
|
+
return td;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
static void mi_thread_data_free( mi_thread_data_t* tdfree ) {
|
|
350
|
+
// try to add the thread metadata to the cache
|
|
351
|
+
for (int i = 0; i < TD_CACHE_SIZE; i++) {
|
|
352
|
+
mi_thread_data_t* td = mi_atomic_load_ptr_relaxed(mi_thread_data_t, &td_cache[i]);
|
|
353
|
+
if (td == NULL) {
|
|
354
|
+
mi_thread_data_t* expected = NULL;
|
|
355
|
+
if (mi_atomic_cas_ptr_weak_acq_rel(mi_thread_data_t, &td_cache[i], &expected, tdfree)) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
// if that fails, just free it directly
|
|
361
|
+
_mi_os_free(tdfree, sizeof(mi_thread_data_t), tdfree->memid);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
void _mi_thread_data_collect(void) {
|
|
365
|
+
// free all thread metadata from the cache
|
|
366
|
+
for (int i = 0; i < TD_CACHE_SIZE; i++) {
|
|
367
|
+
mi_thread_data_t* td = mi_atomic_load_ptr_relaxed(mi_thread_data_t, &td_cache[i]);
|
|
368
|
+
if (td != NULL) {
|
|
369
|
+
td = mi_atomic_exchange_ptr_acq_rel(mi_thread_data_t, &td_cache[i], NULL);
|
|
370
|
+
if (td != NULL) {
|
|
371
|
+
_mi_os_free(td, sizeof(mi_thread_data_t), td->memid);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Initialize the thread local default heap, called from `mi_thread_init`
|
|
378
|
+
static bool _mi_thread_heap_init(void) {
|
|
379
|
+
if (mi_heap_is_initialized(mi_prim_get_default_heap())) return true;
|
|
380
|
+
if (_mi_is_main_thread()) {
|
|
381
|
+
// mi_assert_internal(_mi_heap_main.thread_id != 0); // can happen on freeBSD where alloc is called before any initialization
|
|
382
|
+
// the main heap is statically allocated
|
|
383
|
+
mi_heap_main_init();
|
|
384
|
+
_mi_heap_set_default_direct(&_mi_heap_main);
|
|
385
|
+
//mi_assert_internal(_mi_heap_default->tld->heap_backing == mi_prim_get_default_heap());
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
// use `_mi_os_alloc` to allocate directly from the OS
|
|
389
|
+
mi_thread_data_t* td = mi_thread_data_zalloc();
|
|
390
|
+
if (td == NULL) return false;
|
|
391
|
+
|
|
392
|
+
mi_tld_t* tld = &td->tld;
|
|
393
|
+
mi_heap_t* heap = &td->heap;
|
|
394
|
+
_mi_tld_init(tld, heap); // must be before `_mi_heap_init`
|
|
395
|
+
_mi_heap_init(heap, tld, _mi_arena_id_none(), false /* can reclaim */, 0 /* default tag */);
|
|
396
|
+
_mi_heap_set_default_direct(heap);
|
|
397
|
+
}
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// initialize thread local data
|
|
402
|
+
void _mi_tld_init(mi_tld_t* tld, mi_heap_t* bheap) {
|
|
403
|
+
_mi_memcpy_aligned(tld, &tld_empty, sizeof(mi_tld_t));
|
|
404
|
+
tld->heap_backing = bheap;
|
|
405
|
+
tld->heaps = NULL;
|
|
406
|
+
tld->segments.subproc = &mi_subproc_default;
|
|
407
|
+
tld->segments.stats = &tld->stats;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Free the thread local default heap (called from `mi_thread_done`)
|
|
411
|
+
static bool _mi_thread_heap_done(mi_heap_t* heap) {
|
|
412
|
+
if (!mi_heap_is_initialized(heap)) return true;
|
|
413
|
+
|
|
414
|
+
// reset default heap
|
|
415
|
+
_mi_heap_set_default_direct(_mi_is_main_thread() ? &_mi_heap_main : (mi_heap_t*)&_mi_heap_empty);
|
|
416
|
+
|
|
417
|
+
// switch to backing heap
|
|
418
|
+
heap = heap->tld->heap_backing;
|
|
419
|
+
if (!mi_heap_is_initialized(heap)) return false;
|
|
420
|
+
|
|
421
|
+
// delete all non-backing heaps in this thread
|
|
422
|
+
mi_heap_t* curr = heap->tld->heaps;
|
|
423
|
+
while (curr != NULL) {
|
|
424
|
+
mi_heap_t* next = curr->next; // save `next` as `curr` will be freed
|
|
425
|
+
if (curr != heap) {
|
|
426
|
+
mi_assert_internal(!mi_heap_is_backing(curr));
|
|
427
|
+
mi_heap_delete(curr);
|
|
428
|
+
}
|
|
429
|
+
curr = next;
|
|
430
|
+
}
|
|
431
|
+
mi_assert_internal(heap->tld->heaps == heap && heap->next == NULL);
|
|
432
|
+
mi_assert_internal(mi_heap_is_backing(heap));
|
|
433
|
+
|
|
434
|
+
// collect if not the main thread
|
|
435
|
+
if (heap != &_mi_heap_main) {
|
|
436
|
+
_mi_heap_collect_abandon(heap);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// merge stats
|
|
440
|
+
_mi_stats_done(&heap->tld->stats);
|
|
441
|
+
|
|
442
|
+
// free if not the main thread
|
|
443
|
+
if (heap != &_mi_heap_main) {
|
|
444
|
+
// the following assertion does not always hold for huge segments as those are always treated
|
|
445
|
+
// as abondened: one may allocate it in one thread, but deallocate in another in which case
|
|
446
|
+
// the count can be too large or negative. todo: perhaps not count huge segments? see issue #363
|
|
447
|
+
// mi_assert_internal(heap->tld->segments.count == 0 || heap->thread_id != _mi_thread_id());
|
|
448
|
+
mi_thread_data_free((mi_thread_data_t*)heap);
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
#if 0
|
|
452
|
+
// never free the main thread even in debug mode; if a dll is linked statically with mimalloc,
|
|
453
|
+
// there may still be delete/free calls after the mi_fls_done is called. Issue #207
|
|
454
|
+
_mi_heap_destroy_pages(heap);
|
|
455
|
+
mi_assert_internal(heap->tld->heap_backing == &_mi_heap_main);
|
|
456
|
+
#endif
|
|
457
|
+
}
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
// --------------------------------------------------------
|
|
464
|
+
// Try to run `mi_thread_done()` automatically so any memory
|
|
465
|
+
// owned by the thread but not yet released can be abandoned
|
|
466
|
+
// and re-owned by another thread.
|
|
467
|
+
//
|
|
468
|
+
// 1. windows dynamic library:
|
|
469
|
+
// call from DllMain on DLL_THREAD_DETACH
|
|
470
|
+
// 2. windows static library:
|
|
471
|
+
// use `FlsAlloc` to call a destructor when the thread is done
|
|
472
|
+
// 3. unix, pthreads:
|
|
473
|
+
// use a pthread key to call a destructor when a pthread is done
|
|
474
|
+
//
|
|
475
|
+
// In the last two cases we also need to call `mi_process_init`
|
|
476
|
+
// to set up the thread local keys.
|
|
477
|
+
// --------------------------------------------------------
|
|
478
|
+
|
|
479
|
+
// Set up handlers so `mi_thread_done` is called automatically
|
|
480
|
+
static void mi_process_setup_auto_thread_done(void) {
|
|
481
|
+
static bool tls_initialized = false; // fine if it races
|
|
482
|
+
if (tls_initialized) return;
|
|
483
|
+
tls_initialized = true;
|
|
484
|
+
_mi_prim_thread_init_auto_done();
|
|
485
|
+
_mi_heap_set_default_direct(&_mi_heap_main);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
bool _mi_is_main_thread(void) {
|
|
490
|
+
return (_mi_heap_main.thread_id==0 || _mi_heap_main.thread_id == _mi_thread_id());
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
static _Atomic(size_t) thread_count = MI_ATOMIC_VAR_INIT(1);
|
|
494
|
+
|
|
495
|
+
size_t _mi_current_thread_count(void) {
|
|
496
|
+
return mi_atomic_load_relaxed(&thread_count);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// This is called from the `mi_malloc_generic`
|
|
500
|
+
void mi_thread_init(void) mi_attr_noexcept
|
|
501
|
+
{
|
|
502
|
+
// ensure our process has started already
|
|
503
|
+
mi_process_init();
|
|
504
|
+
|
|
505
|
+
// initialize the thread local default heap
|
|
506
|
+
// (this will call `_mi_heap_set_default_direct` and thus set the
|
|
507
|
+
// fiber/pthread key to a non-zero value, ensuring `_mi_thread_done` is called)
|
|
508
|
+
if (_mi_thread_heap_init()) return; // returns true if already initialized
|
|
509
|
+
|
|
510
|
+
_mi_stat_increase(&_mi_stats_main.threads, 1);
|
|
511
|
+
mi_atomic_increment_relaxed(&thread_count);
|
|
512
|
+
//_mi_verbose_message("thread init: 0x%zx\n", _mi_thread_id());
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
void mi_thread_done(void) mi_attr_noexcept {
|
|
516
|
+
_mi_thread_done(NULL);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
void _mi_thread_done(mi_heap_t* heap)
|
|
520
|
+
{
|
|
521
|
+
// calling with NULL implies using the default heap
|
|
522
|
+
if (heap == NULL) {
|
|
523
|
+
heap = mi_prim_get_default_heap();
|
|
524
|
+
if (heap == NULL) return;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// prevent re-entrancy through heap_done/heap_set_default_direct (issue #699)
|
|
528
|
+
if (!mi_heap_is_initialized(heap)) {
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// adjust stats
|
|
533
|
+
mi_atomic_decrement_relaxed(&thread_count);
|
|
534
|
+
_mi_stat_decrease(&_mi_stats_main.threads, 1);
|
|
535
|
+
|
|
536
|
+
// check thread-id as on Windows shutdown with FLS the main (exit) thread may call this on thread-local heaps...
|
|
537
|
+
if (heap->thread_id != _mi_thread_id()) return;
|
|
538
|
+
|
|
539
|
+
// abandon the thread local heap
|
|
540
|
+
if (_mi_thread_heap_done(heap)) return; // returns true if already ran
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
void _mi_heap_set_default_direct(mi_heap_t* heap) {
|
|
544
|
+
mi_assert_internal(heap != NULL);
|
|
545
|
+
#if defined(MI_TLS_SLOT)
|
|
546
|
+
mi_prim_tls_slot_set(MI_TLS_SLOT,heap);
|
|
547
|
+
#elif defined(MI_TLS_PTHREAD_SLOT_OFS)
|
|
548
|
+
*mi_prim_tls_pthread_heap_slot() = heap;
|
|
549
|
+
#elif defined(MI_TLS_PTHREAD)
|
|
550
|
+
// we use _mi_heap_default_key
|
|
551
|
+
#else
|
|
552
|
+
_mi_heap_default = heap;
|
|
553
|
+
#endif
|
|
554
|
+
|
|
555
|
+
// ensure the default heap is passed to `_mi_thread_done`
|
|
556
|
+
// setting to a non-NULL value also ensures `mi_thread_done` is called.
|
|
557
|
+
_mi_prim_thread_associate_default_heap(heap);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
void mi_thread_set_in_threadpool(void) mi_attr_noexcept {
|
|
561
|
+
// nothing
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// --------------------------------------------------------
|
|
565
|
+
// Run functions on process init/done, and thread init/done
|
|
566
|
+
// --------------------------------------------------------
|
|
567
|
+
static bool os_preloading = true; // true until this module is initialized
|
|
568
|
+
|
|
569
|
+
// Returns true if this module has not been initialized; Don't use C runtime routines until it returns false.
|
|
570
|
+
bool mi_decl_noinline _mi_preloading(void) {
|
|
571
|
+
return os_preloading;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// Returns true if mimalloc was redirected
|
|
575
|
+
mi_decl_nodiscard bool mi_is_redirected(void) mi_attr_noexcept {
|
|
576
|
+
return _mi_is_redirected();
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// Called once by the process loader from `src/prim/prim.c`
|
|
580
|
+
void _mi_auto_process_init(void) {
|
|
581
|
+
mi_heap_main_init();
|
|
582
|
+
#if defined(__APPLE__) || defined(MI_TLS_RECURSE_GUARD)
|
|
583
|
+
volatile mi_heap_t* dummy = _mi_heap_default; // access TLS to allocate it before setting tls_initialized to true;
|
|
584
|
+
if (dummy == NULL) return; // use dummy or otherwise the access may get optimized away (issue #697)
|
|
585
|
+
#endif
|
|
586
|
+
os_preloading = false;
|
|
587
|
+
mi_assert_internal(_mi_is_main_thread());
|
|
588
|
+
_mi_options_init();
|
|
589
|
+
mi_process_setup_auto_thread_done();
|
|
590
|
+
mi_process_init();
|
|
591
|
+
if (_mi_is_redirected()) _mi_verbose_message("malloc is redirected.\n");
|
|
592
|
+
|
|
593
|
+
// show message from the redirector (if present)
|
|
594
|
+
const char* msg = NULL;
|
|
595
|
+
_mi_allocator_init(&msg);
|
|
596
|
+
if (msg != NULL && (mi_option_is_enabled(mi_option_verbose) || mi_option_is_enabled(mi_option_show_errors))) {
|
|
597
|
+
_mi_fputs(NULL,NULL,NULL,msg);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// reseed random
|
|
601
|
+
_mi_random_reinit_if_weak(&_mi_heap_main.random);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
#if defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64))
|
|
605
|
+
#include <intrin.h>
|
|
606
|
+
mi_decl_cache_align bool _mi_cpu_has_fsrm = false;
|
|
607
|
+
mi_decl_cache_align bool _mi_cpu_has_erms = false;
|
|
608
|
+
|
|
609
|
+
static void mi_detect_cpu_features(void) {
|
|
610
|
+
// FSRM for fast short rep movsb/stosb support (AMD Zen3+ (~2020) or Intel Ice Lake+ (~2017))
|
|
611
|
+
// EMRS for fast enhanced rep movsb/stosb support
|
|
612
|
+
int32_t cpu_info[4];
|
|
613
|
+
__cpuid(cpu_info, 7);
|
|
614
|
+
_mi_cpu_has_fsrm = ((cpu_info[3] & (1 << 4)) != 0); // bit 4 of EDX : see <https://en.wikipedia.org/wiki/CPUID#EAX=7,_ECX=0:_Extended_Features>
|
|
615
|
+
_mi_cpu_has_erms = ((cpu_info[1] & (1 << 9)) != 0); // bit 9 of EBX : see <https://en.wikipedia.org/wiki/CPUID#EAX=7,_ECX=0:_Extended_Features>
|
|
616
|
+
}
|
|
617
|
+
#else
|
|
618
|
+
static void mi_detect_cpu_features(void) {
|
|
619
|
+
// nothing
|
|
620
|
+
}
|
|
621
|
+
#endif
|
|
622
|
+
|
|
623
|
+
// Initialize the process; called by thread_init or the process loader
|
|
624
|
+
void mi_process_init(void) mi_attr_noexcept {
|
|
625
|
+
// ensure we are called once
|
|
626
|
+
static mi_atomic_once_t process_init;
|
|
627
|
+
#if _MSC_VER < 1920
|
|
628
|
+
mi_heap_main_init(); // vs2017 can dynamically re-initialize _mi_heap_main
|
|
629
|
+
#endif
|
|
630
|
+
if (!mi_atomic_once(&process_init)) return;
|
|
631
|
+
_mi_process_is_initialized = true;
|
|
632
|
+
_mi_verbose_message("process init: 0x%zx\n", _mi_thread_id());
|
|
633
|
+
mi_process_setup_auto_thread_done();
|
|
634
|
+
|
|
635
|
+
mi_detect_cpu_features();
|
|
636
|
+
_mi_os_init();
|
|
637
|
+
mi_heap_main_init();
|
|
638
|
+
mi_thread_init();
|
|
639
|
+
|
|
640
|
+
#if defined(_WIN32)
|
|
641
|
+
// On windows, when building as a static lib the FLS cleanup happens to early for the main thread.
|
|
642
|
+
// To avoid this, set the FLS value for the main thread to NULL so the fls cleanup
|
|
643
|
+
// will not call _mi_thread_done on the (still executing) main thread. See issue #508.
|
|
644
|
+
_mi_prim_thread_associate_default_heap(NULL);
|
|
645
|
+
#endif
|
|
646
|
+
|
|
647
|
+
mi_stats_reset(); // only call stat reset *after* thread init (or the heap tld == NULL)
|
|
648
|
+
mi_track_init();
|
|
649
|
+
|
|
650
|
+
if (mi_option_is_enabled(mi_option_reserve_huge_os_pages)) {
|
|
651
|
+
size_t pages = mi_option_get_clamp(mi_option_reserve_huge_os_pages, 0, 128*1024);
|
|
652
|
+
long reserve_at = mi_option_get(mi_option_reserve_huge_os_pages_at);
|
|
653
|
+
if (reserve_at != -1) {
|
|
654
|
+
mi_reserve_huge_os_pages_at(pages, reserve_at, pages*500);
|
|
655
|
+
} else {
|
|
656
|
+
mi_reserve_huge_os_pages_interleave(pages, 0, pages*500);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
if (mi_option_is_enabled(mi_option_reserve_os_memory)) {
|
|
660
|
+
long ksize = mi_option_get(mi_option_reserve_os_memory);
|
|
661
|
+
if (ksize > 0) {
|
|
662
|
+
mi_reserve_os_memory((size_t)ksize*MI_KiB, true /* commit? */, true /* allow large pages? */);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// Called when the process is done (cdecl as it is used with `at_exit` on some platforms)
|
|
668
|
+
void mi_cdecl mi_process_done(void) mi_attr_noexcept {
|
|
669
|
+
// only shutdown if we were initialized
|
|
670
|
+
if (!_mi_process_is_initialized) return;
|
|
671
|
+
// ensure we are called once
|
|
672
|
+
static bool process_done = false;
|
|
673
|
+
if (process_done) return;
|
|
674
|
+
process_done = true;
|
|
675
|
+
|
|
676
|
+
// get the default heap so we don't need to acces thread locals anymore
|
|
677
|
+
mi_heap_t* heap = mi_prim_get_default_heap(); // use prim to not initialize any heap
|
|
678
|
+
mi_assert_internal(heap != NULL);
|
|
679
|
+
|
|
680
|
+
// release any thread specific resources and ensure _mi_thread_done is called on all but the main thread
|
|
681
|
+
_mi_prim_thread_done_auto_done();
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
#ifndef MI_SKIP_COLLECT_ON_EXIT
|
|
685
|
+
#if (MI_DEBUG || !defined(MI_SHARED_LIB))
|
|
686
|
+
// free all memory if possible on process exit. This is not needed for a stand-alone process
|
|
687
|
+
// but should be done if mimalloc is statically linked into another shared library which
|
|
688
|
+
// is repeatedly loaded/unloaded, see issue #281.
|
|
689
|
+
mi_heap_collect(heap, true /* force */ );
|
|
690
|
+
#endif
|
|
691
|
+
#endif
|
|
692
|
+
|
|
693
|
+
// Forcefully release all retained memory; this can be dangerous in general if overriding regular malloc/free
|
|
694
|
+
// since after process_done there might still be other code running that calls `free` (like at_exit routines,
|
|
695
|
+
// or C-runtime termination code.
|
|
696
|
+
if (mi_option_is_enabled(mi_option_destroy_on_exit)) {
|
|
697
|
+
mi_heap_collect(heap, true /* force */);
|
|
698
|
+
_mi_heap_unsafe_destroy_all(heap); // forcefully release all memory held by all heaps (of this thread only!)
|
|
699
|
+
_mi_arena_unsafe_destroy_all();
|
|
700
|
+
_mi_segment_map_unsafe_destroy();
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
if (mi_option_is_enabled(mi_option_show_stats) || mi_option_is_enabled(mi_option_verbose)) {
|
|
704
|
+
mi_stats_print(NULL);
|
|
705
|
+
}
|
|
706
|
+
_mi_allocator_done();
|
|
707
|
+
_mi_verbose_message("process done: 0x%zx\n", _mi_heap_main.thread_id);
|
|
708
|
+
os_preloading = true; // don't call the C runtime anymore
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
void mi_cdecl _mi_auto_process_done(void) mi_attr_noexcept {
|
|
712
|
+
if (_mi_option_get_fast(mi_option_destroy_on_exit)>1) return;
|
|
713
|
+
mi_process_done();
|
|
714
|
+
}
|