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
5- include (" setup_Compiler.jl" )
67
78# Cassette
89# ========
910
11+ # TODO Use CassetteBase.jl instead of this mini-cassette?
12+
1013module MiniCassette
1114 # A minimal demonstration of the cassette mechanism. Doesn't support all the
1215 # fancy features, but sufficient to exercise this code path in the compiler.
1316
17+ using Core: SimpleVector
1418 using Core. IR
15- using .. Compiler
16- using .. Compiler : retrieve_code_info, quoted, anymap
19+ using Base : Compiler as CC
20+ using . CC : retrieve_code_info, quoted, anymap
1721 using Base. Meta: isexpr
1822
1923 export Ctx, overdub
2024
2125 struct Ctx; end
2226
2327 # A no-op cassette-like transform
24- 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 )
2529 @nospecialize expr
2630 transform (@nospecialize expr) = transform_expr (expr, map_slot_number, map_ssa_value, sparams)
2731 if isexpr (expr, :call )
@@ -45,11 +49,11 @@ module MiniCassette
4549 end
4650 end
4751
48- function transform! (mi:: MethodInstance , ci:: CodeInfo , nargs:: Int , sparams:: Core. SimpleVector )
52+ function transform! (mi:: MethodInstance , ci:: CodeInfo , nargs:: Int , sparams:: SimpleVector )
4953 code = ci. code
50- di = Compiler . DebugInfoStream (mi, ci. debuginfo, length (code))
51- ci. slotnames = Symbol[Symbol (" #self#" ), :ctx , :f , :args , ci. slotnames[nargs+ 1 : end ]. .. ]
52- 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 ]. .. ]
5357 # Insert one SSAValue for every argument statement
5458 prepend! (code, Any[Expr (:call , getfield, SlotNumber (4 ), i) for i = 1 : nargs])
5559 prepend! (di. codelocs, fill (Int32 (0 ), 3 nargs))
@@ -76,31 +80,48 @@ module MiniCassette
7680
7781 function overdub_generator (world:: UInt , source, self, ctx, f, args)
7882 @nospecialize
83+ argnames = Core. svec (:overdub , :ctx , :f , :args )
84+ spnames = Core. svec ()
85+
7986 if ! Base. issingletontype (f)
8087 # (c, f, args..) -> f(args...)
81- ex = :(return f (args... ))
82- 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... )))
8389 end
8490
8591 tt = Tuple{f, args... }
8692 match = Base. _which (tt; world)
8793 mi = Base. specialize_method (match)
8894 # Unsupported in this mini-cassette
89- @assert ! mi. def. isva
95+ ! mi. def. isva ||
96+ return generate_lambda_ex (world, source, argnames, spnames, :(error (" Unsupported vararg method" )))
9097 src = retrieve_code_info (mi, world)
91- @assert isa (src, CodeInfo)
98+ isa (src, CodeInfo) ||
99+ return generate_lambda_ex (world, source, argnames, spnames, :(error (" Unexpected code transformation" )))
92100 src = copy (src)
93- @assert src. edges === Core. svec ()
101+ src. edges === Core. svec () ||
102+ return generate_lambda_ex (world, source, argnames, spnames, :(error (" Unexpected code transformation" )))
94103 src. edges = Any[mi]
95104 transform! (mi, src, length (args), match. sparams)
96105 # TODO : this is mandatory: code_info.min_world = max(code_info.min_world, min_world[])
97106 # TODO : this is mandatory: code_info.max_world = min(code_info.max_world, max_world[])
98107 # Match the generator, since that's what our transform! does
99108 src. nargs = 4
100109 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
101115 return src
102116 end
103117
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+
104125 @inline overdub (:: Ctx , f:: Union{Core.Builtin, Core.IntrinsicFunction} , args... ) = f (args... )
105126
106127 @eval function overdub (ctx:: Ctx , f, args... )
@@ -124,3 +145,8 @@ f() = 2
124145foo (i) = i+ bar (Val (1 ))
125146
126147@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