Skip to content

Commit

Permalink
WIP code to generically compile all definitions statically.
Browse files Browse the repository at this point in the history
in "no jit" mode the method cache uses linfo->unspecialized for all needed
entries. static parameters are provided via a closure environment.

codegen changes to move some errors to run time to tolerate weaker
type information.
  • Loading branch information
JeffBezanson authored and Keno committed Aug 20, 2014
1 parent f42cea3 commit 114e4dc
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 23 deletions.
2 changes: 2 additions & 0 deletions base/precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ precompile(REPLCompletions.shell_completions, (ASCIIString, Int))
precompile(REPLCompletions.complete_symbol, (ASCIIString, Function))
precompile(REPLCompletions.complete_path, (ASCIIString,))
precompile(REPLCompletions.complete_methods, (ASCIIString,))
precompile(REPL.REPLDisplay, (REPL.LineEditREPL,))
precompile(REPL.REPLDisplay, (REPL.BasicREPL,))
precompile(LineEdit.setup_search_keymap, (REPL.REPLHistoryProvider,))
precompile(LineEdit.run_interface, (Terminals.TTYTerminal, LineEdit.ModalInterface))
precompile(LineEdit.prompt!, (Terminals.TTYTerminal, LineEdit.ModalInterface, LineEdit.MIState))
Expand Down
15 changes: 10 additions & 5 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -757,10 +757,8 @@ extern int jl_in_inference;
extern int jl_boot_file_loaded;
int jl_eval_with_compiler_p(jl_expr_t *expr, int compileloops);

JL_CALLABLE(jl_trampoline)
void jl_trampoline_compile_function(jl_function_t *f, int always_infer, jl_tuple_t *sig)
{
assert(jl_is_func(F));
jl_function_t *f = (jl_function_t*)F;
assert(f->linfo != NULL);
// to run inference on all thunks. slows down loading files.
// NOTE: if this call to inference is removed, type_annotate in inference.jl
Expand All @@ -770,8 +768,8 @@ JL_CALLABLE(jl_trampoline)
if (!jl_is_expr(f->linfo->ast)) {
f->linfo->ast = jl_uncompress_ast(f->linfo, f->linfo->ast);
}
if (jl_eval_with_compiler_p(jl_lam_body((jl_expr_t*)f->linfo->ast),1)) {
jl_type_infer(f->linfo, jl_tuple_type, f->linfo);
if (always_infer || jl_eval_with_compiler_p(jl_lam_body((jl_expr_t*)f->linfo->ast),1)) {
jl_type_infer(f->linfo, sig, f->linfo);
}
}
}
Expand All @@ -783,6 +781,13 @@ JL_CALLABLE(jl_trampoline)
if (jl_boot_file_loaded && jl_is_expr(f->linfo->ast)) {
f->linfo->ast = jl_compress_ast(f->linfo, f->linfo->ast);
}
}

JL_CALLABLE(jl_trampoline)
{
assert(jl_is_func(F));
jl_function_t *f = (jl_function_t*)F;
jl_trampoline_compile_function(f, 0, jl_tuple_type);
return jl_apply(f, args, nargs);
}

