Stream: helpdesk (published)

Topic: overwrite method table


view this post on Zulip Maarten (Jul 09 2024 at 12:46):

I would like to highjack all calls to a particular function.

I've tried cassette, but this runs into the llvmcall issue. I've tried cassetteoverlay, but that breaks julia entirely (argextype called on Expr with head :call which is not valid for IR in argument-position.) I've also looked at irtools/dynamo, but run into an issue where irtools breaks on certain broadcast expressions.

I realise that I'm trying to do something that is highly discouraged and hacky, but do there nevertheless exist other solutions that I haven't explored yet? It seems that Cassette work has somewhat stalled with the promise that some work in base (abstractinterpreter) will allow for a more robust cassette like implementation. Does that exist somewhere?

view this post on Zulip DrChainsaw (Jul 10 2024 at 08:02):

A low-tech option is to create an own type and just implement methods for it until you are able to hit the function you want to overwrite.

view this post on Zulip Maarten (Jul 10 2024 at 08:30):

That'd be a lot of work that I would ideally avoid. One workaround for me may be to hack on top of JuliaInterpreter.

They have a global dictionary that links methods with their frames, so all I'd need to do is manually insert the calls that I want to detour there...

view this post on Zulip Maarten (Jul 10 2024 at 09:54):

Nevermind, juliainterpreter is too slow

view this post on Zulip Sukera (Jul 10 2024 at 10:02):

you'll probably want to watch this talk that just ended https://pretalx.com/juliacon2024/talk/D88XFU/

view this post on Zulip Sukera (Jul 10 2024 at 10:02):

the recording will be up on youtube at some point

view this post on Zulip Sukera (Jul 10 2024 at 10:02):

the live stream is https://www.youtube.com/watch?v=OQnHyHgs0Qo, you should be able to scroll back ~30 minutes (at time of writing)

view this post on Zulip Sukera (Jul 10 2024 at 10:03):

I doubt a bit though whether this is less work :sweat_smile:

view this post on Zulip Maarten (Jul 10 2024 at 10:05):

watching it now :)

view this post on Zulip Maarten (Jul 10 2024 at 10:06):

I may also take some inspiration from infiltrator.jl

view this post on Zulip Sukera (Jul 10 2024 at 10:06):

I think both Cassette.jl and Infiltrator.jl are going to be completely subsumed by that talk

view this post on Zulip Sukera (Jul 10 2024 at 10:07):

oh, right before that talk was another ~half hour talk explaining the basic compiler/optimization pipeline which might be useful if you're not already familiar with it

view this post on Zulip Maarten (Jul 10 2024 at 10:37):

If that talk gets merged, it'd be perfect !

view this post on Zulip Mason Protter (Jul 10 2024 at 12:49):

What doesn't work for you with cassetteoverlay?

view this post on Zulip Maarten (Jul 10 2024 at 13:01):

something deep within julia's abstracteval errors. The code partially runs after spitting out an enormous stacktrace. I don't have a real "minimal" working example, but I did open an issue https://github.com/JuliaDebug/CassetteOverlay.jl/issues/57

view this post on Zulip Maarten (Jul 10 2024 at 13:03):

https://gist.github.com/maartenvd/e9e3afbefe2577a0c504bdb217508ea8 for an example part of the stacktrace

view this post on Zulip Maarten (Jul 10 2024 at 13:03):

Interestingly on master I get an entirely different error, but an error nevertheless

view this post on Zulip Maarten (Jul 11 2024 at 13:38):

I think I found the problem with IRtools dynamo...

view this post on Zulip Maarten (Jul 12 2024 at 13:17):

I forgot that I can simply re-use some of the amazing work in Revise/CodeTracking!

view this post on Zulip Maarten (Jul 12 2024 at 18:22):

using Revise, CodeTracking

function hello(a::String)
    println(a)
end

function detourhack(::typeof(hello),a::String)
    println("detoured "*a)
end

detourtable = Any[]
for detour in methods(Main.detourhack)
    orig = which(Tuple{detour.sig.parameters[2:end]...})
    orig_expr = definition(orig)
    push!(detourtable,(detour,orig,orig_expr))
end

function enable_highjack()
    tsymb = GlobalRef(Main,:detourhack)
    for (detour,orig,orig_expr) in detourtable
        orsigparams = orig.sig.parameters
        pars = [gensym() for v in orsigparams]
        fdeff = Expr(:call,[Expr(:(::),a,b) for (a,b) in zip(pars,orsigparams)]...)
        body = Expr(:call,tsymb,pars...)
        orig.module.eval(Expr(:function,fdeff,body))
    end
end

function disable_highjack()
    for (detour,orig,orig_expr) in detourtable
        orig.module.eval(orig_expr)
    end
end

julia> hello("world")
world
julia>enable_highjack()
julia>hello("world")
detoured world

I don't know how to make this work with kwargs though


Last updated: Nov 06 2024 at 04:40 UTC