Skip to content

Commit cc4122c

Browse files
authored
Switch debug registry mapping to CodeInstance (#56878)
Currently our debugging code maps from pointers to `MethodInstance`. However, I think it makes more sense to map to `CodeInstance` instead, since that's what we're actually compiling and as we're starting to make more use of external owners and custom specializations, we'll want to be able to annotate that in backtraces. This only adjusts the internal data structures - any actual printing changes for those sorts of use cases will have to come separately.
1 parent 5ee67b8 commit cc4122c

File tree

8 files changed

+88
-56
lines changed

8 files changed

+88
-56
lines changed

base/errorshow.jl

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -915,9 +915,9 @@ function _collapse_repeated_frames(trace)
915915
[3] g(x::Int64) <-- useless
916916
@ Main ./REPL[1]:1
917917
=#
918-
if frame.linfo isa MethodInstance && last_frame.linfo isa MethodInstance &&
919-
frame.linfo.def isa Method && last_frame.linfo.def isa Method
920-
m, last_m = frame.linfo.def::Method, last_frame.linfo.def::Method
918+
m, last_m = StackTraces.frame_method_or_module(frame),
919+
StackTraces.frame_method_or_module(last_frame)
920+
if m isa Method && last_m isa Method
921921
params, last_params = Base.unwrap_unionall(m.sig).parameters, Base.unwrap_unionall(last_m.sig).parameters
922922
if last_m.nkw != 0
923923
pos_sig_params = last_params[(last_m.nkw+2):end]
@@ -944,7 +944,6 @@ function _collapse_repeated_frames(trace)
944944
return trace[kept_frames]
945945
end
946946

947-
948947
function process_backtrace(t::Vector, limit::Int=typemax(Int); skipC = true)
949948
n = 0
950949
last_frame = StackTraces.UNKNOWN
@@ -965,9 +964,8 @@ function process_backtrace(t::Vector, limit::Int=typemax(Int); skipC = true)
965964
if (lkup.from_c && skipC)
966965
continue
967966
end
968-
code = lkup.linfo
969-
if code isa MethodInstance
970-
def = code.def
967+
if lkup.linfo isa Union{MethodInstance, CodeInstance}
968+
def = StackTraces.frame_method_or_module(lkup)
971969
if def isa Method && def.name !== :kwcall && def.sig <: Tuple{typeof(Core.kwcall),NamedTuple,Any,Vararg}
972970
# hide kwcall() methods, which are probably internal keyword sorter methods
973971
# (we print the internal method instead, after demangling

base/stacktraces.jl

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module StackTraces
77

88

99
import Base: hash, ==, show
10-
import Core: CodeInfo, MethodInstance
10+
import Core: CodeInfo, MethodInstance, CodeInstance
1111
using Base.IRShow: normalize_method_name, append_scopes!, LineInfoNode
1212

1313
export StackTrace, StackFrame, stacktrace
@@ -21,9 +21,9 @@ Stack information representing execution context, with the following fields:
2121
2222
The name of the function containing the execution context.
2323
24-
- `linfo::Union{Method, Core.MethodInstance, Core.CodeInfo, Nothing}`
24+
- `linfo::Union{Method, Core.MethodInstance, Core.CodeInstance, Core.CodeInfo, Nothing}`
2525
26-
The Method, MethodInstance, or CodeInfo containing the execution context (if it could be found), \
26+
The Method, MethodInstance, CodeInstance, or CodeInfo containing the execution context (if it could be found), \
2727
or nothing (for example, if the inlining was a result of macro expansion).
2828
2929
- `file::Symbol`
@@ -54,9 +54,9 @@ struct StackFrame # this type should be kept platform-agnostic so that profiles
5454
file::Symbol
5555
"the line number in the file containing the execution context"
5656
line::Int
57-
"the MethodInstance or CodeInfo containing the execution context (if it could be found), \
57+
"the CodeInstance or CodeInfo containing the execution context (if it could be found), \
5858
or nothing (for example, if the inlining was a result of macro expansion)."
59-
linfo::Union{MethodInstance, Method, CodeInfo, Nothing}
59+
linfo::Union{Core.MethodInstance, Core.CodeInstance, Method, CodeInfo, Nothing}
6060
"true if the code is from C"
6161
from_c::Bool
6262
"true if the code is from an inlined frame"
@@ -137,16 +137,26 @@ function lookup(ip::Base.InterpreterIP)
137137
line = meth.line
138138
codeinfo = meth.source
139139
else
140+
func = top_level_scope_sym
141+
file = empty_sym
142+
line = Int32(0)
140143
if code isa Core.CodeInstance
141144
codeinfo = code.inferred::CodeInfo
145+
def = code.def
146+
if isa(def, Core.ABIOverride)
147+
def = def.def
148+
end
149+
if isa(def, MethodInstance) && isa(def.def, Method)
150+
meth = def.def
151+
func = meth.name
152+
file = meth.file
153+
line = meth.line
154+
end
142155
else
143156
codeinfo = code::CodeInfo
144157
end
145-
func = top_level_scope_sym
146-
file = empty_sym
147-
line = Int32(0)
148158
end
149-
def = (code isa MethodInstance ? code : StackTraces) # Module just used as a token for top-level code
159+
def = (code isa CodeInfo ? StackTraces : code) # Module just used as a token for top-level code
150160
pc::Int = max(ip.stmt + 1, 0) # n.b. ip.stmt is 0-indexed
151161
scopes = LineInfoNode[]
152162
append_scopes!(scopes, pc, codeinfo.debuginfo, def)
@@ -157,7 +167,7 @@ function lookup(ip::Base.InterpreterIP)
157167
scopes = map(scopes) do lno
158168
if inlined
159169
def = lno.method
160-
def isa Union{Method,MethodInstance} || (def = nothing)
170+
def isa Union{Method,Core.CodeInstance,MethodInstance} || (def = nothing)
161171
else
162172
def = codeinfo
163173
end
@@ -227,6 +237,23 @@ end
227237

228238
is_top_level_frame(f::StackFrame) = f.linfo isa CodeInfo || (f.linfo === nothing && f.func === top_level_scope_sym)
229239

240+
function frame_method_or_module(lkup::StackFrame)
241+
code = lkup.linfo
242+
code isa Method && return code
243+
code isa Module && return code
244+
mi = frame_mi(lkup)
245+
mi isa MethodInstance || return nothing
246+
return mi.def
247+
end
248+
249+
function frame_mi(lkup::StackFrame)
250+
code = lkup.linfo
251+
code isa Core.CodeInstance && (code = code.def)
252+
code isa Core.ABIOverride && (code = code.def)
253+
code isa MethodInstance || return nothing
254+
return code
255+
end
256+
230257
function show_spec_linfo(io::IO, frame::StackFrame)
231258
linfo = frame.linfo
232259
if linfo === nothing
@@ -241,16 +268,18 @@ function show_spec_linfo(io::IO, frame::StackFrame)
241268
print(io, "top-level scope")
242269
elseif linfo isa Module
243270
Base.print_within_stacktrace(io, Base.demangle_function_name(string(frame.func)), bold=true)
244-
elseif linfo isa MethodInstance
245-
def = linfo.def
246-
if def isa Module
247-
Base.show_mi(io, linfo, #=from_stackframe=#true)
271+
else
272+
if linfo isa Union{MethodInstance, CodeInstance}
273+
def = frame_method_or_module(frame)
274+
if def isa Module
275+
Base.show_mi(io, linfo, #=from_stackframe=#true)
276+
else
277+
show_spec_sig(io, def, frame_mi(frame).specTypes)
278+
end
248279
else
249-
show_spec_sig(io, def, linfo.specTypes)
280+
m = linfo::Method
281+
show_spec_sig(io, m, m.sig)
250282
end
251-
else
252-
m = linfo::Method
253-
show_spec_sig(io, m, m.sig)
254283
end
255284
end
256285

@@ -302,6 +331,12 @@ end
302331

303332
function Base.parentmodule(frame::StackFrame)
304333
linfo = frame.linfo
334+
if linfo isa CodeInstance
335+
linfo = linfo.def
336+
if isa(linfo, Core.ABIOverride)
337+
linfo = linfo.def
338+
end
339+
end
305340
if linfo isa MethodInstance
306341
def = linfo.def
307342
if def isa Module

src/debug-registry.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ typedef struct {
1414
int64_t slide;
1515
} objfileentry_t;
1616

17-
// Central registry for resolving function addresses to `jl_method_instance_t`s and
17+
// Central registry for resolving function addresses to `jl_code_instance_t`s and
1818
// originating `ObjectFile`s (for the DWARF debug info).
1919
//
2020
// A global singleton instance is notified by the JIT whenever a new object is emitted,
@@ -82,7 +82,7 @@ class JITDebugInfoRegistry
8282
struct image_info_t {
8383
uint64_t base;
8484
jl_image_fptrs_t fptrs;
85-
jl_method_instance_t **fvars_linfo;
85+
jl_code_instance_t **fvars_cinst;
8686
size_t fvars_n;
8787
};
8888

@@ -124,7 +124,7 @@ class JITDebugInfoRegistry
124124
typedef rev_map<uint64_t, objfileentry_t> objfilemap_t;
125125

126126
objectmap_t objectmap{};
127-
rev_map<size_t, std::pair<size_t, jl_method_instance_t *>> linfomap{};
127+
rev_map<size_t, std::pair<size_t, jl_code_instance_t *>> cimap{};
128128

129129
// Maintain a mapping of unrealized function names -> linfo objects
130130
// so that when we see it get emitted, we can add a link back to the linfo
@@ -145,7 +145,7 @@ class JITDebugInfoRegistry
145145
libc_frames_t libc_frames{};
146146

147147
void add_code_in_flight(llvm::StringRef name, jl_code_instance_t *codeinst, const llvm::DataLayout &DL) JL_NOTSAFEPOINT;
148-
jl_method_instance_t *lookupLinfo(size_t pointer) JL_NOTSAFEPOINT;
148+
jl_code_instance_t *lookupCodeInstance(size_t pointer) JL_NOTSAFEPOINT;
149149
void registerJITObject(const llvm::object::ObjectFile &Object,
150150
std::function<uint64_t(const llvm::StringRef &)> getLoadAddress) JL_NOTSAFEPOINT;
151151
objectmap_t& getObjectMap() JL_NOTSAFEPOINT;

src/debuginfo.cpp

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,12 @@ void JITDebugInfoRegistry::add_code_in_flight(StringRef name, jl_code_instance_t
9494
(**codeinst_in_flight)[mangle(name, DL)] = codeinst;
9595
}
9696

97-
jl_method_instance_t *JITDebugInfoRegistry::lookupLinfo(size_t pointer)
97+
jl_code_instance_t *JITDebugInfoRegistry::lookupCodeInstance(size_t pointer)
9898
{
9999
jl_lock_profile();
100-
auto region = linfomap.lower_bound(pointer);
101-
jl_method_instance_t *linfo = NULL;
102-
if (region != linfomap.end() && pointer < region->first + region->second.first)
100+
auto region = cimap.lower_bound(pointer);
101+
jl_code_instance_t *linfo = NULL;
102+
if (region != cimap.end() && pointer < region->first + region->second.first)
103103
linfo = region->second.second;
104104
jl_unlock_profile();
105105
return linfo;
@@ -371,14 +371,9 @@ void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object,
371371
codeinst_in_flight.erase(codeinst_it);
372372
}
373373
}
374-
jl_method_instance_t *mi = NULL;
375-
if (codeinst) {
376-
JL_GC_PROMISE_ROOTED(codeinst);
377-
mi = jl_get_ci_mi(codeinst);
378-
}
379374
jl_profile_atomic([&]() JL_NOTSAFEPOINT {
380-
if (mi)
381-
linfomap[Addr] = std::make_pair(Size, mi);
375+
if (codeinst)
376+
cimap[Addr] = std::make_pair(Size, codeinst);
382377
hassection = true;
383378
objectmap.insert(std::pair{SectionLoadAddr, SectionInfo{
384379
ObjectCopy,
@@ -506,7 +501,7 @@ static int lookup_pointer(
506501
std::size_t semi_pos = func_name.find(';');
507502
if (semi_pos != std::string::npos) {
508503
func_name = func_name.substr(0, semi_pos);
509-
frame->linfo = NULL; // Looked up on Julia side
504+
frame->ci = NULL; // Looked up on Julia side
510505
}
511506
}
512507
}
@@ -692,9 +687,9 @@ openDebugInfo(StringRef debuginfopath, const debug_link_info &info) JL_NOTSAFEPO
692687
}
693688
extern "C" JL_DLLEXPORT_CODEGEN
694689
void jl_register_fptrs_impl(uint64_t image_base, const jl_image_fptrs_t *fptrs,
695-
jl_method_instance_t **linfos, size_t n)
690+
jl_code_instance_t **cinfos, size_t n)
696691
{
697-
getJITDebugRegistry().add_image_info({(uintptr_t) image_base, *fptrs, linfos, n});
692+
getJITDebugRegistry().add_image_info({(uintptr_t) image_base, *fptrs, cinfos, n});
698693
}
699694

700695
template<typename T>
@@ -1177,13 +1172,13 @@ static int jl_getDylibFunctionInfo(jl_frame_t **frames, size_t pointer, int skip
11771172
if (saddr == image.fptrs.clone_ptrs[i]) {
11781173
uint32_t idx = image.fptrs.clone_idxs[i] & jl_sysimg_val_mask;
11791174
if (idx < image.fvars_n) // items after this were cloned but not referenced directly by a method (such as our ccall PLT thunks)
1180-
frame0->linfo = image.fvars_linfo[idx];
1175+
frame0->ci = image.fvars_cinst[idx];
11811176
break;
11821177
}
11831178
}
11841179
for (size_t i = 0; i < image.fvars_n; i++) {
11851180
if (saddr == image.fptrs.ptrs[i]) {
1186-
frame0->linfo = image.fvars_linfo[i];
1181+
frame0->ci = image.fvars_cinst[i];
11871182
break;
11881183
}
11891184
}
@@ -1255,16 +1250,16 @@ extern "C" JL_DLLEXPORT_CODEGEN int jl_getFunctionInfo_impl(jl_frame_t **frames_
12551250
int64_t slide;
12561251
uint64_t symsize;
12571252
if (jl_DI_for_fptr(pointer, &symsize, &slide, &Section, &context)) {
1258-
frames[0].linfo = getJITDebugRegistry().lookupLinfo(pointer);
1253+
frames[0].ci = getJITDebugRegistry().lookupCodeInstance(pointer);
12591254
int nf = lookup_pointer(Section, context, frames_out, pointer, slide, true, noInline);
12601255
return nf;
12611256
}
12621257
return jl_getDylibFunctionInfo(frames_out, pointer, skipC, noInline);
12631258
}
12641259

1265-
extern "C" jl_method_instance_t *jl_gdblookuplinfo(void *p) JL_NOTSAFEPOINT
1260+
extern "C" jl_code_instance_t *jl_gdblookupci(void *p) JL_NOTSAFEPOINT
12661261
{
1267-
return getJITDebugRegistry().lookupLinfo((size_t)p);
1262+
return getJITDebugRegistry().lookupCodeInstance((size_t)p);
12681263
}
12691264

12701265
#if defined(_OS_DARWIN_) && defined(LLVM_SHLIB)

src/julia_internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1349,7 +1349,7 @@ typedef struct {
13491349
char *func_name;
13501350
char *file_name;
13511351
int line;
1352-
jl_method_instance_t *linfo;
1352+
jl_code_instance_t *ci;
13531353
int fromC;
13541354
int inlined;
13551355
} jl_frame_t;

src/stackwalk.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ JL_DLLEXPORT jl_value_t *jl_lookup_code_address(void *ip, int skipC)
624624
jl_svecset(r, 1, jl_empty_sym);
625625
free(frame.file_name);
626626
jl_svecset(r, 2, jl_box_long(frame.line));
627-
jl_svecset(r, 3, frame.linfo != NULL ? (jl_value_t*)frame.linfo : jl_nothing);
627+
jl_svecset(r, 3, frame.ci != NULL ? (jl_value_t*)frame.ci : jl_nothing);
628628
jl_svecset(r, 4, jl_box_bool(frame.fromC));
629629
jl_svecset(r, 5, jl_box_bool(frame.inlined));
630630
}

test/opaque_closure.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -347,9 +347,12 @@ let (bt, did_gc) = make_oc_and_collect_bt()
347347
GC.gc(true); GC.gc(true); GC.gc(true);
348348
@test did_gc[]
349349
@test any(stacktrace(bt)) do frame
350-
isa(frame.linfo, Core.MethodInstance) || return false
351-
isa(frame.linfo.def, Method) || return false
352-
return frame.linfo.def.is_for_opaque_closure
350+
li = frame.linfo
351+
isa(li, Core.CodeInstance) && (li = li.def)
352+
isa(li, Core.ABIOverride) && (li = li.def)
353+
isa(li, Core.MethodInstance) || return false
354+
isa(li.def, Method) || return false
355+
return li.def.is_for_opaque_closure
353356
end
354357
end
355358

test/stacktraces.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,10 @@ can_inline = Bool(Base.JLOptions().can_inline)
9292
for (frame, func, inlined) in zip(trace, [g,h,f], (can_inline, can_inline, false))
9393
@test frame.func === typeof(func).name.mt.name
9494
# broken until #50082 can be addressed
95-
@test frame.linfo.def.module === which(func, (Any,)).module broken=inlined
96-
@test frame.linfo.def === which(func, (Any,)) broken=inlined
97-
@test frame.linfo.specTypes === Tuple{typeof(func), Int} broken=inlined
95+
mi = isa(frame.linfo, Core.CodeInstance) ? frame.linfo.def : frame.linfo
96+
@test mi.def.module === which(func, (Any,)).module broken=inlined
97+
@test mi.def === which(func, (Any,)) broken=inlined
98+
@test mi.specTypes === Tuple{typeof(func), Int} broken=inlined
9899
# line
99100
@test frame.file === Symbol(@__FILE__)
100101
@test !frame.from_c

0 commit comments

Comments
 (0)