diff --git a/base/REPL.jl b/base/REPL.jl index 977fb156bdfc4..eac428d51d36b 100644 --- a/base/REPL.jl +++ b/base/REPL.jl @@ -131,9 +131,9 @@ function print_response(errio::IO, val::ANY, bt, show_value::Bool, have_color::B if val !== nothing && show_value try if specialdisplay === nothing - display(val) + eval(Main, Expr(:call, () -> display(val))) else - display(specialdisplay,val) + eval(Main, Expr(:call, () -> display(specialdisplay, val))) end catch err println(errio, "Error showing value of type ", typeof(val), ":") diff --git a/base/client.jl b/base/client.jl index d3b163e9ff251..aaf4652f11467 100644 --- a/base/client.jl +++ b/base/client.jl @@ -114,13 +114,14 @@ function eval_user_input(ast::ANY, show_value) errcount, lasterr = 0, () else ast = expand(ast) - value = eval(Main,ast) + value = eval(Main, ast) eval(Main, :(ans = $(Expr(:quote, value)))) - if !is(value,nothing) && show_value + if !is(value, nothing) && show_value if have_color print(answer_color()) end - try display(value) + try + eval(Main, Expr(:call, () -> display(value))) catch err println(STDERR, "Evaluation succeeded, but an error occurred while showing value of type ", typeof(value), ":") rethrow(err) diff --git a/base/inference.jl b/base/inference.jl index 5e166a79d6cf9..e8060546256be 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -49,6 +49,7 @@ type InferenceState # info on the state of inference and the linfo linfo::LambdaInfo + world::UInt nargs::Int stmt_types::Vector{Any} # return type @@ -75,7 +76,7 @@ type InferenceState optimize::Bool inferred::Bool - function InferenceState(linfo::LambdaInfo, optimize::Bool) + function InferenceState(linfo::LambdaInfo, world::UInt, optimize::Bool) @assert isa(linfo.code,Array{Any,1}) nslots = length(linfo.slotnames) nl = label_counter(linfo.code)+1 @@ -155,7 +156,7 @@ type InferenceState inmodule = isdefined(linfo, :def) ? linfo.def.module : current_module() # toplevel thunks are inferred in the current module frame = new( sp, nl, Dict{SSAValue, Bool}(), inmodule, 0, false, - linfo, la, s, Union{}, W, n, + linfo, world, la, s, Union{}, W, n, cur_hand, handler_at, n_handlers, ssavalue_uses, ssavalue_init, ObjectIdDict(), #Dict{InferenceState, Vector{LineNum}}(), @@ -607,14 +608,14 @@ function invoke_tfunc(f::ANY, types::ANY, argtype::ANY, sv::InferenceState) ft = type_typeof(f) types = Tuple{ft, types.parameters...} argtype = Tuple{ft, argtype.parameters...} - entry = ccall(:jl_gf_invoke_lookup, Any, (Any,), types) + entry = ccall(:jl_gf_invoke_lookup, Any, (Any, UInt), types, sv.world) if is(entry, nothing) return Any end meth = entry.func (ti, env) = ccall(:jl_match_method, Any, (Any, Any, Any), argtype, meth.sig, meth.tvars)::SimpleVector - return typeinf_edge(meth::Method, ti, env, sv)[2] + return typeinf_edge(meth::Method, ti, env, sv, sv.world)[2] end function tuple_tfunc(argtype::ANY) @@ -842,7 +843,7 @@ function abstract_call_gf_by_type(f::ANY, argtype::ANY, sv) end end #print(m,"\n") - (_tree, rt) = typeinf_edge(method, sig, m[2], sv) + (_tree, rt) = typeinf_edge(method, sig, m[2], sv, sv.world) rettype = tmerge(rettype, rt) if is(rettype,Any) break @@ -1384,9 +1385,9 @@ function newvar!(sv::InferenceState, typ) end # create a specialized LambdaInfo from a method -function specialize_method(method::Method, types::ANY, sp::SimpleVector, cached) +function specialize_method(method::Method, types::ANY, sp::SimpleVector, cached, world) if cached - return ccall(:jl_specializations_get_linfo, Ref{LambdaInfo}, (Any, Any, Any), method, types, sp) + return ccall(:jl_specializations_get_linfo, Ref{LambdaInfo}, (Any, Any, Any, UInt), method, types, sp, world) else return ccall(:jl_get_specialized, Ref{LambdaInfo}, (Any, Any, Any), method, types, sp) end @@ -1408,16 +1409,24 @@ function unshare_linfo!(li::LambdaInfo) end #### entry points for inferring a LambdaInfo given a type signature #### -function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, needtree::Bool, optimize::Bool, cached::Bool, caller) +let _min_age = Symbol("min-age"), _max_age = Symbol("max-age") + global min_age(m::Method) = getfield(m, _min_age) % UInt + global max_age(m::Method) = getfield(m, _max_age) % UInt +end +function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, needtree::Bool, optimize::Bool, cached::Bool, caller, world::UInt) local code = nothing local frame = nothing + if world < min_age(method) || world > max_age(method) + ccall(:jl_breakpoint, Void, (Any,), (method, world)) + return (nothing, Union{}, false) + end if isa(caller, LambdaInfo) code = caller elseif cached # check cached specializations # for an existing result stored there if !is(method.specializations, nothing) - code = ccall(:jl_specializations_lookup, Any, (Any, Any), method, atypes) + code = ccall(:jl_specializations_lookup, Any, (Any, Any, UInt), method, atypes, world) if isa(code, Void) # something completely new elseif isa(code, LambdaInfo) @@ -1479,12 +1488,12 @@ function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, needtr end try # user code might throw errors – ignore them - linfo = specialize_method(method, atypes, sparams, cached) + linfo = specialize_method(method, atypes, sparams, cached, world) catch return (nothing, Any, false) end else - linfo = specialize_method(method, atypes, sparams, cached) + linfo = specialize_method(method, atypes, sparams, cached, world) end if linfo.inInference @@ -1503,7 +1512,7 @@ function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, needtr else # inference not started yet, make a new frame for a new lambda linfo.inInference = true - frame = InferenceState(unshare_linfo!(linfo::LambdaInfo), optimize) + frame = InferenceState(unshare_linfo!(linfo::LambdaInfo), world, optimize) end frame = frame::InferenceState @@ -1527,24 +1536,25 @@ function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, needtr return (frame.linfo, frame.bestguess, frame.inferred) end -function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, caller) - return typeinf_edge(method, atypes, sparams, false, true, true, caller) +world_counter() = ccall(:jl_get_world_counter, UInt, ()) +function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, caller::InferenceState, world::UInt) + return typeinf_edge(method, atypes, sparams, false, true, true, caller, world) end function typeinf(method::Method, atypes::ANY, sparams::SimpleVector, needtree::Bool=false) - return typeinf_edge(method, atypes, sparams, needtree, true, true, nothing) + return typeinf_edge(method, atypes, sparams, needtree, true, true, nothing, world_counter()) end # compute an inferred (optionally optimized) AST without global effects (i.e. updating the cache) function typeinf_uncached(method::Method, atypes::ANY, sparams::ANY; optimize::Bool=true) - return typeinf_edge(method, atypes, sparams, true, optimize, false, nothing) + return typeinf_edge(method, atypes, sparams, true, optimize, false, nothing, world_counter()) end function typeinf_uncached(method::Method, atypes::ANY, sparams::SimpleVector, optimize::Bool) - return typeinf_edge(method, atypes, sparams, true, optimize, false, nothing) + return typeinf_edge(method, atypes, sparams, true, optimize, false, nothing, world_counter()) end -function typeinf_ext(linfo::LambdaInfo) +function typeinf_ext(linfo::LambdaInfo, world::UInt) if isdefined(linfo, :def) # method lambda - infer this specialization via the method cache - (code, _t, _) = typeinf_edge(linfo.def, linfo.specTypes, linfo.sparam_vals, true, true, true, linfo) - if code.inferred && linfo !== code + (code, _t, inferred) = typeinf_edge(linfo.def, linfo.specTypes, linfo.sparam_vals, true, true, true, linfo, world) + if inferred && code.inferred && linfo !== code # This case occurs when the IR for a function has been deleted. # `code` will be a newly-created LambdaInfo, and we need to copy its # contents to the existing one to copy the info to the method cache. @@ -1564,7 +1574,7 @@ function typeinf_ext(linfo::LambdaInfo) else # toplevel lambda - infer directly linfo.inInference = true - frame = InferenceState(linfo, true) + frame = InferenceState(linfo, world, true) typeinf_loop(frame) @assert frame.inferred # TODO: deal with this better return linfo @@ -2342,7 +2352,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference end function invoke_NF() # converts a :call to :invoke - cache_linfo = ccall(:jl_get_spec_lambda, Any, (Any,), atype_unlimited) + cache_linfo = ccall(:jl_get_spec_lambda, Any, (Any, UInt), atype_unlimited, sv.world) if cache_linfo !== nothing e.head = :invoke unshift!(e.args, cache_linfo) diff --git a/base/methodshow.jl b/base/methodshow.jl index 928c8b09fe70a..195eb68a99113 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -73,9 +73,9 @@ function arg_decl_parts(m::Method) return tv, decls, file, line end -function kwarg_decl(sig::ANY, kwtype::DataType) - sig = Tuple{kwtype, Core.AnyVector, sig.parameters...} - kwli = ccall(:jl_methtable_lookup, Any, (Any, Any), kwtype.name.mt, sig) +function kwarg_decl(m::Method, kwtype::DataType) + sig = Tuple{kwtype, Core.AnyVector, m.sig.parameters...} + kwli = ccall(:jl_methtable_lookup, Any, (Any, Any, UInt), kwtype.name.mt, sig, getfield(m, Symbol("max-age")) % UInt) if kwli !== nothing kwli = kwli::Method return filter(x->!('#' in string(x)), kwli.lambda_template.slotnames[kwli.lambda_template.nargs+1:end]) @@ -108,7 +108,7 @@ function show(io::IO, m::Method; kwtype::Nullable{DataType}=Nullable{DataType}() join(io, [isempty(d[2]) ? d[1] : d[1]*"::"*d[2] for d in decls[2:end]], ", ", ", ") if !isnull(kwtype) - kwargs = kwarg_decl(m.sig, get(kwtype)) + kwargs = kwarg_decl(m, get(kwtype)) if !isempty(kwargs) print(io, "; ") join(io, kwargs, ", ", ", ") @@ -231,7 +231,7 @@ function show(io::IO, ::MIME"text/html", m::Method; kwtype::Nullable{DataType}=N join(io, [isempty(d[2]) ? d[1] : d[1]*"::"*d[2]*"" for d in decls[2:end]], ", ", ", ") if !isnull(kwtype) - kwargs = kwarg_decl(m.sig, get(kwtype)) + kwargs = kwarg_decl(m, get(kwtype)) if !isempty(kwargs) print(io, "; ") join(io, kwargs, ", ", ", ") diff --git a/base/multi.jl b/base/multi.jl index e7ae912babed2..fc62beadf03e8 100644 --- a/base/multi.jl +++ b/base/multi.jl @@ -610,7 +610,7 @@ function lookup_ref(pg, rrid, f) rv = get(pg.refs, rrid, false) if rv === false # first we've heard of this ref - rv = RemoteValue(f()) + rv = RemoteValue(eval(Main, Expr(:call, f))) pg.refs[rrid] = rv push!(rv.clientset, rrid.whence) end @@ -778,7 +778,7 @@ function run_work_thunk(thunk, print_error) result = RemoteException(ce) print_error && showerror(STDERR, ce) end - result + return result end function run_work_thunk(rv::RemoteValue, thunk) put!(rv, run_work_thunk(thunk, false)) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 52b078a89c5bd..4b5bc46742631 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -784,9 +784,10 @@ the order that the first of each set of equivalent elements originally appears. If `dim` is specified, returns unique regions of the array `itr` along `dim`. """ @generated function unique{T,N}(A::AbstractArray{T,N}, dim::Int) + inds = inds -> zeros(UInt, inds) quote 1 <= dim <= $N || return copy(A) - hashes = allocate_for(inds->zeros(UInt, inds), A, shape(A, dim)) + hashes = allocate_for($inds, A, shape(A, dim)) # Compute hash for each row k = 0 diff --git a/base/reflection.jl b/base/reflection.jl index a2f5889b42bca..62ef72652c348 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -385,7 +385,7 @@ function which(f::ANY, t::ANY) return first(ms) else ft = isa(f,Type) ? Type{f} : typeof(f) - m = ccall(:jl_gf_invoke_lookup, Any, (Any,), Tuple{ft, t.parameters...}) + m = ccall(:jl_gf_invoke_lookup, Any, (Any, UInt), Tuple{ft, t.parameters...}, typemax(UInt)) if m === nothing error("no method found for the specified argument types") end @@ -439,7 +439,8 @@ end function method_exists(f::ANY, t::ANY) t = to_tuple_type(t) t = Tuple{isa(f,Type) ? Type{f} : typeof(f), t.parameters...} - return ccall(:jl_method_exists, Cint, (Any, Any), typeof(f).name.mt, t) != 0 + return ccall(:jl_method_exists, Cint, (Any, Any, UInt), typeof(f).name.mt, t, + ccall(:jl_get_world_counter, Int32, ())) != 0 end function isambiguous(m1::Method, m2::Method) diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index 7e3bac45a3594..824df82f62695 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -1387,8 +1387,8 @@ for (Bsig, A1sig, A2sig, gbb, funcname) in global $funcname function $funcname(f::Function, B::$Bsig, A1::$A1sig, A2::$A2sig) func = @get! cache f gen_broadcast_function_sparse($gbb, f, ($A1sig) <: SparseMatrixCSC) - func(B, A1, A2) - B + eval(Expr(:call, () -> func(B, A1, A2))) # need eval because func was just created by gen_broadcast_function_sparse + return B end end # let broadcast_cache end diff --git a/src/alloc.c b/src/alloc.c index 5c3541b71200f..7f8bc6ab071e9 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -407,7 +407,7 @@ STATIC_INLINE jl_value_t *jl_call_staged(jl_svec_t *sparam_vals, jl_lambda_info_ jl_value_t **args, uint32_t nargs) { if (__unlikely(meth->fptr == NULL)) { - jl_compile_linfo(meth); + jl_compile_linfo(meth, meth->def->min_world); jl_generate_fptr(meth); } assert(jl_svec_len(meth->sparam_syms) == jl_svec_len(sparam_vals)); @@ -448,6 +448,7 @@ static jl_lambda_info_t *jl_instantiate_staged(jl_method_t *generator, jl_tuplet // invoke code generator assert(jl_nparams(tt) == jl_array_len(argnames) || (func->isva && (jl_nparams(tt) >= jl_array_len(argnames) - 1))); + // TODO: set world to that of the generator while calling func jl_array_ptr_set(body->args, 1, jl_call_staged(sparam_vals, func, jl_svec_data(tt->parameters), jl_nparams(tt))); @@ -582,6 +583,8 @@ JL_DLLEXPORT jl_method_t *jl_new_method_uninit(void) m->isstaged = 0; m->needs_sparam_vals_ducttape = 2; m->traced = 0; + m->min_world = 1; + m->max_world = ~(size_t)0; return m; } @@ -608,6 +611,7 @@ jl_method_t *jl_new_method(jl_lambda_info_t *definition, jl_sym_t *name, jl_tupl jl_gc_wb(m, definition); definition->def = m; jl_gc_wb(definition, m); + m->min_world = ++jl_world_counter; if (reused) { m->file = oldm->file; diff --git a/src/anticodegen.c b/src/anticodegen.c index b803fe1f757e8..2999d49092628 100644 --- a/src/anticodegen.c +++ b/src/anticodegen.c @@ -15,7 +15,7 @@ int32_t jl_get_llvm_gv(jl_value_t *p) UNAVAILABLE void jl_write_malloc_log(void) UNAVAILABLE void jl_write_coverage_data(void) UNAVAILABLE void jl_generate_fptr(jl_lambda_info_t *li) UNAVAILABLE -void jl_compile_linfo(jl_lambda_info_t *li, void *cyclectx) UNAVAILABLE +void jl_compile_linfo(jl_lambda_info_t *li, size_t world) UNAVAILABLE JL_DLLEXPORT void jl_clear_malloc_data(void) UNAVAILABLE JL_DLLEXPORT void jl_extern_c(jl_function_t *f, jl_value_t *rt, jl_value_t *argt, char *name) UNAVAILABLE diff --git a/src/ast.c b/src/ast.c index 0d9fc15860af7..6368d813471f7 100644 --- a/src/ast.c +++ b/src/ast.c @@ -143,11 +143,12 @@ value_t fl_invoke_julia_macro(fl_context_t *fl_ctx, value_t *args, uint32_t narg int i; for(i=1; i < nargs; i++) margs[i] = scm_to_julia(fl_ctx, args[i], 1); jl_value_t *result = NULL; + size_t world = jl_get_ptls_states()->world_age; JL_TRY { margs[0] = scm_to_julia(fl_ctx, args[0], 1); margs[0] = jl_toplevel_eval(margs[0]); - mfunc = jl_method_lookup(jl_gf_mtable(margs[0]), margs, nargs, 1); + mfunc = jl_method_lookup(jl_gf_mtable(margs[0]), margs, nargs, 1, world); if (mfunc == NULL) { JL_GC_POP(); jl_method_error((jl_function_t*)margs[0], margs, nargs); diff --git a/src/builtins.c b/src/builtins.c index 3f33510add18c..51fb1754ecf10 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -205,6 +205,7 @@ JL_DLLEXPORT void jl_enter_handler(jl_handler_t *eh) #endif eh->defer_signal = ptls->defer_signal; eh->finalizers_inhibited = ptls->finalizers_inhibited; + eh->world_age = ptls->world_age; current_task->eh = eh; } @@ -574,7 +575,6 @@ jl_value_t *jl_toplevel_eval_in_warn(jl_module_t *m, jl_value_t *ex, int delay_w v = jl_toplevel_eval(ex); } JL_CATCH { - ptls->world_age = last_age; ptls->current_module = last_m; ptls->current_task->current_module = task_last_m; jl_warn_on_eval = last_delay_warn; @@ -966,7 +966,8 @@ static void jl_check_type_tuple(jl_value_t *t, jl_sym_t *name, const char *ctx) JL_CALLABLE(jl_f_applicable) { JL_NARGSV(applicable, 1); - return jl_method_lookup(jl_gf_mtable(args[0]), args, nargs, 1) != NULL ? + size_t world = jl_get_ptls_states()->world_age; + return jl_method_lookup(jl_gf_mtable(args[0]), args, nargs, 1, world) != NULL ? jl_true : jl_false; } diff --git a/src/ccall.cpp b/src/ccall.cpp index 1103b4e918ad5..e984ad492d5fd 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -408,7 +408,10 @@ static jl_value_t* try_eval(jl_value_t *ex, jl_codectx_t *ctx, const char *failu if (constant || jl_is_ssavalue(ex)) return constant; JL_TRY { + size_t last_age = jl_get_ptls_states()->world_age; + jl_get_ptls_states()->world_age = ctx->world; constant = jl_interpret_toplevel_expr_in(ctx->module, ex, ctx->linfo); + jl_get_ptls_states()->world_age = last_age; } JL_CATCH { if (compiletime) diff --git a/src/codegen.cpp b/src/codegen.cpp index 2a852419dbd3e..bba442145f50d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1,5 +1,5 @@ // This file is a part of Julia. License is MIT: http://julialang.org/license - +; #include "llvm-version.h" #include "platform.h" #include "options.h" @@ -419,6 +419,7 @@ static Function *resetstkoflw_func; #endif static Function *diff_gc_total_bytes_func; static Function *jlarray_data_owner_func; +static Function *jlgetworld_func; // placeholder functions static Function *gcroot_func; @@ -557,6 +558,8 @@ typedef struct { std::map *handlers; jl_module_t *module; jl_lambda_info_t *linfo; + jl_array_t *code; + size_t world; const char *name; StringRef file; Value *spvals_ptr; @@ -572,6 +575,7 @@ typedef struct { CallInst *ptlsStates; Value *signalPage; + Value *world_age_field; llvm::DIBuilder *dbuilder; bool debug_enabled; @@ -801,12 +805,12 @@ void jl_dump_compiles(void *s) // --- entry point --- //static int n_emit=0; -static std::unique_ptr emit_function(jl_lambda_info_t *lam, jl_llvm_functions_t *declarations); +static std::unique_ptr emit_function(jl_lambda_info_t *lam, size_t world, jl_llvm_functions_t *declarations); void jl_add_linfo_in_flight(StringRef name, jl_lambda_info_t *linfo, const DataLayout &DL); // this is the implementation component of jl_compile_linfo // which compiles li and adds the result to the jitlayers -static void to_function(jl_lambda_info_t *li) +static void to_function(jl_lambda_info_t *li, size_t world) { // setup global state JL_LOCK(&codegen_lock); @@ -822,7 +826,7 @@ static void to_function(jl_lambda_info_t *li) Function *f = NULL, *specf = NULL; // actually do the work of emitting the function JL_TRY { - m = emit_function(li, &li->functionObjectsDecls); + m = emit_function(li, world, &li->functionObjectsDecls); f = (Function*)li->functionObjectsDecls.functionObject; specf = (Function*)li->functionObjectsDecls.specFunctionObject; //n_emit++; @@ -1018,11 +1022,11 @@ extern "C" void jl_generate_fptr(jl_lambda_info_t *li) // this generates llvm code for the lambda info // (and adds it to the shadow module), but doesn't yet compile // or generate object code for it -extern "C" void jl_compile_linfo(jl_lambda_info_t *li) +extern "C" void jl_compile_linfo(jl_lambda_info_t *li, size_t world) { if (li->functionObjectsDecls.functionObject == NULL) { // objective: assign li->functionObject - to_function(li); + to_function(li, world); } } @@ -1100,13 +1104,14 @@ void jl_extern_c(jl_function_t *f, jl_value_t *rt, jl_value_t *argt, char *name) extern "C" JL_DLLEXPORT void *jl_get_llvmf(jl_tupletype_t *tt, bool getwrapper, bool getdeclarations) { + size_t world = jl_world_counter; jl_lambda_info_t *linfo = NULL; JL_GC_PUSH2(&linfo, &tt); if (tt != NULL) { - linfo = jl_get_specialization1(tt); + linfo = jl_get_specialization1(tt, world); if (linfo == NULL) { linfo = jl_method_lookup_by_type( - ((jl_datatype_t*)jl_tparam0(tt))->name->mt, tt, 0, 0); + ((jl_datatype_t*)jl_tparam0(tt))->name->mt, tt, 0, 0, world); if (linfo == NULL || jl_has_call_ambiguities(tt, linfo->def)) { JL_GC_POP(); return NULL; @@ -1119,7 +1124,7 @@ void *jl_get_llvmf(jl_tupletype_t *tt, bool getwrapper, bool getdeclarations) } // make sure to compile this normally first, // since `emit_function` doesn't handle recursive compilation correctly - linfo = jl_compile_for_dispatch(linfo); + linfo = jl_compile_for_dispatch(linfo, world); if (!getdeclarations) { if (linfo->code == jl_nothing) { @@ -1127,7 +1132,7 @@ void *jl_get_llvmf(jl_tupletype_t *tt, bool getwrapper, bool getdeclarations) // XXX: this only /partially/ corrupts linfo // (by confusing the compiler about the // validity of the code it already generated) - linfo = jl_type_infer(linfo, 0); + linfo = jl_type_infer(linfo, world, 0); if (linfo->code == jl_nothing || linfo->inInference) { JL_GC_POP(); return NULL; @@ -1136,7 +1141,7 @@ void *jl_get_llvmf(jl_tupletype_t *tt, bool getwrapper, bool getdeclarations) // emit this function into a new module Function *f, *specf; jl_llvm_functions_t declarations; - std::unique_ptr m = emit_function(linfo, &declarations); + std::unique_ptr m = emit_function(linfo, world, &declarations); finalize_gc_frame(m.get()); PM->run(*m.get()); f = (llvm::Function*)declarations.functionObject; @@ -2697,10 +2702,10 @@ static jl_cgval_t emit_invoke(jl_expr_t *ex, jl_codectx_t *ctx) assert(!li->inCompile); if (li->code == jl_nothing && !li->inInference && li->inferred) { // XXX: it was inferred in the past, so it's almost valid to re-infer it now - jl_type_infer(li, 0); + jl_type_infer(li, ctx->world, 0); } if (!li->inInference && li->inferred && li->code != jl_nothing) { - jl_compile_linfo(li); + jl_compile_linfo(li, ctx->world); } } Value *theFptr = (Value*)li->functionObjectsDecls.functionObject; @@ -3080,6 +3085,10 @@ static void emit_stmtpos(jl_value_t *expr, jl_codectx_t *ctx) return; // fall-through } + if (ctx->linfo->def == NULL) { + Value *world = builder.CreateCall(prepare_call(jlgetworld_func)); + builder.CreateStore(world, ctx->world_age_field); + } (void)emit_expr(expr, ctx); } @@ -3506,17 +3515,17 @@ static Function *gen_cfun_wrapper(jl_function_t *ff, jl_value_t *jlrettype, jl_t const char *name = "cfunction"; // try to look up this function for direct invoking - jl_lambda_info_t *lam = jl_get_specialization1((jl_tupletype_t*)sigt); + jl_lambda_info_t *lam = jl_get_specialization1((jl_tupletype_t*)sigt, jl_world_counter/*FIXME*/); jl_value_t *astrt = (jl_value_t*)jl_any_type; // infer it first, if necessary if (lam && lam->inInference) lam = NULL; // TODO: use emit_invoke framework to dispatch these if (lam && (lam->code == jl_nothing || !lam->inferred)) - jl_type_infer(lam, 0); + jl_type_infer(lam, jl_world_counter, 0); if (lam && (lam->inInference || !lam->inferred)) lam = NULL; // TODO: use emit_invoke framework to dispatch these if (lam != NULL) { - jl_compile_linfo(lam); + jl_compile_linfo(lam, jl_world_counter); name = jl_symbol_name(lam->def->name); astrt = lam->rettype; if (astrt != (jl_value_t*)jl_bottom_type && @@ -3555,6 +3564,8 @@ static Function *gen_cfun_wrapper(jl_function_t *ff, jl_value_t *jlrettype, jl_t jl_codectx_t ctx; ctx.f = cw; ctx.linfo = lam; + ctx.code = NULL; + ctx.world = jl_world_counter; ctx.sret = false; ctx.spvals_ptr = NULL; allocate_gc_frame(b0, &ctx); @@ -3844,8 +3855,9 @@ static Function *jl_cfunction_object(jl_function_t *ff, jl_value_t *declrt, jl_t cfunc_sig = (jl_value_t*)jl_apply_tuple_type((jl_svec_t*)cfunc_sig); // check the cache + size_t world = 1; if (jl_cfunction_list.unknown != jl_nothing) { - jl_typemap_entry_t *sf = jl_typemap_assoc_by_type(jl_cfunction_list, (jl_tupletype_t*)cfunc_sig, NULL, 1, 0, /*offs*/0); + jl_typemap_entry_t *sf = jl_typemap_assoc_by_type(jl_cfunction_list, (jl_tupletype_t*)cfunc_sig, NULL, 1, 0, /*offs*/0, world); if (sf) { Function *f = (Function*)jl_unbox_voidpointer(sf->func.value); if (f) { @@ -3905,6 +3917,8 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, Function *f, bool sre jl_codectx_t ctx; ctx.f = w; ctx.linfo = lam; + ctx.code = NULL; + ctx.world = 0; ctx.sret = false; ctx.spvals_ptr = NULL; allocate_gc_frame(b0, &ctx); @@ -3956,7 +3970,7 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, Function *f, bool sre } // Compile to LLVM IR, using a specialized signature if applicable. -static std::unique_ptr emit_function(jl_lambda_info_t *lam, jl_llvm_functions_t *declarations) +static std::unique_ptr emit_function(jl_lambda_info_t *lam, size_t world, jl_llvm_functions_t *declarations) { assert(declarations && "Capturing declarations is always required"); @@ -3976,6 +3990,8 @@ static std::unique_ptr emit_function(jl_lambda_info_t *lam, jl_llvm_func ctx.handlers = &handlers; ctx.module = lam->def ? lam->def->module : jl_current_module; ctx.linfo = lam; + ctx.code = code; + ctx.world = world; ctx.name = jl_symbol_name(lam->def ? lam->def->name : anonymous_sym); ctx.funcName = ctx.name; ctx.vaSlot = -1; @@ -3983,6 +3999,7 @@ static std::unique_ptr emit_function(jl_lambda_info_t *lam, jl_llvm_func ctx.inbounds.push_back(false); ctx.boundsCheck.push_back(false); ctx.spvals_ptr = NULL; + bool toplevel = lam->def == NULL; // step 2. process var-info lists to see what vars need boxing int n_ssavalues = jl_is_long(lam->ssavaluetypes) ? jl_unbox_long(lam->ssavaluetypes) : jl_array_len(lam->ssavaluetypes); @@ -4419,6 +4436,14 @@ static std::unique_ptr emit_function(jl_lambda_info_t *lam, jl_llvm_func // step 7. set up GC frame allocate_gc_frame(b0, &ctx); + Value *last_age = NULL; + if (toplevel) { + ctx.world_age_field = builder.CreateGEP( + builder.CreateBitCast(ctx.ptlsStates, T_psize), + ConstantInt::get(T_size, offsetof(jl_tls_states_t, world_age) / sizeof(size_t))); + last_age = tbaa_decorate(tbaa_gcframe, builder.CreateLoad(ctx.world_age_field)); + } + // step 8. allocate space for exception handler contexts for(i=0; i < stmtslen; i++) { jl_value_t *stmt = jl_array_ptr_ref(stmts,i); @@ -4766,6 +4791,8 @@ static std::unique_ptr emit_function(jl_lambda_info_t *lam, jl_llvm_func retval = NULL; if (do_malloc_log && lno != -1) mallocVisitLine(filename, lno); + if (toplevel) + builder.CreateStore(last_age, ctx.world_age_field); if (type_is_ghost(retty) || ctx.sret) builder.CreateRetVoid(); else @@ -5594,6 +5621,14 @@ static void init_julia_llvm_env(Module *m) "julia.jlcall_frame_decl", m); add_named_global(jlcall_frame_func, (void*)NULL, /*dllimport*/false); + jlgetworld_func = + Function::Create(FunctionType::get(T_size, ArrayRef(), false), + Function::ExternalLinkage, + "jl_get_world_counter", m); + jlgetworld_func->addFnAttr(Attribute::ReadOnly); + add_named_global(jlgetworld_func, jl_get_world_counter); + + // set up optimization passes #ifdef LLVM37 // No DataLayout pass needed anymore. diff --git a/src/dump.c b/src/dump.c index bf4a47232a40a..1ea8d60db5907 100644 --- a/src/dump.c +++ b/src/dump.c @@ -844,6 +844,8 @@ static void jl_serialize_value_(ios_t *s, jl_value_t *v) write_int8(s, m->isstaged); jl_serialize_value(s, (jl_value_t*)m->file); write_int32(s, m->line); + write_int32(s, m->min_world); + write_int32(s, m->max_world); jl_serialize_value(s, (jl_value_t*)m->sig); jl_serialize_value(s, (jl_value_t*)m->tvars); if (mode != MODE_MODULE_POSTWORK) @@ -1457,6 +1459,8 @@ static jl_value_t *jl_deserialize_value_(ios_t *s, jl_value_t *vtag, jl_value_t m->isstaged = read_int8(s); m->file = (jl_sym_t*)jl_deserialize_value(s, NULL); m->line = read_int32(s); + m->min_world = read_int32(s); + m->max_world = read_int32(s); m->sig = (jl_tupletype_t*)jl_deserialize_value(s, (jl_value_t**)&m->sig); jl_gc_wb(m, m->sig); m->tvars = (jl_svec_t*)jl_deserialize_value(s, (jl_value_t**)&m->tvars); @@ -1924,6 +1928,7 @@ static void jl_save_system_image_to_stream(ios_t *f) write_int32(f, jl_get_t_uid_ctr()); write_int32(f, jl_get_gs_ctr()); + write_int32(f, jl_world_counter); jl_finalize_serializer(f); // done with f htable_reset(&backref_table, 0); @@ -2019,6 +2024,7 @@ static void jl_restore_system_image_from_stream(ios_t *f) int uid_ctr = read_int32(f); int gs_ctr = read_int32(f); + jl_world_counter = read_int32(f); jl_module_init_order = jl_finalize_deserializer(f, NULL); // done with f jl_set_t_uid_ctr(uid_ctr); diff --git a/src/gc.c b/src/gc.c index 498f524d0d129..92fd632f5427f 100644 --- a/src/gc.c +++ b/src/gc.c @@ -105,7 +105,10 @@ static void run_finalizer(jl_value_t *o, jl_value_t *ff) else { jl_value_t *args[2] = {ff,o}; JL_TRY { + size_t last_age = jl_get_ptls_states()->world_age; + jl_get_ptls_states()->world_age = jl_world_counter; jl_apply(args, 2); + jl_get_ptls_states()->world_age = last_age; } JL_CATCH { jl_printf(JL_STDERR, "error in running finalizer: "); diff --git a/src/gf.c b/src/gf.c index a6e9657a783e1..20b1597d4da05 100644 --- a/src/gf.c +++ b/src/gf.c @@ -24,7 +24,11 @@ extern "C" { #endif -size_t jl_world_counter = 0; +size_t jl_world_counter = 1; +JL_DLLEXPORT size_t jl_get_world_counter(void) +{ + return jl_world_counter; +} JL_DLLEXPORT jl_value_t *jl_invoke(jl_lambda_info_t *meth, jl_value_t **args, uint32_t nargs) { @@ -121,30 +125,31 @@ static int8_t jl_cachearg_offset(jl_methtable_t *mt) JL_DLLEXPORT jl_lambda_info_t *jl_get_specialized(jl_method_t *m, jl_tupletype_t *types, jl_svec_t *sp); // get or create the LambdaInfo for a specialization -JL_DLLEXPORT jl_lambda_info_t *jl_specializations_get_linfo(jl_method_t *m, jl_tupletype_t *type, jl_svec_t *sparams) +JL_DLLEXPORT jl_lambda_info_t *jl_specializations_get_linfo(jl_method_t *m, jl_tupletype_t *type, jl_svec_t *sparams, size_t world) { - jl_typemap_entry_t *sf = jl_typemap_assoc_by_type(m->specializations, type, NULL, 1, /*subtype*/0, /*offs*/0); + jl_typemap_entry_t *sf = jl_typemap_assoc_by_type(m->specializations, type, NULL, 1, /*subtype*/0, /*offs*/0, world); if (sf && jl_is_lambda_info(sf->func.value) && ((jl_lambda_info_t*)sf->func.value)->code != jl_nothing) return (jl_lambda_info_t*)sf->func.value; jl_lambda_info_t *li = jl_get_specialized(m, type, sparams); JL_GC_PUSH1(&li); // TODO: fuse lookup and insert steps - jl_typemap_insert(&m->specializations, (jl_value_t*)m, type, jl_emptysvec, NULL, jl_emptysvec, (jl_value_t*)li, 0, &tfunc_cache, 1, ~(size_t)0, NULL); + assert(world >= m->min_world && world <= m->max_world); + jl_typemap_insert(&m->specializations, (jl_value_t*)m, type, jl_emptysvec, NULL, jl_emptysvec, (jl_value_t*)li, 0, &tfunc_cache, m->min_world, m->max_world, NULL); JL_GC_POP(); return li; } -JL_DLLEXPORT jl_value_t *jl_specializations_lookup(jl_method_t *m, jl_tupletype_t *type) +JL_DLLEXPORT jl_value_t *jl_specializations_lookup(jl_method_t *m, jl_tupletype_t *type, size_t world) { - jl_typemap_entry_t *sf = jl_typemap_assoc_by_type(m->specializations, type, NULL, 2, /*subtype*/0, /*offs*/0); + jl_typemap_entry_t *sf = jl_typemap_assoc_by_type(m->specializations, type, NULL, 2, /*subtype*/0, /*offs*/0, world); if (!sf) return jl_nothing; return sf->func.value; } -JL_DLLEXPORT jl_value_t *jl_methtable_lookup(jl_methtable_t *mt, jl_tupletype_t *type) +JL_DLLEXPORT jl_value_t *jl_methtable_lookup(jl_methtable_t *mt, jl_tupletype_t *type, size_t world) { - jl_typemap_entry_t *sf = jl_typemap_assoc_by_type(mt->defs, type, NULL, 2, /*subtype*/0, /*offs*/0); + jl_typemap_entry_t *sf = jl_typemap_assoc_by_type(mt->defs, type, NULL, 2, /*subtype*/0, /*offs*/0, world); if (!sf) return jl_nothing; return sf->func.value; @@ -208,7 +213,7 @@ jl_lambda_info_t *jl_get_unspecialized(jl_lambda_info_t *method) if "li" has been inferred before but the IR was deleted, returns a new LambdaInfo with the IR reconstituted. */ -jl_lambda_info_t *jl_type_infer(jl_lambda_info_t *li, int force) +jl_lambda_info_t *jl_type_infer(jl_lambda_info_t *li, size_t world, int force) { #ifdef ENABLE_INFERENCE jl_module_t *mod = NULL; @@ -222,15 +227,19 @@ jl_lambda_info_t *jl_type_infer(jl_lambda_info_t *li, int force) (mod != jl_core_module || !lastIn)))) { // avoid any potential recursion in calling jl_typeinf_func on itself JL_LOCK(&codegen_lock); // Might GC assert(li->inInference == 0); - jl_value_t *fargs[2]; + jl_value_t *fargs[3]; fargs[0] = (jl_value_t*)jl_typeinf_func; fargs[1] = (jl_value_t*)li; + fargs[2] = jl_box_ulong(world); #ifdef TRACE_INFERENCE jl_printf(JL_STDERR,"inference on "); jl_static_show_func_sig(JL_STDERR, (jl_value_t*)li->specTypes); jl_printf(JL_STDERR, "\n"); #endif - li = (jl_lambda_info_t*)jl_apply(fargs, 2); + size_t last_age = jl_get_ptls_states()->world_age; // FIXME: should be typeinf age? + jl_get_ptls_states()->world_age = jl_world_counter; + li = (jl_lambda_info_t*)jl_apply(fargs, 3); + jl_get_ptls_states()->world_age = last_age; assert(li->def || li->inInference == 0); // if this is toplevel expr, make sure inference finished JL_UNLOCK(&codegen_lock); // Might GC } @@ -309,7 +318,7 @@ JL_DLLEXPORT void jl_set_typeinf_func(jl_value_t *f) jl_reset_mt_caches(jl_main_module, unspec); size_t i, l; for (i = 0, l = jl_array_len(unspec); i < l; i++) { - jl_type_infer((jl_lambda_info_t*)jl_array_ptr_ref(unspec, i), 1); + jl_type_infer((jl_lambda_info_t*)jl_array_ptr_ref(unspec, i), jl_world_counter, 1); } JL_GC_POP(); } @@ -390,7 +399,9 @@ static jl_value_t *ml_matches(union jl_typemap_t ml, int offs, static jl_lambda_info_t *cache_method(jl_methtable_t *mt, union jl_typemap_t *cache, jl_value_t *parent, jl_tupletype_t *type, // the specialized type signature for type lambda jl_tupletype_t *tt, // the original tupletype of the signature - jl_typemap_entry_t *m, jl_svec_t *sparams) + jl_typemap_entry_t *m, + size_t world, + jl_svec_t *sparams) { JL_LOCK(&codegen_lock); // Might GC size_t i; @@ -639,7 +650,7 @@ static jl_lambda_info_t *cache_method(jl_methtable_t *mt, union jl_typemap_t *ca } // here we infer types and specialize the method - newmeth = jl_specializations_get_linfo(definition, type, sparams); + newmeth = jl_specializations_get_linfo(definition, type, sparams, world); if (cache_with_orig) { // if there is a need to cache with one of the original signatures, @@ -677,7 +688,8 @@ static jl_lambda_info_t *cache_method(jl_methtable_t *mt, union jl_typemap_t *ca } } - jl_typemap_insert(cache, parent, origtype, jl_emptysvec, type, guardsigs, (jl_value_t*)newmeth, jl_cachearg_offset(mt), &lambda_cache, 1, ~(size_t)0, NULL); + jl_typemap_insert(cache, parent, origtype, jl_emptysvec, type, guardsigs, (jl_value_t*)newmeth, jl_cachearg_offset(mt), &lambda_cache, m->min_world, m->max_world, NULL); + JL_UNLOCK(&codegen_lock); // Might GC if (definition->traced && jl_method_tracer) jl_call_tracer(jl_method_tracer, (jl_value_t*)newmeth); @@ -685,7 +697,7 @@ static jl_lambda_info_t *cache_method(jl_methtable_t *mt, union jl_typemap_t *ca return newmeth; } -static jl_lambda_info_t *jl_mt_assoc_by_type(jl_methtable_t *mt, jl_datatype_t *tt, int cache, int inexact) +static jl_lambda_info_t *jl_mt_assoc_by_type(jl_methtable_t *mt, jl_datatype_t *tt, int cache, int inexact, size_t world) { jl_typemap_entry_t *entry = NULL; jl_svec_t *env = jl_emptysvec; @@ -693,7 +705,7 @@ static jl_lambda_info_t *jl_mt_assoc_by_type(jl_methtable_t *mt, jl_datatype_t * jl_tupletype_t *sig = NULL; JL_GC_PUSH4(&env, &entry, &func, &sig); - entry = jl_typemap_assoc_by_type(mt->defs, tt, &env, inexact, 1, 0); + entry = jl_typemap_assoc_by_type(mt->defs, tt, &env, inexact, 1, 0, world); if (entry == NULL || entry == INEXACT_ENTRY) { JL_GC_POP(); return NULL; @@ -709,7 +721,7 @@ static jl_lambda_info_t *jl_mt_assoc_by_type(jl_methtable_t *mt, jl_datatype_t * if (!cache) nf = jl_get_specialized(m, sig, env); else - nf = cache_method(mt, &mt->cache, (jl_value_t*)mt, sig, tt, entry, env); + nf = cache_method(mt, &mt->cache, (jl_value_t*)mt, sig, tt, entry, world, env); JL_GC_POP(); return nf; } @@ -776,7 +788,7 @@ static int check_ambiguous_visitor(jl_typemap_entry_t *oldentry, struct typemap_ // now we are checking that the reverse is true if (!jl_args_morespecific((jl_value_t*)(closure->after ? type : sig), (jl_value_t*)(closure->after ? sig : type))) { - jl_typemap_entry_t *l = jl_typemap_assoc_by_type(map, (jl_tupletype_t*)isect, NULL, 0, 0, 0); + jl_typemap_entry_t *l = jl_typemap_assoc_by_type(map, (jl_tupletype_t*)isect, NULL, 0, 0, 0, closure->newentry->min_world); if (l != NULL) // ok, intersection is covered return 1; jl_method_t *mambig = oldentry->func.method; @@ -904,7 +916,7 @@ void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method, jl_tupletyp JL_GC_PUSH3(&oldvalue, &env.match.env, &env.match.ti); jl_typemap_entry_t *newentry = jl_typemap_insert(&mt->defs, (jl_value_t*)mt, type, tvars, simpletype, jl_emptysvec, (jl_value_t*)method, 0, &method_defs, - ++jl_world_counter, ~(size_t)0, &oldvalue); + method->min_world, method->max_world, &oldvalue); if (oldvalue) { method->ambig = ((jl_method_t*)oldvalue)->ambig; method_overwrite(newentry, (jl_method_t*)oldvalue); @@ -928,8 +940,8 @@ void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method, jl_tupletyp env.match.fptr = invalidate_conflicting; env.match.va = va; env.match.type = (jl_value_t*)type; - env.max_world = jl_world_counter - 1; - jl_typemap_intersection_visitor(mt->cache, 0, &env.match); + env.max_world = method->min_world - 1; + jl_typemap_intersection_visitor(mt->cache, jl_cachearg_offset(mt), &env.match); } JL_GC_POP(); update_max_args(mt, type); @@ -938,13 +950,8 @@ void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method, jl_tupletyp void JL_NORETURN jl_method_error_bare(jl_function_t *f, jl_value_t *args) { - jl_value_t *fargs[3] = { - (jl_value_t*)jl_methoderror_type, - (jl_value_t*)f, - args - }; - if (fargs[0]) { - jl_throw(jl_apply_generic(fargs, 3)); + if (jl_methoderror_type) { + jl_throw(jl_new_struct(jl_methoderror_type, f, args)); } else { jl_printf((JL_STREAM*)STDERR_FILENO, "A method error occurred before the base MethodError type was defined. Aborting...\n"); @@ -1001,33 +1008,33 @@ jl_tupletype_t *arg_type_tuple(jl_value_t **args, size_t nargs) } jl_lambda_info_t *jl_method_lookup_by_type(jl_methtable_t *mt, jl_tupletype_t *types, - int cache, int inexact) + int cache, int inexact, size_t world) { - jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(mt->cache, types, NULL, 0, 1, jl_cachearg_offset(mt)); + jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(mt->cache, types, NULL, 0, 1, jl_cachearg_offset(mt), world); jl_lambda_info_t *sf; if (entry) { sf = entry->func.linfo; } else { if (jl_is_leaf_type((jl_value_t*)types)) cache=1; - sf = jl_mt_assoc_by_type(mt, types, cache, inexact); + sf = jl_mt_assoc_by_type(mt, types, cache, inexact, world); } return sf; } -JL_DLLEXPORT int jl_method_exists(jl_methtable_t *mt, jl_tupletype_t *types) +JL_DLLEXPORT int jl_method_exists(jl_methtable_t *mt, jl_tupletype_t *types, size_t world) { - return jl_method_lookup_by_type(mt, types, 0, 0) != NULL; + return jl_method_lookup_by_type(mt, types, 0, 0, world) != NULL; } -jl_lambda_info_t *jl_method_lookup(jl_methtable_t *mt, jl_value_t **args, size_t nargs, int cache) +jl_lambda_info_t *jl_method_lookup(jl_methtable_t *mt, jl_value_t **args, size_t nargs, int cache, size_t world) { jl_lambda_info_t *sf; - jl_typemap_entry_t *entry = jl_typemap_assoc_exact(mt->cache, args, nargs, jl_cachearg_offset(mt)); + jl_typemap_entry_t *entry = jl_typemap_assoc_exact(mt->cache, args, nargs, jl_cachearg_offset(mt), world); if (entry == NULL) { jl_tupletype_t *tt = arg_type_tuple(args, nargs); JL_GC_PUSH1(&tt); - sf = jl_mt_assoc_by_type(mt, tt, cache, 0); + sf = jl_mt_assoc_by_type(mt, tt, cache, 0, world); JL_GC_POP(); } else { @@ -1039,7 +1046,7 @@ jl_lambda_info_t *jl_method_lookup(jl_methtable_t *mt, jl_value_t **args, size_t JL_DLLEXPORT jl_value_t *jl_matching_methods(jl_tupletype_t *types, int lim, int include_ambiguous); -jl_lambda_info_t *jl_compile_for_dispatch(jl_lambda_info_t *li) +jl_lambda_info_t *jl_compile_for_dispatch(jl_lambda_info_t *li, size_t world) { if (li->functionObjectsDecls.functionObject == NULL) { if (li->inInference || li->inCompile) { @@ -1052,7 +1059,7 @@ jl_lambda_info_t *jl_compile_for_dispatch(jl_lambda_info_t *li) if (li->code == jl_nothing || (!li->inferred && li->def != NULL && jl_symbol_name(li->def->name)[0] != '@')) { // don't bother with typeinf on macros or toplevel thunks - jl_type_infer(li, 0); + jl_type_infer(li, world, 0); } if (li->functionObjectsDecls.functionObject == NULL) { if (li->inInference || li->inCompile || li->code == jl_nothing) { @@ -1064,7 +1071,7 @@ jl_lambda_info_t *jl_compile_for_dispatch(jl_lambda_info_t *li) } } if (li->functionObjectsDecls.functionObject == NULL) { // check again, because jl_type_infer may have compiled it - jl_compile_linfo(li); + jl_compile_linfo(li, world); } } jl_generate_fptr(li); @@ -1072,7 +1079,7 @@ jl_lambda_info_t *jl_compile_for_dispatch(jl_lambda_info_t *li) } // compile-time method lookup -jl_lambda_info_t *jl_get_specialization1(jl_tupletype_t *types) +jl_lambda_info_t *jl_get_specialization1(jl_tupletype_t *types, size_t world) { assert(jl_nparams(types) > 0); if (!jl_is_leaf_type((jl_value_t*)types) || jl_has_typevars((jl_value_t*)types)) @@ -1100,7 +1107,7 @@ jl_lambda_info_t *jl_get_specialization1(jl_tupletype_t *types) // not be the case JL_GC_PUSH1(&sf); JL_TRY { - sf = jl_method_lookup_by_type(mt, types, 1, 1); + sf = jl_method_lookup_by_type(mt, types, 1, 1, world); } JL_CATCH { sf = NULL; } @@ -1114,7 +1121,7 @@ jl_lambda_info_t *jl_get_specialization1(jl_tupletype_t *types) JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types) { - jl_lambda_info_t *li = jl_get_specialization1(types); + jl_lambda_info_t *li = jl_get_specialization1(types, jl_world_counter); if (li == NULL) return 0; if (li->functionObjectsDecls.functionObject == NULL) { @@ -1122,17 +1129,17 @@ JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types) if (li->inInference) return 0; if (li->code == jl_nothing || !li->inferred) - jl_type_infer(li, 0); + jl_type_infer(li, jl_world_counter, 0); if (li->inInference || li->code == jl_nothing) return 0; - jl_compile_linfo(li); + jl_compile_linfo(li, jl_world_counter); } return 1; } -JL_DLLEXPORT jl_value_t *jl_get_spec_lambda(jl_tupletype_t *types) +JL_DLLEXPORT jl_value_t *jl_get_spec_lambda(jl_tupletype_t *types, size_t world) { - jl_value_t *li = (jl_value_t*)jl_get_specialization1(types); + jl_value_t *li = (jl_value_t*)jl_get_specialization1(types, world); return li ? li : jl_nothing; } @@ -1346,7 +1353,7 @@ static void _compile_all_deq(jl_array_t *found) if (jl_is_method(ml->func.value)) { // type infer a copy of the template, to avoid modifying the template itself templ = ml->func.method->lambda_template; - linfo = jl_specializations_get_linfo(ml->func.method, ml->sig, jl_emptysvec); + linfo = jl_specializations_get_linfo(ml->func.method, ml->sig, jl_emptysvec, jl_world_counter); } else if (jl_is_lambda_info(ml->func.value)) { templ = ml->func.linfo; @@ -1358,7 +1365,7 @@ static void _compile_all_deq(jl_array_t *found) if (!linfo->inferred || linfo->code == jl_nothing) { // force this function to be recompiled - jl_type_infer(linfo, 1); + jl_type_infer(linfo, jl_world_counter, 1); } // keep track of whether all possible signatures have been cached (and thus whether it can skip trying to compile the template function) @@ -1370,7 +1377,7 @@ static void _compile_all_deq(jl_array_t *found) templ->functionID = -1; } else { - jl_compile_linfo(linfo); + jl_compile_linfo(linfo, jl_world_counter); assert(linfo->functionID > 0); if (linfo != templ) { // copy the function pointer back to the lambda_template @@ -1639,6 +1646,7 @@ JL_DLLEXPORT jl_value_t *jl_apply_generic(jl_value_t **args, uint32_t nargs) if (traceen) show_call(args[0], &args[1], nargs-1); #endif + size_t world = jl_get_ptls_states()->world_age; /* search order: @@ -1672,7 +1680,7 @@ JL_DLLEXPORT jl_value_t *jl_apply_generic(jl_value_t **args, uint32_t nargs) // if (entry == NULL) { // jl_value_t *F = args[0]; // mt = jl_gf_mtable(F); -// entry = jl_typemap_assoc_exact(mt->cache, args, nargs, jl_cachearg_offset(mt)); +// entry = jl_typemap_assoc_exact(mt->cache, args, nargs, jl_cachearg_offset(mt), world); // if (entry && entry->isleafsig && entry->simplesig == (void*)jl_nothing && entry->guardsigs == jl_emptysvec) { // switch (++pick_which[cache_idx1] & 1) { // case 0: @@ -1706,7 +1714,7 @@ JL_DLLEXPORT jl_value_t *jl_apply_generic(jl_value_t **args, uint32_t nargs) // // jl_value_t *F = args[0]; // mt = jl_gf_mtable(F); -// entry = jl_typemap_assoc_exact(mt->cache, args, nargs, jl_cachearg_offset(mt)); +// entry = jl_typemap_assoc_exact(mt->cache, args, nargs, jl_cachearg_offset(mt), world); // if (entry && entry->isleafsig && entry->simplesig == (void*)jl_nothing && entry->guardsigs == jl_emptysvec) { // switch (++pick_which[cache_idx1] & 3) { // case 0: @@ -1745,7 +1753,8 @@ JL_DLLEXPORT jl_value_t *jl_apply_generic(jl_value_t **args, uint32_t nargs) for (i = 0; i < 4; i++) { entry = call_cache[cache_idx[i]]; if (entry && nargs == jl_svec_len(entry->sig->parameters) && - sig_match_fast(args, jl_svec_data(entry->sig->parameters), 0, nargs)) { + sig_match_fast(args, jl_svec_data(entry->sig->parameters), 0, nargs) && + world >= entry->min_world && world <= entry->max_world) { break; } } @@ -1753,7 +1762,7 @@ JL_DLLEXPORT jl_value_t *jl_apply_generic(jl_value_t **args, uint32_t nargs) if (i == 4) { jl_value_t *F = args[0]; mt = jl_gf_mtable(F); - entry = jl_typemap_assoc_exact(mt->cache, args, nargs, jl_cachearg_offset(mt)); + entry = jl_typemap_assoc_exact(mt->cache, args, nargs, jl_cachearg_offset(mt), world); if (entry && entry->isleafsig && entry->simplesig == (void*)jl_nothing && entry->guardsigs == jl_emptysvec) { // put the entry into the cache if it's valid for a leaftype lookup, // using pick_which to slightly randomize where it ends up @@ -1769,7 +1778,7 @@ JL_DLLEXPORT jl_value_t *jl_apply_generic(jl_value_t **args, uint32_t nargs) // if running inference overwrites this particular method, it becomes // unreachable from the method table, so root mfunc. JL_GC_PUSH2(&tt, &mfunc); - mfunc = jl_mt_assoc_by_type(mt, tt, 1, 0); + mfunc = jl_mt_assoc_by_type(mt, tt, 1, 0, world); if (mfunc == NULL) { #ifdef JL_TRACE @@ -1794,11 +1803,11 @@ JL_DLLEXPORT jl_value_t *jl_apply_generic(jl_value_t **args, uint32_t nargs) return verify_type(res); } -JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup(jl_datatype_t *types) +JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup(jl_datatype_t *types, size_t world) { jl_methtable_t *mt = ((jl_datatype_t*)jl_tparam0(types))->name->mt; jl_typemap_entry_t *entry = jl_typemap_assoc_by_type(mt->defs, types, /*don't record env*/NULL, - /*exact match*/0, /*subtype*/1, /*offs*/0); + /*exact match*/0, /*subtype*/1, /*offs*/0, world); if (!entry) return jl_nothing; return (jl_value_t*)entry; @@ -1815,6 +1824,7 @@ JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup(jl_datatype_t *types) // NOTE: assumes argument type is a subtype of the lookup type. jl_value_t *jl_gf_invoke(jl_tupletype_t *types0, jl_value_t **args, size_t nargs) { + size_t world = jl_get_ptls_states()->world_age; jl_svec_t *tpenv = jl_emptysvec; jl_tupletype_t *newsig = NULL; jl_tupletype_t *tt = NULL; @@ -1824,7 +1834,7 @@ jl_value_t *jl_gf_invoke(jl_tupletype_t *types0, jl_value_t **args, size_t nargs jl_value_t *gf = args[0]; types = (jl_datatype_t*)jl_argtype_with_function(gf, (jl_tupletype_t*)types0); jl_methtable_t *mt = jl_gf_mtable(gf); - jl_typemap_entry_t *entry = (jl_typemap_entry_t*)jl_gf_invoke_lookup(types); + jl_typemap_entry_t *entry = (jl_typemap_entry_t*)jl_gf_invoke_lookup(types, world); if ((jl_value_t*)entry == jl_nothing) { jl_method_error_bare(gf, (jl_value_t*)types0); @@ -1837,7 +1847,7 @@ jl_value_t *jl_gf_invoke(jl_tupletype_t *types0, jl_value_t **args, size_t nargs jl_lambda_info_t *mfunc = NULL; jl_typemap_entry_t *tm = NULL; if (entry->func.method->invokes.unknown != NULL) - tm = jl_typemap_assoc_exact(entry->func.method->invokes, args, nargs, jl_cachearg_offset(mt)); + tm = jl_typemap_assoc_exact(entry->func.method->invokes, args, nargs, jl_cachearg_offset(mt), world); if (tm == NULL) { tt = arg_type_tuple(args, nargs); if (entry->tvars != jl_emptysvec) { @@ -1852,7 +1862,7 @@ jl_value_t *jl_gf_invoke(jl_tupletype_t *types0, jl_value_t **args, size_t nargs if (func->invokes.unknown == NULL) func->invokes.unknown = jl_nothing; - mfunc = cache_method(mt, &func->invokes, entry->func.value, sig, tt, entry, tpenv); + mfunc = cache_method(mt, &func->invokes, entry->func.value, sig, tt, entry, world, tpenv); } else { mfunc = tm->func.linfo; diff --git a/src/init.c b/src/init.c index 9db6f36df98bc..9764435286a2e 100644 --- a/src/init.c +++ b/src/init.c @@ -230,7 +230,10 @@ JL_DLLEXPORT void jl_atexit_hook(int exitcode) jl_value_t *f = jl_get_global(jl_base_module, jl_symbol("_atexit")); if (f != NULL) { JL_TRY { + size_t last_age = jl_get_ptls_states()->world_age; + jl_get_ptls_states()->world_age = jl_get_world_counter(); jl_apply(&f, 1); + jl_get_ptls_states()->world_age = last_age; } JL_CATCH { jl_printf(JL_STDERR, "\natexit hook threw an error: "); diff --git a/src/interpreter.c b/src/interpreter.c index 8d83eec54bd65..c8f4ee35dc7df 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -28,7 +28,11 @@ int jl_is_toplevel_only_expr(jl_value_t *e); jl_value_t *jl_interpret_toplevel_expr(jl_value_t *e) { - return eval(e, NULL); + size_t last_age = jl_get_ptls_states()->world_age; + jl_get_ptls_states()->world_age = jl_world_counter; + jl_value_t *ret = eval(e, NULL); + jl_get_ptls_states()->world_age = last_age; + return ret; } JL_DLLEXPORT jl_value_t *jl_interpret_toplevel_expr_in(jl_module_t *m, jl_value_t *e, @@ -439,7 +443,10 @@ static jl_value_t *eval(jl_value_t *e, interpreter_state *s) jl_value_t *jl_toplevel_eval_body(jl_array_t *stmts) { - return eval_body(stmts, NULL, 0, 1); + size_t last_age = jl_get_ptls_states()->world_age; + jl_value_t *ret = eval_body(stmts, NULL, 0, 1); + jl_get_ptls_states()->world_age = last_age; + return ret; } static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, int start, int toplevel) @@ -450,15 +457,17 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, int start, while (1) { if (i >= ns) jl_error("`body` expression must terminate in `return`. Use `block` instead."); - jl_value_t *stmt = jl_array_ptr_ref(stmts,i); + if (toplevel) + jl_get_ptls_states()->world_age = jl_world_counter; + jl_value_t *stmt = jl_array_ptr_ref(stmts, i); if (jl_is_gotonode(stmt)) { - i = jl_gotonode_label(stmt)-1; + i = jl_gotonode_label(stmt) - 1; continue; } else if (jl_is_expr(stmt)) { jl_sym_t *head = ((jl_expr_t*)stmt)->head; if (head == return_sym) { - jl_value_t *ex = jl_exprarg(stmt,0); + jl_value_t *ex = jl_exprarg(stmt, 0); if (toplevel && jl_is_toplevel_only_expr(ex)) return jl_toplevel_eval(ex); else @@ -466,7 +475,7 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, int start, } else if (head == assign_sym) { jl_value_t *sym = jl_exprarg(stmt, 0); - jl_value_t *rhs = eval(jl_exprarg(stmt,1), s); + jl_value_t *rhs = eval(jl_exprarg(stmt, 1), s); if (jl_is_ssavalue(sym)) { ssize_t genid = ((jl_ssavalue_t*)sym)->id; if (genid >= jl_linfo_nssavalues(s->lam) || genid < 0) @@ -485,7 +494,7 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, int start, sym = (jl_value_t*)jl_globalref_name(sym); } else { - m = (s==NULL || s->lam==NULL || s->lam->def==NULL) ? jl_current_module : s->lam->def->module; + m = (s == NULL || s->lam == NULL || s->lam->def == NULL) ? jl_current_module : s->lam->def->module; } assert(jl_is_symbol(sym)); JL_GC_PUSH1(&rhs); @@ -495,9 +504,9 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, int start, } } else if (head == goto_ifnot_sym) { - jl_value_t *cond = eval(jl_exprarg(stmt,0), s); + jl_value_t *cond = eval(jl_exprarg(stmt, 0), s); if (cond == jl_false) { - i = jl_unbox_long(jl_exprarg(stmt, 1))-1; + i = jl_unbox_long(jl_exprarg(stmt, 1)) - 1; continue; } else if (cond != jl_true) { @@ -506,20 +515,20 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, int start, } else if (head == line_sym) { if (toplevel) - jl_lineno = jl_unbox_long(jl_exprarg(stmt,0)); + jl_lineno = jl_unbox_long(jl_exprarg(stmt, 0)); // TODO: interpreted function line numbers } else if (head == enter_sym) { jl_enter_handler(&__eh); if (!jl_setjmp(__eh.eh_ctx,1)) { - return eval_body(stmts, s, i+1, toplevel); + return eval_body(stmts, s, i + 1, toplevel); } else { #ifdef _OS_WINDOWS_ if (jl_exception_in_transit == jl_stackovf_exception) _resetstkoflw(); #endif - i = jl_unbox_long(jl_exprarg(stmt,0))-1; + i = jl_unbox_long(jl_exprarg(stmt, 0)) - 1; continue; } } @@ -540,11 +549,11 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, int start, // TODO: interpreted function line numbers } else if (jl_is_newvarnode(stmt)) { - jl_value_t *var = jl_fieldref(stmt,0); + jl_value_t *var = jl_fieldref(stmt, 0); assert(jl_is_slot(var)); ssize_t n = jl_slot_number(var); assert(n <= jl_linfo_nslots(s->lam) && n > 0); - s->locals[n-1] = NULL; + s->locals[n - 1] = NULL; } else { eval(stmt, s); @@ -562,22 +571,27 @@ jl_value_t *jl_interpret_call(jl_lambda_info_t *lam, jl_value_t **args, uint32_t jl_value_t **locals; JL_GC_PUSHARGS(locals, jl_linfo_nslots(lam) + jl_linfo_nssavalues(lam)); interpreter_state s; - s.lam = lam; s.locals = locals; s.sparam_vals = sparam_vals; + s.lam = lam; + s.locals = locals; + s.sparam_vals = sparam_vals; size_t i; - for(i=0; i < lam->nargs; i++) { - if (lam->isva && i == lam->nargs-1) - locals[i] = jl_f_tuple(NULL, &args[i], nargs-i); + for (i = 0; i < lam->nargs; i++) { + if (lam->isva && i == lam->nargs - 1) + locals[i] = jl_f_tuple(NULL, &args[i], nargs - i); else locals[i] = args[i]; } - jl_value_t *r = eval_body(stmts, &s, 0, lam->nargs==0); + jl_value_t *r = eval_body(stmts, &s, 0, lam->def == NULL); JL_GC_POP(); return r; } jl_value_t *jl_interpret_toplevel_thunk(jl_lambda_info_t *lam) { - return jl_interpret_call(lam, NULL, 0, NULL); + size_t last_age = jl_get_ptls_states()->world_age; + jl_value_t *ret = jl_interpret_call(lam, NULL, 0, NULL); + jl_get_ptls_states()->world_age = last_age; + return ret; } #ifdef __cplusplus diff --git a/src/jl_uv.c b/src/jl_uv.c index 0e862db4c77cc..43c7a8714ae89 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -100,8 +100,12 @@ JL_DLLEXPORT void jl_uv_closeHandle(uv_handle_t *handle) if (handle == (uv_handle_t*)JL_STDERR) JL_STDERR = (JL_STREAM*)STDERR_FILENO; // also let the client app do its own cleanup - if (handle->type != UV_FILE && handle->data) + if (handle->type != UV_FILE && handle->data) { + size_t last_age = jl_get_ptls_states()->world_age; + jl_get_ptls_states()->world_age = jl_world_counter; jl_uv_call_close_callback((jl_value_t*)handle->data); + jl_get_ptls_states()->world_age = last_age; + } if (handle == (uv_handle_t*)&signal_async) return; free(handle); diff --git a/src/jlapi.c b/src/jlapi.c index a169b8bc302f2..b6cf870734bfc 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -56,7 +56,10 @@ JL_DLLEXPORT jl_value_t *jl_eval_string(const char *str) jl_value_t *ast = jl_parse_input_line(str, strlen(str), filename, strlen(filename)); JL_GC_PUSH1(&ast); + size_t last_age = jl_get_ptls_states()->world_age; + jl_get_ptls_states()->world_age = jl_get_world_counter(); r = jl_toplevel_eval(ast); + jl_get_ptls_states()->world_age = last_age; JL_GC_POP(); jl_exception_clear(); } @@ -121,7 +124,10 @@ JL_DLLEXPORT jl_value_t *jl_call(jl_function_t *f, jl_value_t **args, int32_t na argv[0] = (jl_value_t*)f; for(int i=1; iworld_age; + jl_get_ptls_states()->world_age = jl_get_world_counter(); v = jl_apply(argv, nargs+1); + jl_get_ptls_states()->world_age = last_age; JL_GC_POP(); jl_exception_clear(); } @@ -136,7 +142,10 @@ JL_DLLEXPORT jl_value_t *jl_call0(jl_function_t *f) jl_value_t *v; JL_TRY { JL_GC_PUSH1(&f); + size_t last_age = jl_get_ptls_states()->world_age; + jl_get_ptls_states()->world_age = jl_get_world_counter(); v = jl_apply(&f, 1); + jl_get_ptls_states()->world_age = last_age; JL_GC_POP(); jl_exception_clear(); } @@ -153,7 +162,10 @@ JL_DLLEXPORT jl_value_t *jl_call1(jl_function_t *f, jl_value_t *a) jl_value_t **argv; JL_GC_PUSHARGS(argv, 2); argv[0] = f; argv[1] = a; + size_t last_age = jl_get_ptls_states()->world_age; + jl_get_ptls_states()->world_age = jl_get_world_counter(); v = jl_apply(argv, 2); + jl_get_ptls_states()->world_age = last_age; JL_GC_POP(); jl_exception_clear(); } @@ -170,7 +182,10 @@ JL_DLLEXPORT jl_value_t *jl_call2(jl_function_t *f, jl_value_t *a, jl_value_t *b jl_value_t **argv; JL_GC_PUSHARGS(argv, 3); argv[0] = f; argv[1] = a; argv[2] = b; + size_t last_age = jl_get_ptls_states()->world_age; + jl_get_ptls_states()->world_age = jl_get_world_counter(); v = jl_apply(argv, 3); + jl_get_ptls_states()->world_age = last_age; JL_GC_POP(); jl_exception_clear(); } @@ -188,7 +203,10 @@ JL_DLLEXPORT jl_value_t *jl_call3(jl_function_t *f, jl_value_t *a, jl_value_t **argv; JL_GC_PUSHARGS(argv, 4); argv[0] = f; argv[1] = a; argv[2] = b; argv[3] = c; + size_t last_age = jl_get_ptls_states()->world_age; + jl_get_ptls_states()->world_age = jl_get_world_counter(); v = jl_apply(argv, 4); + jl_get_ptls_states()->world_age = last_age; JL_GC_POP(); jl_exception_clear(); } diff --git a/src/jltypes.c b/src/jltypes.c index da0407420ccf7..954730240721b 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3668,13 +3668,15 @@ void jl_init_types(void) jl_method_type = jl_new_datatype(jl_symbol("Method"), jl_any_type, jl_emptysvec, - jl_svec(15, + jl_svec(17, jl_symbol("name"), jl_symbol("module"), jl_symbol("file"), jl_symbol("line"), jl_symbol("sig"), jl_symbol("tvars"), + jl_symbol("min-age"), + jl_symbol("max-age"), jl_symbol("ambig"), jl_symbol("specializations"), jl_symbol("lambda_template"), @@ -3684,23 +3686,25 @@ void jl_init_types(void) jl_symbol("isstaged"), jl_symbol("needs_sparam_vals_ducttape"), jl_symbol("")), - jl_svec(15, + jl_svec(17, jl_sym_type, jl_module_type, jl_sym_type, jl_int32_type, jl_type_type, - jl_any_type, + jl_any_type, // Union{TypeVar, SimpleVector} + jl_long_type, + jl_long_type, jl_any_type, // Union{Array, Void} - jl_any_type, - jl_any_type, + jl_any_type, // TypeMap + jl_any_type, // LambdaInfo jl_array_any_type, jl_any_type, jl_int32_type, jl_bool_type, jl_bool_type, jl_bool_type), - 0, 1, 8); + 0, 1, 11); jl_lambda_info_type = jl_new_datatype(jl_symbol("LambdaInfo"), @@ -3755,7 +3759,7 @@ void jl_init_types(void) jl_int32_type, jl_int32_type), 0, 1, 7); jl_svecset(jl_lambda_info_type->types, 9, jl_lambda_info_type); - jl_svecset(jl_method_type->types, 8, jl_lambda_info_type); + jl_svecset(jl_method_type->types, 10, jl_lambda_info_type); jl_typector_type = jl_new_datatype(jl_symbol("TypeConstructor"), diff --git a/src/julia.h b/src/julia.h index 75defc8201c16..c7316ae81585a 100644 --- a/src/julia.h +++ b/src/julia.h @@ -202,10 +202,14 @@ typedef struct _jl_method_t { jl_sym_t *file; int32_t line; - // method's type signature. partly redundant with lambda_template->specTypes + // partly redundant with the containing TypeMapEntry + // method's type signature jl_tupletype_t *sig; - // bound type variables (static parameters). redundant with TypeMapEntry->tvars + // bound type variables (static parameters) jl_svec_t *tvars; + size_t min_world; + size_t max_world; + // list of potentially-ambiguous methods (nothing = none, Vector{Any} of Methods otherwise) jl_value_t *ambig; @@ -1031,6 +1035,7 @@ JL_DLLEXPORT jl_value_t *jl_generic_function_def(jl_sym_t *name, jl_value_t **bp jl_value_t *bp_owner, jl_binding_t *bnd); JL_DLLEXPORT void jl_method_def(jl_svec_t *argdata, jl_lambda_info_t *f, jl_value_t *isstaged); +JL_DLLEXPORT size_t jl_get_world_counter(void); JL_DLLEXPORT jl_function_t *jl_get_kwsorter(jl_typename_t *tn); JL_DLLEXPORT jl_value_t *jl_box_bool(int8_t x); JL_DLLEXPORT jl_value_t *jl_box_int8(int8_t x); @@ -1419,6 +1424,7 @@ typedef struct _jl_handler_t { #endif sig_atomic_t defer_signal; int finalizers_inhibited; + size_t world_age; } jl_handler_t; typedef struct _jl_task_t { @@ -1520,6 +1526,7 @@ STATIC_INLINE void jl_eh_restore_state(jl_handler_t *eh) locks->len = eh->locks_len; } #endif + ptls->world_age = eh->world_age; ptls->defer_signal = eh->defer_signal; ptls->gc_state = eh->gc_state; ptls->finalizers_inhibited = eh->finalizers_inhibited; diff --git a/src/julia_internal.h b/src/julia_internal.h index b7500f8cf7d16..075dfd812168b 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -70,11 +70,11 @@ STATIC_INLINE jl_value_t *newstruct(jl_datatype_t *type) return jv; } -jl_lambda_info_t *jl_type_infer(jl_lambda_info_t *li, int force); +jl_lambda_info_t *jl_type_infer(jl_lambda_info_t *li, size_t world, int force); void jl_generate_fptr(jl_lambda_info_t *li); -void jl_compile_linfo(jl_lambda_info_t *li); +void jl_compile_linfo(jl_lambda_info_t *li, size_t world); JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types); -jl_lambda_info_t *jl_compile_for_dispatch(jl_lambda_info_t *li); +jl_lambda_info_t *jl_compile_for_dispatch(jl_lambda_info_t *li, size_t world); // invoke (compiling if necessary) the jlcall function pointer for a method jl_lambda_info_t *jl_get_unspecialized(jl_lambda_info_t *method); @@ -82,7 +82,7 @@ STATIC_INLINE jl_value_t *jl_call_method_internal(jl_lambda_info_t *meth, jl_val { jl_lambda_info_t *mfptr = meth; if (__unlikely(mfptr->fptr == NULL)) - mfptr = jl_compile_for_dispatch(mfptr); + mfptr = jl_compile_for_dispatch(mfptr, jl_get_ptls_states()->world_age); if (mfptr->jlcall_api == 0) return mfptr->fptr(args[0], &args[1], nargs-1); else @@ -201,8 +201,8 @@ int jl_is_toplevel_only_expr(jl_value_t *e); jl_value_t *jl_call_scm_on_ast(char *funcname, jl_value_t *expr); jl_lambda_info_t *jl_method_lookup_by_type(jl_methtable_t *mt, jl_tupletype_t *types, - int cache, int inexact); -jl_lambda_info_t *jl_method_lookup(jl_methtable_t *mt, jl_value_t **args, size_t nargs, int cache); + int cache, int inexact, size_t world); +jl_lambda_info_t *jl_method_lookup(jl_methtable_t *mt, jl_value_t **args, size_t nargs, int cache, size_t world); jl_value_t *jl_gf_invoke(jl_tupletype_t *types, jl_value_t **args, size_t nargs); jl_datatype_t *jl_first_argument_datatype(jl_value_t *argtypes); @@ -313,7 +313,7 @@ int32_t jl_get_llvm_gv(jl_value_t *p); void jl_idtable_rehash(jl_array_t **pa, size_t newsz); JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *module); -jl_lambda_info_t *jl_get_specialization1(jl_tupletype_t *types); +jl_lambda_info_t *jl_get_specialization1(jl_tupletype_t *types, size_t world); int jl_has_call_ambiguities(jl_tupletype_t *types, jl_method_t *m); jl_function_t *jl_module_get_initializer(jl_module_t *m); @@ -606,18 +606,18 @@ jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache, jl_value_t *par jl_value_t **overwritten); jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_tupletype_t *types, jl_svec_t **penv, - int8_t subtype_inexact__sigseq_useenv, int8_t subtype, int8_t offs); + int8_t subtype_inexact__sigseq_useenv, int8_t subtype, int8_t offs, size_t world); static jl_typemap_entry_t *const INEXACT_ENTRY = (jl_typemap_entry_t*)(uintptr_t)-1; -jl_typemap_entry_t *jl_typemap_level_assoc_exact(jl_typemap_level_t *cache, jl_value_t **args, size_t n, int8_t offs); -jl_typemap_entry_t *jl_typemap_entry_assoc_exact(jl_typemap_entry_t *mn, jl_value_t **args, size_t n); -STATIC_INLINE jl_typemap_entry_t *jl_typemap_assoc_exact(union jl_typemap_t ml_or_cache, jl_value_t **args, size_t n, int8_t offs) +jl_typemap_entry_t *jl_typemap_level_assoc_exact(jl_typemap_level_t *cache, jl_value_t **args, size_t n, int8_t offs, size_t world); +jl_typemap_entry_t *jl_typemap_entry_assoc_exact(jl_typemap_entry_t *mn, jl_value_t **args, size_t n, size_t world); +STATIC_INLINE jl_typemap_entry_t *jl_typemap_assoc_exact(union jl_typemap_t ml_or_cache, jl_value_t **args, size_t n, int8_t offs, size_t world) { // NOTE: This function is a huge performance hot spot!! if (jl_typeof(ml_or_cache.unknown) == (jl_value_t*)jl_typemap_entry_type) { - return jl_typemap_entry_assoc_exact(ml_or_cache.leaf, args, n); + return jl_typemap_entry_assoc_exact(ml_or_cache.leaf, args, n, world); } else if (jl_typeof(ml_or_cache.unknown) == (jl_value_t*)jl_typemap_level_type) { - return jl_typemap_level_assoc_exact(ml_or_cache.node, args, n, offs); + return jl_typemap_level_assoc_exact(ml_or_cache.node, args, n, offs, world); } return NULL; } diff --git a/src/module.c b/src/module.c index 53f7846fcb1ab..05afd794e6ae0 100644 --- a/src/module.c +++ b/src/module.c @@ -597,7 +597,6 @@ void jl_module_run_initializer(jl_module_t *m) jl_get_ptls_states()->world_age = last_age; } JL_CATCH { - jl_get_ptls_states()->world_age = last_age; if (jl_initerror_type == NULL) { jl_rethrow(); } diff --git a/src/task.c b/src/task.c index eb0bc90b2bfa7..555617aada6d8 100644 --- a/src/task.c +++ b/src/task.c @@ -254,6 +254,7 @@ static void NOINLINE JL_NORETURN start_task(void) jl_gc_wb(t, res); } } + jl_get_ptls_states()->world_age = jl_world_counter; // TODO finish_task(t, res); gc_debug_critical_error(); abort(); diff --git a/src/toplevel.c b/src/toplevel.c index fe56ab3f0952d..38e746ecd979a 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -174,7 +174,6 @@ jl_value_t *jl_eval_module_expr(jl_expr_t *ex) } } JL_CATCH { - ptls->world_age = last_age; ptls->current_module = last_module; ptls->current_task->current_module = task_last_m; outermost = prev_outermost; @@ -543,7 +542,7 @@ jl_value_t *jl_toplevel_eval_flex(jl_value_t *e, int fast, int expanded) thk->specTypes = (jl_tupletype_t*)jl_typeof(jl_emptytuple); // no gc_wb needed if (ewc) { - jl_type_infer(thk, 0); + jl_type_infer(thk, jl_get_ptls_states()->world_age, 0); jl_value_t *dummy_f_arg=NULL; result = jl_call_method_internal(thk, &dummy_f_arg, 1); } diff --git a/src/typemap.c b/src/typemap.c index 1431f05a4bafe..987c30160630b 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -533,11 +533,12 @@ int sigs_eq(jl_value_t *a, jl_value_t *b, int useenv) there tends to be lots of variation there. The type of the 0th argument (the function) is always the same for most functions. */ -static jl_typemap_entry_t *jl_typemap_assoc_by_type_(jl_typemap_entry_t *ml, jl_tupletype_t *types, int8_t inexact, jl_svec_t **penv) +static jl_typemap_entry_t *jl_typemap_assoc_by_type_(jl_typemap_entry_t *ml, jl_tupletype_t *types, + int8_t inexact, jl_svec_t **penv, size_t world) { size_t n = jl_datatype_nfields(types); for (; ml != (void*)jl_nothing; ml = ml->next) { - if (ml->max_world != ~(size_t)0) + if (world < ml->min_world || world > ml->max_world) continue; // ignore replaced methods size_t lensig = jl_datatype_nfields(ml->sig); if (lensig == n || (ml->va && lensig <= n+1)) { @@ -623,14 +624,15 @@ static jl_typemap_entry_t *jl_typemap_assoc_by_type_(jl_typemap_entry_t *ml, jl_ return NULL; } -static jl_typemap_entry_t *jl_typemap_lookup_by_type_(jl_typemap_entry_t *ml, jl_tupletype_t *types, int8_t useenv) +static jl_typemap_entry_t *jl_typemap_lookup_by_type_(jl_typemap_entry_t *ml, jl_tupletype_t *types, int8_t useenv, size_t world) { - while (ml != (void*)jl_nothing) { + for (; ml != (void*)jl_nothing; ml = ml->next) { + if (world < ml->min_world || world > ml->max_world) + continue; // TODO: more efficient if (sigs_eq((jl_value_t*)types, (jl_value_t*)ml->sig, useenv)) { return ml; } - ml = ml->next; } return NULL; } @@ -639,7 +641,7 @@ static jl_typemap_entry_t *jl_typemap_lookup_by_type_(jl_typemap_entry_t *ml, jl // this is the general entry point for looking up a type in the cache // (as a subtype, or with typeseq) jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_tupletype_t *types, jl_svec_t **penv, - int8_t subtype_inexact__sigseq_useenv, int8_t subtype, int8_t offs) + int8_t subtype_inexact__sigseq_useenv, int8_t subtype, int8_t offs, size_t world) { if (jl_typeof(ml_or_cache.unknown) == (jl_value_t*)jl_typemap_level_type) { jl_typemap_level_t *cache = ml_or_cache.node; @@ -664,7 +666,7 @@ jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_ // If there is a type at offs, look in the optimized caches if (!subtype) { if (ty && jl_is_any(ty)) - return jl_typemap_assoc_by_type(cache->any, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1); + return jl_typemap_assoc_by_type(cache->any, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1, world); if (isva) // in lookup mode, want to match Vararg exactly, not as a subtype ty = NULL; } @@ -675,7 +677,7 @@ jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_ union jl_typemap_t ml = mtcache_hash_lookup(cache->targ, a0, 1, offs); if (ml.unknown != jl_nothing) { jl_typemap_entry_t *li = jl_typemap_assoc_by_type(ml, types, penv, - subtype_inexact__sigseq_useenv, subtype, offs+1); + subtype_inexact__sigseq_useenv, subtype, offs+1, world); if (li) return li; } } @@ -685,7 +687,7 @@ jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_ union jl_typemap_t ml = mtcache_hash_lookup(cache->arg1, ty, 0, offs); if (ml.unknown != jl_nothing) { jl_typemap_entry_t *li = jl_typemap_assoc_by_type(ml, types, penv, - subtype_inexact__sigseq_useenv, subtype, offs+1); + subtype_inexact__sigseq_useenv, subtype, offs+1, world); if (li) return li; } } @@ -693,51 +695,52 @@ jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_ } // Always check the list (since offs doesn't always start at 0) if (subtype) { - jl_typemap_entry_t *li = jl_typemap_assoc_by_type_(cache->linear, types, subtype_inexact__sigseq_useenv, penv); + jl_typemap_entry_t *li = jl_typemap_assoc_by_type_(cache->linear, types, subtype_inexact__sigseq_useenv, penv, world); if (li) return li; - return jl_typemap_assoc_by_type(cache->any, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1); + return jl_typemap_assoc_by_type(cache->any, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1, world); } else { - return jl_typemap_lookup_by_type_(cache->linear, types, subtype_inexact__sigseq_useenv); + return jl_typemap_lookup_by_type_(cache->linear, types, subtype_inexact__sigseq_useenv, world); } } else { return subtype ? - jl_typemap_assoc_by_type_(ml_or_cache.leaf, types, subtype_inexact__sigseq_useenv, penv) : - jl_typemap_lookup_by_type_(ml_or_cache.leaf, types, subtype_inexact__sigseq_useenv); + jl_typemap_assoc_by_type_(ml_or_cache.leaf, types, subtype_inexact__sigseq_useenv, penv, world) : + jl_typemap_lookup_by_type_(ml_or_cache.leaf, types, subtype_inexact__sigseq_useenv, world); } } -jl_typemap_entry_t *jl_typemap_entry_assoc_exact(jl_typemap_entry_t *ml, jl_value_t **args, size_t n) +jl_typemap_entry_t *jl_typemap_entry_assoc_exact(jl_typemap_entry_t *ml, jl_value_t **args, size_t n, size_t world) { // some manually-unrolled common special cases while (ml->simplesig == (void*)jl_nothing && ml->guardsigs == jl_emptysvec && ml->isleafsig) { // use a tight loop for a long as possible - if (ml->max_world == ~(size_t)0 && n == jl_datatype_nfields(ml->sig) && jl_typeof(args[0]) == jl_tparam(ml->sig, 0)) { - if (n == 1) - return ml; - if (n == 2) { - if (jl_typeof(args[1]) == jl_tparam(ml->sig, 1)) - return ml; - } - else if (n == 3) { - if (jl_typeof(args[1]) == jl_tparam(ml->sig, 1) && - jl_typeof(args[2]) == jl_tparam(ml->sig, 2)) - return ml; - } - else { - if (sig_match_leaf(args, jl_svec_data(ml->sig->parameters), n)) + if (world >= ml->min_world && world <= ml->max_world) + if (n == jl_datatype_nfields(ml->sig) && jl_typeof(args[0]) == jl_tparam(ml->sig, 0)) { + if (n == 1) return ml; + if (n == 2) { + if (jl_typeof(args[1]) == jl_tparam(ml->sig, 1)) + return ml; + } + else if (n == 3) { + if (jl_typeof(args[1]) == jl_tparam(ml->sig, 1) && + jl_typeof(args[2]) == jl_tparam(ml->sig, 2)) + return ml; + } + else { + if (sig_match_leaf(args, jl_svec_data(ml->sig->parameters), n)) + return ml; + } } - } ml = ml->next; if (ml == (void*)jl_nothing) return NULL; } - while (ml != (void*)jl_nothing) { - if (ml->max_world != ~(size_t)0) - goto nomatch; // ignore replaced methods + for (; ml != (void*)jl_nothing; ml = ml->next) { + if (world < ml->min_world || world > ml->max_world) + continue; // ignore replaced methods size_t lensig = jl_datatype_nfields(ml->sig); if (lensig == n || (ml->va && lensig <= n+1)) { if (ml->simplesig != (void*)jl_nothing) { @@ -745,24 +748,24 @@ jl_typemap_entry_t *jl_typemap_entry_assoc_exact(jl_typemap_entry_t *ml, jl_valu int isva = lensimplesig > 0 && jl_is_vararg_type(jl_tparam(ml->simplesig, lensimplesig - 1)); if (lensig == n || (isva && lensimplesig <= n + 1)) { if (!sig_match_simple(args, n, jl_svec_data(ml->simplesig->parameters), isva, lensimplesig)) - goto nomatch; + continue; } else { - goto nomatch; + continue; } } if (ml->isleafsig) { if (!sig_match_leaf(args, jl_svec_data(ml->sig->parameters), n)) - goto nomatch; + continue; } else if (ml->issimplesig) { if (!sig_match_simple(args, n, jl_svec_data(ml->sig->parameters), ml->va, lensig)) - goto nomatch; + continue; } else { if (!jl_tuple_subtype(args, n, ml->sig, 1)) - goto nomatch; + continue; } size_t i, l; @@ -777,14 +780,14 @@ jl_typemap_entry_t *jl_typemap_entry_assoc_exact(jl_typemap_entry_t *ml, jl_valu } } return ml; - } nomatch: - ml = ml->next; + continue; + } } return NULL; } -jl_typemap_entry_t *jl_typemap_level_assoc_exact(jl_typemap_level_t *cache, jl_value_t **args, size_t n, int8_t offs) +jl_typemap_entry_t *jl_typemap_level_assoc_exact(jl_typemap_level_t *cache, jl_value_t **args, size_t n, int8_t offs, size_t world) { if (n > offs) { jl_value_t *a1 = args[offs]; @@ -792,21 +795,21 @@ jl_typemap_entry_t *jl_typemap_level_assoc_exact(jl_typemap_level_t *cache, jl_v assert(jl_is_datatype(ty)); if (ty == (jl_value_t*)jl_datatype_type && cache->targ != (void*)jl_nothing) { union jl_typemap_t ml_or_cache = mtcache_hash_lookup(cache->targ, a1, 1, offs); - jl_typemap_entry_t *ml = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1); + jl_typemap_entry_t *ml = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1, world); if (ml) return ml; } if (cache->arg1 != (void*)jl_nothing) { union jl_typemap_t ml_or_cache = mtcache_hash_lookup(cache->arg1, ty, 0, offs); - jl_typemap_entry_t *ml = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1); + jl_typemap_entry_t *ml = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1, world); if (ml) return ml; } } if (jl_typeof(cache->linear) != (jl_value_t*)jl_nothing) { - jl_typemap_entry_t *ml = jl_typemap_entry_assoc_exact(cache->linear, args, n); + jl_typemap_entry_t *ml = jl_typemap_entry_assoc_exact(cache->linear, args, n, world); if (ml) return ml; } if (jl_typeof(cache->any.unknown) != (jl_value_t*)jl_nothing) - return jl_typemap_assoc_exact(cache->any, args, n, offs+1); + return jl_typemap_assoc_exact(cache->any, args, n, offs+1, world); return NULL; } @@ -953,9 +956,9 @@ jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache, jl_value_t *par } if ((jl_value_t*)simpletype == jl_nothing) { - jl_typemap_entry_t *ml = jl_typemap_assoc_by_type(*cache, type, NULL, 1, 0, offs); + jl_typemap_entry_t *ml = jl_typemap_assoc_by_type(*cache, type, NULL, 1, 0, offs, min_world); if (ml && ml->simplesig == (void*)jl_nothing) { - if (newvalue == ml->func.value) // no change + if (newvalue == ml->func.value) // no change. TODO: involve world in computation return ml; if (overwritten != NULL) *overwritten = ml->func.value; diff --git a/test/loading.jl b/test/loading.jl index b7687d65d71e8..cadf484aceb2e 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -8,7 +8,8 @@ using Base.Test include("test_sourcepath.jl") thefname = "the fname!//\\&\0\1*" -@test include_string("include_string_test() = @__FILE__", thefname)() == Base.source_path() +include_string_test_func = include_string("include_string_test() = @__FILE__", thefname) +@test include_string_test_func() == Base.source_path() @test include_string("Base.source_path()", thefname) == Base.source_path() @test basename(@__FILE__) == "loading.jl" @test isabspath(@__FILE__) diff --git a/test/runtests.jl b/test/runtests.jl index 4fef9b34cfbf2..53114f4cc342a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -77,7 +77,7 @@ cd(dirname(@__FILE__)) do for t in node1_tests n > 1 && print("\tFrom worker 1:\t") - runtests(t) + eval(Expr(:call, () -> runtests(t))) # runtests is defined by the include above end println(" \033[32;1mSUCCESS\033[0m") diff --git a/test/staged.jl b/test/staged.jl index 8f064b56b5e3a..2a2633b96de76 100644 --- a/test/staged.jl +++ b/test/staged.jl @@ -154,7 +154,7 @@ end # @generated functions including inner functions @generated function _g_f_with_inner(x) - :(y->y) + return y -> y end @test (_g_f_with_inner(1))(8) == 8 diff --git a/ui/repl.c b/ui/repl.c index c7f391a8189b4..2c393695c4900 100644 --- a/ui/repl.c +++ b/ui/repl.c @@ -547,7 +547,10 @@ static NOINLINE int true_main(int argc, char *argv[]) (jl_function_t*)jl_get_global(jl_base_module, jl_symbol("_start")) : NULL; if (start_client) { + size_t last_age = jl_get_ptls_states()->world_age; + jl_get_ptls_states()->world_age = jl_get_world_counter(); jl_apply(&start_client, 1); + jl_get_ptls_states()->world_age = last_age; return 0; }