Skip to content

Commit 546bfa3

Browse files
authored
Merge pull request #19290 from JuliaLang/tb/codegen_hooks
CodegenHooks for external language implementations
2 parents 484e919 + 0607ae0 commit 546bfa3

File tree

5 files changed

+124
-27
lines changed

5 files changed

+124
-27
lines changed

base/reflection.jl

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,18 @@ function uncompressed_ast(m::Method, s::CodeInfo)
501501
return s
502502
end
503503

504+
# this type mirrors jl_cghooks_t (documented in julia.h)
505+
immutable CodegenHooks
506+
module_setup::Ptr{Void}
507+
module_activation::Ptr{Void}
508+
raise_exception::Ptr{Void}
509+
510+
CodegenHooks(;module_setup=nothing, module_activation=nothing, raise_exception=nothing) =
511+
new(pointer_from_objref(module_setup),
512+
pointer_from_objref(module_activation),
513+
pointer_from_objref(raise_exception))
514+
end
515+
504516
# this type mirrors jl_cgparams_t (documented in julia.h)
505517
immutable CodegenParams
506518
cached::Cint
@@ -512,14 +524,18 @@ immutable CodegenParams
512524
static_alloc::Cint
513525
dynamic_alloc::Cint
514526

527+
hooks::CodegenHooks
528+
515529
CodegenParams(;cached::Bool=true,
516530
runtime::Bool=true, exceptions::Bool=true,
517531
track_allocations::Bool=true, code_coverage::Bool=true,
518-
static_alloc::Bool=true, dynamic_alloc::Bool=true) =
532+
static_alloc::Bool=true, dynamic_alloc::Bool=true,
533+
hooks::CodegenHooks=CodegenHooks()) =
519534
new(Cint(cached),
520535
Cint(runtime), Cint(exceptions),
521536
Cint(track_allocations), Cint(code_coverage),
522-
Cint(static_alloc), Cint(dynamic_alloc))
537+
Cint(static_alloc), Cint(dynamic_alloc),
538+
hooks)
523539
end
524540

525541
# Printing code representations in IR and assembly

src/cgutils.cpp

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,24 @@ static Value *prepare_call(Value *Callee)
3838
__FUNCTION__, (ctx)->file.str().c_str(), *(ctx)->line);
3939

4040

41+
// --- hook checks ---
42+
43+
#define JL_HOOK_TEST(params,hook) ((params)->hooks.hook != jl_nothing)
44+
45+
#define JL_HOOK_CALL(params,hook,argc,...) \
46+
_hook_call<argc>((params)->hooks.hook, {{__VA_ARGS__}});
47+
template<int N>
48+
static inline void _hook_call(jl_value_t *hook, std::array<jl_value_t*,N> args) {
49+
jl_value_t **argv;
50+
JL_GC_PUSHARGS(argv, N+1);
51+
argv[0] = hook;
52+
for (int i = 0; i < N; i++)
53+
argv[i+1] = args[i];
54+
jl_apply(argv, N+1);
55+
JL_GC_POP();
56+
}
57+
58+
4159
// --- string constants ---
4260
static StringMap<GlobalVariable*> stringConstants;
4361
static Value *stringConstPtr(IRBuilder<> &builder, const std::string &txt)
@@ -673,12 +691,18 @@ static void error_unless(Value *cond, const std::string &msg, jl_codectx_t *ctx)
673691
static void raise_exception(Value *exc, jl_codectx_t *ctx,
674692
BasicBlock *contBB=nullptr)
675693
{
676-
JL_FEAT_REQUIRE(ctx, runtime);
694+
if (JL_HOOK_TEST(ctx->params, raise_exception)) {
695+
JL_HOOK_CALL(ctx->params, raise_exception, 2,
696+
jl_box_voidpointer(wrap(builder.GetInsertBlock())),
697+
jl_box_voidpointer(wrap(exc)));
698+
} else {
699+
JL_FEAT_REQUIRE(ctx, runtime);
677700
#if JL_LLVM_VERSION >= 30700
678-
builder.CreateCall(prepare_call(jlthrow_func), { exc });
701+
builder.CreateCall(prepare_call(jlthrow_func), { exc });
679702
#else
680-
builder.CreateCall(prepare_call(jlthrow_func), exc);
703+
builder.CreateCall(prepare_call(jlthrow_func), exc);
681704
#endif
705+
}
682706
builder.CreateUnreachable();
683707
if (!contBB) {
684708
contBB = BasicBlock::Create(jl_LLVMContext, "after_throw", ctx->f);
@@ -1849,3 +1873,19 @@ static Value *emit_defer_signal(jl_codectx_t *ctx)
18491873
offsetof(jl_tls_states_t, defer_signal) / sizeof(sig_atomic_t));
18501874
return builder.CreateGEP(ptls, ArrayRef<Value*>(offset), "jl_defer_signal");
18511875
}
1876+
1877+
static int compare_cgparams(const jl_cgparams_t *a, const jl_cgparams_t *b)
1878+
{
1879+
return (a->cached == b->cached) &&
1880+
// language features
1881+
(a->runtime == b->runtime) &&
1882+
(a->exceptions == b->exceptions) &&
1883+
(a->track_allocations == b->track_allocations) &&
1884+
(a->code_coverage == b->code_coverage) &&
1885+
(a->static_alloc == b->static_alloc) &&
1886+
(a->dynamic_alloc == b->dynamic_alloc) &&
1887+
// hooks
1888+
(a->hooks.module_setup == b->hooks.module_setup) &&
1889+
(a->hooks.module_activation == b->hooks.module_activation) &&
1890+
(a->hooks.raise_exception == b->hooks.raise_exception);
1891+
}

