Skip to content

Commit 384a474

Browse files
committed
replace ANY with @nospecialize annotation. part of #11339
1 parent 4b345c1 commit 384a474

File tree

15 files changed

+108
-41
lines changed

15 files changed

+108
-41
lines changed

base/boot.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,10 @@ macro _noinline_meta()
196196
Expr(:meta, :noinline)
197197
end
198198

199+
macro nospecialize(x)
200+
Expr(:meta, :nospecialize, x)
201+
end
202+
199203
struct BoundsError <: Exception
200204
a::Any
201205
i::Any

base/essentials.jl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,29 @@ end
1717
macro _noinline_meta()
1818
Expr(:meta, :noinline)
1919
end
20+
"""
21+
@nospecialize
22+
23+
Applied to a function argument name, hints to the compiler that the method
24+
should not be specialized for different types of the specified argument.
25+
This is only a hint for avoiding excess code generation.
26+
Can be applied to an argument within a formal argument list, or in the
27+
function body:
28+
29+
```julia
30+
function example_function(@nospecialize x)
31+
...
32+
end
33+
34+
function example_function(x, y, z)
35+
@nospecialize x y
36+
...
37+
end
38+
```
39+
"""
40+
macro nospecialize(var, vars...)
41+
Expr(:meta, :nospecialize, var, vars...)
42+
end
2043
macro _pure_meta()
2144
Expr(:meta, :pure)
2245
end

base/exports.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,6 +1285,7 @@ export
12851285
@simd,
12861286
@inline,
12871287
@noinline,
1288+
@nospecialize,
12881289
@polly,
12891290

12901291
@assert,

src/ast.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ jl_sym_t *inert_sym; jl_sym_t *vararg_sym;
5656
jl_sym_t *unused_sym; jl_sym_t *static_parameter_sym;
5757
jl_sym_t *polly_sym; jl_sym_t *inline_sym;
5858
jl_sym_t *propagate_inbounds_sym;
59-
jl_sym_t *isdefined_sym;
59+
jl_sym_t *isdefined_sym; jl_sym_t *nospecialize_sym;
6060

6161
static uint8_t flisp_system_image[] = {
6262
#include <julia_flisp.boot.inc>
@@ -433,6 +433,7 @@ void jl_init_frontend(void)
433433
inline_sym = jl_symbol("inline");
434434
propagate_inbounds_sym = jl_symbol("propagate_inbounds");
435435
isdefined_sym = jl_symbol("isdefined");
436+
nospecialize_sym = jl_symbol("nospecialize");
436437
}
437438

438439
JL_DLLEXPORT void jl_lisp_prompt(void)

src/ast.scm

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@
152152
(if (not (symbol? (cadr v)))
153153
(bad-formal-argument (cadr v)))
154154
(decl-var v))
155+
((meta) ;; allow certain per-argument annotations
156+
(if (and (length= v 3) (eq? (cadr v) 'nospecialize))
157+
(arg-name (caddr v))
158+
(bad-formal-argument v)))
155159
(else (bad-formal-argument v))))))
156160

157161
(define (arg-type v)
@@ -167,6 +171,10 @@
167171
(if (not (symbol? (cadr v)))
168172
(bad-formal-argument (cadr v)))
169173
(decl-type v))
174+
((meta) ;; allow certain per-argument annotations
175+
(if (and (length= v 3) (eq? (cadr v) 'nospecialize))
176+
(arg-type (caddr v))
177+
(bad-formal-argument v)))
170178
(else (bad-formal-argument v))))))
171179

