|
7 | 7 | #include <stdlib.h> |
8 | 8 | #include <stdio.h> |
9 | 9 | #include <string.h> |
| 10 | + |
| 11 | +#include "support/strhash.h" |
| 12 | + |
10 | 13 | #ifdef _OS_WINDOWS_ |
11 | 14 | #include <malloc.h> |
12 | 15 | #endif |
@@ -215,11 +218,85 @@ static value_t fl_nothrow_julia_global(fl_context_t *fl_ctx, value_t *args, uint |
215 | 218 | decode_restriction_value(pku) : jl_atomic_load_relaxed(&b->value)) != NULL ? fl_ctx->T : fl_ctx->F; |
216 | 219 | } |
217 | 220 |
|
| 221 | +static htable_t *rebuild_counter_table(jl_module_t *m) JL_NOTSAFEPOINT |
| 222 | +{ |
| 223 | + htable_t *counter_table = m->counter_table = htable_new((htable_t *)malloc_s(sizeof(htable_t)), 0); |
| 224 | + jl_svec_t *t = jl_atomic_load_relaxed(&m->bindings); |
| 225 | + for (size_t i = 0; i < jl_svec_len(t); i++) { |
| 226 | + jl_binding_t *b = (jl_binding_t*)jl_svecref(t, i); |
| 227 | + if ((void*)b == jl_nothing) { |
| 228 | + continue; |
| 229 | + } |
| 230 | + char *globalref_name = jl_symbol_name(b->globalref->name); |
| 231 | + if (is_canonicalized_anonfn_typename(globalref_name)) { |
| 232 | + int should_free = 1; |
| 233 | + // copy globalref_name into the buffer until we hit a `#` character |
| 234 | + char *delim = strchr(&globalref_name[1], '#'); |
| 235 | + assert(delim != NULL); |
| 236 | + size_t len = delim - globalref_name - 1; |
| 237 | + assert(len > 0); |
| 238 | + char *enclosing_function_name = (char*)calloc_s(len + 1); |
| 239 | + memcpy(enclosing_function_name, &globalref_name[1], len); |
| 240 | + // check if the enclosing function name is already in the counter table |
| 241 | + if (strhash_get(counter_table, enclosing_function_name) == HT_NOTFOUND) { |
| 242 | + strhash_put(counter_table, enclosing_function_name, (void*)((uintptr_t)HT_NOTFOUND + 1)); |
| 243 | + should_free = 0; |
| 244 | + } |
| 245 | + char *pint = strrchr(globalref_name, '#'); |
| 246 | + assert(pint != NULL); |
| 247 | + int counter = atoi(pint + 1); |
| 248 | + int max_seen_so_far = ((uint32_t)(uintptr_t)strhash_get(counter_table, enclosing_function_name) - (uintptr_t)HT_NOTFOUND - 1); |
| 249 | + if (counter >= max_seen_so_far) { |
| 250 | + strhash_put(counter_table, enclosing_function_name, (void*)((uintptr_t)counter + 1 + (uintptr_t)HT_NOTFOUND + 1)); |
| 251 | + } |
| 252 | + if (should_free) { |
| 253 | + free(enclosing_function_name); |
| 254 | + } |
| 255 | + } |
| 256 | + } |
| 257 | + return counter_table; |
| 258 | +} |
| 259 | + |
| 260 | +// used to generate a unique suffix for a given symbol (e.g. variable or type name) |
| 261 | +// first argument contains a stack of method definitions seen so far by `closure-convert` in flisp. |
| 262 | +// if the top of the stack is non-NIL, we use it to augment the suffix so that it becomes |
| 263 | +// of the form $top_level_method_name##$counter, where counter is stored in a per-module |
| 264 | +// side table indexed by top-level method name. |
| 265 | +// this ensures that precompile statements are a bit more stable across different versions |
| 266 | +// of a codebase. see #53719 |
218 | 267 | static value_t fl_current_module_counter(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) JL_NOTSAFEPOINT |
219 | 268 | { |
| 269 | + argcount(fl_ctx, "current-julia-module-counter", nargs, 1); |
220 | 270 | jl_ast_context_t *ctx = jl_ast_ctx(fl_ctx); |
221 | | - assert(ctx->module); |
222 | | - return fixnum(jl_module_next_counter(ctx->module)); |
| 271 | + jl_module_t *m = ctx->module; |
| 272 | + assert(m != NULL); |
| 273 | + // Get the outermost function name from the `parsed_method_stack` top |
| 274 | + char *funcname = NULL; |
| 275 | + value_t parsed_method_stack = args[0]; |
| 276 | + if (parsed_method_stack != fl_ctx->NIL) { |
| 277 | + value_t bottom_stack_symbol = fl_applyn(fl_ctx, 1, symbol_value(symbol(fl_ctx, "last")), parsed_method_stack); |
| 278 | + funcname = symbol_name(fl_ctx, bottom_stack_symbol); |
| 279 | + } |
| 280 | + char buf[(funcname != NULL ? strlen(funcname) : 0) + 20]; |
| 281 | + if (funcname != NULL && strchr(funcname, '#') == NULL) { |
| 282 | + jl_mutex_lock_nogc(&m->lock); |
| 283 | + htable_t *counter_table = m->counter_table; |
| 284 | + if (counter_table == NULL) { |
| 285 | + counter_table = rebuild_counter_table(m); |
| 286 | + } |
| 287 | + // try to find the function name in the module's counter table, if it's not found, add it |
| 288 | + if (strhash_get(counter_table, funcname) == HT_NOTFOUND) { |
| 289 | + strhash_put(counter_table, funcname, (void*)((uintptr_t)HT_NOTFOUND + 1)); |
| 290 | + } |
| 291 | + uint32_t nxt = ((uint32_t)(uintptr_t)strhash_get(counter_table, funcname) - (uintptr_t)HT_NOTFOUND - 1); |
| 292 | + snprintf(buf, sizeof(buf), "%s##%d", funcname, nxt); |
| 293 | + strhash_put(counter_table, funcname, (void*)(nxt + 1 + (uintptr_t)HT_NOTFOUND + 1)); |
| 294 | + jl_mutex_unlock_nogc(&m->lock); |
| 295 | + } |
| 296 | + else { |
| 297 | + snprintf(buf, sizeof(buf), "%d", jl_module_next_counter(ctx->module)); |
| 298 | + } |
| 299 | + return symbol(fl_ctx, buf); |
223 | 300 | } |
224 | 301 |
|
225 | 302 | static int jl_is_number(jl_value_t *v) |
|
0 commit comments