diff --git a/base/Base.jl b/base/Base.jl index 58d527f365aa7..85a9c8d5048e3 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -478,7 +478,7 @@ in_sysimage(pkgid::PkgId) = pkgid in _sysimage_modules for match = _methods(+, (Int, Int), -1, get_world_counter()) m = match.method delete!(push!(Set{Method}(), m), m) - copy(Core.Compiler.retrieve_code_info(Core.Compiler.specialize_method(match), typemax(UInt))) + copy(Core.Compiler.retrieve_code_info(Core.Compiler.specialize_method(match))) empty!(Set()) push!(push!(Set{Union{GlobalRef,Symbol}}(), :two), GlobalRef(Base, :two)) diff --git a/base/boot.jl b/base/boot.jl index ca6e6c81405e2..b4e01b0c884c1 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -590,25 +590,28 @@ println(@nospecialize a...) = println(stdout, a...) struct GeneratedFunctionStub gen - argnames::SimpleVector - spnames::SimpleVector + argnames::Array{Any,1} + spnames::Union{Nothing, Array{Any,1}} + line::Int + file::Symbol + expand_early::Bool end -# invoke and wrap the results of @generated expression -function (g::GeneratedFunctionStub)(world::UInt, source::LineNumberNode, @nospecialize args...) - # args is (spvals..., argtypes...) +# invoke and wrap the results of @generated +function (g::GeneratedFunctionStub)(@nospecialize args...) body = g.gen(args...) - file = source.file - file isa Symbol || (file = :none) - lam = Expr(:lambda, Expr(:argnames, g.argnames...).args, - Expr(:var"scope-block", + if body isa CodeInfo + return body + end + lam = Expr(:lambda, g.argnames, + Expr(Symbol("scope-block"), Expr(:block, - source, - Expr(:meta, :push_loc, file, :var"@generated body"), + LineNumberNode(g.line, g.file), + Expr(:meta, :push_loc, g.file, Symbol("@generated body")), Expr(:return, body), Expr(:meta, :pop_loc)))) spnames = g.spnames - if spnames === svec() + if spnames === nothing return lam else return Expr(Symbol("with-static-parameters"), lam, spnames...) diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 5fac62eb7578d..0d0280e40e817 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -569,7 +569,7 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp break end topmost === nothing || continue - if edge_matches_sv(interp, infstate, method, sig, sparams, hardlimit, sv) + if edge_matches_sv(infstate, method, sig, sparams, hardlimit, sv) topmost = infstate edgecycle = true end @@ -677,13 +677,12 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp return MethodCallResult(rt, edgecycle, edgelimited, edge, effects) end -function edge_matches_sv(interp::AbstractInterpreter, frame::InferenceState, method::Method, @nospecialize(sig), sparams::SimpleVector, hardlimit::Bool, sv::InferenceState) +function edge_matches_sv(frame::InferenceState, method::Method, @nospecialize(sig), sparams::SimpleVector, hardlimit::Bool, sv::InferenceState) # The `method_for_inference_heuristics` will expand the given method's generator if # necessary in order to retrieve this field from the generated `CodeInfo`, if it exists. # The other `CodeInfo`s we inspect will already have this field inflated, so we just # access it directly instead (to avoid regeneration). - world = get_world_counter(interp) - callee_method2 = method_for_inference_heuristics(method, sig, sparams, world) # Union{Method, Nothing} + callee_method2 = method_for_inference_heuristics(method, sig, sparams) # Union{Method, Nothing} inf_method2 = frame.src.method_for_inference_limit_heuristics # limit only if user token match inf_method2 isa Method || (inf_method2 = nothing) @@ -720,11 +719,11 @@ function edge_matches_sv(interp::AbstractInterpreter, frame::InferenceState, met end # This function is used for computing alternate limit heuristics -function method_for_inference_heuristics(method::Method, @nospecialize(sig), sparams::SimpleVector, world::UInt) - if isdefined(method, :generator) && !(method.generator isa Core.GeneratedFunctionStub) && may_invoke_generator(method, sig, sparams) +function method_for_inference_heuristics(method::Method, @nospecialize(sig), sparams::SimpleVector) + if isdefined(method, :generator) && method.generator.expand_early && may_invoke_generator(method, sig, sparams) method_instance = specialize_method(method, sig, sparams) if isa(method_instance, MethodInstance) - cinfo = get_staged(method_instance, world) + cinfo = get_staged(method_instance) if isa(cinfo, CodeInfo) method2 = cinfo.method_for_inference_limit_heuristics if method2 isa Method diff --git a/base/compiler/bootstrap.jl b/base/compiler/bootstrap.jl index 1f62d21c9d2d9..77b36cb9c7f71 100644 --- a/base/compiler/bootstrap.jl +++ b/base/compiler/bootstrap.jl @@ -36,7 +36,7 @@ let interp = NativeInterpreter() else tt = Tuple{typeof(f), Vararg{Any}} end - for m in _methods_by_ftype(tt, 10, get_world_counter())::Vector + for m in _methods_by_ftype(tt, 10, typemax(UInt))::Vector # remove any TypeVars from the intersection m = m::MethodMatch typ = Any[m.spec_types.parameters...] diff --git a/base/compiler/inferencestate.jl b/base/compiler/inferencestate.jl index 959d2d157f219..7ff740a23a540 100644 --- a/base/compiler/inferencestate.jl +++ b/base/compiler/inferencestate.jl @@ -363,8 +363,7 @@ end function InferenceState(result::InferenceResult, cache::Symbol, interp::AbstractInterpreter) # prepare an InferenceState object for inferring lambda - world = get_world_counter(interp) - src = retrieve_code_info(result.linfo, world) + src = retrieve_code_info(result.linfo) src === nothing && return nothing validate_code_in_debug_mode(result.linfo, src, "lowered") return InferenceState(result, src, cache, interp) diff --git a/base/compiler/optimize.jl b/base/compiler/optimize.jl index edf678e919b61..dc321be5108cf 100644 --- a/base/compiler/optimize.jl +++ b/base/compiler/optimize.jl @@ -183,8 +183,7 @@ function OptimizationState(linfo::MethodInstance, src::CodeInfo, params::Optimiz return OptimizationState(linfo, src, nothing, stmt_info, mod, sptypes, slottypes, inlining, nothing, false) end function OptimizationState(linfo::MethodInstance, params::OptimizationParams, interp::AbstractInterpreter) - world = get_world_counter(interp) - src = retrieve_code_info(linfo, world) + src = retrieve_code_info(linfo) src === nothing && return nothing return OptimizationState(linfo, src, params, interp) end diff --git a/base/compiler/typeinfer.jl b/base/compiler/typeinfer.jl index 734c357201d25..f7723a968da3e 100644 --- a/base/compiler/typeinfer.jl +++ b/base/compiler/typeinfer.jl @@ -1035,7 +1035,7 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance) end end if ccall(:jl_get_module_infer, Cint, (Any,), method.module) == 0 && !generating_sysimg() - return retrieve_code_info(mi, get_world_counter(interp)) + return retrieve_code_info(mi) end lock_mi_inference(interp, mi) result = InferenceResult(mi, typeinf_lattice(interp)) diff --git a/base/compiler/types.jl b/base/compiler/types.jl index 7bdbdbd8bdf01..cac15e9a69513 100644 --- a/base/compiler/types.jl +++ b/base/compiler/types.jl @@ -330,7 +330,7 @@ struct NativeInterpreter <: AbstractInterpreter cache = Vector{InferenceResult}() # Initially empty cache # Sometimes the caller is lazy and passes typemax(UInt). - # we cap it to the current world age for correctness + # we cap it to the current world age if world == typemax(UInt) world = get_world_counter() end diff --git a/base/compiler/utilities.jl b/base/compiler/utilities.jl index 0acbc926ae671..6cf600560902d 100644 --- a/base/compiler/utilities.jl +++ b/base/compiler/utilities.jl @@ -114,23 +114,23 @@ end invoke_api(li::CodeInstance) = ccall(:jl_invoke_api, Cint, (Any,), li) use_const_api(li::CodeInstance) = invoke_api(li) == 2 -function get_staged(mi::MethodInstance, world::UInt) +function get_staged(mi::MethodInstance) may_invoke_generator(mi) || return nothing try # user code might throw errors – ignore them - ci = ccall(:jl_code_for_staged, Any, (Any, UInt), mi, world)::CodeInfo + ci = ccall(:jl_code_for_staged, Any, (Any,), mi)::CodeInfo return ci catch return nothing end end -function retrieve_code_info(linfo::MethodInstance, world::UInt) +function retrieve_code_info(linfo::MethodInstance) m = linfo.def::Method c = nothing if isdefined(m, :generator) # user code might throw errors – ignore them - c = get_staged(linfo, world) + c = get_staged(linfo) end if c === nothing && isdefined(m, :source) src = m.source diff --git a/base/compiler/validation.jl b/base/compiler/validation.jl index 68eb2ab15c59d..22a21a4559985 100644 --- a/base/compiler/validation.jl +++ b/base/compiler/validation.jl @@ -200,14 +200,15 @@ end """ validate_code!(errors::Vector{InvalidCodeError}, mi::MethodInstance, - c::Union{Nothing,CodeInfo}) + c::Union{Nothing,CodeInfo} = Core.Compiler.retrieve_code_info(mi)) Validate `mi`, logging any violation by pushing an `InvalidCodeError` into `errors`. If `isa(c, CodeInfo)`, also call `validate_code!(errors, c)`. It is assumed that `c` is -a `CodeInfo` instance associated with `mi`. +the `CodeInfo` instance associated with `mi`. """ -function validate_code!(errors::Vector{InvalidCodeError}, mi::Core.MethodInstance, c::Union{Nothing,CodeInfo}) +function validate_code!(errors::Vector{InvalidCodeError}, mi::Core.MethodInstance, + c::Union{Nothing,CodeInfo} = Core.Compiler.retrieve_code_info(mi)) is_top_level = mi.def isa Module if is_top_level mnargs = 0 diff --git a/base/expr.jl b/base/expr.jl index 5649303b41ef4..46e89bf64da8a 100644 --- a/base/expr.jl +++ b/base/expr.jl @@ -962,7 +962,10 @@ macro generated(f) Expr(:block, lno, Expr(:if, Expr(:generated), - body, + # https://github.com/JuliaLang/julia/issues/25678 + Expr(:block, + :(local $tmp = $body), + :(if $tmp isa $(GlobalRef(Core, :CodeInfo)); return $tmp; else $tmp; end)), Expr(:block, Expr(:meta, :generated_only), Expr(:return, nothing)))))) diff --git a/base/reflection.jl b/base/reflection.jl index bb7dfc0f0cf00..9e2615a16a190 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -961,11 +961,10 @@ function code_lowered(@nospecialize(f), @nospecialize(t=Tuple); generated::Bool= if debuginfo !== :source && debuginfo !== :none throw(ArgumentError("'debuginfo' must be either :source or :none")) end - world = get_world_counter() - return map(method_instances(f, t, world)) do m + return map(method_instances(f, t)) do m if generated && hasgenerator(m) if may_invoke_generator(m) - return ccall(:jl_code_for_staged, Any, (Any, UInt), m, world)::CodeInfo + return ccall(:jl_code_for_staged, Any, (Any,), m)::CodeInfo else error("Could not expand generator for `@generated` method ", m, ". ", "This can happen if the provided argument types (", t, ") are ", @@ -1054,8 +1053,6 @@ methods(@nospecialize(f), @nospecialize(t), mod::Module) = methods(f, t, (mod,)) function methods_including_ambiguous(@nospecialize(f), @nospecialize(t)) tt = signature_type(f, t) world = get_world_counter() - (ccall(:jl_is_in_pure_context, Bool, ()) || world == typemax(UInt)) && - error("code reflection cannot be used from generated functions") min = RefValue{UInt}(typemin(UInt)) max = RefValue{UInt}(typemax(UInt)) ms = _methods_by_ftype(tt, nothing, -1, world, true, min, max, Ptr{Int32}(C_NULL))::Vector @@ -1128,11 +1125,9 @@ _uncompressed_ir(ci::Core.CodeInstance, s::Array{UInt8,1}) = ccall(:jl_uncompres const uncompressed_ast = uncompressed_ir const _uncompressed_ast = _uncompressed_ir -function method_instances(@nospecialize(f), @nospecialize(t), world::UInt) +function method_instances(@nospecialize(f), @nospecialize(t), world::UInt=get_world_counter()) tt = signature_type(f, t) results = Core.MethodInstance[] - # this make a better error message than the typeassert that follows - world == typemax(UInt) && error("code reflection cannot be used from generated functions") for match in _methods_by_ftype(tt, -1, world)::Vector instance = Core.Compiler.specialize_method(match) push!(results, instance) @@ -1203,22 +1198,20 @@ function may_invoke_generator(method::Method, @nospecialize(atype), sparams::Sim # generator only has one method generator = method.generator isa(generator, Core.GeneratedFunctionStub) || return false - gen_mthds = _methods_by_ftype(Tuple{typeof(generator.gen), Vararg{Any}}, 1, method.primary_world) - (gen_mthds isa Vector && length(gen_mthds) == 1) || return false + gen_mthds = methods(generator.gen)::MethodList + length(gen_mthds) == 1 || return false - generator_method = first(gen_mthds).method + generator_method = first(gen_mthds) nsparams = length(sparams) isdefined(generator_method, :source) || return false code = generator_method.source nslots = ccall(:jl_ir_nslots, Int, (Any,), code) - at = unwrap_unionall(atype) - at isa DataType || return false + at = unwrap_unionall(atype)::DataType (nslots >= 1 + length(sparams) + length(at.parameters)) || return false - firstarg = 1 for i = 1:nsparams if isa(sparams[i], TypeVar) - if (ast_slotflag(code, firstarg + i) & SLOT_USED) != 0 + if (ast_slotflag(code, 1 + i) & SLOT_USED) != 0 return false end end @@ -1227,7 +1220,7 @@ function may_invoke_generator(method::Method, @nospecialize(atype), sparams::Sim non_va_args = method.isva ? nargs - 1 : nargs for i = 1:non_va_args if !isdispatchelem(at.parameters[i]) - if (ast_slotflag(code, firstarg + i + nsparams) & SLOT_USED) != 0 + if (ast_slotflag(code, 1 + i + nsparams) & SLOT_USED) != 0 return false end end @@ -1235,7 +1228,7 @@ function may_invoke_generator(method::Method, @nospecialize(atype), sparams::Sim if method.isva # If the va argument is used, we need to ensure that all arguments that # contribute to the va tuple are dispatchelemes - if (ast_slotflag(code, firstarg + nargs + nsparams) & SLOT_USED) != 0 + if (ast_slotflag(code, 1 + nargs + nsparams) & SLOT_USED) != 0 for i = (non_va_args+1):length(at.parameters) if !isdispatchelem(at.parameters[i]) return false @@ -1325,8 +1318,7 @@ function code_typed_by_type(@nospecialize(tt::Type); debuginfo::Symbol=:default, world = get_world_counter(), interp = Core.Compiler.NativeInterpreter(world)) - (ccall(:jl_is_in_pure_context, Bool, ()) || world == typemax(UInt)) && - error("code reflection cannot be used from generated functions") + ccall(:jl_is_in_pure_context, Bool, ()) && error("code reflection cannot be used from generated functions") if @isdefined(IRShow) debuginfo = IRShow.debuginfo(debuginfo) elseif debuginfo === :default @@ -1435,7 +1427,7 @@ function code_ircode_by_type( interp = Core.Compiler.NativeInterpreter(world), optimize_until::Union{Integer,AbstractString,Nothing} = nothing, ) - (ccall(:jl_is_in_pure_context, Bool, ()) || world == typemax(UInt)) && + ccall(:jl_is_in_pure_context, Bool, ()) && error("code reflection cannot be used from generated functions") tt = to_tuple_type(tt) matches = _methods_by_ftype(tt, -1, world)::Vector @@ -1462,8 +1454,7 @@ end function return_types(@nospecialize(f), @nospecialize(types=default_tt(f)); world = get_world_counter(), interp = Core.Compiler.NativeInterpreter(world)) - (ccall(:jl_is_in_pure_context, Bool, ()) || world == typemax(UInt)) && - error("code reflection cannot be used from generated functions") + ccall(:jl_is_in_pure_context, Bool, ()) && error("code reflection cannot be used from generated functions") if isa(f, Core.OpaqueClosure) _, rt = only(code_typed_opaque_closure(f)) return Any[rt] @@ -1487,8 +1478,7 @@ end function infer_effects(@nospecialize(f), @nospecialize(types=default_tt(f)); world = get_world_counter(), interp = Core.Compiler.NativeInterpreter(world)) - (ccall(:jl_is_in_pure_context, Bool, ()) || world == typemax(UInt)) && - error("code reflection cannot be used from generated functions") + ccall(:jl_is_in_pure_context, Bool, ()) && error("code reflection cannot be used from generated functions") if isa(f, Core.Builtin) types = to_tuple_type(types) argtypes = Any[Core.Compiler.Const(f), types.parameters...] diff --git a/doc/src/devdocs/ast.md b/doc/src/devdocs/ast.md index 76b0cc97df5bf..df6a2224c2a48 100644 --- a/doc/src/devdocs/ast.md +++ b/doc/src/devdocs/ast.md @@ -685,10 +685,10 @@ A (usually temporary) container for holding lowered source code. A `UInt8` array of slot properties, represented as bit flags: - * 0x02 - assigned (only false if there are *no* assignment statements with this var on the left) - * 0x08 - used (if there is any read or write of the slot) - * 0x10 - statically assigned once - * 0x20 - might be used before assigned. This flag is only valid after type inference. + * 2 - assigned (only false if there are *no* assignment statements with this var on the left) + * 8 - const (currently unused for local variables) + * 16 - statically assigned once + * 32 - might be used before assigned. This flag is only valid after type inference. * `ssavaluetypes` diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 866d9dabe5100..d1694eaf9e0d5 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -1088,7 +1088,7 @@ void jl_get_llvmf_defn_impl(jl_llvmf_dump_t* dump, jl_method_instance_t *mi, siz if (src) jlrettype = src->rettype; else if (jl_is_method(mi->def.method)) { - src = mi->def.method->generator ? jl_code_for_staged(mi, world) : (jl_code_info_t*)mi->def.method->source; + src = mi->def.method->generator ? jl_code_for_staged(mi) : (jl_code_info_t*)mi->def.method->source; if (src && !jl_is_code_info(src) && jl_is_method(mi->def.method)) src = jl_uncompress_ir(mi->def.method, NULL, (jl_array_t*)src); } diff --git a/src/ast.c b/src/ast.c index 3f3d6176d342e..cb03b7efb6eb7 100644 --- a/src/ast.c +++ b/src/ast.c @@ -1024,10 +1024,10 @@ static jl_value_t *jl_invoke_julia_macro(jl_array_t *args, jl_module_t *inmodule jl_value_t *result; JL_TRY { margs[0] = jl_toplevel_eval(*ctx, margs[0]); - jl_method_instance_t *mfunc = jl_method_lookup(margs, nargs, ct->world_age); + jl_method_instance_t *mfunc = jl_method_lookup(margs, nargs, world); JL_GC_PROMISE_ROOTED(mfunc); if (mfunc == NULL) { - jl_method_error(margs[0], &margs[1], nargs, ct->world_age); + jl_method_error(margs[0], &margs[1], nargs, world); // unreachable } *ctx = mfunc->def.method->module; diff --git a/src/gf.c b/src/gf.c index d8c5e571e820f..42990baf7ad24 100644 --- a/src/gf.c +++ b/src/gf.c @@ -27,9 +27,6 @@ extern "C" { JL_DLLEXPORT _Atomic(size_t) jl_world_counter = 1; // uses atomic acquire/release JL_DLLEXPORT size_t jl_get_world_counter(void) JL_NOTSAFEPOINT { - jl_task_t *ct = jl_current_task; - if (ct->ptls->in_pure_callback) - return ~(size_t)0; return jl_atomic_load_acquire(&jl_world_counter); } @@ -2299,7 +2296,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t // if that didn't work and compilation is off, try running in the interpreter if (compile_option == JL_OPTIONS_COMPILE_OFF || compile_option == JL_OPTIONS_COMPILE_MIN) { - jl_code_info_t *src = jl_code_for_interpreter(mi, world); + jl_code_info_t *src = jl_code_for_interpreter(mi); if (!jl_code_requires_compiler(src, 0)) { jl_code_instance_t *codeinst = jl_new_codeinst(mi, (jl_value_t*)jl_any_type, NULL, NULL, @@ -3142,8 +3139,6 @@ static jl_value_t *ml_matches(jl_methtable_t *mt, int intersections, size_t world, int cache_result, size_t *min_valid, size_t *max_valid, int *ambig) { - if (world > jl_atomic_load_acquire(&jl_world_counter)) - return jl_nothing; // the future is not enumerable int has_ambiguity = 0; jl_value_t *unw = jl_unwrap_unionall((jl_value_t*)type); assert(jl_is_datatype(unw)); diff --git a/src/interpreter.c b/src/interpreter.c index 713887f234898..08cb87791c5a3 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -626,7 +626,7 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, size_t ip, // preparing method IR for interpreter -jl_code_info_t *jl_code_for_interpreter(jl_method_instance_t *mi, size_t world) +jl_code_info_t *jl_code_for_interpreter(jl_method_instance_t *mi) { jl_code_info_t *src = (jl_code_info_t*)jl_atomic_load_relaxed(&mi->uninferred); if (jl_is_method(mi->def.value)) { @@ -636,7 +636,7 @@ jl_code_info_t *jl_code_for_interpreter(jl_method_instance_t *mi, size_t world) } else { assert(mi->def.method->generator); - src = jl_code_for_staged(mi, world); + src = jl_code_for_staged(mi); } } if (src && (jl_value_t*)src != jl_nothing) { @@ -659,9 +659,7 @@ jl_value_t *NOINLINE jl_fptr_interpret_call(jl_value_t *f, jl_value_t **args, ui { interpreter_state *s; jl_method_instance_t *mi = codeinst->def; - jl_task_t *ct = jl_current_task; - size_t world = ct->world_age; - jl_code_info_t *src = jl_code_for_interpreter(mi, world); + jl_code_info_t *src = jl_code_for_interpreter(mi); jl_array_t *stmts = src->code; assert(jl_typeis(stmts, jl_array_any_type)); unsigned nroots = jl_source_nslots(src) + jl_source_nssavalues(src) + 2; diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 940613fd596f4..b489665f5629d 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -499,7 +499,7 @@ void jl_generate_fptr_for_unspecialized_impl(jl_code_instance_t *unspec) // TODO: this is wrong assert(def->generator); // TODO: jl_code_for_staged can throw - src = jl_code_for_staged(unspec->def, unspec->min_world); + src = jl_code_for_staged(unspec->def); } if (src && (jl_value_t*)src != jl_nothing) src = jl_uncompress_ir(def, NULL, (jl_array_t*)src); @@ -554,7 +554,7 @@ jl_value_t *jl_dump_method_asm_impl(jl_method_instance_t *mi, size_t world, if (jl_is_method(def)) { if (!src) { // TODO: jl_code_for_staged can throw - src = def->generator ? jl_code_for_staged(mi, world) : (jl_code_info_t*)def->source; + src = def->generator ? jl_code_for_staged(mi) : (jl_code_info_t*)def->source; } if (src && (jl_value_t*)src != jl_nothing) src = jl_uncompress_ir(mi->def.method, codeinst, (jl_array_t*)src); diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 2a4e95ab1da86..4a0407e019432 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -382,8 +382,13 @@ `((meta generated (new (core GeneratedFunctionStub) ,gname - (call (core svec) ,@(map quotify anames)) - (call (core svec) ,@(map quotify names))))))) + ,(cons 'list anames) + ,(if (null? sparams) + 'nothing + (cons 'list (map car sparams))) + ,(cadr loc) + (inert ,(caddr loc)) + (false)))))) (list gf)) '())) (types (llist-types argl)) diff --git a/src/julia.h b/src/julia.h index 083e4ef2eab02..19dab5cd3a704 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1495,7 +1495,7 @@ JL_DLLEXPORT jl_value_t *jl_generic_function_def(jl_sym_t *name, _Atomic(jl_value_t*) *bp, jl_binding_t *bnd); JL_DLLEXPORT jl_method_t *jl_method_def(jl_svec_t *argdata, jl_methtable_t *mt, jl_code_info_t *f, jl_module_t *module); -JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo, size_t world); +JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo); JL_DLLEXPORT jl_code_info_t *jl_copy_code_info(jl_code_info_t *src); JL_DLLEXPORT size_t jl_get_world_counter(void) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_box_bool(int8_t x) JL_NOTSAFEPOINT; diff --git a/src/julia_internal.h b/src/julia_internal.h index 492c0ec8a8984..b77de64732116 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -621,7 +621,7 @@ jl_method_instance_t *jl_get_unspecialized(jl_method_t *def JL_PROPAGATES_ROOT); JL_DLLEXPORT void jl_compile_method_instance(jl_method_instance_t *mi, jl_tupletype_t *types, size_t world); JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types); -jl_code_info_t *jl_code_for_interpreter(jl_method_instance_t *lam JL_PROPAGATES_ROOT, size_t world); +jl_code_info_t *jl_code_for_interpreter(jl_method_instance_t *lam JL_PROPAGATES_ROOT); int jl_code_requires_compiler(jl_code_info_t *src, int include_force_compile); jl_code_info_t *jl_new_code_info_from_ir(jl_expr_t *ast); JL_DLLEXPORT jl_code_info_t *jl_new_code_info_uninit(void); diff --git a/src/method.c b/src/method.c index 64bec989251a8..d5f56a5921358 100644 --- a/src/method.c +++ b/src/method.c @@ -517,21 +517,21 @@ void jl_add_function_name_to_lineinfo(jl_code_info_t *ci, jl_value_t *name) } // invoke (compiling if necessary) the jlcall function pointer for a method template -static jl_value_t *jl_call_staged(jl_method_t *def, jl_value_t *generator, - size_t world, jl_svec_t *sparam_vals, jl_value_t **args, uint32_t nargs) +STATIC_INLINE jl_value_t *jl_call_staged(jl_method_t *def, jl_value_t *generator, jl_svec_t *sparam_vals, + jl_value_t **args, uint32_t nargs) { size_t n_sparams = jl_svec_len(sparam_vals); jl_value_t **gargs; - size_t totargs = 2 + n_sparams + def->nargs; + size_t totargs = 1 + n_sparams + nargs + def->isva; JL_GC_PUSHARGS(gargs, totargs); - gargs[0] = jl_box_ulong(world); - gargs[1] = jl_box_long(def->line); - gargs[1] = jl_new_struct(jl_linenumbernode_type, gargs[1], def->file); - memcpy(&gargs[2], jl_svec_data(sparam_vals), n_sparams * sizeof(void*)); - memcpy(&gargs[2 + n_sparams], args, (def->nargs - def->isva) * sizeof(void*)); - if (def->isva) - gargs[totargs - 1] = jl_f_tuple(NULL, &args[def->nargs - 1], nargs - def->nargs + 1); - jl_value_t *code = jl_apply_generic(generator, gargs, totargs); + gargs[0] = generator; + memcpy(&gargs[1], jl_svec_data(sparam_vals), n_sparams * sizeof(void*)); + memcpy(&gargs[1 + n_sparams], args, nargs * sizeof(void*)); + if (def->isva) { + gargs[totargs-1] = jl_f_tuple(NULL, &gargs[1 + n_sparams + def->nargs - 1], nargs - (def->nargs - 1)); + gargs[1 + n_sparams + def->nargs - 1] = gargs[totargs - 1]; + } + jl_value_t *code = jl_apply(gargs, 1 + n_sparams + def->nargs); JL_GC_POP(); return code; } @@ -555,7 +555,7 @@ JL_DLLEXPORT jl_code_info_t *jl_expand_and_resolve(jl_value_t *ex, jl_module_t * // Return a newly allocated CodeInfo for the function signature // effectively described by the tuple (specTypes, env, Method) inside linfo -JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo, size_t world) +JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) { jl_value_t *uninferred = jl_atomic_load_relaxed(&linfo->uninferred); if (uninferred) { @@ -579,13 +579,13 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo, siz JL_TRY { ct->ptls->in_pure_callback = 1; + // and the right world ct->world_age = def->primary_world; // invoke code generator jl_tupletype_t *ttdt = (jl_tupletype_t*)jl_unwrap_unionall(tt); - ex = jl_call_staged(def, generator, world, linfo->sparam_vals, jl_svec_data(ttdt->parameters), jl_nparams(ttdt)); + ex = jl_call_staged(def, generator, linfo->sparam_vals, jl_svec_data(ttdt->parameters), jl_nparams(ttdt)); - // do some post-processing if (jl_is_code_info(ex)) { func = (jl_code_info_t*)ex; jl_array_t *stmts = (jl_array_t*)func->code; @@ -602,6 +602,7 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo, siz jl_error("The function body AST defined by this @generated function is not pure. This likely means it contains a closure, a comprehension or a generator."); } } + jl_add_function_name_to_lineinfo(func, (jl_value_t*)def->name); // If this generated function has an opaque closure, cache it for @@ -741,12 +742,20 @@ static void jl_method_set_source(jl_method_t *m, jl_code_info_t *src) st = jl_nothing; } else if (nargs == 2 && jl_exprarg(st, 0) == (jl_value_t*)jl_generated_sym) { - if (m->generator != NULL) - jl_error("duplicate @generated function body"); + m->generator = NULL; jl_value_t *gexpr = jl_exprarg(st, 1); - // the frontend would put (new (core GeneratedFunctionStub) funcname argnames sp) here, for example - m->generator = jl_toplevel_eval(m->module, gexpr); - jl_gc_wb(m, m->generator); + if (jl_expr_nargs(gexpr) == 7) { + // expects (new (core GeneratedFunctionStub) funcname argnames sp line file expandearly) + jl_value_t *funcname = jl_exprarg(gexpr, 1); + assert(jl_is_symbol(funcname)); + if (jl_get_global(m->module, (jl_sym_t*)funcname) != NULL) { + m->generator = jl_toplevel_eval(m->module, gexpr); + jl_gc_wb(m, m->generator); + } + } + if (m->generator == NULL) { + jl_error("invalid @generated function; try placing it in global scope"); + } st = jl_nothing; } else if (nargs == 1 && jl_exprarg(st, 0) == (jl_value_t*)jl_generated_only_sym) { diff --git a/test/ambiguous.jl b/test/ambiguous.jl index 4ab779d76e6f0..e96954299b702 100644 --- a/test/ambiguous.jl +++ b/test/ambiguous.jl @@ -357,7 +357,7 @@ f35983(::Type, ::Type) = 2 @test length(Base.methods(f35983, (Any, Any))) == 2 @test first(Base.methods(f35983, (Any, Any))).sig == Tuple{typeof(f35983), Type, Type} let ambig = Ref{Int32}(0) - ms = Base._methods_by_ftype(Tuple{typeof(f35983), Type, Type}, nothing, -1, Base.get_world_counter(), true, Ref{UInt}(typemin(UInt)), Ref{UInt}(typemax(UInt)), ambig) + ms = Base._methods_by_ftype(Tuple{typeof(f35983), Type, Type}, nothing, -1, typemax(UInt), true, Ref{UInt}(typemin(UInt)), Ref{UInt}(typemax(UInt)), ambig) @test ms isa Vector @test length(ms) == 1 @test ambig[] == 0 @@ -366,7 +366,7 @@ f35983(::Type{Int16}, ::Any) = 3 @test length(Base.methods_including_ambiguous(f35983, (Type, Type))) == 2 @test length(Base.methods(f35983, (Type, Type))) == 1 let ambig = Ref{Int32}(0) - ms = Base._methods_by_ftype(Tuple{typeof(f35983), Type, Type}, nothing, -1, Base.get_world_counter(), true, Ref{UInt}(typemin(UInt)), Ref{UInt}(typemax(UInt)), ambig) + ms = Base._methods_by_ftype(Tuple{typeof(f35983), Type, Type}, nothing, -1, typemax(UInt), true, Ref{UInt}(typemin(UInt)), Ref{UInt}(typemax(UInt)), ambig) @test ms isa Vector @test length(ms) == 2 @test ambig[] == 1 @@ -374,7 +374,7 @@ end struct B38280 <: Real; val; end let ambig = Ref{Int32}(0) - ms = Base._methods_by_ftype(Tuple{Type{B38280}, Any}, nothing, 1, Base.get_world_counter(), false, Ref{UInt}(typemin(UInt)), Ref{UInt}(typemax(UInt)), ambig) + ms = Base._methods_by_ftype(Tuple{Type{B38280}, Any}, nothing, 1, typemax(UInt), false, Ref{UInt}(typemin(UInt)), Ref{UInt}(typemax(UInt)), ambig) @test ms isa Vector @test length(ms) == 1 @test ambig[] == 1 diff --git a/test/compiler/contextual.jl b/test/compiler/contextual.jl index 9db7ae1aeaa5d..740e985e388df 100644 --- a/test/compiler/contextual.jl +++ b/test/compiler/contextual.jl @@ -7,7 +7,7 @@ module MiniCassette # A minimal demonstration of the cassette mechanism. Doesn't support all the # fancy features, but sufficient to exercise this code path in the compiler. - using Core.Compiler: retrieve_code_info, CodeInfo, + using Core.Compiler: method_instances, retrieve_code_info, CodeInfo, MethodInstance, SSAValue, GotoNode, GotoIfNot, ReturnNode, SlotNumber, quoted, signature_type using Base: _methods_by_ftype @@ -69,28 +69,24 @@ module MiniCassette end end - function overdub_generator(world::UInt, source, self, c, f, args) - @nospecialize + function overdub_generator(self, c, f, args) if !Base.issingletontype(f) - # (c, f, args..) -> f(args...) - code_info = :(return f(args...)) - return Core.GeneratedFunctionStub(identity, Core.svec(:overdub, :c, :f, :args), Core.svec())(world, source, code_info) + return :(return f(args...)) end tt = Tuple{f, args...} - match = Base._which(tt; world) + match = Base._which(tt; world=typemax(UInt)) mi = Core.Compiler.specialize_method(match) # Unsupported in this mini-cassette @assert !mi.def.isva - code_info = retrieve_code_info(mi, world) + code_info = retrieve_code_info(mi) @assert isa(code_info, CodeInfo) code_info = copy(code_info) - @assert code_info.edges === nothing - code_info.edges = MethodInstance[mi] + if isdefined(code_info, :edges) + code_info.edges = MethodInstance[mi] + end transform!(code_info, length(args), match.sparams) - # TODO: this is mandatory: code_info.min_world = max(code_info.min_world, min_world[]) - # TODO: this is mandatory: code_info.max_world = min(code_info.max_world, max_world[]) - return code_info + code_info end @inline function overdub(c::Ctx, f::Union{Core.Builtin, Core.IntrinsicFunction}, args...) @@ -99,7 +95,16 @@ module MiniCassette @eval function overdub(c::Ctx, f, args...) $(Expr(:meta, :generated_only)) - $(Expr(:meta, :generated, overdub_generator)) + $(Expr(:meta, + :generated, + Expr(:new, + Core.GeneratedFunctionStub, + :overdub_generator, + Any[:overdub, :ctx, :f, :args], + Any[], + @__LINE__, + QuoteNode(Symbol(@__FILE__)), + true))) end end diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 5209ef879324e..182776d79d7ec 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -1787,17 +1787,9 @@ bar_22708(x) = f_22708(x) @test bar_22708(1) == "x" -struct EarlyGeneratedFunctionStub - stub::Core.GeneratedFunctionStub -end -(stub::EarlyGeneratedFunctionStub)(args...) = (@nospecialize; stub.stub(args...)) - # mechanism for spoofing work-limiting heuristics and early generator expansion (#24852) -function _generated_stub(gen::Symbol, args::Core.SimpleVector, params::Core.SimpleVector, expand_early::Bool) - stub = Expr(:new, Core.GeneratedFunctionStub, gen, args, params) - if expand_early - stub = Expr(:new, EarlyGeneratedFunctionStub, stub) - end +function _generated_stub(gen::Symbol, args::Vector{Any}, params::Vector{Any}, line, file, expand_early) + stub = Expr(:new, Core.GeneratedFunctionStub, gen, args, params, line, file, expand_early) return Expr(:meta, :generated, stub) end @@ -1806,21 +1798,10 @@ f24852_kernel2(x, y::Tuple) = f24852_kernel1(x, (y,)) f24852_kernel3(x, y::Tuple) = f24852_kernel2(x, (y,)) f24852_kernel(x, y::Number) = f24852_kernel3(x, (y,)) -function f24852_kernel_cinfo(world::UInt, source, fsig::Type) - matches = Base._methods_by_ftype(fsig, -1, world) - if matches === nothing || length(matches) != 1 - match = nothing - else - match = matches[1] - if !isdefined(match.method, :source) - match = nothing - end - end - if match === nothing - code_info = :(f(x, y)) - code_info = Core.GeneratedFunctionStub(identity, Core.svec(:self, :f, :x, :y), Core.svec(:X, :Y))(world, source, code_info) - return (nothing, code_info) - end +function f24852_kernel_cinfo(fsig::Type) + world = typemax(UInt) # FIXME + match = Base._methods_by_ftype(fsig, -1, world)[1] + isdefined(match.method, :source) || return (nothing, :(f(x, y))) code_info = Base.uncompressed_ir(match.method) Meta.partially_inline!(code_info.code, Any[], match.spec_types, Any[match.sparams...], 1, 0, :propagate) if startswith(String(match.method.name), "f24852") @@ -1835,23 +1816,21 @@ function f24852_kernel_cinfo(world::UInt, source, fsig::Type) end pushfirst!(code_info.slotnames, Symbol("#self#")) pushfirst!(code_info.slotflags, 0x00) - # TODO: this is mandatory: code_info.min_world = max(code_info.min_world, min_world[]) - # TODO: this is mandatory: code_info.max_world = min(code_info.max_world, max_world[]) return match.method, code_info end -function f24852_gen_cinfo_uninflated(world::UInt, source, X, Y, _, f, x, y) - _, code_info = f24852_kernel_cinfo(world, source, Tuple{f, x, y}) +function f24852_gen_cinfo_uninflated(X, Y, _, f, x, y) + _, code_info = f24852_kernel_cinfo(Tuple{f, x, y}) return code_info end -function f24852_gen_cinfo_inflated(world::UInt, source, X, Y, _, f, x, y) - method, code_info = f24852_kernel_cinfo(world, source, Tuple{f, x, y}) +function f24852_gen_cinfo_inflated(X, Y, _, f, x, y) + method, code_info = f24852_kernel_cinfo(Tuple{f, x, y}) code_info.method_for_inference_limit_heuristics = method return code_info end -function f24852_gen_expr(X, Y, _, f, x, y) # deparse of f(x::X, y::Y) where {X, Y} +function f24852_gen_expr(X, Y, _, f, x, y) # deparse f(x::X, y::Y) where {X, Y} if f === typeof(f24852_kernel) f2 = :f24852_kernel3 elseif f === typeof(f24852_kernel3) @@ -1868,8 +1847,20 @@ end @eval begin function f24852_late_expr(f, x::X, y::Y) where {X, Y} - $(_generated_stub(:f24852_gen_expr, Core.svec(:self, :f, :x, :y), - Core.svec(:X, :Y), false)) + $(_generated_stub(:f24852_gen_expr, Any[:self, :f, :x, :y], + Any[:X, :Y], @__LINE__, QuoteNode(Symbol(@__FILE__)), false)) + $(Expr(:meta, :generated_only)) + #= no body =# + end + function f24852_late_inflated(f, x::X, y::Y) where {X, Y} + $(_generated_stub(:f24852_gen_cinfo_inflated, Any[:self, :f, :x, :y], + Any[:X, :Y], @__LINE__, QuoteNode(Symbol(@__FILE__)), false)) + $(Expr(:meta, :generated_only)) + #= no body =# + end + function f24852_late_uninflated(f, x::X, y::Y) where {X, Y} + $(_generated_stub(:f24852_gen_cinfo_uninflated, Any[:self, :f, :x, :y], + Any[:X, :Y], @__LINE__, QuoteNode(Symbol(@__FILE__)), false)) $(Expr(:meta, :generated_only)) #= no body =# end @@ -1877,18 +1868,20 @@ end @eval begin function f24852_early_expr(f, x::X, y::Y) where {X, Y} - $(_generated_stub(:f24852_gen_expr, Core.svec(:self, :f, :x, :y), - Core.svec(:X, :Y), true)) + $(_generated_stub(:f24852_gen_expr, Any[:self, :f, :x, :y], + Any[:X, :Y], @__LINE__, QuoteNode(Symbol(@__FILE__)), true)) $(Expr(:meta, :generated_only)) #= no body =# end function f24852_early_inflated(f, x::X, y::Y) where {X, Y} - $(Expr(:meta, :generated, f24852_gen_cinfo_inflated)) + $(_generated_stub(:f24852_gen_cinfo_inflated, Any[:self, :f, :x, :y], + Any[:X, :Y], @__LINE__, QuoteNode(Symbol(@__FILE__)), true)) $(Expr(:meta, :generated_only)) #= no body =# end function f24852_early_uninflated(f, x::X, y::Y) where {X, Y} - $(Expr(:meta, :generated, f24852_gen_cinfo_uninflated)) + $(_generated_stub(:f24852_gen_cinfo_uninflated, Any[:self, :f, :x, :y], + Any[:X, :Y], @__LINE__, QuoteNode(Symbol(@__FILE__)), true)) $(Expr(:meta, :generated_only)) #= no body =# end @@ -1899,6 +1892,10 @@ result = f24852_kernel(x, y) @test result === f24852_late_expr(f24852_kernel, x, y) @test Base.return_types(f24852_late_expr, typeof((f24852_kernel, x, y))) == Any[Any] +@test result === f24852_late_uninflated(f24852_kernel, x, y) +@test Base.return_types(f24852_late_uninflated, typeof((f24852_kernel, x, y))) == Any[Any] +@test result === f24852_late_uninflated(f24852_kernel, x, y) +@test Base.return_types(f24852_late_uninflated, typeof((f24852_kernel, x, y))) == Any[Any] @test result === f24852_early_expr(f24852_kernel, x, y) @test Base.return_types(f24852_early_expr, typeof((f24852_kernel, x, y))) == Any[Any] @@ -1906,6 +1903,7 @@ result = f24852_kernel(x, y) @test Base.return_types(f24852_early_uninflated, typeof((f24852_kernel, x, y))) == Any[Any] @test result === @inferred f24852_early_inflated(f24852_kernel, x, y) @test Base.return_types(f24852_early_inflated, typeof((f24852_kernel, x, y))) == Any[Float64] + # TODO: test that `expand_early = true` + inflated `method_for_inference_limit_heuristics` # can be used to tighten up some inference result. diff --git a/test/compiler/validation.jl b/test/compiler/validation.jl index 5fd074fee73ae..c25aae71ab157 100644 --- a/test/compiler/validation.jl +++ b/test/compiler/validation.jl @@ -22,9 +22,10 @@ msig = Tuple{typeof(f22938),Int,Int,Int,Int} world = Base.get_world_counter() match = only(Base._methods_by_ftype(msig, -1, world)) mi = Core.Compiler.specialize_method(match) -c0 = Core.Compiler.retrieve_code_info(mi, world) +c0 = Core.Compiler.retrieve_code_info(mi) -@test isempty(Core.Compiler.validate_code(mi, c0)) +@test isempty(Core.Compiler.validate_code(mi)) +@test isempty(Core.Compiler.validate_code(c0)) @testset "INVALID_EXPR_HEAD" begin c = copy(c0) @@ -115,7 +116,7 @@ end @testset "SIGNATURE_NARGS_MISMATCH" begin old_sig = mi.def.sig mi.def.sig = Tuple{1,2} - errors = Core.Compiler.validate_code(mi, nothing) + errors = Core.Compiler.validate_code(mi) mi.def.sig = old_sig @test length(errors) == 1 @test errors[1].kind === Core.Compiler.SIGNATURE_NARGS_MISMATCH @@ -131,7 +132,7 @@ end @testset "SLOTNAMES_NARGS_MISMATCH" begin mi.def.nargs += 20 - errors = Core.Compiler.validate_code(mi, c0) + errors = Core.Compiler.validate_code(mi) mi.def.nargs -= 20 @test length(errors) == 2 @test count(e.kind === Core.Compiler.SLOTNAMES_NARGS_MISMATCH for e in errors) == 1 diff --git a/test/core.jl b/test/core.jl index 8507f2bdb8a01..8af7421ba7501 100644 --- a/test/core.jl +++ b/test/core.jl @@ -3883,8 +3883,7 @@ PossiblyInvalidUnion{T} = Union{T,Int} # issue #13007 call13007(::Type{Array{T,N}}) where {T,N} = 0 call13007(::Type{Array}) = 1 -@test Base._methods(call13007, Tuple{Type{x} where x<:Array}, 4, typemax(UInt)) === nothing -@test length(Base._methods(call13007, Tuple{Type{x} where x<:Array}, 4, Base.get_world_counter())) == 2 +@test length(Base._methods(call13007, Tuple{Type{x} where x<:Array}, 4, typemax(UInt))) == 2 # detecting cycles during type intersection, e.g. #1631 cycle_in_solve_tvar_constraints(::Type{Some{S}}, x::S) where {S} = 0 diff --git a/test/opaque_closure.jl b/test/opaque_closure.jl index d54d38403913a..b5d5f9ed522ac 100644 --- a/test/opaque_closure.jl +++ b/test/opaque_closure.jl @@ -173,23 +173,28 @@ mk_va_opaque() = @opaque (x...)->x @test repr(@opaque x->1) == "(::Any)::Any->◌" # Opaque closure in CodeInfo returned from generated functions -let ci = @code_lowered const_int() - global function mk_ocg(world::UInt, source, args...) - @nospecialize - cig = Meta.lower(@__MODULE__, Expr(:new_opaque_closure, Tuple{}, Any, Any, - Expr(:opaque_closure_method, nothing, 0, false, lno, ci))).args[1] - cig.slotnames = Symbol[Symbol("#self#")] - cig.slottypes = Any[Any] - cig.slotflags = UInt8[0x00] - @assert cig.min_world == UInt(1) - @assert cig.max_world == typemax(UInt) - return cig - end +function mk_ocg(args...) + ci = @code_lowered const_int() + cig = Meta.lower(@__MODULE__, Expr(:new_opaque_closure, Tuple{}, Any, Any, + Expr(:opaque_closure_method, nothing, 0, false, lno, ci))).args[1] + cig.slotnames = Symbol[Symbol("#self#")] + cig.slottypes = Any[Any] + cig.slotflags = UInt8[0x00] + cig end @eval function oc_trivial_generated() $(Expr(:meta, :generated_only)) - $(Expr(:meta, :generated, mk_ocg)) + $(Expr(:meta, + :generated, + Expr(:new, + Core.GeneratedFunctionStub, + :mk_ocg, + Any[:oc_trivial_generated], + Any[], + @__LINE__, + QuoteNode(Symbol(@__FILE__)), + true))) end @test isa(oc_trivial_generated(), Core.OpaqueClosure{Tuple{}, Any}) @test oc_trivial_generated()() == 1 diff --git a/test/reflection.jl b/test/reflection.jl index f31b77ad26aed..0c1081ba2c42f 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -648,7 +648,7 @@ let world = Core.Compiler.get_world_counter() match = Base._methods_by_ftype(T22979, -1, world)[1] instance = Core.Compiler.specialize_method(match) - cinfo_generated = Core.Compiler.get_staged(instance, world) + cinfo_generated = Core.Compiler.get_staged(instance) @test_throws ErrorException Base.uncompressed_ir(match.method) test_similar_codeinfo(code_lowered(f22979, typeof(x22979))[1], cinfo_generated) diff --git a/test/staged.jl b/test/staged.jl index 0fa8ecb182cff..4a7fa3d7f4c84 100644 --- a/test/staged.jl +++ b/test/staged.jl @@ -196,11 +196,12 @@ let gf_err2 return nothing end Expected = ErrorException("code reflection cannot be used from generated functions") - @test_throws Expected gf_err2(code_lowered) @test_throws Expected gf_err2(code_typed) @test_throws Expected gf_err2(code_llvm) @test_throws Expected gf_err2(code_native) - @test gf_err_ref[] == 88 + @test gf_err_ref[] == 66 + @test gf_err2(code_lowered) === nothing + @test gf_err_ref[] == 1077 end # issue #15043 @@ -245,18 +246,12 @@ f22440kernel(x::AbstractFloat) = x * x f22440kernel(::Type{T}) where {T} = one(T) f22440kernel(::Type{T}) where {T<:AbstractFloat} = zero(T) -function f22440_gen(world::UInt, source, _, y) - match = only(Base._methods_by_ftype(Tuple{typeof(f22440kernel),y}, -1, world)) +@generated function f22440(y) + match = Base._methods_by_ftype(Tuple{typeof(f22440kernel),y}, -1, typemax(UInt))[1] code_info = Base.uncompressed_ir(match.method) Meta.partially_inline!(code_info.code, Any[], match.spec_types, Any[match.sparams...], 0, 0, :propagate) - # TODO: this is mandatory: code_info.min_world = max(code_info.min_world, min_world[]) - # TODO: this is mandatory: code_info.max_world = min(code_info.max_world, max_world[]) return code_info end -@eval function f22440(y) - $(Expr(:meta, :generated, f22440_gen)) - $(Expr(:meta, :generated_only)) -end @test f22440(Int) === f22440kernel(Int) @test f22440(Float64) === f22440kernel(Float64) @@ -314,33 +309,26 @@ end # https://github.com/JuliaDebug/CassetteOverlay.jl/issues/12 # generated function with varargs and unfortunately placed unused slot @generated function f_vararg_generated(args...) - local unusedslot4 - local unusedslot5 - local unusedslot6 :($args) end g_vararg_generated() = f_vararg_generated((;), (;), Base.inferencebarrier((;))) let tup = g_vararg_generated() @test all(==(typeof((;))), tup) - # This is just to make sure that the test is actually testing what we want: - # the test only works if there is an unused that matches the position of - # the inferencebarrier argument above (N.B. the generator function itself + # This is just to make sure that the test is actually testing what we want - + # the test only works if there's an unused that matches the position of the + # inferencebarrier argument above (N.B. the generator function itself # shifts everything over by 1) - @test_broken only(code_lowered(only(methods(f_vararg_generated)).generator.gen)).slotflags[5] == 0x00 + @test only(code_lowered(only(methods(f_vararg_generated)).generator.gen)).slotflags[5] == UInt8(0x00) end # respect a given linetable in code generation # https://github.com/JuliaLang/julia/pull/47750 -let world = Base.get_world_counter() - match = Base._which(Tuple{typeof(sin), Int}; world) +let match = Base._which(Tuple{typeof(sin),Int}) mi = Core.Compiler.specialize_method(match) - lwr = Core.Compiler.retrieve_code_info(mi, world) - @test all(lin->lin.method === :sin, lwr.linetable) - @eval function sin_generated(a) - $(Expr(:meta, :generated, Returns(lwr))) - $(Expr(:meta, :generated_only)) - end + lwr = Core.Compiler.retrieve_code_info(mi) + @test all(lin->lin.method===:sin, lwr.linetable) + @generated sin_generated(a) = lwr src = only(code_lowered(sin_generated, (Int,))) - @test all(lin->lin.method === :sin, src.linetable) + @test all(lin->lin.method===:sin, src.linetable) @test sin_generated(42) == sin(42) end diff --git a/test/syntax.jl b/test/syntax.jl index e60bbd81a04ab..756af45e6b3c7 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -3053,6 +3053,9 @@ end end # issue 25678 +@generated f25678(x::T) where {T} = code_lowered(sin, Tuple{x})[] +@test f25678(pi/6) === sin(pi/6) + @generated g25678(x) = return :x @test g25678(7) === 7