Skip to content

Commit

Permalink
Merge pull request #22472 from JuliaLang/yyc/codegen/function_offset
Browse files Browse the repository at this point in the history
Store global variables and function addresses as 32bit offsets
  • Loading branch information
yuyichao authored Jun 23, 2017
2 parents 0737032 + 92152aa commit d040151
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 109 deletions.
5 changes: 3 additions & 2 deletions src/anticodegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ int jl_getFunctionInfo(jl_frame_t **frames, uintptr_t pointer, int skipC, int no
return 0;
}

void jl_register_fptrs(uint64_t sysimage_base, void **fptrs, jl_method_instance_t **linfos, size_t n)
void jl_register_fptrs(uint64_t sysimage_base, const char *base, const int32_t *offsets,
jl_method_instance_t **linfos, size_t n)
{
(void)sysimage_base; (void)fptrs; (void)linfos; (void)n;
(void)sysimage_base; (void)base; (void)offsets; (void)linfos; (void)n;
}

void jl_compile_linfo(jl_method_instance_t *li) { }
Expand Down
150 changes: 99 additions & 51 deletions src/debuginfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -696,13 +696,20 @@ openDebugInfo(StringRef debuginfopath, const debug_link_info &info)
}

static uint64_t jl_sysimage_base;
static void **sysimg_fvars;
static const char *sysimg_fvars_base = nullptr;
static const int32_t *sysimg_fvars_offsets;
static jl_method_instance_t **sysimg_fvars_linfo;
static size_t sysimg_fvars_n;
extern "C" void jl_register_fptrs(uint64_t sysimage_base, void **fptrs, jl_method_instance_t **linfos, size_t n)
static const void *sysimg_fvars(size_t idx)
{
return sysimg_fvars_base + sysimg_fvars_offsets[idx];
}
void jl_register_fptrs(uint64_t sysimage_base, const char *base, const int32_t *offsets,
jl_method_instance_t **linfos, size_t n)
{
jl_sysimage_base = (uintptr_t)sysimage_base;
sysimg_fvars = fptrs;
sysimg_fvars_base = base;
sysimg_fvars_offsets = offsets;
sysimg_fvars_linfo = linfos;
sysimg_fvars_n = n;
}
Expand All @@ -716,6 +723,85 @@ static inline void ignoreError(T &err)
#endif
}

static void get_function_name_and_base(const object::ObjectFile *object, bool insysimage,
void **saddr, char **name, size_t pointer,
int64_t slide)
{
if (!object)
return;
// Assume we only need base address for sysimg for now
if (!insysimage || !sysimg_fvars_base)
saddr = nullptr;
// Try platform specific methods first since they are usually faster
if (saddr && !*saddr) {
#if defined(_OS_LINUX_) && !defined(JL_DISABLE_LIBUNWIND)
unw_proc_info_t pip;
if (unw_get_proc_info_by_ip(unw_local_addr_space, pointer, &pip, NULL) == 0) {
*saddr = (void*)pip.start_ip;
}
#endif
#if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_)
DWORD64 ImageBase;
PRUNTIME_FUNCTION fn = RtlLookupFunctionEntry(pointer, &ImageBase, NULL);
if (fn) {
*saddr = (void*)(ImageBase + fn->BeginAddress);
}
#endif
}
if ((saddr && !*saddr) || (name && !*name)) {
size_t distance = (size_t)-1;
SymRef sym_found;
for (auto sym: object->symbols()) {
auto addr = sym.getAddress();
if (!addr)
continue;
size_t symptr = addr.get();
if (symptr > pointer + slide)
continue;
size_t new_dist = pointer + slide - symptr;
if (new_dist > distance)
continue;
distance = new_dist;
sym_found = sym;
}
if (distance != (size_t)-1) {
if (saddr && !*saddr) {
auto addr = sym_found.getAddress();
assert(addr);
*saddr = (void*)(uintptr_t)(addr.get() - slide);
}
if (name && !*name) {
if (auto name_or_err = sym_found.getName()) {
auto nameref = name_or_err.get();
size_t len = nameref.size();
*name = (char*)malloc(len + 1);
(*name)[len] = 0;
memcpy(*name, nameref.data(), len);
}
}
}
}
#ifdef _OS_WINDOWS_
// For ntdll and msvcrt since we are currently only parsing DWARF debug info through LLVM
if (!insysimage && name && !*name) {
static char frame_info_func[
sizeof(SYMBOL_INFO) +
MAX_SYM_NAME * sizeof(TCHAR)];
DWORD64 dwDisplacement64 = 0;
DWORD64 dwAddress = pointer;
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)frame_info_func;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
jl_in_stackwalk = 1;
if (SymFromAddr(GetCurrentProcess(), dwAddress, &dwDisplacement64, pSymbol)) {
// errors are ignored
jl_copy_str(name, pSymbol->Name);
}
jl_in_stackwalk = 0;
}
#endif
}

