diff --git a/.github/workflows/precompile.yml b/.github/workflows/precompile.yml new file mode 100644 index 000000000..d90ad59f6 --- /dev/null +++ b/.github/workflows/precompile.yml @@ -0,0 +1,40 @@ +name: Regenerate precompile statements +on: + workflow_dispatch: +permissions: # Permissions for the `GITHUB_TOKEN` token + contents: write + pull-requests: write +concurrency: + # Skip intermediate builds: all builds except for builds on the `master` or `release-*` branches + # Cancel intermediate builds: only pull request builds + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.ref != 'refs/heads/master' || startsWith(github.ref, 'refs/heads/release-') || github.run_number }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} +jobs: + regenerate_precompile_statements: + name: Regenerate precompile statements + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v2 + with: + persist-credentials: false + - uses: julia-actions/setup-julia@v1 + with: + version: 'nightly' # TODO: delete this line once Julia 1.9 is releease + # version: '1' # TODO: uncomment this line once Julia 1.9 is releease + - name: Instantiate + run: julia --project -e 'import Pkg; Pkg.instantiate(); Pkg.update(); Pkg.precompile()' + - name: Run the `contrib/precompile_generate.jl` script + run: julia --project contrib/precompile_generate.jl + - name: Create (or update) the pull request + uses: peter-evans/create-pull-request@18f7dc018cc2cd597073088f7c7591b9d1c02672 # v3.14.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + branch: "bot/regenerate-precompile-statements" + delete-branch: true + commit-message: "🤖 Regenerate the precompile statements" + title: "🤖 Regenerate the precompile statements" + body: | + This PR regenerates the precompile statements. + Note: CI will not automatically run on this PR. To run CI, please + close and reopen the PR. diff --git a/contrib/precompile_generate.jl b/contrib/precompile_generate.jl new file mode 100644 index 000000000..df951a424 --- /dev/null +++ b/contrib/precompile_generate.jl @@ -0,0 +1,96 @@ +function gen_single_tracefile( + code::AbstractString, + tracefile::AbstractString, + ) + julia_binary = Base.julia_cmd().exec[1] + cmd = `$(julia_binary)` + push!(cmd.exec, "--compile=all") + push!(cmd.exec, "--trace-compile=$(tracefile)") + push!(cmd.exec, "-e $(code)") + splitter = Sys.iswindows() ? ';' : ':' + project = Base.active_project() + env2 = copy(ENV) + env2["JULIA_LOAD_PATH"] = "$(project)$(splitter)@stdlib" + env2["JULIA_PROJECT"] = "$(project)" + run(setenv(cmd, env2)) + return nothing +end + +function gen_single_precompile(code::AbstractString) + str = mktempdir() do dir + tracefile = joinpath(dir, "tracefile") + gen_single_tracefile(code, tracefile) + return read(tracefile, String)::String + end::String + lines = convert( + Vector{String}, + strip.(split(strip(str), '\n')), + )::Vector{String} + filter!(line -> !isempty(line), lines) + return lines +end + +function gen_all_precompile() + codes = String[ + "import HTTP; HTTP.get(\"https://example.com/\")", + ] + all_lines = String[] + for code in codes + lines = gen_single_precompile(code) + append!(all_lines, lines) + end + unique!(all_lines) +end + +function write_all_precompile(io::IO, all_lines::Vector{String}) + preamble_lines = String[ + "import MbedTLS", + "const MbedTLS_jll = MbedTLS.MbedTLS_jll" + ] + for line in preamble_lines + println(io, line) + end + println(io) + println(io, """ + function _precompile() + """) + println(io, """ + if ccall(:jl_generating_output, Cint, ()) != 1 + return nothing + end + """) + println(io, """ + @static if Base.VERSION < v"1.9-" + # We need https://github.com/JuliaLang/julia/pull/43990, otherwise this isn't worth doing. + return nothing + end + """) + for line in all_lines + println(io, " ", line) + end + println(io) + println(io, """ + return nothing + end + """) + return nothing +end + +function write_all_precompile( + output_file::AbstractString, + all_lines::Vector{String}, + ) + open(output_file, "w") do io + write_all_precompile(io, all_lines) + end + return nothing +end + +function main() + output_file = joinpath(dirname(@__DIR__), "src", "precompile.jl") + all_lines = gen_all_precompile() + write_all_precompile(output_file, all_lines) + return nothing +end + +main() diff --git a/src/HTTP.jl b/src/HTTP.jl index cf6824d24..a40191aee 100644 --- a/src/HTTP.jl +++ b/src/HTTP.jl @@ -631,4 +631,7 @@ function Base.parse(::Type{T}, str::AbstractString)::T where T <: Message return m end +include("precompile.jl") +_precompile() + end # module diff --git a/src/precompile.jl b/src/precompile.jl new file mode 100644 index 000000000..dad40fa2a --- /dev/null +++ b/src/precompile.jl @@ -0,0 +1,73 @@ +import MbedTLS +const MbedTLS_jll = MbedTLS.MbedTLS_jll + +function _precompile() + + if ccall(:jl_generating_output, Cint, ()) != 1 + return nothing + end + + @static if Base.VERSION < v"1.9-" + # We need https://github.com/JuliaLang/julia/pull/43990, otherwise this isn't worth doing. + return nothing + end + + precompile(Tuple{typeof(Base.:(!=)), UInt64, UInt64}) + precompile(Tuple{typeof(MbedTLS_jll.__init__)}) + precompile(Tuple{typeof(MbedTLS.f_send), Ptr{Nothing}, Ptr{UInt8}, UInt64}) + precompile(Tuple{typeof(MbedTLS.f_recv), Ptr{Nothing}, Ptr{UInt8}, UInt64}) + precompile(Tuple{typeof(MbedTLS.__init__)}) + precompile(Tuple{typeof(URIs.__init__)}) + precompile(Tuple{typeof(HTTP.Parsers.__init__)}) + precompile(Tuple{typeof(HTTP.CookieRequest.__init__)}) + precompile(Tuple{typeof(HTTP.ConnectionRequest.__init__)}) + precompile(Tuple{typeof(HTTP.Servers.__init__)}) + precompile(Tuple{typeof(HTTP.MultiPartParsing.__init__)}) + precompile(Tuple{typeof(HTTP.get), String}) + precompile(Tuple{Type{NamedTuple{(:init,), T} where T<:Tuple}, Tuple{DataType}}) + precompile(Tuple{Base.var"#reduce##kw", NamedTuple{(:init,), Tuple{DataType}}, typeof(Base.reduce), Function, Base.Set{Tuple{Union{Type{Union{}}, UnionAll}, UnionAll}}}) + precompile(Tuple{typeof(Base.mapfoldl_impl), typeof(Base.identity), HTTP.var"#24#25", Type, Base.Set{Tuple{Union{Type{Union{}}, UnionAll}, UnionAll}}}) + precompile(Tuple{typeof(HTTP.request), Type{HTTP.TopRequest.TopLayer{HTTP.RedirectRequest.RedirectLayer{HTTP.BasicAuthRequest.BasicAuthLayer{HTTP.MessageRequest.MessageLayer{HTTP.RetryRequest.RetryLayer{HTTP.ExceptionRequest.ExceptionLayer{HTTP.ConnectionRequest.ConnectionPoolLayer{HTTP.StreamRequest.StreamLayer{Union{}}}}}}}}}}, String, URIs.URI, Array{Pair{Base.SubString{String}, Base.SubString{String}}, 1}, Array{UInt8, 1}}) + precompile(Tuple{HTTP.var"#request##kw", NamedTuple{(:iofunction, :reached_redirect_limit), Tuple{Nothing, Bool}}, typeof(HTTP.request), Type{HTTP.ExceptionRequest.ExceptionLayer{HTTP.ConnectionRequest.ConnectionPoolLayer{HTTP.StreamRequest.StreamLayer{Union{}}}}}, URIs.URI, HTTP.Messages.Request, Array{UInt8, 1}}) + precompile(Tuple{HTTP.var"#request##kw", NamedTuple{(:iofunction, :reached_redirect_limit), Tuple{Nothing, Bool}}, typeof(HTTP.request), Type{HTTP.ConnectionRequest.ConnectionPoolLayer{HTTP.StreamRequest.StreamLayer{Union{}}}}, URIs.URI, HTTP.Messages.Request, Array{UInt8, 1}}) + precompile(Tuple{typeof(Sockets.uv_getaddrinfocb), Ptr{Nothing}, Int32, Ptr{Nothing}}) + precompile(Tuple{HTTP.ConnectionPool.var"#newconnection##kw", NamedTuple{(:iofunction, :reached_redirect_limit), Tuple{Nothing, Bool}}, typeof(HTTP.ConnectionPool.newconnection), Type{MbedTLS.SSLContext}, Base.SubString{String}, Base.SubString{String}}) + precompile(Tuple{typeof(Sockets.uv_connectcb), Ptr{Nothing}, Int32}) + precompile(Tuple{typeof(Sockets.connect), Sockets.IPv4, UInt64}) + precompile(Tuple{typeof(Base.setproperty!), Sockets.TCPSocket, Symbol, Int64}) + precompile(Tuple{typeof(Base.notify), Base.GenericCondition{Base.Threads.SpinLock}}) + precompile(Tuple{typeof(MbedTLS.f_rng), MbedTLS.CtrDrbg, Ptr{UInt8}, UInt64}) + precompile(Tuple{typeof(Base.isopen), Sockets.TCPSocket}) + precompile(Tuple{typeof(Base.getproperty), Sockets.TCPSocket, Symbol}) + precompile(Tuple{typeof(Base.unsafe_write), Sockets.TCPSocket, Ptr{UInt8}, UInt64}) + precompile(Tuple{typeof(Base.bytesavailable), Sockets.TCPSocket}) + precompile(Tuple{typeof(Base.eof), Sockets.TCPSocket}) + precompile(Tuple{typeof(Base.alloc_buf_hook), Sockets.TCPSocket, UInt64}) + precompile(Tuple{Base.var"#readcb_specialized#671", Sockets.TCPSocket, Int64, UInt64}) + precompile(Tuple{typeof(Base.min), UInt64, Int64}) + precompile(Tuple{typeof(Base.unsafe_read), Sockets.TCPSocket, Ptr{UInt8}, UInt64}) + precompile(Tuple{Type{Int32}, UInt64}) + precompile(Tuple{typeof(HTTP.Messages.hasheader), HTTP.Messages.Request, String}) + precompile(Tuple{typeof(HTTP.Messages.ischunked), HTTP.Messages.Request}) + precompile(Tuple{typeof(HTTP.Messages.writeheaders), Base.GenericIOBuffer{Array{UInt8, 1}}, HTTP.Messages.Request}) + precompile(Tuple{typeof(Base.unsafe_write), MbedTLS.SSLContext, Ptr{UInt8}, UInt64}) + precompile(Tuple{typeof(Base.check_open), Sockets.TCPSocket}) + precompile(Tuple{MbedTLS.var"#25#26"{MbedTLS.SSLContext}}) + precompile(Tuple{typeof(Base.eof), MbedTLS.SSLContext}) + precompile(Tuple{HTTP.StreamRequest.var"#2#3"{HTTP.ConnectionPool.Connection, HTTP.Messages.Request, Array{UInt8, 1}, HTTP.Streams.Stream{HTTP.Messages.Response, HTTP.ConnectionPool.Connection}}}) + precompile(Tuple{typeof(Base.bytesavailable), MbedTLS.SSLContext}) + precompile(Tuple{typeof(Base.unsafe_read), MbedTLS.SSLContext, Ptr{UInt8}, Int64}) + precompile(Tuple{typeof(Base.readuntil), Base.GenericIOBuffer{Array{UInt8, 1}}, typeof(HTTP.Parsers.find_end_of_header)}) + precompile(Tuple{typeof(Base.release), HTTP.ConnectionPool.ConnectionPools.Pool{HTTP.ConnectionPool.Connection}, Tuple{DataType, String, String, Bool, Bool}, HTTP.ConnectionPool.Connection}) + precompile(Tuple{typeof(Base.isequal), Tuple{DataType, String, String, Bool, Bool}, Tuple{DataType, Base.SubString{String}, Base.SubString{String}, Bool, Bool}}) + precompile(Tuple{typeof(Base.isopen), MbedTLS.SSLContext}) + precompile(Tuple{MbedTLS.var"#21#23"{MbedTLS.SSLContext}, MbedTLS.SSLContext}) + precompile(Tuple{MbedTLS.var"#15#16", MbedTLS.CRT}) + precompile(Tuple{MbedTLS.var"#10#11", MbedTLS.CtrDrbg}) + precompile(Tuple{MbedTLS.var"#8#9", MbedTLS.Entropy}) + precompile(Tuple{MbedTLS.var"#17#19", MbedTLS.SSLConfig}) + precompile(Tuple{typeof(Base.uvfinalize), Sockets.TCPSocket}) + + return nothing +end +