Skip to content

Commit

Permalink
Revert "inference: implement an opt-in interface to cache generated s…
Browse files Browse the repository at this point in the history
…ources (…"

This reverts commit b5d0b90.
  • Loading branch information
vtjnash committed Jun 28, 2024
1 parent 334e4d9 commit 7331859
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 72 deletions.
7 changes: 0 additions & 7 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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} =
Expand Down
16 changes: 1 addition & 15 deletions base/compiler/utilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
54 changes: 29 additions & 25 deletions test/compiler/contextual.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -72,36 +75,38 @@ 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...}
match = Base._which(tt; world)
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
Expand Down Expand Up @@ -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

Expand Down
25 changes: 0 additions & 25 deletions test/staged.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 7331859

Please sign in to comment.