Repository: JuliaLang/julia
File: src/ast.c (C)

Code before:
        } else {
            (void)tosymbol(fl_ctx, argmod, "nothrow-julia-global");
            if (scmsym_to_julia(fl_ctx, argmod) != jl_thismodule_sym) {
                lerrorf(fl_ctx, fl_ctx->ArgError, "nothrow-julia-global: Unknown globalref module kind");
            }
        }
        (void)tosymbol(fl_ctx, args[1], "nothrow-julia-global");
        var = scmsym_to_julia(fl_ctx, args[1]);
    }
    jl_binding_t *b = jl_get_module_binding(mod, var, 0);
    b = b ? jl_atomic_load_relaxed(&b->owner) : NULL;
    return b != NULL && jl_atomic_load_relaxed(&b->value) != NULL ? fl_ctx->T : fl_ctx->F;
}

arraylist_t parsed_method_stack; // for keeping track of which methods are being parsed
uv_mutex_t counter_table_lock;
htable_t counter_table; // map from module_name -> inner htable; inner htable maps from char * -> uint32_t

static value_t fl_current_module_counter(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) JL_NOTSAFEPOINT
{
    jl_ast_context_t *ctx = jl_ast_ctx(fl_ctx);
    assert(ctx->module);
    // Create a string of the form <$outermost_func_name>$counter
    // where counter is the next counter for the module obtained by calling `jl_module_next_counter`
    // Get the module name
    char *modname = jl_symbol_name(ctx->module->name);
    // Get the outermost function name from the `parsed_method_stack` top
    char *funcname = NULL;
    value_t funcname_v = parsed_method_stack.len > 0 ? (value_t)parsed_method_stack.items[0] : fl_ctx->NIL;
    if (funcname_v != fl_ctx->NIL) {
        funcname = symbol_name(fl_ctx, funcname_v);
    }
    // Create the string
    char buf[(funcname != NULL ? strlen(funcname) : 0) + 20];
    if (funcname != NULL && funcname[0] != '#') {
        uint32_t nxt;
        uv_mutex_lock(&counter_table_lock);
        // try to find the module name in the counter table, if it's not create a symbol table for it
        if (ptrhash_get(&counter_table, modname) == HT_NOTFOUND) {
            // if not found, add it to the counter table
            htable_t *new_table = (htable_t*)malloc_s(sizeof(htable_t));
            htable_new(new_table, 0);
            ptrhash_put(&counter_table, modname, new_table);
        }
        htable_t *mod_table = (htable_t*)ptrhash_get(&counter_table, modname);
        // try to find the function name in the module's counter table, if it's not found, add it
        if (ptrhash_get(mod_table, funcname) == HT_NOTFOUND) {
            // Don't forget to shift the counter by 2 and or it with 3
            // to avoid the counter being 0 or 1, which are reserved
            ptrhash_put(mod_table, funcname, (void*)(uintptr_t)3);
        }

Review comment (suggestion):
This should probably be done by Module and not by Module name, as Kiran recommended above. It's not uncommon to do something like this:
```julia
julia> mod = Module(); Core.eval(mod, quote
           function plus(x)
               return (y)->(x + y)
           end
       end)
 ```
 
in which case I believe the name is usually `anonymous` (but can also be user-supplied and in general is not unique)

Code after:
        if (iscvalue(argmod) && cv_class((cvalue_t*)ptr(argmod)) == jl_ast_ctx(fl_ctx)->jvtype) {
            mod = *(jl_module_t**)cv_data((cvalue_t*)ptr(argmod));
            JL_GC_PROMISE_ROOTED(mod);
        } else {
            if (!iscons(argmod) || !issymbol(car_(argmod)) || scmsym_to_julia(fl_ctx, car_(argmod)) != jl_thismodule_sym) {
                lerrorf(fl_ctx, fl_ctx->ArgError, "nothrow-julia-global: Unknown globalref module kind");
            }
        }
        (void)tosymbol(fl_ctx, args[1], "nothrow-julia-global");
        var = scmsym_to_julia(fl_ctx, args[1]);
    }
    jl_binding_t *b = jl_get_module_binding(mod, var, 0);
    jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age);
    jl_ptr_kind_union_t pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age);
    if (!bpart)
        return fl_ctx->F;
    if (jl_bkind_is_some_guard(decode_restriction_kind(pku)))
        return fl_ctx->F;
    return  (jl_bkind_is_some_constant(decode_restriction_kind(pku)) ?
        decode_restriction_value(pku) : jl_atomic_load_relaxed(&b->value)) != NULL ? fl_ctx->T : fl_ctx->F;
}

// Used to generate a unique suffix for a given symbol (e.g. variable or type name)
// first argument contains a stack of method definitions seen so far by `closure-convert` in flisp.
// if the top of the stack is non-NIL, we use it to augment the suffix so that it becomes
// of the form $top_level_method_name##$counter, where `counter` is the smallest integer
// such that the resulting name is not already defined in the current module's bindings.
// If the top of the stack is NIL, we simply return the current module's counter.
// This ensures that precompile statements are a bit more stable across different versions
// of a codebase. see #53719
static value_t fl_module_unique_name(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
{
    argcount(fl_ctx, "julia-module-unique-name", nargs, 1);
    jl_ast_context_t *ctx = jl_ast_ctx(fl_ctx);
    jl_module_t *m = ctx->module;
    assert(m != NULL);
    // Get the outermost function name from the `parsed_method_stack` top
    char *funcname = NULL;
    value_t parsed_method_stack = args[0];
    if (parsed_method_stack != fl_ctx->NIL) {
        value_t bottom_stack_symbol = fl_applyn(fl_ctx, 1, symbol_value(symbol(fl_ctx, "last")), parsed_method_stack);
        funcname = tosymbol(fl_ctx, bottom_stack_symbol, "julia-module-unique-name")->name;
    }
    size_t sz = funcname != NULL ? strlen(funcname) + 32 : 32; // 32 is enough for the suffix
    char *buf = (char*)alloca(sz);
    if (funcname != NULL && strchr(funcname, '#') == NULL) {
        for (int i = 0; ; i++) {
            snprintf(buf, sz, "%s##%d", funcname, i);
            jl_sym_t *sym = jl_symbol(buf);
            JL_LOCK(&m->lock);
            if (jl_get_module_binding(m, sym, 0) == NULL) { // make sure this name is not already taken