Expand Down
23 changes: 14 additions & 9 deletions src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,8 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
jl_tuple_len(ctx->sp)/2);
}
JL_CATCH {
jl_rethrow_with_add("error interpreting ccall return type");
//jl_rethrow_with_add("error interpreting ccall return type");
rt = (jl_value_t*)jl_any_type;
}
}
if (jl_is_tuple(rt)) {
Expand All @@ -815,26 +816,30 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
if (rt == (jl_value_t*)jl_pointer_type)
jl_error("ccall: return type Ptr should have an element type, Ptr{T}");

JL_TYPECHK(ccall, type, rt);
Type *lrt = julia_struct_to_llvm(rt);
if (lrt == NULL) {
JL_GC_POP();
emit_error("ccall: return type doesn't correspond to a C type", ctx);
return literal_pointer_val(jl_nothing);
}

{
JL_TRY {
at = jl_interpret_toplevel_expr_in(ctx->module, args[3],
&jl_tupleref(ctx->sp,0),
jl_tuple_len(ctx->sp)/2);
}
JL_CATCH {
jl_rethrow_with_add("error interpreting ccall argument tuple");
//jl_rethrow_with_add("error interpreting ccall argument tuple");
emit_error("error interpreting ccall argument tuple", ctx);
JL_GC_POP();
return UndefValue::get(lrt);
}
}

JL_TYPECHK(ccall, type, rt);
JL_TYPECHK(ccall, tuple, at);
JL_TYPECHK(ccall, type, at);
Type *lrt = julia_struct_to_llvm(rt);
if (lrt == NULL) {
JL_GC_POP();
emit_error("ccall: return type doesn't correspond to a C type", ctx);
return literal_pointer_val(jl_nothing);
}
jl_tuple_t *tt = (jl_tuple_t*)at;
std::vector<Type *> fargt(0);
std::vector<Type *> fargt_sig(0);
Expand Down
6 changes: 5 additions & 1 deletion src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1445,7 +1445,11 @@ static jl_value_t *static_void_instance(jl_value_t *jt)
jl_datatype_t *jb = (jl_datatype_t*)jt;
if (jb->instance == NULL)
jl_new_struct_uninit(jb);
assert(jb->instance != NULL);
if (jb->instance == NULL)
// if we can't get an instance then this was an UndefValue due
// to throwing an error.
return (jl_value_t*)jl_nothing;
//assert(jb->instance != NULL);
return (jl_value_t*)jb->instance;
}
else if (jt == jl_typeof(jl_nothing) || jt == jl_bottom_type) {
Expand Down
3 changes: 2 additions & 1 deletion src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ static void jl_serialize_value_(ios_t *s, jl_value_t *v)
jl_serialize_value(s, (jl_value_t*)li->roots);
jl_serialize_value(s, (jl_value_t*)li->def);
jl_serialize_value(s, (jl_value_t*)li->capt);
jl_serialize_value(s, (jl_value_t*)li->unspecialized);
// save functionObject pointers
write_int32(s, li->functionID);
write_int32(s, li->cFunctionID);
Expand Down Expand Up @@ -825,7 +826,7 @@ static jl_value_t *jl_deserialize_value_internal(ios_t *s)
li->cFunctionObject = NULL;
li->inInference = 0;
li->inCompile = 0;
li->unspecialized = NULL;
li->unspecialized = (jl_function_t*)jl_deserialize_value(s);
li->functionID = 0;
li->cFunctionID = 0;
int32_t cfunc_llvm, func_llvm;
Expand Down
115 changes: 112 additions & 3 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ static jl_methtable_t *new_method_table(jl_sym_t *name)
return mt;
}

