Skip to content

Commit ce8dba4

Browse files
committed
Re-work jl_adopt_thread runtime auto-initialization
This should be a dramatically simpler implementation, by just setting up the `jl_pgcstack_func_slot` to have a usable function pointer by default and then performing library introspection based on `__builtin_return_address` in the runtime. This avoids needing to modify codegen for `julia.get_pgcstack` at all.
1 parent 3db38f9 commit ce8dba4

File tree

9 files changed

+63
-101
lines changed

9 files changed

+63
-101
lines changed

src/aotcompile.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -975,17 +975,19 @@ static GlobalVariable *emit_shard_table(Module &M, Type *T_size, Type *T_psize,
975975
}
976976

977977
// See src/processor.h for documentation about this table. Corresponds to jl_image_ptls_t.
978-
static GlobalVariable *emit_ptls_table(Module &M, Type *T_size, Type *T_psize) {
978+
static GlobalVariable *emit_ptls_table(Module &M, Type *T_size, Type *T_ptr) {
979+
Function *jl_pgcstack_default_func = Function::Create(
980+
FunctionType::get(T_ptr, false), GlobalValue::ExternalLinkage, "jl_pgcstack_default_func", &M);
979981
std::array<Constant *, 3> ptls_table{
980-
new GlobalVariable(M, T_size, false, GlobalValue::ExternalLinkage, Constant::getNullValue(T_size), "jl_pgcstack_func_slot"),
982+
new GlobalVariable(M, T_ptr, false, GlobalValue::ExternalLinkage, jl_pgcstack_default_func, "jl_pgcstack_func_slot"),
981983
new GlobalVariable(M, T_size, false, GlobalValue::ExternalLinkage, Constant::getNullValue(T_size), "jl_pgcstack_key_slot"),
982984
new GlobalVariable(M, T_size, false, GlobalValue::ExternalLinkage, Constant::getNullValue(T_size), "jl_tls_offset"),
983985
};
984986
for (auto &gv : ptls_table) {
985987
cast<GlobalVariable>(gv)->setVisibility(GlobalValue::HiddenVisibility);
986988
cast<GlobalVariable>(gv)->setDSOLocal(true);
987989
}
988-
auto ptls_table_arr = ConstantArray::get(ArrayType::get(T_psize, ptls_table.size()), ptls_table);
990+
auto ptls_table_arr = ConstantArray::get(ArrayType::get(T_ptr, ptls_table.size()), ptls_table);
989991
auto ptls_table_gv = new GlobalVariable(M, ptls_table_arr->getType(), false,
990992
GlobalValue::ExternalLinkage, ptls_table_arr, "jl_ptls_table");
991993
ptls_table_gv->setVisibility(GlobalValue::HiddenVisibility);
@@ -2184,6 +2186,7 @@ void jl_dump_native_impl(void *native_code,
21842186

21852187
Type *T_size = DL.getIntPtrType(Context);
21862188
Type *T_psize = T_size->getPointerTo();
2189+
Type *T_ptr = PointerType::get(Context, 0);
21872190

21882191
auto FT = FunctionType::get(Type::getInt8Ty(Context)->getPointerTo()->getPointerTo(), {}, false);
21892192
auto F = Function::Create(FT, Function::ExternalLinkage, "get_jl_RTLD_DEFAULT_handle_addr", metadataM);
@@ -2226,7 +2229,7 @@ void jl_dump_native_impl(void *native_code,
22262229
GlobalVariable::InternalLinkage,
22272230
value, "jl_dispatch_target_ids");
22282231
auto shards = emit_shard_table(metadataM, T_size, T_psize, threads);
2229-
auto ptls = emit_ptls_table(metadataM, T_size, T_psize);
2232+
auto ptls = emit_ptls_table(metadataM, T_size, T_ptr);
22302233
auto header = emit_image_header(metadataM, threads, nfvars, ngvars);
22312234
auto AT = ArrayType::get(T_size, sizeof(jl_small_typeof) / sizeof(void*));
22322235
auto jl_small_typeof_copy = new GlobalVariable(metadataM, AT, false,

src/dlload.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -240,22 +240,30 @@ JL_DLLEXPORT int jl_dlclose(void *handle) JL_NOTSAFEPOINT
240240
#endif
241241
}
242242

243-
void *jl_find_dynamic_library_by_addr(void *symbol) {
243+
void *jl_find_dynamic_library_by_addr(void *symbol, int throw_err) {
244244
void *handle;
245245
#ifdef _OS_WINDOWS_
246246
if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
247247
(LPCWSTR)symbol,
248248
(HMODULE*)&handle)) {
249-
jl_error("could not load base module");
249+
if (throw_err)
250+
jl_error("could not load base module");
251+
else
252+
return NULL;
250253
}
251254
#else
252255
Dl_info info;
253256
if (!dladdr(symbol, &info) || !info.dli_fname) {
254-
jl_error("could not load base module");
257+
if (throw_err)
258+
jl_error("could not load base module");
259+
else
260+
return NULL;
255261
}
256262
handle = dlopen(info.dli_fname, RTLD_NOW | RTLD_NOLOAD | RTLD_LOCAL);
257-
if (handle == NULL && dlerror() == NULL) // We loaded the executable but got RTLD_DEFAULT back, give a real handle instead
263+
if (handle == RTLD_DEFAULT && (RTLD_DEFAULT != NULL || dlerror() == NULL)) {
264+
// We loaded the executable but got RTLD_DEFAULT back, ask for a real handle instead
258265
handle = dlopen("", RTLD_NOW | RTLD_NOLOAD | RTLD_LOCAL);
266+
}
259267
if (handle) // We may get a null handle so don't segfault
260268
dlclose(handle); // Undo ref count increment from `dlopen`
261269
#endif
@@ -280,7 +288,7 @@ JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags,
280288

281289
// modname == NULL is a sentinel value requesting the handle of libjulia-internal
282290
if (modname == NULL)
283-
return jl_find_dynamic_library_by_addr(&jl_load_dynamic_library);
291+
return jl_find_dynamic_library_by_addr(&jl_load_dynamic_library, throw_err);
284292

285293
abspath = jl_isabspath(modname);
286294
is_atpath = 0;

src/init.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ JL_DLLEXPORT void jl_atexit_hook(int exitcode) JL_NOTSAFEPOINT_ENTER
238238
jl_task_t *ct = jl_get_current_task();
239239

240240
if (ct == NULL && jl_base_module) {
241-
ct = container_of(jl_adopt_thread(NULL), jl_task_t, gcstack);
241+
ct = container_of(jl_adopt_thread(), jl_task_t, gcstack);
242242
}
243243
else if (ct != NULL) {
244244
// we are about to start tearing everything down, so lets try not to get
@@ -808,8 +808,8 @@ JL_DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel)
808808
void *stack_lo, *stack_hi;
809809
jl_init_stack_limits(1, &stack_lo, &stack_hi);
810810

811-
jl_libjulia_internal_handle = jl_find_dynamic_library_by_addr(&jl_load_dynamic_library);
812-
jl_libjulia_handle = jl_find_dynamic_library_by_addr(&jl_any_type);
811+
jl_libjulia_internal_handle = jl_find_dynamic_library_by_addr(&jl_load_dynamic_library, /* throw_err */ 1);
812+
jl_libjulia_handle = jl_find_dynamic_library_by_addr(&jl_any_type, /* throw_err */ 1);
813813
#ifdef _OS_WINDOWS_
814814
jl_exe_handle = GetModuleHandleA(NULL);
815815
jl_RTLD_DEFAULT_handle = jl_libjulia_internal_handle;

src/jl_exported_funcs.inc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
XX(jl_atomic_store_bits) \
4141
XX(jl_atomic_storeonce_bits) \
4242
XX(jl_atomic_swap_bits) \
43+
XX(jl_autoinit_and_adopt_thread) \
4344
XX(jl_backtrace_from_here) \
4445
XX(jl_base_relative_to) \
4546
XX(jl_bitcast) \
@@ -292,7 +293,6 @@
292293
XX(jl_load_) \
293294
XX(jl_load_and_lookup) \
294295
XX(jl_load_dynamic_library) \
295-
XX(jl_find_dynamic_library_by_addr) \
296296
XX(jl_load_file_string) \
297297
XX(jl_lookup_code_address) \
298298
XX(jl_lseek) \
@@ -362,6 +362,7 @@
362362
XX(jl_pathname_for_handle) \
363363
XX(jl_pchar_to_array) \
364364
XX(jl_pchar_to_string) \
365+
XX(jl_pgcstack_default_func) \
365366
XX(jl_pointerref) \
366367
XX(jl_pointerset) \
367368
XX(jl_pop_handler) \

src/jlapi.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,13 +1125,6 @@ JL_DLLEXPORT int jl_repl_entrypoint(int argc, char *argv[])
11251125
jl_atexit_hook(ret);
11261126
return ret;
11271127
}
1128-
int jl_init_runtime_adopt_thread(void* sysimg_handle)
1129-
{
1130-
//Unimplemented
1131-
abort();
1132-
return 0;
1133-
}
1134-
11351128

11361129
#ifdef __cplusplus
11371130
}

src/julia.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2241,7 +2241,7 @@ JL_DLLEXPORT void jl_postoutput_hook(void);
22412241
JL_DLLEXPORT void JL_NORETURN jl_exit(int status);
22422242
JL_DLLEXPORT void JL_NORETURN jl_raise(int signo);
22432243
JL_DLLEXPORT const char *jl_pathname_for_handle(void *handle);
2244-
JL_DLLEXPORT jl_gcframe_t **jl_adopt_thread(void* sysimage_handle);
2244+
JL_DLLEXPORT jl_gcframe_t **jl_adopt_thread(void);
22452245

22462246
JL_DLLEXPORT int jl_deserialize_verify_header(ios_t *s);
22472247
JL_DLLEXPORT void jl_preload_sysimg_so(const char *fname);

src/julia_internal.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,7 +1099,6 @@ void jl_init_serializer(void);
10991099
void jl_init_uv(void);
11001100
void jl_init_int32_int64_cache(void);
11011101
JL_DLLEXPORT void jl_init_options(void);
1102-
int jl_init_runtime_adopt_thread(void* sysimg_handle);
11031102

11041103
void jl_set_base_ctx(char *__stk);
11051104

@@ -1514,7 +1513,7 @@ void win32_formatmessage(DWORD code, char *reason, int len) JL_NOTSAFEPOINT;
15141513
#endif
15151514

15161515
JL_DLLEXPORT void *jl_get_library_(const char *f_lib, int throw_err);
1517-
JL_DLLEXPORT void *jl_find_dynamic_library_by_addr(void *symbol);
1516+
void *jl_find_dynamic_library_by_addr(void *symbol, int throw_err);
15181517
#define jl_get_library(f_lib) jl_get_library_(f_lib, 1)
15191518
JL_DLLEXPORT void *jl_load_and_lookup(const char *f_lib, const char *f_name, _Atomic(void*) *hnd);
15201519
JL_DLLEXPORT void *jl_lazy_load_and_lookup(jl_value_t *lib_val, const char *f_name);

src/llvm-ptls.cpp

Lines changed: 12 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
#include "support/dtypes.h"
66
#include "passes.h"
77

8-
#include "llvm/IR/BasicBlock.h"
9-
#include "llvm/IR/Instruction.h"
10-
#include "llvm/Support/Debug.h"
118
#include <llvm-c/Core.h>
129
#include <llvm-c/Types.h>
1310

@@ -146,17 +143,7 @@ void LowerPTLS::fix_pgcstack_use(CallInst *pgcstack, Function *pgcstack_getter,
146143
return;
147144
}
148145
if (or_new) {
149-
// pgcstack = pgstack_intrinsic()
150-
151-
152-
// if (offset != 0)
153-
// pgcstack = tp + offset; // fast
154-
// else
155-
// pgcstack_getter = load pgcstack_func_slot
156-
// if pgcstack_getter == nullptr // Runtime not initialized
157-
// pgcstack = nullptr
158-
// else
159-
// pgcstack = pgcstack_getter();
146+
// pgcstack();
160147
// if (pgcstack != nullptr)
161148
// last_gc_state = emit_gc_unsafe_enter(ctx);
162149
// phi = pgcstack; // fast
@@ -182,29 +169,17 @@ void LowerPTLS::fix_pgcstack_use(CallInst *pgcstack, Function *pgcstack_getter,
182169
if (CFGModified)
183170
*CFGModified = true;
184171
// emit slow branch code
185-
Function *adoptFunc = M->getFunction(XSTR(jl_adopt_thread));
172+
CallInst *adopt = cast<CallInst>(pgcstack->clone());
173+
Function *adoptFunc = M->getFunction(XSTR(jl_autoinit_and_adopt_thread));
186174
if (adoptFunc == NULL) {
187-
adoptFunc = Function::Create(FunctionType::get(builder.getPtrTy(), { builder.getPtrTy()}, false),
175+
adoptFunc = Function::Create(pgcstack_getter->getFunctionType(),
188176
pgcstack_getter->getLinkage(), pgcstack_getter->getAddressSpace(),
189-
XSTR(jl_adopt_thread), M);
177+
XSTR(jl_autoinit_and_adopt_thread), M);
190178
adoptFunc->copyAttributesFrom(pgcstack_getter);
191179
adoptFunc->copyMetadata(pgcstack_getter, 0);
192180
}
193-
builder.SetInsertPoint(slowTerm);
194-
Value* handle = Constant::getNullValue(builder.getPtrTy());
195-
if (imaging_mode) {
196-
// Adopt thread takes in a handle to the sysimage and this is the easiest way to get it.
197-
Function *dladdr = M->getFunction(XSTR(jl_find_dynamic_library_by_addr)); // gets handle to sysimage
198-
if (dladdr == NULL) {
199-
dladdr = Function::Create(FunctionType::get(builder.getPtrTy(), { builder.getPtrTy()}, false),
200-
pgcstack_getter->getLinkage(), pgcstack_getter->getAddressSpace(),
201-
XSTR(jl_find_dynamic_library_by_addr), M);
202-
}
203-
auto this_func = builder.GetInsertBlock()->getParent();
204-
handle = builder.CreateCall(dladdr, {ConstantExpr::getBitCast(this_func, builder.getPtrTy())});
205-
}
206-
207-
auto adopt = builder.CreateCall(adoptFunc, {handle});
181+
adopt->setCalledFunction(adoptFunc);
182+
adopt->insertBefore(slowTerm);
208183
phi->addIncoming(adopt, slowTerm->getParent());
209184
// emit fast branch code
210185
builder.SetInsertPoint(fastTerm->getParent());
@@ -235,20 +210,17 @@ void LowerPTLS::fix_pgcstack_use(CallInst *pgcstack, Function *pgcstack_getter,
235210

236211
if (imaging_mode) {
237212
IRBuilder<> builder(pgcstack);
238-
SmallVector<uint32_t, 2> Weights{9, 1};
239-
MDBuilder MDB(pgcstack->getContext());
240213
if (jl_tls_elf_support) {
241214
// if (offset != 0)
242215
// pgcstack = tp + offset; // fast
243216
// else
244-
// if pgcstack_getter == null
245-
// pgcstack = null; // slow
246-
// else
247-
// pgcstack = pgcstack_getter(); // slow
217+
// pgcstack = getter(); // slow
248218
auto offset = builder.CreateLoad(T_size, pgcstack_offset);
249219
offset->setMetadata(llvm::LLVMContext::MD_tbaa, tbaa_const);
250220
offset->setMetadata(llvm::LLVMContext::MD_invariant_load, MDNode::get(pgcstack->getContext(), None));
251221
auto cmp = builder.CreateICmpNE(offset, Constant::getNullValue(offset->getType()));
222+
MDBuilder MDB(pgcstack->getContext());
223+
SmallVector<uint32_t, 2> Weights{9, 1};
252224
TerminatorInst *fastTerm;
253225
TerminatorInst *slowTerm;
254226
SplitBlockAndInsertIfThenElse(cmp, pgcstack, &fastTerm, &slowTerm,
@@ -265,52 +237,21 @@ void LowerPTLS::fix_pgcstack_use(CallInst *pgcstack, Function *pgcstack_getter,
265237
// refresh the basic block in the builder
266238
builder.SetInsertPoint(pgcstack);
267239
auto getter = builder.CreateLoad(T_pgcstack_getter, pgcstack_func_slot);
268-
auto phi_value = cast<Instruction>(pgcstack);
269-
if (or_new) {
270-
// if pgcstack_func_slot is not initialized we set pgcstack to null to trigger the slow path
271-
TerminatorInst *nonNullTerm;
272-
TerminatorInst *nullTerm;
273-
auto is_null = builder.CreateICmpEQ(getter, Constant::getNullValue(builder.getPtrTy()));
274-
SplitBlockAndInsertIfThenElse(is_null, pgcstack, &nullTerm, &nonNullTerm,
275-
MDB.createBranchWeights(Weights));
276-
builder.SetInsertPoint(pgcstack);
277-
auto phi2 = builder.CreatePHI(T_pppjlvalue, 2, "pgcstack");
278-
pgcstack->moveBefore(nonNullTerm);
279-
phi2->addIncoming(pgcstack, nonNullTerm->getParent());
280-
phi2->addIncoming(Constant::getNullValue(T_pppjlvalue), nullTerm->getParent());
281-
phi_value = phi2;
282-
builder.SetInsertPoint(pgcstack);
283-
// Check if pgcstack_func_slot is initialized
284-
}
285240
getter->setMetadata(llvm::LLVMContext::MD_tbaa, tbaa_const);
286241
getter->setMetadata(llvm::LLVMContext::MD_invariant_load, MDNode::get(pgcstack->getContext(), None));
287242
pgcstack->setCalledFunction(pgcstack->getFunctionType(), getter);
288243
set_pgcstack_attrs(pgcstack);
289244

290245
phi->addIncoming(fastTLS, fastTLS->getParent());
291-
phi->addIncoming(phi_value, phi_value->getParent());
246+
phi->addIncoming(pgcstack, pgcstack->getParent());
247+
292248
return;
293249
}
294250
// In imaging mode, we emit the function address as a load of a static
295251
// variable to be filled (in `staticdata.c`) at initialization time of the sysimg.
296252
// This way we can bypass the extra indirection in `jl_get_pgcstack`
297253
// since we may not know which getter function to use ahead of time.
298254
auto getter = builder.CreateLoad(T_pgcstack_getter, pgcstack_func_slot);
299-
if (or_new) {
300-
// if pgcstack_func_slot is not initialized we set pgcstack to null to trigger the slow path
301-
TerminatorInst *nonNullTerm;
302-
TerminatorInst *nullTerm;
303-
auto is_null = builder.CreateICmpEQ(getter, Constant::getNullValue(builder.getPtrTy()));
304-
SplitBlockAndInsertIfThenElse(is_null, pgcstack, &nullTerm, &nonNullTerm,
305-
MDB.createBranchWeights(Weights));
306-
builder.SetInsertPoint(pgcstack);
307-
auto phi2 = builder.CreatePHI(T_pppjlvalue, 2, "pgcstack");
308-
pgcstack->moveBefore(nonNullTerm);
309-
pgcstack->replaceAllUsesWith(phi2);
310-
phi2->addIncoming(pgcstack, nonNullTerm->getParent());
311-
phi2->addIncoming(Constant::getNullValue(T_pppjlvalue), nullTerm->getParent());
312-
builder.SetInsertPoint(pgcstack);
313-
}
314255
getter->setMetadata(llvm::LLVMContext::MD_tbaa, tbaa_const);
315256
getter->setMetadata(llvm::LLVMContext::MD_invariant_load, MDNode::get(pgcstack->getContext(), None));
316257
if (TargetTriple.isOSDarwin()) {

src/threading.c

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,11 @@ JL_DLLEXPORT jl_gcframe_t **jl_get_pgcstack(void) JL_GLOBALLY_ROOTED
276276
#endif
277277
}
278278

279+
JL_DLLEXPORT jl_gcframe_t **jl_pgcstack_default_func(void) JL_GLOBALLY_ROOTED
280+
{
281+
return NULL;
282+
}
283+
279284
void jl_pgcstack_getkey(jl_get_pgcstack_func **f, jl_pgcstack_key_t *k)
280285
{
281286
#ifndef __clang_gcanalyzer__
@@ -433,14 +438,9 @@ static void jl_init_task_lock(jl_task_t *ct)
433438
}
434439
}
435440
}
436-
// Pass in the handle to the system image. This is used to initialize the runtime correctly in case we are a shared library
437-
JL_DLLEXPORT jl_gcframe_t **jl_adopt_thread(void* sysimg_handle)
441+
442+
JL_DLLEXPORT jl_gcframe_t **jl_adopt_thread(void)
438443
{
439-
if (!jl_is_initialized()) {
440-
if (jl_init_runtime_adopt_thread(sysimg_handle) == 1)
441-
return &jl_get_current_task()->gcstack;
442-
// We lost the race and need to be initialized as usual
443-
}
444444
// `jl_init_threadtls` puts us in a GC unsafe region, so ensure GC isn't running.
445445
// we can't use a normal safepoint because we don't have signal handlers yet.
446446
jl_atomic_fetch_add(&jl_gc_disable_counter, 1);
@@ -464,6 +464,23 @@ JL_DLLEXPORT jl_gcframe_t **jl_adopt_thread(void* sysimg_handle)
464464
return &ct->gcstack;
465465
}
466466

467+
JL_DLLEXPORT jl_gcframe_t **jl_autoinit_and_adopt_thread(void)
468+
{
469+
void *retaddr = __builtin_extract_return_addr(__builtin_return_address(0));
470+
void *sysimg_handle = jl_find_dynamic_library_by_addr(retaddr, /* throw_err */ 0);
471+
472+
if (!jl_is_initialized()) {
473+
if (sysimg_handle == NULL) {
474+
fprintf(stderr, "error: runtime auto-initialization failed due to bad sysimage lookup\n"
475+
" (this should not happen, please file a bug report)\n");
476+
abort();
477+
}
478+
479+
assert(0 && "TODO: implement auto-init");
480+
}
481+
482+
return jl_adopt_thread();
483+
}
467484

468485
void jl_safepoint_suspend_all_threads(jl_task_t *ct)
469486
{

0 commit comments

Comments
 (0)