Skip to content

Commit 228aa19

Browse files
committed
Add codegen hooks to override code generation behavior.
1 parent c263a6e commit 228aa19

File tree

5 files changed

+96
-26
lines changed

5 files changed

+96
-26
lines changed

base/reflection.jl

+18-2
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,18 @@ function uncompressed_ast(m::Method, s::CodeInfo)
493493
return s
494494
end
495495

496+
# this type mirrors jl_cghooks_t (documented in julia.h)
497+
immutable CodegenHooks
498+
module_setup::Ptr{Void}
499+
module_activation::Ptr{Void}
500+
raise_exception::Ptr{Void}
501+
502+
CodegenHooks(;module_setup=nothing, module_activation=nothing, raise_exception=nothing) =
503+
new(pointer_from_objref(module_setup),
504+
pointer_from_objref(module_activation),
505+
pointer_from_objref(raise_exception))
506+
end
507+
496508
# this type mirrors jl_cgparams_t (documented in julia.h)
497509
immutable CodegenParams
498510
cached::Cint
@@ -504,14 +516,18 @@ immutable CodegenParams
504516
static_alloc::Cint
505517
dynamic_alloc::Cint
506518

519+
hooks::CodegenHooks
520+
507521
CodegenParams(;cached::Bool=true,
508522
runtime::Bool=true, exceptions::Bool=true,
509523
track_allocations::Bool=true, code_coverage::Bool=true,
510-
static_alloc::Bool=true, dynamic_alloc::Bool=true) =
524+
static_alloc::Bool=true, dynamic_alloc::Bool=true,
525+
hooks::CodegenHooks=CodegenHooks()) =
511526
new(Cint(cached),
512527
Cint(runtime), Cint(exceptions),
513528
Cint(track_allocations), Cint(code_coverage),
514-
Cint(static_alloc), Cint(dynamic_alloc))
529+
Cint(static_alloc), Cint(dynamic_alloc),
530+
hooks)
515531
end
516532

517533
# Printing code representations in IR and assembly

src/cgutils.cpp