extern "C" void jl_refresh_dbg_module_list(void);
bool jl_dylib_DI_for_fptr(size_t pointer, const llvm::object::ObjectFile **obj, llvm::DIContext **context, int64_t *slide, int64_t *section_slide,
bool onlySysImg, bool *isSysImg, void **saddr, char **name, char **filename)
Expand Down Expand Up @@ -746,35 +832,12 @@ bool jl_dylib_DI_for_fptr(size_t pointer, const llvm::object::ObjectFile **obj,
if (onlySysImg && !insysimage) {
return false;
}
static char frame_info_func[
sizeof(SYMBOL_INFO) +
MAX_SYM_NAME * sizeof(TCHAR)];
DWORD64 dwDisplacement64 = 0;
DWORD64 dwAddress = pointer;
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)frame_info_func;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
jl_in_stackwalk = 1;
if (SymFromAddr(GetCurrentProcess(), dwAddress, &dwDisplacement64,
pSymbol)) {
// SymFromAddr returned success
// errors are ignored, but are hopefully patched up by
// using llvm to read the object (below)
if (name)
jl_copy_str(name, pSymbol->Name);
if (saddr)
*saddr = (void*)(uintptr_t)pSymbol->Address;
}
else if (saddr) {
*saddr = NULL;
}

// If we didn't find the filename before in the debug
// info, use the dll name
if (filename && !*filename)
jl_copy_str(filename, fname.data());

jl_in_stackwalk = 0;
if (saddr)
*saddr = NULL;

#else // ifdef _OS_WINDOWS_
Dl_info dlinfo;
Expand Down Expand Up @@ -832,6 +895,7 @@ bool jl_dylib_DI_for_fptr(size_t pointer, const llvm::object::ObjectFile **obj,
*context = it->second.ctx;
*slide = it->second.slide;
*section_slide = it->second.section_slide;
get_function_name_and_base(*obj, insysimage, saddr, name, pointer, *slide);
return true;
}

Expand Down Expand Up @@ -961,6 +1025,7 @@ bool jl_dylib_DI_for_fptr(size_t pointer, const llvm::object::ObjectFile **obj,
// update cache
objfileentry_t entry = {*obj, *context, *slide, *section_slide};
objfilemap[fbase] = entry;
get_function_name_and_base(*obj, insysimage, saddr, name, pointer, *slide);
return true;
}

