@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,733 @@
|
|
|
1
|
+
/*----------------------------------------------------------------------------
|
|
2
|
+
Copyright (c) 2018-2021, 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
|
+
|
|
8
|
+
#include "mimalloc.h"
|
|
9
|
+
#include "mimalloc/internal.h"
|
|
10
|
+
#include "mimalloc/atomic.h"
|
|
11
|
+
#include "mimalloc/prim.h" // mi_prim_get_default_heap
|
|
12
|
+
|
|
13
|
+
#include <string.h> // memset, memcpy
|
|
14
|
+
|
|
15
|
+
#if defined(_MSC_VER) && (_MSC_VER < 1920)
|
|
16
|
+
#pragma warning(disable:4204) // non-constant aggregate initializer
|
|
17
|
+
#endif
|
|
18
|
+
|
|
19
|
+
/* -----------------------------------------------------------
|
|
20
|
+
Helpers
|
|
21
|
+
----------------------------------------------------------- */
|
|
22
|
+
|
|
23
|
+
// return `true` if ok, `false` to break
|
|
24
|
+
typedef bool (heap_page_visitor_fun)(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t* page, void* arg1, void* arg2);
|
|
25
|
+
|
|
26
|
+
// Visit all pages in a heap; returns `false` if break was called.
|
|
27
|
+
static bool mi_heap_visit_pages(mi_heap_t* heap, heap_page_visitor_fun* fn, void* arg1, void* arg2)
|
|
28
|
+
{
|
|
29
|
+
if (heap==NULL || heap->page_count==0) return 0;
|
|
30
|
+
|
|
31
|
+
// visit all pages
|
|
32
|
+
#if MI_DEBUG>1
|
|
33
|
+
size_t total = heap->page_count;
|
|
34
|
+
size_t count = 0;
|
|
35
|
+
#endif
|
|
36
|
+
|
|
37
|
+
for (size_t i = 0; i <= MI_BIN_FULL; i++) {
|
|
38
|
+
mi_page_queue_t* pq = &heap->pages[i];
|
|
39
|
+
mi_page_t* page = pq->first;
|
|
40
|
+
while(page != NULL) {
|
|
41
|
+
mi_page_t* next = page->next; // save next in case the page gets removed from the queue
|
|
42
|
+
mi_assert_internal(mi_page_heap(page) == heap);
|
|
43
|
+
#if MI_DEBUG>1
|
|
44
|
+
count++;
|
|
45
|
+
#endif
|
|
46
|
+
if (!fn(heap, pq, page, arg1, arg2)) return false;
|
|
47
|
+
page = next; // and continue
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
mi_assert_internal(count == total);
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
#if MI_DEBUG>=2
|
|
56
|
+
static bool mi_heap_page_is_valid(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t* page, void* arg1, void* arg2) {
|
|
57
|
+
MI_UNUSED(arg1);
|
|
58
|
+
MI_UNUSED(arg2);
|
|
59
|
+
MI_UNUSED(pq);
|
|
60
|
+
mi_assert_internal(mi_page_heap(page) == heap);
|
|
61
|
+
mi_segment_t* segment = _mi_page_segment(page);
|
|
62
|
+
mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == heap->thread_id);
|
|
63
|
+
mi_assert_expensive(_mi_page_is_valid(page));
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
#endif
|
|
67
|
+
#if MI_DEBUG>=3
|
|
68
|
+
static bool mi_heap_is_valid(mi_heap_t* heap) {
|
|
69
|
+
mi_assert_internal(heap!=NULL);
|
|
70
|
+
mi_heap_visit_pages(heap, &mi_heap_page_is_valid, NULL, NULL);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
#endif
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
/* -----------------------------------------------------------
|
|
79
|
+
"Collect" pages by migrating `local_free` and `thread_free`
|
|
80
|
+
lists and freeing empty pages. This is done when a thread
|
|
81
|
+
stops (and in that case abandons pages if there are still
|
|
82
|
+
blocks alive)
|
|
83
|
+
----------------------------------------------------------- */
|
|
84
|
+
|
|
85
|
+
typedef enum mi_collect_e {
|
|
86
|
+
MI_NORMAL,
|
|
87
|
+
MI_FORCE,
|
|
88
|
+
MI_ABANDON
|
|
89
|
+
} mi_collect_t;
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
static bool mi_heap_page_collect(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t* page, void* arg_collect, void* arg2 ) {
|
|
93
|
+
MI_UNUSED(arg2);
|
|
94
|
+
MI_UNUSED(heap);
|
|
95
|
+
mi_assert_internal(mi_heap_page_is_valid(heap, pq, page, NULL, NULL));
|
|
96
|
+
mi_collect_t collect = *((mi_collect_t*)arg_collect);
|
|
97
|
+
_mi_page_free_collect(page, collect >= MI_FORCE);
|
|
98
|
+
if (collect == MI_FORCE) {
|
|
99
|
+
// note: call before a potential `_mi_page_free` as the segment may be freed if this was the last used page in that segment.
|
|
100
|
+
mi_segment_t* segment = _mi_page_segment(page);
|
|
101
|
+
_mi_segment_collect(segment, true /* force? */);
|
|
102
|
+
}
|
|
103
|
+
if (mi_page_all_free(page)) {
|
|
104
|
+
// no more used blocks, free the page.
|
|
105
|
+
// note: this will free retired pages as well.
|
|
106
|
+
_mi_page_free(page, pq, collect >= MI_FORCE);
|
|
107
|
+
}
|
|
108
|
+
else if (collect == MI_ABANDON) {
|
|
109
|
+
// still used blocks but the thread is done; abandon the page
|
|
110
|
+
_mi_page_abandon(page, pq);
|
|
111
|
+
}
|
|
112
|
+
return true; // don't break
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
static bool mi_heap_page_never_delayed_free(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t* page, void* arg1, void* arg2) {
|
|
116
|
+
MI_UNUSED(arg1);
|
|
117
|
+
MI_UNUSED(arg2);
|
|
118
|
+
MI_UNUSED(heap);
|
|
119
|
+
MI_UNUSED(pq);
|
|
120
|
+
_mi_page_use_delayed_free(page, MI_NEVER_DELAYED_FREE, false);
|
|
121
|
+
return true; // don't break
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
static void mi_heap_collect_ex(mi_heap_t* heap, mi_collect_t collect)
|
|
125
|
+
{
|
|
126
|
+
if (heap==NULL || !mi_heap_is_initialized(heap)) return;
|
|
127
|
+
|
|
128
|
+
const bool force = (collect >= MI_FORCE);
|
|
129
|
+
_mi_deferred_free(heap, force);
|
|
130
|
+
|
|
131
|
+
// python/cpython#112532: we may be called from a thread that is not the owner of the heap
|
|
132
|
+
const bool is_main_thread = (_mi_is_main_thread() && heap->thread_id == _mi_thread_id());
|
|
133
|
+
|
|
134
|
+
// note: never reclaim on collect but leave it to threads that need storage to reclaim
|
|
135
|
+
const bool force_main =
|
|
136
|
+
#ifdef NDEBUG
|
|
137
|
+
collect == MI_FORCE
|
|
138
|
+
#else
|
|
139
|
+
collect >= MI_FORCE
|
|
140
|
+
#endif
|
|
141
|
+
&& is_main_thread && mi_heap_is_backing(heap) && !heap->no_reclaim;
|
|
142
|
+
|
|
143
|
+
if (force_main) {
|
|
144
|
+
// the main thread is abandoned (end-of-program), try to reclaim all abandoned segments.
|
|
145
|
+
// if all memory is freed by now, all segments should be freed.
|
|
146
|
+
// note: this only collects in the current subprocess
|
|
147
|
+
_mi_abandoned_reclaim_all(heap, &heap->tld->segments);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// if abandoning, mark all pages to no longer add to delayed_free
|
|
151
|
+
if (collect == MI_ABANDON) {
|
|
152
|
+
mi_heap_visit_pages(heap, &mi_heap_page_never_delayed_free, NULL, NULL);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// free all current thread delayed blocks.
|
|
156
|
+
// (if abandoning, after this there are no more thread-delayed references into the pages.)
|
|
157
|
+
_mi_heap_delayed_free_all(heap);
|
|
158
|
+
|
|
159
|
+
// collect retired pages
|
|
160
|
+
_mi_heap_collect_retired(heap, force);
|
|
161
|
+
|
|
162
|
+
// collect all pages owned by this thread
|
|
163
|
+
mi_heap_visit_pages(heap, &mi_heap_page_collect, &collect, NULL);
|
|
164
|
+
mi_assert_internal( collect != MI_ABANDON || mi_atomic_load_ptr_acquire(mi_block_t,&heap->thread_delayed_free) == NULL );
|
|
165
|
+
|
|
166
|
+
// collect abandoned segments (in particular, purge expired parts of segments in the abandoned segment list)
|
|
167
|
+
// note: forced purge can be quite expensive if many threads are created/destroyed so we do not force on abandonment
|
|
168
|
+
_mi_abandoned_collect(heap, collect == MI_FORCE /* force? */, &heap->tld->segments);
|
|
169
|
+
|
|
170
|
+
// if forced, collect thread data cache on program-exit (or shared library unload)
|
|
171
|
+
if (force && is_main_thread && mi_heap_is_backing(heap)) {
|
|
172
|
+
_mi_thread_data_collect(); // collect thread data cache
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// collect arenas (this is program wide so don't force purges on abandonment of threads)
|
|
176
|
+
_mi_arenas_collect(collect == MI_FORCE /* force purge? */);
|
|
177
|
+
|
|
178
|
+
// merge statistics
|
|
179
|
+
if (collect <= MI_FORCE) { _mi_stats_merge_thread(heap->tld); }
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
void _mi_heap_collect_abandon(mi_heap_t* heap) {
|
|
183
|
+
mi_heap_collect_ex(heap, MI_ABANDON);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
void mi_heap_collect(mi_heap_t* heap, bool force) mi_attr_noexcept {
|
|
187
|
+
mi_heap_collect_ex(heap, (force ? MI_FORCE : MI_NORMAL));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
void mi_collect(bool force) mi_attr_noexcept {
|
|
191
|
+
mi_heap_collect(mi_prim_get_default_heap(), force);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
/* -----------------------------------------------------------
|
|
196
|
+
Heap new
|
|
197
|
+
----------------------------------------------------------- */
|
|
198
|
+
|
|
199
|
+
mi_heap_t* mi_heap_get_default(void) {
|
|
200
|
+
mi_thread_init();
|
|
201
|
+
return mi_prim_get_default_heap();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
static bool mi_heap_is_default(const mi_heap_t* heap) {
|
|
205
|
+
return (heap == mi_prim_get_default_heap());
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
mi_heap_t* mi_heap_get_backing(void) {
|
|
210
|
+
mi_heap_t* heap = mi_heap_get_default();
|
|
211
|
+
mi_assert_internal(heap!=NULL);
|
|
212
|
+
mi_heap_t* bheap = heap->tld->heap_backing;
|
|
213
|
+
mi_assert_internal(bheap!=NULL);
|
|
214
|
+
mi_assert_internal(bheap->thread_id == _mi_thread_id());
|
|
215
|
+
return bheap;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
void _mi_heap_init(mi_heap_t* heap, mi_tld_t* tld, mi_arena_id_t arena_id, bool noreclaim, uint8_t tag) {
|
|
219
|
+
_mi_memcpy_aligned(heap, &_mi_heap_empty, sizeof(mi_heap_t));
|
|
220
|
+
heap->tld = tld;
|
|
221
|
+
heap->thread_id = _mi_thread_id();
|
|
222
|
+
heap->arena_id = arena_id;
|
|
223
|
+
heap->no_reclaim = noreclaim;
|
|
224
|
+
heap->tag = tag;
|
|
225
|
+
if (heap == tld->heap_backing) {
|
|
226
|
+
_mi_random_init(&heap->random);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
_mi_random_split(&tld->heap_backing->random, &heap->random);
|
|
230
|
+
}
|
|
231
|
+
heap->cookie = _mi_heap_random_next(heap) | 1;
|
|
232
|
+
heap->keys[0] = _mi_heap_random_next(heap);
|
|
233
|
+
heap->keys[1] = _mi_heap_random_next(heap);
|
|
234
|
+
_mi_heap_guarded_init(heap);
|
|
235
|
+
// push on the thread local heaps list
|
|
236
|
+
heap->next = heap->tld->heaps;
|
|
237
|
+
heap->tld->heaps = heap;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
mi_decl_nodiscard mi_heap_t* mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id) {
|
|
241
|
+
mi_heap_t* bheap = mi_heap_get_backing();
|
|
242
|
+
mi_heap_t* heap = mi_heap_malloc_tp(bheap, mi_heap_t); // todo: OS allocate in secure mode?
|
|
243
|
+
if (heap == NULL) return NULL;
|
|
244
|
+
mi_assert(heap_tag >= 0 && heap_tag < 256);
|
|
245
|
+
_mi_heap_init(heap, bheap->tld, arena_id, allow_destroy /* no reclaim? */, (uint8_t)heap_tag /* heap tag */);
|
|
246
|
+
return heap;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
mi_decl_nodiscard mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t arena_id) {
|
|
250
|
+
return mi_heap_new_ex(0 /* default heap tag */, false /* don't allow `mi_heap_destroy` */, arena_id);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
mi_decl_nodiscard mi_heap_t* mi_heap_new(void) {
|
|
254
|
+
// don't reclaim abandoned memory or otherwise destroy is unsafe
|
|
255
|
+
return mi_heap_new_ex(0 /* default heap tag */, true /* no reclaim */, _mi_arena_id_none());
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
bool _mi_heap_memid_is_suitable(mi_heap_t* heap, mi_memid_t memid) {
|
|
259
|
+
return _mi_arena_memid_is_suitable(memid, heap->arena_id);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
uintptr_t _mi_heap_random_next(mi_heap_t* heap) {
|
|
263
|
+
return _mi_random_next(&heap->random);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// zero out the page queues
|
|
267
|
+
static void mi_heap_reset_pages(mi_heap_t* heap) {
|
|
268
|
+
mi_assert_internal(heap != NULL);
|
|
269
|
+
mi_assert_internal(mi_heap_is_initialized(heap));
|
|
270
|
+
// TODO: copy full empty heap instead?
|
|
271
|
+
memset(&heap->pages_free_direct, 0, sizeof(heap->pages_free_direct));
|
|
272
|
+
_mi_memcpy_aligned(&heap->pages, &_mi_heap_empty.pages, sizeof(heap->pages));
|
|
273
|
+
heap->thread_delayed_free = NULL;
|
|
274
|
+
heap->page_count = 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// called from `mi_heap_destroy` and `mi_heap_delete` to free the internal heap resources.
|
|
278
|
+
static void mi_heap_free(mi_heap_t* heap) {
|
|
279
|
+
mi_assert(heap != NULL);
|
|
280
|
+
mi_assert_internal(mi_heap_is_initialized(heap));
|
|
281
|
+
if (heap==NULL || !mi_heap_is_initialized(heap)) return;
|
|
282
|
+
if (mi_heap_is_backing(heap)) return; // dont free the backing heap
|
|
283
|
+
|
|
284
|
+
// reset default
|
|
285
|
+
if (mi_heap_is_default(heap)) {
|
|
286
|
+
_mi_heap_set_default_direct(heap->tld->heap_backing);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// remove ourselves from the thread local heaps list
|
|
290
|
+
// linear search but we expect the number of heaps to be relatively small
|
|
291
|
+
mi_heap_t* prev = NULL;
|
|
292
|
+
mi_heap_t* curr = heap->tld->heaps;
|
|
293
|
+
while (curr != heap && curr != NULL) {
|
|
294
|
+
prev = curr;
|
|
295
|
+
curr = curr->next;
|
|
296
|
+
}
|
|
297
|
+
mi_assert_internal(curr == heap);
|
|
298
|
+
if (curr == heap) {
|
|
299
|
+
if (prev != NULL) { prev->next = heap->next; }
|
|
300
|
+
else { heap->tld->heaps = heap->next; }
|
|
301
|
+
}
|
|
302
|
+
mi_assert_internal(heap->tld->heaps != NULL);
|
|
303
|
+
|
|
304
|
+
// and free the used memory
|
|
305
|
+
mi_free(heap);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// return a heap on the same thread as `heap` specialized for the specified tag (if it exists)
|
|
309
|
+
mi_heap_t* _mi_heap_by_tag(mi_heap_t* heap, uint8_t tag) {
|
|
310
|
+
if (heap->tag == tag) {
|
|
311
|
+
return heap;
|
|
312
|
+
}
|
|
313
|
+
for (mi_heap_t *curr = heap->tld->heaps; curr != NULL; curr = curr->next) {
|
|
314
|
+
if (curr->tag == tag) {
|
|
315
|
+
return curr;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return NULL;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/* -----------------------------------------------------------
|
|
322
|
+
Heap destroy
|
|
323
|
+
----------------------------------------------------------- */
|
|
324
|
+
|
|
325
|
+
static bool _mi_heap_page_destroy(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t* page, void* arg1, void* arg2) {
|
|
326
|
+
MI_UNUSED(arg1);
|
|
327
|
+
MI_UNUSED(arg2);
|
|
328
|
+
MI_UNUSED(heap);
|
|
329
|
+
MI_UNUSED(pq);
|
|
330
|
+
|
|
331
|
+
// ensure no more thread_delayed_free will be added
|
|
332
|
+
_mi_page_use_delayed_free(page, MI_NEVER_DELAYED_FREE, false);
|
|
333
|
+
|
|
334
|
+
// stats
|
|
335
|
+
const size_t bsize = mi_page_block_size(page);
|
|
336
|
+
if (bsize > MI_MEDIUM_OBJ_SIZE_MAX) {
|
|
337
|
+
//if (bsize <= MI_LARGE_OBJ_SIZE_MAX) {
|
|
338
|
+
// mi_heap_stat_decrease(heap, malloc_large, bsize);
|
|
339
|
+
//}
|
|
340
|
+
//else
|
|
341
|
+
{
|
|
342
|
+
mi_heap_stat_decrease(heap, malloc_huge, bsize);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
#if (MI_STAT>0)
|
|
346
|
+
_mi_page_free_collect(page, false); // update used count
|
|
347
|
+
const size_t inuse = page->used;
|
|
348
|
+
if (bsize <= MI_LARGE_OBJ_SIZE_MAX) {
|
|
349
|
+
mi_heap_stat_decrease(heap, malloc_normal, bsize * inuse);
|
|
350
|
+
#if (MI_STAT>1)
|
|
351
|
+
mi_heap_stat_decrease(heap, malloc_bins[_mi_bin(bsize)], inuse);
|
|
352
|
+
#endif
|
|
353
|
+
}
|
|
354
|
+
// mi_heap_stat_decrease(heap, malloc_requested, bsize * inuse); // todo: off for aligned blocks...
|
|
355
|
+
#endif
|
|
356
|
+
|
|
357
|
+
/// pretend it is all free now
|
|
358
|
+
mi_assert_internal(mi_page_thread_free(page) == NULL);
|
|
359
|
+
page->used = 0;
|
|
360
|
+
|
|
361
|
+
// and free the page
|
|
362
|
+
// mi_page_free(page,false);
|
|
363
|
+
page->next = NULL;
|
|
364
|
+
page->prev = NULL;
|
|
365
|
+
_mi_segment_page_free(page,false /* no force? */, &heap->tld->segments);
|
|
366
|
+
|
|
367
|
+
return true; // keep going
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
void _mi_heap_destroy_pages(mi_heap_t* heap) {
|
|
371
|
+
mi_heap_visit_pages(heap, &_mi_heap_page_destroy, NULL, NULL);
|
|
372
|
+
mi_heap_reset_pages(heap);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
#if MI_TRACK_HEAP_DESTROY
|
|
376
|
+
static bool mi_cdecl mi_heap_track_block_free(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg) {
|
|
377
|
+
MI_UNUSED(heap); MI_UNUSED(area); MI_UNUSED(arg); MI_UNUSED(block_size);
|
|
378
|
+
mi_track_free_size(block,mi_usable_size(block));
|
|
379
|
+
return true;
|
|
380
|
+
}
|
|
381
|
+
#endif
|
|
382
|
+
|
|
383
|
+
void mi_heap_destroy(mi_heap_t* heap) {
|
|
384
|
+
mi_assert(heap != NULL);
|
|
385
|
+
mi_assert(mi_heap_is_initialized(heap));
|
|
386
|
+
mi_assert(heap->no_reclaim);
|
|
387
|
+
mi_assert_expensive(mi_heap_is_valid(heap));
|
|
388
|
+
if (heap==NULL || !mi_heap_is_initialized(heap)) return;
|
|
389
|
+
#if MI_GUARDED
|
|
390
|
+
// _mi_warning_message("'mi_heap_destroy' called but MI_GUARDED is enabled -- using `mi_heap_delete` instead (heap at %p)\n", heap);
|
|
391
|
+
mi_heap_delete(heap);
|
|
392
|
+
return;
|
|
393
|
+
#else
|
|
394
|
+
if (!heap->no_reclaim) {
|
|
395
|
+
_mi_warning_message("'mi_heap_destroy' called but ignored as the heap was not created with 'allow_destroy' (heap at %p)\n", heap);
|
|
396
|
+
// don't free in case it may contain reclaimed pages
|
|
397
|
+
mi_heap_delete(heap);
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
// track all blocks as freed
|
|
401
|
+
#if MI_TRACK_HEAP_DESTROY
|
|
402
|
+
mi_heap_visit_blocks(heap, true, mi_heap_track_block_free, NULL);
|
|
403
|
+
#endif
|
|
404
|
+
// free all pages
|
|
405
|
+
_mi_heap_destroy_pages(heap);
|
|
406
|
+
mi_heap_free(heap);
|
|
407
|
+
}
|
|
408
|
+
#endif
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// forcefully destroy all heaps in the current thread
|
|
412
|
+
void _mi_heap_unsafe_destroy_all(mi_heap_t* heap) {
|
|
413
|
+
mi_assert_internal(heap != NULL);
|
|
414
|
+
if (heap == NULL) return;
|
|
415
|
+
mi_heap_t* curr = heap->tld->heaps;
|
|
416
|
+
while (curr != NULL) {
|
|
417
|
+
mi_heap_t* next = curr->next;
|
|
418
|
+
if (curr->no_reclaim) {
|
|
419
|
+
mi_heap_destroy(curr);
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
_mi_heap_destroy_pages(curr);
|
|
423
|
+
}
|
|
424
|
+
curr = next;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/* -----------------------------------------------------------
|
|
429
|
+
Safe Heap delete
|
|
430
|
+
----------------------------------------------------------- */
|
|
431
|
+
|
|
432
|
+
// Transfer the pages from one heap to the other
|
|
433
|
+
static void mi_heap_absorb(mi_heap_t* heap, mi_heap_t* from) {
|
|
434
|
+
mi_assert_internal(heap!=NULL);
|
|
435
|
+
if (from==NULL || from->page_count == 0) return;
|
|
436
|
+
|
|
437
|
+
// reduce the size of the delayed frees
|
|
438
|
+
_mi_heap_delayed_free_partial(from);
|
|
439
|
+
|
|
440
|
+
// transfer all pages by appending the queues; this will set a new heap field
|
|
441
|
+
// so threads may do delayed frees in either heap for a while.
|
|
442
|
+
// note: appending waits for each page to not be in the `MI_DELAYED_FREEING` state
|
|
443
|
+
// so after this only the new heap will get delayed frees
|
|
444
|
+
for (size_t i = 0; i <= MI_BIN_FULL; i++) {
|
|
445
|
+
mi_page_queue_t* pq = &heap->pages[i];
|
|
446
|
+
mi_page_queue_t* append = &from->pages[i];
|
|
447
|
+
size_t pcount = _mi_page_queue_append(heap, pq, append);
|
|
448
|
+
heap->page_count += pcount;
|
|
449
|
+
from->page_count -= pcount;
|
|
450
|
+
}
|
|
451
|
+
mi_assert_internal(from->page_count == 0);
|
|
452
|
+
|
|
453
|
+
// and do outstanding delayed frees in the `from` heap
|
|
454
|
+
// note: be careful here as the `heap` field in all those pages no longer point to `from`,
|
|
455
|
+
// turns out to be ok as `_mi_heap_delayed_free` only visits the list and calls a
|
|
456
|
+
// the regular `_mi_free_delayed_block` which is safe.
|
|
457
|
+
_mi_heap_delayed_free_all(from);
|
|
458
|
+
#if !defined(_MSC_VER) || (_MSC_VER > 1900) // somehow the following line gives an error in VS2015, issue #353
|
|
459
|
+
mi_assert_internal(mi_atomic_load_ptr_relaxed(mi_block_t,&from->thread_delayed_free) == NULL);
|
|
460
|
+
#endif
|
|
461
|
+
|
|
462
|
+
// and reset the `from` heap
|
|
463
|
+
mi_heap_reset_pages(from);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// are two heaps compatible with respect to heap-tag, exclusive arena etc.
|
|
467
|
+
static bool mi_heaps_are_compatible(mi_heap_t* heap1, mi_heap_t* heap2) {
|
|
468
|
+
return (heap1->tag == heap2->tag && // store same kind of objects
|
|
469
|
+
heap1->arena_id == heap2->arena_id); // same arena preference
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Safe delete a heap without freeing any still allocated blocks in that heap.
|
|
473
|
+
void mi_heap_delete(mi_heap_t* heap)
|
|
474
|
+
{
|
|
475
|
+
mi_assert(heap != NULL);
|
|
476
|
+
mi_assert(mi_heap_is_initialized(heap));
|
|
477
|
+
mi_assert_expensive(mi_heap_is_valid(heap));
|
|
478
|
+
if (heap==NULL || !mi_heap_is_initialized(heap)) return;
|
|
479
|
+
|
|
480
|
+
mi_heap_t* bheap = heap->tld->heap_backing;
|
|
481
|
+
if (bheap != heap && mi_heaps_are_compatible(bheap,heap)) {
|
|
482
|
+
// transfer still used pages to the backing heap
|
|
483
|
+
mi_heap_absorb(bheap, heap);
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
// the backing heap abandons its pages
|
|
487
|
+
_mi_heap_collect_abandon(heap);
|
|
488
|
+
}
|
|
489
|
+
mi_assert_internal(heap->page_count==0);
|
|
490
|
+
mi_heap_free(heap);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
mi_heap_t* mi_heap_set_default(mi_heap_t* heap) {
|
|
494
|
+
mi_assert(heap != NULL);
|
|
495
|
+
mi_assert(mi_heap_is_initialized(heap));
|
|
496
|
+
if (heap==NULL || !mi_heap_is_initialized(heap)) return NULL;
|
|
497
|
+
mi_assert_expensive(mi_heap_is_valid(heap));
|
|
498
|
+
mi_heap_t* old = mi_prim_get_default_heap();
|
|
499
|
+
_mi_heap_set_default_direct(heap);
|
|
500
|
+
return old;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
/* -----------------------------------------------------------
|
|
507
|
+
Analysis
|
|
508
|
+
----------------------------------------------------------- */
|
|
509
|
+
|
|
510
|
+
// static since it is not thread safe to access heaps from other threads.
|
|
511
|
+
static mi_heap_t* mi_heap_of_block(const void* p) {
|
|
512
|
+
if (p == NULL) return NULL;
|
|
513
|
+
mi_segment_t* segment = _mi_ptr_segment(p);
|
|
514
|
+
bool valid = (_mi_ptr_cookie(segment) == segment->cookie);
|
|
515
|
+
mi_assert_internal(valid);
|
|
516
|
+
if mi_unlikely(!valid) return NULL;
|
|
517
|
+
return mi_page_heap(_mi_segment_page_of(segment,p));
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
bool mi_heap_contains_block(mi_heap_t* heap, const void* p) {
|
|
521
|
+
mi_assert(heap != NULL);
|
|
522
|
+
if (heap==NULL || !mi_heap_is_initialized(heap)) return false;
|
|
523
|
+
return (heap == mi_heap_of_block(p));
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
static bool mi_heap_page_check_owned(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t* page, void* p, void* vfound) {
|
|
528
|
+
MI_UNUSED(heap);
|
|
529
|
+
MI_UNUSED(pq);
|
|
530
|
+
bool* found = (bool*)vfound;
|
|
531
|
+
void* start = mi_page_start(page);
|
|
532
|
+
void* end = (uint8_t*)start + (page->capacity * mi_page_block_size(page));
|
|
533
|
+
*found = (p >= start && p < end);
|
|
534
|
+
return (!*found); // continue if not found
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
bool mi_heap_check_owned(mi_heap_t* heap, const void* p) {
|
|
538
|
+
mi_assert(heap != NULL);
|
|
539
|
+
if (heap==NULL || !mi_heap_is_initialized(heap)) return false;
|
|
540
|
+
if (((uintptr_t)p & (MI_INTPTR_SIZE - 1)) != 0) return false; // only aligned pointers
|
|
541
|
+
bool found = false;
|
|
542
|
+
mi_heap_visit_pages(heap, &mi_heap_page_check_owned, (void*)p, &found);
|
|
543
|
+
return found;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
bool mi_check_owned(const void* p) {
|
|
547
|
+
return mi_heap_check_owned(mi_prim_get_default_heap(), p);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/* -----------------------------------------------------------
|
|
551
|
+
Visit all heap blocks and areas
|
|
552
|
+
Todo: enable visiting abandoned pages, and
|
|
553
|
+
enable visiting all blocks of all heaps across threads
|
|
554
|
+
----------------------------------------------------------- */
|
|
555
|
+
|
|
556
|
+
void _mi_heap_area_init(mi_heap_area_t* area, mi_page_t* page) {
|
|
557
|
+
const size_t bsize = mi_page_block_size(page);
|
|
558
|
+
const size_t ubsize = mi_page_usable_block_size(page);
|
|
559
|
+
area->reserved = page->reserved * bsize;
|
|
560
|
+
area->committed = page->capacity * bsize;
|
|
561
|
+
area->blocks = mi_page_start(page);
|
|
562
|
+
area->used = page->used; // number of blocks in use (#553)
|
|
563
|
+
area->block_size = ubsize;
|
|
564
|
+
area->full_block_size = bsize;
|
|
565
|
+
area->heap_tag = page->heap_tag;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
static void mi_get_fast_divisor(size_t divisor, uint64_t* magic, size_t* shift) {
|
|
570
|
+
mi_assert_internal(divisor > 0 && divisor <= UINT32_MAX);
|
|
571
|
+
*shift = MI_SIZE_BITS - mi_clz(divisor - 1);
|
|
572
|
+
*magic = ((((uint64_t)1 << 32) * (((uint64_t)1 << *shift) - divisor)) / divisor + 1);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
static size_t mi_fast_divide(size_t n, uint64_t magic, size_t shift) {
|
|
576
|
+
mi_assert_internal(n <= UINT32_MAX);
|
|
577
|
+
const uint64_t hi = ((uint64_t)n * magic) >> 32;
|
|
578
|
+
return (size_t)((hi + n) >> shift);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
bool _mi_heap_area_visit_blocks(const mi_heap_area_t* area, mi_page_t* page, mi_block_visit_fun* visitor, void* arg) {
|
|
582
|
+
mi_assert(area != NULL);
|
|
583
|
+
if (area==NULL) return true;
|
|
584
|
+
mi_assert(page != NULL);
|
|
585
|
+
if (page == NULL) return true;
|
|
586
|
+
|
|
587
|
+
_mi_page_free_collect(page,true); // collect both thread_delayed and local_free
|
|
588
|
+
mi_assert_internal(page->local_free == NULL);
|
|
589
|
+
if (page->used == 0) return true;
|
|
590
|
+
|
|
591
|
+
size_t psize;
|
|
592
|
+
uint8_t* const pstart = _mi_segment_page_start(_mi_page_segment(page), page, &psize);
|
|
593
|
+
mi_heap_t* const heap = mi_page_heap(page);
|
|
594
|
+
const size_t bsize = mi_page_block_size(page);
|
|
595
|
+
const size_t ubsize = mi_page_usable_block_size(page); // without padding
|
|
596
|
+
|
|
597
|
+
// optimize page with one block
|
|
598
|
+
if (page->capacity == 1) {
|
|
599
|
+
mi_assert_internal(page->used == 1 && page->free == NULL);
|
|
600
|
+
return visitor(mi_page_heap(page), area, pstart, ubsize, arg);
|
|
601
|
+
}
|
|
602
|
+
mi_assert(bsize <= UINT32_MAX);
|
|
603
|
+
|
|
604
|
+
// optimize full pages
|
|
605
|
+
if (page->used == page->capacity) {
|
|
606
|
+
uint8_t* block = pstart;
|
|
607
|
+
for (size_t i = 0; i < page->capacity; i++) {
|
|
608
|
+
if (!visitor(heap, area, block, ubsize, arg)) return false;
|
|
609
|
+
block += bsize;
|
|
610
|
+
}
|
|
611
|
+
return true;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// create a bitmap of free blocks.
|
|
615
|
+
#define MI_MAX_BLOCKS (MI_SMALL_PAGE_SIZE / sizeof(void*))
|
|
616
|
+
uintptr_t free_map[MI_MAX_BLOCKS / MI_INTPTR_BITS];
|
|
617
|
+
const uintptr_t bmapsize = _mi_divide_up(page->capacity, MI_INTPTR_BITS);
|
|
618
|
+
memset(free_map, 0, bmapsize * sizeof(intptr_t));
|
|
619
|
+
if (page->capacity % MI_INTPTR_BITS != 0) {
|
|
620
|
+
// mark left-over bits at the end as free
|
|
621
|
+
size_t shift = (page->capacity % MI_INTPTR_BITS);
|
|
622
|
+
uintptr_t mask = (UINTPTR_MAX << shift);
|
|
623
|
+
free_map[bmapsize - 1] = mask;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// fast repeated division by the block size
|
|
627
|
+
uint64_t magic;
|
|
628
|
+
size_t shift;
|
|
629
|
+
mi_get_fast_divisor(bsize, &magic, &shift);
|
|
630
|
+
|
|
631
|
+
#if MI_DEBUG>1
|
|
632
|
+
size_t free_count = 0;
|
|
633
|
+
#endif
|
|
634
|
+
for (mi_block_t* block = page->free; block != NULL; block = mi_block_next(page, block)) {
|
|
635
|
+
#if MI_DEBUG>1
|
|
636
|
+
free_count++;
|
|
637
|
+
#endif
|
|
638
|
+
mi_assert_internal((uint8_t*)block >= pstart && (uint8_t*)block < (pstart + psize));
|
|
639
|
+
size_t offset = (uint8_t*)block - pstart;
|
|
640
|
+
mi_assert_internal(offset % bsize == 0);
|
|
641
|
+
mi_assert_internal(offset <= UINT32_MAX);
|
|
642
|
+
size_t blockidx = mi_fast_divide(offset, magic, shift);
|
|
643
|
+
mi_assert_internal(blockidx == offset / bsize);
|
|
644
|
+
mi_assert_internal(blockidx < MI_MAX_BLOCKS);
|
|
645
|
+
size_t bitidx = (blockidx / MI_INTPTR_BITS);
|
|
646
|
+
size_t bit = blockidx - (bitidx * MI_INTPTR_BITS);
|
|
647
|
+
free_map[bitidx] |= ((uintptr_t)1 << bit);
|
|
648
|
+
}
|
|
649
|
+
mi_assert_internal(page->capacity == (free_count + page->used));
|
|
650
|
+
|
|
651
|
+
// walk through all blocks skipping the free ones
|
|
652
|
+
#if MI_DEBUG>1
|
|
653
|
+
size_t used_count = 0;
|
|
654
|
+
#endif
|
|
655
|
+
uint8_t* block = pstart;
|
|
656
|
+
for (size_t i = 0; i < bmapsize; i++) {
|
|
657
|
+
if (free_map[i] == 0) {
|
|
658
|
+
// every block is in use
|
|
659
|
+
for (size_t j = 0; j < MI_INTPTR_BITS; j++) {
|
|
660
|
+
#if MI_DEBUG>1
|
|
661
|
+
used_count++;
|
|
662
|
+
#endif
|
|
663
|
+
if (!visitor(heap, area, block, ubsize, arg)) return false;
|
|
664
|
+
block += bsize;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
else {
|
|
668
|
+
// visit the used blocks in the mask
|
|
669
|
+
uintptr_t m = ~free_map[i];
|
|
670
|
+
while (m != 0) {
|
|
671
|
+
#if MI_DEBUG>1
|
|
672
|
+
used_count++;
|
|
673
|
+
#endif
|
|
674
|
+
size_t bitidx = mi_ctz(m);
|
|
675
|
+
if (!visitor(heap, area, block + (bitidx * bsize), ubsize, arg)) return false;
|
|
676
|
+
m &= m - 1; // clear least significant bit
|
|
677
|
+
}
|
|
678
|
+
block += bsize * MI_INTPTR_BITS;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
mi_assert_internal(page->used == used_count);
|
|
682
|
+
return true;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
// Separate struct to keep `mi_page_t` out of the public interface
|
|
688
|
+
typedef struct mi_heap_area_ex_s {
|
|
689
|
+
mi_heap_area_t area;
|
|
690
|
+
mi_page_t* page;
|
|
691
|
+
} mi_heap_area_ex_t;
|
|
692
|
+
|
|
693
|
+
typedef bool (mi_heap_area_visit_fun)(const mi_heap_t* heap, const mi_heap_area_ex_t* area, void* arg);
|
|
694
|
+
|
|
695
|
+
static bool mi_heap_visit_areas_page(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t* page, void* vfun, void* arg) {
|
|
696
|
+
MI_UNUSED(heap);
|
|
697
|
+
MI_UNUSED(pq);
|
|
698
|
+
mi_heap_area_visit_fun* fun = (mi_heap_area_visit_fun*)vfun;
|
|
699
|
+
mi_heap_area_ex_t xarea;
|
|
700
|
+
xarea.page = page;
|
|
701
|
+
_mi_heap_area_init(&xarea.area, page);
|
|
702
|
+
return fun(heap, &xarea, arg);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// Visit all heap pages as areas
|
|
706
|
+
static bool mi_heap_visit_areas(const mi_heap_t* heap, mi_heap_area_visit_fun* visitor, void* arg) {
|
|
707
|
+
if (visitor == NULL) return false;
|
|
708
|
+
return mi_heap_visit_pages((mi_heap_t*)heap, &mi_heap_visit_areas_page, (void*)(visitor), arg); // note: function pointer to void* :-{
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// Just to pass arguments
|
|
712
|
+
typedef struct mi_visit_blocks_args_s {
|
|
713
|
+
bool visit_blocks;
|
|
714
|
+
mi_block_visit_fun* visitor;
|
|
715
|
+
void* arg;
|
|
716
|
+
} mi_visit_blocks_args_t;
|
|
717
|
+
|
|
718
|
+
static bool mi_heap_area_visitor(const mi_heap_t* heap, const mi_heap_area_ex_t* xarea, void* arg) {
|
|
719
|
+
mi_visit_blocks_args_t* args = (mi_visit_blocks_args_t*)arg;
|
|
720
|
+
if (!args->visitor(heap, &xarea->area, NULL, xarea->area.block_size, args->arg)) return false;
|
|
721
|
+
if (args->visit_blocks) {
|
|
722
|
+
return _mi_heap_area_visit_blocks(&xarea->area, xarea->page, args->visitor, args->arg);
|
|
723
|
+
}
|
|
724
|
+
else {
|
|
725
|
+
return true;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// Visit all blocks in a heap
|
|
730
|
+
bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) {
|
|
731
|
+
mi_visit_blocks_args_t args = { visit_blocks, visitor, arg };
|
|
732
|
+
return mi_heap_visit_areas(heap, &mi_heap_area_visitor, &args);
|
|
733
|
+
}
|