From 27b3daa763ef25eab874691c4181b55fe11c4882 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sun, 4 Sep 2016 14:31:06 -0400 Subject: [PATCH 1/3] make the llvm-gcroot special functions parentless, so that JuliaGCAllocator::eraseFunction doesn't delete our global this only comes up if a finalizer runs something that wasn't already compiled which currently apparently doesn't happen on master --- src/codegen.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 671dbd0a17346..a1583221e23d7 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5601,29 +5601,29 @@ static void init_julia_llvm_env(Module *m) gcroot_func = Function::Create(FunctionType::get(T_ppjlvalue, false), Function::ExternalLinkage, - "julia.gc_root_decl", m); + "julia.gc_root_decl"); add_named_global(gcroot_func, (void*)NULL, /*dllimport*/false); gckill_func = Function::Create(FunctionType::get(T_void, ArrayRef(T_ppjlvalue), false), Function::ExternalLinkage, - "julia.gc_root_kill", m); + "julia.gc_root_kill"); add_named_global(gckill_func, (void*)NULL, /*dllimport*/false); jlcall_frame_func = Function::Create(FunctionType::get(T_ppjlvalue, ArrayRef(T_int32), false), Function::ExternalLinkage, - "julia.jlcall_frame_decl", m); + "julia.jlcall_frame_decl"); add_named_global(jlcall_frame_func, (void*)NULL, /*dllimport*/false); gcroot_flush_func = Function::Create(FunctionType::get(T_void, false), Function::ExternalLinkage, - "julia.gcroot_flush", m); + "julia.gcroot_flush"); add_named_global(gcroot_flush_func, (void*)NULL, /*dllimport*/false); except_enter_func = Function::Create(FunctionType::get(T_int32, false), Function::ExternalLinkage, - "julia.except_enter", m); + "julia.except_enter"); except_enter_func->addFnAttr(Attribute::ReturnsTwice); add_named_global(except_enter_func, (void*)NULL, /*dllimport*/false); From 017d6a266e6a60f2a1cd4b9d96bdcfe3cc471a5e Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 27 Oct 2015 21:36:57 -0400 Subject: [PATCH 2/3] add runtime emulation for the cglobal intrinsic and fix runtime setting of intrinsic properties array --- src/init.c | 1 + src/intrinsics.cpp | 3 +++ src/intrinsics.h | 36 ++++++++++++++++++++------- src/julia_internal.h | 3 +++ src/runtime_intrinsics.c | 54 +++++++++++++++++++++++++++++++++++++++- 5 files changed, 87 insertions(+), 10 deletions(-) diff --git a/src/init.c b/src/init.c index da8051986b48a..779966d6ef62a 100644 --- a/src/init.c +++ b/src/init.c @@ -661,6 +661,7 @@ void _julia_init(JL_IMAGE_SEARCH rel) jl_an_empty_vec_any = (jl_value_t*)jl_alloc_vec_any(0); jl_init_serializer(); + jl_init_intrinsic_properties(); if (!jl_options.image_file) { jl_core_module = jl_new_module(jl_symbol("Core")); diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 47452dc53ead3..b33ed2b01cb69 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -923,6 +923,8 @@ static jl_cgval_t emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs, f = fptoui_auto; if (f == fptosi && nargs == 1) f = fptosi_auto; + if (f == cglobal && nargs == 1) + f = cglobal_auto; unsigned expected_nargs = intrinsic_nargs[f]; if (expected_nargs && expected_nargs != nargs) { jl_errorf("intrinsic #%d %s: wrong number of arguments", f, JL_I::jl_intrinsic_name((int)f)); @@ -930,6 +932,7 @@ static jl_cgval_t emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs, switch (f) { case ccall: return emit_ccall(args, nargs, ctx); + case cglobal_auto: case cglobal: return emit_cglobal(args, nargs, ctx); case llvmcall: return emit_llvmcall(args, nargs, ctx); case arraylen: diff --git a/src/intrinsics.h b/src/intrinsics.h index eb72f3244e816..3fafbc57110fb 100644 --- a/src/intrinsics.h +++ b/src/intrinsics.h @@ -101,13 +101,14 @@ ADD_I(pointerset, 4) \ /* c interface */ \ ALIAS(ccall, ccall) \ - ALIAS(cglobal, cglobal) \ + ADD_I(cglobal, 2) \ ALIAS(llvmcall, llvmcall) \ /* object access */ \ ADD_I(arraylen, 1) \ /* hidden intrinsics */ \ ADD_HIDDEN(fptoui_auto, 1) \ - ADD_HIDDEN(fptosi_auto, 1) + ADD_HIDDEN(fptosi_auto, 1) \ + ADD_HIDDEN(cglobal_auto, 1) enum intrinsic { #define ADD_I(func, nargs) func, @@ -154,10 +155,12 @@ JL_CALLABLE(jl_f_intrinsic_call) JL_NARGSV(intrinsic_call, 1); JL_TYPECHK(intrinsic_call, intrinsic, args[0]); enum intrinsic f = (enum intrinsic)*(uint32_t*)jl_data_ptr(args[0]); - if (f == fptoui && nargs == 1) + if (f == fptoui && nargs == 2) f = fptoui_auto; - if (f == fptosi && nargs == 1) + if (f == fptosi && nargs == 2) f = fptosi_auto; + if (f == cglobal && nargs == 2) + f = cglobal_auto; unsigned fargs = intrinsic_nargs[f]; JL_NARGS(intrinsic_call, 1 + fargs, 1 + fargs); switch (fargs) { @@ -191,16 +194,31 @@ static void add_intrinsic(jl_module_t *inm, const char *name, enum intrinsic f) #ifdef __cplusplus extern "C" #endif -void jl_init_intrinsic_functions() +void jl_init_intrinsic_properties(void) +{ +#define ADD_I(name, nargs) add_intrinsic_properties(name, nargs, (void(*)(void))&jl_##name); +#define ADD_HIDDEN ADD_I +#define ALIAS(alias, base) add_intrinsic_properties(alias, intrinsic_nargs[base], runtime_fp[base]); + ADD_HIDDEN(reinterpret, 2); + INTRINSICS +#undef ADD_I +#undef ADD_HIDDEN +#undef ALIAS + +} + +#ifdef __cplusplus +extern "C" +#endif +void jl_init_intrinsic_functions(void) { jl_module_t *inm = jl_new_module(jl_symbol("Intrinsics")); inm->parent = jl_core_module; jl_set_const(jl_core_module, jl_symbol("Intrinsics"), (jl_value_t*)inm); -#define ADD_I(name, nargs) add_intrinsic(inm, #name, name); add_intrinsic_properties(name, nargs, (void(*)(void))&jl_##name); -#define ADD_HIDDEN(name, nargs) add_intrinsic_properties(name, nargs, (void(*)(void))&jl_##name); -#define ALIAS(alias, base) add_intrinsic(inm, #alias, alias); add_intrinsic_properties(alias, intrinsic_nargs[base], runtime_fp[base]); - ADD_HIDDEN(reinterpret, 2); +#define ADD_I(name, nargs) add_intrinsic(inm, #name, name); +#define ADD_HIDDEN(name, nargs) +#define ALIAS ADD_I INTRINSICS #undef ADD_I #undef ADD_HIDDEN diff --git a/src/julia_internal.h b/src/julia_internal.h index a13b0eb6ef822..40b29fca93340 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -335,6 +335,7 @@ void jl_init_frontend(void); void jl_init_primitives(void); void jl_init_codegen(void); void jl_init_intrinsic_functions(void); +void jl_init_intrinsic_properties(void); void jl_init_tasks(void); void jl_init_stack_limits(int ismaster); void jl_init_root_task(void *stack, size_t ssize); @@ -532,6 +533,8 @@ const char *jl_intrinsic_name(int f); JL_DLLEXPORT jl_value_t *jl_reinterpret(jl_value_t *ty, jl_value_t *v); JL_DLLEXPORT jl_value_t *jl_pointerref(jl_value_t *p, jl_value_t *i, jl_value_t *align); JL_DLLEXPORT jl_value_t *jl_pointerset(jl_value_t *p, jl_value_t *x, jl_value_t *align, jl_value_t *i); +JL_DLLEXPORT jl_value_t *jl_cglobal(jl_value_t *v, jl_value_t *ty); +JL_DLLEXPORT jl_value_t *jl_cglobal_auto(jl_value_t *v); JL_DLLEXPORT jl_value_t *jl_neg_int(jl_value_t *a); JL_DLLEXPORT jl_value_t *jl_add_int(jl_value_t *a, jl_value_t *b); diff --git a/src/runtime_intrinsics.c b/src/runtime_intrinsics.c index 6ea3a9d7dfcc2..2806967c957f8 100644 --- a/src/runtime_intrinsics.c +++ b/src/runtime_intrinsics.c @@ -1,7 +1,7 @@ // This file is a part of Julia. License is MIT: http://julialang.org/license // This is in implementation of the Julia intrinsic functions against boxed types -// excluding the c interface (ccall, cglobal, llvmcall) +// excluding the native function call interface (ccall, llvmcall) // // this file assumes a little-endian processor, although that isn't too hard to fix // it also assumes two's complement negative numbers, which might be a bit harder to fix @@ -76,6 +76,58 @@ JL_DLLEXPORT jl_value_t *jl_pointerset(jl_value_t *p, jl_value_t *x, jl_value_t return p; } +JL_DLLEXPORT jl_value_t *jl_cglobal(jl_value_t *v, jl_value_t *ty) +{ + JL_TYPECHK(cglobal, type, ty); + jl_value_t *rt = + v == (jl_value_t*)jl_void_type ? (jl_value_t*)jl_voidpointer_type : // a common case + (jl_value_t*)jl_apply_type_((jl_value_t*)jl_pointer_type, &ty, 1); + + if (!jl_is_leaf_type(rt)) + jl_error("cglobal: type argument not a leaftype"); + + if (jl_is_tuple(v) && jl_nfields(v) == 1) + v = jl_fieldref(v, 0); + + if (jl_is_pointer(v)) + return jl_reinterpret(rt, v); + + char *f_lib = NULL; + if (jl_is_tuple(v) && jl_nfields(v) > 1) { + jl_value_t *t1 = jl_fieldref(v, 1); + v = jl_fieldref(v, 0); + if (jl_is_symbol(t1)) + f_lib = jl_symbol_name((jl_sym_t*)t1); + else if (jl_is_string(t1)) + f_lib = jl_string_data(t1); + else + JL_TYPECHK(cglobal, symbol, t1) + } + + char *f_name = NULL; + if (jl_is_symbol(v)) + f_name = jl_symbol_name((jl_sym_t*)v); + else if (jl_is_string(v)) + f_name = jl_string_data(v); + else + JL_TYPECHK(cglobal, symbol, v) + +#ifdef _OS_WINDOWS_ + if (!f_lib) + f_lib = jl_dlfind_win32(f_name); +#endif + + void *ptr = jl_dlsym(jl_get_library(f_lib), f_name); + jl_value_t *jv = jl_gc_alloc_1w(); + jl_set_typeof(jv, rt); + *(void**)jl_data_ptr(jv) = ptr; + return jv; +} + +JL_DLLEXPORT jl_value_t *jl_cglobal_auto(jl_value_t *v) { + return jl_cglobal(v, (jl_value_t*)jl_void_type); +} + static inline char signbitbyte(void *a, unsigned bytes) { // sign bit of an signed number of n bytes, as a byte From 8f753474709bf3b47a070b407ab330dc9042842b Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 6 Sep 2016 18:03:23 -0400 Subject: [PATCH 3/3] hook up runtime-intrinsics now IntrinsicFunctions works just like any other BuiltinFunction (except for ccall and llvmcall, which don't yet have runtime versions) --- base/replutil.jl | 6 +++++- base/show.jl | 3 ++- src/builtins.c | 2 +- src/dump.c | 17 +++++++++++++++-- src/gf.c | 13 ++++++++----- src/intrinsics.h | 26 +++++++++++++------------- src/jltypes.c | 2 +- src/julia_internal.h | 4 ++-- test/core.jl | 7 +++++++ 9 files changed, 54 insertions(+), 26 deletions(-) diff --git a/base/replutil.jl b/base/replutil.jl index 6a5002a4efaba..0c40305f80917 100644 --- a/base/replutil.jl +++ b/base/replutil.jl @@ -99,7 +99,11 @@ end function show(io::IO, ::MIME"text/plain", f::Function) ft = typeof(f) mt = ft.name.mt - if isa(f, Core.Builtin) + if isa(f, Core.IntrinsicFunction) + show(io, f) + id = Core.Intrinsics.box(Int32, f) + print(io, " (intrinsic function #$id)") + elseif isa(f, Core.Builtin) print(io, mt.name, " (built-in function)") else name = mt.name diff --git a/base/show.jl b/base/show.jl index 66574576eb59e..63803be9e7dee 100644 --- a/base/show.jl +++ b/base/show.jl @@ -170,7 +170,8 @@ function show(io::IO, f::Function) end function show(io::IO, x::Core.IntrinsicFunction) - print(io, "(intrinsic function #", box(Int32, unbox(Core.IntrinsicFunction, x)), ")") + name = ccall(:jl_intrinsic_name, Cstring, (Core.IntrinsicFunction,), x) + print(io, unsafe_string(name)) end function show(io::IO, x::Union) diff --git a/src/builtins.c b/src/builtins.c index 0044339c835b6..f93f27475a96f 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1124,7 +1124,7 @@ jl_fptr_t jl_get_builtin_fptr(jl_value_t *b) static void add_builtin_func(const char *name, jl_fptr_t fptr) { - add_builtin(name, jl_mk_builtin_func(name, fptr)); + jl_mk_builtin_func(NULL, name, fptr); } void jl_init_primitives(void) diff --git a/src/dump.c b/src/dump.c index c2c387e7af753..628b04903f4e5 100644 --- a/src/dump.c +++ b/src/dump.c @@ -2050,7 +2050,13 @@ static void jl_save_system_image_to_stream(ios_t *f) jl_serialize_value(&s, jl_main_module); jl_serialize_value(&s, jl_top_module); jl_serialize_value(&s, jl_typeinf_func); + + // deserialize method tables of builtin types jl_serialize_value(&s, jl_type_type->name->mt); + jl_serialize_value(&s, jl_intrinsic_type->name->mt); + jl_serialize_value(&s, jl_sym_type->name->mt); + jl_serialize_value(&s, jl_array_type->name->mt); + jl_serialize_value(&s, jl_module_type->name->mt); jl_prune_type_cache(jl_tuple_typename->cache); jl_prune_type_cache(jl_tuple_typename->linearcache); @@ -2146,10 +2152,17 @@ static void jl_restore_system_image_from_stream(ios_t *f) jl_main_module = (jl_module_t*)jl_deserialize_value(&s, NULL); jl_top_module = (jl_module_t*)jl_deserialize_value(&s, NULL); jl_internal_main_module = jl_main_module; + jl_typeinf_func = (jl_function_t*)jl_deserialize_value(&s, NULL); jl_type_type_mt = (jl_methtable_t*)jl_deserialize_value(&s, NULL); - jl_type_type->name->mt = jl_typector_type->name->mt = jl_uniontype_type->name->mt = jl_datatype_type->name->mt = - jl_type_type_mt; + jl_type_type->name->mt = jl_type_type_mt; + jl_typector_type->name->mt = jl_type_type_mt; + jl_uniontype_type->name->mt = jl_type_type_mt; + jl_datatype_type->name->mt = jl_type_type_mt; + jl_intrinsic_type->name->mt = (jl_methtable_t*)jl_deserialize_value(&s, NULL); + jl_sym_type->name->mt = (jl_methtable_t*)jl_deserialize_value(&s, NULL); + jl_array_type->name->mt = (jl_methtable_t*)jl_deserialize_value(&s, NULL); + jl_module_type->name->mt = (jl_methtable_t*)jl_deserialize_value(&s, NULL); intptr_t i; for(i=0; i < builtin_types.len; i++) { diff --git a/src/gf.c b/src/gf.c index 123d817bdc6ce..c8fb0263a90f4 100644 --- a/src/gf.c +++ b/src/gf.c @@ -154,10 +154,14 @@ JL_DLLEXPORT jl_value_t *jl_methtable_lookup(jl_methtable_t *mt, jl_tupletype_t JL_DLLEXPORT jl_method_t *jl_new_method_uninit(void); static jl_function_t *jl_new_generic_function_with_supertype(jl_sym_t *name, jl_module_t *module, jl_datatype_t *st, int iskw); -jl_value_t *jl_mk_builtin_func(const char *name, jl_fptr_t fptr) +void jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_t fptr) { jl_sym_t *sname = jl_symbol(name); - jl_value_t *f = jl_new_generic_function_with_supertype(sname, jl_core_module, jl_builtin_type, 0); + if (dt == NULL) { + jl_value_t *f = jl_new_generic_function_with_supertype(sname, jl_core_module, jl_builtin_type, 0); + jl_set_const(jl_core_module, sname, f); + dt = (jl_datatype_t*)jl_typeof(f); + } jl_lambda_info_t *li = jl_new_lambda_info_uninit(); li->fptr = fptr; li->code = jl_nothing; @@ -168,14 +172,13 @@ jl_value_t *jl_mk_builtin_func(const char *name, jl_fptr_t fptr) li->def = jl_new_method_uninit(); li->def->name = sname; - // li->def->module will be set to jl_core_module by init.c + li->def->module = jl_core_module; li->def->lambda_template = li; li->def->sig = jl_anytuple_type; li->def->tvars = jl_emptysvec; - jl_methtable_t *mt = jl_gf_mtable(f); + jl_methtable_t *mt = dt->name->mt; jl_typemap_insert(&mt->cache, (jl_value_t*)mt, jl_anytuple_type, jl_emptysvec, NULL, jl_emptysvec, (jl_value_t*)li, 0, &lambda_cache, NULL); - return f; } /* diff --git a/src/intrinsics.h b/src/intrinsics.h index 3fafbc57110fb..d15910fa6737b 100644 --- a/src/intrinsics.h +++ b/src/intrinsics.h @@ -125,7 +125,7 @@ enum intrinsic { #ifdef __cplusplus extern "C" #endif -const char *jl_intrinsic_name(int f) +JL_DLLEXPORT const char *jl_intrinsic_name(int f) { switch ((enum intrinsic)f) { default: return "invalid"; @@ -153,23 +153,25 @@ extern "C" JL_CALLABLE(jl_f_intrinsic_call) { JL_NARGSV(intrinsic_call, 1); - JL_TYPECHK(intrinsic_call, intrinsic, args[0]); - enum intrinsic f = (enum intrinsic)*(uint32_t*)jl_data_ptr(args[0]); - if (f == fptoui && nargs == 2) + JL_TYPECHK(intrinsic_call, intrinsic, F); + enum intrinsic f = (enum intrinsic)*(uint32_t*)jl_data_ptr(F); + if (f == fptoui && nargs == 1) f = fptoui_auto; - if (f == fptosi && nargs == 2) + if (f == fptosi && nargs == 1) f = fptosi_auto; - if (f == cglobal && nargs == 2) + if (f == cglobal && nargs == 1) f = cglobal_auto; unsigned fargs = intrinsic_nargs[f]; - JL_NARGS(intrinsic_call, 1 + fargs, 1 + fargs); + if (!fargs) + jl_error("this intrinsic must be compiled to be called"); + JL_NARGS(intrinsic_call, fargs, fargs); switch (fargs) { case 1: - return ((intrinsic_call_1_arg)runtime_fp[f])(args[1]); + return ((intrinsic_call_1_arg)runtime_fp[f])(args[0]); case 2: - return ((intrinsic_call_2_arg)runtime_fp[f])(args[1], args[2]); + return ((intrinsic_call_2_arg)runtime_fp[f])(args[0], args[1]); case 3: - return ((intrinsic_call_3_arg)runtime_fp[f])(args[1], args[2], args[3]); + return ((intrinsic_call_3_arg)runtime_fp[f])(args[0], args[1], args[2]); default: assert(0 && "unexpected number of arguments to an intrinsic function"); } @@ -215,6 +217,7 @@ void jl_init_intrinsic_functions(void) jl_module_t *inm = jl_new_module(jl_symbol("Intrinsics")); inm->parent = jl_core_module; jl_set_const(jl_core_module, jl_symbol("Intrinsics"), (jl_value_t*)inm); + jl_mk_builtin_func(jl_intrinsic_type, "IntrinsicFunction", jl_f_intrinsic_call); #define ADD_I(name, nargs) add_intrinsic(inm, #name, name); #define ADD_HIDDEN(name, nargs) @@ -223,7 +226,4 @@ void jl_init_intrinsic_functions(void) #undef ADD_I #undef ADD_HIDDEN #undef ALIAS - - jl_set_const(inm, jl_symbol("intrinsic_call"), - jl_mk_builtin_func("intrinsic_call", jl_f_intrinsic_call)); } diff --git a/src/jltypes.c b/src/jltypes.c index a0a224e737b5a..7c2b37da69bf5 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3947,7 +3947,7 @@ void jl_init_types(void) jl_type_type->name->mt; jl_intrinsic_type = jl_new_bitstype((jl_value_t*)jl_symbol("IntrinsicFunction"), - jl_any_type, jl_emptysvec, 32); + jl_builtin_type, jl_emptysvec, 32); tv = jl_svec1(tvar("T")); jl_ref_type = diff --git a/src/julia_internal.h b/src/julia_internal.h index 40b29fca93340..00225f51f7214 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -269,7 +269,7 @@ int jl_types_equal_generic(jl_value_t *a, jl_value_t *b, int useenv); jl_datatype_t *jl_inst_concrete_tupletype_v(jl_value_t **p, size_t np); jl_datatype_t *jl_inst_concrete_tupletype(jl_svec_t *p); void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype); -jl_value_t *jl_mk_builtin_func(const char *name, jl_fptr_t fptr); +void jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_t fptr); STATIC_INLINE int jl_is_type(jl_value_t *v) { jl_value_t *t = jl_typeof(v); @@ -528,7 +528,7 @@ extern JL_DLLEXPORT jl_value_t *jl_segv_exception; #endif // -- Runtime intrinsics -- // -const char *jl_intrinsic_name(int f); +JL_DLLEXPORT const char *jl_intrinsic_name(int f); JL_DLLEXPORT jl_value_t *jl_reinterpret(jl_value_t *ty, jl_value_t *v); JL_DLLEXPORT jl_value_t *jl_pointerref(jl_value_t *p, jl_value_t *i, jl_value_t *align); diff --git a/test/core.jl b/test/core.jl index 3790769b4d1dd..b486051db1cef 100644 --- a/test/core.jl +++ b/test/core.jl @@ -504,6 +504,13 @@ glotest() @test glob_x == 88 @test loc_x == 10 +# runtime intrinsics + +let f = Any[Core.Intrinsics.add_int, Core.Intrinsics.sub_int] + @test f[1](1, 1) == 2 + @test f[2](1, 1) == 0 +end + # issue #7234 begin glob_x2 = 24