src/codegen.cpp

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <sstream>
2828
#include <fstream>
2929
#include <map>
30+
#include <array>
3031
#include <vector>
3132
#include <set>
3233
#include <cstdio>
@@ -843,6 +844,11 @@ jl_llvm_functions_t jl_compile_linfo(jl_method_instance_t **pli, jl_code_info_t
843844
jl_method_instance_t *li = *pli;
844845
assert(jl_is_method_instance(li));
845846
jl_llvm_functions_t decls = {};
847+
848+
if (params != &jl_default_cgparams /* fast path */ &&
849+
!compare_cgparams(params, &jl_default_cgparams) && params->cached)
850+
jl_error("functions compiled with custom codegen params mustn't be cached");
851+
846852
// Step 1. See if it is already compiled,
847853
// Get the codegen lock,
848854
// And get the source
@@ -946,25 +952,30 @@ jl_llvm_functions_t jl_compile_linfo(jl_method_instance_t **pli, jl_code_info_t
946952
Function *f = (Function*)decls.functionObject;
947953
Function *specf = (Function*)decls.specFunctionObject;
948954

949-
// Step 4. Prepare debug info to receive this function
950-
// record that this function name came from this linfo,
951-
// so we can build a reverse mapping for debug-info.
952-
bool toplevel = li->def == NULL;
953-
if (!toplevel) {
954-
const DataLayout &DL =
955-
#if JL_LLVM_VERSION >= 30500
956-
m->getDataLayout();
957-
#else
958-
*jl_data_layout;
959-
#endif
960-
// but don't remember toplevel thunks because
961-
// they may not be rooted in the gc for the life of the program,
962-
// and the runtime doesn't notify us when the code becomes unreachable :(
963-
jl_add_linfo_in_flight((specf ? specf : f)->getName(), li, DL);
964-
}
965955

966-
// Step 5. Add the result to the execution engine now
967-
jl_finalize_module(m.release(), !toplevel);
956+
if (JL_HOOK_TEST(params, module_activation)) {
957+
JL_HOOK_CALL(params, module_activation, 1, jl_box_voidpointer(wrap(m.release())));
958+
} else {
959+
// Step 4. Prepare debug info to receive this function
960+
// record that this function name came from this linfo,
961+
// so we can build a reverse mapping for debug-info.
962+
bool toplevel = li->def == NULL;
963+
if (!toplevel) {
964+
const DataLayout &DL =
965+
#if JL_LLVM_VERSION >= 30500
966+
m->getDataLayout();
967+
#else
968+
*jl_data_layout;
969+
#endif
970+
// but don't remember toplevel thunks because
971+
// they may not be rooted in the gc for the life of the program,
972+
// and the runtime doesn't notify us when the code becomes unreachable :(
973+
jl_add_linfo_in_flight((specf ? specf : f)->getName(), li, DL);
974+
}
975+
976+
// Step 5. Add the result to the execution engine now
977+
jl_finalize_module(m.release(), !toplevel);
978+
}
968979

969980
if (world && li->jlcall_api != 2) {
970981
// if not inlineable, code won't be needed again
@@ -1009,8 +1020,13 @@ static Value *getModuleFlag(Module *m, StringRef Key)
10091020
#define getModuleFlag(m,str) m->getModuleFlag(str)
10101021
#endif
10111022

1012-
static void jl_setup_module(Module *m)
1023+
static void jl_setup_module(Module *m, const jl_cgparams_t *params = &jl_default_cgparams)
10131024
{
1025+
if (JL_HOOK_TEST(params, module_setup)) {
1026+
JL_HOOK_CALL(params, module_setup, 1, jl_box_voidpointer(wrap(m)));
1027+
return;
1028+
}
1029+
10141030
// Some linkers (*cough* OS X) don't understand DWARF v4, so we use v2 in
10151031
// imaging mode. The structure of v4 is slightly nicer for debugging JIT
10161032
// code.
@@ -4286,7 +4302,7 @@ static std::unique_ptr<Module> emit_function(
42864302

42874303
ctx.sret = false;
42884304
Module *M = new Module(ctx.name, jl_LLVMContext);
4289-
jl_setup_module(M);
4305+
jl_setup_module(M, params);
42904306
if (specsig) { // assumes !va and !needsparams
42914307
std::vector<Type*> fsig(0);
42924308
Type *rt;

src/jltypes.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ JL_DLLEXPORT jl_value_t *jl_emptytuple=NULL;
6868
jl_svec_t *jl_emptysvec;
6969
jl_value_t *jl_nothing;
7070

71-
const jl_cgparams_t jl_default_cgparams = {1, 1, 1, 1, 1, 1, 1};
71+
jl_cgparams_t jl_default_cgparams = {1, 1, 1, 1, 1, 1, 1, {NULL, NULL, NULL}};
7272

7373
// --- type properties and predicates ---
7474

@@ -3523,6 +3523,10 @@ void jl_init_types(void)
35233523
jl_methtable_type = jl_new_uninitialized_datatype();
35243524
jl_nothing = jl_gc_alloc(ptls, 0, NULL);
35253525

3526+
jl_default_cgparams.hooks.module_setup = jl_nothing;
3527+
jl_default_cgparams.hooks.module_activation = jl_nothing;
3528+
jl_default_cgparams.hooks.raise_exception = jl_nothing;
3529+
35263530
jl_emptysvec = (jl_svec_t*)jl_gc_alloc(ptls, sizeof(void*),
35273531
jl_simplevector_type);
35283532
jl_svec_set_len_unsafe(jl_emptysvec, 0);

src/julia.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,25 @@ typedef struct {
17701770

17711771
// codegen interface ----------------------------------------------------------
17721772

1773+
typedef struct {
1774+
// to disable a hook: set to NULL or nothing
1775+
1776+
// module setup: prepare a module for code emission (data layout, DWARF version, ...)
1777+
// parameters: LLVMModuleRef as Ptr{Void}
1778+
// return value: none
1779+
jl_value_t *module_setup;
1780+
1781+
// module activation: registers debug info, adds module to JIT
1782+
// parameters: LLVMModuleRef as Ptr{Void}
1783+
// return value: none
1784+
jl_value_t *module_activation;
1785+
1786+
// exception raising: emit LLVM instructions to raise an exception
1787+
// parameters: LLVMBasicBlockRef as Ptr{Void}, LLVMValueRef as Ptr{Void}
1788+
// return value: none
1789+
jl_value_t *raise_exception;
1790+
} jl_cghooks_t;
1791+
17731792
typedef struct {
17741793
int cached; // can the compiler use/populate the compilation cache?
17751794

@@ -1780,8 +1799,10 @@ typedef struct {
17801799
int code_coverage; // can we measure coverage (don't if disallowed)?
17811800
int static_alloc; // is the compiler allowed to allocate statically?
17821801
int dynamic_alloc; // is the compiler allowed to allocate dynamically (requires runtime)?
1802+
1803+
jl_cghooks_t hooks;
17831804
} jl_cgparams_t;
1784-
extern JL_DLLEXPORT const jl_cgparams_t jl_default_cgparams;
1805+
extern JL_DLLEXPORT jl_cgparams_t jl_default_cgparams;
17851806

17861807
#ifdef __cplusplus
17871808
}

0 commit comments

Comments
 (0)