diff --git a/Compiler/Project.toml b/Compiler/Project.toml new file mode 100644 index 0000000000000..b933d08db5205 --- /dev/null +++ b/Compiler/Project.toml @@ -0,0 +1,3 @@ +name = "Compiler" +uuid = "807dbc54-b67e-4c79-8afb-eafe4df6f2e1" +version = "0.0.1" diff --git a/Compiler/src/Compiler.jl b/Compiler/src/Compiler.jl new file mode 100644 index 0000000000000..c2c074dc92bbc --- /dev/null +++ b/Compiler/src/Compiler.jl @@ -0,0 +1,194 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +# When generating an incremental precompile file, we first check whether we +# already have a copy of this *exact* code in the system image. If so, we +# simply generates a pkgimage that has the dependency edges we recorded in +# the system image and simply returns that copy of the compiler. If not, +# we proceed to load/precompile this as an ordinary package. +if isdefined(Base, :generating_output) && Base.generating_output(true) && + Base.samefile(Base._compiler_require_dependencies[1][2], @eval @__FILE__) && + !Base.any_includes_stale( + map(Base.CacheHeaderIncludes, Base._compiler_require_dependencies), + "sysimg", nothing) + + Base.prepare_compiler_stub_image!() + append!(Base._require_dependencies, Base._compiler_require_dependencies) + # There isn't much point in precompiling native code - downstream users will + # specialize their own versions of the compiler code and we don't activate + # the compiler by default anyway, so let's save ourselves some disk space. + ccall(:jl_suppress_precompile, Cvoid, (Cint,), 1) + +else + +@eval baremodule Compiler + +# Needs to match UUID defined in Project.toml +ccall(:jl_set_module_uuid, Cvoid, (Any, NTuple{2, UInt64}), Compiler, + (0x807dbc54_b67e_4c79, 0x8afb_eafe4df6f2e1)) + +using Core.Intrinsics, Core.IR + +import Core: print, println, show, write, unsafe_write, + _apply_iterate, svec, apply_type, Builtin, IntrinsicFunction, + MethodInstance, CodeInstance, MethodTable, MethodMatch, PartialOpaque, + TypeofVararg, Core, SimpleVector, donotdelete, compilerbarrier, + memoryref_isassigned, memoryrefnew, memoryrefoffset, memoryrefget, + memoryrefset!, typename + +using Base +using Base: Ordering, vect, EffectsOverride, BitVector, @_gc_preserve_begin, @_gc_preserve_end, RefValue, + @nospecializeinfer, @_foldable_meta, fieldindex, is_function_def, indexed_iterate, isexpr, methods, + get_world_counter, JLOptions, _methods_by_ftype, unwrap_unionall, cconvert, unsafe_convert, + issingletontype, isType, rewrap_unionall, has_free_typevars, isvarargtype, hasgenerator, + IteratorSize, SizeUnknown, _array_for, Bottom, generating_output, diff_names, + ismutationfree, NUM_EFFECTS_OVERRIDES, _NAMEDTUPLE_NAME, datatype_fieldtypes, + argument_datatype, isfieldatomic, unwrapva, iskindtype, _bits_findnext, copy_exprargs, + Generator, Filter, ismutabletypename, isvatuple, datatype_fieldcount, + isconcretedispatch, isdispatchelem, datatype_layoutsize, + datatype_arrayelem, unionlen, isidentityfree, _uniontypes, uniontypes, OneTo, Callable, + DataTypeFieldDesc, datatype_nfields, datatype_pointerfree, midpoint, is_valid_intrinsic_elptr, + allocatedinline, isbitsunion, widen_diagonal, unconstrain_vararg_length, + rename_unionall, may_invoke_generator, is_meta_expr_head, is_meta_expr, quoted, + specialize_method, hasintersect, is_nospecializeinfer, is_nospecialized, + get_nospecializeinfer_sig, tls_world_age, uniontype_layout, kwerr, + moduleroot, is_file_tracked, decode_effects_override, lookup_binding_partition, + is_some_imported, binding_kind, is_some_guard, is_some_const_binding, partition_restriction, + BINDING_KIND_GLOBAL, structdiff +using Base.Order +import Base: getindex, setindex!, length, iterate, push!, isempty, first, convert, ==, + copy, popfirst!, in, haskey, resize!, copy!, append!, last, get!, size, + get, iterate, findall, min_world, max_world, _topmod + +const getproperty = Core.getfield +const setproperty! = Core.setfield! +const swapproperty! = Core.swapfield! +const modifyproperty! = Core.modifyfield! +const replaceproperty! = Core.replacefield! +const _DOCS_ALIASING_WARNING = "" + +ccall(:jl_set_istopmod, Cvoid, (Any, Bool), Compiler, false) + +eval(x) = Core.eval(Compiler, x) +eval(m, x) = Core.eval(m, x) + +function include(x::String) + if !isdefined(Base, :end_base_include) + # During bootstrap, all includes are relative to `base/` + x = Base.strcat(Base.strcat(Base.BUILDROOT, "../usr/share/julia/Compiler/src/"), x) + end + Base.include(Compiler, x) +end + +function include(mod::Module, x::String) + if !isdefined(Base, :end_base_include) + x = Base.strcat(Base.strcat(Base.BUILDROOT, "../usr/share/julia/Compiler/src/"), x) + end + Base.include(mod, x) +end + + +macro _boundscheck() Expr(:boundscheck) end + +# These types are used by reflection.jl and expr.jl too, so declare them here. +# Note that `@assume_effects` is available only after loading namedtuple.jl. +abstract type MethodTableView end +abstract type AbstractInterpreter end + +function return_type end +function is_return_type(Core.@nospecialize(f)) + f === return_type && return true + if isdefined(Base, :Compiler) && Compiler !== Base.Compiler + # Also model the return_type function of the builtin Compiler the same. + # This isn't completely sound. We don't actually have any idea what the + # base compiler will do at runtime. In the fullness of time, we should + # re-work the semantics to make the cache primary and thus avoid having + # to reason about what the compiler may do at runtime, but we're not + # fully there yet. + return f === Base.Compiler.return_type + end + return false +end + +include("sort.jl") + +# We don't include some.jl, but this definition is still useful. +something(x::Nothing, y...) = something(y...) +something(x::Any, y...) = x + +############ +# compiler # +############ + +baremodule BuildSettings +using Core: ARGS, include +using ..Compiler: >, getindex, length + +global MAX_METHODS::Int = 3 + +if length(ARGS) > 2 && ARGS[2] === "--buildsettings" + include(BuildSettings, ARGS[3]) +end +end + +if false + import Base: Base, @show +else + macro show(ex...) + blk = Expr(:block) + for s in ex + push!(blk.args, :(println(stdout, $(QuoteNode(s)), " = ", + begin local value = $(esc(s)) end))) + end + isempty(ex) || push!(blk.args, :value) + blk + end +end + +include("cicache.jl") +include("methodtable.jl") +include("effects.jl") +include("types.jl") +include("utilities.jl") +include("validation.jl") + +include("ssair/basicblock.jl") +include("ssair/domtree.jl") +include("ssair/ir.jl") +include("ssair/tarjan.jl") + +include("abstractlattice.jl") +include("stmtinfo.jl") +include("inferenceresult.jl") +include("inferencestate.jl") + +include("typeutils.jl") +include("typelimits.jl") +include("typelattice.jl") +include("tfuncs.jl") + +include("abstractinterpretation.jl") +include("typeinfer.jl") +include("optimize.jl") + +include("bootstrap.jl") +include("reflection_interface.jl") + +if isdefined(Base, :IRShow) + @eval module IRShow + import ..Compiler + using Core.IR + using ..Base + import .Compiler: IRCode, CFG, scan_ssa_use!, + isexpr, compute_basic_blocks, block_for_inst, IncrementalCompact, + Effects, ALWAYS_TRUE, ALWAYS_FALSE, DebugInfoStream, getdebugidx, + VarState, InvalidIRError, argextype, widenconst, singleton_type, + sptypes_from_meth_instance, EMPTY_SPTYPES, InferenceState, + NativeInterpreter, CachedMethodTable, LimitedAccuracy, Timings + # During bootstrap, Base will later include this into its own "IRShow module" + Compiler.include(IRShow, "ssair/show.jl") + end +end + +end + +end diff --git a/base/compiler/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl similarity index 99% rename from base/compiler/abstractinterpretation.jl rename to Compiler/src/abstractinterpretation.jl index dbfe3bb9ccac4..d9319c02b110a 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -2047,7 +2047,7 @@ function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, (; fargs elsetype = rt === Const(true) ? Bottom : widenslotwrapper(aty) return Conditional(a, thentype, elsetype) end - elseif f === Core.Compiler.not_int + elseif f === Core.Intrinsics.not_int aty = argtypes[2] if isa(aty, Conditional) thentype = rt === Const(false) ? Bottom : aty.elsetype @@ -2119,7 +2119,7 @@ function form_partially_defined_struct(@nospecialize(obj), @nospecialize(name)) else fldidx > nminfld || return nothing end - return PartialStruct(objt0, Any[obj isa PartialStruct && i≀length(obj.fields) ? + return PartialStruct(fallback_lattice, objt0, Any[obj isa PartialStruct && i≀length(obj.fields) ? obj.fields[i] : fieldtype(objt0,i) for i = 1:fldidx]) end @@ -2955,7 +2955,7 @@ function abstract_eval_new(interp::AbstractInterpreter, e::Expr, vtypes::Union{V # - any refinement information is available (`anyrefine`), or when # - `nargs` is greater than `n_initialized` derived from the struct type # information alone - rt = PartialStruct(rt, ats) + rt = PartialStruct(𝕃ᡒ, rt, ats) end else rt = refine_partial_type(rt) @@ -2990,7 +2990,7 @@ function abstract_eval_splatnew(interp::AbstractInterpreter, e::Expr, vtypes::Un all(i::Int -> βŠ‘(𝕃ᡒ, (at.fields::Vector{Any})[i], fieldtype(t, i)), 1:n) end)) nothrow = isexact - rt = PartialStruct(rt, at.fields::Vector{Any}) + rt = PartialStruct(𝕃ᡒ, rt, at.fields::Vector{Any}) end else rt = refine_partial_type(rt) @@ -3524,7 +3524,7 @@ end end fields[i] = a end - anyrefine && return PartialStruct(rt.typ, fields) + anyrefine && return PartialStruct(𝕃ᡒ, rt.typ, fields) end if isa(rt, PartialOpaque) return rt # XXX: this case was missed in #39512 diff --git a/base/compiler/abstractlattice.jl b/Compiler/src/abstractlattice.jl similarity index 100% rename from base/compiler/abstractlattice.jl rename to Compiler/src/abstractlattice.jl diff --git a/Compiler/src/bootstrap.jl b/Compiler/src/bootstrap.jl new file mode 100644 index 0000000000000..4205b072d232f --- /dev/null +++ b/Compiler/src/bootstrap.jl @@ -0,0 +1,66 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +# make sure that typeinf is executed before turning on typeinf_ext +# this ensures that typeinf_ext doesn't recurse before it can add the item to the workq +# especially try to make sure any recursive and leaf functions have concrete signatures, +# since we won't be able to specialize & infer them at runtime + +activate_codegen!() = ccall(:jl_set_typeinf_func, Cvoid, (Any,), typeinf_ext_toplevel) + +function bootstrap!() + let time() = ccall(:jl_clock_now, Float64, ()) + println("Compiling the compiler. This may take several minutes ...") + interp = NativeInterpreter() + + # analyze_escapes_tt = Tuple{typeof(analyze_escapes), IRCode, Int, TODO} + optimize_tt = Tuple{typeof(optimize), NativeInterpreter, OptimizationState{NativeInterpreter}, InferenceResult} + fs = Any[ + # we first create caches for the optimizer, because they contain many loop constructions + # and they're better to not run in interpreter even during bootstrapping + #=analyze_escapes_tt,=# optimize_tt, + # then we create caches for inference entries + typeinf_ext, typeinf, typeinf_edge, + ] + # tfuncs can't be inferred from the inference entries above, so here we infer them manually + for x in T_FFUNC_VAL + push!(fs, x[3]) + end + for i = 1:length(T_IFUNC) + if isassigned(T_IFUNC, i) + x = T_IFUNC[i] + push!(fs, x[3]) + else + println(stderr, "WARNING: tfunc missing for ", reinterpret(IntrinsicFunction, Int32(i))) + end + end + starttime = time() + for f in fs + if isa(f, DataType) && f.name === typename(Tuple) + tt = f + else + tt = Tuple{typeof(f), Vararg{Any}} + end + for m in _methods_by_ftype(tt, 10, get_world_counter())::Vector + # remove any TypeVars from the intersection + m = m::MethodMatch + typ = Any[m.spec_types.parameters...] + for i = 1:length(typ) + typ[i] = unwraptv(typ[i]) + end + typeinf_type(interp, m.method, Tuple{typ...}, m.sparams) + end + end + endtime = time() + println("Base.Compiler ──── ", sub_float(endtime,starttime), " seconds") + end + activate_codegen!() +end + +function activate!(; reflection=true, codegen=false) + if reflection + Base.REFLECTION_COMPILER[] = Compiler + end + if codegen + activate_codegen!() + end +end diff --git a/base/compiler/cicache.jl b/Compiler/src/cicache.jl similarity index 100% rename from base/compiler/cicache.jl rename to Compiler/src/cicache.jl diff --git a/base/compiler/effects.jl b/Compiler/src/effects.jl similarity index 99% rename from base/compiler/effects.jl rename to Compiler/src/effects.jl index a2e7e3dde603d..e521166fd61fa 100644 --- a/base/compiler/effects.jl +++ b/Compiler/src/effects.jl @@ -351,13 +351,13 @@ function decode_effects(e::UInt32) return Effects( UInt8((e >> 0) & 0x07), UInt8((e >> 3) & 0x03), - _Bool((e >> 5) & 0x01), - _Bool((e >> 6) & 0x01), - _Bool((e >> 7) & 0x01), + Bool((e >> 5) & 0x01), + Bool((e >> 6) & 0x01), + Bool((e >> 7) & 0x01), UInt8((e >> 8) & 0x03), UInt8((e >> 10) & 0x03), UInt8((e >> 12) & 0x03), - _Bool((e >> 14) & 0x01)) + Bool((e >> 14) & 0x01)) end decode_statement_effects_override(ssaflag::UInt32) = diff --git a/base/compiler/inferenceresult.jl b/Compiler/src/inferenceresult.jl similarity index 100% rename from base/compiler/inferenceresult.jl rename to Compiler/src/inferenceresult.jl diff --git a/base/compiler/inferencestate.jl b/Compiler/src/inferencestate.jl similarity index 100% rename from base/compiler/inferencestate.jl rename to Compiler/src/inferencestate.jl diff --git a/base/compiler/methodtable.jl b/Compiler/src/methodtable.jl similarity index 100% rename from base/compiler/methodtable.jl rename to Compiler/src/methodtable.jl diff --git a/base/compiler/optimize.jl b/Compiler/src/optimize.jl similarity index 99% rename from base/compiler/optimize.jl rename to Compiler/src/optimize.jl index edc374f675c5f..8cdd56f4c1a76 100644 --- a/base/compiler/optimize.jl +++ b/Compiler/src/optimize.jl @@ -212,14 +212,14 @@ end function argextype end # imported by EscapeAnalysis function try_compute_field end # imported by EscapeAnalysis -include("compiler/ssair/heap.jl") -include("compiler/ssair/slot2ssa.jl") -include("compiler/ssair/inlining.jl") -include("compiler/ssair/verify.jl") -include("compiler/ssair/legacy.jl") -include("compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl") -include("compiler/ssair/passes.jl") -include("compiler/ssair/irinterp.jl") +include("ssair/heap.jl") +include("ssair/slot2ssa.jl") +include("ssair/inlining.jl") +include("ssair/verify.jl") +include("ssair/legacy.jl") +include("ssair/EscapeAnalysis/EscapeAnalysis.jl") +include("ssair/passes.jl") +include("ssair/irinterp.jl") function ir_to_codeinf!(opt::OptimizationState) (; linfo, src) = opt diff --git a/Compiler/src/reflection_interface.jl b/Compiler/src/reflection_interface.jl new file mode 100644 index 0000000000000..3fc182685e598 --- /dev/null +++ b/Compiler/src/reflection_interface.jl @@ -0,0 +1,58 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +_findall_matches(interp::AbstractInterpreter, @nospecialize(tt)) = findall(tt, method_table(interp)) +_default_interp(world::UInt) = NativeInterpreter(world) + +_may_throw_methoderror(matches::MethodLookupResult) = + matches.ambig || !any(match::Core.MethodMatch->match.fully_covers, matches.matches) + +function _infer_exception_type(interp::AbstractInterpreter, @nospecialize(tt), optimize::Bool) + matches = _findall_matches(interp, tt) + matches === nothing && return nothing + exct = Union{} + if _may_throw_methoderror(matches) + # account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature. + exct = MethodError + end + for match in matches.matches + match = match::Core.MethodMatch + frame = typeinf_frame(interp, match, #=run_optimizer=#optimize) + frame === nothing && return Any + exct = tmerge(exct, widenconst(frame.result.exc_result)) + end + return exct +end + +function _infer_effects(interp::AbstractInterpreter, @nospecialize(tt), optimize::Bool) + matches = _findall_matches(interp, tt) + matches === nothing && return nothing + effects = EFFECTS_TOTAL + if _may_throw_methoderror(matches) + # account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature. + effects = Effects(effects; nothrow=false) + end + for match in matches.matches + match = match::Core.MethodMatch + frame = typeinf_frame(interp, match, #=run_optimizer=#optimize) + frame === nothing && return Effects() + effects = merge_effects(effects, frame.result.ipo_effects) + end + return effects +end + +function statement_costs!(interp::AbstractInterpreter, cost::Vector{Int}, body::Vector{Any}, src::Union{CodeInfo, IRCode}, match::Core.MethodMatch) + params = OptimizationParams(interp) + sptypes = VarState[VarState(sp, false) for sp in match.sparams] + return statement_costs!(cost, body, src, sptypes, params) +end + +function findsup_mt(@nospecialize(tt), world, method_table) + if method_table === nothing + table = InternalMethodTable(world) + elseif method_table isa Core.MethodTable + table = OverlayMethodTable(world, method_table) + else + table = method_table + end + return findsup(tt, table) +end diff --git a/base/compiler/sort.jl b/Compiler/src/sort.jl similarity index 100% rename from base/compiler/sort.jl rename to Compiler/src/sort.jl diff --git a/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl b/Compiler/src/ssair/EscapeAnalysis/EscapeAnalysis.jl similarity index 99% rename from base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl rename to Compiler/src/ssair/EscapeAnalysis/EscapeAnalysis.jl index 887a21ef7e0f6..c3b1a8b641af4 100644 --- a/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl +++ b/Compiler/src/ssair/EscapeAnalysis/EscapeAnalysis.jl @@ -22,20 +22,24 @@ using ._TOP_MOD: # Base definitions @nospecialize, @specialize, BitSet, Callable, Csize_t, IdDict, IdSet, UnitRange, Vector, copy, delete!, empty!, enumerate, error, first, get, get!, haskey, in, isassigned, isempty, ismutabletype, keys, last, length, max, min, missing, pop!, push!, pushfirst!, - unwrap_unionall, !, !=, !==, &, *, +, -, :, <, <<, =>, >, |, ∈, βˆ‰, ∩, βˆͺ, β‰ , ≀, β‰₯, βŠ† -using Core.Compiler: # Core.Compiler specific definitions + unwrap_unionall, !, !=, !==, &, *, +, -, :, <, <<, =>, >, |, ∈, βˆ‰, ∩, βˆͺ, β‰ , ≀, β‰₯, βŠ†, + hasintersect +using ..Compiler: # Core.Compiler specific definitions AbstractLattice, Bottom, IRCode, IR_FLAG_NOTHROW, InferenceResult, SimpleInferenceLattice, argextype, fieldcount_noerror, hasintersect, has_flag, intrinsic_nothrow, is_meta_expr_head, is_identity_free_argtype, isexpr, println, setfield!_nothrow, - singleton_type, try_compute_field, try_compute_fieldidx, widenconst, βŠ‘ + singleton_type, try_compute_field, try_compute_fieldidx, widenconst, βŠ‘, Compiler -include(x) = _TOP_MOD.include(@__MODULE__, x) -if _TOP_MOD === Core.Compiler - include("compiler/ssair/EscapeAnalysis/disjoint_set.jl") -else - include("disjoint_set.jl") +function include(x) + if !isdefined(_TOP_MOD.Base, :end_base_include) + # During bootstrap, all includes are relative to `base/` + x = ccall(:jl_prepend_string, Ref{String}, (Any, Any), "ssair/EscapeAnalysis/", x) + end + _TOP_MOD.include(@__MODULE__, x) end +include("disjoint_set.jl") + const AInfo = IdSet{Any} """ diff --git a/base/compiler/ssair/EscapeAnalysis/disjoint_set.jl b/Compiler/src/ssair/EscapeAnalysis/disjoint_set.jl similarity index 100% rename from base/compiler/ssair/EscapeAnalysis/disjoint_set.jl rename to Compiler/src/ssair/EscapeAnalysis/disjoint_set.jl diff --git a/base/compiler/ssair/basicblock.jl b/Compiler/src/ssair/basicblock.jl similarity index 100% rename from base/compiler/ssair/basicblock.jl rename to Compiler/src/ssair/basicblock.jl diff --git a/base/compiler/ssair/domtree.jl b/Compiler/src/ssair/domtree.jl similarity index 100% rename from base/compiler/ssair/domtree.jl rename to Compiler/src/ssair/domtree.jl diff --git a/base/compiler/ssair/heap.jl b/Compiler/src/ssair/heap.jl similarity index 100% rename from base/compiler/ssair/heap.jl rename to Compiler/src/ssair/heap.jl diff --git a/base/compiler/ssair/inlining.jl b/Compiler/src/ssair/inlining.jl similarity index 100% rename from base/compiler/ssair/inlining.jl rename to Compiler/src/ssair/inlining.jl diff --git a/base/compiler/ssair/ir.jl b/Compiler/src/ssair/ir.jl similarity index 99% rename from base/compiler/ssair/ir.jl rename to Compiler/src/ssair/ir.jl index 41423a03cc276..9a76c7370c68d 100644 --- a/base/compiler/ssair/ir.jl +++ b/Compiler/src/ssair/ir.jl @@ -1,7 +1,5 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -Core.PhiNode() = Core.PhiNode(Int32[], Any[]) - isterminator(@nospecialize(stmt)) = isa(stmt, GotoNode) || isa(stmt, GotoIfNot) || isa(stmt, ReturnNode) || isa(stmt, EnterNode) || isexpr(stmt, :leave) @@ -272,6 +270,7 @@ function InstructionStream(len::Int) end InstructionStream() = InstructionStream(0) length(is::InstructionStream) = length(is.stmt) +iterate(is::Compiler.InstructionStream, st::Int=1) = (st <= Compiler.length(is)) ? (is[st], st + 1) : nothing isempty(is::InstructionStream) = isempty(is.stmt) function add_new_idx!(is::InstructionStream) ninst = length(is) + 1 diff --git a/base/compiler/ssair/irinterp.jl b/Compiler/src/ssair/irinterp.jl similarity index 100% rename from base/compiler/ssair/irinterp.jl rename to Compiler/src/ssair/irinterp.jl diff --git a/base/compiler/ssair/legacy.jl b/Compiler/src/ssair/legacy.jl similarity index 100% rename from base/compiler/ssair/legacy.jl rename to Compiler/src/ssair/legacy.jl diff --git a/base/compiler/ssair/passes.jl b/Compiler/src/ssair/passes.jl similarity index 100% rename from base/compiler/ssair/passes.jl rename to Compiler/src/ssair/passes.jl diff --git a/base/compiler/ssair/show.jl b/Compiler/src/ssair/show.jl similarity index 93% rename from base/compiler/ssair/show.jl rename to Compiler/src/ssair/show.jl index f3e11445d6c6c..a2212272ce3fc 100644 --- a/base/compiler/ssair/show.jl +++ b/Compiler/src/ssair/show.jl @@ -5,17 +5,8 @@ @nospecialize -if Pair != Base.Pair -import Base: Base, IOContext, string, join, sprint -IOContext(io::IO, KV::Pair) = IOContext(io, Base.Pair(KV[1], KV[2])) -length(s::String) = Base.length(s) -^(s::String, i::Int) = Base.:^(s, i) -end - import Base: show_unquoted using Base: printstyled, with_output_color, prec_decl, @invoke -using Core.Compiler: VarState, InvalidIRError, argextype, widenconst, singleton_type, - sptypes_from_meth_instance, EMPTY_SPTYPES function Base.show(io::IO, cfg::CFG) print(io, "CFG with $(length(cfg.blocks)) blocks:") @@ -143,9 +134,9 @@ function print_stmt(io::IO, idx::Int, @nospecialize(stmt), code::Union{IRCode,Co elseif stmt isa GotoNode print(io, "goto #", stmt.label) elseif stmt isa PhiNode - show_unquoted_phinode(io, stmt, indent, "#") + Base.show_unquoted_phinode(io, stmt, indent, "#") elseif stmt isa GotoIfNot - show_unquoted_gotoifnot(io, stmt, indent, "#") + Base.show_unquoted_gotoifnot(io, stmt, indent, "#") # everything else in the IR, defer to the generic AST printer else show_unquoted(io, stmt, indent, show_type ? prec_decl : 0) @@ -153,65 +144,6 @@ function print_stmt(io::IO, idx::Int, @nospecialize(stmt), code::Union{IRCode,Co nothing end -show_unquoted(io::IO, val::Argument, indent::Int, prec::Int) = show_unquoted(io, Core.SlotNumber(val.n), indent, prec) - -show_unquoted(io::IO, stmt::PhiNode, indent::Int, ::Int) = show_unquoted_phinode(io, stmt, indent, "%") -function show_unquoted_phinode(io::IO, stmt::PhiNode, indent::Int, prefix::String) - args = String[let - e = stmt.edges[i] - v = !isassigned(stmt.values, i) ? "#undef" : - sprint(; context=io) do ioβ€² - show_unquoted(ioβ€², stmt.values[i], indent) - end - "$prefix$e => $v" - end for i in 1:length(stmt.edges) - ] - print(io, "Ο† ", '(') - join(io, args, ", ") - print(io, ')') -end - -function show_unquoted(io::IO, stmt::PhiCNode, indent::Int, ::Int) - print(io, "Ο†αΆœ (") - first = true - for v in stmt.values - first ? (first = false) : print(io, ", ") - show_unquoted(io, v, indent) - end - print(io, ")") -end - -function show_unquoted(io::IO, stmt::PiNode, indent::Int, ::Int) - print(io, "Ο€ (") - show_unquoted(io, stmt.val, indent) - print(io, ", ") - printstyled(io, stmt.typ, color=:cyan) - print(io, ")") -end - -function show_unquoted(io::IO, stmt::UpsilonNode, indent::Int, ::Int) - print(io, "Ο’ (") - isdefined(stmt, :val) ? - show_unquoted(io, stmt.val, indent) : - print(io, "#undef") - print(io, ")") -end - -function show_unquoted(io::IO, stmt::ReturnNode, indent::Int, ::Int) - if !isdefined(stmt, :val) - print(io, "unreachable") - else - print(io, "return ") - show_unquoted(io, stmt.val, indent) - end -end - -show_unquoted(io::IO, stmt::GotoIfNot, indent::Int, ::Int) = show_unquoted_gotoifnot(io, stmt, indent, "%") -function show_unquoted_gotoifnot(io::IO, stmt::GotoIfNot, indent::Int, prefix::String) - print(io, "goto ", prefix, stmt.dest, " if not ") - show_unquoted(io, stmt.cond, indent) -end - function should_print_ssa_type(@nospecialize node) if isa(node, Expr) return !(node.head in (:gc_preserve_begin, :gc_preserve_end, :meta, :leave)) @@ -982,7 +914,7 @@ function show_ir(io::IO, ir::IRCode, config::IRShowConfig=default_config(ir); pop_new_node! = new_nodes_iter(ir)) used = stmts_used(io, ir) cfg = ir.cfg - maxssaid = length(ir.stmts) + Core.Compiler.length(ir.new_nodes) + maxssaid = length(ir.stmts) + Compiler.length(ir.new_nodes) let io = IOContext(io, :maxssaid=>maxssaid) show_ir_stmts(io, ir, 1:length(ir.stmts), config, ir.sptypes, used, cfg, 1; pop_new_node!) end @@ -1039,13 +971,13 @@ function show_ir(io::IO, compact::IncrementalCompact, config::IRShowConfig=defau still_to_be_inserted = (last(input_bb.stmts) - compact.idx) + count result_bb = result_bbs[compact.active_result_bb] - result_bbs[compact.active_result_bb] = Core.Compiler.BasicBlock(result_bb, - Core.Compiler.StmtRange(first(result_bb.stmts), compact.result_idx+still_to_be_inserted)) + result_bbs[compact.active_result_bb] = Compiler.BasicBlock(result_bb, + Compiler.StmtRange(first(result_bb.stmts), compact.result_idx+still_to_be_inserted)) end compact_cfg = CFG(result_bbs, Int[first(result_bbs[i].stmts) for i in 2:length(result_bbs)]) pop_new_node! = new_nodes_iter(compact) - maxssaid = length(compact.result) + Core.Compiler.length(compact.new_new_nodes) + maxssaid = length(compact.result) + Compiler.length(compact.new_new_nodes) bb_idx = let io = IOContext(io, :maxssaid=>maxssaid) show_ir_stmts(io, compact, 1:compact.result_idx-1, config, compact.ir.sptypes, used_compacted, compact_cfg, 1; pop_new_node!) @@ -1066,8 +998,8 @@ function show_ir(io::IO, compact::IncrementalCompact, config::IRShowConfig=defau inputs_bbs = copy(cfg.blocks) for (i, bb) in enumerate(inputs_bbs) if bb.stmts.stop < bb.stmts.start - inputs_bbs[i] = Core.Compiler.BasicBlock(bb, - Core.Compiler.StmtRange(last(bb.stmts), last(bb.stmts))) + inputs_bbs[i] = Compiler.BasicBlock(bb, + Compiler.StmtRange(last(bb.stmts), last(bb.stmts))) # this is not entirely correct, and will result in the bb starting again, # but is the best we can do without changing how `finish_current_bb!` works. end @@ -1075,7 +1007,7 @@ function show_ir(io::IO, compact::IncrementalCompact, config::IRShowConfig=defau uncompacted_cfg = CFG(inputs_bbs, Int[first(inputs_bbs[i].stmts) for i in 2:length(inputs_bbs)]) pop_new_node! = new_nodes_iter(compact.ir, compact.new_nodes_idx) - maxssaid = length(compact.ir.stmts) + Core.Compiler.length(compact.ir.new_nodes) + maxssaid = length(compact.ir.stmts) + Compiler.length(compact.ir.new_nodes) let io = IOContext(io, :maxssaid=>maxssaid) # first show any new nodes to be attached after the last compacted statement if compact.idx > 1 @@ -1139,4 +1071,62 @@ function Base.show(io::IO, e::Effects) print(io, ')') end + +function show(io::IO, inferred::Compiler.InferenceResult) + mi = inferred.linfo + tt = mi.specTypes.parameters[2:end] + tts = join(["::$(t)" for t in tt], ", ") + rettype = inferred.result + if isa(rettype, Compiler.InferenceState) + rettype = rettype.bestguess + end + if isa(mi.def, Method) + print(io, mi.def.name, "(", tts, " => ", rettype, ")") + else + print(io, "Toplevel MethodInstance thunk from ", mi.def, " => ", rettype) + end +end + +Base.show(io::IO, sv::InferenceState) = + (print(io, "InferenceState for "); show(io, sv.linfo)) + +Base.show(io::IO, ::NativeInterpreter) = + print(io, "Compiler.NativeInterpreter(...)") + +Base.show(io::IO, cache::CachedMethodTable) = + print(io, typeof(cache), "(", length(cache.cache), " entries)") + +function Base.show(io::IO, limited::LimitedAccuracy) + print(io, "LimitedAccuracy(") + show(io, limited.typ) + print(io, ", #= ", length(limited.causes), " cause(s) =#)") +end + + +# These sometimes show up as Const-values in InferenceFrameInfo signatures +function show(io::IO, mi_info::Timings.InferenceFrameInfo) + mi = mi_info.mi + def = mi.def + if isa(def, Method) + if isdefined(def, :generator) && mi === def.generator + print(io, "InferenceFrameInfo generator for ") + show(io, def) + else + print(io, "InferenceFrameInfo for ") + argnames = [isa(a, Core.Const) ? (isa(a.val, Type) ? "" : a.val) : "" for a in mi_info.slottypes[1:mi_info.nargs]] + show_tuple_as_call(io, def.name, mi.specTypes; argnames, qualified=true) + end + else + di = mi.cache.inferred.debuginfo + file, line = debuginfo_firstline(di) + file = string(file) + line = isempty(file) || line < 0 ? "" : "$file:$line" + print(io, "Toplevel InferenceFrameInfo thunk from ", def, " starting at ", line) + end +end + +function show(io::IO, tinf::Timings.Timing) + print(io, "Compiler.Timings.Timing(", tinf.mi_info, ") with ", length(tinf.children), " children") +end + @specialize diff --git a/base/compiler/ssair/slot2ssa.jl b/Compiler/src/ssair/slot2ssa.jl similarity index 100% rename from base/compiler/ssair/slot2ssa.jl rename to Compiler/src/ssair/slot2ssa.jl diff --git a/base/compiler/ssair/tarjan.jl b/Compiler/src/ssair/tarjan.jl similarity index 99% rename from base/compiler/ssair/tarjan.jl rename to Compiler/src/ssair/tarjan.jl index 3727fe218dc1d..e73039868c367 100644 --- a/base/compiler/ssair/tarjan.jl +++ b/Compiler/src/ssair/tarjan.jl @@ -1,6 +1,6 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -using Core.Compiler: DomTree, CFG, BasicBlock, StmtRange, dominates +using .Compiler: DomTree, CFG, BasicBlock, StmtRange, dominates struct SCCStackItem v::Int32 diff --git a/base/compiler/ssair/verify.jl b/Compiler/src/ssair/verify.jl similarity index 100% rename from base/compiler/ssair/verify.jl rename to Compiler/src/ssair/verify.jl diff --git a/base/compiler/stmtinfo.jl b/Compiler/src/stmtinfo.jl similarity index 100% rename from base/compiler/stmtinfo.jl rename to Compiler/src/stmtinfo.jl diff --git a/base/compiler/tfuncs.jl b/Compiler/src/tfuncs.jl similarity index 99% rename from base/compiler/tfuncs.jl rename to Compiler/src/tfuncs.jl index f0212f1082331..3b524742b1609 100644 --- a/base/compiler/tfuncs.jl +++ b/Compiler/src/tfuncs.jl @@ -1436,7 +1436,7 @@ end if TF2 === Bottom RT = Bottom elseif isconcretetype(RT) && has_nontrivial_extended_info(𝕃ᡒ, TF2) # isconcrete condition required to form a PartialStruct - RT = PartialStruct(RT, Any[TF, TF2]) + RT = PartialStruct(fallback_lattice, RT, Any[TF, TF2]) end info = ModifyOpInfo(callinfo.info) return CallMeta(RT, Any, Effects(), info) @@ -1996,7 +1996,7 @@ function tuple_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any}) typ = Tuple{params...} # replace a singleton type with its equivalent Const object issingletontype(typ) && return Const(typ.instance) - return anyinfo ? PartialStruct(typ, argtypes) : typ + return anyinfo ? PartialStruct(𝕃, typ, argtypes) : typ end @nospecs function memoryrefget_tfunc(𝕃::AbstractLattice, mem, order, boundscheck) diff --git a/base/compiler/typeinfer.jl b/Compiler/src/typeinfer.jl similarity index 98% rename from base/compiler/typeinfer.jl rename to Compiler/src/typeinfer.jl index 1b3ff144639e4..94c65684e672c 100644 --- a/base/compiler/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -10,19 +10,19 @@ being used for this purpose alone. """ module Timings -using Core.Compiler: -, +, :, Vector, length, first, empty!, push!, pop!, @inline, +using ..Compiler: -, +, :, Vector, length, first, empty!, push!, pop!, @inline, @inbounds, copy, backtrace # What we record for any given frame we infer during type inference. struct InferenceFrameInfo mi::Core.MethodInstance world::UInt64 - sptypes::Vector{Core.Compiler.VarState} + sptypes::Vector{Compiler.VarState} slottypes::Vector{Any} nargs::Int end -function _typeinf_identifier(frame::Core.Compiler.InferenceState) +function _typeinf_identifier(frame::Compiler.InferenceState) mi_info = InferenceFrameInfo( frame.linfo, frame_world(sv), @@ -36,7 +36,7 @@ end _typeinf_identifier(frame::InferenceFrameInfo) = frame """ - Core.Compiler.Timing(mi_info, start_time, ...) + Compiler.Timing(mi_info, start_time, ...) Internal type containing the timing result for running type inference on a single MethodInstance. @@ -65,18 +65,18 @@ const _timings = Timing[] # ROOT() is an empty function used as the top-level Timing node to measure all time spent # *not* in type inference during a given recording trace. It is used as a "dummy" node. function ROOT() end -const ROOTmi = Core.Compiler.specialize_method( - first(Core.Compiler.methods(ROOT)), Tuple{typeof(ROOT)}, Core.svec()) +const ROOTmi = Compiler.specialize_method( + first(Compiler.methods(ROOT)), Tuple{typeof(ROOT)}, Core.svec()) """ - Core.Compiler.reset_timings() + Compiler.reset_timings() -Empty out the previously recorded type inference timings (`Core.Compiler._timings`), and +Empty out the previously recorded type inference timings (`Compiler._timings`), and start the ROOT() timer again. `ROOT()` measures all time spent _outside_ inference. """ function reset_timings() end push!(_timings, Timing( # The MethodInstance for ROOT(), and default empty values for other fields. - InferenceFrameInfo(ROOTmi, 0x0, Core.Compiler.VarState[], Any[Core.Const(ROOT)], 1), + InferenceFrameInfo(ROOTmi, 0x0, Compiler.VarState[], Any[Core.Const(ROOT)], 1), _time_ns())) function close_current_timer() end function enter_new_timer(frame) end @@ -85,7 +85,7 @@ function exit_current_timer(_expected_frame_) end end # module Timings """ - Core.Compiler.__set_measure_typeinf(onoff::Bool) + Compiler.__set_measure_typeinf(onoff::Bool) If set to `true`, record per-method-instance timings within type inference in the Compiler. """ @@ -861,7 +861,7 @@ function cached_return_type(code::CodeInstance) # the second subtyping/egal conditions are necessary to distinguish usual cases # from rare cases when `Const` wrapped those extended lattice type objects if isa(rettype_const, Vector{Any}) && !(Vector{Any} <: rettype) - return PartialStruct(rettype, rettype_const) + return PartialStruct(fallback_lattice, rettype, rettype_const) elseif isa(rettype_const, PartialOpaque) && rettype <: Core.OpaqueClosure return rettype_const elseif isa(rettype_const, InterConditional) && rettype !== InterConditional @@ -1179,7 +1179,7 @@ end function return_type(@nospecialize(f), t::DataType) # this method has a special tfunc world = tls_world_age() args = Any[_return_type, NativeInterpreter(world), Tuple{Core.Typeof(f), t.parameters...}] - return ccall(:jl_call_in_typeinf_world, Any, (Ptr{Ptr{Cvoid}}, Cint), args, length(args)) + return ccall(:jl_call_in_typeinf_world, Any, (Ptr{Any}, Cint), args, length(args)) end function return_type(@nospecialize(f), t::DataType, world::UInt) @@ -1193,7 +1193,7 @@ end function return_type(t::DataType, world::UInt) args = Any[_return_type, NativeInterpreter(world), t] - return ccall(:jl_call_in_typeinf_world, Any, (Ptr{Ptr{Cvoid}}, Cint), args, length(args)) + return ccall(:jl_call_in_typeinf_world, Any, (Ptr{Any}, Cint), args, length(args)) end function _return_type(interp::AbstractInterpreter, t::DataType) diff --git a/base/compiler/typelattice.jl b/Compiler/src/typelattice.jl similarity index 92% rename from base/compiler/typelattice.jl rename to Compiler/src/typelattice.jl index 86fa8af21615f..2832edc9219ff 100644 --- a/base/compiler/typelattice.jl +++ b/Compiler/src/typelattice.jl @@ -6,48 +6,7 @@ # N.B.: Const/PartialStruct/InterConditional are defined in Core, to allow them to be used # inside the global code cache. - -import Core: Const, PartialStruct - -""" - struct Const - val - end - -The type representing a constant value. -""" -:(Const) - -""" - struct PartialStruct - typ - fields::Vector{Any} # elements are other type lattice members - end - -This extended lattice element is introduced when we have information about an object's -fields beyond what can be obtained from the object type. E.g. it represents a tuple where -some elements are known to be constants or a struct whose `Any`-typed field is initialized -with `Int` values. - -- `typ` indicates the type of the object -- `fields` holds the lattice elements corresponding to each field of the object - -If `typ` is a struct, `fields` represents the fields of the struct that are guaranteed to be -initialized. For instance, if the length of `fields` of `PartialStruct` representing a -struct with 4 fields is 3, the 4th field may not be initialized. If the length is 4, all -fields are guaranteed to be initialized. - -If `typ` is a tuple, the last element of `fields` may be `Vararg`. In this case, it is -guaranteed that the number of elements in the tuple is at least `length(fields)-1`, but the -exact number of elements is unknown. -""" -:(PartialStruct) -function PartialStruct(@nospecialize(typ), fields::Vector{Any}) - for i = 1:length(fields) - assert_nested_slotwrapper(fields[i]) - end - return Core._PartialStruct(typ, fields) -end +import Core: Const, InterConditional, PartialStruct """ cnd::Conditional @@ -87,23 +46,6 @@ end Conditional(var::SlotNumber, @nospecialize(thentype), @nospecialize(elsetype); isdefined::Bool=false) = Conditional(slot_id(var), thentype, elsetype; isdefined) -import Core: InterConditional -""" - struct InterConditional - slot::Int - thentype - elsetype - end - -Similar to `Conditional`, but conveys inter-procedural constraints imposed on call arguments. -This is separate from `Conditional` to catch logic errors: the lattice element name is `InterConditional` -while processing a call, then `Conditional` everywhere else. Thus `InterConditional` does not appear in -`CompilerTypes`β€”these type's usages are disjointβ€”though we define the lattice for `InterConditional`. -""" -:(InterConditional) -InterConditional(var::SlotNumber, @nospecialize(thentype), @nospecialize(elsetype)) = - InterConditional(slot_id(var), thentype, elsetype) - const AnyConditional = Union{Conditional,InterConditional} Conditional(cnd::InterConditional) = Conditional(cnd.slot, cnd.thentype, cnd.elsetype) InterConditional(cnd::Conditional) = InterConditional(cnd.slot, cnd.thentype, cnd.elsetype) @@ -388,8 +330,8 @@ end end end return Conditional(slot, - thenfields === nothing ? Bottom : PartialStruct(vartyp.typ, thenfields), - elsefields === nothing ? Bottom : PartialStruct(vartyp.typ, elsefields)) + thenfields === nothing ? Bottom : PartialStruct(fallback_lattice, vartyp.typ, thenfields), + elsefields === nothing ? Bottom : PartialStruct(fallback_lattice, vartyp.typ, elsefields)) else vartyp_widened = widenconst(vartyp) thenfields = thentype === Bottom ? nothing : Any[] @@ -405,8 +347,8 @@ end end end return Conditional(slot, - thenfields === nothing ? Bottom : PartialStruct(vartyp_widened, thenfields), - elsefields === nothing ? Bottom : PartialStruct(vartyp_widened, elsefields)) + thenfields === nothing ? Bottom : PartialStruct(fallback_lattice, vartyp_widened, thenfields), + elsefields === nothing ? Bottom : PartialStruct(fallback_lattice, vartyp_widened, elsefields)) end end @@ -734,7 +676,7 @@ widenconst(::AnyConditional) = Bool widenconst(a::AnyMustAlias) = widenconst(widenmustalias(a)) widenconst(c::Const) = (v = c.val; isa(v, Type) ? Type{v} : typeof(v)) widenconst(::PartialTypeVar) = TypeVar -widenconst(t::PartialStruct) = t.typ +widenconst(t::Core.PartialStruct) = t.typ widenconst(t::PartialOpaque) = t.typ @nospecializeinfer widenconst(@nospecialize t::Type) = t widenconst(::TypeVar) = error("unhandled TypeVar") @@ -799,3 +741,13 @@ function stoverwrite1!(state::VarTable, change::StateUpdate) state[changeid] = newtype return state end + +# The ::AbstractLattice argument is unused and simply serves to disambiguate +# different instances of the compiler that may share the `Core.PartialStruct` +# type. +function Core.PartialStruct(::AbstractLattice, @nospecialize(typ), fields::Vector{Any}) + for i = 1:length(fields) + assert_nested_slotwrapper(fields[i]) + end + return Core._PartialStruct(typ, fields) +end diff --git a/base/compiler/typelimits.jl b/Compiler/src/typelimits.jl similarity index 99% rename from base/compiler/typelimits.jl rename to Compiler/src/typelimits.jl index 3d0e5f3d0877d..e420db030715b 100644 --- a/base/compiler/typelimits.jl +++ b/Compiler/src/typelimits.jl @@ -641,7 +641,7 @@ end β‹€(𝕃, tyi, ft) # just a type-level information, but more precise than the declared type end end - anyrefine && return PartialStruct(aty, fields) + anyrefine && return PartialStruct(𝕃, aty, fields) end return nothing end diff --git a/base/compiler/types.jl b/Compiler/src/types.jl similarity index 100% rename from base/compiler/types.jl rename to Compiler/src/types.jl diff --git a/base/compiler/typeutils.jl b/Compiler/src/typeutils.jl similarity index 100% rename from base/compiler/typeutils.jl rename to Compiler/src/typeutils.jl diff --git a/base/compiler/utilities.jl b/Compiler/src/utilities.jl similarity index 99% rename from base/compiler/utilities.jl rename to Compiler/src/utilities.jl index 5361ff26f997c..0f1e2988bd669 100644 --- a/base/compiler/utilities.jl +++ b/Compiler/src/utilities.jl @@ -42,12 +42,6 @@ end anymap(f::Function, a::Array{Any,1}) = Any[ f(a[i]) for i in 1:length(a) ] -########### -# scoping # -########### - -_topmod(m::Module) = ccall(:jl_base_relative_to, Any, (Any,), m)::Module - ############ # inlining # ############ diff --git a/base/compiler/validation.jl b/Compiler/src/validation.jl similarity index 100% rename from base/compiler/validation.jl rename to Compiler/src/validation.jl diff --git a/Makefile b/Makefile index 2cac2f8818324..f0b1dfaa708e4 100644 --- a/Makefile +++ b/Makefile @@ -75,6 +75,13 @@ ifndef JULIA_VAGRANT_BUILD endif endif +TOP_LEVEL_PKGS := Compiler + +TOP_LEVEL_PKG_LINK_TARGETS := $(addprefix $(build_datarootdir)/julia/,$(TOP_LEVEL_PKGS)) + +# Generate symlinks for top level pkgs in usr/share/julia/ +$(foreach module, $(TOP_LEVEL_PKGS), $(eval $(call symlink_target,$$(JULIAHOME)/$(module),$$(build_datarootdir)/julia,$(module)))) + julia-deps: | $(DIRS) $(build_datarootdir)/julia/base $(build_datarootdir)/julia/test @$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT)/deps @@ -103,10 +110,10 @@ julia-src-release julia-src-debug : julia-src-% : julia-deps julia_flisp.boot.in julia-cli-release julia-cli-debug: julia-cli-% : julia-deps @$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT)/cli $* -julia-sysimg-ji : julia-stdlib julia-base julia-cli-$(JULIA_BUILD_MODE) julia-src-$(JULIA_BUILD_MODE) | $(build_private_libdir) +julia-sysimg-ji : $(TOP_LEVEL_PKG_LINK_TARGETS) julia-stdlib julia-base julia-cli-$(JULIA_BUILD_MODE) julia-src-$(JULIA_BUILD_MODE) | $(build_private_libdir) @$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT) -f sysimage.mk sysimg-ji JULIA_EXECUTABLE='$(JULIA_EXECUTABLE)' -julia-sysimg-bc : julia-stdlib julia-base julia-cli-$(JULIA_BUILD_MODE) julia-src-$(JULIA_BUILD_MODE) | $(build_private_libdir) +julia-sysimg-bc : $(TOP_LEVEL_PKG_LINK_TARGETS) julia-stdlib julia-base julia-cli-$(JULIA_BUILD_MODE) julia-src-$(JULIA_BUILD_MODE) | $(build_private_libdir) @$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT) -f sysimage.mk sysimg-bc JULIA_EXECUTABLE='$(JULIA_EXECUTABLE)' julia-sysimg-release julia-sysimg-debug : julia-sysimg-% : julia-sysimg-ji julia-src-% diff --git a/base/Base.jl b/base/Base.jl index 874cec56329d1..39507b625660d 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -1,227 +1,8 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -baremodule Base - -using Core.Intrinsics, Core.IR - -# to start, we're going to use a very simple definition of `include` -# that doesn't require any function (except what we can get from the `Core` top-module) -# start this big so that we don't have to resize before we have defined how to grow an array -const _included_files = Array{Tuple{Module,String},1}(Core.undef, 400) -setfield!(_included_files, :size, (1,)) -function include(mod::Module, path::String) - len = getfield(_included_files.size, 1) - memlen = _included_files.ref.mem.length - lenp1 = Core.add_int(len, 1) - if len === memlen # by the time this is true we hopefully will have defined _growend! - _growend!(_included_files, UInt(1)) - else - setfield!(_included_files, :size, (lenp1,)) - end - Core.memoryrefset!(Core.memoryref(_included_files.ref, lenp1), (mod, ccall(:jl_prepend_cwd, Any, (Any,), path)), :not_atomic, true) - Core.println(path) - ccall(:jl_uv_flush, Nothing, (Ptr{Nothing},), Core.io_pointer(Core.stdout)) - Core.include(mod, path) -end -include(path::String) = include(Base, path) - -struct IncludeInto <: Function - m::Module -end -(this::IncludeInto)(fname::AbstractString) = include(this.m, fname) - -# from now on, this is now a top-module for resolving syntax -const is_primary_base_module = ccall(:jl_module_parent, Ref{Module}, (Any,), Base) === Core.Main -ccall(:jl_set_istopmod, Cvoid, (Any, Bool), Base, is_primary_base_module) - -# The @inline/@noinline macros that can be applied to a function declaration are not available -# until after array.jl, and so we will mark them within a function body instead. -macro inline() Expr(:meta, :inline) end -macro noinline() Expr(:meta, :noinline) end - -macro _boundscheck() Expr(:boundscheck) end - -# Try to help prevent users from shooting them-selves in the foot -# with ambiguities by defining a few common and critical operations -# (and these don't need the extra convert code) -getproperty(x::Module, f::Symbol) = (@inline; getglobal(x, f)) -getproperty(x::Type, f::Symbol) = (@inline; getfield(x, f)) -setproperty!(x::Type, f::Symbol, v) = error("setfield! fields of Types should not be changed") -setproperty!(x::Array, f::Symbol, v) = error("setfield! fields of Array should not be changed") -getproperty(x::Tuple, f::Int) = (@inline; getfield(x, f)) -setproperty!(x::Tuple, f::Int, v) = setfield!(x, f, v) # to get a decent error - -getproperty(x, f::Symbol) = (@inline; getfield(x, f)) -function setproperty!(x, f::Symbol, v) - ty = fieldtype(typeof(x), f) - val = v isa ty ? v : convert(ty, v) - return setfield!(x, f, val) -end - -typeof(function getproperty end).name.constprop_heuristic = Core.FORCE_CONST_PROP -typeof(function setproperty! end).name.constprop_heuristic = Core.FORCE_CONST_PROP - -dotgetproperty(x, f) = getproperty(x, f) - -getproperty(x::Module, f::Symbol, order::Symbol) = (@inline; getglobal(x, f, order)) -function setproperty!(x::Module, f::Symbol, v, order::Symbol=:monotonic) - @inline - ty = Core.get_binding_type(x, f) - val = v isa ty ? v : convert(ty, v) - return setglobal!(x, f, val, order) -end -getproperty(x::Type, f::Symbol, order::Symbol) = (@inline; getfield(x, f, order)) -setproperty!(x::Type, f::Symbol, v, order::Symbol) = error("setfield! fields of Types should not be changed") -getproperty(x::Tuple, f::Int, order::Symbol) = (@inline; getfield(x, f, order)) -setproperty!(x::Tuple, f::Int, v, order::Symbol) = setfield!(x, f, v, order) # to get a decent error - -getproperty(x, f::Symbol, order::Symbol) = (@inline; getfield(x, f, order)) -function setproperty!(x, f::Symbol, v, order::Symbol) - @inline - ty = fieldtype(typeof(x), f) - val = v isa ty ? v : convert(ty, v) - return setfield!(x, f, val, order) -end - -function swapproperty!(x, f::Symbol, v, order::Symbol=:not_atomic) - @inline - ty = fieldtype(typeof(x), f) - val = v isa ty ? v : convert(ty, v) - return Core.swapfield!(x, f, val, order) -end -function modifyproperty!(x, f::Symbol, op, v, order::Symbol=:not_atomic) - @inline - return Core.modifyfield!(x, f, op, v, order) -end -function replaceproperty!(x, f::Symbol, expected, desired, success_order::Symbol=:not_atomic, fail_order::Symbol=success_order) - @inline - ty = fieldtype(typeof(x), f) - val = desired isa ty ? desired : convert(ty, desired) - return Core.replacefield!(x, f, expected, val, success_order, fail_order) -end -function setpropertyonce!(x, f::Symbol, desired, success_order::Symbol=:not_atomic, fail_order::Symbol=success_order) - @inline - ty = fieldtype(typeof(x), f) - val = desired isa ty ? desired : convert(ty, desired) - return Core.setfieldonce!(x, f, val, success_order, fail_order) -end - -function swapproperty!(x::Module, f::Symbol, v, order::Symbol=:not_atomic) - @inline - ty = Core.get_binding_type(x, f) - val = v isa ty ? v : convert(ty, v) - return Core.swapglobal!(x, f, val, order) -end -function modifyproperty!(x::Module, f::Symbol, op, v, order::Symbol=:not_atomic) - @inline - return Core.modifyglobal!(x, f, op, v, order) -end -function replaceproperty!(x::Module, f::Symbol, expected, desired, success_order::Symbol=:not_atomic, fail_order::Symbol=success_order) - @inline - ty = Core.get_binding_type(x, f) - val = desired isa ty ? desired : convert(ty, desired) - return Core.replaceglobal!(x, f, expected, val, success_order, fail_order) -end -function setpropertyonce!(x::Module, f::Symbol, desired, success_order::Symbol=:not_atomic, fail_order::Symbol=success_order) - @inline - ty = Core.get_binding_type(x, f) - val = desired isa ty ? desired : convert(ty, desired) - return Core.setglobalonce!(x, f, val, success_order, fail_order) -end - - -convert(::Type{Any}, Core.@nospecialize x) = x -convert(::Type{T}, x::T) where {T} = x -include("coreio.jl") - -eval(x) = Core.eval(Base, x) -eval(m::Module, x) = Core.eval(m, x) +const start_base_include = time_ns() -# init core docsystem -import Core: @doc, @__doc__, WrappedException, @int128_str, @uint128_str, @big_str, @cmd -if isdefined(Core, :Compiler) - import Core.Compiler.CoreDocs - Core.atdoc!(CoreDocs.docm) -end - -include("exports.jl") -include("public.jl") - -if false - # simple print definitions for debugging. enable these if something - # goes wrong during bootstrap before printing code is available. - # otherwise, they just just eventually get (noisily) overwritten later - global show, print, println - show(io::IO, x) = Core.show(io, x) - print(io::IO, a...) = Core.print(io, a...) - println(io::IO, x...) = Core.println(io, x...) -end - -""" - time_ns() -> UInt64 - -Get the time in nanoseconds relative to some arbitrary time in the past. The primary use is for measuring the elapsed time -between two moments in time. -""" -time_ns() = ccall(:jl_hrtime, UInt64, ()) - -start_base_include = time_ns() - -# A warning to be interpolated in the docstring of every dangerous mutating function in Base, see PR #50824 -const _DOCS_ALIASING_WARNING = """ -!!! warning - Behavior can be unexpected when any mutated argument shares memory with any other argument. -""" - -## Load essential files and libraries -include("essentials.jl") -include("ctypes.jl") -include("gcutils.jl") -include("generator.jl") -include("runtime_internals.jl") include("reflection.jl") -include("options.jl") - -# define invoke(f, T, args...; kwargs...), without kwargs wrapping -# to forward to invoke -function Core.kwcall(kwargs::NamedTuple, ::typeof(invoke), f, T, args...) - @inline - # prepend kwargs and f to the invoked from the user - T = rewrap_unionall(Tuple{Core.Typeof(kwargs), Core.Typeof(f), (unwrap_unionall(T)::DataType).parameters...}, T) - return invoke(Core.kwcall, T, kwargs, f, args...) -end -# invoke does not have its own call cache, but kwcall for invoke does -setfield!(typeof(invoke).name.mt, :max_args, 3, :monotonic) # invoke, f, T, args... - -# define applicable(f, T, args...; kwargs...), without kwargs wrapping -# to forward to applicable -function Core.kwcall(kwargs::NamedTuple, ::typeof(applicable), @nospecialize(args...)) - @inline - return applicable(Core.kwcall, kwargs, args...) -end -function Core._hasmethod(@nospecialize(f), @nospecialize(t)) # this function has a special tfunc (TODO: make this a Builtin instead like applicable) - tt = rewrap_unionall(Tuple{Core.Typeof(f), (unwrap_unionall(t)::DataType).parameters...}, t) - return Core._hasmethod(tt) -end - -# core operations & types -include("promotion.jl") -include("tuple.jl") -include("expr.jl") -include("pair.jl") -include("traits.jl") -include("range.jl") -include("error.jl") - -# core numeric operations & types -==(x, y) = x === y -include("bool.jl") -include("number.jl") -include("int.jl") -include("operators.jl") -include("pointer.jl") -include("refvalue.jl") -include("cmem.jl") include("refpointer.jl") # now replace the Pair constructor (relevant for NamedTuples) with one that calls our Base.convert @@ -233,64 +14,7 @@ end # The REPL stdlib hooks into Base using this Ref const REPL_MODULE_REF = Ref{Module}(Base) - -include("checked.jl") -using .Checked -function cld end -function fld end - -# Lazy strings -include("strings/lazy.jl") - -# array structures -include("indices.jl") -include("genericmemory.jl") -include("array.jl") -include("abstractarray.jl") -include("subarray.jl") -include("views.jl") -include("baseext.jl") - -include("c.jl") -include("ntuple.jl") -include("abstractdict.jl") -include("iddict.jl") -include("idset.jl") -include("iterators.jl") -using .Iterators: zip, enumerate, only -using .Iterators: Flatten, Filter, product # for generators -using .Iterators: Stateful # compat (was formerly used in reinterpretarray.jl) -include("namedtuple.jl") - -# For OS specific stuff -# We need to strcat things here, before strings are really defined -function strcat(x::String, y::String) - out = ccall(:jl_alloc_string, Ref{String}, (Csize_t,), Core.sizeof(x) + Core.sizeof(y)) - GC.@preserve x y out begin - out_ptr = unsafe_convert(Ptr{UInt8}, out) - unsafe_copyto!(out_ptr, unsafe_convert(Ptr{UInt8}, x), Core.sizeof(x)) - unsafe_copyto!(out_ptr + Core.sizeof(x), unsafe_convert(Ptr{UInt8}, y), Core.sizeof(y)) - end - return out -end - -BUILDROOT::String = "" - -baremodule BuildSettings -end - -let i = 1 - global BUILDROOT - while i <= length(Core.ARGS) - if Core.ARGS[i] == "--buildsettings" - include(BuildSettings, ARGS[i+1]) - i += 1 - else - BUILDROOT = Core.ARGS[i] - end - i += 1 - end -end +process_sysimg_args!() include(strcat(BUILDROOT, "build_h.jl")) # include($BUILDROOT/base/build_h.jl) include(strcat(BUILDROOT, "version_git.jl")) # include($BUILDROOT/base/version_git.jl) @@ -332,13 +56,6 @@ include("reduce.jl") ## core structures include("reshapedarray.jl") include("reinterpretarray.jl") -include("bitarray.jl") -include("bitset.jl") - -if !isdefined(Core, :Compiler) - include("docs/core.jl") - Core.atdoc!(CoreDocs.docm) -end include("multimedia.jl") using .Multimedia @@ -347,7 +64,6 @@ using .Multimedia include("some.jl") include("dict.jl") -include("abstractset.jl") include("set.jl") # Strings @@ -485,10 +201,6 @@ include("accumulate.jl") include("permuteddimsarray.jl") using .PermutedDimsArrays -# basic data structures -include("ordering.jl") -using .Order - # Combinatorics include("sort.jl") using .Sort @@ -566,9 +278,8 @@ include("docs/basedocs.jl") # Documentation -- should always be included last in sysimg. include("docs/Docs.jl") using .Docs -if isdefined(Core, :Compiler) && is_primary_base_module - Docs.loaddocs(Core.Compiler.CoreDocs.DOCS) -end +Docs.loaddocs(CoreDocs.DOCS) +@eval CoreDocs DOCS = DocLinkedList() include("precompilation.jl") @@ -591,6 +302,10 @@ a_method_to_overwrite_in_test() = inferencebarrier(1) (this::IncludeInto)(fname::AbstractString) = include(identity, this.m, fname) (this::IncludeInto)(mapexpr::Function, fname::AbstractString) = include(mapexpr, this.m, fname) +# Compatibility with when Compiler was in Core +@eval Core const Compiler = Main.Base.Compiler +@eval Compiler const fl_parse = Core.Main.Base.fl_parse + # External libraries vendored into Base Core.println("JuliaSyntax/src/JuliaSyntax.jl") include(@__MODULE__, string(BUILDROOT, "JuliaSyntax/src/JuliaSyntax.jl")) # include($BUILDROOT/base/JuliaSyntax/JuliaSyntax.jl) @@ -681,10 +396,21 @@ end # enable threads support @eval PCRE PCRE_COMPILE_LOCK = Threads.SpinLock() +# Record dependency information for files belonging to the Compiler, so that +# we know whether the .ji can just give the Base copy or not. +# TODO: We may want to do this earlier to avoid TOCTOU issues. +const _compiler_require_dependencies = Any[] +for i = 1:length(_included_files) + isassigned(_included_files, i) || continue + (mod, file) = _included_files[i] + if mod === Compiler || parentmodule(mod) === Compiler || endswith(file, "/Compiler.jl") + _include_dependency!(_compiler_require_dependencies, true, mod, file, true, false) + end +end +@assert length(_compiler_require_dependencies) >= 15 + end # Ensure this file is also tracked @assert !isassigned(_included_files, 1) _included_files[1] = (parentmodule(Base), abspath(@__FILE__)) - -end # baremodule Base diff --git a/base/Base_compiler.jl b/base/Base_compiler.jl new file mode 100644 index 0000000000000..691e2c574acd6 --- /dev/null +++ b/base/Base_compiler.jl @@ -0,0 +1,302 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +baremodule Base +using Core.Intrinsics, Core.IR + +# to start, we're going to use a very simple definition of `include` +# that doesn't require any function (except what we can get from the `Core` top-module) +# start this big so that we don't have to resize before we have defined how to grow an array +const _included_files = Array{Tuple{Module,String},1}(Core.undef, 400) +setfield!(_included_files, :size, (1,)) +function include(mod::Module, path::String) + len = getfield(_included_files.size, 1) + memlen = _included_files.ref.mem.length + lenp1 = Core.add_int(len, 1) + if len === memlen # by the time this is true we hopefully will have defined _growend! + _growend!(_included_files, UInt(1)) + else + setfield!(_included_files, :size, (lenp1,)) + end + Core.memoryrefset!(Core.memoryref(_included_files.ref, lenp1), (mod, ccall(:jl_prepend_cwd, Any, (Any,), path)), :not_atomic, true) + Core.println(path) + ccall(:jl_uv_flush, Nothing, (Ptr{Nothing},), Core.io_pointer(Core.stdout)) + Core.include(mod, path) +end +include(path::String) = include(Base, path) + +struct IncludeInto <: Function + m::Module +end +(this::IncludeInto)(fname::AbstractString) = include(this.m, fname) + +# from now on, this is now a top-module for resolving syntax +const is_primary_base_module = ccall(:jl_module_parent, Ref{Module}, (Any,), Base) === Core.Main +ccall(:jl_set_istopmod, Cvoid, (Any, Bool), Base, is_primary_base_module) + +# The @inline/@noinline macros that can be applied to a function declaration are not available +# until after array.jl, and so we will mark them within a function body instead. +macro inline() Expr(:meta, :inline) end +macro noinline() Expr(:meta, :noinline) end + +macro _boundscheck() Expr(:boundscheck) end + +# Try to help prevent users from shooting them-selves in the foot +# with ambiguities by defining a few common and critical operations +# (and these don't need the extra convert code) +getproperty(x::Module, f::Symbol) = (@inline; getglobal(x, f)) +getproperty(x::Type, f::Symbol) = (@inline; getfield(x, f)) +setproperty!(x::Type, f::Symbol, v) = error("setfield! fields of Types should not be changed") +setproperty!(x::Array, f::Symbol, v) = error("setfield! fields of Array should not be changed") +getproperty(x::Tuple, f::Int) = (@inline; getfield(x, f)) +setproperty!(x::Tuple, f::Int, v) = setfield!(x, f, v) # to get a decent error + +getproperty(x, f::Symbol) = (@inline; getfield(x, f)) +function setproperty!(x, f::Symbol, v) + ty = fieldtype(typeof(x), f) + val = v isa ty ? v : convert(ty, v) + return setfield!(x, f, val) +end + +typeof(function getproperty end).name.constprop_heuristic = Core.FORCE_CONST_PROP +typeof(function setproperty! end).name.constprop_heuristic = Core.FORCE_CONST_PROP + +dotgetproperty(x, f) = getproperty(x, f) + +getproperty(x::Module, f::Symbol, order::Symbol) = (@inline; getglobal(x, f, order)) +function setproperty!(x::Module, f::Symbol, v, order::Symbol=:monotonic) + @inline + ty = Core.get_binding_type(x, f) + val = v isa ty ? v : convert(ty, v) + return setglobal!(x, f, val, order) +end +getproperty(x::Type, f::Symbol, order::Symbol) = (@inline; getfield(x, f, order)) +setproperty!(x::Type, f::Symbol, v, order::Symbol) = error("setfield! fields of Types should not be changed") +getproperty(x::Tuple, f::Int, order::Symbol) = (@inline; getfield(x, f, order)) +setproperty!(x::Tuple, f::Int, v, order::Symbol) = setfield!(x, f, v, order) # to get a decent error + +getproperty(x, f::Symbol, order::Symbol) = (@inline; getfield(x, f, order)) +function setproperty!(x, f::Symbol, v, order::Symbol) + @inline + ty = fieldtype(typeof(x), f) + val = v isa ty ? v : convert(ty, v) + return setfield!(x, f, val, order) +end + +function swapproperty!(x, f::Symbol, v, order::Symbol=:not_atomic) + @inline + ty = fieldtype(typeof(x), f) + val = v isa ty ? v : convert(ty, v) + return Core.swapfield!(x, f, val, order) +end +function modifyproperty!(x, f::Symbol, op, v, order::Symbol=:not_atomic) + @inline + return Core.modifyfield!(x, f, op, v, order) +end +function replaceproperty!(x, f::Symbol, expected, desired, success_order::Symbol=:not_atomic, fail_order::Symbol=success_order) + @inline + ty = fieldtype(typeof(x), f) + val = desired isa ty ? desired : convert(ty, desired) + return Core.replacefield!(x, f, expected, val, success_order, fail_order) +end +function setpropertyonce!(x, f::Symbol, desired, success_order::Symbol=:not_atomic, fail_order::Symbol=success_order) + @inline + ty = fieldtype(typeof(x), f) + val = desired isa ty ? desired : convert(ty, desired) + return Core.setfieldonce!(x, f, val, success_order, fail_order) +end + +function swapproperty!(x::Module, f::Symbol, v, order::Symbol=:not_atomic) + @inline + ty = Core.get_binding_type(x, f) + val = v isa ty ? v : convert(ty, v) + return Core.swapglobal!(x, f, val, order) +end +function modifyproperty!(x::Module, f::Symbol, op, v, order::Symbol=:not_atomic) + @inline + return Core.modifyglobal!(x, f, op, v, order) +end +function replaceproperty!(x::Module, f::Symbol, expected, desired, success_order::Symbol=:not_atomic, fail_order::Symbol=success_order) + @inline + ty = Core.get_binding_type(x, f) + val = desired isa ty ? desired : convert(ty, desired) + return Core.replaceglobal!(x, f, expected, val, success_order, fail_order) +end +function setpropertyonce!(x::Module, f::Symbol, desired, success_order::Symbol=:not_atomic, fail_order::Symbol=success_order) + @inline + ty = Core.get_binding_type(x, f) + val = desired isa ty ? desired : convert(ty, desired) + return Core.setglobalonce!(x, f, val, success_order, fail_order) +end + + +convert(::Type{Any}, Core.@nospecialize x) = x +convert(::Type{T}, x::T) where {T} = x +include("coreio.jl") + +import Core: @doc, @__doc__, WrappedException, @int128_str, @uint128_str, @big_str, @cmd + +# core docsystem +include("docs/core.jl") +Core.atdoc!(CoreDocs.docm) + +eval(x) = Core.eval(Base, x) +eval(m::Module, x) = Core.eval(m, x) + +include("exports.jl") +include("public.jl") + +if false + # simple print definitions for debugging. enable these if something + # goes wrong during bootstrap before printing code is available. + # otherwise, they just just eventually get (noisily) overwritten later + global show, print, println + show(io::IO, x) = Core.show(io, x) + print(io::IO, a...) = Core.print(io, a...) + println(io::IO, x...) = Core.println(io, x...) +end + +""" + time_ns() -> UInt64 + +Get the time in nanoseconds relative to some arbitrary time in the past. The primary use is for measuring the elapsed time +between two moments in time. +""" +time_ns() = ccall(:jl_hrtime, UInt64, ()) + +# A warning to be interpolated in the docstring of every dangerous mutating function in Base, see PR #50824 +const _DOCS_ALIASING_WARNING = """ +!!! warning + Behavior can be unexpected when any mutated argument shares memory with any other argument. +""" + +## Load essential files and libraries +include("essentials.jl") +include("ctypes.jl") +include("gcutils.jl") +include("generator.jl") +include("runtime_internals.jl") +include("options.jl") + +# define invoke(f, T, args...; kwargs...), without kwargs wrapping +# to forward to invoke +function Core.kwcall(kwargs::NamedTuple, ::typeof(invoke), f, T, args...) + @inline + # prepend kwargs and f to the invoked from the user + T = rewrap_unionall(Tuple{Core.Typeof(kwargs), Core.Typeof(f), (unwrap_unionall(T)::DataType).parameters...}, T) + return invoke(Core.kwcall, T, kwargs, f, args...) +end +# invoke does not have its own call cache, but kwcall for invoke does +setfield!(typeof(invoke).name.mt, :max_args, 3, :monotonic) # invoke, f, T, args... + +# define applicable(f, T, args...; kwargs...), without kwargs wrapping +# to forward to applicable +function Core.kwcall(kwargs::NamedTuple, ::typeof(applicable), @nospecialize(args...)) + @inline + return applicable(Core.kwcall, kwargs, args...) +end +function Core._hasmethod(@nospecialize(f), @nospecialize(t)) # this function has a special tfunc (TODO: make this a Builtin instead like applicable) + tt = rewrap_unionall(Tuple{Core.Typeof(f), (unwrap_unionall(t)::DataType).parameters...}, t) + return Core._hasmethod(tt) +end + +# core operations & types +include("promotion.jl") +include("tuple.jl") +include("expr.jl") +include("pair.jl") +include("traits.jl") +include("range.jl") +include("error.jl") + +# core numeric operations & types +==(x, y) = x === y +include("bool.jl") +include("number.jl") +include("int.jl") +include("operators.jl") +include("pointer.jl") +include("refvalue.jl") +include("cmem.jl") + +include("checked.jl") +using .Checked +function cld end +function fld end + +# Lazy strings +include("strings/lazy.jl") + +# array structures +include("indices.jl") +include("genericmemory.jl") +include("array.jl") +include("abstractarray.jl") +include("subarray.jl") +include("views.jl") +include("baseext.jl") + +include("c.jl") +include("ntuple.jl") +include("abstractset.jl") +include("bitarray.jl") +include("bitset.jl") +include("abstractdict.jl") +include("iddict.jl") +include("idset.jl") +include("iterators.jl") +using .Iterators: zip, enumerate, only +using .Iterators: Flatten, Filter, product # for generators +using .Iterators: Stateful # compat (was formerly used in reinterpretarray.jl) +include("namedtuple.jl") + +include("ordering.jl") +using .Order + +include("coreir.jl") + + +# For OS specific stuff +# We need to strcat things here, before strings are really defined +function strcat(x::String, y::String) + out = ccall(:jl_alloc_string, Ref{String}, (Csize_t,), Core.sizeof(x) + Core.sizeof(y)) + GC.@preserve x y out begin + out_ptr = unsafe_convert(Ptr{UInt8}, out) + unsafe_copyto!(out_ptr, unsafe_convert(Ptr{UInt8}, x), Core.sizeof(x)) + unsafe_copyto!(out_ptr + Core.sizeof(x), unsafe_convert(Ptr{UInt8}, y), Core.sizeof(y)) + end + return out +end + +BUILDROOT::String = "" + +baremodule BuildSettings +end + +function process_sysimg_args!() + let i = 1 + global BUILDROOT + while i <= length(Core.ARGS) + if Core.ARGS[i] == "--buildsettings" + include(BuildSettings, ARGS[i+1]) + i += 1 + else + BUILDROOT = Core.ARGS[i] + end + i += 1 + end + end +end +process_sysimg_args!() + +include(strcat(BUILDROOT, "../usr/share/julia/Compiler/src/Compiler.jl")) + +const _return_type = Compiler.return_type + +# Enable compiler +Compiler.bootstrap!() + +include("flparse.jl") +Core._setparser!(fl_parse) + +# Further definition of Base will happen in Base.jl if loaded. +end diff --git a/base/array.jl b/base/array.jl index 7a9649f20dded..68d0f13d3893a 100644 --- a/base/array.jl +++ b/base/array.jl @@ -769,28 +769,15 @@ end # gets inlined into the caller before recursion detection # gets a chance to see it, so that recursive calls to the caller # don't trigger the inference limiter -if isdefined(Core, :Compiler) - macro default_eltype(itr) - I = esc(itr) - return quote - if $I isa Generator && ($I).f isa Type - T = ($I).f - else - T = Core.Compiler.return_type(_iterator_upper_bound, Tuple{typeof($I)}) - end - promote_typejoin_union(T) - end - end -else - macro default_eltype(itr) - I = esc(itr) - return quote - if $I isa Generator && ($I).f isa Type - promote_typejoin_union($I.f) - else - Any - end +macro default_eltype(itr) + I = esc(itr) + return quote + if $I isa Generator && ($I).f isa Type + T = ($I).f + else + T = Base._return_type(_iterator_upper_bound, Tuple{typeof($I)}) end + promote_typejoin_union(T) end end diff --git a/base/bool.jl b/base/bool.jl index d7dcf76caa91b..3a5c36b09ae2c 100644 --- a/base/bool.jl +++ b/base/bool.jl @@ -184,3 +184,5 @@ end div(x::Bool, y::Bool) = y ? x : throw(DivideError()) rem(x::Bool, y::Bool) = y ? false : throw(DivideError()) mod(x::Bool, y::Bool) = rem(x,y) + +Bool(x::Real) = x==0 ? false : x==1 ? true : throw(InexactError(:Bool, Bool, x)) diff --git a/base/boot.jl b/base/boot.jl index 5d40191ecab21..612efc0b50c8a 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -512,7 +512,6 @@ eval(Core, quote UpsilonNode(@nospecialize(val)) = $(Expr(:new, :UpsilonNode, :val)) UpsilonNode() = $(Expr(:new, :UpsilonNode)) Const(@nospecialize(v)) = $(Expr(:new, :Const, :v)) - # NOTE the main constructor is defined within `Core.Compiler` _PartialStruct(@nospecialize(typ), fields::Array{Any, 1}) = $(Expr(:new, :PartialStruct, :typ, :fields)) PartialOpaque(@nospecialize(typ), @nospecialize(env), parent::MethodInstance, source) = $(Expr(:new, :PartialOpaque, :typ, :env, :parent, :source)) InterConditional(slot::Int, @nospecialize(thentype), @nospecialize(elsetype)) = $(Expr(:new, :InterConditional, :slot, :thentype, :elsetype)) diff --git a/base/client.jl b/base/client.jl index a04556507d5dc..e95d518d3e501 100644 --- a/base/client.jl +++ b/base/client.jl @@ -557,7 +557,7 @@ function _start() try repl_was_requested = exec_options(JLOptions()) if should_use_main_entrypoint() && !is_interactive - if Core.Compiler.generating_output() + if Base.generating_output() precompile(Main.main, (typeof(ARGS),)) else ret = invokelatest(Main.main, ARGS) diff --git a/base/compiler/bootstrap.jl b/base/compiler/bootstrap.jl deleted file mode 100644 index 12c83df74fe50..0000000000000 --- a/base/compiler/bootstrap.jl +++ /dev/null @@ -1,52 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -# make sure that typeinf is executed before turning on typeinf_ext -# this ensures that typeinf_ext doesn't recurse before it can add the item to the workq -# especially try to make sure any recursive and leaf functions have concrete signatures, -# since we won't be able to specialize & infer them at runtime - -let time() = ccall(:jl_clock_now, Float64, ()) - - interp = NativeInterpreter() - - # analyze_escapes_tt = Tuple{typeof(analyze_escapes), IRCode, Int, TODO} - optimize_tt = Tuple{typeof(optimize), NativeInterpreter, OptimizationState{NativeInterpreter}, InferenceResult} - fs = Any[ - # we first create caches for the optimizer, because they contain many loop constructions - # and they're better to not run in interpreter even during bootstrapping - #=analyze_escapes_tt,=# optimize_tt, - # then we create caches for inference entries - typeinf_ext, typeinf, typeinf_edge, - ] - # tfuncs can't be inferred from the inference entries above, so here we infer them manually - for x in T_FFUNC_VAL - push!(fs, x[3]) - end - for i = 1:length(T_IFUNC) - if isassigned(T_IFUNC, i) - x = T_IFUNC[i] - push!(fs, x[3]) - else - println(stderr, "WARNING: tfunc missing for ", reinterpret(IntrinsicFunction, Int32(i))) - end - end - starttime = time() - for f in fs - if isa(f, DataType) && f.name === typename(Tuple) - tt = f - else - tt = Tuple{typeof(f), Vararg{Any}} - end - for m in _methods_by_ftype(tt, 10, get_world_counter())::Vector - # remove any TypeVars from the intersection - m = m::MethodMatch - typ = Any[m.spec_types.parameters...] - for i = 1:length(typ) - typ[i] = unwraptv(typ[i]) - end - typeinf_type(interp, m.method, Tuple{typ...}, m.sparams) - end - end - endtime = time() - println("Core.Compiler ──── ", sub_float(endtime,starttime), " seconds") -end diff --git a/base/compiler/compiler.jl b/base/compiler/compiler.jl deleted file mode 100644 index 7d1dba88c9011..0000000000000 --- a/base/compiler/compiler.jl +++ /dev/null @@ -1,203 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -getfield(Core, :eval)(Core, :(baremodule Compiler - -using Core.Intrinsics, Core.IR - -import Core: print, println, show, write, unsafe_write, stdout, stderr, - _apply_iterate, svec, apply_type, Builtin, IntrinsicFunction, - MethodInstance, CodeInstance, MethodTable, MethodMatch, PartialOpaque, - TypeofVararg - -const getproperty = Core.getfield -const setproperty! = Core.setfield! -const swapproperty! = Core.swapfield! -const modifyproperty! = Core.modifyfield! -const replaceproperty! = Core.replacefield! -const _DOCS_ALIASING_WARNING = "" - -ccall(:jl_set_istopmod, Cvoid, (Any, Bool), Compiler, false) - -eval(x) = Core.eval(Compiler, x) -eval(m, x) = Core.eval(m, x) - -include(x) = Core.include(Compiler, x) -include(mod, x) = Core.include(mod, x) - -# The @inline/@noinline macros that can be applied to a function declaration are not available -# until after array.jl, and so we will mark them within a function body instead. -macro inline() Expr(:meta, :inline) end -macro noinline() Expr(:meta, :noinline) end - -macro _boundscheck() Expr(:boundscheck) end - -convert(::Type{Any}, Core.@nospecialize x) = x -convert(::Type{T}, x::T) where {T} = x - -# These types are used by reflection.jl and expr.jl too, so declare them here. -# Note that `@assume_effects` is available only after loading namedtuple.jl. -abstract type MethodTableView end -abstract type AbstractInterpreter end - -# essential files and libraries -include("essentials.jl") -include("ctypes.jl") -include("generator.jl") -include("runtime_internals.jl") -include("options.jl") - -ntuple(f, ::Val{0}) = () -ntuple(f, ::Val{1}) = (@inline; (f(1),)) -ntuple(f, ::Val{2}) = (@inline; (f(1), f(2))) -ntuple(f, ::Val{3}) = (@inline; (f(1), f(2), f(3))) -ntuple(f, ::Val{n}) where {n} = ntuple(f, n::Int) -ntuple(f, n) = (Any[f(i) for i = 1:n]...,) - -# core operations & types -function return_type end # promotion.jl expects this to exist -is_return_type(Core.@nospecialize(f)) = f === return_type -include("promotion.jl") -include("tuple.jl") -include("pair.jl") -include("traits.jl") -include("range.jl") -include("expr.jl") -include("error.jl") - -# core numeric operations & types -==(x::T, y::T) where {T} = x === y -include("bool.jl") -include("number.jl") -include("int.jl") -include("operators.jl") -include("pointer.jl") -include("refvalue.jl") - -# the same constructor as defined in float.jl, but with a different name to avoid redefinition -_Bool(x::Real) = x==0 ? false : x==1 ? true : throw(InexactError(:Bool, Bool, x)) -# fld(x,y) == div(x,y) - ((x>=0) != (y>=0) && rem(x,y) != 0 ? 1 : 0) -fld(x::T, y::T) where {T<:Unsigned} = div(x, y) -function fld(x::T, y::T) where T<:Integer - d = div(x, y) - return d - (signbit(x ⊻ y) & (d * y != x)) -end -# cld(x,y) = div(x,y) + ((x>0) == (y>0) && rem(x,y) != 0 ? 1 : 0) -function cld(x::T, y::T) where T<:Unsigned - d = div(x, y) - return d + (d * y != x) -end -function cld(x::T, y::T) where T<:Integer - d = div(x, y) - return d + (((x > 0) == (y > 0)) & (d * y != x)) -end - -# checked arithmetic -const checked_add = + -const checked_sub = - -const SignedInt = Union{Int8,Int16,Int32,Int64,Int128} -const UnsignedInt = Union{UInt8,UInt16,UInt32,UInt64,UInt128} -sub_with_overflow(x::T, y::T) where {T<:SignedInt} = checked_ssub_int(x, y) -sub_with_overflow(x::T, y::T) where {T<:UnsignedInt} = checked_usub_int(x, y) -sub_with_overflow(x::Bool, y::Bool) = (x-y, false) -add_with_overflow(x::T, y::T) where {T<:SignedInt} = checked_sadd_int(x, y) -add_with_overflow(x::T, y::T) where {T<:UnsignedInt} = checked_uadd_int(x, y) -add_with_overflow(x::Bool, y::Bool) = (x+y, false) - -include("cmem.jl") -include("strings/lazy.jl") - -# core array operations -include("indices.jl") -include("genericmemory.jl") -include("array.jl") -include("abstractarray.jl") - -# core structures -include("bitarray.jl") -include("bitset.jl") -include("abstractdict.jl") -include("iddict.jl") -include("idset.jl") -include("abstractset.jl") -include("iterators.jl") -using .Iterators: zip, enumerate -using .Iterators: Flatten, Filter, product # for generators -include("namedtuple.jl") - -# core docsystem -include("docs/core.jl") -import Core.Compiler.CoreDocs -Core.atdoc!(CoreDocs.docm) - -# sorting -include("ordering.jl") -using .Order -include("compiler/sort.jl") - -# We don't include some.jl, but this definition is still useful. -something(x::Nothing, y...) = something(y...) -something(x::Any, y...) = x - -############ -# compiler # -############ - -baremodule BuildSettings -using Core: ARGS, include -using Core.Compiler: >, getindex, length - -global MAX_METHODS::Int = 3 - -if length(ARGS) > 2 && ARGS[2] === "--buildsettings" - include(BuildSettings, ARGS[3]) -end -end - -if false - import Base: Base, @show -else - macro show(ex...) - blk = Expr(:block) - for s in ex - push!(blk.args, :(println(stdout, $(QuoteNode(s)), " = ", - begin local value = $(esc(s)) end))) - end - isempty(ex) || push!(blk.args, :value) - blk - end -end - -include("compiler/cicache.jl") -include("compiler/methodtable.jl") -include("compiler/effects.jl") -include("compiler/types.jl") -include("compiler/utilities.jl") -include("compiler/validation.jl") - -include("compiler/ssair/basicblock.jl") -include("compiler/ssair/domtree.jl") -include("compiler/ssair/ir.jl") -include("compiler/ssair/tarjan.jl") - -include("compiler/abstractlattice.jl") -include("compiler/stmtinfo.jl") -include("compiler/inferenceresult.jl") -include("compiler/inferencestate.jl") - -include("compiler/typeutils.jl") -include("compiler/typelimits.jl") -include("compiler/typelattice.jl") -include("compiler/tfuncs.jl") - -include("compiler/abstractinterpretation.jl") -include("compiler/typeinfer.jl") -include("compiler/optimize.jl") - -include("compiler/bootstrap.jl") -ccall(:jl_set_typeinf_func, Cvoid, (Any,), typeinf_ext_toplevel) - -include("compiler/parsing.jl") -Core._setparser!(fl_parse) - -end # baremodule Compiler -)) diff --git a/base/coreir.jl b/base/coreir.jl new file mode 100644 index 0000000000000..a21eeceffe4c5 --- /dev/null +++ b/base/coreir.jl @@ -0,0 +1,54 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +Core.PhiNode() = Core.PhiNode(Int32[], Any[]) + +""" + struct Const + val + end + +The type representing a constant value. +""" +Core.Const + +""" + struct PartialStruct + typ + fields::Vector{Any} # elements are other type lattice members + end + +This extended lattice element is introduced when we have information about an object's +fields beyond what can be obtained from the object type. E.g. it represents a tuple where +some elements are known to be constants or a struct whose `Any`-typed field is initialized +with `Int` values. + +- `typ` indicates the type of the object +- `fields` holds the lattice elements corresponding to each field of the object + +If `typ` is a struct, `fields` represents the fields of the struct that are guaranteed to be +initialized. For instance, if the length of `fields` of `PartialStruct` representing a +struct with 4 fields is 3, the 4th field may not be initialized. If the length is 4, all +fields are guaranteed to be initialized. + +If `typ` is a tuple, the last element of `fields` may be `Vararg`. In this case, it is +guaranteed that the number of elements in the tuple is at least `length(fields)-1`, but the +exact number of elements is unknown. +""" +Core.PartialStruct + +""" + struct InterConditional + slot::Int + thentype + elsetype + end + +Similar to `Conditional`, but conveys inter-procedural constraints imposed on call arguments. +This is separate from `Conditional` to catch logic errors: the lattice element name is `InterConditional` +while processing a call, then `Conditional` everywhere else. Thus `InterConditional` does not appear in +`CompilerTypes`β€”these type's usages are disjointβ€”though we define the lattice for `InterConditional`. +""" +Core.InterConditional + +InterConditional(var::SlotNumber, @nospecialize(thentype), @nospecialize(elsetype)) = + InterConditional(slot_id(var), thentype, elsetype) diff --git a/base/docs/Docs.jl b/base/docs/Docs.jl index 1a2403bbb8644..61c0cf71e70c2 100644 --- a/base/docs/Docs.jl +++ b/base/docs/Docs.jl @@ -750,15 +750,16 @@ include("utils.jl") # Swap out the bootstrap macro with the real one. Core.atdoc!(docm) -function loaddocs(docs::Vector{Core.SimpleVector}) - for (mod, ex, str, file, line) in docs +function loaddocs(docs::Base.CoreDocs.DocLinkedList) + while isdefined(docs, :doc) + (mod, ex, str, file, line) = docs.doc data = Dict{Symbol,Any}(:path => string(file), :linenumber => line) doc = docstr(str, data) lno = LineNumberNode(line, file) docstring = docm(lno, mod, doc, ex, false) # expand the real @doc macro now Core.eval(mod, Expr(:var"hygienic-scope", docstring, Docs, lno)) + docs = docs.next end - empty!(docs) nothing end diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index d618330e79874..c872244964160 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -2614,7 +2614,7 @@ ERROR: UndefVarError: `a` not defined in `M` Suggestion: add an appropriate import or assignment. This global was declared but not assigned. Stacktrace: [1] getproperty(x::Module, f::Symbol) - @ Base ./Base.jl:42 + @ Base ./Base_compiler.jl:40 [2] top-level scope @ none:1 diff --git a/base/docs/core.jl b/base/docs/core.jl index 718e49917632f..93265416099f9 100644 --- a/base/docs/core.jl +++ b/base/docs/core.jl @@ -2,15 +2,21 @@ module CoreDocs -import ..esc, ..push!, ..getindex, ..unsafe_load, ..Csize_t, ..@nospecialize +import Core: @nospecialize, SimpleVector -@nospecialize # don't specialize on any arguments of the methods declared herein +struct DocLinkedList + doc::SimpleVector + next::DocLinkedList + DocLinkedList() = new() + DocLinkedList(doc::SimpleVector, next::DocLinkedList) = new(doc, next) +end +global DOCS = DocLinkedList() function doc!(source::LineNumberNode, mod::Module, str, ex) - push!(DOCS, Core.svec(mod, ex, str, source.file, source.line)) + global DOCS + DOCS = DocLinkedList(Core.svec(mod, ex, str, source.file, source.line), DOCS) nothing end -const DOCS = Array{Core.SimpleVector,1}() isexpr(x, h::Symbol) = isa(x, Expr) && x.head === h @@ -25,9 +31,9 @@ function docm(source::LineNumberNode, mod::Module, str, x) else out = Expr(:block, x, out) end - return esc(out) + return Expr(:escape, out) end docm(source::LineNumberNode, mod::Module, x) = - isexpr(x, :->) ? docm(source, mod, x.args[1], x.args[2].args[2]) : error("invalid '@doc'.") + (isa(x, Expr) && x.head === :->) ? docm(source, mod, x.args[1], x.args[2].args[2]) : error("invalid '@doc'.") end diff --git a/base/error.jl b/base/error.jl index c49ede624607d..276555033443a 100644 --- a/base/error.jl +++ b/base/error.jl @@ -42,6 +42,7 @@ typeof(error).name.max_methods = UInt8(2) Raise an `ErrorException` with the given message. """ error(s::AbstractString) = throw(ErrorException(s)) +error() = throw(ErrorException("")) """ error(msg...) diff --git a/base/errorshow.jl b/base/errorshow.jl index 7225a024f529e..70ac8105feb21 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -448,7 +448,7 @@ function show_method_candidates(io::IO, ex::MethodError, kwargs=[]) # pool MethodErrors for these two functions. if f === convert && !isempty(arg_types_param) at1 = arg_types_param[1] - if isType(at1) && !Core.Compiler.has_free_typevars(at1) + if isType(at1) && !has_free_typevars(at1) push!(funcs, (at1.parameters[1], arg_types_param[2:end])) end end diff --git a/base/essentials.jl b/base/essentials.jl index 64fbaea95d4e7..efae59b82b5f9 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -184,11 +184,8 @@ end _nameof(m::Module) = ccall(:jl_module_name, Ref{Symbol}, (Any,), m) function _is_internal(__module__) - if ccall(:jl_base_relative_to, Any, (Any,), __module__)::Module === Core.Compiler || - _nameof(__module__) === :Base - return true - end - return false + return _nameof(__module__) === :Base || + _nameof(ccall(:jl_base_relative_to, Any, (Any,), __module__)::Module) === :Compiler end # can be used in place of `@assume_effects :total` (supposed to be used for bootstrapping) diff --git a/base/float.jl b/base/float.jl index ff628f0ac7126..90a5d8b1c66f4 100644 --- a/base/float.jl +++ b/base/float.jl @@ -248,8 +248,6 @@ for t1 in (Float16, Float32, Float64) end end -Bool(x::Real) = x==0 ? false : x==1 ? true : throw(InexactError(:Bool, Bool, x)) - promote_rule(::Type{Float64}, ::Type{UInt128}) = Float64 promote_rule(::Type{Float64}, ::Type{Int128}) = Float64 promote_rule(::Type{Float32}, ::Type{UInt128}) = Float32 diff --git a/base/compiler/parsing.jl b/base/flparse.jl similarity index 100% rename from base/compiler/parsing.jl rename to base/flparse.jl diff --git a/base/iterators.jl b/base/iterators.jl index 1a0d42ed7447f..6b8d9fe75e302 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -18,14 +18,9 @@ using .Base: tail, fieldtypes, min, max, minimum, zero, oneunit, promote, promote_shape, LazyString using Core: @doc -if Base !== Core.Compiler using .Base: cld, fld, SubArray, view, resize!, IndexCartesian using .Base.Checked: checked_mul -else - # Checked.checked_mul is not available during bootstrapping: - const checked_mul = * -end import .Base: first, last, @@ -35,13 +30,9 @@ import .Base: getindex, setindex!, get, iterate, popfirst!, isdone, peek, intersect -export enumerate, zip, rest, countfrom, take, drop, takewhile, dropwhile, cycle, repeated, product, flatten, flatmap +export enumerate, zip, rest, countfrom, take, drop, takewhile, dropwhile, cycle, repeated, product, flatten, flatmap, partition public accumulate, filter, map, peel, reverse, Stateful -if Base !== Core.Compiler -export partition -end - """ Iterators.map(f, iterators...) @@ -279,10 +270,8 @@ pairs(v::Core.SimpleVector) = Pairs(v, LinearIndices(v)) pairs(A::AbstractVector) = pairs(IndexLinear(), A) # pairs(v::Pairs) = v # listed for reference, but already defined from being an AbstractDict -if Base !== Core.Compiler pairs(::IndexCartesian, A::AbstractArray) = Pairs(A, Base.CartesianIndices(axes(A))) pairs(A::AbstractArray) = pairs(IndexCartesian(), A) -end length(v::Pairs) = length(getfield(v, :itr)) axes(v::Pairs) = axes(getfield(v, :itr)) @@ -1302,7 +1291,6 @@ true """ flatmap(f, c...) = flatten(map(f, c...)) -if Base !== Core.Compiler # views are not defined @doc """ partition(collection, n) @@ -1509,8 +1497,6 @@ IteratorSize(::Type{<:Stateful{T}}) where {T} = IteratorSize(T) isa IsInfinite ? eltype(::Type{<:Stateful{T}}) where {T} = eltype(T) IteratorEltype(::Type{<:Stateful{T}}) where {T} = IteratorEltype(T) -end # if statement several hundred lines above - """ only(x) diff --git a/base/loading.jl b/base/loading.jl index 7b45348f47009..2765c6ea3ed1f 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -1296,7 +1296,7 @@ function _include_from_serialized(pkg::PkgId, path::String, ocachepath::Union{No for M in restored M = M::Module - if parentmodule(M) === M && PkgId(M) == pkg + if is_root_module(M) && PkgId(M) == pkg register && register_root_module(M) if timing_imports elapsed_time = time_ns() - t_before @@ -2239,15 +2239,22 @@ const include_callbacks = Any[] const _concrete_dependencies = Pair{PkgId,UInt128}[] # these dependency versions are "set in stone", because they are explicitly loaded, and the process should try to avoid invalidating them const _require_dependencies = Any[] # a list of (mod, abspath, fsize, hash, mtime) tuples that are the file dependencies of the module currently being precompiled const _track_dependencies = Ref(false) # set this to true to track the list of file dependencies -function _include_dependency(mod::Module, _path::AbstractString; track_content=true, - path_may_be_dir=false) + +function _include_dependency(mod::Module, _path::AbstractString; track_content::Bool=true, + path_may_be_dir::Bool=false) + _include_dependency!(_require_dependencies, _track_dependencies[], mod, _path, track_content, path_may_be_dir) +end + +function _include_dependency!(dep_list::Vector{Any}, track_dependencies::Bool, + mod::Module, _path::AbstractString, + track_content::Bool, path_may_be_dir::Bool) prev = source_path(nothing) if prev === nothing path = abspath(_path) else path = normpath(joinpath(dirname(prev), _path)) end - if !_track_dependencies[] + if !track_dependencies[] if !path_may_be_dir && !isfile(path) throw(SystemError("opening file $(repr(path))", Libc.ENOENT)) elseif path_may_be_dir && !Filesystem.isreadable(path) @@ -2258,9 +2265,9 @@ function _include_dependency(mod::Module, _path::AbstractString; track_content=t if track_content hash = isdir(path) ? _crc32c(join(readdir(path))) : open(_crc32c, path, "r") # use mtime=-1.0 here so that fsize==0 && mtime==0.0 corresponds to a missing include_dependency - push!(_require_dependencies, (mod, path, filesize(path), hash, -1.0)) + push!(dep_list, (mod, path, filesize(path), hash, -1.0)) else - push!(_require_dependencies, (mod, path, UInt64(0), UInt32(0), mtime(path))) + push!(dep_list, (mod, path, UInt64(0), UInt32(0), mtime(path))) end end end @@ -2797,9 +2804,6 @@ function require_stdlib(package_uuidkey::PkgId, ext::Union{Nothing, String}=noth end end - - - # relative-path load """ @@ -3326,6 +3330,10 @@ mutable struct CacheHeaderIncludes const modpath::Vector{String} # seemingly not needed in Base, but used by Revise end +function CacheHeaderIncludes(dep_tuple::Tuple{Module, String, Int64, UInt32, Float64}) + return CacheHeaderIncludes(PkgId(dep_tuple[1]), dep_tuple[2:end]..., String[]) +end + function replace_depot_path(path::AbstractString, depots::Vector{String}=normalize_depots_for_relocation()) for depot in depots if startswith(path, string(depot, Filesystem.pathsep())) || path == depot @@ -3865,6 +3873,56 @@ function list_reasons(reasons::Dict{String,Int}) end list_reasons(::Nothing) = "" +function any_includes_stale(includes::Vector{CacheHeaderIncludes}, cachefile::String, reasons::Union{Dict{String,Int},Nothing}=nothing) + for chi in includes + f, fsize_req, hash_req, ftime_req = chi.filename, chi.fsize, chi.hash, chi.mtime + if startswith(f, string("@depot", Filesystem.pathsep())) + @debug("Rejecting stale cache file $cachefile because its depot could not be resolved") + record_reason(reasons, "nonresolveable depot") + return true + end + if !ispath(f) + _f = fixup_stdlib_path(f) + if _f != f && isfile(_f) && startswith(_f, Sys.STDLIB) + continue + end + @debug "Rejecting stale cache file $cachefile because file $f does not exist" + record_reason(reasons, "missing sourcefile") + return true + end + if ftime_req >= 0.0 + # this is an include_dependency for which we only recorded the mtime + ftime = mtime(f) + is_stale = ( ftime != ftime_req ) && + ( ftime != floor(ftime_req) ) && # Issue #13606, PR #13613: compensate for Docker images rounding mtimes + ( ftime != ceil(ftime_req) ) && # PR: #47433 Compensate for CirceCI's truncating of timestamps in its caching + ( ftime != trunc(ftime_req, digits=6) ) && # Issue #20837, PR #20840: compensate for GlusterFS truncating mtimes to microseconds + ( ftime != 1.0 ) && # PR #43090: provide compatibility with Nix mtime. + !( 0 < (ftime_req - ftime) < 1e-6 ) # PR #45552: Compensate for Windows tar giving mtimes that may be incorrect by up to one microsecond + if is_stale + @debug "Rejecting stale cache file $cachefile because mtime of include_dependency $f has changed (mtime $ftime, before $ftime_req)" + record_reason(reasons, "include_dependency mtime change") + return true + end + else + fstat = stat(f) + fsize = filesize(fstat) + if fsize != fsize_req + @debug "Rejecting stale cache file $cachefile because file size of $f has changed (file size $fsize, before $fsize_req)" + record_reason(reasons, "include_dependency fsize change") + return true + end + hash = isdir(fstat) ? _crc32c(join(readdir(f))) : open(_crc32c, f, "r") + if hash != hash_req + @debug "Rejecting stale cache file $cachefile because hash of $f has changed (hash $hash, before $hash_req)" + record_reason(reasons, "include_dependency fhash change") + return true + end + end + end + return false +end + # returns true if it "cachefile.ji" is stale relative to "modpath.jl" and build_id for modkey # otherwise returns the list of dependencies to also check @constprop :none function stale_cachefile(modpath::String, cachefile::String; ignore_loaded::Bool = false, requested_flags::CacheFlags=CacheFlags(), reasons=nothing) @@ -4024,51 +4082,8 @@ end return true end end - for chi in includes - f, fsize_req, hash_req, ftime_req = chi.filename, chi.fsize, chi.hash, chi.mtime - if startswith(f, string("@depot", Filesystem.pathsep())) - @debug("Rejecting stale cache file $cachefile because its depot could not be resolved") - record_reason(reasons, "nonresolveable depot") - return true - end - if !ispath(f) - _f = fixup_stdlib_path(f) - if _f != f && isfile(_f) && startswith(_f, Sys.STDLIB) - continue - end - @debug "Rejecting stale cache file $cachefile because file $f does not exist" - record_reason(reasons, "missing sourcefile") - return true - end - if ftime_req >= 0.0 - # this is an include_dependency for which we only recorded the mtime - ftime = mtime(f) - is_stale = ( ftime != ftime_req ) && - ( ftime != floor(ftime_req) ) && # Issue #13606, PR #13613: compensate for Docker images rounding mtimes - ( ftime != ceil(ftime_req) ) && # PR: #47433 Compensate for CirceCI's truncating of timestamps in its caching - ( ftime != trunc(ftime_req, digits=6) ) && # Issue #20837, PR #20840: compensate for GlusterFS truncating mtimes to microseconds - ( ftime != 1.0 ) && # PR #43090: provide compatibility with Nix mtime. - !( 0 < (ftime_req - ftime) < 1e-6 ) # PR #45552: Compensate for Windows tar giving mtimes that may be incorrect by up to one microsecond - if is_stale - @debug "Rejecting stale cache file $cachefile because mtime of include_dependency $f has changed (mtime $ftime, before $ftime_req)" - record_reason(reasons, "include_dependency mtime change") - return true - end - else - fstat = stat(f) - fsize = filesize(fstat) - if fsize != fsize_req - @debug "Rejecting stale cache file $cachefile because file size of $f has changed (file size $fsize, before $fsize_req)" - record_reason(reasons, "include_dependency fsize change") - return true - end - hash = isdir(fstat) ? _crc32c(join(readdir(f))) : open(_crc32c, f, "r") - if hash != hash_req - @debug "Rejecting stale cache file $cachefile because hash of $f has changed (hash $hash, before $hash_req)" - record_reason(reasons, "include_dependency fhash change") - return true - end - end + if any_includes_stale(includes, cachefile, reasons) + return true end end @@ -4148,6 +4163,12 @@ macro __DIR__() return isempty(_dirname) ? pwd() : abspath(_dirname) end +function prepare_compiler_stub_image!() + ccall(:jl_add_to_module_init_list, Cvoid, (Any,), Compiler) + register_root_module(Compiler) + filter!(mod->mod !== Compiler, loaded_modules_order) +end + """ precompile(f, argtypes::Tuple{Vararg{Any}}) diff --git a/base/meta.jl b/base/meta.jl index e648df29c12f9..bcf4fbf632ab2 100644 --- a/base/meta.jl +++ b/base/meta.jl @@ -449,7 +449,7 @@ function _partially_inline!(@nospecialize(x), slot_replacements::Vector{Any}, @assert isa(arg, Union{GlobalRef, Symbol}) return x end - elseif !Core.Compiler.is_meta_expr_head(head) + elseif !Base.is_meta_expr_head(head) partially_inline!(x.args, slot_replacements, type_signature, static_param_values, slot_offset, statement_offset, boundscheck) end diff --git a/base/opaque_closure.jl b/base/opaque_closure.jl index 0f1fdf47afed8..d7a91cff7d602 100644 --- a/base/opaque_closure.jl +++ b/base/opaque_closure.jl @@ -38,24 +38,25 @@ macro opaque(ty, ex) end # OpaqueClosure construction from pre-inferred CodeInfo/IRCode -using Core.Compiler: IRCode, SSAValue -using Core: CodeInfo +using Core: CodeInfo, SSAValue +using Base: Compiler +using .Compiler: IRCode function compute_ir_rettype(ir::IRCode) rt = Union{} for i = 1:length(ir.stmts) stmt = ir[SSAValue(i)][:stmt] - if isa(stmt, Core.Compiler.ReturnNode) && isdefined(stmt, :val) - rt = Core.Compiler.tmerge(Core.Compiler.argextype(stmt.val, ir), rt) + if isa(stmt, Core.ReturnNode) && isdefined(stmt, :val) + rt = Compiler.tmerge(Compiler.argextype(stmt.val, ir), rt) end end - return Core.Compiler.widenconst(rt) + return Compiler.widenconst(rt) end function compute_oc_signature(ir::IRCode, nargs::Int, isva::Bool) argtypes = Vector{Any}(undef, nargs) for i = 1:nargs - argtypes[i] = Core.Compiler.widenconst(ir.argtypes[i+1]) + argtypes[i] = Compiler.widenconst(ir.argtypes[i+1]) end if isva lastarg = pop!(argtypes) diff --git a/base/promotion.jl b/base/promotion.jl index 1004c64433ec1..72257f8ba5a3d 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -207,7 +207,7 @@ function typejoin_union_tuple(T::DataType) c = Vector{Any}(undef, lr) for i = 1:lr pi = p[i] - U = Core.Compiler.unwrapva(pi) + U = unwrapva(pi) if U === Union{} ci = Union{} elseif U isa Union @@ -217,7 +217,7 @@ function typejoin_union_tuple(T::DataType) else ci = promote_typejoin_union(U) end - if i == lr && Core.Compiler.isvarargtype(pi) + if i == lr && isvarargtype(pi) c[i] = isdefined(pi, :N) ? Vararg{ci, pi.N} : Vararg{ci} else c[i] = ci @@ -493,12 +493,6 @@ max(x::Real, y::Real) = max(promote(x,y)...) min(x::Real, y::Real) = min(promote(x,y)...) minmax(x::Real, y::Real) = minmax(promote(x, y)...) -if isdefined(Core, :Compiler) - const _return_type = Core.Compiler.return_type -else - _return_type(@nospecialize(f), @nospecialize(t)) = Any -end - function TupleOrBottom(tt...) any(p -> p === Union{}, tt) && return Union{} return Tuple{tt...} diff --git a/base/reduce.jl b/base/reduce.jl index 0c37256b64fb5..952d71bb2a849 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -1333,6 +1333,8 @@ end end @inline _all_tuple(f, anymissing) = anymissing ? missing : true +all(::Tuple{Missing}) = missing + ## count _bool(f) = x->f(x)::Bool diff --git a/base/reflection.jl b/base/reflection.jl index 0b7612e44f744..1b8ed9413a35b 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -1,7 +1,5 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -const Compiler = Core.Compiler - """ code_lowered(f, types; generated=true, debuginfo=:default) @@ -151,7 +149,7 @@ function method_instances(@nospecialize(f), @nospecialize(t), world::UInt) # 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::Core.MethodMatch) + instance = specialize_method(match::Core.MethodMatch) push!(results, instance) end return results @@ -348,6 +346,36 @@ function raise_match_failure(name::Symbol, @nospecialize(tt)) error("$name: unanalyzable call given $sig_str") end +const REFLECTION_COMPILER = RefValue{Union{Nothing, Module}}(nothing) + +function invoke_in_typeinf_world(args...) + vargs = Any[args...] + return ccall(:jl_call_in_typeinf_world, Any, (Ptr{Any}, Cint), vargs, length(vargs)) +end + +function invoke_default_compiler(fname::Symbol, args...) + if REFLECTION_COMPILER[] === nothing + return invoke_in_typeinf_world(getglobal(Compiler, fname), args...) + else + return getglobal(REFLECTION_COMPILER[], fname)(args...) + end +end + +function invoke_interp_compiler(interp, fname::Symbol, args...) + if interp === nothing + return invoke_default_compiler(fname, args...) + else + T = typeof(interp) + while true + Tname = typename(T).name + Tname === :Any && error("Expected Interpreter") + Tname === :AbstractInterpreter && break + T = supertype(T) + end + return getglobal(typename(T).module, fname)(args...) + end +end + """ code_typed_by_type(types::Type{<:Tuple}; ...) @@ -358,7 +386,9 @@ function code_typed_by_type(@nospecialize(tt::Type); optimize::Bool=true, debuginfo::Symbol=:default, world::UInt=get_world_counter(), - interp::Compiler.AbstractInterpreter=Compiler.NativeInterpreter(world)) + interp=nothing) + passed_interp = interp + interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp (ccall(:jl_is_in_pure_context, Bool, ()) || world == typemax(UInt)) && error("code reflection cannot be used from generated functions") if @isdefined(IRShow) @@ -370,12 +400,12 @@ function code_typed_by_type(@nospecialize(tt::Type); throw(ArgumentError("'debuginfo' must be either :source or :none")) end tt = to_tuple_type(tt) - matches = Compiler.findall(tt, Compiler.method_table(interp)) + matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt) matches === nothing && raise_match_failure(:code_typed, tt) asts = [] for match in matches.matches match = match::Core.MethodMatch - code = Compiler.typeinf_code(interp, match, optimize) + code = invoke_interp_compiler(passed_interp, :typeinf_code, interp, match, optimize) if code === nothing push!(asts, match.method => Any) else @@ -386,7 +416,7 @@ function code_typed_by_type(@nospecialize(tt::Type); return asts end -function get_oc_code_rt(oc::Core.OpaqueClosure, types, optimize::Bool) +function get_oc_code_rt(passed_interp, oc::Core.OpaqueClosure, types, optimize::Bool) @nospecialize oc types ccall(:jl_is_in_pure_context, Bool, ()) && error("code reflection cannot be used from generated functions") @@ -395,9 +425,9 @@ function get_oc_code_rt(oc::Core.OpaqueClosure, types, optimize::Bool) if isdefined(m, :source) if optimize tt = Tuple{typeof(oc.captures), to_tuple_type(types).parameters...} - mi = Compiler.specialize_method(m, tt, Core.svec()) - interp = Compiler.NativeInterpreter(m.primary_world) - code = Compiler.typeinf_code(interp, mi, optimize) + mi = specialize_method(m, tt, Core.svec()) + interp = invoke_interp_compiler(passed_interp, :_default_interp, m.primary_world) + code = invoke_interp_compiler(passed_interp, :typeinf_code, interp, mi, optimize) if code isa CodeInfo return Pair{CodeInfo, Any}(code, code.rettype) end @@ -420,9 +450,10 @@ end function code_typed_opaque_closure(oc::Core.OpaqueClosure, types; debuginfo::Symbol=:default, optimize::Bool=true, + interp=nothing, _...) @nospecialize oc types - (code, rt) = get_oc_code_rt(oc, types, optimize) + (code, rt) = get_oc_code_rt(interp, oc, types, optimize) debuginfo === :none && remove_linenums!(code) return Any[Pair{CodeInfo,Any}(code, rt)] end @@ -487,18 +518,20 @@ a full signature to query. function code_ircode_by_type( @nospecialize(tt::Type); world::UInt=get_world_counter(), - interp::Compiler.AbstractInterpreter=Compiler.NativeInterpreter(world), + interp=nothing, optimize_until::Union{Integer,AbstractString,Nothing}=nothing, ) + passed_interp = interp + interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp (ccall(:jl_is_in_pure_context, Bool, ()) || world == typemax(UInt)) && error("code reflection cannot be used from generated functions") tt = to_tuple_type(tt) - matches = Compiler.findall(tt, Compiler.method_table(interp)) + matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt) matches === nothing && raise_match_failure(:code_ircode, tt) asts = [] for match in matches.matches match = match::Core.MethodMatch - (code, ty) = Compiler.typeinf_ircode(interp, match, optimize_until) + (code, ty) = invoke_interp_compiler(passed_interp, :typeinf_ircode, interp, match, optimize_until) if code === nothing push!(asts, match.method => Any) else @@ -508,24 +541,26 @@ function code_ircode_by_type( return asts end -function _builtin_return_type(interp::Compiler.AbstractInterpreter, +function _builtin_return_type(passed_interp, interp, @nospecialize(f::Core.Builtin), @nospecialize(types)) argtypes = Any[to_tuple_type(types).parameters...] - rt = Compiler.builtin_tfunction(interp, f, argtypes, nothing) - return Compiler.widenconst(rt) + rt = invoke_interp_compiler(passed_interp, :builtin_tfunction, interp, f, argtypes, nothing) + return invoke_interp_compiler(passed_interp, :widenconst, rt) end -function _builtin_effects(interp::Compiler.AbstractInterpreter, +function _builtin_effects(passed_interp, interp, @nospecialize(f::Core.Builtin), @nospecialize(types)) argtypes = Any[to_tuple_type(types).parameters...] - rt = Compiler.builtin_tfunction(interp, f, argtypes, nothing) - return Compiler.builtin_effects(Compiler.typeinf_lattice(interp), f, argtypes, rt) + rt = invoke_interp_compiler(passed_interp, :builtin_tfunction, interp, f, argtypes, nothing) + return invoke_interp_compiler(passed_interp, :builtin_effects, + invoke_interp_compiler(passed_interp, :typeinf_lattice, interp), + f, argtypes, rt) end -function _builtin_exception_type(interp::Compiler.AbstractInterpreter, +function _builtin_exception_type(passed_interp, interp, @nospecialize(f::Core.Builtin), @nospecialize(types)) - effects = _builtin_effects(interp, f, types) - return Compiler.is_nothrow(effects) ? Union{} : Any + effects = _builtin_effects(passed_interp, interp, f, types) + return invoke_interp_compiler(passed_interp, :is_nothrow, effects) ? Union{} : Any end check_generated_context(world::UInt) = @@ -581,20 +616,22 @@ julia> Base.return_types(sum, (Union{Vector{Int},UnitRange{Int}},)) """ function return_types(@nospecialize(f), @nospecialize(types=default_tt(f)); world::UInt=get_world_counter(), - interp::Compiler.AbstractInterpreter=Compiler.NativeInterpreter(world)) + interp=nothing) + passed_interp = interp + interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp check_generated_context(world) if isa(f, Core.OpaqueClosure) - _, rt = only(code_typed_opaque_closure(f, types)) + _, rt = only(code_typed_opaque_closure(f, types; Compiler)) return Any[rt] elseif isa(f, Core.Builtin) - return Any[_builtin_return_type(interp, f, types)] + return Any[_builtin_return_type(passed_interp, interp, f, types)] end tt = signature_type(f, types) - matches = Compiler.findall(tt, Compiler.method_table(interp)) + matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt) matches === nothing && raise_match_failure(:return_types, tt) rts = Any[] for match in matches.matches - ty = Compiler.typeinf_type(interp, match::Core.MethodMatch) + ty = invoke_interp_compiler(passed_interp, :typeinf_type, interp, match::Core.MethodMatch) push!(rts, something(ty, Any)) end return rts @@ -649,20 +686,22 @@ On the other hand `Base.infer_return_type` returns one collective result that su """ function infer_return_type(@nospecialize(f), @nospecialize(types=default_tt(f)); world::UInt=get_world_counter(), - interp::Compiler.AbstractInterpreter=Compiler.NativeInterpreter(world)) + interp=nothing) + passed_interp = interp + interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp check_generated_context(world) if isa(f, Core.OpaqueClosure) - return last(only(code_typed_opaque_closure(f, types))) + return last(only(code_typed_opaque_closure(f, types; interp=passed_interp))) elseif isa(f, Core.Builtin) - return _builtin_return_type(interp, f, types) + return _builtin_return_type(passed_interp, interp, f, types) end tt = signature_type(f, types) - matches = Compiler.findall(tt, Compiler.method_table(interp)) + matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt) matches === nothing && raise_match_failure(:infer_return_type, tt) rt = Union{} for match in matches.matches - ty = Compiler.typeinf_type(interp, match::Core.MethodMatch) - rt = Compiler.tmerge(rt, something(ty, Any)) + ty = invoke_interp_compiler(passed_interp, :typeinf_type, interp, match::Core.MethodMatch) + rt = invoke_interp_compiler(passed_interp, :tmerge, rt, something(ty, Any)) end return rt end @@ -719,32 +758,31 @@ julia> Base.infer_exception_types(throw_if_number, (Any,)) """ function infer_exception_types(@nospecialize(f), @nospecialize(types=default_tt(f)); world::UInt=get_world_counter(), - interp::Compiler.AbstractInterpreter=Compiler.NativeInterpreter(world)) + interp=nothing) + passed_interp = interp + interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp check_generated_context(world) if isa(f, Core.OpaqueClosure) return Any[Any] # TODO elseif isa(f, Core.Builtin) - return Any[_builtin_exception_type(interp, f, types)] + return Any[_builtin_exception_type(passed_interp, interp, f, types)] end tt = signature_type(f, types) - matches = Compiler.findall(tt, Compiler.method_table(interp)) + matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt) matches === nothing && raise_match_failure(:infer_exception_types, tt) excts = Any[] for match in matches.matches - frame = Compiler.typeinf_frame(interp, match::Core.MethodMatch, #=run_optimizer=#false) + frame = invoke_interp_compiler(passed_interp, :typeinf_frame, interp, match::Core.MethodMatch, #=run_optimizer=#false) if frame === nothing exct = Any else - exct = Compiler.widenconst(frame.result.exc_result) + exct = invoke_interp_compiler(passed_interp, :widenconst, frame.result.exc_result) end push!(excts, exct) end return excts end -_may_throw_methoderror(matches#=::Core.Compiler.MethodLookupResult=#) = - matches.ambig || !any(match::Core.MethodMatch->match.fully_covers, matches.matches) - """ Base.infer_exception_type( f, types=default_tt(f); @@ -798,27 +836,18 @@ signature, the exception type is widened to `MethodError`. """ function infer_exception_type(@nospecialize(f), @nospecialize(types=default_tt(f)); world::UInt=get_world_counter(), - interp::Compiler.AbstractInterpreter=Compiler.NativeInterpreter(world)) + interp=nothing) + passed_interp = interp + interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp check_generated_context(world) if isa(f, Core.OpaqueClosure) return Any # TODO elseif isa(f, Core.Builtin) - return _builtin_exception_type(interp, f, types) + return _builtin_exception_type(passed_interp, interp, f, types) end tt = signature_type(f, types) - matches = Compiler.findall(tt, Compiler.method_table(interp)) - matches === nothing && raise_match_failure(:infer_exception_type, tt) - exct = Union{} - if _may_throw_methoderror(matches) - # account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature. - exct = Compiler.tmerge(exct, MethodError) - end - for match in matches.matches - match = match::Core.MethodMatch - frame = Compiler.typeinf_frame(interp, match, #=run_optimizer=#false) - frame === nothing && return Any - exct = Compiler.tmerge(exct, Compiler.widenconst(frame.result.exc_result)) - end + exct = invoke_interp_compiler(passed_interp, :_infer_exception_type, interp, tt, false) + exct === nothing && raise_match_failure(:infer_exception_type, tt) return exct end @@ -877,34 +906,25 @@ signature, the `:nothrow` bit gets tainted. The `Base.infer_effects` function should not be used from generated functions; doing so will result in an error. -$(Core.Compiler.effects_key_string) +$(Compiler.effects_key_string) # See Also -- [`Core.Compiler.Effects`](@ref): A type representing the computational effects of a method call. +- [`Compiler.Effects`](@ref): A type representing the computational effects of a method call. - [`Base.@assume_effects`](@ref): A macro for making assumptions about the effects of a method. """ function infer_effects(@nospecialize(f), @nospecialize(types=default_tt(f)); optimize::Bool=true, world::UInt=get_world_counter(), - interp::Compiler.AbstractInterpreter=Compiler.NativeInterpreter(world)) + interp=nothing) + passed_interp = interp + interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp check_generated_context(world) if isa(f, Core.Builtin) - return _builtin_effects(interp, f, types) + return _builtin_effects(passed_interp, interp, f, types) end tt = signature_type(f, types) - matches = Compiler.findall(tt, Compiler.method_table(interp)) - matches === nothing && raise_match_failure(:infer_effects, tt) - effects = Compiler.EFFECTS_TOTAL - if _may_throw_methoderror(matches) - # account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature. - effects = Compiler.Effects(effects; nothrow=false) - end - for match in matches.matches - match = match::Core.MethodMatch - frame = Compiler.typeinf_frame(interp, match, #=run_optimizer=#optimize) - frame === nothing && return Compiler.Effects() - effects = Compiler.merge_effects(effects, frame.result.ipo_effects) - end + effects = invoke_interp_compiler(passed_interp, :_infer_effects, interp, tt, optimize) + effects === nothing && raise_match_failure(:infer_effects, tt) return effects end @@ -921,24 +941,24 @@ end function print_statement_costs(io::IO, @nospecialize(tt::Type); world::UInt=get_world_counter(), - interp::Compiler.AbstractInterpreter=Compiler.NativeInterpreter(world)) + interp=nothing) + passed_interp = interp + interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp tt = to_tuple_type(tt) world == typemax(UInt) && error("code reflection cannot be used from generated functions") - matches = Compiler.findall(tt, Compiler.method_table(interp)) + matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt) matches === nothing && raise_match_failure(:print_statement_costs, tt) - params = Compiler.OptimizationParams(interp) cst = Int[] for match in matches.matches match = match::Core.MethodMatch println(io, match.method) - code = Compiler.typeinf_code(interp, match, true) + code = invoke_interp_compiler(passed_interp, :typeinf_code, interp, match, true) if code === nothing println(io, " inference not successful") else empty!(cst) resize!(cst, length(code.code)) - sptypes = Compiler.VarState[Compiler.VarState(sp, false) for sp in match.sparams] - maxcost = Compiler.statement_costs!(cst, code.code, code, sptypes, params) + maxcost = invoke_interp_compiler(passed_interp, :statement_costs!, interp, cst, code.code, code, match) nd = ndigits(maxcost) irshow_config = IRShow.IRShowConfig() do io, linestart, idx print(io, idx > 0 ? lpad(cst[idx], nd+1) : " "^(nd+1), " ") @@ -953,18 +973,11 @@ end print_statement_costs(args...; kwargs...) = print_statement_costs(stdout, args...; kwargs...) function _which(@nospecialize(tt::Type); - method_table::Union{Nothing,Core.MethodTable,Compiler.MethodTableView}=nothing, + method_table #=::Union{Nothing,Core.MethodTable,Compiler.MethodTableView}=# =nothing, world::UInt=get_world_counter(), raise::Bool=true) world == typemax(UInt) && error("code reflection cannot be used from generated functions") - if method_table === nothing - table = Compiler.InternalMethodTable(world) - elseif method_table isa Core.MethodTable - table = Compiler.OverlayMethodTable(world, method_table) - else - table = method_table - end - match, = Compiler.findsup(tt, table) + match, = invoke_default_compiler(:findsup_mt, tt, world, method_table) if match === nothing raise && error("no unique matching method found for the specified argument types") return nothing @@ -984,7 +997,7 @@ See also: [`parentmodule`](@ref), [`@which`](@ref Main.InteractiveUtils.@which), function which(@nospecialize(f), @nospecialize(t)) tt = signature_type(f, t) world = get_world_counter() - match, _ = Compiler._findsup(tt, nothing, world) + match, _ = invoke_default_compiler(:_findsup, tt, nothing, world) if match === nothing me = MethodError(f, t, world) ee = ErrorException(sprint(io -> begin @@ -1350,7 +1363,7 @@ julia> @macroexpand @invoke (xs::Xs)[i::I] = v::V The additional syntax is supported as of Julia 1.10. """ macro invoke(ex) - topmod = Compiler._topmod(__module__) # well, except, do not get it via CC but define it locally + topmod = _topmod(__module__) f, args, kwargs = destructure_callex(topmod, ex) types = Expr(:curly, :Tuple) out = Expr(:call, GlobalRef(Core, :invoke)) @@ -1409,7 +1422,7 @@ julia> @macroexpand @invokelatest xs[i] = v The additional `x.f` and `xs[i]` syntax requires Julia 1.10. """ macro invokelatest(ex) - topmod = Compiler._topmod(__module__) # well, except, do not get it via CC but define it locally + topmod = _topmod(__module__) f, args, kwargs = destructure_callex(topmod, ex) out = Expr(:call, GlobalRef(Base, :invokelatest)) isempty(kwargs) || push!(out.args, Expr(:parameters, kwargs...)) diff --git a/base/runtime_internals.jl b/base/runtime_internals.jl index 4a04d406550b7..cbbde7d9535a2 100644 --- a/base/runtime_internals.jl +++ b/base/runtime_internals.jl @@ -20,7 +20,7 @@ Base """ parentmodule(m::Module) = (@_total_meta; ccall(:jl_module_parent, Ref{Module}, (Any,), m)) -is_root_module(m::Module) = parentmodule(m) === m || (isdefined(Main, :Base) && m === Main.Base) +is_root_module(m::Module) = parentmodule(m) === m || m === Compiler || (isdefined(Main, :Base) && m === Main.Base) """ moduleroot(m::Module) -> Module @@ -1556,3 +1556,9 @@ function specialize_method(match::Core.MethodMatch; kwargs...) end hasintersect(@nospecialize(a), @nospecialize(b)) = typeintersect(a, b) !== Bottom + +########### +# scoping # +########### + +_topmod(m::Module) = ccall(:jl_base_relative_to, Any, (Any,), m)::Module diff --git a/base/show.jl b/base/show.jl index 627982b2bcb1a..8f305107d10f5 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1,6 +1,6 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -using Core.Compiler: has_typevar +using .Compiler: has_typevar function show(io::IO, ::MIME"text/plain", u::UndefInitializer) show(io, u) @@ -1385,35 +1385,6 @@ function show_mi(io::IO, mi::Core.MethodInstance, from_stackframe::Bool=false) end end -# These sometimes show up as Const-values in InferenceFrameInfo signatures -show(io::IO, r::Core.Compiler.UnitRange) = show(io, r.start : r.stop) -show(io::IO, mime::MIME{Symbol("text/plain")}, r::Core.Compiler.UnitRange) = show(io, mime, r.start : r.stop) - -function show(io::IO, mi_info::Core.Compiler.Timings.InferenceFrameInfo) - mi = mi_info.mi - def = mi.def - if isa(def, Method) - if isdefined(def, :generator) && mi === def.generator - print(io, "InferenceFrameInfo generator for ") - show(io, def) - else - print(io, "InferenceFrameInfo for ") - argnames = [isa(a, Core.Const) ? (isa(a.val, Type) ? "" : a.val) : "" for a in mi_info.slottypes[1:mi_info.nargs]] - show_tuple_as_call(io, def.name, mi.specTypes; argnames, qualified=true) - end - else - di = mi.cache.inferred.debuginfo - file, line = IRShow.debuginfo_firstline(di) - file = string(file) - line = isempty(file) || line < 0 ? "" : "$file:$line" - print(io, "Toplevel InferenceFrameInfo thunk from ", def, " starting at ", line) - end -end - -function show(io::IO, tinf::Core.Compiler.Timings.Timing) - print(io, "Core.Compiler.Timings.Timing(", tinf.mi_info, ") with ", length(tinf.children), " children") -end - function show_delim_array(io::IO, itr::Union{AbstractArray,SimpleVector}, op, delim, cl, delim_one, i1=first(LinearIndices(itr)), l=last(LinearIndices(itr))) print(io, op) @@ -2851,22 +2822,17 @@ function show(io::IO, vm::Core.TypeofVararg) end module IRShow - const Compiler = Core.Compiler + import ..Compiler using Core.IR import ..Base import .Compiler: IRCode, CFG, scan_ssa_use!, isexpr, compute_basic_blocks, block_for_inst, IncrementalCompact, - Effects, ALWAYS_TRUE, ALWAYS_FALSE, DebugInfoStream, getdebugidx - Base.getindex(r::Compiler.StmtRange, ind::Integer) = Compiler.getindex(r, ind) - Base.size(r::Compiler.StmtRange) = Compiler.size(r) - Base.first(r::Compiler.StmtRange) = Compiler.first(r) - Base.last(r::Compiler.StmtRange) = Compiler.last(r) - Base.length(is::Compiler.InstructionStream) = Compiler.length(is) - Base.iterate(is::Compiler.InstructionStream, st::Int=1) = (st <= Compiler.length(is)) ? (is[st], st + 1) : nothing - Base.getindex(is::Compiler.InstructionStream, idx::Int) = Compiler.getindex(is, idx) - Base.getindex(node::Compiler.Instruction, fld::Symbol) = Compiler.getindex(node, fld) - Base.getindex(ir::IRCode, ssa::SSAValue) = Compiler.getindex(ir, ssa) - include("compiler/ssair/show.jl") + Effects, ALWAYS_TRUE, ALWAYS_FALSE, DebugInfoStream, getdebugidx, + VarState, InvalidIRError, argextype, widenconst, singleton_type, + sptypes_from_meth_instance, EMPTY_SPTYPES, InferenceState, + NativeInterpreter, CachedMethodTable, LimitedAccuracy, Timings + + Base.include(IRShow, Base.strcat(Base.BUILDROOT, "../usr/share/julia/Compiler/src/ssair/show.jl")) const __debuginfo = Dict{Symbol, Any}( # :full => src -> statementidx_lineinfo_printer(src), # and add variable slot information @@ -2893,34 +2859,63 @@ function show(io::IO, src::CodeInfo; debuginfo::Symbol=:source) print(io, ")") end -function show(io::IO, inferred::Core.Compiler.InferenceResult) - mi = inferred.linfo - tt = mi.specTypes.parameters[2:end] - tts = join(["::$(t)" for t in tt], ", ") - rettype = inferred.result - if isa(rettype, Core.Compiler.InferenceState) - rettype = rettype.bestguess - end - if isa(mi.def, Method) - print(io, mi.def.name, "(", tts, " => ", rettype, ")") - else - print(io, "Toplevel MethodInstance thunk from ", mi.def, " => ", rettype) +show_unquoted(io::IO, val::Argument, indent::Int, prec::Int) = show_unquoted(io, Core.SlotNumber(val.n), indent, prec) + +show_unquoted(io::IO, stmt::PhiNode, indent::Int, ::Int) = show_unquoted_phinode(io, stmt, indent, "%") +function show_unquoted_phinode(io::IO, stmt::PhiNode, indent::Int, prefix::String) + args = String[let + e = stmt.edges[i] + v = !isassigned(stmt.values, i) ? "#undef" : + sprint(; context=io) do ioβ€² + show_unquoted(ioβ€², stmt.values[i], indent) + end + "$prefix$e => $v" + end for i in 1:length(stmt.edges) + ] + print(io, "Ο† ", '(') + join(io, args, ", ") + print(io, ')') +end + +function show_unquoted(io::IO, stmt::PhiCNode, indent::Int, ::Int) + print(io, "Ο†αΆœ (") + first = true + for v in stmt.values + first ? (first = false) : print(io, ", ") + show_unquoted(io, v, indent) end + print(io, ")") end -show(io::IO, sv::Core.Compiler.InferenceState) = - (print(io, "InferenceState for "); show(io, sv.linfo)) +function show_unquoted(io::IO, stmt::PiNode, indent::Int, ::Int) + print(io, "Ο€ (") + show_unquoted(io, stmt.val, indent) + print(io, ", ") + printstyled(io, stmt.typ, color=:cyan) + print(io, ")") +end -show(io::IO, ::Core.Compiler.NativeInterpreter) = - print(io, "Core.Compiler.NativeInterpreter(...)") +function show_unquoted(io::IO, stmt::UpsilonNode, indent::Int, ::Int) + print(io, "Ο’ (") + isdefined(stmt, :val) ? + show_unquoted(io, stmt.val, indent) : + print(io, "#undef") + print(io, ")") +end -show(io::IO, cache::Core.Compiler.CachedMethodTable) = - print(io, typeof(cache), "(", Core.Compiler.length(cache.cache), " entries)") +function show_unquoted(io::IO, stmt::ReturnNode, indent::Int, ::Int) + if !isdefined(stmt, :val) + print(io, "unreachable") + else + print(io, "return ") + show_unquoted(io, stmt.val, indent) + end +end -function show(io::IO, limited::Core.Compiler.LimitedAccuracy) - print(io, "Core.Compiler.LimitedAccuracy(") - show(io, limited.typ) - print(io, ", #= ", Core.Compiler.length(limited.causes), " cause(s) =#)") +show_unquoted(io::IO, stmt::GotoIfNot, indent::Int, ::Int) = show_unquoted_gotoifnot(io, stmt, indent, "%") +function show_unquoted_gotoifnot(io::IO, stmt::GotoIfNot, indent::Int, prefix::String) + print(io, "goto ", prefix, stmt.dest, " if not ") + show_unquoted(io, stmt.cond, indent) end function dump(io::IOContext, x::SimpleVector, n::Int, indent) diff --git a/base/stacktraces.jl b/base/stacktraces.jl index 102e415a22de2..e16757541cfc9 100644 --- a/base/stacktraces.jl +++ b/base/stacktraces.jl @@ -124,7 +124,7 @@ end const top_level_scope_sym = Symbol("top-level scope") -function lookup(ip::Union{Base.InterpreterIP,Core.Compiler.InterpreterIP}) +function lookup(ip::Base.InterpreterIP) code = ip.code if code === nothing # interpreted top-level expression with no CodeInfo @@ -175,7 +175,7 @@ Return a stack trace in the form of a vector of `StackFrame`s. (By default stack doesn't return C functions, but this can be enabled.) When called without specifying a trace, `stacktrace` first calls `backtrace`. """ -Base.@constprop :none function stacktrace(trace::Vector{<:Union{Base.InterpreterIP,Core.Compiler.InterpreterIP,Ptr{Cvoid}}}, c_funcs::Bool=false) +Base.@constprop :none function stacktrace(trace::Vector{<:Union{Base.InterpreterIP,Ptr{Cvoid}}}, c_funcs::Bool=false) stack = StackTrace() for ip in trace for frame in lookup(ip) diff --git a/base/sysimg.jl b/base/sysimg.jl index ccc8ef38e81bc..476b9715b7e11 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -1,6 +1,16 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -Core.include(Main, "Base.jl") +# Can be be loaded on top of either an existing system image built from +# `Base_compiler.jl` or standalone, in which case we will build it now. +let had_compiler = isdefined(Main, :Base) +if had_compiler; else +include("Base_compiler.jl") +end + +Core.include(Base, "Base.jl") + +had_compiler && ccall(:jl_init_restored_module, Cvoid, (Any,), Base) +end using .Base diff --git a/base/tuple.jl b/base/tuple.jl index fc213410cfd7c..8690f89bdc263 100644 --- a/base/tuple.jl +++ b/base/tuple.jl @@ -664,7 +664,9 @@ all(x::Tuple{}) = true all(x::Tuple{Bool}) = x[1] all(x::Tuple{Bool, Bool}) = x[1]&x[2] all(x::Tuple{Bool, Bool, Bool}) = x[1]&x[2]&x[3] -# use generic reductions for the rest +all(x::Tuple{Any}) = x[1] || return false +all(f, x::Tuple{}) = true +all(f, x::Tuple{Any}) = all((f(x[1]),)) any(x::Tuple{}) = false any(x::Tuple{Bool}) = x[1] diff --git a/contrib/generate_precompile.jl b/contrib/generate_precompile.jl index 55de3492e9447..ffbbfd620997f 100644 --- a/contrib/generate_precompile.jl +++ b/contrib/generate_precompile.jl @@ -359,6 +359,7 @@ generate_precompile_statements() = try # Make sure `ansi_enablecursor` is printe eval(PrecompileStagingArea, :(const $(Symbol(_mod)) = $_mod)) end end + eval(PrecompileStagingArea, :(const Compiler = Base.Compiler)) n_succeeded = 0 # Make statements unique diff --git a/doc/src/devdocs/EscapeAnalysis.md b/doc/src/devdocs/EscapeAnalysis.md index 1bd7868790f7f..ea874bf7371b0 100644 --- a/doc/src/devdocs/EscapeAnalysis.md +++ b/doc/src/devdocs/EscapeAnalysis.md @@ -1,6 +1,6 @@ # `EscapeAnalysis` -`Core.Compiler.EscapeAnalysis` is a compiler utility module that aims to analyze +`Compiler.EscapeAnalysis` is a compiler utility module that aims to analyze escape information of [Julia's SSA-form IR](@ref Julia-SSA-form-IR) a.k.a. `IRCode`. This escape analysis aims to: @@ -59,7 +59,7 @@ The symbols on the side of each call argument and SSA statements represent the f - `βœ“` (green or cyan): this value never escapes (`has_no_escape(result.state[x])` holds), colored blue if it has arg escape also (`has_arg_escape(result.state[x])` holds) - `↑` (blue or yellow): this value can escape to the caller via return (`has_return_escape(result.state[x])` holds), colored yellow if it has unhandled thrown escape also (`has_thrown_escape(result.state[x])` holds) - `X` (red): this value can escape to somewhere the escape analysis can't reason about like escapes to a global memory (`has_all_escape(result.state[x])` holds) -- `*` (bold): this value's escape state is between the `ReturnEscape` and `AllEscape` in the partial order of [`EscapeInfo`](@ref Core.Compiler.EscapeAnalysis.EscapeInfo), colored yellow if it has unhandled thrown escape also (`has_thrown_escape(result.state[x])` holds) +- `*` (bold): this value's escape state is between the `ReturnEscape` and `AllEscape` in the partial order of [`EscapeInfo`](@ref Base.Compiler.EscapeAnalysis.EscapeInfo), colored yellow if it has unhandled thrown escape also (`has_thrown_escape(result.state[x])` holds) - `β€²`: this value has additional object field / array element information in its `AliasInfo` property Escape information of each call argument and SSA value can be inspected programmatically as like: @@ -74,7 +74,7 @@ result.state[Core.SSAValue(3)] # get EscapeInfo of `r3` ### Lattice Design `EscapeAnalysis` is implemented as a [data-flow analysis](https://en.wikipedia.org/wiki/Data-flow_analysis) -that works on a lattice of [`x::EscapeInfo`](@ref Core.Compiler.EscapeAnalysis.EscapeInfo), +that works on a lattice of [`x::EscapeInfo`](@ref Base.Compiler.EscapeAnalysis.EscapeInfo), which is composed of the following properties: - `x.Analyzed::Bool`: not formally part of the lattice, only indicates `x` has not been analyzed or not - `x.ReturnEscape::BitSet`: records SSA statements where `x` can escape to the caller via return @@ -366,9 +366,9 @@ More interestingly, it is also valid to use `IPO EA` escape information for type e.g., inference accuracy can be improved by forming `Const`/`PartialStruct`/`MustAlias` of mutable object. ```@docs -Core.Compiler.EscapeAnalysis.analyze_escapes -Core.Compiler.EscapeAnalysis.EscapeState -Core.Compiler.EscapeAnalysis.EscapeInfo +Base.Compiler.EscapeAnalysis.analyze_escapes +Base.Compiler.EscapeAnalysis.EscapeState +Base.Compiler.EscapeAnalysis.EscapeInfo ``` -------------------------------------------------------------------------------------------- diff --git a/src/jltypes.c b/src/jltypes.c index 71eaa003d7d4a..6c6325d84a5ff 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3956,14 +3956,16 @@ void post_image_load_hooks(void) { // Ensure that `Base` has been loaded. assert(jl_base_module != NULL); - jl_libdl_module = (jl_module_t *)jl_get_global( - ((jl_module_t *)jl_get_global(jl_base_module, jl_symbol("Libc"))), - jl_symbol("Libdl") - ); - jl_libdl_dlopen_func = jl_get_global( - jl_libdl_module, - jl_symbol("dlopen") - ); + jl_module_t *libc_module = (jl_module_t *)jl_get_global(jl_base_module, jl_symbol("Libc")); + if (libc_module) { + jl_libdl_module = (jl_module_t *)jl_get_global(libc_module, jl_symbol("Libdl")); + } + if (jl_libdl_module) { + jl_libdl_dlopen_func = jl_get_global( + jl_libdl_module, + jl_symbol("dlopen") + ); + } } #undef XX diff --git a/src/module.c b/src/module.c index 08ad0d64dbf55..85813af6adc6f 100644 --- a/src/module.c +++ b/src/module.c @@ -1276,6 +1276,7 @@ JL_DLLEXPORT jl_uuid_t jl_module_uuid(jl_module_t* m) { return m->uuid; } // TODO: make this part of the module constructor and read-only? JL_DLLEXPORT void jl_set_module_uuid(jl_module_t *m, jl_uuid_t uuid) { m->uuid = uuid; } +JL_DLLEXPORT void jl_set_module_parent(jl_module_t *m, jl_module_t *parent) { m->parent = parent; } int jl_is_submodule(jl_module_t *child, jl_module_t *parent) JL_NOTSAFEPOINT { @@ -1308,15 +1309,20 @@ JL_DLLEXPORT void jl_clear_implicit_imports(jl_module_t *m) JL_UNLOCK(&m->lock); } +JL_DLLEXPORT void jl_add_to_module_init_list(jl_value_t *mod) +{ + if (jl_module_init_order == NULL) + jl_module_init_order = jl_alloc_vec_any(0); + jl_array_ptr_1d_push(jl_module_init_order, mod); +} + JL_DLLEXPORT void jl_init_restored_module(jl_value_t *mod) { if (!jl_generating_output() || jl_options.incremental) { jl_module_run_initializer((jl_module_t*)mod); } else { - if (jl_module_init_order == NULL) - jl_module_init_order = jl_alloc_vec_any(0); - jl_array_ptr_1d_push(jl_module_init_order, mod); + jl_add_to_module_init_list(mod); } } diff --git a/src/precompile_utils.c b/src/precompile_utils.c index fc361d8b88e6f..01e8a2040a751 100644 --- a/src/precompile_utils.c +++ b/src/precompile_utils.c @@ -281,6 +281,12 @@ static void *jl_precompile(int all) return native_code; } +static int suppress_precompile = 0; +JL_DLLEXPORT void jl_suppress_precompile(int suppress) +{ + suppress_precompile = suppress; +} + static void *jl_precompile_worklist(jl_array_t *worklist, jl_array_t *extext_methods, jl_array_t *new_ext_cis) { if (!worklist) @@ -289,34 +295,36 @@ static void *jl_precompile_worklist(jl_array_t *worklist, jl_array_t *extext_met // type signatures that were inferred but haven't been compiled jl_array_t *m = jl_alloc_vec_any(0); JL_GC_PUSH1(&m); - size_t i, n = jl_array_nrows(worklist); - for (i = 0; i < n; i++) { - jl_module_t *mod = (jl_module_t*)jl_array_ptr_ref(worklist, i); - assert(jl_is_module(mod)); - foreach_mtable_in_module(mod, precompile_enq_all_specializations_, m); - } - n = jl_array_nrows(extext_methods); - for (i = 0; i < n; i++) { - jl_method_t *method = (jl_method_t*)jl_array_ptr_ref(extext_methods, i); - assert(jl_is_method(method)); - jl_value_t *specializations = jl_atomic_load_relaxed(&method->specializations); - if (!jl_is_svec(specializations)) { - precompile_enq_specialization_((jl_method_instance_t*)specializations, m); + if (!suppress_precompile) { + size_t i, n = jl_array_nrows(worklist); + for (i = 0; i < n; i++) { + jl_module_t *mod = (jl_module_t*)jl_array_ptr_ref(worklist, i); + assert(jl_is_module(mod)); + foreach_mtable_in_module(mod, precompile_enq_all_specializations_, m); } - else { - size_t j, l = jl_svec_len(specializations); - for (j = 0; j < l; j++) { - jl_value_t *mi = jl_svecref(specializations, j); - if (mi != jl_nothing) - precompile_enq_specialization_((jl_method_instance_t*)mi, m); + n = jl_array_nrows(extext_methods); + for (i = 0; i < n; i++) { + jl_method_t *method = (jl_method_t*)jl_array_ptr_ref(extext_methods, i); + assert(jl_is_method(method)); + jl_value_t *specializations = jl_atomic_load_relaxed(&method->specializations); + if (!jl_is_svec(specializations)) { + precompile_enq_specialization_((jl_method_instance_t*)specializations, m); + } + else { + size_t j, l = jl_svec_len(specializations); + for (j = 0; j < l; j++) { + jl_value_t *mi = jl_svecref(specializations, j); + if (mi != jl_nothing) + precompile_enq_specialization_((jl_method_instance_t*)mi, m); + } } } - } - if (new_ext_cis) { - n = jl_array_nrows(new_ext_cis); - for (i = 0; i < n; i++) { - jl_code_instance_t *ci = (jl_code_instance_t*)jl_array_ptr_ref(new_ext_cis, i); - precompile_enq_specialization_(ci->def, m); + if (new_ext_cis) { + n = jl_array_nrows(new_ext_cis); + for (i = 0; i < n; i++) { + jl_code_instance_t *ci = (jl_code_instance_t*)jl_array_ptr_ref(new_ext_cis, i); + precompile_enq_specialization_(ci->def, m); + } } } void *native_code = jl_precompile_(m, 1); diff --git a/src/toplevel.c b/src/toplevel.c index 45143f99a178c..b0163683cf87c 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -1289,6 +1289,21 @@ JL_DLLEXPORT jl_value_t *jl_prepend_cwd(jl_value_t *str) return jl_cstr_to_string(path); } +JL_DLLEXPORT jl_value_t *jl_prepend_string(jl_value_t *prefix, jl_value_t *str) +{ + char path[1024]; + const char *pstr = (const char*)jl_string_data(prefix); + size_t sz = strlen(pstr); + const char *fstr = (const char*)jl_string_data(str); + if (strlen(fstr) + sz >= sizeof(path)) { + jl_errorf("use a bigger buffer for jl_fullpath"); + } + strcpy(path, pstr); + strcpy(path + sz, fstr); + return jl_cstr_to_string(path); +} + + #ifdef __cplusplus } #endif diff --git a/stdlib/InteractiveUtils/src/InteractiveUtils.jl b/stdlib/InteractiveUtils/src/InteractiveUtils.jl index f14e2f7de2f49..aa13fa3cdd31d 100644 --- a/stdlib/InteractiveUtils/src/InteractiveUtils.jl +++ b/stdlib/InteractiveUtils/src/InteractiveUtils.jl @@ -11,7 +11,8 @@ Base.Experimental.@optlevel 1 export apropos, edit, less, code_warntype, code_llvm, code_native, methodswith, varinfo, versioninfo, subtypes, supertypes, @which, @edit, @less, @functionloc, @code_warntype, - @code_typed, @code_lowered, @code_llvm, @code_native, @time_imports, clipboard, @trace_compile, @trace_dispatch + @code_typed, @code_lowered, @code_llvm, @code_native, @time_imports, clipboard, @trace_compile, @trace_dispatch, + @activate import Base.Docs.apropos diff --git a/stdlib/InteractiveUtils/src/codeview.jl b/stdlib/InteractiveUtils/src/codeview.jl index 92354d2fb9a75..1aa83a19285ff 100644 --- a/stdlib/InteractiveUtils/src/codeview.jl +++ b/stdlib/InteractiveUtils/src/codeview.jl @@ -145,7 +145,7 @@ See also: [`@code_warntype`](@ref), [`code_typed`](@ref), [`code_lowered`](@ref) """ function code_warntype(io::IO, @nospecialize(f), @nospecialize(tt=Base.default_tt(f)); world=Base.get_world_counter(), - interp::Core.Compiler.AbstractInterpreter=Core.Compiler.NativeInterpreter(world), + interp::Base.Compiler.AbstractInterpreter=Base.Compiler.NativeInterpreter(world), debuginfo::Symbol=:default, optimize::Bool=false, kwargs...) (ccall(:jl_is_in_pure_context, Bool, ()) || world == typemax(UInt)) && error("code reflection cannot be used from generated functions") @@ -159,12 +159,12 @@ function code_warntype(io::IO, @nospecialize(f), @nospecialize(tt=Base.default_t return nothing end tt = Base.signature_type(f, tt) - matches = Core.Compiler.findall(tt, Core.Compiler.method_table(interp)) + matches = findall(tt, Base.Compiler.method_table(interp)) matches === nothing && Base.raise_match_failure(:code_warntype, tt) for match in matches.matches match = match::Core.MethodMatch - src = Core.Compiler.typeinf_code(interp, match, optimize) - mi = Core.Compiler.specialize_method(match) + src = Base.Compiler.typeinf_code(interp, match, optimize) + mi = Base.Compiler.specialize_method(match) mi.def isa Method && (nargs = (mi.def::Method).nargs) print_warntype_mi(io, mi) if src isa Core.CodeInfo @@ -202,7 +202,7 @@ function _dump_function(@nospecialize(f), @nospecialize(t), native::Bool, wrappe if !isa(f, Core.OpaqueClosure) world = Base.get_world_counter() match = Base._which(signature_type(f, t); world) - mi = Core.Compiler.specialize_method(match) + mi = Base.specialize_method(match) # TODO: use jl_is_cacheable_sig instead of isdispatchtuple isdispatchtuple(mi.specTypes) || (warning = GENERIC_SIG_WARNING) else @@ -213,9 +213,9 @@ function _dump_function(@nospecialize(f), @nospecialize(t), native::Bool, wrappe # specialization and we can't infer anything more precise either. world = f.source.primary_world mi = f.source.specializations::Core.MethodInstance - Core.Compiler.hasintersect(typeof(f).parameters[1], tt) || (warning = OC_MISMATCH_WARNING) + Base.hasintersect(typeof(f).parameters[1], tt) || (warning = OC_MISMATCH_WARNING) else - mi = Core.Compiler.specialize_method(f.source, Tuple{typeof(f.captures), tt.parameters...}, Core.svec()) + mi = Base.specialize_method(f.source, Tuple{typeof(f.captures), tt.parameters...}, Core.svec()) isdispatchtuple(mi.specTypes) || (warning = GENERIC_SIG_WARNING) end end @@ -237,18 +237,18 @@ function _dump_function(@nospecialize(f), @nospecialize(t), native::Bool, wrappe if isempty(str) # if that failed (or we want metadata), use LLVM to generate more accurate assembly output if !isa(f, Core.OpaqueClosure) - src = Core.Compiler.typeinf_code(Core.Compiler.NativeInterpreter(world), mi, true) + src = Base.Compiler.typeinf_code(Base.Compiler.NativeInterpreter(world), mi, true) else - src, rt = Base.get_oc_code_rt(f, tt, true) + src, rt = Base.get_oc_code_rt(nothing, f, tt, true) end src isa Core.CodeInfo || error("failed to infer source for $mi") str = _dump_function_native_assembly(mi, src, wrapper, syntax, debuginfo, binary, raw, params) end else if !isa(f, Core.OpaqueClosure) - src = Core.Compiler.typeinf_code(Core.Compiler.NativeInterpreter(world), mi, true) + src = Base.Compiler.typeinf_code(Base.Compiler.NativeInterpreter(world), mi, true) else - src, rt = Base.get_oc_code_rt(f, tt, true) + src, rt = Base.get_oc_code_rt(nothing, f, tt, true) end src isa Core.CodeInfo || error("failed to infer source for $mi") str = _dump_function_llvm(mi, src, wrapper, !raw, dump_module, optimize, debuginfo, params) diff --git a/stdlib/InteractiveUtils/src/macros.jl b/stdlib/InteractiveUtils/src/macros.jl index a21bf30dbcd6c..68afc40976275 100644 --- a/stdlib/InteractiveUtils/src/macros.jl +++ b/stdlib/InteractiveUtils/src/macros.jl @@ -429,3 +429,64 @@ like the julia arg `--trace-dispatch=stderr` but specifically for a call. """ :@trace_dispatch + +""" + @activate Component + +Activate a newly loaded copy of an otherwise builtin component. The `Component` +to be activated will be resolved using the ordinary rules of module resolution +in the current environment. + +When using `@activate`, additional options for a component may be specified in +square brackets `@activate Compiler[:option1, :option]` + +Currently `@activate Compiler` is the only available component that may be +activatived. + +For `@activate Compiler`, the following options are available: +1. `:reflection` - Activate the compiler for reflection purposes only. + The ordinary reflection functionality in `Base` and `InteractiveUtils`. + Will use the newly loaded compiler. Note however, that these reflection + functions will still interact with the ordinary native cache (both loading + and storing). An incorrect compiler implementation may thus corrupt runtime + state if reflection is used. Use external packages like `Cthulhu.jl` + introspecting compiler behavior with a separated cache partition. + +2. `:codegen` - Activate the compiler for internal codegen purposes. The new compiler + will be invoked whenever the runtime requests compilation. + +`@activate Compiler` without options is equivalent to `@activate Compiler[:reflection]`. + +""" +macro activate(what) + options = Symbol[] + if Meta.isexpr(what, :ref) + Component = what.args[1] + for i = 2:length(what.args) + arg = what.args[i] + if !isa(arg, QuoteNode) || !isa(arg.value, Symbol) + error("Usage Error: Option $arg is not a symbol") + end + push!(options, arg.value) + end + else + Component = what + end + if !isa(Component, Symbol) + error("Usage Error: Component $Component is not a symbol") + end + allowed_components = (:Compiler,) + if !(Component in allowed_components) + error("Usage Error: Component $Component is not recognized. Expected one of $allowed_components") + end + s = gensym() + if Component === :Compiler && isempty(options) + push!(options, :reflection) + end + options = map(options) do opt + Expr(:kw, opt, true) + end + Expr(:toplevel, + esc(:(import $Component as $s)), + esc(:($s.activate!(;$(options...))))) +end diff --git a/stdlib/Makefile b/stdlib/Makefile index ebc40c9db2b12..aacf7ca30e146 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -39,7 +39,6 @@ install-$$($(1)_JLL_NAME)_jll: get-$$($(1)_JLL_NAME)_jll endef $(foreach jll,$(JLLS),$(eval $(call download-artifacts-toml,$(jll)))) - STDLIBS = Artifacts Base64 CRC32c Dates FileWatching \ Future InteractiveUtils Libdl LibGit2 LinearAlgebra Logging \ Markdown Mmap Printf Profile Random REPL Serialization \ @@ -56,7 +55,6 @@ ifneq ($(filter $(STDLIBS),$(STDLIBS_EXT)),) $(error ERROR duplicated STDLIBS in list) endif - # Generate symlinks to all stdlibs at usr/share/julia/stdlib/vX.Y/ $(foreach module, $(STDLIBS), $(eval $(call symlink_target,$$(JULIAHOME)/stdlib/$(module),$$(build_datarootdir)/julia/stdlib/$$(VERSDIR),$(module)))) diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 23f3337ab5e8e..df3a0cad76878 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -5,7 +5,10 @@ module REPLCompletions export completions, shell_completions, bslash_completions, completion_text using Core: Const -const CC = Core.Compiler +# We want to insulate the REPLCompletion module from any changes the user may +# make to the compiler, since it runs by default and the system becomes unusable +# if it breaks. +const CC = Base.Compiler using Base.Meta using Base: propertynames, something, IdSet using Base.Filesystem: _readdirx diff --git a/sysimage.mk b/sysimage.mk index d0e106d4ce3da..9e3e52157aa45 100644 --- a/sysimage.mk +++ b/sysimage.mk @@ -22,6 +22,7 @@ $(build_private_libdir)/%.$(SHLIB_EXT): $(build_private_libdir)/%-o.a @$(DSYMUTIL) $@ COMPILER_SRCS := $(addprefix $(JULIAHOME)/, \ + base/Base_compiler.jl \ base/boot.jl \ base/docs/core.jl \ base/abstractarray.jl \ @@ -49,24 +50,24 @@ COMPILER_SRCS := $(addprefix $(JULIAHOME)/, \ base/pointer.jl \ base/promotion.jl \ base/range.jl \ - base/reflection.jl \ + base/runtime_internals.jl \ base/traits.jl \ base/refvalue.jl \ base/tuple.jl) -COMPILER_SRCS += $(shell find $(JULIAHOME)/base/compiler -name \*.jl) +COMPILER_SRCS += $(shell find $(JULIAHOME)/Compiler/src -name \*.jl) # sort these to remove duplicates BASE_SRCS := $(sort $(shell find $(JULIAHOME)/base -name \*.jl -and -not -name sysimg.jl) \ $(shell find $(BUILDROOT)/base -name \*.jl -and -not -name sysimg.jl)) STDLIB_SRCS := $(JULIAHOME)/base/sysimg.jl $(SYSIMG_STDLIBS_SRCS) RELBUILDROOT := $(call rel_path,$(JULIAHOME)/base,$(BUILDROOT)/base)/ # <-- make sure this always has a trailing slash -$(build_private_libdir)/corecompiler.ji: $(COMPILER_SRCS) +$(build_private_libdir)/basecompiler.ji: $(COMPILER_SRCS) @$(call PRINT_JULIA, cd $(JULIAHOME)/base && \ $(call spawn,$(JULIA_EXECUTABLE)) -C "$(JULIA_CPU_TARGET)" $(HEAPLIM) --output-ji $(call cygpath_w,$@).tmp \ - --startup-file=no --warn-overwrite=yes -g$(BOOTSTRAP_DEBUG_LEVEL) -O1 compiler/compiler.jl) + --startup-file=no --warn-overwrite=yes -g$(BOOTSTRAP_DEBUG_LEVEL) -O1 Base_compiler.jl $(RELBUILDROOT)) @mv $@.tmp $@ -$(build_private_libdir)/sys.ji: $(build_private_libdir)/corecompiler.ji $(JULIAHOME)/VERSION $(BASE_SRCS) $(STDLIB_SRCS) +$(build_private_libdir)/sys.ji: $(build_private_libdir)/basecompiler.ji $(JULIAHOME)/VERSION $(BASE_SRCS) $(STDLIB_SRCS) @$(call PRINT_JULIA, cd $(JULIAHOME)/base && \ if ! JULIA_BINDIR=$(call cygpath_w,$(build_bindir)) WINEPATH="$(call cygpath_w,$(build_bindir));$$WINEPATH" \ $(call spawn, $(JULIA_EXECUTABLE)) -g1 -O1 -C "$(JULIA_CPU_TARGET)" $(HEAPLIM) --output-ji $(call cygpath_w,$@).tmp $(JULIA_SYSIMG_BUILD_FLAGS) \ diff --git a/test/ambiguous.jl b/test/ambiguous.jl index 2f8a4193cf592..43ec1aab0557d 100644 --- a/test/ambiguous.jl +++ b/test/ambiguous.jl @@ -192,8 +192,7 @@ end # some ambiguities involving Union{} type parameters may be expected, but not required let ambig = Set(detect_ambiguities(Core; recursive=true, ambiguous_bottom=true)) - @test !isempty(ambig) - @test length(ambig) < 30 + @test isempty(ambig) end STDLIB_DIR = Sys.STDLIB @@ -349,10 +348,6 @@ end # TODO: review this list and remove everything between test_broken and test let need_to_handle_undef_sparam = Set{Method}(detect_unbound_args(Core; recursive=true)) - pop!(need_to_handle_undef_sparam, which(Core.Compiler.eltype, Tuple{Type{Tuple{Any}}})) - @test_broken isempty(need_to_handle_undef_sparam) - pop!(need_to_handle_undef_sparam, which(Core.Compiler._cat, Tuple{Any, AbstractArray})) - pop!(need_to_handle_undef_sparam, first(methods(Core.Compiler.same_names))) @test isempty(need_to_handle_undef_sparam) end let need_to_handle_undef_sparam = diff --git a/test/backtrace.jl b/test/backtrace.jl index 68873678df57b..ee04a46b17304 100644 --- a/test/backtrace.jl +++ b/test/backtrace.jl @@ -237,7 +237,7 @@ let trace = try end @test trace[1].func === Symbol("top-level scope") @test trace[1].file === :a_filename - @test trace[1].line == 3 + @test trace[1].line in (2, 3) end # issue #45171 diff --git a/test/compiler/EscapeAnalysis/EAUtils.jl b/test/compiler/EscapeAnalysis/EAUtils.jl index 65fa9f75fe03f..4f1d1c0bba898 100644 --- a/test/compiler/EscapeAnalysis/EAUtils.jl +++ b/test/compiler/EscapeAnalysis/EAUtils.jl @@ -127,10 +127,6 @@ end using Core: Argument, SSAValue using .CC: widenconst, singleton_type -if EA._TOP_MOD === CC - Base.getindex(estate::EscapeState, @nospecialize(x)) = CC.getindex(estate, x) -end - function get_name_color(x::EscapeInfo, symbol::Bool = false) getname(x) = string(nameof(x)) if x === EA.βŠ₯ diff --git a/test/compiler/effects.jl b/test/compiler/effects.jl index 4174aa3d01030..bc9bc7e2295fe 100644 --- a/test/compiler/effects.jl +++ b/test/compiler/effects.jl @@ -927,7 +927,7 @@ unknown_sparam_nothrow2(x::Ref{Ref{T}}) where T = (T; nothing) # purely abstract recursion should not taint :terminates # https://github.com/JuliaLang/julia/issues/48983 abstractly_recursive1() = abstractly_recursive2() -abstractly_recursive2() = (Core.Compiler._return_type(abstractly_recursive1, Tuple{}); 1) +abstractly_recursive2() = (Base._return_type(abstractly_recursive1, Tuple{}); 1) abstractly_recursive3() = abstractly_recursive2() @test_broken Core.Compiler.is_terminates(Base.infer_effects(abstractly_recursive3, ())) actually_recursive1(x) = actually_recursive2(x) diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 9fafc9bdca6ad..8a14774e2404f 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -1535,7 +1535,7 @@ let nfields_tfunc(@nospecialize xs...) = @test sizeof_nothrow(String) @test !sizeof_nothrow(Type{String}) @test sizeof_tfunc(Type{Union{Int64, Int32}}) == Const(Core.sizeof(Union{Int64, Int32})) - let PT = Core.PartialStruct(Tuple{Int64,UInt64}, Any[Const(10), UInt64]) + let PT = Core.PartialStruct(Base.Compiler.fallback_lattice, Tuple{Int64,UInt64}, Any[Const(10), UInt64]) @test sizeof_tfunc(PT) === Const(16) @test nfields_tfunc(PT) === Const(2) @test sizeof_nothrow(PT) @@ -3381,9 +3381,9 @@ struct FooPartial b::Int c::Int end -let PT1 = PartialStruct(FooPartial, Any[Const(1), Const(2), Int]), - PT2 = PartialStruct(FooPartial, Any[Const(1), Int, Int]), - PT3 = PartialStruct(FooPartial, Any[Const(1), Int, Const(3)]) +let PT1 = PartialStruct(Base.Compiler.fallback_lattice, FooPartial, Any[Const(1), Const(2), Int]), + PT2 = PartialStruct(Base.Compiler.fallback_lattice, FooPartial, Any[Const(1), Int, Int]), + PT3 = PartialStruct(Base.Compiler.fallback_lattice, FooPartial, Any[Const(1), Int, Const(3)]) @test PT1 βŠ‘ PT2 @test !(PT1 βŠ‘ PT3) && !(PT2 βŠ‘ PT1) @@ -4635,18 +4635,18 @@ end @testset "issue #43784" begin βŠ‘ = Core.Compiler.partialorder(Core.Compiler.fallback_lattice) βŠ” = Core.Compiler.join(Core.Compiler.fallback_lattice) + 𝕃 = Core.Compiler.fallback_lattice Const, PartialStruct = Core.Const, Core.PartialStruct - let init = Base.ImmutableDict{Any,Any}() a = Const(init) - b = PartialStruct(typeof(init), Any[Const(init), Any, Any]) + b = PartialStruct(𝕃, typeof(init), Any[Const(init), Any, Any]) c = a βŠ” b @test a βŠ‘ c && b βŠ‘ c @test c === typeof(init) end let init = Base.ImmutableDict{Any,Any}(1,2) a = Const(init) - b = PartialStruct(typeof(init), Any[Const(getfield(init,1)), Any, Any]) + b = PartialStruct(𝕃, typeof(init), Any[Const(getfield(init,1)), Any, Any]) c = a βŠ” b @test a βŠ‘ c && b βŠ‘ c @test c isa PartialStruct @@ -4654,14 +4654,14 @@ end end let init = Base.ImmutableDict{Number,Number}() a = Const(init) - b = PartialStruct(typeof(init), Any[Const(init), Number, ComplexF64]) + b = PartialStruct(𝕃, typeof(init), Any[Const(init), Number, ComplexF64]) c = a βŠ” b @test a βŠ‘ c && b βŠ‘ c @test c === typeof(init) end let init = Base.ImmutableDict{Number,Number}() - a = PartialStruct(typeof(init), Any[Const(init), ComplexF64, ComplexF64]) - b = PartialStruct(typeof(init), Any[Const(init), Number, ComplexF64]) + a = PartialStruct(𝕃, typeof(init), Any[Const(init), ComplexF64, ComplexF64]) + b = PartialStruct(𝕃, typeof(init), Any[Const(init), Number, ComplexF64]) c = a βŠ” b @test a βŠ‘ c && b βŠ‘ c @test c isa PartialStruct @@ -4669,8 +4669,8 @@ end @test c.fields[3] === ComplexF64 end let init = Base.ImmutableDict{Number,Number}() - a = PartialStruct(typeof(init), Any[Const(init), ComplexF64, ComplexF64]) - b = PartialStruct(typeof(init), Any[Const(init), ComplexF32, Union{ComplexF32,ComplexF64}]) + a = PartialStruct(𝕃, typeof(init), Any[Const(init), ComplexF64, ComplexF64]) + b = PartialStruct(𝕃, typeof(init), Any[Const(init), ComplexF32, Union{ComplexF32,ComplexF64}]) c = a βŠ” b @test a βŠ‘ c && b βŠ‘ c @test c isa PartialStruct @@ -4678,8 +4678,8 @@ end @test c.fields[3] === Complex end let T = Base.ImmutableDict{Number,Number} - a = PartialStruct(T, Any[T]) - b = PartialStruct(T, Any[T, Number, Number]) + a = PartialStruct(𝕃, T, Any[T]) + b = PartialStruct(𝕃, T, Any[T, Number, Number]) @test b βŠ‘ a c = a βŠ” b @test a βŠ‘ c && b βŠ‘ c @@ -4687,7 +4687,7 @@ end @test length(c.fields) == 1 end let T = Base.ImmutableDict{Number,Number} - a = PartialStruct(T, Any[T]) + a = PartialStruct(𝕃, T, Any[T]) b = Const(T()) c = a βŠ” b @test a βŠ‘ c && b βŠ‘ c @@ -4695,7 +4695,7 @@ end end let T = Base.ImmutableDict{Number,Number} a = Const(T()) - b = PartialStruct(T, Any[T]) + b = PartialStruct(𝕃, T, Any[T]) c = a βŠ” b @test a βŠ‘ c && b βŠ‘ c @test c === T @@ -4742,22 +4742,23 @@ end let βŠ‘ = Core.Compiler.partialorder(Core.Compiler.fallback_lattice) βŠ” = Core.Compiler.join(Core.Compiler.fallback_lattice) + 𝕃 = Core.Compiler.fallback_lattice Const, PartialStruct = Core.Const, Core.PartialStruct - @test (Const((1,2)) βŠ‘ PartialStruct(Tuple{Int,Int}, Any[Const(1),Int])) - @test !(Const((1,2)) βŠ‘ PartialStruct(Tuple{Int,Int,Int}, Any[Const(1),Int,Int])) - @test !(Const((1,2,3)) βŠ‘ PartialStruct(Tuple{Int,Int}, Any[Const(1),Int])) - @test (Const((1,2,3)) βŠ‘ PartialStruct(Tuple{Int,Int,Int}, Any[Const(1),Int,Int])) - @test (Const((1,2)) βŠ‘ PartialStruct(Tuple{Int,Vararg{Int}}, Any[Const(1),Vararg{Int}])) - @test (Const((1,2)) βŠ‘ PartialStruct(Tuple{Int,Int,Vararg{Int}}, Any[Const(1),Int,Vararg{Int}])) broken=true - @test (Const((1,2,3)) βŠ‘ PartialStruct(Tuple{Int,Int,Vararg{Int}}, Any[Const(1),Int,Vararg{Int}])) - @test !(PartialStruct(Tuple{Int,Int}, Any[Const(1),Int]) βŠ‘ Const((1,2))) - @test !(PartialStruct(Tuple{Int,Int,Int}, Any[Const(1),Int,Int]) βŠ‘ Const((1,2))) - @test !(PartialStruct(Tuple{Int,Int}, Any[Const(1),Int]) βŠ‘ Const((1,2,3))) - @test !(PartialStruct(Tuple{Int,Int,Int}, Any[Const(1),Int,Int]) βŠ‘ Const((1,2,3))) - @test !(PartialStruct(Tuple{Int,Vararg{Int}}, Any[Const(1),Vararg{Int}]) βŠ‘ Const((1,2))) - @test !(PartialStruct(Tuple{Int,Int,Vararg{Int}}, Any[Const(1),Int,Vararg{Int}]) βŠ‘ Const((1,2))) - @test !(PartialStruct(Tuple{Int,Int,Vararg{Int}}, Any[Const(1),Int,Vararg{Int}]) βŠ‘ Const((1,2,3))) + @test (Const((1,2)) βŠ‘ PartialStruct(𝕃, Tuple{Int,Int}, Any[Const(1),Int])) + @test !(Const((1,2)) βŠ‘ PartialStruct(𝕃, Tuple{Int,Int,Int}, Any[Const(1),Int,Int])) + @test !(Const((1,2,3)) βŠ‘ PartialStruct(𝕃, Tuple{Int,Int}, Any[Const(1),Int])) + @test (Const((1,2,3)) βŠ‘ PartialStruct(𝕃, Tuple{Int,Int,Int}, Any[Const(1),Int,Int])) + @test (Const((1,2)) βŠ‘ PartialStruct(𝕃, Tuple{Int,Vararg{Int}}, Any[Const(1),Vararg{Int}])) + @test (Const((1,2)) βŠ‘ PartialStruct(𝕃, Tuple{Int,Int,Vararg{Int}}, Any[Const(1),Int,Vararg{Int}])) broken=true + @test (Const((1,2,3)) βŠ‘ PartialStruct(𝕃, Tuple{Int,Int,Vararg{Int}}, Any[Const(1),Int,Vararg{Int}])) + @test !(PartialStruct(𝕃, Tuple{Int,Int}, Any[Const(1),Int]) βŠ‘ Const((1,2))) + @test !(PartialStruct(𝕃, Tuple{Int,Int,Int}, Any[Const(1),Int,Int]) βŠ‘ Const((1,2))) + @test !(PartialStruct(𝕃, Tuple{Int,Int}, Any[Const(1),Int]) βŠ‘ Const((1,2,3))) + @test !(PartialStruct(𝕃, Tuple{Int,Int,Int}, Any[Const(1),Int,Int]) βŠ‘ Const((1,2,3))) + @test !(PartialStruct(𝕃, Tuple{Int,Vararg{Int}}, Any[Const(1),Vararg{Int}]) βŠ‘ Const((1,2))) + @test !(PartialStruct(𝕃, Tuple{Int,Int,Vararg{Int}}, Any[Const(1),Int,Vararg{Int}]) βŠ‘ Const((1,2))) + @test !(PartialStruct(𝕃, Tuple{Int,Int,Vararg{Int}}, Any[Const(1),Int,Vararg{Int}]) βŠ‘ Const((1,2,3))) t = Const((false, false)) βŠ” Const((false, true)) @test t isa PartialStruct && length(t.fields) == 2 && t.fields[1] === Const(false) @@ -4899,7 +4900,7 @@ let src = code_typed1() do end # Test that Const βŠ‘ PartialStruct respects vararg -@test Const((1,2)) βŠ‘ PartialStruct(Tuple{Vararg{Int}}, [Const(1), Vararg{Int}]) +@test Const((1,2)) βŠ‘ PartialStruct(Core.Compiler.fallback_lattice, Tuple{Vararg{Int}}, [Const(1), Vararg{Int}]) # Test that semi-concrete interpretation doesn't break on functions with while loops in them. Base.@assume_effects :consistent :effect_free :terminates_globally function pure_annotated_loop(x::Int, y::Int) diff --git a/test/docs.jl b/test/docs.jl index 8db9db30b8463..8cfdbba3f2d97 100644 --- a/test/docs.jl +++ b/test/docs.jl @@ -1518,7 +1518,7 @@ struct B_20087 end # issue #27832 _last_atdoc = Core.atdoc -Core.atdoc!(Core.Compiler.CoreDocs.docm) # test bootstrap doc system +Core.atdoc!(Base.CoreDocs.docm) # test bootstrap doc system """ """ diff --git a/test/misc.jl b/test/misc.jl index e089395ce4557..7f9992e22a3d7 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -560,7 +560,7 @@ struct ambigconvert; end # inject a problematic `convert` method to ensure it st Base.convert(::Any, v::ambigconvert) = v import Base.summarysize -@test summarysize(Core) > (summarysize(Core.Compiler) + Base.summarysize(Core.Intrinsics)) > Core.sizeof(Core) +@test summarysize(Core) > Base.summarysize(Core.Intrinsics) > Core.sizeof(Core) @test summarysize(Base) > 100_000 * sizeof(Ptr) let R = Ref{Any}(nothing), depth = 10^6