Skip to content

Commit

Permalink
Move Core.Compiler into Base
Browse files Browse the repository at this point in the history
This is the first step in what I am hoping will eventually result in making
the compiler itself and upgradable stdlib. Over time, we've gained several
non-Base consumers of `Core.Compiler`, and we've reached a bit of a breaking
point where maintaining those downstream dependencies is getting more difficult
than the close coupling of Core.Compiler to the runtime is worth.

In this first step, I am moving Core.Compiler into Base, ending the duplication
of common data structure and generic functions between Core.Compiler and Base.
This split goes back quite far (although not all the way) to the early days of
Julia and predates the world-age mechanism.

The extant Base and Core.Compiler environments have some differences
(other than the duplication). I think the primary ones are (but I will add
more here if somebody points one out).

- `Core.Compiler` does not use `getproperty`
- `Core.Compiler` does not have extensible `==` equality

In this, I decided to retain the former by setting `getproperty = getfield`
for Core.Compiler itself (though of course not for the datatstructures shared
with Base). I don't think it's strictly necessary, but might as well.

For equality, I decided the easiest thing to do would be to try to merge
the equalities and see what happens. In general, Core.Compiler is relatively
restricted in the kinds of equality comparisons it can make, so I think it'll
work out fine, but we can revisit this.

This seems to be fully working and most of this is just moving code around.
I think most of that refactoring is independently useful, so I'll pull some
of it out into separate PRs to make this PR more manageable.
  • Loading branch information
Keno committed Oct 17, 2024
1 parent 727a57e commit 08f4b0b
Show file tree
Hide file tree
Showing 42 changed files with 445 additions and 542 deletions.
267 changes: 10 additions & 257 deletions base/Base.jl
Original file line number Diff line number Diff line change
@@ -1,223 +1,15 @@
# 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)

# 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)
if isdefined(Base, :Compiler)
ccall(:jl_init_restored_module, Cvoid, (Any,), Base)
else
include("Base_compiler.jl")
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
const start_base_include = time_ns()

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)

# 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
Expand All @@ -230,33 +22,6 @@ 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
Expand Down Expand Up @@ -328,13 +93,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
Expand All @@ -343,7 +101,6 @@ using .Multimedia
include("some.jl")

include("dict.jl")
include("abstractset.jl")
include("set.jl")

# Strings
Expand Down Expand Up @@ -481,10 +238,6 @@ include("accumulate.jl")
include("permuteddimsarray.jl")
using .PermutedDimsArrays

# basic data structures
include("ordering.jl")
using .Order

# Combinatorics
include("sort.jl")
using .Sort
Expand Down Expand Up @@ -562,9 +315,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")

Expand All @@ -582,6 +334,9 @@ a_method_to_overwrite_in_test() = inferencebarrier(1)
include(mod::Module, _path::AbstractString) = _include(identity, mod, _path)
include(mapexpr::Function, mod::Module, _path::AbstractString) = _include(mapexpr, mod, _path)

# Compatibility with when Compiler was in Core
@eval Core const Compiler = Main.Base.Compiler

# 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)
Expand Down Expand Up @@ -678,5 +433,3 @@ end
# Ensure this file is also tracked
@assert !isassigned(_included_files, 1)
_included_files[1] = (parentmodule(Base), abspath(@__FILE__))

end # baremodule Base
Loading

0 comments on commit 08f4b0b

Please sign in to comment.