1
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2
2
3
+ module contextual
4
+
3
5
# N.B.: This file is also run from interpreter.jl, so needs to be standalone-executable
4
6
using Test
5
- include (" setup_Compiler.jl" )
6
7
7
8
# Cassette
8
9
# ========
9
10
11
+ # TODO Use CassetteBase.jl instead of this mini-cassette?
12
+
10
13
module MiniCassette
11
14
# A minimal demonstration of the cassette mechanism. Doesn't support all the
12
15
# fancy features, but sufficient to exercise this code path in the compiler.
13
16
17
+ using Core: SimpleVector
14
18
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
17
21
using Base. Meta: isexpr
18
22
19
23
export Ctx, overdub
20
24
21
25
struct Ctx; end
22
26
23
27
# 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 )
25
29
@nospecialize expr
26
30
transform (@nospecialize expr) = transform_expr (expr, map_slot_number, map_ssa_value, sparams)
27
31
if isexpr (expr, :call )
@@ -45,11 +49,11 @@ module MiniCassette
45
49
end
46
50
end
47
51
48
- function transform! (mi:: MethodInstance , ci:: CodeInfo , nargs:: Int , sparams:: Core. SimpleVector )
52
+ function transform! (mi:: MethodInstance , ci:: CodeInfo , nargs:: Int , sparams:: SimpleVector )
49
53
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 ]. .. ]
53
57
# Insert one SSAValue for every argument statement
54
58
prepend! (code, Any[Expr (:call , getfield, SlotNumber (4 ), i) for i = 1 : nargs])
55
59
prepend! (di. codelocs, fill (Int32 (0 ), 3 nargs))
@@ -76,31 +80,48 @@ module MiniCassette
76
80
77
81
function overdub_generator (world:: UInt , source, self, ctx, f, args)
78
82
@nospecialize
83
+ argnames = Core. svec (:overdub , :ctx , :f , :args )
84
+ spnames = Core. svec ()
85
+
79
86
if ! Base. issingletontype (f)
80
87
# (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... )))
83
89
end
84
90
85
91
tt = Tuple{f, args... }
86
92
match = Base. _which (tt; world)
87
93
mi = Base. specialize_method (match)
88
94
# 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" )))
90
97
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" )))
92
100
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" )))
94
103
src. edges = Any[mi]
95
104
transform! (mi, src, length (args), match. sparams)
96
105
# TODO : this is mandatory: code_info.min_world = max(code_info.min_world, min_world[])
97
106
# TODO : this is mandatory: code_info.max_world = min(code_info.max_world, max_world[])
98
107
# Match the generator, since that's what our transform! does
99
108
src. nargs = 4
100
109
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
101
115
return src
102
116
end
103
117
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
+
104
125
@inline overdub (:: Ctx , f:: Union{Core.Builtin, Core.IntrinsicFunction} , args... ) = f (args... )
105
126
106
127
@eval function overdub (ctx:: Ctx , f, args... )
@@ -124,3 +145,8 @@ f() = 2
124
145
foo (i) = i+ bar (Val (1 ))
125
146
126
147
@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