From 73318590e198d12dc660c86b40d765d01f0516cc Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 28 Jun 2024 21:27:42 +0200 Subject: [PATCH] =?UTF-8?q?Revert=20"inference:=20implement=20an=20opt-in?= =?UTF-8?q?=20interface=20to=20cache=20generated=20sources=20(=E2=80=A6"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit b5d0b9056969d0512470d2fff46e981032361fcc. --- base/boot.jl | 7 ----- base/compiler/utilities.jl | 16 +---------- test/compiler/contextual.jl | 54 ++++++++++++++++++++----------------- test/staged.jl | 25 ----------------- 4 files changed, 30 insertions(+), 72 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index 1481928b319b7..3d19e46bf5d5d 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -750,13 +750,6 @@ function (g::GeneratedFunctionStub)(world::UInt, source::LineNumberNode, @nospec end end -# If the generator is a subtype of this trait, inference caches the generated unoptimized -# code, sacrificing memory space to improve the performance of subsequent inferences. -# This tradeoff is not appropriate in general cases (e.g., for `GeneratedFunctionStub`s -# generated from the front end), but it can be justified for generators involving complex -# code transformations, such as a Cassette-like system. -abstract type CachedGenerator end - NamedTuple() = NamedTuple{(),Tuple{}}(()) eval(Core, :(NamedTuple{names}(args::Tuple) where {names} = diff --git a/base/compiler/utilities.jl b/base/compiler/utilities.jl index 527c6ab42eb2d..5eb0b718f68cc 100644 --- a/base/compiler/utilities.jl +++ b/base/compiler/utilities.jl @@ -138,27 +138,13 @@ use_const_api(li::CodeInstance) = invoke_api(li) == 2 function get_staged(mi::MethodInstance, world::UInt) may_invoke_generator(mi) || return nothing - cache_ci = (mi.def::Method).generator isa Core.CachedGenerator ? - RefValue{CodeInstance}() : nothing try - return call_get_staged(mi, world, cache_ci) + return ccall(:jl_code_for_staged, Ref{CodeInfo}, (Any, UInt, Ptr{Cvoid}), mi, world, C_NULL) catch # user code might throw errors – ignore them return nothing end end -# enable caching of unoptimized generated code if the generator is `CachedGenerator` -function call_get_staged(mi::MethodInstance, world::UInt, cache_ci::RefValue{CodeInstance}) - token = @_gc_preserve_begin cache_ci - cache_ci_ptr = pointer_from_objref(cache_ci) - src = ccall(:jl_code_for_staged, Ref{CodeInfo}, (Any, UInt, Ptr{CodeInstance}), mi, world, cache_ci_ptr) - @_gc_preserve_end token - return src -end -function call_get_staged(mi::MethodInstance, world::UInt, ::Nothing) - return ccall(:jl_code_for_staged, Ref{CodeInfo}, (Any, UInt, Ptr{Cvoid}), mi, world, C_NULL) -end - function get_cached_uninferred(mi::MethodInstance, world::UInt) ccall(:jl_cached_uninferred, Any, (Any, UInt), mi.cache, world)::CodeInstance end diff --git a/test/compiler/contextual.jl b/test/compiler/contextual.jl index 7f8c8f6e8be9b..f86453c451e71 100644 --- a/test/compiler/contextual.jl +++ b/test/compiler/contextual.jl @@ -10,9 +10,12 @@ module MiniCassette # A minimal demonstration of the cassette mechanism. Doesn't support all the # fancy features, but sufficient to exercise this code path in the compiler. - using Core.IR - using Core.Compiler: retrieve_code_info, quoted, signature_type, anymap + using Core.Compiler: retrieve_code_info, CodeInfo, + MethodInstance, SSAValue, GotoNode, GotoIfNot, ReturnNode, SlotNumber, quoted, + signature_type, anymap + using Base: _methods_by_ftype using Base.Meta: isexpr + using Test export Ctx, overdub @@ -72,12 +75,12 @@ module MiniCassette end end - function overdub_generator(world::UInt, source, self, ctx, f, args) + function overdub_generator(world::UInt, source, self, c, f, args) @nospecialize if !Base.issingletontype(f) # (c, f, args..) -> f(args...) - ex = :(return f(args...)) - return Core.GeneratedFunctionStub(identity, Core.svec(:overdub, :ctx, :f, :args), Core.svec())(world, source, ex) + code_info = :(return f(args...)) + return Core.GeneratedFunctionStub(identity, Core.svec(:overdub, :c, :f, :args), Core.svec())(world, source, code_info) end tt = Tuple{f, args...} @@ -85,23 +88,25 @@ module MiniCassette mi = Core.Compiler.specialize_method(match) # Unsupported in this mini-cassette @assert !mi.def.isva - src = retrieve_code_info(mi, world) - @assert isa(src, CodeInfo) - src = copy(src) - @assert src.edges === nothing - src.edges = MethodInstance[mi] - transform!(mi, src, length(args), match.sparams) + code_info = retrieve_code_info(mi, world) + @assert isa(code_info, CodeInfo) + code_info = copy(code_info) + @assert code_info.edges === nothing + code_info.edges = MethodInstance[mi] + transform!(mi, code_info, length(args), match.sparams) # TODO: this is mandatory: code_info.min_world = max(code_info.min_world, min_world[]) # TODO: this is mandatory: code_info.max_world = min(code_info.max_world, max_world[]) # Match the generator, since that's what our transform! does - src.nargs = 4 - src.isva = true - return src + code_info.nargs = 4 + code_info.isva = true + return code_info end - @inline overdub(::Ctx, f::Union{Core.Builtin, Core.IntrinsicFunction}, args...) = f(args...) + @inline function overdub(c::Ctx, f::Union{Core.Builtin, Core.IntrinsicFunction}, args...) + f(args...) + end - @eval function overdub(ctx::Ctx, f, args...) + @eval function overdub(c::Ctx, f, args...) $(Expr(:meta, :generated_only)) $(Expr(:meta, :generated, overdub_generator)) end @@ -144,15 +149,14 @@ end end # module OverlayModule -let ms = Base._methods_by_ftype(Tuple{typeof(sin), Float64}, nothing, 1, Base.get_world_counter()) - @test only(ms).method.module === Base.Math -end -let ms = Base._methods_by_ftype(Tuple{typeof(sin), Float64}, OverlayModule.mt, 1, Base.get_world_counter()) - @test only(ms).method.module === OverlayModule -end -let ms = Base._methods_by_ftype(Tuple{typeof(sin), Int}, OverlayModule.mt, 1, Base.get_world_counter()) - @test isempty(ms) -end +methods = Base._methods_by_ftype(Tuple{typeof(sin), Float64}, nothing, 1, Base.get_world_counter()) +@test only(methods).method.module === Base.Math + +methods = Base._methods_by_ftype(Tuple{typeof(sin), Float64}, OverlayModule.mt, 1, Base.get_world_counter()) +@test only(methods).method.module === OverlayModule + +methods = Base._methods_by_ftype(Tuple{typeof(sin), Int}, OverlayModule.mt, 1, Base.get_world_counter()) +@test isempty(methods) # precompilation diff --git a/test/staged.jl b/test/staged.jl index 3443fe43cb9b5..6bc3ead35586d 100644 --- a/test/staged.jl +++ b/test/staged.jl @@ -377,28 +377,3 @@ let ir, _ = Base.code_ircode(f_unreachable, ()) |> only @test length(ir.cfg.blocks) == 1 end - -# Test that `Core.CachedGenerator` works as expected -struct Generator54916 <: Core.CachedGenerator end -function (::Generator54916)(world::UInt, source::LineNumberNode, args...) - stub = Core.GeneratedFunctionStub(identity, Core.svec(:doit54916, :func, :arg), Core.svec()) - return stub(world, source, :(func(arg))) -end -@eval function doit54916(func, arg) - $(Expr(:meta, :generated, Generator54916())) - $(Expr(:meta, :generated_only)) -end -@test doit54916(sin, 1) == sin(1) -let mi = only(methods(doit54916)).specializations - ci = mi.cache::Core.CodeInstance - found = false - while true - if ci.owner === :uninferred && ci.inferred isa Core.CodeInfo - found = true - break - end - isdefined(ci, :next) || break - ci = ci.next - end - @test found -end