-
-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hide safepoint prologue and CFI instructions from reflection. #49948
Conversation
Yes having a |
+1 for having raw=true add the safepoints back, it's quite useful for getting the modules out of julia to play with in godbolt/opt |
Looks like
I'll hook it up to that for now, but maybe we should rename the option? EDIT: ah, that won't work. Well, it will work for |
@vtjnash Would it be possible to re-use our own disassembler, |
5ace6e8
to
cf6c298
Compare
Adding
Still some verbose module output, but AsmPrinter doesn't seem customizable enough to hide those. |
str = _dump_function_linfo_native(linfo, world, wrapper, syntax, debuginfo, binary, params) | ||
else | ||
# if we don't want the module metadata, just disassemble what our JIT has. | ||
# TODO: make it possible to hide the safepoint prologue here too. | ||
# once that works, it would be good to default to dump_module=false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dump_module=false
will always give sometimes wrong or misleading answers and lacks configuration, so it typically is a bad default. (Also, TODO items should be issues, not code comments.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dump_module=false
will always give sometimes wrong or misleading answers
Why is that? I was actually looking into using that disassembly path for code we get from jl_get_llvmf_defn
, i.e., to allow configuration. The output is slightly nicer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disassembly is an art, not a science. It is right most of the time, but often makes mistakes because doing it right is can actually be harder than turing-complete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I just hadn't run into actual issues. But you're right that it's probably better not to default to the disassembler.
Do you think it would be useful to upstream my changes that make it possible to disassemble arbitrary objects (i.e. not only fptr
s we look up through the JIT), so that its possible to use the disassembler with non-default codegen options? May also be useful for external compilers, to be able to disassemble externally-produced objects while using the Julia assembly annotator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see which changes you mean here, but yes, in general it is reasonable to want to ask for disassembly of some bytes in an arbitrary range, as long as we can detect the unwind info exists for it (via asking debuginfo.cpp if it knows about the code)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't committed it, but was working on it until you said the disassembler path is not what we want to use. Something like:
extern "C" JL_DLLEXPORT_CODEGEN
jl_value_t *jl_dump_bin_asm_impl(void* bin, size_t len, const char* asm_variant, const char *debuginfo, char binary)
{
std::string code;
raw_string_ostream stream(code);
// read the object file
auto buf = llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(static_cast<const char*>(bin), len));
auto objectFileOrError = llvm::object::ObjectFile::createObjectFile(buf->getMemBufferRef());
if (!objectFileOrError) {
jl_printf(JL_STDERR, "WARNING: failed to load object file: %s\n", llvm::toString(objectFileOrError.takeError()).c_str());
return jl_an_empty_string;
}
auto objectFile = objectFileOrError.get().get();
auto context = DWARFContext::create(*objectFile).release();
// find the first text section
object::SectionRef TextSection;
uint64_t TextAddr = -1;
for (auto &Section : objectFile->sections()) {
if (!Section.isText())
continue;
uint64_t Addr = Section.getAddress();
if (Addr < TextAddr) {
TextAddr = Addr;
TextSection = Section;
}
}
if (TextAddr == -1) {
jl_printf(JL_STDERR, "WARNING: no text section found\n");
return jl_an_empty_string;
}
// determine the location in memory of the code
auto sectionContents = TextSection.getContents();
uintptr_t code_ptr = reinterpret_cast<std::uintptr_t>(sectionContents->data());
size_t code_size = sectionContents->size();
// determine the offset between the code in memory and the code in the object file
int64_t slide = 0;
if (auto *OF = dyn_cast<const object::COFFObjectFile>(objectFile)) {
slide = OF->getImageBase() - (int64_t)code_ptr;
}
else {
slide = -(int64_t)code_ptr;
}
// Dump assembly code
jl_ptls_t ptls = jl_current_task->ptls;
int8_t gc_state = jl_gc_safe_enter(ptls);
jl_dump_asm_internal(
code_ptr, code_size, slide,
TextSection, context,
stream,
asm_variant,
debuginfo,
binary);
jl_gc_safe_leave(ptls, gc_state);
return jl_pchar_to_string(stream.str().data(), stream.str().size());
}
To be cleaned-up, etc. If useful, we could add this under a code_name(; disassemble=true)
flag or something.
474b394
to
64e43ce
Compare
64e43ce
to
68ea43f
Compare
Fixes #49918 (comment)
Before:
After:
Same for native code:
For
code_llvm
we could hook up the toggle toraw
, i.e., do still show the safepoint code when settingraw=true
(although I'm not sure how useful that would be).code_native
doesn't have araw
kwarg though...