static int cache_match_by_type(jl_value_t **types, size_t n, jl_tuple_t *sig,
int va)
static int cache_match_by_type(jl_value_t **types, size_t n, jl_tuple_t *sig, int va)
{
if (!va && n > jl_tuple_len(sig))
return 0;
Expand Down Expand Up @@ -799,7 +798,32 @@ static jl_function_t *cache_method(jl_methtable_t *mt, jl_tuple_t *type,
return newmeth;
}
else {
newmeth = jl_instantiate_method(method, sparams);
if (0 /* no jit mode */) {
if (method->linfo->unspecialized == NULL) {
// not yet handled
JL_PRINTF(JL_STDERR,"code missing for %s", method->linfo->name->name);
jl_static_show(JL_STDERR, (jl_value_t*)type);
JL_PRINTF(JL_STDERR, "\n");
exit(1);
}
newmeth = method->linfo->unspecialized;

if (sparams != jl_null) {
temp = (jl_value_t*)jl_alloc_tuple(jl_tuple_len(sparams)/2);
for(i=0; i < jl_tuple_len(temp); i++) {
jl_tupleset(temp, i, jl_tupleref(sparams,i*2+1));
}
temp = (jl_value_t*)jl_tuple_append((jl_tuple_t*)newmeth->env, (jl_tuple_t*)temp);
newmeth = jl_new_closure(newmeth->fptr, temp, newmeth->linfo);
}

(void)jl_method_cache_insert(mt, type, newmeth);
JL_GC_POP();
return newmeth;
}
else {
newmeth = jl_instantiate_method(method, sparams);
}
}
/*
if "method" itself can ever be compiled, for example for use as
Expand Down Expand Up @@ -1352,6 +1376,91 @@ jl_function_t *jl_get_specialization(jl_function_t *f, jl_tuple_t *types)
return sf;
}

void jl_trampoline_compile_function(jl_function_t *f, int always_infer, jl_tuple_t *sig);

void jl_compile_all_defs(jl_function_t *gf)
{
assert(jl_is_gf(gf));
jl_methtable_t *mt = jl_gf_mtable(gf);
if (mt->kwsorter != NULL)
jl_compile_all_defs(mt->kwsorter);
jl_methlist_t *m = mt->defs;
while (m != JL_NULL) {
if (jl_is_leaf_type((jl_value_t*)m->sig)) {
jl_get_specialization(gf, m->sig);
}
else if (m->func->linfo->unspecialized == NULL) {
jl_function_t *func = jl_instantiate_method(m->func, jl_null);
m->func->linfo->unspecialized = func;
func->linfo->specTypes = m->sig;
if (m->tvars != jl_null) {
// add static parameter names to end of closure env; compile
// assuming they are there. method cache will fill them in when
// it constructs closures for new "specializations".
func->linfo->ast = jl_prepare_ast(func->linfo, jl_null);
jl_array_t *closed = jl_lam_capt((jl_expr_t*)func->linfo->ast);
jl_value_t **tvs;
int tvarslen;
if (jl_is_typevar(m->tvars)) {
tvs = (jl_value_t**)&m->tvars;
tvarslen = 1;
}
else {
tvs = &jl_t0(m->tvars);
tvarslen = jl_tuple_len(m->tvars);
}
size_t i;
for(i=0; i < tvarslen; i++) {
jl_array_t *vi = jl_alloc_cell_1d(3);
jl_cellset(vi, 0, ((jl_tvar_t*)tvs[i])->name);
jl_cellset(vi, 1, jl_any_type);
jl_cellset(vi, 2, jl_box_long(1));
jl_cell_1d_push(closed, (jl_value_t*)vi);
}
}
jl_trampoline_compile_function(func, 1, m->sig);
}
m = m->next;
}
}

static void _compile_all(jl_module_t *m, htable_t *h)
{
size_t i;
size_t sz = m->bindings.size;
void **table = malloc(sz * sizeof(void*));
memcpy(table, m->bindings.table, sz*sizeof(void*));
ptrhash_put(h, m, m);
for(i=1; i < sz; i+=2) {
if (table[i] != HT_NOTFOUND) {
jl_binding_t *b = (jl_binding_t*)table[i];
if (b->value != NULL) {
jl_value_t *v = b->value;
if (jl_is_gf(v)) {
jl_compile_all_defs((jl_function_t*)v);
}
else if (jl_is_datatype(v) && ((jl_function_t*)v)->fptr == jl_f_ctor_trampoline) {
jl_add_constructors((jl_datatype_t*)v);
jl_compile_all_defs((jl_function_t*)v);
}
else if (jl_is_module(v)) {
if (!ptrhash_has(h, v)) {
_compile_all((jl_module_t*)v, h);
}
}
}
}
}
free(table);
}

void jl_compile_all()
{
htable_t h;
htable_new(&h, 0);
_compile_all(jl_main_module, &h);
}

DLLEXPORT void jl_compile_hint(jl_function_t *f, jl_tuple_t *types)
{
(void)jl_get_specialization(f, types);
Expand Down
1 change: 1 addition & 0 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,7 @@ DLLEXPORT int julia_trampoline(int argc, char **argv, int (*pmain)(int ac,char *
int ret = pmain(argc, argv);
char *build_path = jl_compileropts.build_path;
if (build_path) {
jl_compile_all();
char *build_ji;
if (asprintf(&build_ji, "%s.ji",build_path) > 0) {
jl_save_system_image(build_ji);
Expand Down
14 changes: 10 additions & 4 deletions src/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,8 +356,11 @@ static Value *generic_unbox(jl_value_t *targ, jl_value_t *x, jl_codectx_t *ctx)
}
JL_CATCH {
}
if (bt == NULL || !jl_is_bitstype(bt))
jl_error("unbox: could not determine argument size");
if (bt == NULL || !jl_is_bitstype(bt)) {
//jl_error("unbox: could not determine argument size");
emit_error("unbox: could not determine argument size", ctx);
return UndefValue::get(T_void);
}
nb = (bt==(jl_value_t*)jl_bool_type) ? 1 : jl_datatype_size(bt)*8;
}
Type *to = IntegerType::get(jl_LLVMContext, nb);
Expand Down Expand Up @@ -401,8 +404,11 @@ static Value *generic_box(jl_value_t *targ, jl_value_t *x, jl_codectx_t *ctx)
nb = (bt==(jl_value_t*)jl_bool_type) ? 1 : jl_datatype_size(bt)*8;
}

if (nb == -1)
jl_error("box: could not determine argument size");
if (nb == -1) {
emit_error("box: could not determine argument size", ctx);
return UndefValue::get(jl_pvalue_llvmt);
//jl_error("box: could not determine argument size");
}

if (llvmt == NULL)
llvmt = IntegerType::get(jl_LLVMContext, nb);
Expand Down

0 comments on commit 114e4dc

Please sign in to comment.