Skip to content

Commit 0c9c1e2

Browse files
authored
Canonicalize names of nested functions by keeping a more fine grained counter -- per (module, method name) pair (#53719)
As mentioned in #53716, we've been noticing that `precompile` statements lists from one version of our codebase often don't apply cleanly in a slightly different version. That's because a lot of nested and anonymous function names have a global numeric suffix which is incremented every time a new name is generated, and these numeric suffixes are not very stable across codebase changes. To solve this, this PR makes the numeric suffixes a bit more fine grained: every pair of (module, top-level/outermost function name) will have its own counter, which should make nested function names a bit more stable across different versions. This PR applies @JeffBezanson's idea of making the symbol name changes directly in `current-julia-module-counter`. Here is an example: ```Julia julia> function foo(x) function bar(y) return x + y end end foo (generic function with 1 method) julia> f = foo(42) (::var"#bar#foo##0"{Int64}) (generic function with 1 method) ```
1 parent 8547b02 commit 0c9c1e2

File tree

7 files changed

+193
-48
lines changed

7 files changed

+193
-48
lines changed

doc/src/manual/functions.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,12 @@ syntaxes:
292292

293293
```jldoctest
294294
julia> x -> x^2 + 2x - 1
295-
#1 (generic function with 1 method)
295+
#2 (generic function with 1 method)
296296
297297
julia> function (x)
298298
x^2 + 2x - 1
299299
end
300-
#3 (generic function with 1 method)
300+
#5 (generic function with 1 method)
301301
```
302302

303303
Each statement creates a function taking one argument `x` and returning the value of the polynomial `x^2 +

src/ast.c

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <stdlib.h>
88
#include <stdio.h>
99
#include <string.h>
10+
1011
#ifdef _OS_WINDOWS_
1112
#include <malloc.h>
1213
#endif
@@ -215,11 +216,46 @@ static value_t fl_nothrow_julia_global(fl_context_t *fl_ctx, value_t *args, uint
215216
decode_restriction_value(pku) : jl_atomic_load_relaxed(&b->value)) != NULL ? fl_ctx->T : fl_ctx->F;
216217
}
217218

218-
static value_t fl_current_module_counter(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) JL_NOTSAFEPOINT
219+
// Used to generate a unique suffix for a given symbol (e.g. variable or type name)
220+
// first argument contains a stack of method definitions seen so far by `closure-convert` in flisp.
221+
// if the top of the stack is non-NIL, we use it to augment the suffix so that it becomes
222+
// of the form $top_level_method_name##$counter, where `counter` is the smallest integer
223+
// such that the resulting name is not already defined in the current module's bindings.
224+
// If the top of the stack is NIL, we simply return the current module's counter.
225+
// This ensures that precompile statements are a bit more stable across different versions
226+
// of a codebase. see #53719
227+
static value_t fl_module_unique_name(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
219228
{
229+
argcount(fl_ctx, "julia-module-unique-name", nargs, 1);
220230
jl_ast_context_t *ctx = jl_ast_ctx(fl_ctx);
221-
assert(ctx->module);
222-
return fixnum(jl_module_next_counter(ctx->module));
231+
jl_module_t *m = ctx->module;
232+
assert(m != NULL);
233+
// Get the outermost function name from the `parsed_method_stack` top
234+
char *funcname = NULL;
235+
value_t parsed_method_stack = args[0];
236+
if (parsed_method_stack != fl_ctx->NIL) {
237+
value_t bottom_stack_symbol = fl_applyn(fl_ctx, 1, symbol_value(symbol(fl_ctx, "last")), parsed_method_stack);
238+
funcname = tosymbol(fl_ctx, bottom_stack_symbol, "julia-module-unique-name")->name;
239+
}
240+
size_t sz = funcname != NULL ? strlen(funcname) + 32 : 32; // 32 is enough for the suffix
241+
char *buf = (char*)alloca(sz);
242+
if (funcname != NULL && strchr(funcname, '#') == NULL) {
243+
for (int i = 0; ; i++) {
244+
snprintf(buf, sz, "%s##%d", funcname, i);
245+
jl_sym_t *sym = jl_symbol(buf);
246+
JL_LOCK(&m->lock);
247+
if (jl_get_module_binding(m, sym, 0) == NULL) { // make sure this name is not already taken
248+
jl_get_module_binding(m, sym, 1); // create the binding
249+
JL_UNLOCK(&m->lock);
250+
return symbol(fl_ctx, buf);
251+
}
252+
JL_UNLOCK(&m->lock);
253+
}
254+
}
255+
else {
256+
snprintf(buf, sz, "%d", jl_module_next_counter(m));
257+
}
258+
return symbol(fl_ctx, buf);
223259
}
224260

225261
static int jl_is_number(jl_value_t *v)
@@ -252,7 +288,7 @@ static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, jl_module_t *m
252288
static const builtinspec_t julia_flisp_ast_ext[] = {
253289
{ "defined-julia-global", fl_defined_julia_global }, // TODO: can we kill this safepoint
254290
{ "nothrow-julia-global", fl_nothrow_julia_global },
255-
{ "current-julia-module-counter", fl_current_module_counter },
291+
{ "current-julia-module-counter", fl_module_unique_name },
256292
{ "julia-scalar?", fl_julia_scalar },
257293
{ NULL, NULL }
258294
};

src/datatype.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,21 @@ extern "C" {
2020

2121
// allocating TypeNames -----------------------------------------------------------
2222

23-
static int is10digit(char c) JL_NOTSAFEPOINT
24-
{
25-
return (c >= '0' && c <= '9');
26-
}
27-
2823
static jl_sym_t *jl_demangle_typename(jl_sym_t *s) JL_NOTSAFEPOINT
2924
{
3025
char *n = jl_symbol_name(s);
3126
if (n[0] != '#')
3227
return s;
33-
char *end = strrchr(n, '#');
28+
char *end = strchr(&n[1], '#');
29+
// handle `#f...##...#...`
30+
if (end != NULL && end[1] == '#')
31+
end = strchr(&end[2], '#');
3432
int32_t len;
35-
if (end == n || end == n+1)
33+
if (end == NULL || end == n+1)
3634
len = strlen(n) - 1;
3735
else
3836
len = (end-n) - 1; // extract `f` from `#f#...`
39-
if (is10digit(n[1]))
37+
if (isdigit(n[1]) || is_canonicalized_anonfn_typename(n))
4038
return _jl_symbol(n, len+1);
4139
return _jl_symbol(&n[1], len);
4240
}

src/flisp/flisp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ value_t fl_cons(fl_context_t *fl_ctx, value_t a, value_t b) JL_NOTSAFEPOINT;
158158
value_t fl_list2(fl_context_t *fl_ctx, value_t a, value_t b) JL_NOTSAFEPOINT;
159159
value_t fl_listn(fl_context_t *fl_ctx, size_t n, ...) JL_NOTSAFEPOINT;
160160
value_t symbol(fl_context_t *fl_ctx, const char *str) JL_NOTSAFEPOINT;
161-
char *symbol_name(fl_context_t *fl_ctx, value_t v);
161+
char *symbol_name(fl_context_t *fl_ctx, value_t v) JL_NOTSAFEPOINT;
162162
int fl_is_keyword_name(const char *str, size_t len);
163163
value_t alloc_vector(fl_context_t *fl_ctx, size_t n, int init);
164164
size_t llength(value_t v);

0 commit comments

Comments
 (0)