172180
;; convert a lambda list into a list of just symbols
@@ -310,6 +318,9 @@
310318
(define (kwarg? e)
311319
(and (pair? e) (eq? (car e) 'kw)))
312320

321+
(define (nospecialize-meta? e)
322+
(and (length> e 2) (eq? (car e) 'meta) (eq? (cadr e) 'nospecialize)))
323+
313324
;; flatten nested expressions with the given head
314325
;; (op (op a b) c) => (op a b c)
315326
(define (flatten-ex head e)

src/gf.c

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -611,8 +611,7 @@ static void jl_cacheable_sig(
611611

612612
int notcalled_func = (i > 0 && i <= 8 && !(definition->called & (1 << (i - 1))) &&
613613
jl_subtype(elt, (jl_value_t*)jl_function_type));
614-
if (decl_i == jl_ANY_flag) {
615-
// don't specialize on slots marked ANY
614+
if (i > 0 && i <= 8 && definition->nospec & (1 << (i - 1))) {
616615
if (!*newparams) *newparams = jl_svec_copy(type->parameters);
617616
jl_svecset(*newparams, i, (jl_value_t*)jl_any_type);
618617
*need_guard_entries = 1;
@@ -714,9 +713,8 @@ JL_DLLEXPORT int jl_is_cacheable_sig(
714713
continue;
715714
if (jl_is_kind(elt)) // kind slots always need guard entries (checking for subtypes of Type)
716715
continue;
717-
if (decl_i == jl_ANY_flag) {
718-
// don't specialize on slots marked ANY
719-
if (elt != (jl_value_t*)jl_any_type && elt != jl_ANY_flag)
716+
if (i > 0 && i <= 8 && definition->nospec & (1 << (i - 1))) {
717+
if (elt != (jl_value_t*)jl_any_type)
720718
return 0;
721719
continue;
722720
}
@@ -2258,16 +2256,6 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio
22582256
break;
22592257
}
22602258
}
2261-
// don't analyze slots declared with ANY
2262-
// TODO
2263-
/*
2264-
l = jl_nparams(ml->sig);
2265-
size_t m = jl_nparams(ti);
2266-
for(i=0; i < l && i < m; i++) {
2267-
if (jl_tparam(ml->sig, i) == jl_ANY_flag)
2268-
jl_tupleset(ti, i, jl_any_type);
2269-
}
2270-
*/
22712259
}
22722260
if (!skip) {
22732261
/*

src/jltypes.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ static int typeenv_has(jl_typeenv_t *env, jl_tvar_t *v)
146146
static int has_free_typevars(jl_value_t *v, jl_typeenv_t *env)
147147
{
148148
if (jl_typeis(v, jl_tvar_type)) {
149-
if (v == jl_ANY_flag) return 0;
150149
return !typeenv_has(env, (jl_tvar_t*)v);
151150
}
152151
if (jl_is_uniontype(v))
@@ -181,7 +180,6 @@ JL_DLLEXPORT int jl_has_free_typevars(jl_value_t *v)
181180
static void find_free_typevars(jl_value_t *v, jl_typeenv_t *env, jl_array_t *out)
182181
{
183182
if (jl_typeis(v, jl_tvar_type)) {
184-
if (v == jl_ANY_flag) return;
185183
if (!typeenv_has(env, (jl_tvar_t*)v))
186184
jl_array_ptr_1d_push(out, v);
187185
}
@@ -238,7 +236,7 @@ static int jl_has_bound_typevars(jl_value_t *v, jl_typeenv_t *env)
238236
return ans;
239237
}
240238
if (jl_is_datatype(v)) {
241-
if (!((jl_datatype_t*)v)->hasfreetypevars && !(env && env->var == (jl_tvar_t*)jl_ANY_flag))
239+
if (!((jl_datatype_t*)v)->hasfreetypevars)
242240
return 0;
243241
size_t i;
244242
for (i=0; i < jl_nparams(v); i++) {
@@ -669,8 +667,6 @@ static int is_cacheable(jl_datatype_t *type)
669667
assert(jl_is_datatype(type));
670668
jl_svec_t *t = type->parameters;
671669
if (jl_svec_len(t) == 0) return 0;
672-
if (jl_has_typevar((jl_value_t*)type, (jl_tvar_t*)jl_ANY_flag))
673-
return 0;
674670
// cache abstract types with no free type vars
675671
if (jl_is_abstracttype(type))
676672
return !jl_has_free_typevars((jl_value_t*)type);
@@ -1939,7 +1935,7 @@ void jl_init_types(void)
19391935
jl_method_type =
19401936
jl_new_datatype(jl_symbol("Method"), core,
19411937
jl_any_type, jl_emptysvec,
1942-
jl_perm_symsvec(19,
1938+
jl_perm_symsvec(20,
19431939
"name",
19441940
"module",
19451941
"file",
@@ -1956,10 +1952,11 @@ void jl_init_types(void)
19561952
"invokes",
19571953
"nargs",
19581954
"called",
1955+
"nospec",
19591956
"isva",
19601957
"isstaged",
19611958
"pure"),
1962-
jl_svec(19,
1959+
jl_svec(20,
19631960
jl_sym_type,
19641961
jl_module_type,
19651962
jl_sym_type,
@@ -1976,6 +1973,7 @@ void jl_init_types(void)
19761973
jl_any_type,
19771974
jl_int32_type,
19781975
jl_int32_type,
1976+
jl_int32_type,
19791977
jl_bool_type,
19801978
jl_bool_type,
19811979
jl_bool_type),

src/julia-syntax.scm

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,17 @@
10261026
(string "function Base.broadcast(::typeof(" (deparse op_) "), ...)")))
10271027
op_))
10281028
(name (if op '(|.| Base (inert broadcast)) name))
1029+
(annotations (map (lambda (a)
1030+
`(meta nospecialize ,(arg-name a)))
1031+
(filter nospecialize-meta? argl)))
1032+
(body (if (null? annotations)
1033+
(caddr e)
1034+
(insert-after-meta (caddr e) annotations)))
1035+
(argl (map (lambda (a)
1036+
(if (nospecialize-meta? a)
1037+
(caddr a)
1038+
a))
1039+
argl))
10291040
(argl (if op (cons `(|::| (call (core Typeof) ,op)) argl) argl))
10301041
(sparams (map analyze-typevar (cond (has-sp (cddr head))
10311042
(where where)
@@ -1046,7 +1057,7 @@
10461057
(name (if (or (decl? name) (and (pair? name) (eq? (car name) 'curly)))
10471058
#f name)))
10481059
(expand-forms
1049-
(method-def-expr name sparams argl (caddr e) isstaged rett))))
1060+
(method-def-expr name sparams argl body isstaged rett))))
10501061
(else
10511062
(error (string "invalid assignment location \"" (deparse name) "\""))))))
10521063

@@ -1170,7 +1181,7 @@
11701181
(|::| __module__ (core Module))
11711182
,@(map (lambda (v)
11721183
(if (symbol? v)
1173-
`(|::| ,v (core ANY))
1184+
`(|::| ,v (core ANY)) ;; TODO: ANY deprecation
11741185
v))
11751186
anames))
11761187
,@(cddr e)))))
@@ -3780,6 +3791,9 @@ f(x) = yt(x)
37803791
((and (pair? e) (eq? (car e) 'outerref))
37813792
(let ((idx (get sp-table (cadr e) #f)))
37823793
(if idx `(static_parameter ,idx) (cadr e))))
3794+
((and (length> e 2) (eq? (car e) 'meta) (eq? (cadr e) 'nospecialize))
3795+
;; convert nospecialize vars to slot numbers
3796+
`(meta nospecialize ,@(map renumber-slots (cddr e))))
37833797
((or (atom? e) (quoted? e)) e)
37843798
((ssavalue? e)
37853799
(let ((idx (or (get ssavalue-table (cadr e) #f)

src/julia.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ typedef struct _jl_method_t {
255255

256256
int32_t nargs;
257257
int32_t called; // bit flags: whether each of the first 8 arguments is called
258+
int32_t nospec; // bit flags: which arguments should not be specialized
258259
uint8_t isva;
259260
uint8_t isstaged;
260261
uint8_t pure;

src/julia_internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1001,7 +1001,7 @@ extern jl_sym_t *meta_sym; extern jl_sym_t *list_sym;
10011001
extern jl_sym_t *inert_sym; extern jl_sym_t *static_parameter_sym;
10021002
extern jl_sym_t *polly_sym; extern jl_sym_t *inline_sym;
10031003
extern jl_sym_t *propagate_inbounds_sym;
1004-
extern jl_sym_t *isdefined_sym;
1004+
extern jl_sym_t *isdefined_sym; extern jl_sym_t *nospecialize_sym;
10051005

10061006
void jl_register_fptrs(uint64_t sysimage_base, const char *base, const int32_t *offsets,
10071007
jl_method_instance_t **linfos, size_t n);

0 commit comments

Comments
 (0)