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
46using Test
57
6- include (" setup_Compiler.jl" )
7-
88# Cassette
99# ========
1010
11+ # TODO Use CassetteBase.jl instead of this mini-cassette?
12+
1113module 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 ), 3 nargs))
@@ -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
125145foo (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