Skip to content
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

Protect shared JIT variables from being modified unsafely #44914

Merged
merged 6 commits into from
Apr 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/src/devdocs/locks.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ The following are definitely leaf locks (level 1), and must not try to acquire a
> * flisp
> * jl_in_stackwalk (Win32)
> * ResourcePool<?>::mutex
> * RLST_mutex
> * jl_locked_stream::mutex
>
> > flisp itself is already threadsafe, this lock only protects the `jl_ast_context_list_t` pool
> > likewise, the ResourcePool<?>::mutexes just protect the associated resource pool
Expand Down
28 changes: 14 additions & 14 deletions src/aotcompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -460,11 +460,11 @@ void jl_dump_native_impl(void *native_code,
TheTriple.setOS(llvm::Triple::MacOSX);
#endif
std::unique_ptr<TargetMachine> TM(
jl_ExecutionEngine->getTargetMachine().getTarget().createTargetMachine(
jl_ExecutionEngine->getTarget().createTargetMachine(
TheTriple.getTriple(),
jl_ExecutionEngine->getTargetMachine().getTargetCPU(),
jl_ExecutionEngine->getTargetMachine().getTargetFeatureString(),
jl_ExecutionEngine->getTargetMachine().Options,
jl_ExecutionEngine->getTargetCPU(),
jl_ExecutionEngine->getTargetFeatureString(),
jl_ExecutionEngine->getTargetOptions(),
#if defined(_OS_LINUX_) || defined(_OS_FREEBSD_)
Reloc::PIC_,
#else
Expand All @@ -481,7 +481,7 @@ void jl_dump_native_impl(void *native_code,
));

legacy::PassManager PM;
addTargetPasses(&PM, TM.get());
addTargetPasses(&PM, TM->getTargetTriple(), TM->getTargetIRAnalysis());

// set up optimization passes
SmallVector<char, 0> bc_Buffer;
Expand All @@ -502,7 +502,7 @@ void jl_dump_native_impl(void *native_code,
PM.add(createBitcodeWriterPass(unopt_bc_OS));
if (bc_fname || obj_fname || asm_fname) {
addOptimizationPasses(&PM, jl_options.opt_level, true, true);
addMachinePasses(&PM, TM.get(), jl_options.opt_level);
addMachinePasses(&PM, jl_options.opt_level);
}
if (bc_fname)
PM.add(createBitcodeWriterPass(bc_OS));
Expand Down Expand Up @@ -595,14 +595,14 @@ void jl_dump_native_impl(void *native_code,
delete data;
}

void addTargetPasses(legacy::PassManagerBase *PM, TargetMachine *TM)
void addTargetPasses(legacy::PassManagerBase *PM, const Triple &triple, TargetIRAnalysis analysis)
{
PM->add(new TargetLibraryInfoWrapperPass(Triple(TM->getTargetTriple())));
PM->add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis()));
PM->add(new TargetLibraryInfoWrapperPass(triple));
PM->add(createTargetTransformInfoWrapperPass(std::move(analysis)));
}


void addMachinePasses(legacy::PassManagerBase *PM, TargetMachine *TM, int optlevel)
void addMachinePasses(legacy::PassManagerBase *PM, int optlevel)
{
// TODO: don't do this on CPUs that natively support Float16
PM->add(createDemoteFloat16Pass());
Expand Down Expand Up @@ -857,9 +857,9 @@ class JuliaPipeline : public Pass {
(void)jl_init_llvm();
PMTopLevelManager *TPM = Stack.top()->getTopLevelManager();
TPMAdapter Adapter(TPM);
addTargetPasses(&Adapter, &jl_ExecutionEngine->getTargetMachine());
addTargetPasses(&Adapter, jl_ExecutionEngine->getTargetTriple(), jl_ExecutionEngine->getTargetIRAnalysis());
addOptimizationPasses(&Adapter, OptLevel, true, dump_native, true);
addMachinePasses(&Adapter, &jl_ExecutionEngine->getTargetMachine(), OptLevel);
addMachinePasses(&Adapter, OptLevel);
}
JuliaPipeline() : Pass(PT_PassManager, ID) {}
Pass *createPrinterPass(raw_ostream &O, const std::string &Banner) const override {
Expand Down Expand Up @@ -993,9 +993,9 @@ void *jl_get_llvmf_defn_impl(jl_method_instance_t *mi, size_t world, char getwra
static legacy::PassManager *PM;
if (!PM) {
PM = new legacy::PassManager();
addTargetPasses(PM, &jl_ExecutionEngine->getTargetMachine());
addTargetPasses(PM, jl_ExecutionEngine->getTargetTriple(), jl_ExecutionEngine->getTargetIRAnalysis());
addOptimizationPasses(PM, jl_options.opt_level);
addMachinePasses(PM, &jl_ExecutionEngine->getTargetMachine(), jl_options.opt_level);
addMachinePasses(PM, jl_options.opt_level);
}

// get the source code for this function
Expand Down
12 changes: 6 additions & 6 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,10 @@ typedef Instruction TerminatorInst;
#include "processor.h"
#include "julia_assert.h"

JL_STREAM *dump_emitted_mi_name_stream = NULL;
extern "C" JL_DLLEXPORT
void jl_dump_emitted_mi_name_impl(void *s)
{
dump_emitted_mi_name_stream = (JL_STREAM*)s;
**jl_ExecutionEngine->get_dump_emitted_mi_name_stream() = (JL_STREAM*)s;
}

extern "C" {
Expand Down Expand Up @@ -7978,15 +7977,16 @@ jl_llvm_functions_t jl_emit_code(
"functions compiled with custom codegen params must not be cached");
JL_TRY {
decls = emit_function(m, li, src, jlrettype, params);
if (dump_emitted_mi_name_stream != NULL) {
jl_printf(dump_emitted_mi_name_stream, "%s\t", decls.specFunctionObject.c_str());
auto stream = *jl_ExecutionEngine->get_dump_emitted_mi_name_stream();
if (stream) {
jl_printf(stream, "%s\t", decls.specFunctionObject.c_str());
// NOTE: We print the Type Tuple without surrounding quotes, because the quotes
// break CSV parsing if there are any internal quotes in the Type name (e.g. in
// Symbol("...")). The \t delineator should be enough to ensure whitespace is
// handled correctly. (And we don't need to worry about any tabs in the printed
// string, because tabs are printed as "\t" by `show`.)
jl_static_show(dump_emitted_mi_name_stream, li->specTypes);
jl_printf(dump_emitted_mi_name_stream, "\n");
jl_static_show(stream, li->specTypes);
jl_printf(stream, "\n");
}
}
JL_CATCH {
Expand Down
5 changes: 3 additions & 2 deletions src/disasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1208,9 +1208,10 @@ jl_value_t *jl_dump_function_asm_impl(void *F, char raw_mc, const char* asm_vari
f2.deleteBody();
}
});
LLVMTargetMachine *TM = static_cast<LLVMTargetMachine*>(&jl_ExecutionEngine->getTargetMachine());
auto TMBase = jl_ExecutionEngine->cloneTargetMachine();
LLVMTargetMachine *TM = static_cast<LLVMTargetMachine*>(TMBase.get());
legacy::PassManager PM;
addTargetPasses(&PM, TM);
addTargetPasses(&PM, TM->getTargetTriple(), TM->getTargetIRAnalysis());
if (raw_mc) {
raw_svector_ostream obj_OS(ObjBufferSV);
if (TM->addPassesToEmitFile(PM, obj_OS, nullptr, CGFT_ObjectFile, false, nullptr))
Expand Down
143 changes: 84 additions & 59 deletions src/jitlayers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,15 @@ using namespace llvm;
#define DEBUG_TYPE "jitlayers"

// Snooping on which functions are being compiled, and how long it takes
JL_STREAM *dump_compiles_stream = NULL;
extern "C" JL_DLLEXPORT
void jl_dump_compiles_impl(void *s)
{
dump_compiles_stream = (JL_STREAM*)s;
**jl_ExecutionEngine->get_dump_compiles_stream() = (JL_STREAM*)s;
}
JL_STREAM *dump_llvm_opt_stream = NULL;
extern "C" JL_DLLEXPORT
void jl_dump_llvm_opt_impl(void *s)
{
dump_llvm_opt_stream = (JL_STREAM*)s;
**jl_ExecutionEngine->get_dump_llvm_opt_stream() = (JL_STREAM*)s;
}

static void jl_add_to_ee(orc::ThreadSafeModule &M, StringMap<orc::ThreadSafeModule*> &NewExports);
Expand Down Expand Up @@ -108,7 +106,8 @@ static jl_callptr_t _jl_compile_codeinst(
// caller must hold codegen_lock
// and have disabled finalizers
uint64_t start_time = 0;
if (dump_compiles_stream != NULL)
bool timed = !!*jl_ExecutionEngine->get_dump_compiles_stream();
if (timed)
start_time = jl_hrtime();

assert(jl_is_code_instance(codeinst));
Expand Down Expand Up @@ -198,17 +197,18 @@ static jl_callptr_t _jl_compile_codeinst(
}

uint64_t end_time = 0;
if (dump_compiles_stream != NULL)
if (timed)
end_time = jl_hrtime();

// If logging of the compilation stream is enabled,
// then dump the method-instance specialization type to the stream
jl_method_instance_t *mi = codeinst->def;
if (jl_is_method(mi->def.method)) {
if (dump_compiles_stream != NULL) {
jl_printf(dump_compiles_stream, "%" PRIu64 "\t\"", end_time - start_time);
jl_static_show(dump_compiles_stream, mi->specTypes);
jl_printf(dump_compiles_stream, "\"\n");
auto stream = *jl_ExecutionEngine->get_dump_compiles_stream();
if (stream) {
jl_printf(stream, "%" PRIu64 "\t\"", end_time - start_time);
jl_static_show(stream, mi->specTypes);
jl_printf(stream, "\"\n");
}
}
return fptr;
Expand Down Expand Up @@ -480,13 +480,6 @@ CodeGenOpt::Level CodeGenOptLevelFor(int optlevel)
#endif
}

static void addPassesForOptLevel(legacy::PassManager &PM, TargetMachine &TM, int optlevel)
{
addTargetPasses(&PM, &TM);
addOptimizationPasses(&PM, optlevel);
addMachinePasses(&PM, &TM, optlevel);
}

static auto countBasicBlocks(const Function &F)
{
return std::distance(F.begin(), F.end());
Expand Down Expand Up @@ -899,7 +892,9 @@ namespace {
}
std::unique_ptr<legacy::PassManager> operator()() {
auto PM = std::make_unique<legacy::PassManager>();
addPassesForOptLevel(*PM, *TM, optlevel);
addTargetPasses(PM.get(), TM->getTargetTriple(), TM->getTargetIRAnalysis());
addOptimizationPasses(PM.get(), optlevel);
addMachinePasses(PM.get(), optlevel);
return PM;
}
};
Expand All @@ -910,24 +905,27 @@ namespace {
OptimizerResultT operator()(orc::ThreadSafeModule TSM, orc::MaterializationResponsibility &R) {
TSM.withModuleDo([&](Module &M) {
uint64_t start_time = 0;
if (dump_llvm_opt_stream != NULL) {
// Print LLVM function statistics _before_ optimization
// Print all the information about this invocation as a YAML object
jl_printf(dump_llvm_opt_stream, "- \n");
// We print the name and some statistics for each function in the module, both
// before optimization and again afterwards.
jl_printf(dump_llvm_opt_stream, " before: \n");
for (auto &F : M.functions()) {
if (F.isDeclaration() || F.getName().startswith("jfptr_")) {
continue;
{
auto stream = *jl_ExecutionEngine->get_dump_llvm_opt_stream();
if (stream) {
// Print LLVM function statistics _before_ optimization
// Print all the information about this invocation as a YAML object
jl_printf(stream, "- \n");
// We print the name and some statistics for each function in the module, both
// before optimization and again afterwards.
jl_printf(stream, " before: \n");
for (auto &F : M.functions()) {
if (F.isDeclaration() || F.getName().startswith("jfptr_")) {
continue;
}
// Each function is printed as a YAML object with several attributes
jl_printf(stream, " \"%s\":\n", F.getName().str().c_str());
jl_printf(stream, " instructions: %u\n", F.getInstructionCount());
jl_printf(stream, " basicblocks: %lu\n", countBasicBlocks(F));
}
// Each function is printed as a YAML object with several attributes
jl_printf(dump_llvm_opt_stream, " \"%s\":\n", F.getName().str().c_str());
jl_printf(dump_llvm_opt_stream, " instructions: %u\n", F.getInstructionCount());
jl_printf(dump_llvm_opt_stream, " basicblocks: %lu\n", countBasicBlocks(F));
}

start_time = jl_hrtime();
start_time = jl_hrtime();
}
}

JL_TIMING(LLVM_OPT);
Expand All @@ -936,20 +934,23 @@ namespace {
(***PMs).run(M);

uint64_t end_time = 0;
if (dump_llvm_opt_stream != NULL) {
end_time = jl_hrtime();
jl_printf(dump_llvm_opt_stream, " time_ns: %" PRIu64 "\n", end_time - start_time);
jl_printf(dump_llvm_opt_stream, " optlevel: %d\n", optlevel);

// Print LLVM function statistics _after_ optimization
jl_printf(dump_llvm_opt_stream, " after: \n");
for (auto &F : M.functions()) {
if (F.isDeclaration() || F.getName().startswith("jfptr_")) {
continue;
{
auto stream = *jl_ExecutionEngine->get_dump_llvm_opt_stream();
if (stream) {
end_time = jl_hrtime();
jl_printf(stream, " time_ns: %" PRIu64 "\n", end_time - start_time);
jl_printf(stream, " optlevel: %d\n", optlevel);

// Print LLVM function statistics _after_ optimization
jl_printf(stream, " after: \n");
for (auto &F : M.functions()) {
if (F.isDeclaration() || F.getName().startswith("jfptr_")) {
continue;
}
jl_printf(stream, " \"%s\":\n", F.getName().str().c_str());
jl_printf(stream, " instructions: %u\n", F.getInstructionCount());
jl_printf(stream, " basicblocks: %lu\n", countBasicBlocks(F));
}
jl_printf(dump_llvm_opt_stream, " \"%s\":\n", F.getName().str().c_str());
jl_printf(dump_llvm_opt_stream, " instructions: %u\n", F.getInstructionCount());
jl_printf(dump_llvm_opt_stream, " basicblocks: %lu\n", countBasicBlocks(F));
}
}
});
Expand Down Expand Up @@ -1166,7 +1167,7 @@ uint64_t JuliaOJIT::getFunctionAddress(StringRef Name)

StringRef JuliaOJIT::getFunctionAtAddress(uint64_t Addr, jl_code_instance_t *codeinst)
{
static int globalUnique = 0;
std::lock_guard<std::mutex> lock(RLST_mutex);
std::string *fname = &ReverseLocalSymbolTable[(void*)(uintptr_t)Addr];
if (fname->empty()) {
std::string string_fname;
Expand All @@ -1186,7 +1187,7 @@ StringRef JuliaOJIT::getFunctionAtAddress(uint64_t Addr, jl_code_instance_t *cod
stream_fname << "jlsys_";
}
const char* unadorned_name = jl_symbol_name(codeinst->def->def.method->name);
stream_fname << unadorned_name << "_" << globalUnique++;
stream_fname << unadorned_name << "_" << RLST_inc++;
*fname = std::move(stream_fname.str()); // store to ReverseLocalSymbolTable
addGlobalMapping(*fname, Addr);
}
Expand Down Expand Up @@ -1232,16 +1233,6 @@ const DataLayout& JuliaOJIT::getDataLayout() const
return DL;
}

TargetMachine &JuliaOJIT::getTargetMachine()
{
return *TM;
}

const Triple& JuliaOJIT::getTargetTriple() const
{
return TM->getTargetTriple();
}

std::string JuliaOJIT::getMangledName(StringRef Name)
{
SmallString<128> FullName;
Expand Down Expand Up @@ -1412,6 +1403,40 @@ void JuliaOJIT::shareStrings(Module &M)
GV->eraseFromParent();
}

//TargetMachine pass-through methods

std::unique_ptr<TargetMachine> JuliaOJIT::cloneTargetMachine() const
{
return std::unique_ptr<TargetMachine>(getTarget()
.createTargetMachine(
getTargetTriple().str(),
getTargetCPU(),
getTargetFeatureString(),
getTargetOptions(),
TM->getRelocationModel(),
TM->getCodeModel(),
TM->getOptLevel()));
}

const Triple& JuliaOJIT::getTargetTriple() const {
return TM->getTargetTriple();
}
StringRef JuliaOJIT::getTargetFeatureString() const {
return TM->getTargetFeatureString();
}
StringRef JuliaOJIT::getTargetCPU() const {
return TM->getTargetCPU();
}
const TargetOptions &JuliaOJIT::getTargetOptions() const {
return TM->Options;
}
const Target &JuliaOJIT::getTarget() const {
return TM->getTarget();
}
TargetIRAnalysis JuliaOJIT::getTargetIRAnalysis() const {
return TM->getTargetIRAnalysis();
}

static void jl_decorate_module(Module &M) {
#if defined(_CPU_X86_64_) && defined(_OS_WINDOWS_)
// Add special values used by debuginfo to build the UnwindData table registration for Win64
Expand Down
Loading