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

Code before:
        (void)tosymbol(fl_ctx, args[0], "nothrow-julia-global");
        var = scmsym_to_julia(fl_ctx, args[0]);
    }
    else {
        argcount(fl_ctx, "nothrow-julia-global", nargs, 2);
        value_t argmod = args[0];
        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 {
            (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] != '#' && !isdigit(funcname[strlen(funcname)-1])) {
        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);

Review comment (suggestion):
This could go into `jl_module_t`, which already has a lock (and an atomic field called `counter`; not sure if that's related?). I think that will reduce a lookup here and let us avoid having yet another couple of globals.

Code after:
    jl_module_t *mod = ctx->module;
    jl_sym_t *var = NULL;
    if (nargs == 1) {
        (void)tosymbol(fl_ctx, args[0], "nothrow-julia-global");
        var = scmsym_to_julia(fl_ctx, args[0]);
    }
    else {
        argcount(fl_ctx, "nothrow-julia-global", nargs, 2);
        value_t argmod = args[0];
        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;