Skip to content

Commit f486c9a

Browse files
committed
use src.nargs for validate_code!
This is a follow-up to #54341. Otherwise, `validate_code!` may raise wrong errors for unmatched `nargs` information between generated code and original method.
1 parent 6ddf4c3 commit f486c9a

File tree

2 files changed

+41
-15
lines changed

2 files changed

+41
-15
lines changed

Compiler/src/validation.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ function validate_code!(errors::Vector{InvalidCodeError}, mi::Core.MethodInstanc
225225
mnargs = 0
226226
else
227227
m = mi.def::Method
228-
mnargs = m.nargs
228+
mnargs = Int(m.nargs)
229229
n_sig_params = length((unwrap_unionall(m.sig)::DataType).parameters)
230230
if m.is_for_opaque_closure
231231
m.sig === Tuple || push!(errors, InvalidCodeError(INVALID_SIGNATURE_OPAQUE_CLOSURE, (m.sig, m.isva)))
@@ -234,6 +234,7 @@ function validate_code!(errors::Vector{InvalidCodeError}, mi::Core.MethodInstanc
234234
end
235235
end
236236
if isa(c, CodeInfo)
237+
mnargs = Int(c.nargs)
237238
mnargs > length(c.slotnames) && push!(errors, InvalidCodeError(SLOTNAMES_NARGS_MISMATCH))
238239
validate_code!(errors, c, is_top_level)
239240
end

Compiler/test/contextual.jl

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,31 @@
11
# This file is a part of Julia. License is MIT: https://julialang.org/license
22

3+
module contextual
4+
35
# N.B.: This file is also run from interpreter.jl, so needs to be standalone-executable
46
using Test
57

6-
include("setup_Compiler.jl")
7-
88
# Cassette
99
# ========
1010

11+
# TODO Use CassetteBase.jl instead of this mini-cassette?
12+
1113
module MiniCassette
1214
# A minimal demonstration of the cassette mechanism. Doesn't support all the
1315
# fancy features, but sufficient to exercise this code path in the compiler.
1416

17+
using Core: SimpleVector
1518
using Core.IR
16-
using ..Compiler
17-
using ..Compiler: retrieve_code_info, quoted, anymap
19+
using Base: Compiler as CC
20+
using .CC: retrieve_code_info, quoted, anymap
1821
using Base.Meta: isexpr
1922

2023
export Ctx, overdub
2124

2225
struct Ctx; end
2326

2427
# A no-op cassette-like transform
25-
function transform_expr(expr, map_slot_number, map_ssa_value, sparams::Core.SimpleVector)
28+
function transform_expr(expr, map_slot_number, map_ssa_value, sparams::SimpleVector)
2629
@nospecialize expr
2730
transform(@nospecialize expr) = transform_expr(expr, map_slot_number, map_ssa_value, sparams)
2831
if isexpr(expr, :call)
@@ -46,11 +49,11 @@ module MiniCassette
4649
end
4750
end
4851

49-
function transform!(mi::MethodInstance, ci::CodeInfo, nargs::Int, sparams::Core.SimpleVector)
52+
function transform!(mi::MethodInstance, ci::CodeInfo, nargs::Int, sparams::SimpleVector)
5053
code = ci.code
51-
di = Compiler.DebugInfoStream(mi, ci.debuginfo, length(code))
52-
ci.slotnames = Symbol[Symbol("#self#"), :ctx, :f, :args, ci.slotnames[nargs+1:end]...]
53-
ci.slotflags = UInt8[(0x00 for i = 1:4)..., ci.slotflags[nargs+1:end]...]
54+
di = CC.DebugInfoStream(mi, ci.debuginfo, length(code))
55+
ci.slotnames = Symbol[Symbol("#self#"), :ctx, :f, :args, ci.slotnames[nargs+2:end]...]
56+
ci.slotflags = UInt8[(0x00 for i = 1:4)..., ci.slotflags[nargs+2:end]...]
5457
# Insert one SSAValue for every argument statement
5558
prepend!(code, Any[Expr(:call, getfield, SlotNumber(4), i) for i = 1:nargs])
5659
prepend!(di.codelocs, fill(Int32(0), 3nargs))
@@ -77,31 +80,48 @@ module MiniCassette
7780

7881
function overdub_generator(world::UInt, source, self, ctx, f, args)
7982
@nospecialize
83+
argnames = Core.svec(:overdub, :ctx, :f, :args)
84+
spnames = Core.svec()
85+
8086
if !Base.issingletontype(f)
8187
# (c, f, args..) -> f(args...)
82-
ex = :(return f(args...))
83-
return Core.GeneratedFunctionStub(identity, Core.svec(:overdub, :ctx, :f, :args), Core.svec())(world, source, ex)
88+
return generate_lambda_ex(world, source, argnames, spnames, :(return f(args...)))
8489
end
8590

8691
tt = Tuple{f, args...}
8792
match = Base._which(tt; world)
8893
mi = Base.specialize_method(match)
8994
# Unsupported in this mini-cassette
90-
@assert !mi.def.isva
95+
!mi.def.isva ||
96+
return generate_lambda_ex(world, source, argnames, spnames, :(error("Unsupported varargs")))
9197
src = retrieve_code_info(mi, world)
92-
@assert isa(src, CodeInfo)
98+
isa(src, CodeInfo) ||
99+
return generate_lambda_ex(world, source, argnames, spnames, :(error("Unexpected code transformation")))
93100
src = copy(src)
94-
@assert src.edges === Core.svec()
101+
src.edges === Core.svec() ||
102+
return generate_lambda_ex(world, source, argnames, spnames, :(error("Unexpected code transformation")))
95103
src.edges = Any[mi]
96104
transform!(mi, src, length(args), match.sparams)
97105
# TODO: this is mandatory: code_info.min_world = max(code_info.min_world, min_world[])
98106
# TODO: this is mandatory: code_info.max_world = min(code_info.max_world, max_world[])
99107
# Match the generator, since that's what our transform! does
100108
src.nargs = 4
101109
src.isva = true
110+
errors = CC.validate_code(mi, src)
111+
if !isempty(errors)
112+
foreach(Core.println, errors)
113+
return generate_lambda_ex(world, source, argnames, spnames, :(error("Found errors in generated code")))
114+
end
102115
return src
103116
end
104117

118+
function generate_lambda_ex(world::UInt, source::Method,
119+
argnames::SimpleVector, spnames::SimpleVector,
120+
body::Expr)
121+
stub = Core.GeneratedFunctionStub(identity, argnames, spnames)
122+
return stub(world, source, body)
123+
end
124+
105125
@inline overdub(::Ctx, f::Union{Core.Builtin, Core.IntrinsicFunction}, args...) = f(args...)
106126

107127
@eval function overdub(ctx::Ctx, f, args...)
@@ -125,3 +145,8 @@ f() = 2
125145
foo(i) = i+bar(Val(1))
126146

127147
@test @inferred(overdub(Ctx(), foo, 1)) == 43
148+
149+
morethan4args(a, b, c, d, e) = a + b + c + d + e
150+
@test overdub(Ctx(), morethan4args, 1, 2, 3, 4, 5) == 15
151+
152+
end # module contextual

0 commit comments

Comments
 (0)