Ai
21 Star 49 Fork 0

Gitee 极速下载/julia-language

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
此仓库是为了提升国内下载速度的镜像仓库,每日同步一次。 原始仓库: https://github.com/JuliaLang/julia
克隆/下载
contextual.jl 5.77 KB
一键复制 编辑 原始数据 按行查看 历史
Shuhei Kadowaki 提交于 2025-05-06 19:05 +08:00 . use src.nargs for validate_code! (#58327)
# This file is a part of Julia. License is MIT: https://julialang.org/license
module contextual
# N.B.: This file is also run from interpreter.jl, so needs to be standalone-executable
using Test
# Cassette
# ========
# TODO Use CassetteBase.jl instead of this mini-cassette?
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: SimpleVector
using Core.IR
using Base: Compiler as CC
using .CC: retrieve_code_info, quoted, anymap
using Base.Meta: isexpr
export Ctx, overdub
struct Ctx; end
# A no-op cassette-like transform
function transform_expr(expr, map_slot_number, map_ssa_value, sparams::SimpleVector)
@nospecialize expr
transform(@nospecialize expr) = transform_expr(expr, map_slot_number, map_ssa_value, sparams)
if isexpr(expr, :call)
return Expr(:call, overdub, SlotNumber(2), anymap(transform, expr.args)...)
elseif isa(expr, GotoIfNot)
return GotoIfNot(transform(expr.cond), map_ssa_value(SSAValue(expr.dest)).id)
elseif isexpr(expr, :static_parameter)
return quoted(sparams[expr.args[1]])
elseif isa(expr, ReturnNode)
return ReturnNode(transform(expr.val))
elseif isa(expr, Expr)
return Expr(expr.head, anymap(transform, expr.args)...)
elseif isa(expr, GotoNode)
return GotoNode(map_ssa_value(SSAValue(expr.label)).id)
elseif isa(expr, SlotNumber)
return map_slot_number(expr.id)
elseif isa(expr, SSAValue)
return map_ssa_value(expr)
else
return expr
end
end
function transform!(mi::MethodInstance, ci::CodeInfo, nargs::Int, sparams::SimpleVector)
code = ci.code
di = CC.DebugInfoStream(mi, ci.debuginfo, length(code))
ci.slotnames = Symbol[Symbol("#self#"), :ctx, :f, :args, ci.slotnames[nargs+2:end]...]
ci.slotflags = UInt8[(0x00 for i = 1:4)..., ci.slotflags[nargs+2:end]...]
# Insert one SSAValue for every argument statement
prepend!(code, Any[Expr(:call, getfield, SlotNumber(4), i) for i = 1:nargs])
prepend!(di.codelocs, fill(Int32(0), 3nargs))
prepend!(ci.ssaflags, fill(0x00, nargs))
ci.debuginfo = Core.DebugInfo(di, length(code))
ci.ssavaluetypes += nargs
function map_slot_number(slot::Int)
if slot == 1
# self in the original function is now `f`
return SlotNumber(3)
elseif 2 <= slot <= nargs + 1
# Arguments get inserted as ssa values at the top of the function
return SSAValue(slot - 1)
else
# The first non-argument slot will be 5
return SlotNumber(slot - (nargs + 1) + 4)
end
end
map_ssa_value(ssa::SSAValue) = SSAValue(ssa.id + nargs)
for i = (nargs+1:length(code))
code[i] = transform_expr(code[i], map_slot_number, map_ssa_value, sparams)
end
end
function overdub_generator(world::UInt, source, self, ctx, f, args)
@nospecialize
argnames = Core.svec(:overdub, :ctx, :f, :args)
spnames = Core.svec()
if !Base.issingletontype(f)
# (c, f, args..) -> f(args...)
return generate_lambda_ex(world, source, argnames, spnames, :(return f(args...)))
end
tt = Tuple{f, args...}
match = Base._which(tt; world)
mi = Base.specialize_method(match)
# Unsupported in this mini-cassette
!mi.def.isva ||
return generate_lambda_ex(world, source, argnames, spnames, :(error("Unsupported vararg method")))
src = retrieve_code_info(mi, world)
isa(src, CodeInfo) ||
return generate_lambda_ex(world, source, argnames, spnames, :(error("Unexpected code transformation")))
src = copy(src)
src.edges === Core.svec() ||
return generate_lambda_ex(world, source, argnames, spnames, :(error("Unexpected code transformation")))
src.edges = Any[mi]
transform!(mi, src, 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
errors = CC.validate_code(mi, src)
if !isempty(errors)
foreach(Core.println, errors)
return generate_lambda_ex(world, source, argnames, spnames, :(error("Found errors in generated code")))
end
return src
end
function generate_lambda_ex(world::UInt, source::Method,
argnames::SimpleVector, spnames::SimpleVector,
body::Expr)
stub = Core.GeneratedFunctionStub(identity, argnames, spnames)
return stub(world, source, body)
end
@inline overdub(::Ctx, f::Union{Core.Builtin, Core.IntrinsicFunction}, args...) = f(args...)
@eval function overdub(ctx::Ctx, f, args...)
$(Expr(:meta, :generated_only))
$(Expr(:meta, :generated, overdub_generator))
end
end
using .MiniCassette
# Test #265 for Cassette
f() = 1
@test overdub(Ctx(), f) === 1
f() = 2
@test overdub(Ctx(), f) === 2
# Test that MiniCassette is at least somewhat capable by overdubbing gcd
@test overdub(Ctx(), gcd, 10, 20) === gcd(10, 20)
@generated bar(::Val{align}) where {align} = :(42)
foo(i) = i+bar(Val(1))
@test @inferred(overdub(Ctx(), foo, 1)) == 43
morethan4args(a, b, c, d, e) = (((a + b) + c) + d) + e
@test overdub(Ctx(), morethan4args, 1, 2, 3, 4, 5) == 15
end # module contextual
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C++
1
https://gitee.com/mirrors/julia-language.git
git@gitee.com:mirrors/julia-language.git
mirrors
julia-language
julia-language
master

搜索帮助