Expand Down Expand Up @@ -999,32 +1064,15 @@ static int jl_getDylibFunctionInfo(jl_frame_t **frames, size_t pointer, int skip
return 1;
}
frame0->fromC = !isSysImg;
if (isSysImg && sysimg_fvars) {
#if defined(_OS_LINUX_) && !defined(JL_DISABLE_LIBUNWIND)
unw_proc_info_t pip;
if (!saddr && unw_get_proc_info_by_ip(unw_local_addr_space,
pointer, &pip, NULL) == 0)
saddr = (void*)pip.start_ip;
#endif
#if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_)
if (!saddr) {
DWORD64 ImageBase;
PRUNTIME_FUNCTION fn = RtlLookupFunctionEntry(pointer, &ImageBase, NULL);
if (fn)
saddr = (void*)(ImageBase + fn->BeginAddress);
}
#endif
if (saddr) {
for (size_t i = 0; i < sysimg_fvars_n; i++) {
if (saddr == sysimg_fvars[i]) {
frame0->linfo = sysimg_fvars_linfo[i];
break;
}
if (isSysImg && sysimg_fvars_base && saddr) {
for (size_t i = 0; i < sysimg_fvars_n; i++) {
if (saddr == sysimg_fvars(i)) {
frame0->linfo = sysimg_fvars_linfo[i];
break;
}
}
return lookup_pointer(context, frames, pointer+slide, isSysImg, noInline);
}
return lookup_pointer(context, frames, pointer+slide, isSysImg, noInline);
return lookup_pointer(context, frames, pointer + slide, isSysImg, noInline);
}

int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide, int64_t *section_slide,
Expand Down
50 changes: 32 additions & 18 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,20 @@ static void write_float64(ios_t *s, double x)
#define jl_serialize_value(s, v) jl_serialize_value_((s), (jl_value_t*)(v), 0)
static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_literal);
static jl_value_t *jl_deserialize_value(jl_serializer_state *s, jl_value_t **loc);
static jl_value_t ***sysimg_gvars = NULL;
static void **sysimg_fvars = NULL;
static char *sysimg_gvars_base = NULL;
static const int32_t *sysimg_gvars_offsets = NULL;
static const char *sysimg_fvars_base = NULL;
static const int32_t *sysimg_fvars_offsets = NULL;

static inline jl_value_t **sysimg_gvars(size_t idx)
{
return (jl_value_t**)(sysimg_gvars_base + sysimg_gvars_offsets[idx]);
}

static inline const void *sysimg_fvars(const char *base, size_t idx)
{
return base + sysimg_fvars_offsets[idx];
}

#ifdef HAVE_CPUID
extern void jl_cpuid(int32_t CPUInfo[4], int32_t InfoType);
Expand All @@ -233,17 +245,21 @@ static void jl_load_sysimg_so(void)
int imaging_mode = jl_generating_output() && !jl_options.incremental;
// in --build mode only use sysimg data, not precompiled native code
if (!imaging_mode && jl_options.use_precompiled==JL_OPTIONS_USE_PRECOMPILED_YES) {
sysimg_gvars = (jl_value_t***)jl_dlsym(jl_sysimg_handle, "jl_sysimg_gvars");
sysimg_fvars = (void**)jl_dlsym(jl_sysimg_handle, "jl_sysimg_fvars");
sysimg_gvars_base = (char*)jl_dlsym(jl_sysimg_handle, "jl_sysimg_gvars_base");
sysimg_gvars_offsets = (const int32_t*)jl_dlsym(jl_sysimg_handle,
"jl_sysimg_gvars_offsets");
sysimg_fvars_base = (const char*)jl_dlsym(jl_sysimg_handle, "jl_sysimg_fvars_base");
sysimg_fvars_offsets = (const int32_t*)jl_dlsym(jl_sysimg_handle,
"jl_sysimg_fvars_offsets");
globalUnique = *(size_t*)jl_dlsym(jl_sysimg_handle, "jl_globalUnique");
#ifdef JULIA_ENABLE_THREADING
size_t tls_getter_idx = *(size_t*)jl_dlsym(jl_sysimg_handle,
"jl_ptls_states_getter_idx");
*sysimg_gvars[tls_getter_idx - 1] =
*sysimg_gvars(tls_getter_idx - 1) =
(jl_value_t*)(uintptr_t)jl_get_ptls_states_getter();
size_t tls_offset_idx = *(size_t*)jl_dlsym(jl_sysimg_handle,
"jl_tls_offset_idx");
*sysimg_gvars[tls_offset_idx - 1] =
*sysimg_gvars(tls_offset_idx - 1) =
(jl_value_t*)(uintptr_t)(jl_tls_offset == -1 ? 0 : jl_tls_offset);
#endif
const char *cpu_target = (const char*)jl_dlsym(jl_sysimg_handle, "jl_sysimg_cpu_target");
Expand Down Expand Up @@ -271,7 +287,7 @@ static void jl_load_sysimg_so(void)
#ifdef _OS_WINDOWS_
sysimage_base = (intptr_t)jl_sysimg_handle;
#else
if (dladdr((void*)sysimg_gvars, &dlinfo) != 0) {
if (dladdr((void*)sysimg_gvars_base, &dlinfo) != 0) {
sysimage_base = (intptr_t)dlinfo.dli_fbase;
}
else {
Expand All @@ -288,8 +304,8 @@ static jl_value_t *jl_deserialize_gv(jl_serializer_state *s, jl_value_t *v)
{
// Restore the GlobalVariable reference to this jl_value_t via the sysimg_gvars table
int32_t gvname_index = read_int32(s->s)-1;
if (sysimg_gvars != NULL && gvname_index >= 0 && s->mode == MODE_SYSTEM_IMAGE) {
*sysimg_gvars[gvname_index] = v;
if (sysimg_gvars_base != NULL && gvname_index >= 0 && s->mode == MODE_SYSTEM_IMAGE) {
*sysimg_gvars(gvname_index) = v;
}
return v;
}
Expand Down Expand Up @@ -419,13 +435,11 @@ static void jl_delayed_fptrs(jl_method_instance_t *li, int32_t func, int32_t cfu
}
}

void jl_register_fptrs(uint64_t sysimage_base, void **fptrs, jl_method_instance_t **linfos, size_t n);

static void jl_update_all_fptrs(void)
{
//jl_printf(JL_STDOUT, "delayed_fptrs_n: %d\n", delayed_fptrs_n);
void **fvars = sysimg_fvars;
if (fvars == NULL) {
const char *fvars_base = sysimg_fvars_base;
if (fvars_base == NULL) {
size_t i;
for (i = 0; i < delayed_fptrs_n; i++) {
jl_method_instance_t *li = delayed_fptrs[i].li;
Expand All @@ -436,25 +450,25 @@ static void jl_update_all_fptrs(void)
}
// jl_fptr_to_llvm needs to decompress some ASTs, therefore this needs to be NULL
// to skip trying to restore GlobalVariable pointers in jl_deserialize_gv
sysimg_gvars = NULL;
sysimg_fvars = NULL;
sysimg_gvars_base = NULL;
sysimg_fvars_base = NULL;
size_t i;
jl_method_instance_t **linfos = (jl_method_instance_t**)malloc(sizeof(jl_method_instance_t*) * sysimg_fvars_max);
for (i = 0; i < delayed_fptrs_n; i++) {
jl_method_instance_t *li = delayed_fptrs[i].li;
assert(jl_is_method(li->def.method) && li->jlcall_api && li->jlcall_api != 2);
int32_t cfunc = delayed_fptrs[i].cfunc - 1;
if (cfunc >= 0) {
jl_fptr_to_llvm((jl_fptr_t)(uintptr_t)fvars[cfunc], li, 1);
jl_fptr_to_llvm((jl_fptr_t)(uintptr_t)sysimg_fvars(fvars_base, cfunc), li, 1);
linfos[cfunc] = li;
}
int32_t func = delayed_fptrs[i].func - 1;
if (func >= 0) {
jl_fptr_to_llvm((jl_fptr_t)(uintptr_t)fvars[func], li, 0);
jl_fptr_to_llvm((jl_fptr_t)(uintptr_t)sysimg_fvars(fvars_base, func), li, 0);
linfos[func] = li;
}
}
jl_register_fptrs(sysimage_base, fvars, linfos, sysimg_fvars_max);
jl_register_fptrs(sysimage_base, fvars_base, sysimg_fvars_offsets, linfos, sysimg_fvars_max);
delayed_fptrs_n = 0;
delayed_fptrs_max = 0;
sysimg_fvars_max = 0;
Expand Down
Loading

2 comments on commit d040151

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Executing the daily benchmark build, I will reply here when finished:

@nanosoldier runbenchmarks(ALL, isdaily = true)

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @jrevels

Please sign in to comment.