From 1b5c405d0b0e0675f9f0313a69fe2b2cc5e479bd Mon Sep 17 00:00:00 2001 From: caipengxiang <291458254@qq.com> Date: Wed, 2 Nov 2022 16:41:26 +0800 Subject: [PATCH 01/26] move src and dst to next buffer position (#47229) Co-authored-by: Gabriel Baraldi (cherry picked from commit 9e1dac045eb332d59617b59e66c4e86fe2eb4766) --- src/datatype.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/datatype.c b/src/datatype.c index eca51949cd40e..00eb3bd08feab 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -1468,6 +1468,7 @@ static inline void memassign_safe(int hasptr, jl_value_t *parent, char *dst, con memmove_refs((void**)dst, (void**)src, nptr); jl_gc_multi_wb(parent, src); src = (jl_value_t*)((char*)src + nptr * sizeof(void*)); + dst = dst + nptr * sizeof(void*); nb -= nptr * sizeof(void*); } else { From 9d86e4fefb4558636d9947bbde2372c84f145ecf Mon Sep 17 00:00:00 2001 From: Nikitas Rontsis Date: Fri, 4 Nov 2022 09:40:10 +0000 Subject: [PATCH 02/26] CircleCI caching: allow ftime to be ceil(ftime_req) in Base.stale_cachefile (#47433) * CircleCI caching: allow ftime to be ceil(ftime_req) in Base.stale_cachefile It appears that [caching functionalities](https://circleci.com/docs/caching/) provided by CircleCi, a leading CI/CD provider, can truncate timestamps to full seconds, resulting in re-compilations as below: ``` Rejecting stale cache file /root/.julia/compiled/v1.8/ComponentArrays/cYHSD_3rQji.ji (mtime 1.6673960929277816e9) because file /root/.julia/packages/ComponentArrays/YyD7i/src/ComponentArrays.jl ``` This PR relaxes the `is_stale` check to be robust against rounding-to-second timestamp mutations. I can provide a minimal CircleCI configuration file to reproduce if this is helpful. (cherry picked from commit bf92e836d3d16876ff48016f55541e4a38ea33ee) --- base/loading.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/base/loading.jl b/base/loading.jl index bbb111c955ecf..e4e990df6990a 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -2147,6 +2147,7 @@ end ftime = mtime(f) is_stale = ( ftime != ftime_req ) && ( ftime != floor(ftime_req) ) && # Issue #13606, PR #13613: compensate for Docker images rounding mtimes + ( ftime != ceil(ftime_req) ) && # PR: #47433 Compensate for CirceCI's truncating of timestamps in its caching ( ftime != trunc(ftime_req, digits=6) ) && # Issue #20837, PR #20840: compensate for GlusterFS truncating mtimes to microseconds ( ftime != 1.0 ) && # PR #43090: provide compatibility with Nix mtime. !( 0 < (ftime_req - ftime) < 1e-6 ) # PR #45552: Compensate for Windows tar giving mtimes that may be incorrect by up to one microsecond From 90ee1b518bdb871caf51362d9b09529a4409e4a1 Mon Sep 17 00:00:00 2001 From: Dilum Aluthge Date: Sat, 5 Nov 2022 21:54:53 -0400 Subject: [PATCH 03/26] Delete `.github/workflows/rerun_failed.yml` (#47460) (cherry picked from commit ebc97ba3036343087b960e61f73e739a06f5ce11) --- .github/workflows/rerun_failed.yml | 92 ------------------------------ 1 file changed, 92 deletions(-) delete mode 100644 .github/workflows/rerun_failed.yml diff --git a/.github/workflows/rerun_failed.yml b/.github/workflows/rerun_failed.yml deleted file mode 100644 index 7d022920658a9..0000000000000 --- a/.github/workflows/rerun_failed.yml +++ /dev/null @@ -1,92 +0,0 @@ -# Please ping @DilumAluthge when making any changes to this file. - -# Here are some steps that we take in this workflow file for security reasons: -# 1. We do not checkout any code. -# 2. We only run actions that are defined in a repository in the `JuliaLang` GitHub organization. -# 3. We do not give the `GITHUB_TOKEN` any permissions. -# 4. We only give the Buildkite API token (`BUILDKITE_API_TOKEN_RETRY`) the minimum necessary -# set of permissions. - -# Important note to Buildkite maintainers: -# In order to make this work, you need to tell Buildkite that it should NOT create a brand-new -# build when someone closes and reopens a pull request. To do so: -# 1. Go to the relevant pipeline (e.g. https://buildkite.com/julialang/julia-master). -# 2. Click on the "Pipeline Settings" button. -# 3. In the left sidebar, under "Pipeline Settings", click on "GitHub". -# 4. In the "GitHub Settings", under "Build Pull Requests", make sure that the "Skip pull -# request builds for existing commits" checkbox is checked. This is the setting that tells -# Buildkite that it should NOT create a brand-new build when someone closes and reopens a -# pull request. -# 5. At the bottom of the page, click the "Save GitHub Settings" button. - -name: Rerun Failed Buildkite Jobs - -# There are two ways that a user can rerun the failed Buildkite jobs: -# 1. Close and reopen the pull request. -# In order to use this approach, the user must be in one of the following three categories: -# (i) Author of the pull request -# (ii) Commit permissions -# (iii) Triage permissions -# 2. Post a comment on the pull request with exactly the following contents: /buildkite rerun failed -# In order to use this approach, the user must be in the following category: -# - A member of the JuliaLang GitHub organization (the membership must be publicized) - -on: - # When using the `pull_request_target` event, all PRs will get access to secret environment - # variables (such as the `BUILDKITE_API_TOKEN_RETRY` secret environment variable), even if - # the PR is from a fork. Therefore, for security reasons, we do not checkout any code in - # this workflow. - pull_request_target: - types: [ reopened ] - issue_comment: - types: [ created ] - -# We do not give the `GITHUB_TOKEN` any permissions. -# Therefore, the `GITHUB_TOKEN` only has the same access as any member of the public. -permissions: - contents: none - -jobs: - rerun-failed-buildkite-jobs: - name: Rerun Failed Buildkite Jobs - runs-on: ubuntu-latest - if: (github.repository == 'JuliaLang/julia') && ((github.event_name == 'pull_request_target' && github.event.action == 'reopened') || (github.event_name == 'issue_comment' && github.event.issue.pull_request && github.event.comment.body == '/buildkite rerun failed')) - steps: - # For security reasons, we do not checkout any code in this workflow. - - name: Check organization membership - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - if [[ "${{ github.event_name }}" == "pull_request_target" ]]; then - if [[ "${{ github.event.action }}" == "reopened" ]]; then - echo "This is a \"reopened\" event, so we do not need to check the user's organization membership." - echo "GOOD_TO_PROCEED=yes" >> ${GITHUB_ENV:?} - echo "PULL_REQUEST_NUMBER=${{ github.event.number }}" >> ${GITHUB_ENV:?} - else - echo "ERROR: The github.event_name is \"pull_request_target\", but the github.event.action is not \"reopened\"." - exit 1 - fi - else - curl -H "Authorization: token ${GITHUB_TOKEN:?}" "https://api.github.com/users/${{ github.event.sender.login }}" - curl -H "Authorization: token ${GITHUB_TOKEN:?}" "https://api.github.com/users/${{ github.event.sender.login }}/orgs" - export USER_IS_ORGANIZATION_MEMBER=`curl -H "Authorization: token ${GITHUB_TOKEN:?}" "https://api.github.com/users/${{ github.event.sender.login }}/orgs" | jq '[.[] | .login] | index("JuliaLang") != null' | tr -s ' '` - if [[ "${USER_IS_ORGANIZATION_MEMBER:?}" == "true" ]]; then - echo "The \"${{ github.event.sender.login }}\" user is a public member of the JuliaLang organization." - echo "GOOD_TO_PROCEED=yes" >> ${GITHUB_ENV:?} - echo "PULL_REQUEST_NUMBER=${{ github.event.issue.number }}" >> ${GITHUB_ENV:?} - else - echo "ERROR: the \"${{ github.event.sender.login }}\" user is NOT a public member of the JuliaLang organization." - echo "If you are a member, please make sure that you have publicized your membership." - exit 1 - fi - fi - - run: | - echo "GOOD_TO_PROCEED: ${{ env.GOOD_TO_PROCEED }}" - echo "PULL_REQUEST_NUMBER: ${{ env.PULL_REQUEST_NUMBER }}" - - uses: JuliaLang/buildkite-rerun-failed@057f6f2d37aa29a57b7679fd2af0df1d9f9188b4 - if: env.GOOD_TO_PROCEED == 'yes' - with: - buildkite_api_token: ${{ secrets.BUILDKITE_API_TOKEN_RETRY }} - buildkite_organization_slug: 'julialang' - buildkite_pipeline_slug: 'julia-master' - pr_number: ${{ env.PULL_REQUEST_NUMBER }} From b66e38c31dfdefe3ec68fb8f5d085070bfc79058 Mon Sep 17 00:00:00 2001 From: apaz Date: Mon, 7 Nov 2022 23:18:57 -0600 Subject: [PATCH 04/26] Removed attributes from arguments to gc_preserve_begin (#47482) LLVM adds the nonnull attribute on its own, which makes the verifier fail. Fixes #47245 (cherry picked from commit bc39fd1c5bc248e0c796f61a39c48dc03e96d2d5) --- src/llvm-alloc-opt.cpp | 2 +- test/llvmpasses/alloc-opt-pass.jl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/llvm-alloc-opt.cpp b/src/llvm-alloc-opt.cpp index d9ddc7a15b9fb..06d2ad3c4bcfe 100644 --- a/src/llvm-alloc-opt.cpp +++ b/src/llvm-alloc-opt.cpp @@ -46,6 +46,7 @@ static void removeGCPreserve(CallInst *call, Instruction *val) { auto replace = Constant::getNullValue(val->getType()); call->replaceUsesOfWith(val, replace); + call->setAttributes(AttributeList()); for (auto &arg: call->args()) { if (!isa(arg.get())) { return; @@ -1079,7 +1080,6 @@ void Optimizer::splitOnStack(CallInst *orig_inst) } auto new_call = builder.CreateCall(pass.gc_preserve_begin_func, operands); new_call->takeName(call); - new_call->setAttributes(call->getAttributes()); call->replaceAllUsesWith(new_call); call->eraseFromParent(); return; diff --git a/test/llvmpasses/alloc-opt-pass.jl b/test/llvmpasses/alloc-opt-pass.jl index 3f2b09ebabb4a..97306b9a98483 100644 --- a/test/llvmpasses/alloc-opt-pass.jl +++ b/test/llvmpasses/alloc-opt-pass.jl @@ -31,7 +31,7 @@ define void @preserve_branches(i8* %fptr, i1 %b, i1 %b2) { L1: %v = call noalias {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, $isz 8, {} addrspace(10)* @tag) - %tok = call token (...) @llvm.julia.gc_preserve_begin({} addrspace(10)* %v) + %tok = call token (...) @llvm.julia.gc_preserve_begin({} addrspace(10)* nonnull %v) call void @external_function() br i1 %b2, label %L2, label %L3 @@ -67,7 +67,7 @@ define void @preserve_branches2(i8* %fptr, i1 %b, i1 %b2) { L1: %v = call noalias {} addrspace(10)* @julia.gc_alloc_obj(i8* %ptls_i8, $isz 8, {} addrspace(10)* @tag) - %tok = call token (...) @llvm.julia.gc_preserve_begin({} addrspace(10)* %v, {} addrspace(10)* %v2) + %tok = call token (...) @llvm.julia.gc_preserve_begin({} addrspace(10)* %v, {} addrspace(10)* nonnull %v2) call void @external_function() br i1 %b2, label %L2, label %L3 From 1387750d002fe68ddcc938938ba5e5ef48e3d46c Mon Sep 17 00:00:00 2001 From: Dilum Aluthge Date: Thu, 17 Nov 2022 09:02:22 -0500 Subject: [PATCH 05/26] Delete `.github/workflows/statuses.yml` (#47562) --- .github/workflows/statuses.yml | 63 ---------------------------------- 1 file changed, 63 deletions(-) delete mode 100644 .github/workflows/statuses.yml diff --git a/.github/workflows/statuses.yml b/.github/workflows/statuses.yml deleted file mode 100644 index 7116a766ad8df..0000000000000 --- a/.github/workflows/statuses.yml +++ /dev/null @@ -1,63 +0,0 @@ -# Please ping @DilumAluthge when making any changes to this file. - -# This is just a short-term solution until we have migrated all of CI to Buildkite. -# -# 1. TODO: delete this file once we have migrated all of CI to Buildkite. - -# Here are some steps that we take in this workflow file for security reasons: -# 1. We do not checkout any code. -# 2. We do not run any external actions. -# 3. We only give the `GITHUB_TOKEN` the minimum necessary set of permissions. - -name: Create Buildbot Statuses - -on: - push: - branches: - - 'master' - - 'release-*' - # When using the `pull_request_target` event, all PRs will get a `GITHUB_TOKEN` that has - # write permissions, even if the PR is from a fork. - # Therefore, for security reasons, we do not checkout any code in this workflow. - pull_request_target: - types: [opened, synchronize] - branches: - - 'master' - - 'release-*' - -# These are the permissions for the `GITHUB_TOKEN`. -# We should only give the token the minimum necessary set of permissions. -permissions: - statuses: write - -jobs: - create-buildbot-statuses: - name: Create Buildbot Statuses - runs-on: ubuntu-latest - if: github.repository == 'JuliaLang/julia' - steps: - # For security reasons, we do not checkout any code in this workflow. - - run: echo "SHA=${{ github.event.pull_request.head.sha }}" >> $GITHUB_ENV - if: github.event_name == 'pull_request_target' - - run: echo "SHA=${{ github.sha }}" >> $GITHUB_ENV - if: github.event_name != 'pull_request_target' - - run: echo "The SHA is ${{ env.SHA }}" - - # As we incrementally migrate individual jobs from Buildbot to Buildkite, we should - # remove them from the `context_list`. - - run: | - declare -a CONTEXT_LIST=( - "buildbot/tester_freebsd64" - ) - for CONTEXT in "${CONTEXT_LIST[@]}" - do - curl \ - -X POST \ - -H "Authorization: token $GITHUB_TOKEN" \ - -H "Accept: application/vnd.github.v3+json" \ - -d "{\"context\": \"$CONTEXT\", \"state\": \"$STATE\"}" \ - https://api.github.com/repos/JuliaLang/julia/statuses/${{ env.SHA }} - done - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - STATE: "pending" From c8b72e2bf49046e8daca64214765694377277947 Mon Sep 17 00:00:00 2001 From: Tyler Thomas <36181311+tylerjthomas9@users.noreply.github.com> Date: Tue, 22 Nov 2022 08:38:16 -0700 Subject: [PATCH 06/26] [CompilerSupportLibraries_jll] Upgrade to libraries from GCC 12 (#47544) --- Make.inc | 6 + base/Makefile | 10 +- deps/checksums/compilersupportlibraries | 184 +++++++++--------- deps/csl.mk | 2 +- .../CompilerSupportLibraries_jll/Project.toml | 2 +- .../src/CompilerSupportLibraries_jll.jl | 2 +- 6 files changed, 110 insertions(+), 96 deletions(-) diff --git a/Make.inc b/Make.inc index dbf723f7ec4ee..41602f354c416 100644 --- a/Make.inc +++ b/Make.inc @@ -1469,13 +1469,19 @@ else LIBGCC_NAME := libgcc_s_seh-1.$(SHLIB_EXT) endif endif +# On macOS, libgcc_s has soversion 1.1 always on aarch64 and only for GCC 12+ +# (-> libgfortran 5) on x86_64 ifeq ($(OS),Darwin) ifeq ($(ARCH),aarch64) LIBGCC_NAME := libgcc_s.1.1.$(SHLIB_EXT) else +ifeq ($(LIBGFORTRAN_VERSION),5) +LIBGCC_NAME := libgcc_s.1.1.$(SHLIB_EXT) +else LIBGCC_NAME := libgcc_s.1.$(SHLIB_EXT) endif endif +endif ifneq ($(findstring $(OS),Linux FreeBSD),) LIBGCC_NAME := libgcc_s.$(SHLIB_EXT).1 endif diff --git a/base/Makefile b/base/Makefile index 23a9c4011131e..0f593f33b860f 100644 --- a/base/Makefile +++ b/base/Makefile @@ -206,11 +206,19 @@ else ifneq ($(USE_SYSTEM_OPENLIBM),0) $(eval $(call symlink_system_library,OPENLIBM,$(LIBMNAME))) endif -ifeq ($(APPLE_ARCH),arm64) +# On macOS, libgcc_s has soversion 1.1 always on aarch64 and only for GCC 12+ +# (-> libgfortran 5) on x86_64 +ifeq ($(OS),Darwin) +ifeq ($(ARCH),aarch64) +$(eval $(call symlink_system_library,CSL,libgcc_s,1.1)) +else +ifeq ($(LIBGFORTRAN_VERSION),5) $(eval $(call symlink_system_library,CSL,libgcc_s,1.1)) else $(eval $(call symlink_system_library,CSL,libgcc_s,1)) endif +endif +endif ifneq (,$(LIBGFORTRAN_VERSION)) $(eval $(call symlink_system_library,CSL,libgfortran,$(LIBGFORTRAN_VERSION))) endif diff --git a/deps/checksums/compilersupportlibraries b/deps/checksums/compilersupportlibraries index 86250fdc63390..721ad2e8a8759 100644 --- a/deps/checksums/compilersupportlibraries +++ b/deps/checksums/compilersupportlibraries @@ -1,92 +1,92 @@ -CompilerSupportLibraries.v0.5.2+0.aarch64-apple-darwin-libgfortran5.tar.gz/md5/e0651fbefd39d405ec97d7530f2887d7 -CompilerSupportLibraries.v0.5.2+0.aarch64-apple-darwin-libgfortran5.tar.gz/sha512/0a067b7e37d98a4c96dd1400b8c1a07c82cc223d11a93a0ee2455c3b55b394eee0cb251e26206495453f2cf8866822fb586ffe105f44e3380fa949adffe8b83c -CompilerSupportLibraries.v0.5.2+0.aarch64-linux-gnu-libgfortran3.tar.gz/md5/1f4a5e98cd88a08029326ca5e9d47e9c -CompilerSupportLibraries.v0.5.2+0.aarch64-linux-gnu-libgfortran3.tar.gz/sha512/696f359746de592d4e30dc9ad19d5e07ebc1e6635e1f082e249747c42338ef04ce885fee5ad5915ec39fa2866af4265bb6ef580c75874c091a15b64d02626123 -CompilerSupportLibraries.v0.5.2+0.aarch64-linux-gnu-libgfortran4.tar.gz/md5/8285fd34164fac0410fcec6bb9d8b8e4 -CompilerSupportLibraries.v0.5.2+0.aarch64-linux-gnu-libgfortran4.tar.gz/sha512/df0869d357326c803d8ff33c9734f01457d877e80c4af33745d4ca016144eb0c52fba7aad7e1098eecde3fc4cf41ed971638b4b6f901c7306a2072e8c14c3513 -CompilerSupportLibraries.v0.5.2+0.aarch64-linux-gnu-libgfortran5.tar.gz/md5/82add6093bda667442236c04d84b6934 -CompilerSupportLibraries.v0.5.2+0.aarch64-linux-gnu-libgfortran5.tar.gz/sha512/81538d75950cdf931f9aaa932d1f9cf40998bc256924c3231e984179f6a5c3eca0f7e1ba315b21f2add3bf9376e3a45ee59ccd8d9f6d765105e05da25bf65cfc -CompilerSupportLibraries.v0.5.2+0.aarch64-linux-musl-libgfortran3.tar.gz/md5/ee0d6a9f0a1372e36a02a95b6c07aefc -CompilerSupportLibraries.v0.5.2+0.aarch64-linux-musl-libgfortran3.tar.gz/sha512/f248e57249af88520f9c7ac32dba45ca03e5904606b4edb682ea514c31a9a775198d02f0892e79124326e184d7906b7a13b0e4f3e7721352b8105cdfa72f89ed -CompilerSupportLibraries.v0.5.2+0.aarch64-linux-musl-libgfortran4.tar.gz/md5/dddc8f7a9be9f07e9738e2a027fe8a0c -CompilerSupportLibraries.v0.5.2+0.aarch64-linux-musl-libgfortran4.tar.gz/sha512/36f9b94f470d451b9c3c2429026292463434427625563240467f50374624a69fbca7ddcb0678937a58d22d32a8157571d3e201c47cc9a2484d1d75d4c0f77ebc -CompilerSupportLibraries.v0.5.2+0.aarch64-linux-musl-libgfortran5.tar.gz/md5/12b7eb088023eaf9583ffa6f9f0e18ac -CompilerSupportLibraries.v0.5.2+0.aarch64-linux-musl-libgfortran5.tar.gz/sha512/a5f5a6053e63ea1fb0185a0c3a7752a938373da847dffb872c1227ed3a0a80f2de1e4394baaaeeb8e0d8f2a4da123433896742cfdca6f94343bd4d0ab3578c65 -CompilerSupportLibraries.v0.5.2+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/md5/e5e6918571981e4cfa5a2951e59f2df7 -CompilerSupportLibraries.v0.5.2+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/sha512/5d7b0f4f55b6726ae7317edb170cafb6a2c4563b0f4a90c619da95c120edd8fdce118bbd1e7168110f75cc899b857472fd524a396deb6d9f2552f53c861faeb7 -CompilerSupportLibraries.v0.5.2+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/md5/7ae11706e9c6c043ad771f2700d06591 -CompilerSupportLibraries.v0.5.2+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/sha512/4f2f01aed00a58f4393cfd4608df1a6df6c9bff6e352a02a2b9af13f14a4436611769d64d082d3b151ba23d3d905ae2700bf469b9858249757ad7b5aae716d6a -CompilerSupportLibraries.v0.5.2+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/md5/e922dad7dad1d5f80cc154a6ddb6de35 -CompilerSupportLibraries.v0.5.2+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/sha512/3fabbcedbbc4abfe1e0c01c387bbe2537105937674877122b5b66d6015944a58f547106da1e185c1434de0c1883d356f8dc52968f075a00c6a8a52edaaf88957 -CompilerSupportLibraries.v0.5.2+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/md5/53741f61d806efe045a5abe0e748aa36 -CompilerSupportLibraries.v0.5.2+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/sha512/b975a8fdfb736ef2b1aede2c89e390df261bfe8aaf8ffdb37887add09263d95f46642c3898ac19ec6098cdfdfc7f0726436dc273e9f70f10fe1abf4ea945277a -CompilerSupportLibraries.v0.5.2+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/md5/9687cf768c6c2879261e385c44ba490c -CompilerSupportLibraries.v0.5.2+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/sha512/02f9accf8273597f6889677de64255e4e399d67377b5363ed31dea7e2118cc24d3b7fad7c0632aea79dee44250b1ff74bf2fa22e4f3e7755de65871854112c14 -CompilerSupportLibraries.v0.5.2+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/md5/b62a81b9f43903b3de6fa1c78c03b89f -CompilerSupportLibraries.v0.5.2+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/sha512/d44eecb30ccf19bc8dca41c738dbedd2bd2cb6e379a3ab181c955cb9cdf9bae8efeaf7a90c85dc7434520ead7e910d38e92b448cff7aecaef0902684e9b06c9f -CompilerSupportLibraries.v0.5.2+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/md5/e31780333339ac64f54ad434578d6294 -CompilerSupportLibraries.v0.5.2+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/sha512/9c3b91ed90f3393dfc72e7e2feefa60afe6ad457971950b163ffbecafa41cea43a15cdfadd8f402fd8fb61652c224f5b1a04c432fb0f43593749f51ed1340116 -CompilerSupportLibraries.v0.5.2+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/md5/0f7bdfb908aa3d721428a1ee8412b594 -CompilerSupportLibraries.v0.5.2+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/sha512/3199da41c3df3d702a557c8b5e9fdde3a47c12d4c45fb9094fd194cbbe667663334b6cc0a5169fcc755790c4b5fada71c5094dc8d9a7f8b6c836d3f4c4c6e509 -CompilerSupportLibraries.v0.5.2+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/md5/f455758e436750092ba2df65adcfd380 -CompilerSupportLibraries.v0.5.2+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/sha512/b5d0dbdff19b5ce076b8ae7b907da25fdbe05eabd47e46987f9987690a3a670d14bd3d2c2343d366ca1ee861b85fcbaccc1460ba3a73571686ef9e4330427b65 -CompilerSupportLibraries.v0.5.2+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/md5/4cf3790d881b829b4b8da882987d5a40 -CompilerSupportLibraries.v0.5.2+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/sha512/ef5810243af32135da0cb7d08ae35ff8a2cce50c05200450154aa860c181719844466b787faae551aa71bd94e721f2d7d17ab14a049d0558666037862aff2f6a -CompilerSupportLibraries.v0.5.2+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/md5/a49e1fa6e040ac86ddd85a3188f83a76 -CompilerSupportLibraries.v0.5.2+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/sha512/cb0292651392a14f952181eb7a4a0ea6359632e96b017169cf4f1792f44f2846b5d6b2b5d334dee490262dd1c2d421de49d1f4a919402392f77fdaf60c1d19a3 -CompilerSupportLibraries.v0.5.2+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/md5/3f64969e0e70dc8644fe09637dd1cbe7 -CompilerSupportLibraries.v0.5.2+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/sha512/0a71f8b731911019666bdc82f42e306ff1801321362ce6fe58988c9a1b110cd032a01c11fd0f9a6a3fbf6c6545f3287e363f5b3c40ef2eab0659638c38687196 -CompilerSupportLibraries.v0.5.2+0.i686-linux-gnu-libgfortran3.tar.gz/md5/28f58931f66a3405fc4c99ce40724ece -CompilerSupportLibraries.v0.5.2+0.i686-linux-gnu-libgfortran3.tar.gz/sha512/d5290079264cfc6f716dcc9171f8412369e685c7ba0b9e82ae3d764de41671fbb4a24fdf7ebae9a9b913393837c2e41951326dbf3e870340fba7121709ebba8b -CompilerSupportLibraries.v0.5.2+0.i686-linux-gnu-libgfortran4.tar.gz/md5/f98763aae801cc7d88124bea422f13ca -CompilerSupportLibraries.v0.5.2+0.i686-linux-gnu-libgfortran4.tar.gz/sha512/da2095a462637ffcd0825949f4bcc86be9484c9e009648dc3c2e22e2fa19c65124e5e45f2694e85616df49b1181e2f4d2b886d3b83401c09ca58207db461ea23 -CompilerSupportLibraries.v0.5.2+0.i686-linux-gnu-libgfortran5.tar.gz/md5/1bfee57db4f2bdd788e59e34d0bb4506 -CompilerSupportLibraries.v0.5.2+0.i686-linux-gnu-libgfortran5.tar.gz/sha512/8f4814d97d6cd6c1f0c1d23fce875c40b6df7de7a8dc66e66681ba3c533120cb14d9d018808ff4e33dec53bb8958fbcedc9be6ac70817839ff89a0db5c0d18a8 -CompilerSupportLibraries.v0.5.2+0.i686-linux-musl-libgfortran3.tar.gz/md5/5da7af0483ffde929c58f3ae411f6489 -CompilerSupportLibraries.v0.5.2+0.i686-linux-musl-libgfortran3.tar.gz/sha512/97e56fe4fe0e10fa0d57ec10882a62d290829940049ffce7a8d81a843b91c7844e53d737bcdbc7a5e8206ca9820a7066fcdd7d0eed1e831d7af96222ccca1224 -CompilerSupportLibraries.v0.5.2+0.i686-linux-musl-libgfortran4.tar.gz/md5/a0b5cf513f2f02107c8887ea5e30cdda -CompilerSupportLibraries.v0.5.2+0.i686-linux-musl-libgfortran4.tar.gz/sha512/aeeacfb58094751fe5cec87825ebb02a22c58d3e7300b6ca6066eb717e28ebecff230838c32935ac11376a6efdd5a0c44fe0c8e7d5b9a1f0165171c2b67a2d8b -CompilerSupportLibraries.v0.5.2+0.i686-linux-musl-libgfortran5.tar.gz/md5/569ef42292d8cfd157026b434e93fe4d -CompilerSupportLibraries.v0.5.2+0.i686-linux-musl-libgfortran5.tar.gz/sha512/daf543fbe7e80fd63220f7c08e0d6b51d45ce9e0af592a591eecadcaac9b859ce596df2bf8fcb3fb72fb799f869d0caac28acb5d26b3c3aed6dc80245b90dcce -CompilerSupportLibraries.v0.5.2+0.i686-w64-mingw32-libgfortran3.tar.gz/md5/f4e0f3d40f7f77d32f26424dedff850f -CompilerSupportLibraries.v0.5.2+0.i686-w64-mingw32-libgfortran3.tar.gz/sha512/57e35c39c4c93919cdbbe33891b5938918d33840ad33ed51a010f9deab791d60fa2d030d3e14df6e445e0607dc9280b07ca287a3273630bf7e245d6ab8069cbd -CompilerSupportLibraries.v0.5.2+0.i686-w64-mingw32-libgfortran4.tar.gz/md5/d366731c11314cb908fca2032e7fefca -CompilerSupportLibraries.v0.5.2+0.i686-w64-mingw32-libgfortran4.tar.gz/sha512/a7e087e718f9d8cb4957b8bf3a4554faae97510b25d88a3e9ae4241cb69efa5b520bd9424a0072e7d712c9435e6900690c56004a716a716838367e91fe20e11d -CompilerSupportLibraries.v0.5.2+0.i686-w64-mingw32-libgfortran5.tar.gz/md5/eff855bb45f038c9d74c67ae2eed5641 -CompilerSupportLibraries.v0.5.2+0.i686-w64-mingw32-libgfortran5.tar.gz/sha512/e674d60247086bb8029270406d246a4857e668442a77299a431ec837446387bd1ed2de5e0f9f6985cc6e5d15b6692f40b18e0016e7c9d4e95a3770dffc19b44d -CompilerSupportLibraries.v0.5.2+0.powerpc64le-linux-gnu-libgfortran3.tar.gz/md5/0bfe78d226b3d89a83b54c6ff39239e1 -CompilerSupportLibraries.v0.5.2+0.powerpc64le-linux-gnu-libgfortran3.tar.gz/sha512/fed14514c9603a1e4772d2fd5f4a48da751c10e34b6fba5e0c35ff40b8ed165af6daebc051fa86751bdffb8f820ac779215dc3b38c4ff5c1624214b61d7ad1b0 -CompilerSupportLibraries.v0.5.2+0.powerpc64le-linux-gnu-libgfortran4.tar.gz/md5/d5219b60117555a3ccd41ab406d485f4 -CompilerSupportLibraries.v0.5.2+0.powerpc64le-linux-gnu-libgfortran4.tar.gz/sha512/9268d7c2c6ef649dc753757f9afc7ac1382e521d02c58a91eead9873f2a80f215f3b67f9a33abad53c8bca18c19ae3e63804e01e3109c939d33555c7ec8c5b1a -CompilerSupportLibraries.v0.5.2+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/md5/1f620c9a049e00b8b11c3970a23f2761 -CompilerSupportLibraries.v0.5.2+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/sha512/6ac900dfac9268334c9b54badbfbec323151353e8d87d3199f875a505febf863766ded0c52bce2939e5975fa6e35a28cc16c88e7c1cce37d65725fe275813606 -CompilerSupportLibraries.v0.5.2+0.x86_64-apple-darwin-libgfortran3.tar.gz/md5/c21c35b00ed7ad0171d63006f1a4170d -CompilerSupportLibraries.v0.5.2+0.x86_64-apple-darwin-libgfortran3.tar.gz/sha512/f993a616a75b1f5ee140ed47b6e4aa981cffbbffd795fc0cf9df9397a6366a4507a158530e961c398bab656e7d51a27be026088678e0c19485ef0bad136bb69a -CompilerSupportLibraries.v0.5.2+0.x86_64-apple-darwin-libgfortran4.tar.gz/md5/f0cd5c8631256f3b903e95ad3623d702 -CompilerSupportLibraries.v0.5.2+0.x86_64-apple-darwin-libgfortran4.tar.gz/sha512/81de3f699169254fa83a3ab8b6063ddfd300065edf90f15239b0a304f3feea9534acba7d982058a7712ce94dcdb1ae036502f276813a96f8254e323787556d63 -CompilerSupportLibraries.v0.5.2+0.x86_64-apple-darwin-libgfortran5.tar.gz/md5/6030c114c1250e99958a0727da9d6daf -CompilerSupportLibraries.v0.5.2+0.x86_64-apple-darwin-libgfortran5.tar.gz/sha512/1d4be1c0718aeab056368653b7f34bd5ac3c85edb9fbdc2752b8c4877fcf5d080774506519cf285954485d806bccc18323f6c45f069db8bd314d064a2cc1ed66 -CompilerSupportLibraries.v0.5.2+0.x86_64-linux-gnu-libgfortran3.tar.gz/md5/b45ac0c04357de9d013df598dd13f3bf -CompilerSupportLibraries.v0.5.2+0.x86_64-linux-gnu-libgfortran3.tar.gz/sha512/42174d05c7165f87693efa09facc9405c9d6eab490c4b5fc74ba02e1e2e871799a24dcb7496e0693f30f9c3fd7e81020b77a3dd946832288769063f6d2a31aba -CompilerSupportLibraries.v0.5.2+0.x86_64-linux-gnu-libgfortran4.tar.gz/md5/761998b08e4b460cec95468adb850c31 -CompilerSupportLibraries.v0.5.2+0.x86_64-linux-gnu-libgfortran4.tar.gz/sha512/32853dcb3202e735325e1e0e3d88e2e446d7c88d45bc462d4e91f7d57dfd78b0f3381302e72163fafdb1c2cef53d4822e1c52289081e06b7b74d67e2ed0d34c2 -CompilerSupportLibraries.v0.5.2+0.x86_64-linux-gnu-libgfortran5.tar.gz/md5/dfd50d071702f903213ea0c6a42ad81b -CompilerSupportLibraries.v0.5.2+0.x86_64-linux-gnu-libgfortran5.tar.gz/sha512/3d6ecca7689bcb1925801d26a328790228c564bb731f6fa25d88763eeb22cccc4409dd6376c7b574ec242fbf85e41fd82d038a2650f8d33bb850b9a9a9f9a722 -CompilerSupportLibraries.v0.5.2+0.x86_64-linux-musl-libgfortran3.tar.gz/md5/0b374bc55dd0d5f4cf34a12d4901c022 -CompilerSupportLibraries.v0.5.2+0.x86_64-linux-musl-libgfortran3.tar.gz/sha512/10db23cc1d1367f40fed6c6cfc232fdc49f55e666d3623faa1af40dd781ea7a5d37b6b5a39524f0fc57d6d49947f429389bbf7075f10163090d7ea48903e688a -CompilerSupportLibraries.v0.5.2+0.x86_64-linux-musl-libgfortran4.tar.gz/md5/1e28cdc7937a500b081a1f4d340190f2 -CompilerSupportLibraries.v0.5.2+0.x86_64-linux-musl-libgfortran4.tar.gz/sha512/0b635b8f594739453033fd1dc5496976a8fff314dd078e2d8248d3c2136abaaa610ebc45252a81d16db9d91a0ec20a552f1bcb65ed3b50a627e40168e7f100e0 -CompilerSupportLibraries.v0.5.2+0.x86_64-linux-musl-libgfortran5.tar.gz/md5/f6fcf32044f69d8305a718eeb7651614 -CompilerSupportLibraries.v0.5.2+0.x86_64-linux-musl-libgfortran5.tar.gz/sha512/5940a145a3203d5a4a9b7cd9aab45b8bcff08a43a69a8fea67a9e18535625c8ecc051ba344421253b2f96eaa1a007d42555897a8f8aa0e8bd5dbf1ddbd38f197 -CompilerSupportLibraries.v0.5.2+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/md5/eb46728ef7d3ce955d5a497a556138c2 -CompilerSupportLibraries.v0.5.2+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/sha512/922d3a85059e7cedc6e0e52687cd6f22cb708677a65fcab86f7571737d8f17455f15b3f1af7442ee5fd04a437f226d4eee374d0f353a10f8f7a87160d7a2351d -CompilerSupportLibraries.v0.5.2+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/md5/fc1f4fc44c08f0c3040b976558a35e3e -CompilerSupportLibraries.v0.5.2+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/sha512/5406251fe1d1d1901ac4e6af3b8e9394fcaee2fa6a4f3d2817161a1626bc6b45d7b184f9bdd3d2e6571640f40b4e06c61f321358ad8fe484871ab9b878801a95 -CompilerSupportLibraries.v0.5.2+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/md5/e1b52fdb233c9667610867e278e7719a -CompilerSupportLibraries.v0.5.2+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/sha512/efadc4efc419808cb289c8c8f52664a72f2646bad2e8e02533456cf9afd613d4cbacd121da786316206df8f65b5264498f25adb04f7673121b2a58a20c4a75b9 -CompilerSupportLibraries.v0.5.2+0.x86_64-w64-mingw32-libgfortran3.tar.gz/md5/a449351de41a3140534d278aacedc54e -CompilerSupportLibraries.v0.5.2+0.x86_64-w64-mingw32-libgfortran3.tar.gz/sha512/db5bfbd161eba076598465cfee277418c6e9f4f0f7c4672a437c68ceff374f600917fdcaaa9dfdb945103d2b5c9786663e8e9403f6fdc796cda7c529dadf28ba -CompilerSupportLibraries.v0.5.2+0.x86_64-w64-mingw32-libgfortran4.tar.gz/md5/facd6a008270b85d08ca835556921127 -CompilerSupportLibraries.v0.5.2+0.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/236438e05eb3f50063aea90522e61f10a03c474f3c26117c071bf94d4ca24fae56e09a565cbf00dc5d1eabefec804fa5503ecbcc324b5da00a65b5471fccfadf -CompilerSupportLibraries.v0.5.2+0.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/cd294be65ddd327d6c0feeca8b13f922 -CompilerSupportLibraries.v0.5.2+0.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/73dc99009d25fa0ebafa77d7c5747d21a6e0778a6266a2408df885d9553e4b8029c104e1fe174526d9261252bb564128ae7cf9058268475d168c79d19ee4f0c0 +CompilerSupportLibraries.v1.0.1+0.aarch64-apple-darwin-libgfortran5.tar.gz/md5/20ebaad57850393b6ac9fa924e511fe4 +CompilerSupportLibraries.v1.0.1+0.aarch64-apple-darwin-libgfortran5.tar.gz/sha512/020de4d8b0ff6bedbadaa305ff8445e6849f12053762ea4aa68412d1ec763dbd86f479587a2fbb862487f1feb04d976c38099ddf3887817a3d32b3f029cf85b1 +CompilerSupportLibraries.v1.0.1+0.aarch64-linux-gnu-libgfortran3.tar.gz/md5/3908fa1a2f739b330e787468c9bfb5c8 +CompilerSupportLibraries.v1.0.1+0.aarch64-linux-gnu-libgfortran3.tar.gz/sha512/1741e3403ac7aa99e7cfd9a01222c4153ed300f47cc1b347e1af1a6cd07a82caaa54b9cfbebae8751440420551621cc6524504413446d104f9493dff2c081853 +CompilerSupportLibraries.v1.0.1+0.aarch64-linux-gnu-libgfortran4.tar.gz/md5/2444dbb7637b32cf543675cc12330878 +CompilerSupportLibraries.v1.0.1+0.aarch64-linux-gnu-libgfortran4.tar.gz/sha512/8537f0b243df8544350c884021b21c585fd302e8dd462a30a6ee84c7a36a049133262e5d1bc362f972066b8e8d6a091c32c3b746bab1feb9fccf2e7cca65756c +CompilerSupportLibraries.v1.0.1+0.aarch64-linux-gnu-libgfortran5.tar.gz/md5/d79c1434594c0c5e7d6be798bf52c99e +CompilerSupportLibraries.v1.0.1+0.aarch64-linux-gnu-libgfortran5.tar.gz/sha512/7e71accc401a45b51b298702fb4c79a2fc856c7b28f0935f6ad3a0db5381c55fe5432daff371842930d718024b7c6c1d80e2bd09d397145203673bebbe3496ae +CompilerSupportLibraries.v1.0.1+0.aarch64-linux-musl-libgfortran3.tar.gz/md5/f212059053d99558a9b0bf54b20180e1 +CompilerSupportLibraries.v1.0.1+0.aarch64-linux-musl-libgfortran3.tar.gz/sha512/5c104b1282cec8a944e5d008f44a4d60f4394fd5d797fec7d1f487d13e7328cd9c88ec4916dabf18596d87160756bda914e4f8c5a356b5577f9349d0d9e976d6 +CompilerSupportLibraries.v1.0.1+0.aarch64-linux-musl-libgfortran4.tar.gz/md5/3e3b3795ee93ef317223050e803a9875 +CompilerSupportLibraries.v1.0.1+0.aarch64-linux-musl-libgfortran4.tar.gz/sha512/85d3c955e15f66bfe8bfec2f28c9160bc03d4d531ea4ffe6bc6b51e0d69ccea3ab67a16ca752dabc870861c407381c4519d75c6be3832e8dccd6122ec8c6ed75 +CompilerSupportLibraries.v1.0.1+0.aarch64-linux-musl-libgfortran5.tar.gz/md5/cf2d1315f6a348af2e6c065e2a286e7a +CompilerSupportLibraries.v1.0.1+0.aarch64-linux-musl-libgfortran5.tar.gz/sha512/58420377bc77aa7678034ee5f708eb6be7db359faef2c2638869765453633da9bf455512bd88e95b38ae0428ecc4053561517b176b2371129bdaef9d8d5dadfd +CompilerSupportLibraries.v1.0.1+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/md5/f5c09ed7e0eeb8d345d328f950582f26 +CompilerSupportLibraries.v1.0.1+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/sha512/9c657f55c8fcdeb404be168a3a63a5e84304730fe34f25673d92cdae4b0a1fcc6a877ee1433f060e1be854c7811d66632e32510a2ed591d88330f1340b9c20de +CompilerSupportLibraries.v1.0.1+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/md5/c685518aca4721cd8621d510e2039683 +CompilerSupportLibraries.v1.0.1+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/sha512/b760468c6377dcd2b8dd50200daaabe604006afc070984d78152b2becd0680b59036c9a6e91dea490121bd85b58d285bfc1e1cf696d29af236528400101de36c +CompilerSupportLibraries.v1.0.1+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/md5/8faf5c8ad62ab10f71dd2ec9683053e2 +CompilerSupportLibraries.v1.0.1+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/sha512/921239f241a5c89710cf07272d7f6c3f10201a7533068ed1e9643f9fb2f439e1bb765a4966d913829866ee0ce4f1589d30d06e4b5c1361e3c016a9473f087177 +CompilerSupportLibraries.v1.0.1+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/md5/b38fcb70691ac2621379d298eef8c79e +CompilerSupportLibraries.v1.0.1+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/sha512/06c7f64257ce721f5941f6e50a0d2717cdc9394fc532ded19ce3eaacd5e92a416969534227562e4fee04d2b6340c650d8bc9779e14519b90038bc41e8d1f5ce3 +CompilerSupportLibraries.v1.0.1+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/md5/cdfab2c7bc41765caf4441c3caeed761 +CompilerSupportLibraries.v1.0.1+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/sha512/7109d4a7b32c00309c42685f54a86fc2cc63c0c00f65584ad296b6e44ad3320eed1aaf49684a8831841cdffa5555d72f89272fb722a780596e27ef020528026b +CompilerSupportLibraries.v1.0.1+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/md5/441980ebd23d72772cbe603f1c275336 +CompilerSupportLibraries.v1.0.1+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/sha512/e273d9f1af259a3080df8f173e1808a1ade976a943aba97216bf59a96178e7c052e7a048b0ceee53ab486ed577a2ecb92579857be2f7b29e76322ee1f13c9d76 +CompilerSupportLibraries.v1.0.1+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/md5/f5c09ed7e0eeb8d345d328f950582f26 +CompilerSupportLibraries.v1.0.1+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/sha512/9c657f55c8fcdeb404be168a3a63a5e84304730fe34f25673d92cdae4b0a1fcc6a877ee1433f060e1be854c7811d66632e32510a2ed591d88330f1340b9c20de +CompilerSupportLibraries.v1.0.1+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/md5/c685518aca4721cd8621d510e2039683 +CompilerSupportLibraries.v1.0.1+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/sha512/b760468c6377dcd2b8dd50200daaabe604006afc070984d78152b2becd0680b59036c9a6e91dea490121bd85b58d285bfc1e1cf696d29af236528400101de36c +CompilerSupportLibraries.v1.0.1+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/md5/8faf5c8ad62ab10f71dd2ec9683053e2 +CompilerSupportLibraries.v1.0.1+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/sha512/921239f241a5c89710cf07272d7f6c3f10201a7533068ed1e9643f9fb2f439e1bb765a4966d913829866ee0ce4f1589d30d06e4b5c1361e3c016a9473f087177 +CompilerSupportLibraries.v1.0.1+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/md5/b38fcb70691ac2621379d298eef8c79e +CompilerSupportLibraries.v1.0.1+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/sha512/06c7f64257ce721f5941f6e50a0d2717cdc9394fc532ded19ce3eaacd5e92a416969534227562e4fee04d2b6340c650d8bc9779e14519b90038bc41e8d1f5ce3 +CompilerSupportLibraries.v1.0.1+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/md5/cdfab2c7bc41765caf4441c3caeed761 +CompilerSupportLibraries.v1.0.1+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/sha512/7109d4a7b32c00309c42685f54a86fc2cc63c0c00f65584ad296b6e44ad3320eed1aaf49684a8831841cdffa5555d72f89272fb722a780596e27ef020528026b +CompilerSupportLibraries.v1.0.1+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/md5/441980ebd23d72772cbe603f1c275336 +CompilerSupportLibraries.v1.0.1+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/sha512/e273d9f1af259a3080df8f173e1808a1ade976a943aba97216bf59a96178e7c052e7a048b0ceee53ab486ed577a2ecb92579857be2f7b29e76322ee1f13c9d76 +CompilerSupportLibraries.v1.0.1+0.i686-linux-gnu-libgfortran3.tar.gz/md5/6decf8fd5afb50451771c761e63a8917 +CompilerSupportLibraries.v1.0.1+0.i686-linux-gnu-libgfortran3.tar.gz/sha512/4984724bcc847724b1bc005b6f760a18b68147f7d5402d0faf4e28fc0d14fa10975368a951f9caf2a8856500046dec8343043274557d58269e77492b929a9e4b +CompilerSupportLibraries.v1.0.1+0.i686-linux-gnu-libgfortran4.tar.gz/md5/39d1e8a3baa144c018d3eaf7f3806482 +CompilerSupportLibraries.v1.0.1+0.i686-linux-gnu-libgfortran4.tar.gz/sha512/fc4d429279c5a93b6c28b6e911b1e7cfd1c1cfe46f11f2e901b3832ce90d45f49d3d29f0ef18518a94af6cc8651f67c4ed81672680f9281ada390440b172a2af +CompilerSupportLibraries.v1.0.1+0.i686-linux-gnu-libgfortran5.tar.gz/md5/37dabd9cd224c9fed9633dedccb6c565 +CompilerSupportLibraries.v1.0.1+0.i686-linux-gnu-libgfortran5.tar.gz/sha512/b253149e72eef9486888fbaace66e9b6945f4477f6b818f64f3047331165b0e2bc17aa6e3fc8c88686a72e478eb62c8f53883415d5419db448d8016fa3a1da5e +CompilerSupportLibraries.v1.0.1+0.i686-linux-musl-libgfortran3.tar.gz/md5/afdd32bfadd465848e6be458817a44ae +CompilerSupportLibraries.v1.0.1+0.i686-linux-musl-libgfortran3.tar.gz/sha512/eebd679c499143014514c7c9d1875dedbbab9e3af51526c4dd445a9e3dbade95d24522da8bbad0a50ab400755e47b018828b324c4ad7705e212ccd990e34439a +CompilerSupportLibraries.v1.0.1+0.i686-linux-musl-libgfortran4.tar.gz/md5/bc4a0f0b7cea328f7e8850583774496b +CompilerSupportLibraries.v1.0.1+0.i686-linux-musl-libgfortran4.tar.gz/sha512/82285b67946212b49cddf6259f2c60ff5469f8c5263ccefe44f1d93ace98ab68e2c152e1b54434b2f075fd8d192c06d5451bc8cca26d951ad15f3453102f02b5 +CompilerSupportLibraries.v1.0.1+0.i686-linux-musl-libgfortran5.tar.gz/md5/177f0232abce8d523882530ed7a93092 +CompilerSupportLibraries.v1.0.1+0.i686-linux-musl-libgfortran5.tar.gz/sha512/db80acf0f2434f28ee7680e1beb34f564940071815d1ad89fb5913cbd9ac24da528e826d0d54be6265a7340ebd661b6d308ed79d96b67fa5d8c98dc3f1bee8d6 +CompilerSupportLibraries.v1.0.1+0.i686-w64-mingw32-libgfortran3.tar.gz/md5/c723e7d3c3038f59b9bf0cc3a65826bc +CompilerSupportLibraries.v1.0.1+0.i686-w64-mingw32-libgfortran3.tar.gz/sha512/0545561ccd7e525b6cd86935366a2724a5e013411a1c01564db21b66da5fef959cf06b0839b96f1dc2c970eb6c8fb19c012e6cd2c17bc381b55420c72fe1b9f6 +CompilerSupportLibraries.v1.0.1+0.i686-w64-mingw32-libgfortran4.tar.gz/md5/763bd82645d2f3c72b6244d68bebb40f +CompilerSupportLibraries.v1.0.1+0.i686-w64-mingw32-libgfortran4.tar.gz/sha512/700e719eeab486915a9fb0954125cb9a3e9a813d7a069eca05be3a16621f4875668918a5ed5f645e734ac62b0c2ddbaa6234adc9109e98fb88b8ca1197481ed8 +CompilerSupportLibraries.v1.0.1+0.i686-w64-mingw32-libgfortran5.tar.gz/md5/18e90d15dc6dd0a836e9aa076b342105 +CompilerSupportLibraries.v1.0.1+0.i686-w64-mingw32-libgfortran5.tar.gz/sha512/9ff61e8da2b431a8cb09818bde5daab2d7b8cf7a934f184f14ea50eccf5796ae91558e06a22137eb021c4055c54faf4a524a54dbbd718e8ea0abb5dcec844fdb +CompilerSupportLibraries.v1.0.1+0.powerpc64le-linux-gnu-libgfortran3.tar.gz/md5/4e5e4b23dc87450738da33926a07511d +CompilerSupportLibraries.v1.0.1+0.powerpc64le-linux-gnu-libgfortran3.tar.gz/sha512/fc09879d94b750e75775d8b64a41ab9924d675fb53c5700467604412928fe7f5cb21911da0f64898d2463fa77ffbaf4c96c397b9060f4746eec152747930cddc +CompilerSupportLibraries.v1.0.1+0.powerpc64le-linux-gnu-libgfortran4.tar.gz/md5/9a92138ed69aa317a932a615c6e62d69 +CompilerSupportLibraries.v1.0.1+0.powerpc64le-linux-gnu-libgfortran4.tar.gz/sha512/0b7785379936a2a209b074177b1424dd7e00b29b5165f564e799b0aa4e06a582e9d616525d97274ba2507cb88192028f1ac485d3f99bdc7ee53fc63c1a7e85de +CompilerSupportLibraries.v1.0.1+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/md5/8ffee3d6de5197c7a1f354d72c8238fa +CompilerSupportLibraries.v1.0.1+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/sha512/deadc4d7224c84f9b82dc956b69e815c44ae036802838365d870ab9f58c8bcf8ce0645f2f387c8ff344ac2108fc8e7e1ee907fa55e93c91aa5d9fd921bf3fdcb +CompilerSupportLibraries.v1.0.1+0.x86_64-apple-darwin-libgfortran3.tar.gz/md5/87449e72e3f33dbb69b7053cdc2649d4 +CompilerSupportLibraries.v1.0.1+0.x86_64-apple-darwin-libgfortran3.tar.gz/sha512/5ce02ad10c6f4686a476eb2a5de2988cd8b482f5e693db2880c84ad1c82f468ef03fe01b9d0feefe5d4ee741d1d16643d36b144e6261ed32311b3b6f312fac2f +CompilerSupportLibraries.v1.0.1+0.x86_64-apple-darwin-libgfortran4.tar.gz/md5/0407cde92cfa42fa89ac83217ca0ec16 +CompilerSupportLibraries.v1.0.1+0.x86_64-apple-darwin-libgfortran4.tar.gz/sha512/032c831f1166a336551138939ac40eb2c68a048ce786c0c1403b879a20c1b706caac16d22560b2c7f2b3d6373986c347188675674116005ca251336ee048d09f +CompilerSupportLibraries.v1.0.1+0.x86_64-apple-darwin-libgfortran5.tar.gz/md5/23418763b808371ee94772a90d501f4d +CompilerSupportLibraries.v1.0.1+0.x86_64-apple-darwin-libgfortran5.tar.gz/sha512/7867b843551457b11bda7821dd384c1c1cf23b80a308b2058a693de7b7da099f0b37eb0a6de2b84c04b625a68c60eea55138e200d5d6ec6f6af09bd7ce406a96 +CompilerSupportLibraries.v1.0.1+0.x86_64-linux-gnu-libgfortran3.tar.gz/md5/e3d33ae03c18affea74699bdc1fabb68 +CompilerSupportLibraries.v1.0.1+0.x86_64-linux-gnu-libgfortran3.tar.gz/sha512/42013f4921de5a69ad857195ce5c19ad1bca3c920d79699e5501f1f4534ab132fabd422362b2b5056f5d182215d6c069db5df460bafa700903faf962cc00f77b +CompilerSupportLibraries.v1.0.1+0.x86_64-linux-gnu-libgfortran4.tar.gz/md5/d40c1e8c0393213c6057c53a12f44175 +CompilerSupportLibraries.v1.0.1+0.x86_64-linux-gnu-libgfortran4.tar.gz/sha512/fe7baa4de7490065ab7b953cc12f41462a24bcb49d0a4a64b23249e98e7569b19bb1cb455af2f76090e34066a7d3cdd7a48cae6515ce6c7a5c8486b0cacc5106 +CompilerSupportLibraries.v1.0.1+0.x86_64-linux-gnu-libgfortran5.tar.gz/md5/48541b90f715c4c86ee4da0570275947 +CompilerSupportLibraries.v1.0.1+0.x86_64-linux-gnu-libgfortran5.tar.gz/sha512/7f2683fb98e80f12629f4ed3bea9fd59d32b7e7a9ed1699e782d8e238ff0915ecc61bf00adaf4597cfe41caf82cdca0f9be250f595f5f0bea6d8f77dba99eaf4 +CompilerSupportLibraries.v1.0.1+0.x86_64-linux-musl-libgfortran3.tar.gz/md5/4547059eb905995667be48bf85d49911 +CompilerSupportLibraries.v1.0.1+0.x86_64-linux-musl-libgfortran3.tar.gz/sha512/7400fdabc924434ab4a4949248c3603887ac06ffd2f205ae33e14495d86cd4f816bbd1999eeafa0257f518df1e7f7c522f596e847a71dbfbfccff4859f50acc7 +CompilerSupportLibraries.v1.0.1+0.x86_64-linux-musl-libgfortran4.tar.gz/md5/46267543cad6584d7b7b9fcc8f18f21d +CompilerSupportLibraries.v1.0.1+0.x86_64-linux-musl-libgfortran4.tar.gz/sha512/0353d7d724be48d4185d3c181692970b7996f53f6a01723072aa5c94b53a8c5055faeed30df51659c252a46f4b941dec0cb24569323e3c85c166f14c5b7c8e9e +CompilerSupportLibraries.v1.0.1+0.x86_64-linux-musl-libgfortran5.tar.gz/md5/14dba2897a6e9d370fa9091c045375fc +CompilerSupportLibraries.v1.0.1+0.x86_64-linux-musl-libgfortran5.tar.gz/sha512/10b79f9c059839f5b57fa8d2a381a034c4067262c4088bd354d14ea56bec097878069383aa9cfadaa09d73bd20fc348fb61662d863a8d62cb25d7af6b8e29858 +CompilerSupportLibraries.v1.0.1+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/md5/eed836d1addeb10d0901f836724aff1e +CompilerSupportLibraries.v1.0.1+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/sha512/e33eca424d1529a1fb23ba9cf7fac345ed1cfc8073c975b6b31ca44d2e8c3f5083af65433df009b22483dceb2e43149f3c1e8433681fec5fb812e1d5b4243ce4 +CompilerSupportLibraries.v1.0.1+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/md5/d5ae9f9519341fdaabf62267c89461d2 +CompilerSupportLibraries.v1.0.1+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/sha512/6421aa5d1bd6f08ad43f59ed4dc1bef8b9b598ebbbd3e48149730f3bec3471f8e2c02ffb338427326924290b8f52ef9e626e3313448bc931a61d866c5dc544ae +CompilerSupportLibraries.v1.0.1+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/md5/fc1df521395362a5aaa2e2aeef707207 +CompilerSupportLibraries.v1.0.1+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/sha512/f2e5a08e3cae171242ae6a20d2d4838c1529ce042745dc466148b7bbc06896d94476fd05c7787e6e8641bea752dfc0e6b09e95b160bede600d20d2ad68e7705f +CompilerSupportLibraries.v1.0.1+0.x86_64-w64-mingw32-libgfortran3.tar.gz/md5/80c337837a9032e4c9614f0d3218993b +CompilerSupportLibraries.v1.0.1+0.x86_64-w64-mingw32-libgfortran3.tar.gz/sha512/cf07e459ca55cb9ee3d38e6858320530c1d1ab2ffd35bfa2a33b2505d3189f13b9743a0e279d70f85d227cee8a8974448f1371a122dcbea03fb1e414f8df8337 +CompilerSupportLibraries.v1.0.1+0.x86_64-w64-mingw32-libgfortran4.tar.gz/md5/792cae36932dd53af20b7f61c80f623b +CompilerSupportLibraries.v1.0.1+0.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/805f2b64fe9d2b94fc6c966945e10458d8d1c47a8d95fcda057c03a13999d7d0f136c754e4b1e152faaf23e4949861c2ad42b4437dba19f59b3db745d7a76108 +CompilerSupportLibraries.v1.0.1+0.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/063c07fcbba4b9c3bd23ab0d987f1dbb +CompilerSupportLibraries.v1.0.1+0.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/1d0344b30b5fb34a63f6844be0501c0ad08f1116b0c7b00e13d47860cc6bbdd39734416ad3b492414a28ba1744240bd05aca0d1560873f687d3f61747058626b diff --git a/deps/csl.mk b/deps/csl.mk index e3f84aa98974d..0df2b92b6ce39 100644 --- a/deps/csl.mk +++ b/deps/csl.mk @@ -22,7 +22,7 @@ endef # would get from CSL (by searching for a `GLIBCXX_3.4.X` symbol that does not exist # in our CSL, but would in a newer one), and default to `USE_BINARYBUILDER_CSL=0` in # this case. -CSL_NEXT_GLIBCXX_VERSION=GLIBCXX_3\.4\.30|GLIBCXX_3\.5\.|GLIBCXX_4\. +CSL_NEXT_GLIBCXX_VERSION=GLIBCXX_3\.4\.31|GLIBCXX_3\.5\.|GLIBCXX_4\. # First, check to see if BB is disabled on a global setting ifeq ($(USE_BINARYBUILDER),0) diff --git a/stdlib/CompilerSupportLibraries_jll/Project.toml b/stdlib/CompilerSupportLibraries_jll/Project.toml index 877a1ab5b005c..b072831326627 100644 --- a/stdlib/CompilerSupportLibraries_jll/Project.toml +++ b/stdlib/CompilerSupportLibraries_jll/Project.toml @@ -4,7 +4,7 @@ uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" # NOTE: When updating this, also make sure to update the value # `CSL_NEXT_GLIBCXX_VERSION` in `deps/csl.mk`, to properly disable # automatic usage of BB-built CSLs on extremely up-to-date systems! -version = "0.5.2+0" +version = "1.0.1+0" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" diff --git a/stdlib/CompilerSupportLibraries_jll/src/CompilerSupportLibraries_jll.jl b/stdlib/CompilerSupportLibraries_jll/src/CompilerSupportLibraries_jll.jl index 1b2c0cd41cbe2..604c7ae89dd5e 100644 --- a/stdlib/CompilerSupportLibraries_jll/src/CompilerSupportLibraries_jll.jl +++ b/stdlib/CompilerSupportLibraries_jll/src/CompilerSupportLibraries_jll.jl @@ -32,7 +32,7 @@ if Sys.iswindows() const libstdcxx = "libstdc++-6.dll" const libgomp = "libgomp-1.dll" elseif Sys.isapple() - if arch(HostPlatform()) == "aarch64" + if arch(HostPlatform()) == "aarch64" || libgfortran_version(HostPlatform()) == v"5" const libgcc_s = "@rpath/libgcc_s.1.1.dylib" else const libgcc_s = "@rpath/libgcc_s.1.dylib" From 96592e21e2b186bfba2044dac84a15d0c31ee662 Mon Sep 17 00:00:00 2001 From: apaz Date: Tue, 8 Nov 2022 16:39:29 -0600 Subject: [PATCH 07/26] Probe and dlopen() the correct libstdc++ (#46976) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Probe if system libstdc++ is newer than ours If the system libstdc++ is detected to be newer, load it. Otherwise, load the one that we ship. This improves compatibility with external shared libraries that the user might have on their system. Fixes #34276 Co-authored-by: Jameson Nash Co-authored-by: Elliot Saba * Addressed review comments. * Change error handling in wrapper functions Co-authored-by: Jameson Nash * Call write_wrapper three times instead of snprintf Co-authored-by: Jameson Nash * Apply suggestions from code review Co-authored-by: Jameson Nash * Update cli/loader_lib.c Co-authored-by: Jameson Nash * Reordered reading and waiting to avoid a deadlock. * Fixed obvious issues. * Only load libstdc++ preemptively on linux. * Update cli/loader_lib.c Co-authored-by: Jameson Nash * Update cli/loader_lib.c Co-authored-by: Jameson Nash * Specified path to bundled libstdc++ on the command line. * Removed whitespace. * Update cli/Makefile Co-authored-by: Jameson Nash * Handled make install stringreplace. * Correctly quoted stringreplace. * Added -Wl,--enable-new-dtags to prevent DT_RPATH for transitive dependencies * Updated news entry. * Added comment about environment variable. * patched rpath for libgfortran and libLLVM. * Added explaination to Make.inc * Removed trailing space * Removed patchelf for libgfortran, now that BB has been fixed. * Fixed typos and comments Co-authored-by: Max Horn Co-authored-by: Mosè Giordano Co-authored-by: Jameson Nash Co-authored-by: Elliot Saba Co-authored-by: Max Horn (cherry picked from commit eb708d62f897dfbf0a757aa24c30754a492c6514) --- Make.inc | 33 ++++++-- Makefile | 12 ++- NEWS.md | 3 +- cli/Makefile | 6 +- cli/loader_lib.c | 214 +++++++++++++++++++++++++++++++++++++++++++++-- deps/csl.mk | 7 +- 6 files changed, 254 insertions(+), 21 deletions(-) diff --git a/Make.inc b/Make.inc index 41602f354c416..02b73aeadfaf5 100644 --- a/Make.inc +++ b/Make.inc @@ -1147,6 +1147,29 @@ BB_TRIPLET := $(subst $(SPACE),-,$(filter-out cxx%,$(filter-out libgfortran%,$(s LIBGFORTRAN_VERSION := $(subst libgfortran,,$(filter libgfortran%,$(subst -,$(SPACE),$(BB_TRIPLET_LIBGFORTRAN)))) +# CSL_NEXT_GLIBCXX_VERSION is a triple of the symbols representing support for whatever +# the next libstdc++ version would be. This is used for two things. +# 1. Whether the system libraries are new enough, if we need to use the libs bundled with CSL +# 2. To know which libstdc++ to load at runtime +# We want whichever libstdc++ library is newer, because if we don't it can cause problems. +# While what CSL bundles is quite bleeding-edge compared to what most distros ship, if someone +# tries to build an older branch of Julia, the version of CSL that ships with it may be +# relatively old. This is not a problem for code that is built in BB, but when we build Julia +# with the system compiler, that compiler uses the version of `libstdc++` that it is bundled +# with, and we can get linker errors when trying to run that `julia` executable with the +# `libstdc++` that comes from the (now old) BB-built CSL. +# To fix this, we take note when the system `libstdc++.so` is newer than whatever we +# would get from CSL (by searching for a `GLIBCXX_X.Y.Z` symbol that does not exist +# in our CSL, but would in a newer one), and default to `USE_BINARYBUILDER_CSL=0` in +# this case. This ensures that we link against a version with the symbols required. +# We also check the system libstdc++ at runtime in the cli loader library, and +# load it if it contains the version symbol that indicates that it is newer than the one +# shipped with CSL. Although we do not depend on any of the symbols, it is entirely +# possible that a user might choose to install a library which depends on symbols provided +# by a newer libstdc++. Without runtime detection, those libraries would break. +CSL_NEXT_GLIBCXX_VERSION=GLIBCXX_3\.4\.31|GLIBCXX_3\.5\.|GLIBCXX_4\. + + # This is the set of projects that BinaryBuilder dependencies are hooked up for. # Note: we explicitly _do not_ define `CSL` here, since it requires some more # advanced techniques to decide whether it should be installed from a BB source @@ -1203,18 +1226,16 @@ ifneq (,$(filter $(OS),WINNT emscripten)) RPATH := RPATH_ORIGIN := RPATH_ESCAPED_ORIGIN := - RPATH_LIB := else ifeq ($(OS), Darwin) RPATH := -Wl,-rpath,'@executable_path/$(build_libdir_rel)' RPATH_ORIGIN := -Wl,-rpath,'@loader_path/' RPATH_ESCAPED_ORIGIN := $(RPATH_ORIGIN) - RPATH_LIB := -Wl,-rpath,'@loader_path/' else - RPATH := -Wl,-rpath,'$$ORIGIN/$(build_libdir_rel)' -Wl,-rpath,'$$ORIGIN/$(build_private_libdir_rel)' -Wl,-rpath-link,$(build_shlibdir) -Wl,-z,origin - RPATH_ORIGIN := -Wl,-rpath,'$$ORIGIN' -Wl,-z,origin - RPATH_ESCAPED_ORIGIN := -Wl,-rpath,'\$$\$$ORIGIN' -Wl,-z,origin -Wl,-rpath-link,$(build_shlibdir) - RPATH_LIB := -Wl,-rpath,'$$ORIGIN/' -Wl,-z,origin + RPATH := -Wl,-rpath,'$$ORIGIN/$(build_libdir_rel)' -Wl,-rpath,'$$ORIGIN/$(build_private_libdir_rel)' -Wl,-rpath-link,$(build_shlibdir) -Wl,-z,origin -Wl,--enable-new-dtags + RPATH_ORIGIN := -Wl,-rpath,'$$ORIGIN' -Wl,-z,origin -Wl,--enable-new-dtags + RPATH_ESCAPED_ORIGIN := -Wl,-rpath,'\$$\$$ORIGIN' -Wl,-z,origin -Wl,-rpath-link,$(build_shlibdir) -Wl,--enable-new-dtags endif +RPATH_LIB := $(RPATH_ORIGIN) # --whole-archive ifeq ($(OS), Darwin) diff --git a/Makefile b/Makefile index 57b5953107914..94df626014059 100644 --- a/Makefile +++ b/Makefile @@ -225,7 +225,7 @@ endif # Note that we disable MSYS2's path munging here, as otherwise # it replaces our `:`-separated list as a `;`-separated one. define stringreplace - MSYS2_ARG_CONV_EXCL='*' $(build_depsbindir)/stringreplace $$(strings -t x - $1 | grep $2 | awk '{print $$1;}') $3 255 "$(call cygpath_w,$1)" + MSYS2_ARG_CONV_EXCL='*' $(build_depsbindir)/stringreplace $$(strings -t x - '$1' | grep "$2" | awk '{print $$1;}') "$3" 255 "$(call cygpath_w,$1)" endef @@ -374,6 +374,16 @@ ifeq ($(BUNDLE_DEBUG_LIBS),1) endif endif + # Fix rpaths for dependencies. This should be fixed in BinaryBuilder later. +ifeq ($(OS), Linux) + -$(PATCHELF) --set-rpath '$$ORIGIN' $(DESTDIR)$(private_shlibdir)/libLLVM.$(SHLIB_EXT) +endif + + # Replace libstdc++ path, which is also moving from `lib` to `../lib/julia`. +ifeq ($(OS),Linux) + $(call stringreplace,$(DESTDIR)$(shlibdir)/libjulia.$(JL_MAJOR_MINOR_SHLIB_EXT),\*libstdc++\.so\.6$$,*$(call dep_lib_path,$(shlibdir),$(private_shlibdir)/libstdc++.so.6)) +endif + ifneq ($(LOADER_BUILD_DEP_LIBS),$(LOADER_INSTALL_DEP_LIBS)) # Next, overwrite relative path to libjulia-internal in our loader if $$(LOADER_BUILD_DEP_LIBS) != $$(LOADER_INSTALL_DEP_LIBS) diff --git a/NEWS.md b/NEWS.md index 62683964eb884..da7fcb356b5a1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -244,7 +244,8 @@ Deprecated or removed External dependencies --------------------- - +* On Linux, now autodetects the system libstdc++ version, and automatically loads the system library if it is newer. The old behavior of loading the bundled libstdc++ regardless of the system version obtained by setting the environment variable `JULIA_PROBE_LIBSTDCXX=0`. +* Removed `RPATH` from the julia binary. On Linux this may break libraries that have failed to set `RUNPATH`. Tooling Improvements --------------------- diff --git a/cli/Makefile b/cli/Makefile index 16b479954c724..bfbd2d8c75262 100644 --- a/cli/Makefile +++ b/cli/Makefile @@ -13,6 +13,8 @@ LOADER_LDFLAGS = $(JLDFLAGS) -ffreestanding -L$(build_shlibdir) -L$(build_libdir ifeq ($(OS),WINNT) LOADER_CFLAGS += -municode -mconsole -nostdlib -fno-stack-check -fno-stack-protector -mno-stack-arg-probe +else ifeq ($(OS),Linux) +LOADER_CFLAGS += -DGLIBCXX_LEAST_VERSION_SYMBOL=\"$(shell echo "$(CSL_NEXT_GLIBCXX_VERSION)" | cut -d'|' -f1 | sed 's/\\//g')\" endif ifeq ($(OS),WINNT) @@ -111,7 +113,7 @@ endif $(build_shlibdir)/libjulia.$(JL_MAJOR_MINOR_SHLIB_EXT): $(LIB_OBJS) $(SRCDIR)/list_strip_symbols.h | $(build_shlibdir) $(build_libdir) @$(call PRINT_LINK, $(CC) $(call IMPLIB_FLAGS,$@.tmp) $(LOADER_CFLAGS) -DLIBRARY_EXPORTS -shared $(SHIPFLAGS) $(LIB_OBJS) -o $@ \ - $(JLIBLDFLAGS) $(LOADER_LDFLAGS) $(RPATH_LIB) $(call SONAME_FLAGS,libjulia.$(JL_MAJOR_SHLIB_EXT))) + $(JLIBLDFLAGS) $(LOADER_LDFLAGS) $(call SONAME_FLAGS,libjulia.$(JL_MAJOR_SHLIB_EXT))) @$(INSTALL_NAME_CMD)libjulia.$(SHLIB_EXT) $@ ifeq ($(OS), WINNT) @# Note that if the objcopy command starts getting too long, we can use `@file` to read @@ -121,7 +123,7 @@ endif $(build_shlibdir)/libjulia-debug.$(JL_MAJOR_MINOR_SHLIB_EXT): $(LIB_DOBJS) $(SRCDIR)/list_strip_symbols.h | $(build_shlibdir) $(build_libdir) @$(call PRINT_LINK, $(CC) $(call IMPLIB_FLAGS,$@.tmp) $(LOADER_CFLAGS) -DLIBRARY_EXPORTS -shared $(DEBUGFLAGS) $(LIB_DOBJS) -o $@ \ - $(JLIBLDFLAGS) $(LOADER_LDFLAGS) $(RPATH_LIB) $(call SONAME_FLAGS,libjulia-debug.$(JL_MAJOR_SHLIB_EXT))) + $(JLIBLDFLAGS) $(LOADER_LDFLAGS) $(call SONAME_FLAGS,libjulia-debug.$(JL_MAJOR_SHLIB_EXT))) @$(INSTALL_NAME_CMD)libjulia-debug.$(SHLIB_EXT) $@ ifeq ($(OS), WINNT) @$(call PRINT_ANALYZE, $(OBJCOPY) $(build_libdir)/$(notdir $@).tmp.a $(STRIP_EXPORTED_FUNCS) $(build_libdir)/$(notdir $@).a && rm $(build_libdir)/$(notdir $@).tmp.a) diff --git a/cli/loader_lib.c b/cli/loader_lib.c index 0301b6eedde62..0069f9e793a1e 100644 --- a/cli/loader_lib.c +++ b/cli/loader_lib.c @@ -16,7 +16,7 @@ extern "C" { #endif // Save DEP_LIBS to a variable that is explicitly sized for expansion -static char dep_libs[1024] = DEP_LIBS; +static char dep_libs[1024] = "\0" DEP_LIBS; JL_DLLEXPORT void jl_loader_print_stderr(const char * msg) { @@ -33,7 +33,6 @@ void jl_loader_print_stderr3(const char * msg1, const char * msg2, const char * /* Wrapper around dlopen(), with extra relative pathing thrown in*/ static void * load_library(const char * rel_path, const char * src_dir, int err) { void * handle = NULL; - // See if a handle is already open to the basename const char *basename = rel_path + strlen(rel_path); while (basename-- > rel_path) @@ -147,6 +146,174 @@ JL_DLLEXPORT const char * jl_get_libdir() return lib_dir; } +// On Linux, it can happen that the system has a newer libstdc++ than the one we ship, +// which can break loading of some system libraries: . +// As a fix, on linux we probe the system libstdc++ to see if it is newer, and then load it if it is. +// Otherwise, we load the bundled one. This improves compatibility with third party dynamic libs that +// may depend on symbols exported by the system libstdxc++. +#ifdef _OS_LINUX_ +#ifndef GLIBCXX_LEAST_VERSION_SYMBOL +#warning GLIBCXX_LEAST_VERSION_SYMBOL should always be defined in the makefile. +#define GLIBCXX_LEAST_VERSION_SYMBOL "GLIBCXX_a.b.c" /* Appease the linter */ +#endif + +#include +#include + +// write(), but handle errors and avoid EINTR +static void write_wrapper(int fd, const char *str, size_t len) +{ + size_t written_sofar = 0; + while (len) { + ssize_t bytes_written = write(fd, str + written_sofar, len); + if (bytes_written == -1 && errno == EINTR) continue; + if (bytes_written == -1 && errno != EINTR) { + perror("(julia) child libstdcxxprobe write"); + _exit(1); + } + len -= bytes_written; + written_sofar += bytes_written; + } +} + +// read(), but handle errors and avoid EINTR +static void read_wrapper(int fd, char **ret, size_t *ret_len) +{ + // Allocate an initial buffer + size_t len = JL_PATH_MAX; + char *buf = (char *)malloc(len + 1); + if (!buf) { + perror("(julia) malloc"); + exit(1); + } + + // Read into it, reallocating as necessary + size_t have_read = 0; + while (1) { + ssize_t n = read(fd, buf + have_read, len - have_read); + have_read += n; + if (n == 0) break; + if (n == -1 && errno != EINTR) { + perror("(julia) libstdcxxprobe read"); + exit(1); + } + if (n == -1 && errno == EINTR) continue; + if (have_read == len) { + buf = (char *)realloc(buf, 1 + (len *= 2)); + if (!buf) { + perror("(julia) realloc"); + exit(1); + } + } + } + + *ret = buf; + *ret_len = have_read; +} + +// Return the path to the libstdcxx to load. +// If the path is found, return it. +// Otherwise, print the error and exit. +// The path returned must be freed. +static char *libstdcxxprobe(void) +{ + // Create the pipe and child process. + int fork_pipe[2]; + int ret = pipe(fork_pipe); + if (ret == -1) { + perror("(julia) Error during libstdcxxprobe: pipe"); + exit(1); + } + pid_t pid = fork(); + if (pid == -1) { + perror("Error during libstdcxxprobe:\nfork"); + exit(1); + } + if (pid == (pid_t) 0) { // Child process. + close(fork_pipe[0]); + + // Open the first available libstdc++.so. + // If it can't be found, report so by exiting zero. + // The star is there to prevent the compiler from merging constants + // with "\0*libstdc++.so.6", which we string replace inside the .so during + // make install. + void *handle = dlopen("libstdc++.so.6\0*", RTLD_LAZY); + if (!handle) { + _exit(0); + } + + // See if the version is compatible + char *dlerr = dlerror(); // clear out dlerror + void *sym = dlsym(handle, GLIBCXX_LEAST_VERSION_SYMBOL); + dlerr = dlerror(); + if (dlerr) { + // We can't use the library that was found, so don't write anything. + // The main process will see that nothing was written, + // then exit the function and return null. + _exit(0); + } + + // No error means the symbol was found, we can use this library. + // Get the path to it, and write it to the parent process. + struct link_map *lm; + ret = dlinfo(handle, RTLD_DI_LINKMAP, &lm); + if (ret == -1) { + char *errbuf = dlerror(); + char *errdesc = (char*)"Error during libstdcxxprobe in child process:\ndlinfo: "; + write_wrapper(STDERR_FILENO, errdesc, strlen(errdesc)); + write_wrapper(STDERR_FILENO, errbuf, strlen(errbuf)); + write_wrapper(STDERR_FILENO, "\n", 1); + _exit(1); + } + char *libpath = lm->l_name; + write_wrapper(fork_pipe[1], libpath, strlen(libpath)); + _exit(0); + } + else { // Parent process. + close(fork_pipe[1]); + + // Read the absolute path to the lib from the child process. + char *path; + size_t pathlen; + read_wrapper(fork_pipe[0], &path, &pathlen); + + // Close the read end of the pipe + close(fork_pipe[0]); + + // Wait for the child to complete. + while (1) { + int wstatus; + pid_t npid = waitpid(pid, &wstatus, 0); + if (npid == -1) { + if (errno == EINTR) continue; + if (errno != EINTR) { + perror("Error during libstdcxxprobe in parent process:\nwaitpid"); + exit(1); + } + } + else if (!WIFEXITED(wstatus)) { + const char *err_str = "Error during libstdcxxprobe in parent process:\n" + "The child process did not exit normally.\n"; + size_t err_strlen = strlen(err_str); + write_wrapper(STDERR_FILENO, err_str, err_strlen); + exit(1); + } + else if (WEXITSTATUS(wstatus)) { + // The child has printed an error and exited, so the parent should exit too. + exit(1); + } + break; + } + + if (!pathlen) { + free(path); + return NULL; + } + return path; + } +} +#endif + void * libjulia_internal = NULL; __attribute__((constructor)) void jl_load_libjulia_internal(void) { // Only initialize this once @@ -155,11 +322,43 @@ __attribute__((constructor)) void jl_load_libjulia_internal(void) { } // Introspect to find our own path - const char * lib_dir = jl_get_libdir(); + const char *lib_dir = jl_get_libdir(); // Pre-load libraries that libjulia-internal needs. - int deps_len = strlen(dep_libs); - char * curr_dep = &dep_libs[0]; + int deps_len = strlen(&dep_libs[1]); + char *curr_dep = &dep_libs[1]; + + void *cxx_handle; + +#if defined(_OS_LINUX_) + int do_probe = 1; + int done_probe = 0; + char *probevar = getenv("JULIA_PROBE_LIBSTDCXX"); + if (probevar) { + if (strcmp(probevar, "1") == 0 || strcmp(probevar, "yes") == 0) + do_probe = 1; + else if (strcmp(probevar, "0") == 0 || strcmp(probevar, "no") == 0) + do_probe = 0; + } + if (do_probe) { + char *cxxpath = libstdcxxprobe(); + if (cxxpath) { + cxx_handle = dlopen(cxxpath, RTLD_LAZY); + char *dlr = dlerror(); + if (dlr) { + jl_loader_print_stderr("ERROR: Unable to dlopen(cxxpath) in parent!\n"); + jl_loader_print_stderr3("Message: ", dlr, "\n"); + exit(1); + } + free(cxxpath); + done_probe = 1; + } + } + if (!done_probe) { + const static char bundled_path[256] = "\0*libstdc++.so.6"; + load_library(&bundled_path[2], lib_dir, 1); + } +#endif // We keep track of "special" libraries names (ones whose name is prefixed with `@`) // which are libraries that we want to load in some special, custom way, such as @@ -183,7 +382,8 @@ __attribute__((constructor)) void jl_load_libjulia_internal(void) { } special_library_names[special_idx] = curr_dep + 1; special_idx += 1; - } else { + } + else { load_library(curr_dep, lib_dir, 1); } @@ -272,7 +472,7 @@ JL_DLLEXPORT int jl_load_repl(int argc, char * argv[]) { } #ifdef _OS_WINDOWS_ -int __stdcall DllMainCRTStartup(void* instance, unsigned reason, void* reserved) { +int __stdcall DllMainCRTStartup(void *instance, unsigned reason, void *reserved) { setup_stdio(); // Because we override DllMainCRTStartup, we have to manually call our constructor methods diff --git a/deps/csl.mk b/deps/csl.mk index 0df2b92b6ce39..dd782880d21fd 100644 --- a/deps/csl.mk +++ b/deps/csl.mk @@ -12,17 +12,16 @@ endef # CSL bundles lots of system compiler libraries, and while it is quite bleeding-edge # as compared to what most distros ship, if someone tries to build an older branch, -# the version of CSL that ships with that branch may become relatively old. This is -# not a problem for code that is built in BB, but when we build Julia with the system +# the version of CSL that ships with that branch may be relatively old. This is not +# a problem for code that is built in BB, but when we build Julia with the system # compiler, that compiler uses the version of `libstdc++` that it is bundled with, -# and we can get linker errors when trying to run that `julia` executable with the +# and we can get linker errors when trying to run that `julia` executable with the # `libstdc++` that comes from the (now old) BB-built CSL. # # To fix this, we take note when the system `libstdc++.so` is newer than whatever we # would get from CSL (by searching for a `GLIBCXX_3.4.X` symbol that does not exist # in our CSL, but would in a newer one), and default to `USE_BINARYBUILDER_CSL=0` in # this case. -CSL_NEXT_GLIBCXX_VERSION=GLIBCXX_3\.4\.31|GLIBCXX_3\.5\.|GLIBCXX_4\. # First, check to see if BB is disabled on a global setting ifeq ($(USE_BINARYBUILDER),0) From b1830313862479c7cf65903ec50e1f355137eb31 Mon Sep 17 00:00:00 2001 From: Elliot Saba Date: Tue, 15 Nov 2022 09:36:14 -0800 Subject: [PATCH 08/26] Limit initial OpenBLAS thread count (#46844) * Limit initial OpenBLAS thread count We set OpenBLAS's initial thread count to `1` to prevent runaway allocation within OpenBLAS's initial thread startup. LinearAlgebra will later call `BLAS.set_num_threads()` to the actual value we require. * Support older names (cherry picked from commit 58b559f4a238faeeac03fbdec181ededd27053bc) --- stdlib/OpenBLAS_jll/src/OpenBLAS_jll.jl | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/stdlib/OpenBLAS_jll/src/OpenBLAS_jll.jl b/stdlib/OpenBLAS_jll/src/OpenBLAS_jll.jl index f656621d957d6..c57dd15bb1930 100644 --- a/stdlib/OpenBLAS_jll/src/OpenBLAS_jll.jl +++ b/stdlib/OpenBLAS_jll/src/OpenBLAS_jll.jl @@ -37,6 +37,19 @@ function __init__() ENV["OPENBLAS_MAIN_FREE"] = "1" end + # Ensure that OpenBLAS does not grab a huge amount of memory at first, + # since it instantly allocates scratch buffer space for the number of + # threads it thinks it needs to use. + # X-ref: https://github.com/xianyi/OpenBLAS/blob/c43ec53bdd00d9423fc609d7b7ecb35e7bf41b85/README.md#setting-the-number-of-threads-using-environment-variables + # X-ref: https://github.com/JuliaLang/julia/issues/45434 + if !haskey(ENV, "OPENBLAS_NUM_THREADS") && + !haskey(ENV, "GOTO_NUM_THREADS") && + !haskey(ENV, "OMP_NUM_THREADS") + # We set this to `1` here, and then LinearAlgebra will update + # to the true value in its `__init__()` function. + ENV["OPENBLAS_NUM_THREADS"] = "1" + end + global libopenblas_handle = dlopen(libopenblas) global libopenblas_path = dlpath(libopenblas_handle) global artifact_dir = dirname(Sys.BINDIR) From b19b2c15da18ccb002c17f548194a0ff3d781bea Mon Sep 17 00:00:00 2001 From: Valentin Churavy Date: Sun, 20 Nov 2022 14:45:20 -0500 Subject: [PATCH 09/26] Turn on Intel jitevents by default on Linux (#47586) (cherry picked from commit bba41d41319aa898373784438bd38873eab1da41) --- Make.inc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Make.inc b/Make.inc index 02b73aeadfaf5..ce2590b2f5a8b 100644 --- a/Make.inc +++ b/Make.inc @@ -73,7 +73,7 @@ JULIA_THREADS := 1 # Set to 1 to enable profiling with OProfile USE_OPROFILE_JITEVENTS ?= 0 -# USE_PERF_JITEVENTS defined below since default is OS specific +# USE_PERF_JITEVENTS, and USE_INTEL_JITEVENTS defined below since default is OS specific # assume we don't have LIBSSP support in our compiler, will enable later if likely true HAVE_SSP := 0 @@ -437,8 +437,10 @@ endif # Set to 1 to enable profiling with perf ifeq ("$(OS)", "Linux") USE_PERF_JITEVENTS ?= 1 +USE_INTEL_JITEVENTS ?= 1 else USE_PERF_JITEVENTS ?= 0 +USE_INTEL_JITEVENTS ?= 0 endif JULIACODEGEN := LLVM From 54a62647d844e00143b873760e206169abcea8e3 Mon Sep 17 00:00:00 2001 From: Elliot Saba Date: Thu, 24 Nov 2022 07:42:49 -0800 Subject: [PATCH 10/26] Filesystem: `rm(; recursive=true)` should ignore `UV_EACCES` (#47668) The command-line program `rm` has no problem deleting an empty directory that we do not have listing permissions on, so we should follow suit. Example: ``` mktempdir() do dir mkpath("$(dir)/foo") chmod("$(dir)/foo", 0o200) rm(dir; recursive=true) end ``` (cherry picked from commit d0a211a9209d25b1297693c562fc3a679204a0c6) --- base/file.jl | 2 +- test/file.jl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/base/file.jl b/base/file.jl index afab2177e061f..b2daf51ca369f 100644 --- a/base/file.jl +++ b/base/file.jl @@ -294,7 +294,7 @@ function rm(path::AbstractString; force::Bool=false, recursive::Bool=false) rm(joinpath(path, p), force=force, recursive=true) end catch err - if !(force && isa(err, IOError) && err.code==Base.UV_EACCES) + if !(isa(err, IOError) && err.code==Base.UV_EACCES) rethrow(err) end end diff --git a/test/file.jl b/test/file.jl index a7c0b6dca125d..ac28aa3badac3 100644 --- a/test/file.jl +++ b/test/file.jl @@ -1519,11 +1519,11 @@ if !Sys.iswindows() chmod(joinpath(d, "empty_outer", "empty_inner"), 0o333) # Test that an empty directory, even when we can't read its contents, is deletable - rm(joinpath(d, "empty_outer"); recursive=true, force=true) + rm(joinpath(d, "empty_outer"); recursive=true) @test !isdir(joinpath(d, "empty_outer")) # But a non-empty directory is not - @test_throws Base.IOError rm(joinpath(d, "nonempty"); recursive=true, force=true) + @test_throws Base.IOError rm(joinpath(d, "nonempty"); recursive=true) chmod(joinpath(d, "nonempty"), 0o777) rm(joinpath(d, "nonempty"); recursive=true, force=true) @test !isdir(joinpath(d, "nonempty")) From 6dad6c56432334b4aba6ee3062466737897269ac Mon Sep 17 00:00:00 2001 From: Rashid Rafeek Date: Mon, 28 Nov 2022 12:14:05 +0530 Subject: [PATCH 11/26] Fix REPL keybinding CTRL-Q for stdlib methods (#47637) (cherry picked from commit 7514bcf0bda547012f19a071daa132c3e8e97613) --- stdlib/REPL/src/REPL.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 3308760046d4e..472e3fd2c3985 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -1203,7 +1203,7 @@ function setup_interface( @goto writeback end try - InteractiveUtils.edit(linfos[n][1], linfos[n][2]) + InteractiveUtils.edit(Base.fixup_stdlib_path(linfos[n][1]), linfos[n][2]) catch ex ex isa ProcessFailedException || ex isa Base.IOError || ex isa SystemError || rethrow() @info "edit failed" _exception=ex From 70c8dc2ee2fddf8e61d42d53e0a1dd82b7df360d Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Mon, 28 Nov 2022 12:17:27 +0100 Subject: [PATCH 12/26] fix 5-arg `mul!` for vectors of vectors (#47665) Co-authored-by: N5N3 <2642243996@qq.com> (cherry picked from commit 902e8a7c2f7ba45aa35b8f5de4c2840a306a1958) --- stdlib/LinearAlgebra/src/matmul.jl | 2 +- stdlib/LinearAlgebra/test/matmul.jl | 52 +++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index 80d9872fdca6e..67476a23052c3 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -807,7 +807,7 @@ function generic_matvecmul!(C::AbstractVector{R}, tA, A::AbstractVecOrMat, B::Ab end for k = 1:mB aoffs = (k-1)*Astride - b = _add(B[k], false) + b = _add(B[k]) for i = 1:mA C[i] += A[aoffs + i] * b end diff --git a/stdlib/LinearAlgebra/test/matmul.jl b/stdlib/LinearAlgebra/test/matmul.jl index ea73814a2848b..0cb8258edb12b 100644 --- a/stdlib/LinearAlgebra/test/matmul.jl +++ b/stdlib/LinearAlgebra/test/matmul.jl @@ -156,6 +156,58 @@ end end end +@testset "generic_matvecmul for vectors of vectors" begin + @testset "matrix of scalars" begin + u = [[1, 2], [3, 4]] + A = [1 2; 3 4] + v = [[0, 0], [0, 0]] + Au = [[7, 10], [15, 22]] + @test A * u == Au + mul!(v, A, u) + @test v == Au + mul!(v, A, u, 2, -1) + @test v == Au + end + + @testset "matrix of matrices" begin + u = [[1, 2], [3, 4]] + A = Matrix{Matrix{Int}}(undef, 2, 2) + A[1, 1] = [1 2; 3 4] + A[1, 2] = [5 6; 7 8] + A[2, 1] = [9 10; 11 12] + A[2, 2] = [13 14; 15 16] + v = [[0, 0], [0, 0]] + Au = [[44, 64], [124, 144]] + @test A * u == Au + mul!(v, A, u) + @test v == Au + mul!(v, A, u, 2, -1) + @test v == Au + end +end + +@testset "generic_matmatmul for matrices of vectors" begin + B = Matrix{Vector{Int}}(undef, 2, 2) + B[1, 1] = [1, 2] + B[2, 1] = [3, 4] + B[1, 2] = [5, 6] + B[2, 2] = [7, 8] + A = [1 2; 3 4] + C = Matrix{Vector{Int}}(undef, 2, 2) + AB = Matrix{Vector{Int}}(undef, 2, 2) + AB[1, 1] = [7, 10] + AB[2, 1] = [15, 22] + AB[1, 2] = [19, 22] + AB[2, 2] = [43, 50] + @test A * B == AB + mul!(C, A, B) + @test C == AB + mul!(C, A, B, 2, -1) + @test C == AB + LinearAlgebra._generic_matmatmul!(C, 'N', 'N', A, B, LinearAlgebra.MulAddMul(2, -1)) + @test C == AB +end + @testset "fallbacks & such for BlasFloats" begin AA = rand(Float64, 6, 6) BB = rand(Float64, 6, 6) From 8abef03011736174a7e81a2311f3c04e73443ccc Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 2 Dec 2022 16:04:40 -0500 Subject: [PATCH 13/26] fix #47662, broken --compile=all on 1.8.x (#47678) --- src/gf.c | 17 +++++++++++++---- src/julia_internal.h | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/gf.c b/src/gf.c index f0dcdbb298528..49078f903b708 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1951,13 +1951,22 @@ JL_DLLEXPORT jl_value_t *jl_matching_methods(jl_tupletype_t *types, jl_value_t * return ml_matches((jl_methtable_t*)mt, types, lim, include_ambiguous, 1, world, 1, min_valid, max_valid, ambig); } -jl_method_instance_t *jl_get_unspecialized(jl_method_instance_t *method JL_PROPAGATES_ROOT) +jl_method_instance_t *jl_get_unspecialized_from_mi(jl_method_instance_t *method JL_PROPAGATES_ROOT) { - // one unspecialized version of a function can be shared among all cached specializations jl_method_t *def = method->def.method; + jl_method_instance_t *mi = jl_get_unspecialized(def); + if (mi == NULL) { + return method; + } + return mi; +} + +jl_method_instance_t *jl_get_unspecialized(jl_method_t *def JL_PROPAGATES_ROOT) +{ + // one unspecialized version of a function can be shared among all cached specializations if (!jl_is_method(def) || def->source == NULL) { // generated functions might instead randomly just never get inferred, sorry - return method; + return NULL; } if (def->unspecialized == NULL) { JL_LOCK(&def->writelock); @@ -2078,7 +2087,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t codeinst = jl_generate_fptr(mi, world); if (!codeinst) { - jl_method_instance_t *unspec = jl_get_unspecialized(mi); + jl_method_instance_t *unspec = jl_get_unspecialized_from_mi(mi); jl_code_instance_t *ucache = jl_get_method_inferred(unspec, (jl_value_t*)jl_any_type, 1, ~(size_t)0); // ask codegen to make the fptr for unspec if (jl_atomic_load_relaxed(&ucache->invoke) == NULL) { diff --git a/src/julia_internal.h b/src/julia_internal.h index 0906782640406..c5516c01315d6 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -526,7 +526,7 @@ void jl_generate_fptr_for_unspecialized(jl_code_instance_t *unspec); JL_DLLEXPORT jl_code_instance_t *jl_get_method_inferred( jl_method_instance_t *mi JL_PROPAGATES_ROOT, jl_value_t *rettype, size_t min_world, size_t max_world); -jl_method_instance_t *jl_get_unspecialized(jl_method_instance_t *method JL_PROPAGATES_ROOT); +jl_method_instance_t *jl_get_unspecialized(jl_method_t *def JL_PROPAGATES_ROOT); JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types); jl_code_info_t *jl_code_for_interpreter(jl_method_instance_t *lam JL_PROPAGATES_ROOT); From 23ce8ab812e8e50b45cf8ebfae05deb77fbc5290 Mon Sep 17 00:00:00 2001 From: Paul Berg Date: Sat, 2 Apr 2022 11:39:38 +0200 Subject: [PATCH 14/26] Fix implicit binding import for aliased bindings (#44827) `b->name` is used to lookup in `b->owner`, not `var`. (cherry picked from commit dbe41d44ec8677232cbf8faddf97a66d8d901647) --- src/module.c | 2 +- test/syntax.jl | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/module.c b/src/module.c index 63dff3ae6deb7..59731e8b5ba80 100644 --- a/src/module.c +++ b/src/module.c @@ -352,7 +352,7 @@ static jl_binding_t *jl_get_binding_(jl_module_t *m, jl_sym_t *var, modstack_t * // do a full import to prevent the result of this lookup // from changing, for example if this var is assigned to // later. - module_import_(m, b->owner, var, var, 0); + module_import_(m, b->owner, b->name, var, 0); return b; } return NULL; diff --git a/test/syntax.jl b/test/syntax.jl index 6ed3e7ca59ad7..795b69c9eea05 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -2520,7 +2520,10 @@ end module Mod2 import ..Mod.x as x_from_mod +import ..Mod.x as x_from_mod2 const y = 2 + +export x_from_mod2 end import .Mod: x as x2 @@ -2565,6 +2568,12 @@ import .Mod2.x_from_mod @test @isdefined(x_from_mod) @test x_from_mod == Mod.x + +using .Mod2 + +@test_nowarn @eval x_from_mod2 +@test @isdefined(x_from_mod2) +@test x_from_mod2 == x_from_mod == Mod.x end import .TestImportAs.Mod2 as M2 From 489888244886c2d5d60dcf005acbcfa6f2b5234d Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Tue, 5 Jul 2022 13:31:53 +0200 Subject: [PATCH 15/26] Add compat to `@test_throws` (#45893) closes #45892 (cherry picked from commit 59ff2e5a4da772216449df825fd0111dc2d3f643) --- stdlib/Test/src/Test.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index b9be89826cd20..6c642659462b6 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -680,6 +680,9 @@ a matching function, or a value (which will be tested for equality by comparing fields). Note that `@test_throws` does not support a trailing keyword form. +!!! compat "Julia 1.8" + The ability to specify anything other than a type or a value as `exception` requires Julia v1.8 or later. + # Examples ```jldoctest julia> @test_throws BoundsError [1, 2, 3][4] From 2950963ff5be7f32b4666176b58b0651a962817a Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 29 Nov 2022 18:48:15 -0500 Subject: [PATCH 16/26] Fix generator-invocation legality check for varargs generators (#47739) This code was introduced by me back in #31025 to speed up evaluation of generated functions that didn't make use of all of their arguments to make generation decisions. However, it neglected to take into account the possibility that the generator could be varargs. As a result, an unfortunate coincidence of an unused slot in the correct position could have allowed expansion of generators that were not supposed to be expandable. This can cause incorrect inference with all the usual consequences. However, fortunately this coincidence appears to be pretty rare. Fixes https://github.com/JuliaDebug/CassetteOverlay.jl/issues/12 (cherry picked from commit 328dd578958d9c2a22ddb11970324ecd04e94314) --- base/reflection.jl | 14 +++++++++++++- test/staged.jl | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/base/reflection.jl b/base/reflection.jl index 223d5fab040e3..25f0024c01e91 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -1155,13 +1155,25 @@ function may_invoke_generator(method::Method, @nospecialize(atype), sparams::Sim end end end - for i = 1:length(at.parameters) + non_va_args = method.isva ? method.nargs - 1 : method.nargs + for i = 1:non_va_args if !isdispatchelem(at.parameters[i]) if (ast_slotflag(code, 1 + i + nsparams) & SLOT_USED) != 0 return false end end end + if method.isva + # If the va argument is used, we need to ensure that all arguments that + # contribute to the va tuple are dispatchelemes + if (ast_slotflag(code, 1 + method.nargs + nsparams) & SLOT_USED) != 0 + for i = (non_va_args+1):length(at.parameters) + if !isdispatchelem(at.parameters[i]) + return false + end + end + end + end return true end diff --git a/test/staged.jl b/test/staged.jl index b99ef46a2bc1e..516baea93ec04 100644 --- a/test/staged.jl +++ b/test/staged.jl @@ -305,3 +305,18 @@ end end @test f33243() === 2 @test x33243 === 2 + +# https://github.com/JuliaDebug/CassetteOverlay.jl/issues/12 +# generated function with varargs and unfortunately placed unused slot +@generated function f_vararg_generated(args...) + :($args) +end +g_vararg_generated() = f_vararg_generated((;), (;), Base.inferencebarrier((;))) +let tup = g_vararg_generated() + @test !any(==(Any), tup) + # This is just to make sure that the test is actually testing what we want - + # the test only works if there's an unused that matches the position of the + # inferencebarrier argument above (N.B. the generator function itself + # shifts everything over by 1) + @test code_lowered(first(methods(f_vararg_generated)).generator.gen)[1].slotflags[5] == UInt8(0x00) +end From c1d3df67e5dfeefc7836514cb8c751112d2e6199 Mon Sep 17 00:00:00 2001 From: Valentin Churavy Date: Sat, 3 Dec 2022 20:46:27 -0500 Subject: [PATCH 17/26] Prioritize build_dir for generated headers (#47783) (cherry picked from commit 0feaf5cc3a6cec0a4f056e4e72ed6469769268a4) --- src/julia.h | 6 ++++-- src/julia_internal.h | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/julia.h b/src/julia.h index 9cdf124fccaa7..df637670dca6d 100644 --- a/src/julia.h +++ b/src/julia.h @@ -4,7 +4,9 @@ #define JULIA_H #ifdef LIBRARY_EXPORTS -#include "jl_internal_funcs.inc" +// Generated file, needs to be searched in include paths so that the builddir +// retains priority +#include #undef jl_setjmp #undef jl_longjmp #undef jl_egal @@ -2140,7 +2142,7 @@ JL_DLLEXPORT int jl_generating_output(void) JL_NOTSAFEPOINT; #define JL_OPTIONS_USE_COMPILED_MODULES_NO 0 // Version information -#include "julia_version.h" +#include // Generated file JL_DLLEXPORT extern int jl_ver_major(void); JL_DLLEXPORT extern int jl_ver_minor(void); diff --git a/src/julia_internal.h b/src/julia_internal.h index c5516c01315d6..65503d472b352 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -1541,7 +1541,9 @@ JL_DLLEXPORT uint16_t julia__truncdfhf2(double param) JL_NOTSAFEPOINT; #endif #ifdef USE_DTRACE -#include "uprobes.h.gen" +// Generated file, needs to be searched in include paths so that the builddir +// retains priority +#include // uprobes.h.gen on systems with DTrace, is auto-generated to include // `JL_PROBE_{PROBE}` and `JL_PROBE_{PROBE}_ENABLED()` macros for every probe From 579f84f2c311a2430f0551a4ad238435074bd4a3 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Sat, 10 Dec 2022 17:24:55 +0100 Subject: [PATCH 18/26] Fix physical_memory exports. (#47859) (cherry picked from commit 5a6c80828698d58405ca38b27628d426665324b5) --- base/sysinfo.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/sysinfo.jl b/base/sysinfo.jl index 62241457f8954..fc9640886074c 100644 --- a/base/sysinfo.jl +++ b/base/sysinfo.jl @@ -20,8 +20,8 @@ export BINDIR, loadavg, free_memory, total_memory, - physical_free_memory, - physical_total_memory, + free_physical_memory, + total_physical_memory, isapple, isbsd, isdragonfly, From 964f86d14b759cf1a28731bb429894a7cd21a3a4 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 16 Nov 2022 11:17:34 -0500 Subject: [PATCH 19/26] fix #47410, syntax error with anonfn inside `elseif` and short-circuit op (#47499) (cherry picked from commit 5f256e7d6bbe8248b58af5c1abbf8f8715522b0b) --- src/julia-syntax.scm | 3 +++ test/syntax.jl | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index ed5a25961df88..cbb4f75f3b2ec 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -4309,6 +4309,9 @@ f(x) = yt(x) cnd))) (define (emit-cond cnd break-labels endl) (let* ((cnd (if (and (pair? cnd) (eq? (car cnd) 'block)) + (flatten-ex 'block cnd) + cnd)) + (cnd (if (and (pair? cnd) (eq? (car cnd) 'block)) (begin (if (length> cnd 2) (compile (butlast cnd) break-labels #f #f)) (last cnd)) cnd)) diff --git a/test/syntax.jl b/test/syntax.jl index 795b69c9eea05..938e737d1305b 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -3297,3 +3297,10 @@ f45162(f) = f(x=1) @test Meta.lower(@__MODULE__, :(global const x::Int)) == Expr(:error, "expected assignment after \"const\"") @test Meta.lower(@__MODULE__, :(const global x)) == Expr(:error, "expected assignment after \"const\"") @test Meta.lower(@__MODULE__, :(const global x::Int)) == Expr(:error, "expected assignment after \"const\"") + +# issue #47410 +# note `eval` is needed since this needs to be at the top level +@test eval(:(if false + elseif false || (()->true)() + 42 + end)) == 42 From f5c000e19cfdbccca8e45fdc5319e1dc068db3a8 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 16 Nov 2022 16:17:00 -0500 Subject: [PATCH 20/26] ensure bindings handle write barriers for ty and globalref (#47580) This has probably been wrong for a long time (since being introduced in 79082468986). (cherry picked from commit b36951160ef0ba8c4641dd768cd7a1f5f570d0a9) --- src/gc.c | 11 ++++++++++- src/module.c | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/gc.c b/src/gc.c index 893b76139b7e6..42c4bc84c8460 100644 --- a/src/gc.c +++ b/src/gc.c @@ -3045,8 +3045,17 @@ static void jl_gc_queue_remset(jl_gc_mark_cache_t *gc_cache, jl_gc_mark_sp_t *sp jl_binding_t *ptr = (jl_binding_t*)items[i]; // A null pointer can happen here when the binding is cleaned up // as an exception is thrown after it was already queued (#10221) + int bnd_refyoung = 0; jl_value_t *v = jl_atomic_load_relaxed(&ptr->value); - if (v != NULL && gc_mark_queue_obj(gc_cache, sp, v)) { + if (v != NULL && gc_mark_queue_obj(gc_cache, sp, v)) + bnd_refyoung = 1; + jl_value_t *ty = jl_atomic_load_relaxed(&ptr->ty); + if (ty != NULL && gc_mark_queue_obj(gc_cache, sp, ty)) + bnd_refyoung = 1; + jl_value_t *globalref = jl_atomic_load_relaxed(&ptr->globalref); + if (globalref != NULL && gc_mark_queue_obj(gc_cache, sp, globalref)) + bnd_refyoung = 1; + if (bnd_refyoung) { items[n_bnd_refyoung] = ptr; n_bnd_refyoung++; } diff --git a/src/module.c b/src/module.c index 59731e8b5ba80..0223ba60095cd 100644 --- a/src/module.c +++ b/src/module.c @@ -419,7 +419,7 @@ JL_DLLEXPORT jl_value_t *jl_module_globalref(jl_module_t *m, jl_sym_t *var) if (jl_atomic_cmpswap_relaxed(&b->globalref, &globalref, newref)) { JL_GC_PROMISE_ROOTED(newref); globalref = newref; - jl_gc_wb(m, globalref); + jl_gc_wb_binding(b, globalref); } } JL_UNLOCK(&m->lock); // may GC From 4e152d4361b83d59fbbf9d9b0ee0e3cf5296e600 Mon Sep 17 00:00:00 2001 From: Simeon Schaub Date: Thu, 1 Dec 2022 21:42:20 +0100 Subject: [PATCH 21/26] fix unescaping in `global` expressions (#47719) This fixes some issues around macro hygiene in `global` expressions. Apparently we always treat l-values in global expressions as being escaped, but we still need to be careful to handle type annotations and destructuring correctly. (cherry picked from commit cc25a1369472756c63c4da81abbc106e2790b4f0) --- src/macroexpand.scm | 29 +++++++++++++++++++++-------- test/syntax.jl | 23 +++++++++++++++++++++++ 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/macroexpand.scm b/src/macroexpand.scm index 516dd9b29f354..2933ca4888c4e 100644 --- a/src/macroexpand.scm +++ b/src/macroexpand.scm @@ -183,6 +183,19 @@ (cadr e) e)) +(define (unescape-global-lhs e env m parent-scope inarg) + (cond ((not (pair? e)) e) + ((eq? (car e) 'escape) (cadr e)) + ((memq (car e) '(parameters tuple)) + (list* (car e) (map (lambda (e) + (unescape-global-lhs e env m parent-scope inarg)) + (cdr e)))) + ((and (memq (car e) '(|::| kw)) (length= e 3)) + (list (car e) (unescape-global-lhs (cadr e) env m parent-scope inarg) + (resolve-expansion-vars-with-new-env (caddr e) env m parent-scope inarg))) + (else + (resolve-expansion-vars-with-new-env e env m parent-scope inarg)))) + (define (typedef-expr-name e) (cond ((atom? e) e) ((or (eq? (car e) 'curly) (eq? (car e) '<:)) (typedef-expr-name (cadr e))) @@ -344,14 +357,14 @@ (m (cadr scope)) (parent-scope (cdr parent-scope))) (resolve-expansion-vars-with-new-env (cadr e) env m parent-scope inarg)))) - ((global) (let ((arg (cadr e))) - (cond ((symbol? arg) e) - ((assignment? arg) - `(global - (= ,(unescape (cadr arg)) - ,(resolve-expansion-vars-with-new-env (caddr arg) env m parent-scope inarg)))) - (else - `(global ,(resolve-expansion-vars-with-new-env arg env m parent-scope inarg)))))) + ((global) + `(global + ,@(map (lambda (arg) + (if (assignment? arg) + `(= ,(unescape-global-lhs (cadr arg) env m parent-scope inarg) + ,(resolve-expansion-vars-with-new-env (caddr arg) env m parent-scope inarg)) + (unescape-global-lhs arg env m parent-scope inarg))) + (cdr e)))) ((using import export meta line inbounds boundscheck loopinfo inline noinline) (map unescape e)) ((macrocall) e) ; invalid syntax anyways, so just act like it's quoted. ((symboliclabel) e) diff --git a/test/syntax.jl b/test/syntax.jl index 938e737d1305b..b828b45bc23b5 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -3304,3 +3304,26 @@ f45162(f) = f(x=1) elseif false || (()->true)() 42 end)) == 42 + +macro _macroexpand(x, m=__module__) + :($__source__; macroexpand($m, Expr(:var"hygienic-scope", $(esc(Expr(:quote, x))), $m))) +end + +@testset "unescaping in :global expressions" begin + m = @__MODULE__ + @test @_macroexpand(global x::T) == :(global x::$(GlobalRef(m, :T))) + @test @_macroexpand(global (x, $(esc(:y)))) == :(global (x, y)) + @test @_macroexpand(global (x::S, $(esc(:y))::$(esc(:T)))) == + :(global (x::$(GlobalRef(m, :S)), y::T)) + @test @_macroexpand(global (; x, $(esc(:y)))) == :(global (; x, y)) + @test @_macroexpand(global (; x::S, $(esc(:y))::$(esc(:T)))) == + :(global (; x::$(GlobalRef(m, :S)), y::T)) + + @test @_macroexpand(global x::T = a) == :(global x::$(GlobalRef(m, :T)) = $(GlobalRef(m, :a))) + @test @_macroexpand(global (x, $(esc(:y))) = a) == :(global (x, y) = $(GlobalRef(m, :a))) + @test @_macroexpand(global (x::S, $(esc(:y))::$(esc(:T))) = a) == + :(global (x::$(GlobalRef(m, :S)), y::T) = $(GlobalRef(m, :a))) + @test @_macroexpand(global (; x, $(esc(:y))) = a) == :(global (; x, y) = $(GlobalRef(m, :a))) + @test @_macroexpand(global (; x::S, $(esc(:y))::$(esc(:T))) = a) == + :(global (; x::$(GlobalRef(m, :S)), y::T) = $(GlobalRef(m, :a))) +end From 8830c265eb1813bbf98b5fd7bb39a44b88892b7f Mon Sep 17 00:00:00 2001 From: Elliot Saba Date: Mon, 5 Dec 2022 14:40:25 -0500 Subject: [PATCH 22/26] Set `OPENBLAS_NUM_THREADS=1` on local Distributed workers (#47803) This should prevent LinearAlgebra from trying to increase our OpenBLAS thread count in its `__init__()` method when we're not trying to enable threaded BLAS. (cherry picked from commit a8b399416208d91061324814ff8ae080a918e48b) --- stdlib/Distributed/src/cluster.jl | 1 + stdlib/Distributed/src/managers.jl | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/stdlib/Distributed/src/cluster.jl b/stdlib/Distributed/src/cluster.jl index b7268a7e053ee..37f1660e19478 100644 --- a/stdlib/Distributed/src/cluster.jl +++ b/stdlib/Distributed/src/cluster.jl @@ -536,6 +536,7 @@ default_addprocs_params() = Dict{Symbol,Any}( :dir => pwd(), :exename => joinpath(Sys.BINDIR, julia_exename()), :exeflags => ``, + :env => [], :enable_threaded_blas => false, :lazy => true) diff --git a/stdlib/Distributed/src/managers.jl b/stdlib/Distributed/src/managers.jl index e3ecb97767ae3..f5f2d877d8328 100644 --- a/stdlib/Distributed/src/managers.jl +++ b/stdlib/Distributed/src/managers.jl @@ -462,10 +462,18 @@ function launch(manager::LocalManager, params::Dict, launched::Array, c::Conditi exename = params[:exename] exeflags = params[:exeflags] bind_to = manager.restrict ? `127.0.0.1` : `$(LPROC.bind_addr)` + env = Dict{String,String}(params[:env]) + + # If we haven't explicitly asked for threaded BLAS, prevent OpenBLAS from starting + # up with multiple threads, thereby sucking up a bunch of wasted memory on Windows. + if !params[:enable_threaded_blas] && + get(env, "OPENBLAS_NUM_THREADS", nothing) === nothing + env["OPENBLAS_NUM_THREADS"] = "1" + end for i in 1:manager.np cmd = `$(julia_cmd(exename)) $exeflags --bind-to $bind_to --worker` - io = open(detach(setenv(cmd, dir=dir)), "r+") + io = open(detach(setenv(addenv(cmd, env), dir=dir)), "r+") write_cookie(io) wconfig = WorkerConfig() From fd92d743e41e44b453817ddf1657fd048c49b5d8 Mon Sep 17 00:00:00 2001 From: Sasank <56350738+sasi591@users.noreply.github.com> Date: Thu, 3 Nov 2022 16:17:53 +0530 Subject: [PATCH 23/26] Fix isdone for empty product iterators, fixes #43921 (#43947) * Fix the issue #43921 * add a test Co-authored-by: Kristoffer (cherry picked from commit b8a77daf3832d4134ad46327049772a663e2643d) --- base/iterators.jl | 1 + test/iterators.jl | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/base/iterators.jl b/base/iterators.jl index 3e339c59bebcb..e14880b6c0a33 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -1041,6 +1041,7 @@ iterate(::ProductIterator{Tuple{}}, state) = nothing done1 === true || return done1 # false or missing return _pisdone(tail(iters), tail(states)) # check tail end +@inline isdone(::ProductIterator{Tuple{}}, states) = true @inline isdone(P::ProductIterator, states) = _pisdone(P.iterators, states) @inline _piterate() = () diff --git a/test/iterators.jl b/test/iterators.jl index 0a038698ea07c..adf8d79e4429e 100644 --- a/test/iterators.jl +++ b/test/iterators.jl @@ -902,3 +902,11 @@ end @test last(Iterators.map(identity, 1:3)) == 3 @test last(Iterators.filter(iseven, (Iterators.map(identity, 1:3)))) == 2 end + +@testset "empty product iterators" begin + v = nothing + for (z,) in zip(Iterators.product()) + v = z + end + @test v == () +end From 5a1d35e33af4d32a781f7d2f27bac515b3cb1ec8 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Wed, 14 Dec 2022 09:01:17 +0100 Subject: [PATCH 24/26] Merge pull request #47741 from JuliaLang/jn/backports-release-1.8-47685 [release 1.8] backport of precompile: serialize the full edges graph (#46920) --- src/dump.c | 1048 +++++++++++++++++++++++-------------- src/gf.c | 11 +- src/jl_exported_funcs.inc | 1 - src/julia.h | 8 +- src/julia_internal.h | 8 +- src/typemap.c | 1 - test/precompile.jl | 58 +- 7 files changed, 720 insertions(+), 415 deletions(-) diff --git a/src/dump.c b/src/dump.c index 920a6981db095..2e2bb2b667919 100644 --- a/src/dump.c +++ b/src/dump.c @@ -104,7 +104,7 @@ static jl_array_t *newly_inferred JL_GLOBALLY_ROOTED; static htable_t queued_method_roots; // inverse of backedges graph (caller=>callees hash) -htable_t edges_map; +jl_array_t *edges_map JL_GLOBALLY_ROOTED; // rooted for the duration of our uses of this // list of requested ccallable signatures static arraylist_t ccallable_list; @@ -157,6 +157,22 @@ uint64_t jl_worklist_key(jl_array_t *worklist) return 0; } +// Use this in a `while` loop to iterate over the backedges in a MethodInstance. +// `*invokesig` will be NULL if the call was made by ordinary dispatch, otherwise +// it will be the signature supplied in an `invoke` call. +// If you don't need `invokesig`, you can set it to NULL on input. +// Initialize iteration with `i = 0`. Returns `i` for the next backedge to be extracted. +static int get_next_edge(jl_array_t *list, int i, jl_value_t** invokesig, jl_method_instance_t **caller) JL_NOTSAFEPOINT +{ + jl_value_t *item = jl_array_ptr_ref(list, i); + if (invokesig != NULL) + *invokesig = NULL; + assert(jl_is_method_instance(item)); + // Not an `invoke` call, it's just the MethodInstance + *caller = (jl_method_instance_t*)item; + return i + 1; +} + // --- serialize --- #define jl_serialize_value(s, v) jl_serialize_value_((s), (jl_value_t*)(v), 0) @@ -241,76 +257,139 @@ static int type_recursively_external(jl_datatype_t *dt) JL_NOTSAFEPOINT return 1; } +static void mark_backedges_in_worklist(jl_method_instance_t *mi, htable_t *visited, int found) +{ + int oldfound = (char*)ptrhash_get(visited, mi) - (char*)HT_NOTFOUND; + if (oldfound < 3) + return; // not in-progress + ptrhash_put(visited, mi, (void*)((char*)HT_NOTFOUND + 1 + found)); +#ifndef NDEBUG + jl_module_t *mod = mi->def.module; + if (jl_is_method(mod)) + mod = ((jl_method_t*)mod)->module; + assert(jl_is_module(mod)); + assert(!mi->precompiled && !module_in_worklist(mod)); + assert(mi->backedges); +#endif + size_t i = 0, n = jl_array_len(mi->backedges); + while (i < n) { + jl_method_instance_t *be; + i = get_next_edge(mi->backedges, i, NULL, &be); + mark_backedges_in_worklist(be, visited, found); + } +} + // When we infer external method instances, ensure they link back to the // package. Otherwise they might be, e.g., for external macros -static int has_backedge_to_worklist(jl_method_instance_t *mi, htable_t *visited) +static int has_backedge_to_worklist(jl_method_instance_t *mi, htable_t *visited, int depth) { - void **bp = ptrhash_bp(visited, mi); - // HT_NOTFOUND: not yet analyzed - // HT_NOTFOUND + 1: doesn't link back - // HT_NOTFOUND + 2: does link back - if (*bp != HT_NOTFOUND) - return (char*)*bp - (char*)HT_NOTFOUND - 1; - *bp = (void*)((char*)HT_NOTFOUND + 1); // preliminarily mark as "not found" - // TODO: this algorithm deals with cycles incorrectly jl_module_t *mod = mi->def.module; if (jl_is_method(mod)) mod = ((jl_method_t*)mod)->module; assert(jl_is_module(mod)); if (mi->precompiled || module_in_worklist(mod)) { - *bp = (void*)((char*)HT_NOTFOUND + 2); // found return 1; } if (!mi->backedges) { return 0; } - size_t i, n = jl_array_len(mi->backedges); - for (i = 0; i < n; i++) { - jl_method_instance_t *be = (jl_method_instance_t*)jl_array_ptr_ref(mi->backedges, i); - if (has_backedge_to_worklist(be, visited)) { - bp = ptrhash_bp(visited, mi); // re-acquire since rehashing might change the location - *bp = (void*)((char*)HT_NOTFOUND + 2); // found - return 1; + void **bp = ptrhash_bp(visited, mi); + // HT_NOTFOUND: not yet analyzed + // HT_NOTFOUND + 1: no link back + // HT_NOTFOUND + 2: does link back + // HT_NOTFOUND + 3 + depth: in-progress + int found = (char*)*bp - (char*)HT_NOTFOUND; + if (found) + return found - 1; + *bp = (void*)((char*)HT_NOTFOUND + 3 + depth); // preliminarily mark as in-progress + size_t i = 0, n = jl_array_len(mi->backedges); + int cycle = 0; + while (i < n) { + jl_method_instance_t *be; + i = get_next_edge(mi->backedges, i, NULL, &be); + int child_found = has_backedge_to_worklist(be, visited, depth + 1); + if (child_found == 1) { + found = 1; + break; + } + else if (child_found >= 2 && child_found - 2 < cycle) { + // record the cycle will resolve at depth "cycle" + cycle = child_found - 2; + assert(cycle); } } - return 0; + if (!found && cycle && cycle != depth) + return cycle + 2; + bp = ptrhash_bp(visited, mi); // re-acquire since rehashing might change the location + *bp = (void*)((char*)HT_NOTFOUND + 1 + found); + if (cycle) { + // If we are the top of the current cycle, now mark all other parts of + // our cycle by re-walking the backedges graph and marking all WIP + // items as found. + // Be careful to only re-walk as far as we had originally scanned above. + // Or if we found a backedge, also mark all of the other parts of the + // cycle as also having an backedge. + n = i; + i = 0; + while (i < n) { + jl_method_instance_t *be; + i = get_next_edge(mi->backedges, i, NULL, &be); + mark_backedges_in_worklist(be, visited, found); + } + } + return found; } // given the list of MethodInstances that were inferred during the // build, select those that are external and have at least one -// relocatable CodeInstance. -static size_t queue_external_mis(jl_array_t *list) +// relocatable CodeInstance and are inferred to be called from the worklist +// or explicitly added by a precompile statement. +// Also prepares external_mis for method_instance_in_queue queries. +static jl_array_t *queue_external_mis(jl_array_t *list) { + if (list == NULL) + return NULL; size_t i, n = 0; htable_t visited; - if (list) { - assert(jl_is_array(list)); - size_t n0 = jl_array_len(list); - htable_new(&visited, n0); - for (i = 0; i < n0; i++) { - jl_method_instance_t *mi = (jl_method_instance_t*)jl_array_ptr_ref(list, i); - assert(jl_is_method_instance(mi)); - if (jl_is_method(mi->def.value)) { - jl_method_t *m = mi->def.method; - if (!module_in_worklist(m->module)) { - jl_code_instance_t *ci = mi->cache; - int relocatable = 0; - while (ci) { - relocatable |= ci->relocatability; - ci = ci->next; - } - if (relocatable && ptrhash_get(&external_mis, mi) == HT_NOTFOUND) { - if (has_backedge_to_worklist(mi, &visited)) { - ptrhash_put(&external_mis, mi, mi); - n++; - } + assert(jl_is_array(list)); + size_t n0 = jl_array_len(list); + htable_new(&visited, n0); + for (i = 0; i < n0; i++) { + jl_method_instance_t *mi = (jl_method_instance_t*)jl_array_ptr_ref(list, i); + assert(jl_is_method_instance(mi)); + if (jl_is_method(mi->def.value)) { + jl_method_t *m = mi->def.method; + if (!module_in_worklist(m->module)) { + jl_code_instance_t *ci = mi->cache; + while (ci) { + if (ci->max_world == ~(size_t)0 && ci->relocatability && ci->inferred) + break; + ci = jl_atomic_load_relaxed(&ci->next); + } + if (ci && ptrhash_get(&external_mis, mi) == HT_NOTFOUND) { + int found = has_backedge_to_worklist(mi, &visited, 1); + assert(found == 0 || found == 1); + if (found == 1) { + ptrhash_put(&external_mis, mi, ci); + n++; } } } } - htable_free(&visited); } - return n; + htable_free(&visited); + if (n == 0) + return NULL; + jl_array_t *mi_list = jl_alloc_vec_any(n); + n = 0; + for (size_t i = 0; i < external_mis.size; i += 2) { + void *ci = external_mis.table[i+1]; + if (ci != HT_NOTFOUND) { + jl_array_ptr_set(mi_list, n++, (jl_value_t*)ci); + } + } + assert(n == jl_array_len(mi_list)); + return mi_list; } static void jl_serialize_datatype(jl_serializer_state *s, jl_datatype_t *dt) JL_GC_DISABLED @@ -579,19 +658,15 @@ static int jl_serialize_generic(jl_serializer_state *s, jl_value_t *v) JL_GC_DIS } static void jl_serialize_code_instance(jl_serializer_state *s, jl_code_instance_t *codeinst, - int skip_partial_opaque, int internal, - int force) JL_GC_DISABLED + int skip_partial_opaque, int force) JL_GC_DISABLED { - if (internal > 2) { - while (codeinst && !codeinst->relocatability) - codeinst = codeinst->next; - } if (!force && jl_serialize_generic(s, (jl_value_t*)codeinst)) { return; } int validate = 0; - if (codeinst->max_world == ~(size_t)0) + if (codeinst->max_world == ~(size_t)0 && codeinst->inferred) + // TODO: also check if this object is part of the codeinst cache and in edges_map validate = 1; // can check on deserialize if this cache entry is still valid int flags = validate << 0; if (codeinst->invoke == jl_fptr_const_return) @@ -606,7 +681,7 @@ static void jl_serialize_code_instance(jl_serializer_state *s, jl_code_instance_ if (write_ret_type && codeinst->rettype_const && jl_typeis(codeinst->rettype_const, jl_partial_opaque_type)) { if (skip_partial_opaque) { - jl_serialize_code_instance(s, codeinst->next, skip_partial_opaque, internal, 0); + jl_serialize_code_instance(s, codeinst->next, skip_partial_opaque, 0); return; } else { @@ -633,7 +708,7 @@ static void jl_serialize_code_instance(jl_serializer_state *s, jl_code_instance_ jl_serialize_value(s, jl_nothing); } write_uint8(s->s, codeinst->relocatability); - jl_serialize_code_instance(s, codeinst->next, skip_partial_opaque, internal, 0); + jl_serialize_code_instance(s, codeinst->next, skip_partial_opaque, 0); } enum METHOD_SERIALIZATION_MODE { @@ -855,8 +930,6 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li internal = 1; else if (module_in_worklist(mi->def.method->module)) internal = 2; - else if (ptrhash_get(&external_mis, (void*)mi) != HT_NOTFOUND) - internal = 3; write_uint8(s->s, internal); if (!internal) { // also flag this in the backref table as special @@ -875,12 +948,16 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li if (backedges) { // filter backedges to only contain pointers // to items that we will actually store (internal >= 2) - size_t ins, i, l = jl_array_len(backedges); - jl_method_instance_t **b_edges = (jl_method_instance_t**)jl_array_data(backedges); - for (ins = i = 0; i < l; i++) { - jl_method_instance_t *backedge = b_edges[i]; + size_t ins = 0, i = 0, l = jl_array_len(backedges); + jl_value_t **b_edges = (jl_value_t**)jl_array_data(backedges); + jl_value_t *invokeTypes; + jl_method_instance_t *backedge; + while (i < l) { + i = get_next_edge(backedges, i, &invokeTypes, &backedge); if (module_in_worklist(backedge->def.method->module) || method_instance_in_queue(backedge)) { - b_edges[ins++] = backedge; + if (invokeTypes) + b_edges[ins++] = invokeTypes; + b_edges[ins++] = (jl_value_t*)backedge; } } if (ins != l) @@ -890,10 +967,10 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li } jl_serialize_value(s, (jl_value_t*)backedges); jl_serialize_value(s, (jl_value_t*)NULL); //callbacks - jl_serialize_code_instance(s, mi->cache, 1, internal, 0); + jl_serialize_code_instance(s, mi->cache, 1, 0); } else if (jl_is_code_instance(v)) { - jl_serialize_code_instance(s, (jl_code_instance_t*)v, 0, 2, 1); + jl_serialize_code_instance(s, (jl_code_instance_t*)v, 0, 1); } else if (jl_typeis(v, jl_module_type)) { jl_serialize_module(s, (jl_module_t*)v); @@ -1062,28 +1139,12 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li } } -// Used to serialize the external method instances queued in queued_method_roots (from newly_inferred) -static void serialize_htable_keys(jl_serializer_state *s, htable_t *ht, int nitems) -{ - write_int32(s->s, nitems); - void **table = ht->table; - size_t i, n = 0, sz = ht->size; - for (i = 0; i < sz; i += 2) { - if (table[i+1] != HT_NOTFOUND) { - jl_serialize_value(s, (jl_value_t*)table[i]); - n += 1; - } - } - assert(n == nitems); -} - // Create the forward-edge map (caller => callees) // the intent of these functions is to invert the backedges tree // for anything that points to a method not part of the worklist -// or method instances not in the queue // // from MethodTables -static void jl_collect_missing_backedges_to_mod(jl_methtable_t *mt) +static void jl_collect_missing_backedges(jl_methtable_t *mt) { jl_array_t *backedges = mt->backedges; if (backedges) { @@ -1091,26 +1152,39 @@ static void jl_collect_missing_backedges_to_mod(jl_methtable_t *mt) for (i = 1; i < l; i += 2) { jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(backedges, i); jl_value_t *missing_callee = jl_array_ptr_ref(backedges, i - 1); // signature of abstract callee - jl_array_t **edges = (jl_array_t**)ptrhash_bp(&edges_map, (void*)caller); - if (*edges == HT_NOTFOUND) - *edges = jl_alloc_vec_any(0); - jl_array_ptr_1d_push(*edges, missing_callee); + jl_array_t *edges = (jl_array_t*)jl_eqtable_get(edges_map, (jl_value_t*)caller, NULL); + if (edges == NULL) { + edges = jl_alloc_vec_any(0); + JL_GC_PUSH1(&edges); + edges_map = jl_eqtable_put(edges_map, (jl_value_t*)caller, (jl_value_t*)edges, NULL); + JL_GC_POP(); + } + jl_array_ptr_1d_push(edges, NULL); + jl_array_ptr_1d_push(edges, missing_callee); } } } + // from MethodInstances -static void collect_backedges(jl_method_instance_t *callee) JL_GC_DISABLED +static void collect_backedges(jl_method_instance_t *callee, int internal) JL_GC_DISABLED { jl_array_t *backedges = callee->backedges; if (backedges) { - size_t i, l = jl_array_len(backedges); - for (i = 0; i < l; i++) { - jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(backedges, i); - jl_array_t **edges = (jl_array_t**)ptrhash_bp(&edges_map, caller); - if (*edges == HT_NOTFOUND) - *edges = jl_alloc_vec_any(0); - jl_array_ptr_1d_push(*edges, (jl_value_t*)callee); + size_t i = 0, l = jl_array_len(backedges); + while (i < l) { + jl_value_t *invokeTypes; + jl_method_instance_t *caller; + i = get_next_edge(backedges, i, &invokeTypes, &caller); + jl_array_t *edges = (jl_array_t*)jl_eqtable_get(edges_map, (jl_value_t*)caller, NULL); + if (edges == NULL) { + edges = jl_alloc_vec_any(0); + JL_GC_PUSH1(&edges); + edges_map = jl_eqtable_put(edges_map, (jl_value_t*)caller, (jl_value_t*)edges, NULL); + JL_GC_POP(); + } + jl_array_ptr_1d_push(edges, invokeTypes); + jl_array_ptr_1d_push(edges, (jl_value_t*)callee); } } } @@ -1119,24 +1193,21 @@ static void collect_backedges(jl_method_instance_t *callee) JL_GC_DISABLED // For functions owned by modules not on the worklist, call this on each method. // - if the method is owned by a worklist module, add it to the list of things to be // fully serialized -// - otherwise (i.e., if it's an external method), check all of its specializations. -// Collect all external backedges (may be needed later when we invert this list). +// - Collect all backedges (may be needed later when we invert this list). static int jl_collect_methcache_from_mod(jl_typemap_entry_t *ml, void *closure) JL_GC_DISABLED { jl_array_t *s = (jl_array_t*)closure; jl_method_t *m = ml->func.method; - if (module_in_worklist(m->module)) { + if (s && module_in_worklist(m->module)) { jl_array_ptr_1d_push(s, (jl_value_t*)m); jl_array_ptr_1d_push(s, (jl_value_t*)ml->simplesig); } - else { - jl_svec_t *specializations = m->specializations; - size_t i, l = jl_svec_len(specializations); - for (i = 0; i < l; i++) { - jl_method_instance_t *callee = (jl_method_instance_t*)jl_svecref(specializations, i); - if ((jl_value_t*)callee != jl_nothing) - collect_backedges(callee); - } + jl_svec_t *specializations = m->specializations; + size_t i, l = jl_svec_len(specializations); + for (i = 0; i < l; i++) { + jl_method_instance_t *callee = (jl_method_instance_t*)jl_svecref(specializations, i); + if ((jl_value_t*)callee != jl_nothing) + collect_backedges(callee, !s); } return 1; } @@ -1151,8 +1222,8 @@ static void jl_collect_methtable_from_mod(jl_array_t *s, jl_methtable_t *mt) JL_ // Also collect relevant backedges static void jl_collect_extext_methods_from_mod(jl_array_t *s, jl_module_t *m) JL_GC_DISABLED { - if (module_in_worklist(m)) - return; + if (s && module_in_worklist(m)) + s = NULL; // do not collect any methods size_t i; void **table = m->bindings.table; for (i = 1; i < m->bindings.size; i += 2) { @@ -1167,8 +1238,10 @@ static void jl_collect_extext_methods_from_mod(jl_array_t *s, jl_module_t *m) JL if (mt != NULL && (jl_value_t*)mt != jl_nothing && (mt != jl_type_type_mt && mt != jl_nonfunction_mt)) { + assert(mt->module == tn->module); jl_collect_methtable_from_mod(s, mt); - jl_collect_missing_backedges_to_mod(mt); + if (s) + jl_collect_missing_backedges(mt); } } } @@ -1194,103 +1267,154 @@ static void jl_collect_extext_methods_from_mod(jl_array_t *s, jl_module_t *m) JL } } -// flatten the backedge map reachable from caller into callees -static void jl_collect_backedges_to(jl_method_instance_t *caller, htable_t *all_callees) JL_GC_DISABLED +static void jl_record_edges(jl_method_instance_t *caller, arraylist_t *wq, jl_array_t *edges) JL_GC_DISABLED { - if (module_in_worklist(caller->def.method->module) || method_instance_in_queue(caller)) - return; - if (ptrhash_has(&edges_map, caller)) { - jl_array_t **pcallees = (jl_array_t**)ptrhash_bp(&edges_map, (void*)caller), - *callees = *pcallees; - assert(callees != HT_NOTFOUND); - *pcallees = (jl_array_t*) HT_NOTFOUND; + jl_array_t *callees = (jl_array_t*)jl_eqtable_pop(edges_map, (jl_value_t*)caller, NULL, NULL); + if (callees != NULL) { + jl_array_ptr_1d_push(edges, (jl_value_t*)caller); + jl_array_ptr_1d_push(edges, (jl_value_t*)callees); size_t i, l = jl_array_len(callees); - for (i = 0; i < l; i++) { - jl_value_t *c = jl_array_ptr_ref(callees, i); - ptrhash_put(all_callees, c, c); - if (jl_is_method_instance(c)) { - jl_collect_backedges_to((jl_method_instance_t*)c, all_callees); + for (i = 1; i < l; i += 2) { + jl_method_instance_t *c = (jl_method_instance_t*)jl_array_ptr_ref(callees, i); + if (c && jl_is_method_instance(c)) { + arraylist_push(wq, c); } } } } + // Extract `edges` and `ext_targets` from `edges_map` -// This identifies internal->external edges in the call graph, pulling them out for special treatment. -static void jl_collect_backedges( /* edges */ jl_array_t *s, /* ext_targets */ jl_array_t *t) +// `edges` = [caller1, targets_indexes1, ...], the list of methods and their edges +// `ext_targets` is [invokesig1, callee1, matches1, ...], the edges for each target +static void jl_collect_edges(jl_array_t *edges, jl_array_t *ext_targets) { - htable_t all_targets; // target => tgtindex mapping - htable_t all_callees; // MIs called by worklist methods (eff. Set{MethodInstance}) - htable_new(&all_targets, 0); - htable_new(&all_callees, 0); - size_t i; - void **table = edges_map.table; // edges is caller => callees - size_t table_size = edges_map.size; - for (i = 0; i < table_size; i += 2) { - assert(table == edges_map.table && table_size == edges_map.size && + size_t world = jl_atomic_load_acquire(&jl_world_counter); + arraylist_t wq; + arraylist_new(&wq, 0); + void **table = (void**)jl_array_data(edges_map); // edges is caller => callees + size_t table_size = jl_array_len(edges_map); + for (size_t i = 0; i < table_size; i += 2) { + assert(table == jl_array_data(edges_map) && table_size == jl_array_len(edges_map) && "edges_map changed during iteration"); jl_method_instance_t *caller = (jl_method_instance_t*)table[i]; jl_array_t *callees = (jl_array_t*)table[i + 1]; - if (callees == HT_NOTFOUND) + if (callees == NULL) continue; assert(jl_is_method_instance(caller) && jl_is_method(caller->def.method)); - if (module_in_worklist(caller->def.method->module) || method_instance_in_queue(caller)) { - size_t i, l = jl_array_len(callees); - for (i = 0; i < l; i++) { - jl_value_t *c = jl_array_ptr_ref(callees, i); - ptrhash_put(&all_callees, c, c); - if (jl_is_method_instance(c)) { - jl_collect_backedges_to((jl_method_instance_t*)c, &all_callees); - } + if (module_in_worklist(caller->def.method->module) || + method_instance_in_queue(caller)) { + jl_record_edges(caller, &wq, edges); + } + } + while (wq.len) { + jl_method_instance_t *caller = (jl_method_instance_t*)arraylist_pop(&wq); + jl_record_edges(caller, &wq, edges); + } + arraylist_free(&wq); + edges_map = NULL; + htable_t edges_map2; + htable_new(&edges_map2, 0); + htable_t edges_ids; + size_t l = jl_array_len(edges); + htable_new(&edges_ids, l); + for (size_t i = 0; i < l / 2; i++) { + jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(edges, i * 2); + void *target = (void*)((char*)HT_NOTFOUND + i + 1); + ptrhash_put(&edges_ids, (void*)caller, target); + } + // process target list to turn it into a memoized validity table + // and compute the old methods list, ready for serialization + jl_value_t *matches = NULL; + jl_array_t *callee_ids = NULL; + JL_GC_PUSH2(&matches, &callee_ids); + for (size_t i = 0; i < l; i += 2) { + jl_array_t *callees = (jl_array_t*)jl_array_ptr_ref(edges, i + 1); + size_t l = jl_array_len(callees); + callee_ids = jl_alloc_array_1d(jl_array_int32_type, l + 1); + int32_t *idxs = (int32_t*)jl_array_data(callee_ids); + idxs[0] = 0; + size_t nt = 0; + for (size_t j = 0; j < l; j += 2) { + jl_value_t *invokeTypes = jl_array_ptr_ref(callees, j); + jl_value_t *callee = jl_array_ptr_ref(callees, j + 1); + assert(callee && "unsupported edge"); + + if (jl_is_method_instance(callee)) { + jl_methtable_t *mt = jl_method_get_table(((jl_method_instance_t*)callee)->def.method); + if (module_in_worklist(mt->module)) + continue; } - callees = jl_alloc_array_1d(jl_array_int32_type, 0); - void **pc = all_callees.table; - size_t j; - int valid = 1; - for (j = 0; valid && j < all_callees.size; j += 2) { - if (pc[j + 1] != HT_NOTFOUND) { - jl_value_t *callee = (jl_value_t*)pc[j]; - void *target = ptrhash_get(&all_targets, (void*)callee); - if (target == HT_NOTFOUND) { - jl_method_instance_t *callee_mi = (jl_method_instance_t*)callee; - jl_value_t *sig; - if (jl_is_method_instance(callee)) { - sig = callee_mi->specTypes; - } - else { - sig = callee; - } - size_t min_valid = 0; - size_t max_valid = ~(size_t)0; - int ambig = 0; - jl_value_t *matches = jl_matching_methods((jl_tupletype_t*)sig, jl_nothing, -1, 0, jl_atomic_load_acquire(&jl_world_counter), &min_valid, &max_valid, &ambig); - if (matches == jl_false) { - valid = 0; + + // (nullptr, c) => call + // (invokeTypes, c) => invoke + // (nullptr, invokeTypes) => missing call + // (invokeTypes, nullptr) => missing invoke (unused--inferred as Any) + void *target = ptrhash_get(&edges_map2, invokeTypes ? (void*)invokeTypes : (void*)callee); + if (target == HT_NOTFOUND) { + size_t min_valid = 0; + size_t max_valid = ~(size_t)0; + if (invokeTypes) { + jl_methtable_t *mt = jl_method_get_table(((jl_method_instance_t*)callee)->def.method); + if ((jl_value_t*)mt == jl_nothing) { + callee_ids = NULL; // invalid + break; + } + else { + matches = jl_gf_invoke_lookup_worlds(invokeTypes, (jl_value_t*)mt, world, &min_valid, &max_valid); + if (matches == jl_nothing) { + callee_ids = NULL; // invalid break; } - size_t k; - for (k = 0; k < jl_array_len(matches); k++) { - jl_method_match_t *match = (jl_method_match_t *)jl_array_ptr_ref(matches, k); - jl_array_ptr_set(matches, k, match->method); - } - jl_array_ptr_1d_push(t, callee); - jl_array_ptr_1d_push(t, matches); - target = (char*)HT_NOTFOUND + jl_array_len(t) / 2; - ptrhash_put(&all_targets, (void*)callee, target); + matches = (jl_value_t*)((jl_method_match_t*)matches)->method; } - jl_array_grow_end(callees, 1); - ((int32_t*)jl_array_data(callees))[jl_array_len(callees) - 1] = (char*)target - (char*)HT_NOTFOUND - 1; } + else { + jl_value_t *sig; + if (jl_is_method_instance(callee)) + sig = ((jl_method_instance_t*)callee)->specTypes; + else + sig = callee; + int ambig = 0; + matches = jl_matching_methods((jl_tupletype_t*)sig, jl_nothing, + -1, 0, world, &min_valid, &max_valid, &ambig); + if (matches == jl_false) { + callee_ids = NULL; // invalid + break; + } + size_t k; + for (k = 0; k < jl_array_len(matches); k++) { + jl_method_match_t *match = (jl_method_match_t *)jl_array_ptr_ref(matches, k); + jl_array_ptr_set(matches, k, match->method); + } + } + jl_array_ptr_1d_push(ext_targets, invokeTypes); + jl_array_ptr_1d_push(ext_targets, callee); + jl_array_ptr_1d_push(ext_targets, matches); + target = (void*)((char*)HT_NOTFOUND + jl_array_len(ext_targets) / 3); + ptrhash_put(&edges_map2, (void*)callee, target); } - htable_reset(&all_callees, 100); - if (valid) { - jl_array_ptr_1d_push(s, (jl_value_t*)caller); - jl_array_ptr_1d_push(s, (jl_value_t*)callees); + idxs[++nt] = (char*)target - (char*)HT_NOTFOUND - 1; + } + jl_array_ptr_set(edges, i + 1, callee_ids); // swap callees for ids + if (!callee_ids) + continue; + idxs[0] = nt; + // record place of every method in edges + // add method edges to the callee_ids list + for (size_t j = 0; j < l; j += 2) { + jl_value_t *callee = jl_array_ptr_ref(callees, j + 1); + if (callee && jl_is_method_instance(callee)) { + void *target = ptrhash_get(&edges_ids, (void*)callee); + if (target != HT_NOTFOUND) { + idxs[++nt] = (char*)target - (char*)HT_NOTFOUND - 1; + } } } + jl_array_del_end(callee_ids, l - nt); } - htable_free(&all_targets); - htable_free(&all_callees); + JL_GC_POP(); + htable_free(&edges_map2); } // serialize information about all loaded modules @@ -2211,242 +2335,385 @@ static void jl_insert_methods(jl_array_t *list) } } -void remove_code_instance_from_validation(jl_code_instance_t *codeinst) +int remove_code_instance_from_validation(jl_code_instance_t *codeinst) { - ptrhash_remove(&new_code_instance_validate, codeinst); + return ptrhash_remove(&new_code_instance_validate, codeinst); } -static void jl_insert_method_instances(jl_array_t *list) +// verify that these edges intersect with the same methods as before +static jl_array_t *jl_verify_edges(jl_array_t *targets) { - size_t i, l = jl_array_len(list); - // Validate the MethodInstances + size_t world = jl_atomic_load_acquire(&jl_world_counter); + size_t i, l = jl_array_len(targets) / 3; jl_array_t *valids = jl_alloc_array_1d(jl_array_uint8_type, l); memset(jl_array_data(valids), 1, l); - size_t world = jl_atomic_load_acquire(&jl_world_counter); + jl_value_t *loctag = NULL; + jl_value_t *matches = NULL; + JL_GC_PUSH3(&valids, &matches, &loctag); for (i = 0; i < l; i++) { - jl_method_instance_t *mi = (jl_method_instance_t*)jl_array_ptr_ref(list, i); - assert(jl_is_method_instance(mi)); - if (jl_is_method(mi->def.method)) { - // Is this still the method we'd be calling? - jl_methtable_t *mt = jl_method_table_for(mi->specTypes); - struct jl_typemap_assoc search = {(jl_value_t*)mi->specTypes, world, NULL, 0, ~(size_t)0}; - jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(mt->defs, &search, /*offs*/0, /*subtype*/1); - if (entry) { - jl_value_t *mworld = entry->func.value; - if (jl_is_method(mworld) && mi->def.method != (jl_method_t*)mworld && jl_type_morespecific(((jl_method_t*)mworld)->sig, mi->def.method->sig)) { - jl_array_uint8_set(valids, i, 0); - invalidate_backedges(&remove_code_instance_from_validation, mi, world, "jl_insert_method_instance"); - // The codeinst of this mi haven't yet been removed - jl_code_instance_t *codeinst = mi->cache; - while (codeinst) { - remove_code_instance_from_validation(codeinst); - codeinst = codeinst->next; - } - if (_jl_debug_method_invalidation) { - jl_array_ptr_1d_push(_jl_debug_method_invalidation, mworld); - jl_array_ptr_1d_push(_jl_debug_method_invalidation, jl_cstr_to_string("jl_method_table_insert")); // GC disabled + jl_value_t *invokesig = jl_array_ptr_ref(targets, i * 3); + jl_value_t *callee = jl_array_ptr_ref(targets, i * 3 + 1); + jl_value_t *expected = jl_array_ptr_ref(targets, i * 3 + 2); + int valid = 1; + size_t min_valid = 0; + size_t max_valid = ~(size_t)0; + if (invokesig) { + assert(callee && "unsupported edge"); + jl_methtable_t *mt = jl_method_get_table(((jl_method_instance_t*)callee)->def.method); + if ((jl_value_t*)mt == jl_nothing) { + valid = 0; + } + else { + matches = jl_gf_invoke_lookup_worlds(invokesig, (jl_value_t*)mt, world, &min_valid, &max_valid); + if (matches == jl_nothing) { + valid = 0; + } + else { + matches = (jl_value_t*)((jl_method_match_t*)matches)->method; + if (matches != expected) { + valid = 0; } } } } - } - // While it's tempting to just remove the invalidated MIs altogether, - // this hurts the ability of SnoopCompile to diagnose problems. - for (i = 0; i < l; i++) { - jl_method_instance_t *mi = (jl_method_instance_t*)jl_array_ptr_ref(list, i); - jl_method_instance_t *milive = jl_specializations_get_or_insert(mi); - ptrhash_put(&uniquing_table, mi, milive); // store the association for the 2nd pass - } - // We may need to fix up the backedges for the ones that didn't "go live" - for (i = 0; i < l; i++) { - jl_method_instance_t *mi = (jl_method_instance_t*)jl_array_ptr_ref(list, i); - jl_method_instance_t *milive = (jl_method_instance_t*)ptrhash_get(&uniquing_table, mi); - if (milive != mi) { - // A previously-loaded module compiled this method, so the one we deserialized will be dropped. - // But make sure the backedges are copied over. - if (mi->backedges) { - if (!milive->backedges) { - // Copy all the backedges (after looking up the live ones) - size_t j, n = jl_array_len(mi->backedges); - milive->backedges = jl_alloc_vec_any(n); - jl_gc_wb(milive, milive->backedges); - for (j = 0; j < n; j++) { - jl_method_instance_t *be = (jl_method_instance_t*)jl_array_ptr_ref(mi->backedges, j); - jl_method_instance_t *belive = (jl_method_instance_t*)ptrhash_get(&uniquing_table, be); - if (belive == HT_NOTFOUND) - belive = be; - jl_array_ptr_set(milive->backedges, j, belive); - } - } else { - // Copy the missing backedges (this is an O(N^2) algorithm, but many methods have few MethodInstances) - size_t j, k, n = jl_array_len(mi->backedges), nlive = jl_array_len(milive->backedges); - for (j = 0; j < n; j++) { - jl_method_instance_t *be = (jl_method_instance_t*)jl_array_ptr_ref(mi->backedges, j); - jl_method_instance_t *belive = (jl_method_instance_t*)ptrhash_get(&uniquing_table, be); - if (belive == HT_NOTFOUND) - belive = be; - int found = 0; - for (k = 0; k < nlive; k++) { - if (belive == (jl_method_instance_t*)jl_array_ptr_ref(milive->backedges, k)) { - found = 1; - break; - } - } - if (!found) - jl_array_ptr_1d_push(milive->backedges, (jl_value_t*)belive); - } - } + else { + jl_value_t *sig; + if (jl_is_method_instance(callee)) + sig = ((jl_method_instance_t*)callee)->specTypes; + else + sig = callee; + assert(jl_is_array(expected)); + int ambig = 0; + // TODO: possibly need to included ambiguities too (for the optimizer correctness)? + matches = jl_matching_methods((jl_tupletype_t*)sig, jl_nothing, + -1, 0, world, &min_valid, &max_valid, &ambig); + if (matches == jl_false) { + valid = 0; } - // Additionally, if we have CodeInstance(s) and the running CodeInstance is world-limited, transfer it - if (mi->cache && jl_array_uint8_ref(valids, i)) { - if (!milive->cache || milive->cache->max_world < ~(size_t)0) { - jl_code_instance_t *cilive = milive->cache, *ci; - milive->cache = mi->cache; - jl_gc_wb(milive, milive->cache); - ci = mi->cache; - ci->def = milive; - while (ci->next) { - ci = ci->next; - ci->def = milive; + else { + // setdiff!(matches, expected) + size_t j, k, ins = 0; + if (jl_array_len(matches) != jl_array_len(expected)) { + valid = 0; + } + for (k = 0; k < jl_array_len(matches); k++) { + jl_method_t *match = ((jl_method_match_t*)jl_array_ptr_ref(matches, k))->method; + size_t l = jl_array_len(expected); + for (j = 0; j < l; j++) + if (match == (jl_method_t*)jl_array_ptr_ref(expected, j)) + break; + if (j == l) { + // intersection has a new method or a method was + // deleted--this is now probably no good, just invalidate + // everything about it now + valid = 0; + if (!_jl_debug_method_invalidation) + break; + jl_array_ptr_set(matches, ins++, match); } - ci->next = cilive; - jl_gc_wb(ci, ci->next); } + if (!valid && _jl_debug_method_invalidation) + jl_array_del_end((jl_array_t*)matches, jl_array_len(matches) - ins); } } + jl_array_uint8_set(valids, i, valid); + if (!valid && _jl_debug_method_invalidation) { + jl_array_ptr_1d_push(_jl_debug_method_invalidation, invokesig ? (jl_value_t*)invokesig : callee); + loctag = jl_cstr_to_string("insert_backedges_callee"); + jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag); + loctag = jl_box_int32((int32_t)i); + jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag); + jl_array_ptr_1d_push(_jl_debug_method_invalidation, matches); + } + //jl_static_show((JL_STREAM*)ios_stderr, (jl_value_t*)invokesig); + //jl_static_show((JL_STREAM*)ios_stderr, (jl_value_t*)callee); + //ios_puts(valid ? "valid\n" : "INVALID\n", ios_stderr); } + JL_GC_POP(); + return valids; } -// verify that these edges intersect with the same methods as before -static void jl_verify_edges(jl_array_t *targets, jl_array_t **pvalids) +// Combine all edges relevant to a method into the visited table +void jl_verify_methods(jl_array_t *edges, jl_array_t *valids, htable_t *visited) { - size_t i, l = jl_array_len(targets) / 2; - jl_array_t *valids = jl_alloc_array_1d(jl_array_uint8_type, l); - memset(jl_array_data(valids), 1, l); jl_value_t *loctag = NULL; JL_GC_PUSH1(&loctag); - *pvalids = valids; + size_t i, l = jl_array_len(edges) / 2; + htable_new(visited, l); for (i = 0; i < l; i++) { - jl_value_t *callee = jl_array_ptr_ref(targets, i * 2); - jl_method_instance_t *callee_mi = (jl_method_instance_t*)callee; - jl_value_t *sig; - if (jl_is_method_instance(callee)) { - sig = callee_mi->specTypes; - } - else { - sig = callee; - } - jl_array_t *expected = (jl_array_t*)jl_array_ptr_ref(targets, i * 2 + 1); - assert(jl_is_array(expected)); + jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(edges, 2 * i); + assert(jl_is_method_instance(caller) && jl_is_method(caller->def.method)); + jl_array_t *callee_ids = (jl_array_t*)jl_array_ptr_ref(edges, 2 * i + 1); + assert(jl_typeis((jl_value_t*)callee_ids, jl_array_int32_type)); int valid = 1; - size_t min_valid = 0; - size_t max_valid = ~(size_t)0; - int ambig = 0; - // TODO: possibly need to included ambiguities too (for the optimizer correctness)? - jl_value_t *matches = jl_matching_methods((jl_tupletype_t*)sig, jl_nothing, -1, 0, jl_atomic_load_acquire(&jl_world_counter), &min_valid, &max_valid, &ambig); - if (matches == jl_false || jl_array_len(matches) != jl_array_len(expected)) { + if (callee_ids == NULL) { + // serializing the edges had failed valid = 0; } else { - size_t j, k, l = jl_array_len(expected); - for (k = 0; k < jl_array_len(matches); k++) { - jl_method_match_t *match = (jl_method_match_t*)jl_array_ptr_ref(matches, k); - jl_method_t *m = match->method; - for (j = 0; j < l; j++) { - if (m == (jl_method_t*)jl_array_ptr_ref(expected, j)) - break; - } - if (j == l) { - // intersection has a new method or a method was - // deleted--this is now probably no good, just invalidate - // everything about it now - valid = 0; - break; + int32_t *idxs = (int32_t*)jl_array_data(callee_ids); + size_t j; + for (j = 0; valid && j < idxs[0]; j++) { + int32_t idx = idxs[j + 1]; + valid = jl_array_uint8_ref(valids, idx); + if (!valid && _jl_debug_method_invalidation) { + jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)caller); + loctag = jl_cstr_to_string("verify_methods"); + jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag); + loctag = jl_box_int32((int32_t)idx); + jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag); } } } - jl_array_uint8_set(valids, i, valid); - if (!valid && _jl_debug_method_invalidation) { - jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)callee); - loctag = jl_cstr_to_string("insert_backedges_callee"); - jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag); + ptrhash_put(visited, caller, (void*)(((char*)HT_NOTFOUND) + valid + 1)); + //jl_static_show((JL_STREAM*)ios_stderr, (jl_value_t*)caller); + //ios_puts(valid ? "valid\n" : "INVALID\n", ios_stderr); + // HT_NOTFOUND: valid (no invalid edges) + // HT_NOTFOUND + 1: invalid + // HT_NOTFOUND + 2: need to scan + // HT_NOTFOUND + 3 + depth: in-progress + } + JL_GC_POP(); +} + + +// Propagate the result of cycle-resolution to all edges (recursively) +static int mark_edges_in_worklist(jl_array_t *edges, int idx, jl_method_instance_t *cycle, htable_t *visited, int found) +{ + jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(edges, idx * 2); + int oldfound = (char*)ptrhash_get(visited, caller) - (char*)HT_NOTFOUND; + if (oldfound < 3) + return 0; // not in-progress + if (!found) { + ptrhash_remove(visited, (void*)caller); + } + else { + ptrhash_put(visited, (void*)caller, (void*)((char*)HT_NOTFOUND + 1 + found)); + } + jl_array_t *callee_ids = (jl_array_t*)jl_array_ptr_ref(edges, idx * 2 + 1); + assert(jl_typeis((jl_value_t*)callee_ids, jl_array_int32_type)); + int32_t *idxs = (int32_t*)jl_array_data(callee_ids); + size_t i, badidx = 0, n = jl_array_len(callee_ids); + for (i = idxs[0] + 1; i < n; i++) { + if (mark_edges_in_worklist(edges, idxs[i], cycle, visited, found) && badidx == 0) + badidx = i - idxs[0]; + } + if (_jl_debug_method_invalidation) { + jl_value_t *loctag = NULL; + JL_GC_PUSH1(&loctag); + jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)caller); + loctag = jl_cstr_to_string("verify_methods"); + jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag); + jl_method_instance_t *callee = cycle; + if (badidx--) + callee = (jl_method_instance_t*)jl_array_ptr_ref(edges, 2 * badidx); + jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)callee); + JL_GC_POP(); + } + return 1; +} + + +// Visit the entire call graph, starting from edges[idx] to determine if that method is valid +static int jl_verify_graph_edge(jl_array_t *edges, int idx, htable_t *visited, int depth) +{ + jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(edges, idx * 2); + assert(jl_is_method_instance(caller) && jl_is_method(caller->def.method)); + int found = (char*)ptrhash_get(visited, (void*)caller) - (char*)HT_NOTFOUND; + if (found == 0) + return 1; // valid + if (found == 1) + return 0; // invalid + if (found != 2) + return found - 1; // depth + found = 0; + ptrhash_put(visited, (void*)caller, (void*)((char*)HT_NOTFOUND + 3 + depth)); // change 2 to in-progress at depth + jl_array_t *callee_ids = (jl_array_t*)jl_array_ptr_ref(edges, idx * 2 + 1); + assert(jl_typeis((jl_value_t*)callee_ids, jl_array_int32_type)); + int32_t *idxs = (int32_t*)jl_array_data(callee_ids); + int cycle = 0; + size_t i, n = jl_array_len(callee_ids); + for (i = idxs[0] + 1; i < n; i++) { + int32_t idx = idxs[i]; + int child_found = jl_verify_graph_edge(edges, idx, visited, depth + 1); + if (child_found == 0) { + found = 1; + if (_jl_debug_method_invalidation) { + jl_value_t *loctag = NULL; + JL_GC_PUSH1(&loctag); + jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)caller); + loctag = jl_cstr_to_string("verify_methods"); + jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag); + jl_array_ptr_1d_push(_jl_debug_method_invalidation, jl_array_ptr_ref(edges, idx * 2)); + JL_GC_POP(); + } + break; + } + else if (child_found >= 2 && child_found - 2 < cycle) { + // record the cycle will resolve at depth "cycle" + cycle = child_found - 2; + assert(cycle); } } + if (!found) { + if (cycle && cycle != depth) + return cycle + 2; + ptrhash_remove(visited, (void*)caller); + } + else { // found invalid + ptrhash_put(visited, (void*)caller, (void*)((char*)HT_NOTFOUND + 1 + found)); + } + if (cycle) { + // If we are the top of the current cycle, now mark all other parts of + // our cycle by re-walking the backedges graph and marking all WIP + // items as found. + // Be careful to only re-walk as far as we had originally scanned above. + // Or if we found a backedge, also mark all of the other parts of the + // cycle as also having an backedge. + n = i; + for (i = idxs[0] + 1; i < n; i++) { + mark_edges_in_worklist(edges, idxs[i], caller, visited, found); + } + } + return found ? 0 : 1; +} + +// Visit all entries in edges, verify if they are valid +static jl_array_t *jl_verify_graph(jl_array_t *edges, htable_t *visited) +{ + size_t i, n = jl_array_len(edges) / 2; + jl_array_t *valids = jl_alloc_array_1d(jl_array_uint8_type, n); + JL_GC_PUSH1(&valids); + int8_t *valids_data = (int8_t*)jl_array_data(valids); + for (i = 0; i < n; i++) { + valids_data[i] = jl_verify_graph_edge(edges, i, visited, 1); + } JL_GC_POP(); + return valids; } // Restore backedges to external targets -// `targets` is [callee1, matches1, ...], the global set of non-worklist callees of worklist-owned methods. -// `list` = [caller1, targets_indexes1, ...], the list of worklist-owned methods calling external methods. -static void jl_insert_backedges(jl_array_t *list, jl_array_t *targets) +// `edges` = [caller1, targets_indexes1, ...], the list of worklist-owned methods calling external methods. +// `ext_targets` is [invokesig1, callee1, matches1, ...], the global set of non-worklist callees of worklist-owned methods. +static void jl_insert_backedges(jl_array_t *edges, jl_array_t *ext_targets, jl_array_t *mi_list) { - // map(enable, ((list[i] => targets[list[i + 1] .* 2]) for i in 1:2:length(list) if all(valids[list[i + 1]]))) - size_t i, l = jl_array_len(list); - jl_array_t *valids = NULL; - jl_value_t *loctag = NULL; - JL_GC_PUSH2(&valids, &loctag); - jl_verify_edges(targets, &valids); - for (i = 0; i < l; i += 2) { - jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(list, i); + // determine which CodeInstance objects are still valid in our image + size_t world = jl_atomic_load_acquire(&jl_world_counter); + jl_array_t *valids = jl_verify_edges(ext_targets); + JL_GC_PUSH1(&valids); + htable_t visited; + htable_new(&visited, 0); + jl_verify_methods(edges, valids, &visited); + valids = jl_verify_graph(edges, &visited); + size_t i, l = jl_array_len(edges) / 2; + + // next build a map from external_mis to their CodeInstance for insertion + if (mi_list == NULL) { + htable_reset(&visited, 0); + } + else { + size_t i, l = jl_array_len(mi_list); + htable_reset(&visited, l); + for (i = 0; i < l; i++) { + jl_code_instance_t *ci = (jl_code_instance_t*)jl_array_ptr_ref(mi_list, i); + ptrhash_put(&visited, (void*)ci->def, (void*)ci); + } + } + + // next disable any invalid codes, so we do not try to enable them + for (i = 0; i < l; i++) { + jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(edges, 2 * i); assert(jl_is_method_instance(caller) && jl_is_method(caller->def.method)); - jl_array_t *idxs_array = (jl_array_t*)jl_array_ptr_ref(list, i + 1); - assert(jl_isa((jl_value_t*)idxs_array, jl_array_int32_type)); - int32_t *idxs = (int32_t*)jl_array_data(idxs_array); - int valid = 1; - size_t j; - for (j = 0; valid && j < jl_array_len(idxs_array); j++) { - int32_t idx = idxs[j]; - valid = jl_array_uint8_ref(valids, idx); - } - if (valid) { - // if this callee is still valid, add all the backedges - for (j = 0; j < jl_array_len(idxs_array); j++) { - int32_t idx = idxs[j]; - jl_value_t *callee = jl_array_ptr_ref(targets, idx * 2); - if (jl_is_method_instance(callee)) { - jl_method_instance_add_backedge((jl_method_instance_t*)callee, caller); - } - else { - jl_methtable_t *mt = jl_method_table_for(callee); - // FIXME: rarely, `callee` has an unexpected `Union` signature, - // see https://github.com/JuliaLang/julia/pull/43990#issuecomment-1030329344 - // Fix the issue and turn this back into an `assert((jl_value_t*)mt != jl_nothing)` - // This workaround exposes us to (rare) 265-violations. - if ((jl_value_t*)mt != jl_nothing) - jl_method_table_add_backedge(mt, callee, (jl_value_t*)caller); - } - } - // then enable it + int valid = jl_array_uint8_ref(valids, i); + if (valid) + continue; + void *ci = ptrhash_get(&visited, (void*)caller); + if (ci != HT_NOTFOUND) { + assert(jl_is_code_instance(ci)); + remove_code_instance_from_validation((jl_code_instance_t*)ci); // mark it as handled + } + else { jl_code_instance_t *codeinst = caller->cache; while (codeinst) { - if (ptrhash_get(&new_code_instance_validate, codeinst) != HT_NOTFOUND && codeinst->min_world > 0) - codeinst->max_world = ~(size_t)0; - ptrhash_remove(&new_code_instance_validate, codeinst); // mark it as handled + remove_code_instance_from_validation(codeinst); // should be left invalid codeinst = jl_atomic_load_relaxed(&codeinst->next); } } + } + + // finally enable any applicable new codes + for (i = 0; i < l; i++) { + jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(edges, 2 * i); + int valid = jl_array_uint8_ref(valids, i); + if (!valid) + continue; + // if this callee is still valid, add all the backedges + jl_array_t *callee_ids = (jl_array_t*)jl_array_ptr_ref(edges, 2 * i + 1); + int32_t *idxs = (int32_t*)jl_array_data(callee_ids); + for (size_t j = 0; j < idxs[0]; j++) { + int32_t idx = idxs[j + 1]; + jl_value_t *invokesig = jl_array_ptr_ref(ext_targets, idx * 3); + jl_value_t *callee = jl_array_ptr_ref(ext_targets, idx * 3 + 1); + if (callee && jl_is_method_instance(callee)) { + assert(invokesig == NULL); (void)invokesig; + jl_method_instance_add_backedge((jl_method_instance_t*)callee, caller); + } + else { + jl_value_t *sig = callee == NULL ? invokesig : callee; + jl_methtable_t *mt = jl_method_table_for(sig); + // FIXME: rarely, `callee` has an unexpected `Union` signature, + // see https://github.com/JuliaLang/julia/pull/43990#issuecomment-1030329344 + // Fix the issue and turn this back into an `assert((jl_value_t*)mt != jl_nothing)` + // This workaround exposes us to (rare) 265-violations. + if ((jl_value_t*)mt != jl_nothing) + jl_method_table_add_backedge(mt, sig, (jl_value_t*)caller); + } + } + // then enable it + void *ci = ptrhash_get(&visited, (void*)caller); + if (ci != HT_NOTFOUND) { + // have some new external code to use + assert(jl_is_code_instance(ci)); + jl_code_instance_t *codeinst = (jl_code_instance_t*)ci; + remove_code_instance_from_validation(codeinst); // mark it as handled + assert(codeinst->min_world >= world && codeinst->inferred); + codeinst->max_world = ~(size_t)0; + if (jl_rettype_inferred(caller, world, ~(size_t)0) == jl_nothing) { + jl_mi_cache_insert(caller, codeinst); + } + } else { jl_code_instance_t *codeinst = caller->cache; while (codeinst) { - ptrhash_remove(&new_code_instance_validate, codeinst); // should be left invalid + if (remove_code_instance_from_validation(codeinst)) { // mark it as handled + assert(codeinst->min_world >= world && codeinst->inferred); + codeinst->max_world = ~(size_t)0; + } codeinst = jl_atomic_load_relaxed(&codeinst->next); } - if (_jl_debug_method_invalidation) { - jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)caller); - loctag = jl_cstr_to_string("insert_backedges"); - jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag); - } } } + + htable_free(&visited); JL_GC_POP(); } static void validate_new_code_instances(void) { + size_t world = jl_atomic_load_acquire(&jl_world_counter); size_t i; for (i = 0; i < new_code_instance_validate.size; i += 2) { if (new_code_instance_validate.table[i+1] != HT_NOTFOUND) { - ((jl_code_instance_t*)new_code_instance_validate.table[i])->max_world = ~(size_t)0; + jl_code_instance_t *ci = (jl_code_instance_t*)new_code_instance_validate.table[i]; + JL_GC_PROMISE_ROOTED(ci); // TODO: this needs a root (or restructuring to avoid it) + assert(ci->min_world >= world && ci->inferred); + ci->max_world = ~(size_t)0; + jl_method_instance_t *caller = ci->def; + if (jl_rettype_inferred(caller, world, ~(size_t)0) == jl_nothing) { + jl_mi_cache_insert(caller, ci); + } + //jl_static_show((JL_STREAM*)ios_stderr, (jl_value_t*)caller); + //ios_puts("FREE\n", ios_stderr); } } } @@ -2621,13 +2888,18 @@ JL_DLLEXPORT void jl_set_newly_inferred(jl_value_t* _newly_inferred) JL_DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist) { JL_TIMING(SAVE_MODULE); + jl_task_t *ct = jl_current_task; ios_t f; - jl_array_t *mod_array = NULL, *udeps = NULL; if (ios_file(&f, fname, 1, 1, 1, 1) == NULL) { jl_printf(JL_STDERR, "Cannot open cache file \"%s\" for writing.\n", fname); return 1; } - JL_GC_PUSH2(&mod_array, &udeps); + + jl_array_t *mod_array = NULL, *udeps = NULL; + jl_array_t *extext_methods = NULL, *mi_list = NULL; + jl_array_t *ext_targets = NULL, *edges = NULL; + JL_GC_PUSH7(&mod_array, &udeps, &extext_methods, &mi_list, &ext_targets, &edges, &edges_map); + mod_array = jl_get_loaded_modules(); // __toplevel__ modules loaded in this session (from Base.loaded_modules_array) assert(jl_precompile_toplevel_module == NULL); jl_precompile_toplevel_module = (jl_module_t*)jl_array_ptr_ref(worklist, jl_array_len(worklist)-1); @@ -2646,7 +2918,6 @@ JL_DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist) write_mod_list(&f, mod_array); arraylist_new(&reinit_list, 0); - htable_new(&edges_map, 0); htable_new(&backref_table, 5000); htable_new(&external_mis, newly_inferred ? jl_array_len(newly_inferred) : 0); ptrhash_put(&backref_table, jl_main_module, (char*)HT_NOTFOUND + 1); @@ -2659,15 +2930,14 @@ JL_DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist) jl_symbol("BITS_PER_LIMB"))) / 8; } - int en = jl_gc_enable(0); // edges map is not gc-safe - jl_array_t *extext_methods = jl_alloc_vec_any(0); // [method1, simplesig1, ...], worklist-owned "extending external" methods added to functions owned by modules outside the worklist - jl_array_t *ext_targets = jl_alloc_vec_any(0); // [callee1, matches1, ...] non-worklist callees of worklist-owned methods - jl_array_t *edges = jl_alloc_vec_any(0); // [caller1, ext_targets_indexes1, ...] for worklist-owned methods calling external methods + jl_gc_enable_finalizers(ct, 0); // make sure we don't run any Julia code concurrently after this point - int n_ext_mis = queue_external_mis(newly_inferred); + // Save the inferred code from newly inferred, external methods + mi_list = queue_external_mis(newly_inferred); - size_t i; - size_t len = jl_array_len(mod_array); + edges_map = jl_alloc_vec_any(0); + extext_methods = jl_alloc_vec_any(0); // [method1, simplesig1, ...], worklist-owned "extending external" methods added to functions owned by modules outside the worklist + size_t i, len = jl_array_len(mod_array); for (i = 0; i < len; i++) { jl_module_t *m = (jl_module_t*)jl_array_ptr_ref(mod_array, i); assert(jl_is_module(m)); @@ -2675,13 +2945,17 @@ JL_DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist) jl_collect_extext_methods_from_mod(extext_methods, m); } jl_collect_methtable_from_mod(extext_methods, jl_type_type_mt); - jl_collect_missing_backedges_to_mod(jl_type_type_mt); + jl_collect_missing_backedges(jl_type_type_mt); jl_collect_methtable_from_mod(extext_methods, jl_nonfunction_mt); - jl_collect_missing_backedges_to_mod(jl_nonfunction_mt); - - // jl_collect_extext_methods_from_mod and jl_collect_missing_backedges_to_mod accumulate data in edges_map. + jl_collect_missing_backedges(jl_nonfunction_mt); + // jl_collect_extext_methods_from_mod and jl_collect_missing_backedges also accumulate data in edges_map. // Process this to extract `edges` and `ext_targets`. - jl_collect_backedges(edges, ext_targets); + ext_targets = jl_alloc_vec_any(0); // [invokesig1, callee1, matches1, ...] non-worklist callees of worklist-owned methods + // ordinary dispatch: invokesig=NULL, callee is MethodInstance + // `invoke` dispatch: invokesig is signature, callee is MethodInstance + // abstract call: callee is signature + edges = jl_alloc_vec_any(0); // [caller1, ext_targets_indexes1, ...] for worklist-owned methods calling external methods + jl_collect_edges(edges, ext_targets); jl_serializer_state s = { &f, @@ -2690,21 +2964,20 @@ JL_DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist) }; jl_serialize_value(&s, worklist); // serialize module-owned items (those accessible from the bindings table) jl_serialize_value(&s, extext_methods); // serialize new worklist-owned methods for external functions - serialize_htable_keys(&s, &external_mis, n_ext_mis); // serialize external MethodInstances - // The next two allow us to restore backedges from external "unserialized" (stub-serialized) MethodInstances - // to the ones we serialize here + // The next three allow us to restore code instances, if still valid + jl_serialize_value(&s, mi_list); jl_serialize_value(&s, edges); jl_serialize_value(&s, ext_targets); jl_finalize_serializer(&s); serializer_worklist = NULL; - jl_gc_enable(en); - htable_reset(&edges_map, 0); - htable_reset(&backref_table, 0); - htable_reset(&external_mis, 0); + htable_free(&backref_table); + htable_free(&external_mis); arraylist_free(&reinit_list); + jl_gc_enable_finalizers(ct, 1); // make sure we don't run any Julia code concurrently before this point + // Write the source-text for the dependent files if (udeps) { // Go back and update the source-text position to point to the current position @@ -3084,15 +3357,11 @@ static jl_value_t *_jl_restore_incremental(ios_t *f, jl_array_t *mod_array) }; jl_array_t *restored = (jl_array_t*)jl_deserialize_value(&s, (jl_value_t**)&restored); serializer_worklist = restored; - assert(jl_isa((jl_value_t*)restored, jl_array_any_type)); + assert(jl_typeis((jl_value_t*)restored, jl_array_any_type)); // See explanation in jl_save_incremental for variables of the same names jl_value_t *extext_methods = jl_deserialize_value(&s, &extext_methods); - int i, n_ext_mis = read_int32(s.s); - jl_array_t *mi_list = jl_alloc_vec_any(n_ext_mis); // reload MIs stored by serialize_htable_keys - jl_value_t **midata = (jl_value_t**)jl_array_data(mi_list); - for (i = 0; i < n_ext_mis; i++) - midata[i] = jl_deserialize_value(&s, &(midata[i])); + jl_value_t *mi_list = jl_deserialize_value(&s, &mi_list); // reload MIs stored by queue_external_mis jl_value_t *edges = jl_deserialize_value(&s, &edges); jl_value_t *ext_targets = jl_deserialize_value(&s, &ext_targets); @@ -3106,19 +3375,16 @@ static jl_value_t *_jl_restore_incremental(ios_t *f, jl_array_t *mod_array) jl_insert_methods((jl_array_t*)extext_methods); // hook up extension methods for external generic functions (needs to be after recache types) jl_recache_other(); // make all of the other objects identities correct (needs to be after insert methods) jl_copy_roots(); // copying new roots of external methods (must wait until recaching is complete) - // At this point, the novel specializations in mi_list reference the real method, but they haven't been cached in its specializations - jl_insert_method_instances(mi_list); // insert novel specializations htable_free(&uniquing_table); jl_array_t *init_order = jl_finalize_deserializer(&s, tracee_list); // done with f and s (needs to be after recache) if (init_order == NULL) init_order = (jl_array_t*)jl_an_empty_vec_any; - assert(jl_isa((jl_value_t*)init_order, jl_array_any_type)); + assert(jl_typeis((jl_value_t*)init_order, jl_array_any_type)); - JL_GC_PUSH4(&init_order, &restored, &edges, &ext_targets); + JL_GC_PUSH5(&init_order, &restored, &edges, &ext_targets, &mi_list); jl_gc_enable(en); // subtyping can allocate a lot, not valid before recache-other - jl_insert_backedges((jl_array_t*)edges, (jl_array_t*)ext_targets); // restore external backedges (needs to be last) - + jl_insert_backedges((jl_array_t*)edges, (jl_array_t*)ext_targets, (jl_array_t*)mi_list); // restore external backedges (needs to be last) // check new CodeInstances and validate any that lack external backedges validate_new_code_instances(); diff --git a/src/gf.c b/src/gf.c index 49078f903b708..855a138186b93 100644 --- a/src/gf.c +++ b/src/gf.c @@ -222,8 +222,6 @@ JL_DLLEXPORT jl_code_instance_t* jl_new_codeinst( int32_t const_flags, size_t min_world, size_t max_world, uint32_t ipo_effects, uint32_t effects, jl_value_t *argescapes, uint8_t relocatability); -JL_DLLEXPORT void jl_mi_cache_insert(jl_method_instance_t *mi JL_ROOTING_ARGUMENT, - jl_code_instance_t *ci JL_ROOTED_ARGUMENT JL_MAYBE_UNROOTED); jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_args_t fptr) JL_GC_DISABLED { @@ -436,7 +434,10 @@ JL_DLLEXPORT void jl_mi_cache_insert(jl_method_instance_t *mi JL_ROOTING_ARGUMEN JL_GC_PUSH1(&ci); if (jl_is_method(mi->def.method)) JL_LOCK(&mi->def.method->writelock); - ci->next = mi->cache; + jl_code_instance_t *oldci = mi->cache; + ci->next = oldci; + if (oldci) + jl_gc_wb(ci, oldci); jl_atomic_store_release(&mi->cache, ci); jl_gc_wb(mi, ci); if (jl_is_method(mi->def.method)) @@ -1423,6 +1424,7 @@ static void invalidate_method_instance(void (*f)(jl_code_instance_t*), jl_method jl_array_ptr_1d_push(_jl_debug_method_invalidation, boxeddepth); JL_GC_POP(); } + //jl_static_show(JL_STDERR, (jl_value_t*)replaced); if (!jl_is_method(replaced->def.method)) return; // shouldn't happen, but better to be safe JL_LOCK(&replaced->def.method->writelock); @@ -1450,10 +1452,11 @@ static void invalidate_method_instance(void (*f)(jl_code_instance_t*), jl_method } // invalidate cached methods that overlap this definition -void invalidate_backedges(void (*f)(jl_code_instance_t*), jl_method_instance_t *replaced_mi, size_t max_world, const char *why) +static void invalidate_backedges(void (*f)(jl_code_instance_t*), jl_method_instance_t *replaced_mi, size_t max_world, const char *why) { JL_LOCK(&replaced_mi->def.method->writelock); jl_array_t *backedges = replaced_mi->backedges; + //jl_static_show(JL_STDERR, (jl_value_t*)replaced_mi); if (backedges) { // invalidate callers (if any) replaced_mi->backedges = NULL; diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index b81e0ef5b6489..c207fd7518714 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -125,7 +125,6 @@ XX(jl_environ) \ XX(jl_eof_error) \ XX(jl_eqtable_get) \ - XX(jl_eqtable_nextind) \ XX(jl_eqtable_pop) \ XX(jl_eqtable_put) \ XX(jl_errno) \ diff --git a/src/julia.h b/src/julia.h index df637670dca6d..39ca0ae93bbce 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1635,9 +1635,10 @@ STATIC_INLINE jl_function_t *jl_get_function(jl_module_t *m, const char *name) } // eq hash tables -JL_DLLEXPORT jl_array_t *jl_eqtable_put(jl_array_t *h, jl_value_t *key, jl_value_t *val, int *inserted); -JL_DLLEXPORT jl_value_t *jl_eqtable_get(jl_array_t *h, jl_value_t *key, jl_value_t *deflt) JL_NOTSAFEPOINT; -jl_value_t *jl_eqtable_getkey(jl_array_t *h, jl_value_t *key, jl_value_t *deflt) JL_NOTSAFEPOINT; +JL_DLLEXPORT jl_array_t *jl_eqtable_put(jl_array_t *h JL_ROOTING_ARGUMENT, jl_value_t *key, jl_value_t *val JL_ROOTED_ARGUMENT, int *inserted); +JL_DLLEXPORT jl_value_t *jl_eqtable_get(jl_array_t *h JL_PROPAGATES_ROOT, jl_value_t *key, jl_value_t *deflt) JL_NOTSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_eqtable_pop(jl_array_t *h, jl_value_t *key, jl_value_t *deflt, int *found); +jl_value_t *jl_eqtable_getkey(jl_array_t *h JL_PROPAGATES_ROOT, jl_value_t *key, jl_value_t *deflt) JL_NOTSAFEPOINT; // system information JL_DLLEXPORT int jl_errno(void) JL_NOTSAFEPOINT; @@ -1814,6 +1815,7 @@ JL_DLLEXPORT jl_value_t *jl_compress_argnames(jl_array_t *syms); JL_DLLEXPORT jl_array_t *jl_uncompress_argnames(jl_value_t *syms); JL_DLLEXPORT jl_value_t *jl_uncompress_argname_n(jl_value_t *syms, size_t i); + JL_DLLEXPORT int jl_is_operator(char *sym); JL_DLLEXPORT int jl_is_unary_operator(char *sym); JL_DLLEXPORT int jl_is_unary_and_binary_operator(char *sym); diff --git a/src/julia_internal.h b/src/julia_internal.h index 65503d472b352..6a9955da48122 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -224,7 +224,6 @@ extern tracer_cb jl_newmeth_tracer; void jl_call_tracer(tracer_cb callback, jl_value_t *tracee); void print_func_loc(JL_STREAM *s, jl_method_t *m); extern jl_array_t *_jl_debug_method_invalidation JL_GLOBALLY_ROOTED; -void invalidate_backedges(void (*f)(jl_code_instance_t*), jl_method_instance_t *replaced_mi, size_t max_world, const char *why); extern JL_DLLEXPORT size_t jl_page_size; extern jl_function_t *jl_typeinf_func; @@ -642,15 +641,18 @@ jl_method_instance_t *jl_method_lookup(jl_value_t **args, size_t nargs, size_t w jl_value_t *jl_gf_invoke_by_method(jl_method_t *method, jl_value_t *gf, jl_value_t **args, size_t nargs); jl_value_t *jl_gf_invoke(jl_value_t *types, jl_value_t *f, jl_value_t **args, size_t nargs); +JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup_worlds(jl_value_t *types, jl_value_t *mt, size_t world, size_t *min_world, size_t *max_world); JL_DLLEXPORT jl_value_t *jl_matching_methods(jl_tupletype_t *types, jl_value_t *mt, int lim, int include_ambiguous, size_t world, size_t *min_valid, size_t *max_valid, int *ambig); +JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup_worlds(jl_value_t *types, jl_value_t *mt, size_t world, size_t *min_world, size_t *max_world); + JL_DLLEXPORT jl_datatype_t *jl_first_argument_datatype(jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_argument_datatype(jl_value_t *argt JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_methtable_t *jl_method_table_for( jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_methtable_t *jl_method_get_table( - jl_method_t *method) JL_NOTSAFEPOINT; + jl_method_t *method JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; jl_methtable_t *jl_argument_method_table(jl_value_t *argt JL_PROPAGATES_ROOT); JL_DLLEXPORT int jl_pointer_egal(jl_value_t *t); @@ -874,6 +876,8 @@ JL_DLLEXPORT jl_method_instance_t *jl_specializations_get_linfo( jl_method_instance_t *jl_specializations_get_or_insert(jl_method_instance_t *mi_ins); JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, jl_method_instance_t *caller); JL_DLLEXPORT void jl_method_table_add_backedge(jl_methtable_t *mt, jl_value_t *typ, jl_value_t *caller); +JL_DLLEXPORT void jl_mi_cache_insert(jl_method_instance_t *mi JL_ROOTING_ARGUMENT, + jl_code_instance_t *ci JL_ROOTED_ARGUMENT JL_MAYBE_UNROOTED); uint32_t jl_module_next_counter(jl_module_t *m) JL_NOTSAFEPOINT; jl_tupletype_t *arg_type_tuple(jl_value_t *arg1, jl_value_t **args, size_t nargs); diff --git a/src/typemap.c b/src/typemap.c index dfa8ac67f6abc..2401fd49728c2 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -290,7 +290,6 @@ static jl_typemap_t *mtcache_hash_lookup(jl_array_t *cache JL_PROPAGATES_ROOT, j if (cache == (jl_array_t*)jl_an_empty_vec_any) return (jl_typemap_t*)jl_nothing; jl_typemap_t *ml = (jl_typemap_t*)jl_eqtable_get(cache, ty, jl_nothing); - JL_GC_PROMISE_ROOTED(ml); // clang-sa doesn't trust our JL_PROPAGATES_ROOT claim return ml; } diff --git a/test/precompile.jl b/test/precompile.jl index 072d0ba694699..12634a7512a78 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -630,16 +630,11 @@ precompile_test_harness("code caching") do dir msize = which(size, (Vector{<:Any},)) hasspec = false for i = 1:length(msize.specializations) - if isassigned(msize.specializations, i) - mi = msize.specializations[i] - if isa(mi, Core.MethodInstance) - tt = Base.unwrap_unionall(mi.specTypes) - if tt.parameters[2] == Vector{Cacheb8321416e8a3e2f1.X} - if isdefined(mi, :cache) && isa(mi.cache, Core.CodeInstance) && mi.cache.max_world == typemax(UInt) && mi.cache.inferred !== nothing - hasspec = true - break - end - end + mi = msize.specializations[i] + if isa(mi, Core.MethodInstance) && mi.specTypes == Tuple{typeof(size),Vector{Cacheb8321416e8a3e2f1.X}} + if isdefined(mi, :cache) && isa(mi.cache, Core.CodeInstance) && mi.cache.max_world == typemax(UInt) && mi.cache.inferred !== nothing + hasspec = true + break end end end @@ -659,7 +654,7 @@ precompile_test_harness("code caching") do dir # Check that internal methods and their roots are accounted appropriately minternal = which(M.getelsize, (Vector,)) mi = minternal.specializations[1] - @test Base.unwrap_unionall(mi.specTypes).parameters[2] == Vector{Int32} + @test mi.specTypes == Tuple{typeof(M.getelsize),Vector{Int32}} ci = mi.cache @test ci.relocatability == 1 @test ci.inferred !== nothing @@ -775,7 +770,7 @@ precompile_test_harness("code caching") do dir end end - # Invalidations (this test is adapted from from SnoopCompile) + # Invalidations (this test is adapted from SnoopCompile) function hasvalid(mi, world) isdefined(mi, :cache) || return false ci = mi.cache @@ -805,6 +800,10 @@ precompile_test_harness("code caching") do dir build_stale(37) stale('c') + ## Reporting tests (unrelated to the above) + nbits(::Int8) = 8 + nbits(::Int16) = 16 + end """ ) @@ -823,6 +822,11 @@ precompile_test_harness("code caching") do dir # force precompilation useA() + ## Reporting tests + call_nbits(x::Integer) = $StaleA.nbits(x) + map_nbits() = map(call_nbits, Integer[Int8(1), Int16(1)]) + map_nbits() + end """ ) @@ -844,9 +848,12 @@ precompile_test_harness("code caching") do dir Base.compilecache(Base.PkgId(string(pkg))) end @eval using $StaleA + MA = getfield(@__MODULE__, StaleA) + Base.eval(MA, :(nbits(::UInt8) = 8)) @eval using $StaleC + invalidations = ccall(:jl_debug_method_invalidation, Any, (Cint,), 1) @eval using $StaleB - MA = getfield(@__MODULE__, StaleA) + ccall(:jl_debug_method_invalidation, Any, (Cint,), 0) MB = getfield(@__MODULE__, StaleB) MC = getfield(@__MODULE__, StaleC) world = Base.get_world_counter() @@ -871,6 +878,31 @@ precompile_test_harness("code caching") do dir m = only(methods(MC.call_buildstale)) mi = m.specializations[1] @test hasvalid(mi, world) # was compiled with the new method + + # Reporting test + @test all(i -> isassigned(invalidations, i), eachindex(invalidations)) + m = only(methods(MB.call_nbits)) + for mi in m.specializations + mi === nothing && continue + hv = hasvalid(mi, world) + @test mi.specTypes.parameters[end] === Integer ? !hv : hv + end + + idxs = findall(==("verify_methods"), invalidations) + idxsbits = filter(idxs) do i + mi = invalidations[i-1] + mi.def == m + end + idx = only(idxsbits) + tagbad = invalidations[idx+1] + @test isa(tagbad, Int32) + j = findfirst(==(tagbad), invalidations) + @test invalidations[j-1] == "insert_backedges_callee" + @test isa(invalidations[j-2], Type) + @test isa(invalidations[j+1], Vector{Any}) # [nbits(::UInt8)] + + m = only(methods(MB.map_nbits)) + @test !hasvalid(m.specializations[1], world+1) # insert_backedges invalidations also trigger their backedges end # test --compiled-modules=no command line option From 992d4cae975ff9fb3685b7d39adcd1dbbbfa6ca7 Mon Sep 17 00:00:00 2001 From: KristofferC Date: Wed, 14 Dec 2022 12:51:08 +0100 Subject: [PATCH 25/26] bump SparseArrays to latest 1.8 --- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + stdlib/SparseArrays.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/SparseArrays-1d3ec8656939cc8a2c6c67fa51b76995fd72b8a6.tar.gz/md5 delete mode 100644 deps/checksums/SparseArrays-1d3ec8656939cc8a2c6c67fa51b76995fd72b8a6.tar.gz/sha512 create mode 100644 deps/checksums/SparseArrays-522bb536dc68ac8abd4710b1bfa8909609ad7382.tar.gz/md5 create mode 100644 deps/checksums/SparseArrays-522bb536dc68ac8abd4710b1bfa8909609ad7382.tar.gz/sha512 diff --git a/deps/checksums/SparseArrays-1d3ec8656939cc8a2c6c67fa51b76995fd72b8a6.tar.gz/md5 b/deps/checksums/SparseArrays-1d3ec8656939cc8a2c6c67fa51b76995fd72b8a6.tar.gz/md5 deleted file mode 100644 index 1e22b80501a93..0000000000000 --- a/deps/checksums/SparseArrays-1d3ec8656939cc8a2c6c67fa51b76995fd72b8a6.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -e62b7c98591daeddeefc775c67a5a174 diff --git a/deps/checksums/SparseArrays-1d3ec8656939cc8a2c6c67fa51b76995fd72b8a6.tar.gz/sha512 b/deps/checksums/SparseArrays-1d3ec8656939cc8a2c6c67fa51b76995fd72b8a6.tar.gz/sha512 deleted file mode 100644 index 8aff3bdef2ba0..0000000000000 --- a/deps/checksums/SparseArrays-1d3ec8656939cc8a2c6c67fa51b76995fd72b8a6.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -10552c210f4152611e65aa7a6f92e382ab3aea51abfd712ca8eb1f42826b1f0c9358bb98a0e54a8b4167f9cb9f9a84a98020be4922084480a3faeae76c072eaf diff --git a/deps/checksums/SparseArrays-522bb536dc68ac8abd4710b1bfa8909609ad7382.tar.gz/md5 b/deps/checksums/SparseArrays-522bb536dc68ac8abd4710b1bfa8909609ad7382.tar.gz/md5 new file mode 100644 index 0000000000000..cbf7923517897 --- /dev/null +++ b/deps/checksums/SparseArrays-522bb536dc68ac8abd4710b1bfa8909609ad7382.tar.gz/md5 @@ -0,0 +1 @@ +67b83fb1f95dd1fd5669b13736e8a20a diff --git a/deps/checksums/SparseArrays-522bb536dc68ac8abd4710b1bfa8909609ad7382.tar.gz/sha512 b/deps/checksums/SparseArrays-522bb536dc68ac8abd4710b1bfa8909609ad7382.tar.gz/sha512 new file mode 100644 index 0000000000000..8126d925e5509 --- /dev/null +++ b/deps/checksums/SparseArrays-522bb536dc68ac8abd4710b1bfa8909609ad7382.tar.gz/sha512 @@ -0,0 +1 @@ +163afbdd2d9f2baf0fb7690ae98858053b40bad6924bb6776ddbefa2a2b0a20794ffb63c78f4e091f31691c88762658c26aaccf1af67ebe619ab736b8a89a8ad diff --git a/stdlib/SparseArrays.version b/stdlib/SparseArrays.version index cdee6b6ffc516..debf6f81cdb00 100644 --- a/stdlib/SparseArrays.version +++ b/stdlib/SparseArrays.version @@ -1,4 +1,4 @@ SPARSEARRAYS_BRANCH = main -SPARSEARRAYS_SHA1 = 1d3ec8656939cc8a2c6c67fa51b76995fd72b8a6 +SPARSEARRAYS_SHA1 = 522bb536dc68ac8abd4710b1bfa8909609ad7382 SPARSEARRAYS_GIT_URL := https://github.com/JuliaSparse/SparseArrays.jl.git SPARSEARRAYS_TAR_URL = https://api.github.com/repos/JuliaSparse/SparseArrays.jl/tarball/$1 From 3f58584277ace0ed8ad530e424f30890efdf9011 Mon Sep 17 00:00:00 2001 From: KristofferC Date: Thu, 15 Dec 2022 14:50:47 +0100 Subject: [PATCH 26/26] bump Pkg to latest 1.8 --- .../Pkg-354530e4c8c3215d92ae15672e7a2bab1db62f76.tar.gz/md5 | 1 - .../Pkg-354530e4c8c3215d92ae15672e7a2bab1db62f76.tar.gz/sha512 | 1 - .../Pkg-b09e05add2442b2ffae9d7bdd7976a7d36949433.tar.gz/md5 | 1 + .../Pkg-b09e05add2442b2ffae9d7bdd7976a7d36949433.tar.gz/sha512 | 1 + stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Pkg-354530e4c8c3215d92ae15672e7a2bab1db62f76.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-354530e4c8c3215d92ae15672e7a2bab1db62f76.tar.gz/sha512 create mode 100644 deps/checksums/Pkg-b09e05add2442b2ffae9d7bdd7976a7d36949433.tar.gz/md5 create mode 100644 deps/checksums/Pkg-b09e05add2442b2ffae9d7bdd7976a7d36949433.tar.gz/sha512 diff --git a/deps/checksums/Pkg-354530e4c8c3215d92ae15672e7a2bab1db62f76.tar.gz/md5 b/deps/checksums/Pkg-354530e4c8c3215d92ae15672e7a2bab1db62f76.tar.gz/md5 deleted file mode 100644 index 7fb351bc6dcd9..0000000000000 --- a/deps/checksums/Pkg-354530e4c8c3215d92ae15672e7a2bab1db62f76.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -1f97646bd4a79fd623faaa029c730e3c diff --git a/deps/checksums/Pkg-354530e4c8c3215d92ae15672e7a2bab1db62f76.tar.gz/sha512 b/deps/checksums/Pkg-354530e4c8c3215d92ae15672e7a2bab1db62f76.tar.gz/sha512 deleted file mode 100644 index b3adde51f2d0e..0000000000000 --- a/deps/checksums/Pkg-354530e4c8c3215d92ae15672e7a2bab1db62f76.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -8eb01bd4690f87d69104284721ec48238f914e8dbcb91df495062794fa26e2c60505b68e990123b532b7c65bca134014a41da60d101ea7b9a711a52939a815f8 diff --git a/deps/checksums/Pkg-b09e05add2442b2ffae9d7bdd7976a7d36949433.tar.gz/md5 b/deps/checksums/Pkg-b09e05add2442b2ffae9d7bdd7976a7d36949433.tar.gz/md5 new file mode 100644 index 0000000000000..b51723e7b9856 --- /dev/null +++ b/deps/checksums/Pkg-b09e05add2442b2ffae9d7bdd7976a7d36949433.tar.gz/md5 @@ -0,0 +1 @@ +a55ebf3435144ba9421e11d224ab08cd diff --git a/deps/checksums/Pkg-b09e05add2442b2ffae9d7bdd7976a7d36949433.tar.gz/sha512 b/deps/checksums/Pkg-b09e05add2442b2ffae9d7bdd7976a7d36949433.tar.gz/sha512 new file mode 100644 index 0000000000000..bc628fa05b679 --- /dev/null +++ b/deps/checksums/Pkg-b09e05add2442b2ffae9d7bdd7976a7d36949433.tar.gz/sha512 @@ -0,0 +1 @@ +f30266649b9f16af640d7e98156ef1a957b36c986348de9d54414be1de18d9ee2bb155d570da066c3b10e56d6df86a87fca3c7b2c0338cfd6d0767f7ce6ec3dd diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 5614030a2a07c..9ee8bf1522c11 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = release-1.8 -PKG_SHA1 = 354530e4c8c3215d92ae15672e7a2bab1db62f76 +PKG_SHA1 = b09e05add2442b2ffae9d7bdd7976a7d36949433 PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1