The lowered AST is what you get when you call expand on any other AST. It
is a simplified format that is easier to analyze, type-infer, and execute.
However, it is still a regular AST object, so you can modify it and
recreate another function with it just like the pre-expanded version (in
fact, this is what inference.jl does). The first few arrays in the lambda
provide information to the compiler. The first is the argument list. The
next is a list of (local variables list, variable info, captured variable
list)

The problem with your code is that you are trying to mutate internal
compiler state, and it has no idea that you are trying to do so. It has
already optimized the call for that function, and no longer cares about the
code.ast field for that lambda. What you really want is a new function
entirely:

julia> function recompile(func1, func2, args)
           code1 = get_code(func1, args)
           code2 = get_code(func2, args)

           @assert code1.module == code2.module

           eval_code1 = code1.module.eval(code1)
           eval_res1 = eval_code1(args...)
           @assert eval_res1 == func1(args...)
           println("eval_code: $(eval_res1)")

           eval_code2 = code2.module.eval(code2)
           eval_res2 = eval_code2(args...)
           @assert eval_res2 == func2(args...)
           println("eval_code: $(eval_res2)")

           ast1 = ccall(:jl_uncompress_ast, Any, (Any, Any), code1, code1.ast)
           println("ast1: $(ast1.args[3])")

           ast2 = ccall(:jl_uncompress_ast, Any, (Any, Any), code2, code2.ast)

           code3 = Expr(:function, Expr(:tuple, ast2.args[1]...),
Expr(:block, ast2.args[3].args...))
        # what did we construct? how does it compare to `:(
function(a,b) a+b end )|>dump`?
        # dump(code3); Meta.show_sexpr(code3); println()
           eval_new_code = code1.module.eval(code3)
           eval_new_res = eval_new_code(args...)

           @assert eval_new_res == func2(args...)
           println("eval_new_code: $(eval_new_res)")
       end
recompile (generic function with 1 method)

julia> recompile(+, -, (1.2, 3.4))
eval_code: 4.6
eval_code: -2.2
ast1: begin  # float.jl, line 192:
    return box(Float64,sub_float(unbox(Float64,x),unbox(Float64,y)))
end
Expr
  head: Symbol function
  args: Array(Any,(2,))
    1: Expr
      head: Symbol tuple
      args: Array(Any,(2,))
        1: Symbol x
        2: Symbol y
      typ: Any
    2: Expr
      head: Symbol block
      args: Array(Any,(2,))
        1: Expr
          head: Symbol line
          args: Array(Any,(2,))
          typ: Any
        2: Expr
          head: Symbol return
          args: Array(Any,(1,))
          typ: Any
      typ: Any
  typ: Any
(:function, (:tuple, :x, :y), (:block,
    (:line, 192, symbol("float.jl")),
    (:return, (:call, :box, :Float64, (:call, :sub_float, (:call,
:unbox, :Float64, :x), (:call, :unbox, :Float64, :y))))
  ))
eval_new_code: -2.2

On Thu Dec 18 2014 at 1:14:32 PM Yichao Yu <[email protected]> wrote:

Hi,
>
> I'm wondering if there's a way to recompile the lowered AST back into a
> function and what additional information (other than the module it should
> be
> evaluate in) is necessary to do that what I've tried and would like to do
> is
> demonstrated with the code attached. The idea is that I would like to
> modify
> the code of a function/method before calling it (in this case, I am
> replacing
> it with the code from another function with the same signature). (In
> another
> word, the question is how to construct a function from code1 with ast2 and
> run
> it.)
>
> It will also be nice if there's more documentation on this "lowered AST"
> since
> it seems to be very different form the one you get in a function
> definition.
> (e.g. what is the array in `code_lowered(+, (Float64, Float64))[1].args[2]`
> mean)
>
> A brief description of what I want to do. I'm writing a control system with
> dynamic logic. However, since the code might not be running on a single
> host,
> it is hard to use an existing interpreter to do what I want. Trying to
> avoid
> inventing yet another language, I hope to use a subset of an existing
> language
> and somehow transform it into a representation that can be run somewhere
> else
> and it seems that the inspection and meta programming feature in julia is
> very
> useful for this. It might be possible to just apply a macro to every
> function
> / method definition but it will be much harder to write. I would rather
> try to
> "trace" the excution and use the AST acquired at runtime. For that I would
> like to know more about the lowered AST and possibly how to execute a
> modified
> version in order to trace recursive / nested function calls. This might
> not be
> the best way to do it and I'm still in planning stage so any suggestions on
> the design is also welcome.
>
> Cheers,
>
> Yichao Yu
>
​

Reply via email to