+27-3
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)
@@ -672,12 +690,18 @@ static void error_unless(Value *cond, const std::string &msg, jl_codectx_t *ctx)
672690
static void raise_exception(Value *exc, jl_codectx_t *ctx,
673691
BasicBlock *contBB=nullptr)
674692
{
675-
JL_FEAT_REQUIRE(ctx, runtime);
693+
if (JL_HOOK_TEST(ctx->params, raise_exception)) {
694+
JL_HOOK_CALL(ctx->params, raise_exception, 2,
695+
jl_box_voidpointer(wrap(builder.GetInsertBlock())),
696+
jl_box_voidpointer(wrap(exc)));
697+
} else {
698+
JL_FEAT_REQUIRE(ctx, runtime);
676699
#if JL_LLVM_VERSION >= 30700
677-
builder.CreateCall(prepare_call(jlthrow_func), { exc });
700+
builder.CreateCall(prepare_call(jlthrow_func), { exc });
678701
#else
679-
builder.CreateCall(prepare_call(jlthrow_func), exc);
702+
builder.CreateCall(prepare_call(jlthrow_func), exc);
680703
#endif
704+
}
681705
builder.CreateUnreachable();
682706
if (!contBB) {
683707
contBB = BasicBlock::Create(jl_LLVMContext, "after_throw", ctx->f);

src/codegen.cpp

+31-20
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>
@@ -923,25 +924,30 @@ jl_llvm_functions_t jl_compile_linfo(jl_method_instance_t *li, jl_code_info_t *s
923924
f = (Function*)decls.functionObject;
924925
specf = (Function*)decls.specFunctionObject;
925926

926-
// Step 4. Prepare debug info to receive this function
927-
// record that this function name came from this linfo,
928-
// so we can build a reverse mapping for debug-info.
929-
bool toplevel = li->def == NULL;
930-
if (!toplevel) {
931-
const DataLayout &DL =
932-
#if JL_LLVM_VERSION >= 30500
933-
m->getDataLayout();
934-
#else
935-
*jl_data_layout;
936-
#endif
937-
// but don't remember toplevel thunks because
938-
// they may not be rooted in the gc for the life of the program,
939-
// and the runtime doesn't notify us when the code becomes unreachable :(
940-
jl_add_linfo_in_flight((specf ? specf : f)->getName(), li, DL);
941-
}
942927

943-
// Step 5. Add the result to the execution engine now
944-
jl_finalize_module(m.release(), !toplevel);
928+
if (JL_HOOK_TEST(params, module_activation)) {
929+
JL_HOOK_CALL(params, module_activation, 1, jl_box_voidpointer(wrap(m.release())));
930+
} else {
931+
// Step 4. Prepare debug info to receive this function
932+
// record that this function name came from this linfo,
933+
// so we can build a reverse mapping for debug-info.
934+
bool toplevel = li->def == NULL;
935+
if (!toplevel) {
936+
const DataLayout &DL =
937+
#if JL_LLVM_VERSION >= 30500
938+
m->getDataLayout();
939+
#else
940+
*jl_data_layout;
941+
#endif
942+
// but don't remember toplevel thunks because
943+
// they may not be rooted in the gc for the life of the program,
944+
// and the runtime doesn't notify us when the code becomes unreachable :(
945+
jl_add_linfo_in_flight((specf ? specf : f)->getName(), li, DL);
946+
}
947+
948+
// Step 5. Add the result to the execution engine now
949+
jl_finalize_module(m.release(), !toplevel);
950+
}
945951

946952
if (li->jlcall_api != 2) {
947953
// if not inlineable, code won't be needed again
@@ -988,8 +994,13 @@ static Value *getModuleFlag(Module *m, StringRef Key)
988994
#define getModuleFlag(m,str) m->getModuleFlag(str)
989995
#endif
990996

991-
static void jl_setup_module(Module *m)
997+
static void jl_setup_module(Module *m, jl_cgparams_t *params = &jl_default_cgparams)
992998
{
999+
if (JL_HOOK_TEST(params, module_setup)) {
1000+
JL_HOOK_CALL(params, module_setup, 1, jl_box_voidpointer(wrap(m)));
1001+
return;
1002+
}
1003+
9931004
// Some linkers (*cough* OS X) don't understand DWARF v4, so we use v2 in
9941005
// imaging mode. The structure of v4 is slightly nicer for debugging JIT
9951006
// code.
@@ -4207,7 +4218,7 @@ static std::unique_ptr<Module> emit_function(jl_method_instance_t *lam, jl_code_
42074218

42084219
ctx.sret = false;
42094220
Module *M = new Module(ctx.name, jl_LLVMContext);
4210-
jl_setup_module(M);
4221+
jl_setup_module(M, params);
42114222
if (specsig) { // assumes !va and !needsparams
42124223
std::vector<Type*> fsig(0);
42134224
Type *rt;

src/jltypes.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ JL_DLLEXPORT jl_value_t *jl_emptytuple=NULL;
6868
jl_svec_t *jl_emptysvec;
6969
jl_value_t *jl_nothing;
7070

71+
jl_cghooks_t jl_no_cghooks;
7172
jl_cgparams_t jl_default_cgparams;
7273

7374
// --- type properties and predicates ---
@@ -3533,7 +3534,8 @@ void jl_init_types(void)
35333534
jl_type_type_mt = jl_new_method_table(jl_type_type->name->name, ptls->current_module);
35343535
jl_type_type->name->mt = jl_type_type_mt;
35353536

3536-
jl_default_cgparams = (jl_cgparams_t){1, 1, 1, 1, 1, 1, 1};
3537+
jl_no_cghooks = (jl_cghooks_t){jl_nothing, jl_nothing, jl_nothing};
3538+
jl_default_cgparams = (jl_cgparams_t){1, 1, 1, 1, 1, 1, 1, jl_no_cghooks};
35373539

35383540
// initialize them. lots of cycles.
35393541
jl_datatype_type->name = jl_new_typename(jl_symbol("DataType"));

src/julia.h

+17
Original file line numberDiff line numberDiff line change
@@ -1757,6 +1757,21 @@ typedef struct {
17571757

17581758
// codegen interface ----------------------------------------------------------
17591759

1760+
typedef struct {
1761+
// module setup: prepare a module for code emission (data layout, DWARF version, ...)
1762+
// parameters: LLVMModuleRef as Ptr{Void}
1763+
// return value: none
1764+
jl_value_t *module_setup;
1765+
1766+
// module activation: registers debug info, adds module to JIT
1767+
// parameters: LLVMModuleRef as Ptr{Void}
1768+
// return value: none
1769+
jl_value_t *module_activation;
1770+
1771+
jl_value_t *raise_exception;
1772+
} jl_cghooks_t;
1773+
extern JL_DLLEXPORT jl_cghooks_t jl_no_cghooks;
1774+
17601775
typedef struct {
17611776
int cached; // can the compiler use/populate the compilation cache?
17621777

@@ -1767,6 +1782,8 @@ typedef struct {
17671782
int code_coverage; // can we measure coverage (don't if disallowed)?
17681783
int static_alloc; // is the compiler allowed to allocate statically?
17691784
int dynamic_alloc; // is the compiler allowed to allocate dynamically (requires runtime)?
1785+
1786+
jl_cghooks_t hooks;
17701787
} jl_cgparams_t;
17711788
extern JL_DLLEXPORT jl_cgparams_t jl_default_cgparams;
17721789

0 commit comments

Comments
 (0)