## [`julia_init()`](#julia_init())
[`jl_init_primitives()`](https://github.com/JuliaLang/julia/blob/master/src/builtins.c) hooks C functions up to Julia function symbols. e.g. the symbol `Core.:(===)()` is bound to C function pointer `jl_f_is()` by calling `add_builtin_func("===", jl_f_is)`.
[`jl_new_main_module()`](https://github.com/JuliaLang/julia/blob/master/src/toplevel.c) creates the global "Main" module and sets `jl_current_task->current_module = jl_main_module`.
Note: `_julia_init()` [then sets](https://github.com/JuliaLang/julia/blob/master/src/init.c) `jl_root_task->current_module = jl_core_module`. `jl_root_task` is an alias of `jl_current_task` at this point, so the `current_module` set by `jl_new_main_module()` above is overwritten.
[`jl_load("boot.jl", sizeof("boot.jl"))`](https://github.com/JuliaLang/julia/blob/master/src/init.c) calls [`jl_parse_eval_all`](https://github.com/JuliaLang/julia/blob/master/src/ast.c) which repeatedly calls [`jl_toplevel_eval_flex()`](https://github.com/JuliaLang/julia/blob/master/src/toplevel.c) to execute [`boot.jl`](https://github.com/JuliaLang/julia/blob/master/base/boot.jl). \<!– TODO – drill down into eval? –>
[`jl_get_builtin_hooks()`](https://github.com/JuliaLang/julia/blob/master/src/init.c) initializes global C pointers to Julia globals defined in `boot.jl`.
[`jl_init_box_caches()`](https://github.com/JuliaLang/julia/blob/master/src/datatype.c) pre-allocates global boxed integer value objects for values up to 1024. This speeds up allocation of boxed ints later on. e.g.:


## [`julia_init()`](#julia_init())
```c
jl_value_t *jl_box_uint8(uint32_t x)
{
    return boxed_uint8_cache[(uint8_t)x];
}
```
[`_julia_init()` iterates](https://github.com/JuliaLang/julia/blob/master/src/init.c) over the `jl_core_module->bindings.table` looking for `jl_datatype_t` values and sets the type name's module prefix to `jl_core_module`.
[`jl_add_standard_imports(jl_main_module)`](https://github.com/JuliaLang/julia/blob/master/src/toplevel.c) does "using Base" in the "Main" module.
Note: `_julia_init()` now reverts to `jl_root_task->current_module = jl_main_module` as it was before being set to `jl_core_module` above.
Platform specific signal handlers are initialized for `SIGSEGV` (OSX, Linux), and `SIGFPE` (Windows).
Other signals (`SIGINFO, SIGBUS, SIGILL, SIGTERM, SIGABRT, SIGQUIT, SIGSYS` and `SIGPIPE`) are hooked up to [`sigdie_handler()`](https://github.com/JuliaLang/julia/blob/master/src/signals-unix.c) which prints a backtrace.
[`jl_init_restored_module()`](https://github.com/JuliaLang/julia/blob/master/src/staticdata.c) calls [`jl_module_run_initializer()`](https://github.com/JuliaLang/julia/blob/master/src/module.c) for each deserialized module to run the `__init__()` function.
Finally [`sigint_handler()`](https://github.com/JuliaLang/julia/blob/master/src/signals-unix.c) is hooked up to `SIGINT` and calls `jl_throw(jl_interrupt_exception)`.
`_julia_init()` then returns [back to `main()` in `cli/loader_exe.c`](https://github.com/JuliaLang/julia/blob/master/cli/loader_exe.c) and `main()` calls `repl_entrypoint(argc, (char**)argv)`.


## [`julia_init()`](#julia_init())
If there is a sysimg file, it contains a pre-cooked image of the `Core` and `Main` modules (and whatever else is created by `boot.jl`). See [Building the Julia system image](../sysimg/#Building-the-Julia-system-image).
[`jl_restore_system_image()`](https://github.com/JuliaLang/julia/blob/master/src/staticdata.c) deserializes the saved sysimg into the current Julia runtime environment and initialization continues after `jl_init_box_caches()` below...
Note: [`jl_restore_system_image()` (and `staticdata.c` in general)](https://github.com/JuliaLang/julia/blob/master/src/staticdata.c) uses the [Legacy `ios.c` library](../stdio/#Legacy-ios.c-library).


## [`repl_entrypoint()`](#repl_entrypoint())
[`repl_entrypoint()`](https://github.com/JuliaLang/julia/blob/master/src/jlapi.c) loads the contents of `argv[]` into [`Base.ARGS`](../../base/constants/#Base.ARGS).
If a `.jl` "program" file was supplied on the command line, then [`exec_program()`](https://github.com/JuliaLang/julia/blob/master/src/jlapi.c) calls [`jl_load(program,len)`](https://github.com/JuliaLang/julia/blob/master/src/toplevel.c) which calls [`jl_parse_eval_all`](https://github.com/JuliaLang/julia/blob/master/src/ast.c) which repeatedly calls [`jl_toplevel_eval_flex()`](https://github.com/JuliaLang/julia/blob/master/src/toplevel.c) to execute the program.
However, in our example (`julia -e 'println("Hello World!")'`), [`jl_get_global(jl_base_module, jl_symbol("_start"))`](https://github.com/JuliaLang/julia/blob/master/src/module.c) looks up [`Base._start`](https://github.com/JuliaLang/julia/blob/master/base/client.jl) and [`jl_apply()`](https://github.com/JuliaLang/julia/blob/master/src/julia.h) executes it.


## [`Base._start`](#Base._start)
[`Base._start`](https://github.com/JuliaLang/julia/blob/master/base/client.jl) calls [`Base.exec_options`](https://github.com/JuliaLang/julia/blob/master/base/client.jl) which calls [`jl_parse_input_line("println("Hello World!")")`](https://github.com/JuliaLang/julia/blob/master/src/ast.c) to create an expression object and [`Core.eval(Main, ex)`](#Core.eval) to execute the parsed expression `ex` in the module context of `Main`.


## [`Core.eval`](#Core.eval)
[`Core.eval(Main, ex)`](#Core.eval) calls [`jl_toplevel_eval_in(m, ex)`](https://github.com/JuliaLang/julia/blob/master/src/toplevel.c), which calls [`jl_toplevel_eval_flex`](https://github.com/JuliaLang/julia/blob/master/src/toplevel.c). `jl_toplevel_eval_flex` implements a simple heuristic to decide whether to compile a given code thunk or run it by interpreter. When given `println("Hello World!")`, it would usually decide to run the code by interpreter, in which case it calls [`jl_interpret_toplevel_thunk`](https://github.com/JuliaLang/julia/blob/master/src/interpreter.c), which then calls [`eval_body`](https://github.com/JuliaLang/julia/blob/master/src/interpreter.c).
The stack dump below shows how the interpreter works its way through various methods of [`Base.println()`](../../base/io-network/#Base.println) and [`Base.print()`](../../base/io-network/#Base.print) before arriving at [`write(s::IO, a::Array{T}) where T`](https://github.com/JuliaLang/julia/blob/master/base/stream.jl) which does `ccall(jl_uv_write())`.
[`jl_uv_write()`](https://github.com/JuliaLang/julia/blob/master/src/jl_uv.c) calls `uv_write()` to write "Hello World!" to `JL_STDOUT`. See [Libuv wrappers for stdio](../stdio/#Libuv-wrappers-for-stdio).:
```julia
Hello World!
```


## [`Core.eval`](#Core.eval)
| Stack frame                   | Source code     | Notes                                                |
|:------------------------------|:----------------|:-----------------------------------------------------|
| `jl_uv_write()`               | `jl_uv.c`       | called though [`ccall`](../../base/c/#ccall)         |
| `julia_write_282942`          | `stream.jl`     | function `write!(s::IO, a::Array{T}) where T`        |
| `julia_print_284639`          | `ascii.jl`      | `print(io::IO, s::String) = (write(io, s); nothing)` |
| `jlcall_print_284639`         |                 |                                                      |
| `jl_apply()`                  | `julia.h`       |                                                      |
| `jl_trampoline()`             | `builtins.c`    |                                                      |
| `jl_apply()`                  | `julia.h`       |                                                      |
| `jl_apply_generic()`          | `gf.c`          | `Base.print(Base.TTY, String)`                       |
| `jl_apply()`                  | `julia.h`       |                                                      |
| `jl_trampoline()`             | `builtins.c`    |                                                      |
| `jl_apply()`                  | `julia.h`       |                                                      |
| `jl_apply_generic()`          | `gf.c`          | `Base.print(Base.TTY, String, Char, Char...)`        |
| `jl_apply()`                  | `julia.h`       |                                                      |
| `jl_f_apply()`                | `builtins.c`    |                                                      |
| `jl_apply()`                  | `julia.h`       |                                                      |
| `jl_trampoline()`             | `builtins.c`    |                                                      |
| `jl_apply()`                  | `julia.h`       |                                                      |
| `jl_apply_generic()`          | `gf.c`          | `Base.println(Base.TTY, String, String...)`          |
| `jl_apply()`                  | `julia.h`       |                                                      |
| `jl_trampoline()`             | `builtins.c`    |                                                      |
| `jl_apply()`                  | `julia.h`       |                                                      |
| `jl_apply_generic()`          | `gf.c`          | `Base.println(String,)`                              |
| `jl_apply()`                  | `julia.h`       |                                                      |
| `do_call()`                   | `interpreter.c` |                                                      |
| `eval_body()`                 | `interpreter.c` |                                                      |
| `jl_interpret_toplevel_thunk` | `interpreter.c` |                                                      |
| `jl_toplevel_eval_flex`       | `toplevel.c`    |                                                      |
| `jl_toplevel_eval_in`         | `toplevel.c`    |                                                      |
| `Core.eval`                   | `boot.jl`       |                                                      |


## [`Core.eval`](#Core.eval)
Since our example has just one function call, which has done its job of printing "Hello World!", the stack now rapidly unwinds back to `main()`.


## [`jl_atexit_hook()`](#jl_atexit_hook())
`main()` calls [`jl_atexit_hook()`](https://github.com/JuliaLang/julia/blob/master/src/init.c). This calls `Base._atexit`, then calls [`jl_gc_run_all_finalizers()`](https://github.com/JuliaLang/julia/blob/master/src/gc.c) and cleans up libuv handles.


## [`julia_save()`](#julia_save())
Finally, `main()` calls [`julia_save()`](https://github.com/JuliaLang/julia/blob/master/src/init.c), which if requested on the command line, saves the runtime state to a new system image. See [`jl_compile_all()`](https://github.com/JuliaLang/julia/blob/master/src/gf.c) and [`jl_save_system_image()`](https://github.com/JuliaLang/julia/blob/master/src/staticdata.c).
------------------------------------------------------------------------


# Julia ASTs · The Julia Language
Source: https://docs.julialang.org/en/v1/devdocs/ast/


# [Julia ASTs](#Julia-ASTs)
Julia has two representations of code. First there is a surface syntax AST returned by the parser (e.g. the [`Meta.parse`](../../base/base/#Base.Meta.parse-Tuple%7BAbstractString,%20Int64%7D) function), and manipulated by macros. It is a structured representation of code as it is written, constructed by `julia-parser.scm` from a character stream. Next there is a lowered form, or IR (intermediate representation), which is used by type inference and code generation. In the lowered form there are fewer types of nodes, all macros are expanded, and all control flow is converted to explicit branches and sequences of statements. The lowered form is constructed by `julia-syntax.scm`.
First we will focus on the AST, since it is needed to write macros.


## [Surface syntax AST](#Surface-syntax-AST)
Front end ASTs consist almost entirely of [`Expr`](../../base/base/#Core.Expr)s and atoms (e.g. symbols, numbers). There is generally a different expression head for each visually distinct syntactic form. Examples will be given in s-expression syntax. Each parenthesized list corresponds to an Expr, where the first element is the head. For example `(call f x)` corresponds to `Expr(:call, :f, :x)` in Julia.


### [Calls](#Calls)
| Input            | AST                                |
|:-----------------|:-----------------------------------|
| `f(x)`           | `(call f x)`                       |
| `f(x, y=1, z=2)` | `(call f x (kw y 1) (kw z 2))`     |
| `f(x; y=1)`      | `(call f (parameters (kw y 1)) x)` |
| `f(x...)`        | `(call f (... x))`                 |
`do` syntax:
```julia
f(x) do a,b
    body
end
```
parses as `(do (call f x) (-> (tuple a b) (block body)))`.


### [Operators](#Operators)
Most uses of operators are just function calls, so they are parsed with the head `call`. However some operators are special forms (not necessarily function calls), and in those cases the operator itself is the expression head. In julia-parser.scm these are referred to as "syntactic operators". Some operators (`+` and `*`) use N-ary parsing; chained calls are parsed as a single N-argument call. Finally, chains of comparisons have their own special expression structure.
| Input       | AST                       |
|:------------|:--------------------------|
| `x+y`       | `(call + x y)`            |
| `a+b+c+d`   | `(call + a b c d)`        |
| `2x`        | `(call * 2 x)`            |
| `a&&b`      | `(&& a b)`                |
| `x += 1`    | `(+= x 1)`                |
| `a ? 1 : 2` | `(if a 1 2)`              |
| `a,b`       | `(tuple a b)`             |
| `a==b`      | `(call == a b)`           |
| `1<i<=n`    | `(comparison 1 < i <= n)` |
| `a.b`       | `(. a (quote b))`         |
| `a.(b)`     | `(. a (tuple b))`         |


### [Bracketed forms](#Bracketed-forms)
| Input                    | AST                                             |
|:-------------------------|:------------------------------------------------|
| `a[i]`                   | `(ref a i)`                                     |
| `t[i;j]`                 | `(typed_vcat t i j)`                            |
| `t[i j]`                 | `(typed_hcat t i j)`                            |
| `t[a b; c d]`            | `(typed_vcat t (row a b) (row c d))`            |
| `t[a b;;; c d]`          | `(typed_ncat t 3 (row a b) (row c d))`          |
| `a{b}`                   | `(curly a b)`                                   |
| `a{b;c}`                 | `(curly a (parameters c) b)`                    |
| `[x]`                    | `(vect x)`                                      |
| `[x,y]`                  | `(vect x y)`                                    |
| `[x;y]`                  | `(vcat x y)`                                    |
| `[x y]`                  | `(hcat x y)`                                    |
| `[x y; z t]`             | `(vcat (row x y) (row z t))`                    |
| `[x;y;; z;t;;;]`         | `(ncat 3 (nrow 2 (nrow 1 x y) (nrow 1 z t)))`   |
| `[x for y in z, a in b]` | `(comprehension (generator x (= y z) (= a b)))` |
| `T[x for y in z]`        | `(typed_comprehension T (generator x (= y z)))` |
| `(a, b, c)`              | `(tuple a b c)`                                 |
| `(a; b; c)`              | `(block a b c)`                                 |


### [Macros](#Macros)
| Input         | AST                                          |
|:--------------|:---------------------------------------------|
| `@m x y`      | `(macrocall @m (line) x y)`                  |
| `Base.@m x y` | `(macrocall (. Base (quote @m)) (line) x y)` |
| `@Base.m x y` | `(macrocall (. Base (quote @m)) (line) x y)` |


### [Strings](#Strings)
| Input         | AST                                 |
|:--------------|:------------------------------------|
| `"a"`         | `"a"`                               |
| `x"y"`        | `(macrocall @x_str (line) "y")`     |
| `x"y"z`       | `(macrocall @x_str (line) "y" "z")` |
| `"x = $x"`    | `(string "x = " x)`                 |
| `` `a b c` `` | `(macrocall @cmd (line) "a b c")`   |
Doc string syntax:
```julia
"some docs"
f(x) = x
```
parses as `(macrocall (|.| Core '@doc) (line) "some docs" (= (call f x) (block x)))`.


### [Imports and such](#Imports-and-such)
| Input               | AST                                 |
|:--------------------|:------------------------------------|
| `import a`          | `(import (. a))`                    |
| `import a.b.c`      | `(import (. a b c))`                |
| `import ...a`       | `(import (. . . . a))`              |
| `import a.b, c.d`   | `(import (. a b) (. c d))`          |
| `import Base: x`    | `(import (: (. Base) (. x)))`       |
| `import Base: x, y` | `(import (: (. Base) (. x) (. y)))` |
| `export a, b`       | `(export a b)`                      |
`using` has the same representation as `import`, but with expression head `:using` instead of `:import`.


### [Numbers](#Numbers)
Julia supports more number types than many scheme implementations, so not all numbers are represented directly as scheme numbers in the AST.
| Input                   | AST                                                      |
|:------------------------|:---------------------------------------------------------|
| `11111111111111111111`  | `(macrocall @int128_str nothing "11111111111111111111")` |
| `0xfffffffffffffffff`   | `(macrocall @uint128_str nothing "0xfffffffffffffffff")` |
| `1111...many digits...` | `(macrocall @big_str nothing "1111....")`                |


### [Block forms](#Block-forms)
A block of statements is parsed as `(block stmt1 stmt2 ...)`.
If statement:
```julia
if a
    b
elseif c
    d
else
    e
end
```
parses as:
```julia
(if a (block (line 2) b)
    (elseif (block (line 3) c) (block (line 4) d)
            (block (line 6 e))))
```
A `while` loop parses as `(while condition body)`.
A `for` loop parses as `(for (= var iter) body)`. If there is more than one iteration specification, they are parsed as a block: `(for (block (= v1 iter1) (= v2 iter2)) body)`.
`break` and `continue` are parsed as 0-argument expressions `(break)` and `(continue)`.
`let` is parsed as `(let (= var val) body)` or `(let (block (= var1 val1) (= var2 val2) ...) body)`, like `for` loops.
A basic function definition is parsed as `(function (call f x) body)`. A more complex example:
```julia
function f(x::T; k = 1) where T
    return x+1
end
```
parses as:
```julia
(function (where (call f (parameters (kw k 1))
                       (:: x T))
                 T)
          (block (line 2) (return (call + x 1))))
```
Type definition:
```julia
mutable struct Foo{T<:S}
    x::T
end
```
parses as:
```julia
(struct true (curly Foo (<: T S))
        (block (line 2) (:: x T)))
```
The first argument is a boolean telling whether the type is mutable.
`try` blocks parse as `(try try_block var catch_block finally_block)`. If no variable is present after `catch`, `var` is `#f`. If there is no `finally` clause, then the last argument is not present.


### [Quote expressions](#Quote-expressions)
Julia source syntax forms for code quoting (`quote` and `:( )`) support interpolation with `$`. In Lisp terminology, this means they are actually "backquote" or "quasiquote" forms. Internally, there is also a need for code quoting without interpolation. In Julia's scheme code, non-interpolating quote is represented with the expression head `inert`.
`inert` expressions are converted to Julia `QuoteNode` objects. These objects wrap a single value of any type, and when evaluated simply return that value.
A `quote` expression whose argument is an atom also gets converted to a `QuoteNode`.


### [Line numbers](#Line-numbers)
Source location information is represented as `(line line_num file_name)` where the third component is optional (and omitted when the current line number, but not file name, changes).
These expressions are represented as `LineNumberNode`s in Julia.


### [Macros](#Macros-2)
Macro hygiene is represented through the expression head pair `escape` and `hygienic-scope`. The result of a macro expansion is automatically wrapped in `(hygienic-scope block module)`, to represent the result of the new scope. The user can insert `(escape block)` inside to interpolate code from the caller.


## [Lowered form](#Lowered-form)
Lowered form (IR) is more important to the compiler, since it is used for type inference, optimizations like inlining, and code generation. It is also less obvious to the human, since it results from a significant rearrangement of the input syntax.
In addition to `Symbol`s and some number types, the following data types exist in lowered form:
-   `Expr`
    Has a node type indicated by the `head` field, and an `args` field which is a `Vector{Any}` of subexpressions. While almost every part of a surface AST is represented by an `Expr`, the IR uses only a limited number of `Expr`s, mostly for calls and some top-level-only forms.
-   `SlotNumber`
    Identifies arguments and local variables by consecutive numbering. It has an integer-valued `id` field giving the slot index. The types of these slots can be found in the `slottypes` field of their `CodeInfo` object.
-   `Argument`
    The same as `SlotNumber`, but appears only post-optimization. Indicates that the referenced slot is an argument of the enclosing function.
-   `CodeInfo`
    Wraps the IR of a group of statements. Its `code` field is an array of expressions to execute.
-   `GotoNode`
    Unconditional branch. The argument is the branch target, represented as an index in the code array to jump to.
-   `GotoIfNot`
    Conditional branch. If the `cond` field evaluates to false, goes to the index identified by the `dest` field.
-   `ReturnNode`


## [Lowered form](#Lowered-form)
    Returns its argument (the `val` field) as the value of the enclosing function. If the `val` field is undefined, then this represents an unreachable statement.
-   `QuoteNode`
    Wraps an arbitrary value to reference as data. For example, the function `f() = :a` contains a `QuoteNode` whose `value` field is the symbol `a`, in order to return the symbol itself instead of evaluating it.
-   `GlobalRef`
    Refers to global variable `name` in module `mod`.
-   `SSAValue`
    Refers to a consecutively-numbered (starting at 1) static single assignment (SSA) variable inserted by the compiler. The number (`id`) of an `SSAValue` is the code array index of the expression whose value it represents.
-   `NewvarNode`
    Marks a point where a variable (slot) is created. This has the effect of resetting a variable to undefined.


### [Expr types](#Expr-types)
These symbols appear in the `head` field of [`Expr`](../../base/base/#Core.Expr)s in lowered form.
-   `call`
    Function call (dynamic dispatch). `args[1]` is the function to call, `args[2:end]` are the arguments.
-   `invoke`
    Function call (static dispatch). `args[1]` is the MethodInstance to call, `args[2:end]` are the arguments (including the function that is being called, at `args[2]`).
-   `static_parameter`
    Reference a static parameter by index.
-   `=`
    Assignment. In the IR, the first argument is always a `SlotNumber` or a `GlobalRef`.
-   `method`
    Adds a method to a generic function and assigns the result if necessary.
    Has a 1-argument form and a 3-argument form. The 1-argument form arises from the syntax `function foo end`. In the 1-argument form, the argument is a symbol. If this symbol already names a function in the current scope, nothing happens. If the symbol is undefined, a new function is created and assigned to the identifier specified by the symbol. If the symbol is defined but names a non-function, an error is raised. The definition of "names a function" is that the binding is constant, and refers to an object of singleton type. The rationale for this is that an instance of a singleton type uniquely identifies the type to add the method to. When the type has fields, it wouldn't be clear whether the method was being added to the instance or its type.
    The 3-argument form has the following arguments:
    -   `args[1]`


### [Expr types](#Expr-types)
        A function name, or `nothing` if unknown or unneeded. If a symbol, then the expression first behaves like the 1-argument form above. This argument is ignored from then on. It can be `nothing` when methods are added strictly by type, `(::T)(x) = x`, or when a method is being added to an existing function, `MyModule.f(x) = x`.
    -   `args[2]`
        A `SimpleVector` of argument type data. `args[2][1]` is a `SimpleVector` of the argument types, and `args[2][2]` is a `SimpleVector` of type variables corresponding to the method's static parameters.
    -   `args[3]`
        A `CodeInfo` of the method itself. For "out of scope" method definitions (adding a method to a function that also has methods defined in different scopes) this is an expression that evaluates to a `:lambda` expression.
-   `struct_type`
    A 7-argument expression that defines a new `struct`:
    -   `args[1]`
        The name of the `struct`
    -   `args[2]`
        A `call` expression that creates a `SimpleVector` specifying its parameters
    -   `args[3]`
        A `call` expression that creates a `SimpleVector` specifying its fieldnames
    -   `args[4]`
        A `Symbol`, `GlobalRef`, or `Expr` specifying the supertype (e.g., `:Integer`, `GlobalRef(Core, :Any)`, or `:(Core.apply_type(AbstractArray, T, N))`)
    -   `args[5]`
        A `call` expression that creates a `SimpleVector` specifying its fieldtypes
    -   `args[6]`
        A Bool, true if `mutable`
    -   `args[7]`


### [Expr types](#Expr-types)
        The number of arguments to initialize. This will be the number of fields, or the minimum number of fields called by an inner constructor's `new` statement.
-   `abstract_type`
    A 3-argument expression that defines a new abstract type. The arguments are the same as arguments 1, 2, and 4 of `struct_type` expressions.
-   `primitive_type`
    A 4-argument expression that defines a new primitive type. Arguments 1, 2, and 4 are the same as `struct_type`. Argument 3 is the number of bits.
    `struct_type`, `abstract_type`, and `primitive_type` were removed in Julia 1.5 and replaced by calls to new builtins.
-   `global`
    Declares a global binding.
-   `const`
    Declares a (global) variable as constant.
-   `new`
    Allocates a new struct-like object. First argument is the type. The [`new`](../../base/base/#new) pseudo-function is lowered to this, and the type is always inserted by the compiler. This is very much an internal-only feature, and does no checking. Evaluating arbitrary `new` expressions can easily segfault.
-   `splatnew`
    Similar to `new`, except field values are passed as a single tuple. Works similarly to `splat(new)` if `new` were a first-class function, hence the name.
-   `isdefined`
    `Expr(:isdefined, :x)` returns a Bool indicating whether `x` has already been defined in the current scope.
-   `the_exception`
    Yields the caught exception inside a `catch` block, as returned by `jl_current_exception(ct)`.
-   `enter`


### [Expr types](#Expr-types)
    Enters an exception handler (`setjmp`). `args[1]` is the label of the catch block to jump to on error. Yields a token which is consumed by `pop_exception`.
-   `leave`
    Pop exception handlers. `args[1]` is the number of handlers to pop.
-   `pop_exception`
    Pop the stack of current exceptions back to the state at the associated `enter` when leaving a catch block. `args[1]` contains the token from the associated `enter`.
    `pop_exception` is new in Julia 1.1.
-   `inbounds`
    Controls turning bounds checks on or off. A stack is maintained; if the first argument of this expression is true or false (`true` means bounds checks are disabled), it is pushed onto the stack. If the first argument is `:pop`, the stack is popped.
-   `boundscheck`
    Has the value `false` if inlined into a section of code marked with `@inbounds`, otherwise has the value `true`.
-   `loopinfo`
    Marks the end of the a loop. Contains metadata that is passed to `LowerSimdLoop` to either mark the inner loop of `@simd` expression, or to propagate information to LLVM loop passes.
-   `copyast`
    Part of the implementation of quasi-quote. The argument is a surface syntax AST that is simply copied recursively and returned at run time.
-   `meta`
    Metadata. `args[1]` is typically a symbol specifying the kind of metadata, and the rest of the arguments are free-form. The following kinds of metadata are commonly used:
    -   `:inline` and `:noinline`: Inlining hints.
-   `foreigncall`
    Statically-computed container for `ccall` information. The fields are:


### [Expr types](#Expr-types)
    -   `args[1]` : name
        The expression that'll be parsed for the foreign function.
    -   `args[2]::Type` : RT
        The (literal) return type, computed statically when the containing method was defined.
    -   `args[3]::SimpleVector` (of Types) : AT
        The (literal) vector of argument types, computed statically when the containing method was defined.
    -   `args[4]::Int` : nreq
        The number of required arguments for a varargs function definition.
    -   `args[5]::QuoteNode{Symbol}` : calling convention
        The calling convention for the call.
    -   `args[6:5+length(args[3])]` : arguments
        The values for all the arguments (with types of each given in args\[3\]).
    -   `args[6+length(args[3])+1:end]` : gc-roots
        The additional objects that may need to be gc-rooted for the duration of the call. See [Working with LLVM](../llvm/#Working-with-LLVM) for where these are derived from and how they get handled.
-   `new_opaque_closure`
    Constructs a new opaque closure. The fields are:
    -   `args[1]` : signature
        The function signature of the opaque closure. Opaque closures don't participate in dispatch, but the input types can be restricted.
    -   `args[2]` : isva
        Indicates whether the closure accepts varargs.
    -   `args[3]` : lb
        Lower bound on the output type. (Defaults to `Union{}`)
    -   `args[4]` : ub
        Upper bound on the output type. (Defaults to `Any`)
    -   `args[5]` : method
        The actual method as an `opaque_closure_method` expression.


### [Expr types](#Expr-types)
    -   `args[6:end]` : captures
        The values captured by the opaque closure.
    Opaque closures were added in Julia 1.7


### [Method](#ast-lowered-method)
A unique'd container describing the shared metadata for a single method.
-   `name`, `module`, `file`, `line`, `sig`
    Metadata to uniquely identify the method for the computer and the human.
-   `ambig`
    Cache of other methods that may be ambiguous with this one.
-   `specializations`
    Cache of all MethodInstance ever created for this Method, used to ensure uniqueness. Uniqueness is required for efficiency, especially for incremental precompile and tracking of method invalidation.
-   `source`
    The original source code (if available, usually compressed).
-   `generator`
    A callable object which can be executed to get specialized source for a specific method signature.
-   `roots`
    Pointers to non-AST things that have been interpolated into the AST, required by compression of the AST, type-inference, or the generation of native code.
-   `nargs`, `isva`, `called`, `is_for_opaque_closure`,
    Descriptive bit-fields for the source code of this Method.
-   `primary_world`
    The world age that "owns" this Method.


### [MethodInstance](#MethodInstance)
A unique'd container describing a single callable signature for a Method. See especially [Proper maintenance and care of multi-threading locks](../locks/#Proper-maintenance-and-care-of-multi-threading-locks) for important details on how to modify these fields safely.
-   `specTypes`
    The primary key for this MethodInstance. Uniqueness is guaranteed through a `def.specializations` lookup.
-   `def`
    The `Method` that this function describes a specialization of. Or a `Module`, if this is a top-level Lambda expanded in Module, and which is not part of a Method.
-   `sparam_vals`
    The values of the static parameters in `specTypes`. For the `MethodInstance` at `Method.unspecialized`, this is the empty `SimpleVector`. But for a runtime `MethodInstance` from the `MethodTable` cache, this will always be defined and indexable.
-   `uninferred`
    The uncompressed source code for a toplevel thunk. Additionally, for a generated function, this is one of many places that the source code might be found.
-   `backedges`


### [MethodInstance](#MethodInstance)
    We store the reverse-list of cache dependencies for efficient tracking of incremental reanalysis/recompilation work that may be needed after a new method definitions. This works by keeping a list of the other `MethodInstance` that have been inferred or optimized to contain a possible call to this `MethodInstance`. Those optimization results might be stored somewhere in the `cache`, or it might have been the result of something we didn't want to cache, such as constant propagation. Thus we merge all of those backedges to various cache entries here (there's almost always only the one applicable cache entry with a sentinel value for max_world anyways).
-   `cache`
    Cache of `CodeInstance` objects that share this template instantiation.


### [CodeInstance](#CodeInstance)
-   `def`
    The `MethodInstance` that this cache entry is derived from.
-   `owner`
    A token that represents the owner of this `CodeInstance`. Will use `jl_egal` to match.
<!-- -->
-   `rettype`/`rettype_const`
    The inferred return type for the `specFunctionObject` field, which (in most cases) is also the computed return type for the function in general.
-   `inferred`
    May contain a cache of the inferred source for this function, or it could be set to `nothing` to just indicate `rettype` is inferred.
-   `ftpr`
    The generic jlcall entry point.
-   `jlcall_api`
    The ABI to use when calling `fptr`. Some significant ones include:
    -   0 - Not compiled yet
    -   1 - `JL_CALLABLE` `jl_value_t *(*)(jl_function_t *f, jl_value_t *args[nargs], uint32_t nargs)`
    -   2 - Constant (value stored in `rettype_const`)
    -   3 - With Static-parameters forwarded `jl_value_t *(*)(jl_svec_t *sparams, jl_function_t *f, jl_value_t *args[nargs], uint32_t nargs)`
    -   4 - Run in interpreter `jl_value_t *(*)(jl_method_instance_t *meth, jl_function_t *f, jl_value_t *args[nargs], uint32_t nargs)`
-   `min_world` / `max_world`
    The range of world ages for which this method instance is valid to be called. If max_world is the special token value `-1`, the value is not yet known. It may continue to be used until we encounter a backedge that requires us to reconsider.


### [CodeInfo](#CodeInfo)
A (usually temporary) container for holding lowered source code.
-   `code`
    An `Any` array of statements
-   `slotnames`
    An array of symbols giving names for each slot (argument or local variable).
-   `slotflags`
    A `UInt8` array of slot properties, represented as bit flags:
    -   0x02 - assigned (only false if there are *no* assignment statements with this var on the left)
    -   0x08 - used (if there is any read or write of the slot)
    -   0x10 - statically assigned once
    -   0x20 - might be used before assigned. This flag is only valid after type inference.
-   `ssavaluetypes`
    Either an array or an `Int`.
    If an `Int`, it gives the number of compiler-inserted temporary locations in the function (the length of `code` array). If an array, specifies a type for each location.
-   `ssaflags`
    Statement-level 32 bits flags for each expression in the function. See the definition of `jl_code_info_t` in julia.h for more details.
-   `linetable`
    An array of source location objects
-   `codelocs`
    An array of integer indices into the `linetable`, giving the location associated with each statement.
Optional Fields:
-   `slottypes`
    An array of types for the slots.
-   `rettype`
    The inferred return type of the lowered form (IR). Default value is `Any`.
-   `method_for_inference_limit_heuristics`
    The `method_for_inference_heuristics` will expand the given method's generator if necessary during inference.
-   `parent`
    The `MethodInstance` that "owns" this object (if applicable).
-   `edges`


### [CodeInfo](#CodeInfo)
    Forward edges to method instances that must be invalidated.
-   `min_world`/`max_world`
    The range of world ages for which this code was valid at the time when it had been inferred.
Boolean properties:
-   `inferred`
    Whether this has been produced by type inference.
-   `inlineable`
    Whether this should be eligible for inlining.
-   `propagate_inbounds`
    Whether this should propagate `@inbounds` when inlined for the purpose of eliding `@boundscheck` blocks.
`UInt8` settings:
-   `constprop`
    -   0 = use heuristic
    -   1 = aggressive
    -   2 = none
-   `purity` Constructed from 5 bit flags:
    -   0x01 \<\< 0 = this method is guaranteed to return or terminate consistently (`:consistent`)
    -   0x01 \<\< 1 = this method is free from externally semantically visible side effects (`:effect_free`)
    -   0x01 \<\< 2 = this method is guaranteed to not throw an exception (`:nothrow`)
    -   0x01 \<\< 3 = this method is guaranteed to terminate (`:terminates_globally`)
    -   0x01 \<\< 4 = the syntactic control flow within this method is guaranteed to terminate (`:terminates_locally`)
    See the documentation of `Base.@assume_effects` for more details.
------------------------------------------------------------------------


# More about types · The Julia Language
Source: https://docs.julialang.org/en/v1/devdocs/types/


# [More about types](#More-about-types)
If you've used Julia for a while, you understand the fundamental role that types play. Here we try to get under the hood, focusing particularly on [Parametric Types](../../manual/types/#Parametric-Types).


## [Types and sets (and Any and Union{}/Bottom)](#Types-and-sets-(and-Any-and-Union%7B%7D/Bottom))
It's perhaps easiest to conceive of Julia's type system in terms of sets. While programs manipulate individual values, a type refers to a set of values. This is not the same thing as a collection; for example a [`Set`](../../base/collections/#Base.Set) of values is itself a single `Set` value. Rather, a type describes a set of *possible* values, expressing uncertainty about which value we have.
A *concrete* type `T` describes the set of values whose direct tag, as returned by the [`typeof`](../../base/base/#Core.typeof) function, is `T`. An *abstract* type describes some possibly-larger set of values.
[`Any`](../../base/base/#Core.Any) describes the entire universe of possible values. [`Integer`](../../base/numbers/#Core.Integer) is a subset of `Any` that includes `Int`, [`Int8`](../../base/numbers/#Core.Int8), and other concrete types. Internally, Julia also makes heavy use of another type known as `Bottom`, which can also be written as `Union{}`. This corresponds to the empty set.
Julia's types support the standard operations of set theory: you can ask whether `T1` is a "subset" (subtype) of `T2` with `T1 <: T2`. Likewise, you intersect two types using [`typeintersect`](../../base/base/#Base.typeintersect), take their union with [`Union`](../../base/base/#Core.Union), and compute a type that contains their union with [`typejoin`](../../base/base/#Base.typejoin):


## [Types and sets (and Any and Union{}/Bottom)](#Types-and-sets-(and-Any-and-Union%7B%7D/Bottom))
```julia-repl
julia> typeintersect(Int, Float64)
Union{}

julia> Union{Int, Float64}
Union{Float64, Int64}

julia> typejoin(Int, Float64)
Real

julia> typeintersect(Signed, Union{UInt8, Int8})
Int8

julia> Union{Signed, Union{UInt8, Int8}}
Union{UInt8, Signed}

julia> typejoin(Signed, Union{UInt8, Int8})
Integer

julia> typeintersect(Tuple{Integer, Float64}, Tuple{Int, Real})
Tuple{Int64, Float64}

julia> Union{Tuple{Integer, Float64}, Tuple{Int, Real}}
Union{Tuple{Int64, Real}, Tuple{Integer, Float64}}

julia> typejoin(Tuple{Integer, Float64}, Tuple{Int, Real})
Tuple{Integer, Real}
```
While these operations may seem abstract, they lie at the heart of Julia. For example, method dispatch is implemented by stepping through the items in a method list until reaching one for which the type of the argument tuple is a subtype of the method signature. For this algorithm to work, it's important that methods be sorted by their specificity, and that the search begins with the most specific methods. Consequently, Julia also implements a partial order on types; this is achieved by functionality that is similar to `<:`, but with differences that will be discussed below.


## [UnionAll types](#UnionAll-types)
Julia's type system can also express an *iterated union* of types: a union of types over all values of some variable. This is needed to describe parametric types where the values of some parameters are not known.
For example, [`Array`](../../base/arrays/#Core.Array) has two parameters as in `Array{Int,2}`. If we did not know the element type, we could write `Array{T,2} where T`, which is the union of `Array{T,2}` for all values of `T`: `Union{Array{Int8,2}, Array{Int16,2}, ...}`.
Such a type is represented by a `UnionAll` object, which contains a variable (`T` in this example, of type `TypeVar`), and a wrapped type (`Array{T,2}` in this example).
Consider the following methods:
```julia
f1(A::Array) = 1
f2(A::Array{Int}) = 2
f3(A::Array{T}) where {T<:Any} = 3
f4(A::Array{Any}) = 4
```
The signature - as described in [Function calls](../functions/#Function-calls) - of `f3` is a `UnionAll` type wrapping a tuple type: `Tuple{typeof(f3), Array{T}} where T`. All but `f4` can be called with `a = [1,2]`; all but `f2` can be called with `b = Any[1,2]`.
Let's look at these types a little more closely:
```julia-repl
julia> dump(Array)
UnionAll
  var: TypeVar
    name: Symbol T
    lb: Union{}
    ub: Any
  body: UnionAll
    var: TypeVar
      name: Symbol N
      lb: Union{}
      ub: Any
    body: Array{T, N} <: DenseArray{T, N}
      ref::MemoryRef{T}
      size::NTuple{N, Int64}
```


## [UnionAll types](#UnionAll-types)
This indicates that `Array` actually names a `UnionAll` type. There is one `UnionAll` type for each parameter, nested. The syntax `Array{Int,2}` is equivalent to `Array{Int}{2}`; internally each `UnionAll` is instantiated with a particular variable value, one at a time, outermost-first. This gives a natural meaning to the omission of trailing type parameters; `Array{Int}` gives a type equivalent to `Array{Int,N} where N`.
A `TypeVar` is not itself a type, but rather should be considered part of the structure of a `UnionAll` type. Type variables have lower and upper bounds on their values (in the fields `lb` and `ub`). The symbol `name` is purely cosmetic. Internally, `TypeVar`s are compared by address, so they are defined as mutable types to ensure that "different" type variables can be distinguished. However, by convention they should not be mutated.
One can construct `TypeVar`s manually:
```julia-repl
julia> TypeVar(:V, Signed, Real)
Signed<:V<:Real
```
There are convenience versions that allow you to omit any of these arguments except the `name` symbol.
The syntax `Array{T} where T<:Integer` is lowered to
```julia
let T = TypeVar(:T,Integer)
    UnionAll(T, Array{T})
end
```
so it is seldom necessary to construct a `TypeVar` manually (indeed, this is to be avoided).


## [Free variables](#Free-variables)
The concept of a *free* type variable is extremely important in the type system. We say that a variable `V` is free in type `T` if `T` does not contain the `UnionAll` that introduces variable `V`. For example, the type `Array{Array{V} where V<:Integer}` has no free variables, but the `Array{V}` part inside of it does have a free variable, `V`.
A type with free variables is, in some sense, not really a type at all. Consider the type `Array{Array{T}} where T`, which refers to all homogeneous arrays of arrays. The inner type `Array{T}`, seen by itself, might seem to refer to any kind of array. However, every element of the outer array must have the *same* array type, so `Array{T}` cannot refer to just any old array. One could say that `Array{T}` effectively "occurs" multiple times, and `T` must have the same value each "time".
For this reason, the function `jl_has_free_typevars` in the C API is very important. Types for which it returns true will not give meaningful answers in subtyping and other type functions.


## [TypeNames](#TypeNames)
The following two [`Array`](../../base/arrays/#Core.Array) types are functionally equivalent, yet print differently:
```julia-repl
julia> TV, NV = TypeVar(:T), TypeVar(:N)
(T, N)

julia> Array
Array

julia> Array{TV, NV}
Array{T, N}
```
These can be distinguished by examining the `name` field of the type, which is an object of type `TypeName`:
```julia-repl
julia> dump(Array{Int,1}.name)
TypeName
  name: Symbol Array
  module: Module Core
  names: empty SimpleVector
  wrapper: UnionAll
    var: TypeVar
      name: Symbol T
      lb: Union{}
      ub: Any
    body: UnionAll
      var: TypeVar
        name: Symbol N
        lb: Union{}
        ub: Any
      body: Array{T, N} <: DenseArray{T, N}
  cache: SimpleVector
    ...

  linearcache: SimpleVector
    ...

  hash: Int64 -7900426068641098781
  mt: MethodTable
    name: Symbol Array
    defs: Nothing nothing
    cache: Nothing nothing
    max_args: Int64 0
    module: Module Core
    : Int64 0
    : Int64 0
```
In this case, the relevant field is `wrapper`, which holds a reference to the top-level type used to make new `Array` types.
```julia-repl
julia> pointer_from_objref(Array)
Ptr{Cvoid} @0x00007fcc7de64850

julia> pointer_from_objref(Array.body.body.name.wrapper)
Ptr{Cvoid} @0x00007fcc7de64850

julia> pointer_from_objref(Array{TV,NV})
Ptr{Cvoid} @0x00007fcc80c4d930

julia> pointer_from_objref(Array{TV,NV}.name.wrapper)
Ptr{Cvoid} @0x00007fcc7de64850
```


## [TypeNames](#TypeNames)
The `wrapper` field of [`Array`](../../base/arrays/#Core.Array) points to itself, but for `Array{TV,NV}` it points back to the original definition of the type.
What about the other fields? `hash` assigns an integer to each type. To examine the `cache` field, it's helpful to pick a type that is less heavily used than Array. Let's first create our own type:
```julia-repl
julia> struct MyType{T,N} end

julia> MyType{Int,2}
MyType{Int64, 2}

julia> MyType{Float32, 5}
MyType{Float32, 5}
```
When you instantiate a parametric type, each concrete type gets saved in a type cache (`MyType.body.body.name.cache`). However, instances containing free type variables are not cached.


## [Tuple types](#Tuple-types)
Tuple types constitute an interesting special case. For dispatch to work on declarations like `x::Tuple`, the type has to be able to accommodate any tuple. Let's check the parameters:
```julia-repl
julia> Tuple
Tuple

julia> Tuple.parameters
svec(Vararg{Any})
```
Unlike other types, tuple types are covariant in their parameters, so this definition permits `Tuple` to match any type of tuple:
```julia-repl
julia> typeintersect(Tuple, Tuple{Int,Float64})
Tuple{Int64, Float64}

julia> typeintersect(Tuple{Vararg{Any}}, Tuple{Int,Float64})
Tuple{Int64, Float64}
```
However, if a variadic (`Vararg`) tuple type has free variables it can describe different kinds of tuples:
```julia-repl
julia> typeintersect(Tuple{Vararg{T} where T}, Tuple{Int,Float64})
Tuple{Int64, Float64}

julia> typeintersect(Tuple{Vararg{T}} where T, Tuple{Int,Float64})
Union{}
```
Notice that when `T` is free with respect to the `Tuple` type (i.e. its binding `UnionAll` type is outside the `Tuple` type), only one `T` value must work over the whole type. Therefore a heterogeneous tuple does not match.
Finally, it's worth noting that `Tuple{}` is distinct:
```julia-repl
julia> Tuple{}
Tuple{}

julia> Tuple{}.parameters
svec()

julia> typeintersect(Tuple{}, Tuple{Int})
Union{}
```
What is the "primary" tuple-type?


## [Tuple types](#Tuple-types)
```julia-repl
julia> pointer_from_objref(Tuple)
Ptr{Cvoid} @0x00007f5998a04370

julia> pointer_from_objref(Tuple{})
Ptr{Cvoid} @0x00007f5998a570d0

julia> pointer_from_objref(Tuple.name.wrapper)
Ptr{Cvoid} @0x00007f5998a04370

julia> pointer_from_objref(Tuple{}.name.wrapper)
Ptr{Cvoid} @0x00007f5998a04370
```
so `Tuple == Tuple{Vararg{Any}}` is indeed the primary type.


## [Diagonal types](#Diagonal-types)
Consider the type `Tuple{T,T} where T`. A method with this signature would look like:
```julia
f(x::T, y::T) where {T} = ...
```
According to the usual interpretation of a `UnionAll` type, this `T` ranges over all types, including `Any`, so this type should be equivalent to `Tuple{Any,Any}`. However, this interpretation causes some practical problems.
First, a value of `T` needs to be available inside the method definition. For a call like `f(1, 1.0)`, it's not clear what `T` should be. It could be `Union{Int,Float64}`, or perhaps [`Real`](../../base/numbers/#Core.Real). Intuitively, we expect the declaration `x::T` to mean `T === typeof(x)`. To make sure that invariant holds, we need `typeof(x) === typeof(y) === T` in this method. That implies the method should only be called for arguments of the exact same type.
It turns out that being able to dispatch on whether two values have the same type is very useful (this is used by the promotion system for example), so we have multiple reasons to want a different interpretation of `Tuple{T,T} where T`. To make this work we add the following rule to subtyping: if a variable occurs more than once in covariant position, it is restricted to ranging over only concrete types. ("Covariant position" means that only `Tuple` and `Union` types occur between an occurrence of a variable and the `UnionAll` type that introduces it.) Such variables are called "diagonal variables" or "concrete variables".


## [Diagonal types](#Diagonal-types)
So for example, `Tuple{T,T} where T` can be seen as `Union{Tuple{Int8,Int8}, Tuple{Int16,Int16}, ...}`, where `T` ranges over all concrete types. This gives rise to some interesting subtyping results. For example `Tuple{Real,Real}` is not a subtype of `Tuple{T,T} where T`, because it includes some types like `Tuple{Int8,Int16}` where the two elements have different types. `Tuple{Real,Real}` and `Tuple{T,T} where T` have the non-trivial intersection `Tuple{T,T} where T<:Real`. However, `Tuple{Real}` *is* a subtype of `Tuple{T} where T`, because in that case `T` occurs only once and so is not diagonal.
Next consider a signature like the following:
```julia
f(a::Array{T}, x::T, y::T) where {T} = ...
```
In this case, `T` occurs in invariant position inside `Array{T}`. That means whatever type of array is passed unambiguously determines the value of `T` – we say `T` has an *equality constraint* on it. Therefore in this case the diagonal rule is not really necessary, since the array determines `T` and we can then allow `x` and `y` to be of any subtypes of `T`. So variables that occur in invariant position are never considered diagonal. This choice of behavior is slightly controversial – some feel this definition should be written as
```julia
f(a::Array{T}, x::S, y::S) where {T, S<:T} = ...
```
to clarify whether `x` and `y` need to have the same type. In this version of the signature they would, or we could introduce a third variable for the type of `y` if `x` and `y` can have different types.


## [Diagonal types](#Diagonal-types)
The next complication is the interaction of unions and diagonal variables, e.g.
```julia
f(x::Union{Nothing,T}, y::T) where {T} = ...
```
Consider what this declaration means. `y` has type `T`. `x` then can have either the same type `T`, or else be of type [`Nothing`](../../base/base/#Core.Nothing). So all of the following calls should match:
```julia
f(1, 1)
f("", "")
f(2.0, 2.0)
f(nothing, 1)
f(nothing, "")
f(nothing, 2.0)
```
These examples are telling us something: when `x` is `nothing::Nothing`, there are no extra constraints on `y`. It is as if the method signature had `y::Any`. Indeed, we have the following type equivalence:
```julia
(Tuple{Union{Nothing,T},T} where T) == Union{Tuple{Nothing,Any}, Tuple{T,T} where T}
```
The general rule is: a concrete variable in covariant position acts like it's not concrete if the subtyping algorithm only *uses* it once. When `x` has type `Nothing`, we don't need to use the `T` in `Union{Nothing,T}`; we only use it in the second slot. This arises naturally from the observation that in `Tuple{T} where T` restricting `T` to concrete types makes no difference; the type is equal to `Tuple{Any}` either way.
However, appearing in *invariant* position disqualifies a variable from being concrete whether that appearance of the variable is used or not. Otherwise types can behave differently depending on which other types they are compared to, making subtyping not transitive. For example, consider
```julia
Tuple{Int,Int8,Vector{Integer}} <: Tuple{T,T,Vector{Union{Integer,T}}} where T
```


## [Diagonal types](#Diagonal-types)
If the `T` inside the `Union` is ignored, then `T` is concrete and the answer is "false" since the first two types aren't the same. But consider instead
```julia
Tuple{Int,Int8,Vector{Any}} <: Tuple{T,T,Vector{Union{Integer,T}}} where T
```
Now we cannot ignore the `T` in the `Union` (we must have `T == Any`), so `T` is not concrete and the answer is "true". That would make the concreteness of `T` depend on the other type, which is not acceptable since a type must have a clear meaning on its own. Therefore the appearance of `T` inside `Vector` is considered in both cases.


## [Subtyping diagonal variables](#Subtyping-diagonal-variables)
The subtyping algorithm for diagonal variables has two components: (1) identifying variable occurrences, and (2) ensuring that diagonal variables range over concrete types only.
The first task is accomplished by keeping counters `occurs_inv` and `occurs_cov` (in `src/subtype.c`) for each variable in the environment, tracking the number of invariant and covariant occurrences, respectively. A variable is diagonal when `occurs_inv == 0 && occurs_cov > 1`.
The second task is accomplished by imposing a condition on a variable's lower bound. As the subtyping algorithm runs, it narrows the bounds of each variable (raising lower bounds and lowering upper bounds) to keep track of the range of variable values for which the subtype relation would hold. When we are done evaluating the body of a `UnionAll` type whose variable is diagonal, we look at the final values of the bounds. Since the variable must be concrete, a contradiction occurs if its lower bound could not be a subtype of a concrete type. For example, an abstract type like [`AbstractArray`](../../base/arrays/#Core.AbstractArray) cannot be a subtype of a concrete type, but a concrete type like `Int` can be, and the empty type `Bottom` can be as well. If a lower bound fails this test the algorithm stops with the answer `false`.
For example, in the problem `Tuple{Int,String} <: Tuple{T,T} where T`, we derive that this would be true if `T` were a supertype of `Union{Int,String}`. However, `Union{Int,String}` is an abstract type, so the relation does not hold.


## [Subtyping diagonal variables](#Subtyping-diagonal-variables)
This concreteness test is done by the function `is_leaf_bound`. Note that this test is slightly different from `jl_is_leaf_type`, since it also returns `true` for `Bottom`. Currently this function is heuristic, and does not catch all possible concrete types. The difficulty is that whether a lower bound is concrete might depend on the values of other type variable bounds. For example, `Vector{T}` is equivalent to the concrete type `Vector{Int}` only if both the upper and lower bounds of `T` equal `Int`. We have not yet worked out a complete algorithm for this.


## [Introduction to the internal machinery](#Introduction-to-the-internal-machinery)
Most operations for dealing with types are found in the files `jltypes.c` and `subtype.c`. A good way to start is to watch subtyping in action. Build Julia with `make debug` and fire up Julia within a debugger. [gdb debugging tips](../debuggingtips/#gdb-debugging-tips) has some tips which may be useful.
Because the subtyping code is used heavily in the REPL itself – and hence breakpoints in this code get triggered often – it will be easiest if you make the following definition:
```julia-repl
julia> function mysubtype(a,b)
           ccall(:jl_breakpoint, Cvoid, (Any,), nothing)
           a <: b
       end
```
and then set a breakpoint in `jl_breakpoint`. Once this breakpoint gets triggered, you can set breakpoints in other functions.
As a warm-up, try the following:
```julia
mysubtype(Tuple{Int, Float64}, Tuple{Integer, Real})
```
We can make it more interesting by trying a more complex case:
```julia
mysubtype(Tuple{Array{Int,2}, Int8}, Tuple{Array{T}, T} where T)
```


## [Subtyping and method sorting](#Subtyping-and-method-sorting)
The `type_morespecific` functions are used for imposing a partial order on functions in method tables (from most-to-least specific). Specificity is strict; if `a` is more specific than `b`, then `a` does not equal `b` and `b` is not more specific than `a`.
If `a` is a strict subtype of `b`, then it is automatically considered more specific. From there, `type_morespecific` employs some less formal rules. For example, `subtype` is sensitive to the number of arguments, but `type_morespecific` may not be. In particular, `Tuple{Int,AbstractFloat}` is more specific than `Tuple{Integer}`, even though it is not a subtype. (Of `Tuple{Int,AbstractFloat}` and `Tuple{Integer,Float64}`, neither is more specific than the other.) Likewise, `Tuple{Int,Vararg{Int}}` is not a subtype of `Tuple{Integer}`, but it is considered more specific. However, `morespecific` does get a bonus for length: in particular, `Tuple{Int,Int}` is more specific than `Tuple{Int,Vararg{Int}}`.
If you're debugging how methods get sorted, it can be convenient to define the function:
```julia
type_morespecific(a, b) = ccall(:jl_type_morespecific, Cint, (Any,Any), a, b)
```
which allows you to test whether tuple type `a` is more specific than tuple type `b`.
------------------------------------------------------------------------


# Memory layout of Julia Objects · The Julia Language
Source: https://docs.julialang.org/en/v1/devdocs/object/


# [Memory layout of Julia Objects](#Memory-layout-of-Julia-Objects)


## [Object layout (jl_value_t)](#Object-layout-(jl_value_t))
The `jl_value_t` struct is the name for a block of memory owned by the Julia Garbage Collector, representing the data associated with a Julia object in memory. Absent any type information, it is simply an opaque pointer:
```c
typedef struct jl_value_t* jl_pvalue_t;
```
Each `jl_value_t` struct is contained in a `jl_typetag_t` struct that contains metadata information about the Julia object, such as its type and garbage collector (gc) reachability:
```c
typedef struct {
    opaque metadata;
    jl_value_t value;
} jl_typetag_t;
```
The type of any Julia object is an instance of a leaf `jl_datatype_t` object. The `jl_typeof()` function can be used to query for it:
```c
jl_value_t *jl_typeof(jl_value_t *v);
```
The layout of the object depends on its type. Reflection methods can be used to inspect that layout. A field can be accessed by calling one of the get-field methods:
```c
jl_value_t *jl_get_nth_field_checked(jl_value_t *v, size_t i);
jl_value_t *jl_get_field(jl_value_t *o, char *fld);
```
If the field types are known, a priori, to be all pointers, the values can also be extracted directly as an array access:
```c
jl_value_t *v = value->fieldptr[n];
```
As an example, a "boxed" `uint16_t` is stored as follows:
```c
struct {
    opaque metadata;
    struct {
        uint16_t data;        // -- 2 bytes
    } jl_value_t;
};
```
This object is created by `jl_box_uint16()`. Note that the `jl_value_t` pointer references the data portion, not the metadata at the top of the struct.


## [Object layout (jl_value_t)](#Object-layout-(jl_value_t))
A value may be stored "unboxed" in many circumstances (just the data, without the metadata, and possibly not even stored but just kept in registers), so it is unsafe to assume that the address of a box is a unique identifier. The "egal" test (corresponding to the `===` function in Julia), should instead be used to compare two unknown objects for equivalence:
```c
int jl_egal(jl_value_t *a, jl_value_t *b);
```
This optimization should be relatively transparent to the API, since the object will be "boxed" on-demand, whenever a `jl_value_t` pointer is needed.
Note that modification of a `jl_value_t` pointer in memory is permitted only if the object is mutable. Otherwise, modification of the value may corrupt the program and the result will be undefined. The mutability property of a value can be queried for with:
```c
int jl_is_mutable(jl_value_t *v);
```
If the object being stored is a `jl_value_t`, the Julia garbage collector must be notified also:
```c
void jl_gc_wb(jl_value_t *parent, jl_value_t *ptr);
```
However, the [Embedding Julia](../../manual/embedding/#Embedding-Julia) section of the manual is also required reading at this point, for covering other details of boxing and unboxing various types, and understanding the gc interactions.


## [Object layout (jl_value_t)](#Object-layout-(jl_value_t))
Mirror structs for some of the built-in types are [defined in `julia.h`](https://github.com/JuliaLang/julia/blob/master/src/julia.h). The corresponding global `jl_datatype_t` objects are created by [`jl_init_types` in `jltypes.c`](https://github.com/JuliaLang/julia/blob/master/src/jltypes.c).


## [Garbage collector mark bits](#Garbage-collector-mark-bits)
The garbage collector uses several bits from the metadata portion of the `jl_typetag_t` to track each object in the system. Further details about this algorithm can be found in the comments of the [garbage collector implementation in `gc.c`](https://github.com/JuliaLang/julia/blob/master/src/gc.c).


## [Object allocation](#Object-allocation)
Most new objects are allocated by `jl_new_structv()`:
```c
jl_value_t *jl_new_struct(jl_datatype_t *type, ...);
jl_value_t *jl_new_structv(jl_datatype_t *type, jl_value_t **args, uint32_t na);
```
Although, [`isbits`](../../base/base/#Base.isbits) objects can be also constructed directly from memory:
```c
jl_value_t *jl_new_bits(jl_value_t *bt, void *data)
```
And some objects have special constructors that must be used instead of the above functions:
Types:
```c
jl_datatype_t *jl_apply_type(jl_datatype_t *tc, jl_tuple_t *params);
jl_datatype_t *jl_apply_array_type(jl_datatype_t *type, size_t dim);
```
While these are the most commonly used options, there are more low-level constructors too, which you can find declared in [`julia.h`](https://github.com/JuliaLang/julia/blob/master/src/julia.h). These are used in `jl_init_types()` to create the initial types needed to bootstrap the creation of the Julia system image.
Tuples:
```c
jl_tuple_t *jl_tuple(size_t n, ...);
jl_tuple_t *jl_tuplev(size_t n, jl_value_t **v);
jl_tuple_t *jl_alloc_tuple(size_t n);
```
The representation of tuples is highly unique in the Julia object representation ecosystem. In some cases, a [`Base.tuple()`](../../base/base/#Core.tuple) object may be an array of pointers to the objects contained by the tuple equivalent to:
```c
typedef struct {
    size_t length;
    jl_value_t *data[length];
} jl_tuple_t;
```


## [Object allocation](#Object-allocation)
However, in other cases, the tuple may be converted to an anonymous [`isbits`](../../base/base/#Base.isbits) type and stored unboxed, or it may not stored at all (if it is not being used in a generic context as a `jl_value_t*`).
Symbols:
```c
jl_sym_t *jl_symbol(const char *str);
```
Functions and MethodInstance:
```c
jl_function_t *jl_new_generic_function(jl_sym_t *name);
jl_method_instance_t *jl_new_method_instance(jl_value_t *ast, jl_tuple_t *sparams);
```
Arrays:
```c
jl_array_t *jl_new_array(jl_value_t *atype, jl_tuple_t *dims);
jl_array_t *jl_alloc_array_1d(jl_value_t *atype, size_t nr);
jl_array_t *jl_alloc_array_nd(jl_value_t *atype, size_t *dims, size_t ndims);
```
Note that many of these have alternative allocation functions for various special-purposes. The list here reflects the more common usages, but a more complete list can be found by reading the [`julia.h` header file](https://github.com/JuliaLang/julia/blob/master/src/julia.h).
Internal to Julia, storage is typically allocated by `newstruct()` (or `newobj()` for the special types):
```c
jl_value_t *newstruct(jl_value_t *type);
jl_value_t *newobj(jl_value_t *type, size_t nfields);
```
And at the lowest level, memory is getting allocated by a call to the garbage collector (in `gc.c`), then tagged with its type:
```c
jl_value_t *jl_gc_allocobj(size_t nbytes);
void jl_set_typeof(jl_value_t *v, jl_datatype_t *type);
```
The documentation and usage for the function `jl_gc_allocobj` may be out of date


## [Object allocation](#Object-allocation)
Note that all objects are allocated in multiples of 4 bytes and aligned to the platform pointer size. Memory is allocated from a pool for smaller objects, or directly with `malloc()` for large objects.
Singleton types have only one instance and no data fields. Singleton instances have a size of 0 bytes, and consist only of their metadata. e.g. `nothing::Nothing`.
See [Singleton Types](../../manual/types/#man-singleton-types) and [Nothingness and missing values](../../manual/faq/#Nothingness-and-missing-values)
------------------------------------------------------------------------


# Eval of Julia code · The Julia Language
Source: https://docs.julialang.org/en/v1/devdocs/eval/


# [Eval of Julia code](#Eval-of-Julia-code)
One of the hardest parts about learning how the Julia Language runs code is learning how all of the pieces work together to execute a block of code.
Each chunk of code typically makes a trip through many steps with potentially unfamiliar names, such as (in no particular order): flisp, AST, C++, LLVM, `eval`, `typeinf`, `macroexpand`, sysimg (or system image), bootstrapping, compile, parse, execute, JIT, interpret, box, unbox, intrinsic function, and primitive function, before turning into the desired result (hopefully).
-   REPL
    REPL stands for Read-Eval-Print Loop. It's just what we call the command line environment for short.
-   AST
    Abstract Syntax Tree The AST is the digital representation of the code structure. In this form the code has been tokenized for meaning so that it is more suitable for manipulation and execution.
![Diagram of the compiler flow](../img/compiler_diagram.png)


## [Julia Execution](#Julia-Execution)
The 10,000 foot view of the whole process is as follows:
1.  The user starts `julia`.
2.  The C function `main()` from `cli/loader_exe.c` gets called. This function processes the command line arguments, filling in the `jl_options` struct and setting the variable `ARGS`. It then initializes Julia (by calling [`julia_init` in `init.c`](https://github.com/JuliaLang/julia/blob/master/src/init.c), which may load a previously compiled [sysimg](#dev-sysimg)). Finally, it passes off control to Julia by calling [`Base._start()`](https://github.com/JuliaLang/julia/blob/master/base/client.jl).
3.  When `_start()` takes over control, the subsequent sequence of commands depends on the command line arguments given. For example, if a filename was supplied, it will proceed to execute that file. Otherwise, it will start an interactive REPL.
4.  Skipping the details about how the REPL interacts with the user, let's just say the program ends up with a block of code that it wants to run.
5.  If the block of code to run is in a file, [`jl_load(char *filename)`](https://github.com/JuliaLang/julia/blob/master/src/toplevel.c) gets invoked to load the file and [parse](#dev-parsing) it. Each fragment of code is then passed to `eval` to execute.
6.  Each fragment of code (or AST), is handed off to [`eval()`](../../base/base/#eval) to turn into results.
7.  [`eval()`](../../base/base/#eval) takes each code fragment and tries to run it in [`jl_toplevel_eval_flex()`](https://github.com/JuliaLang/julia/blob/master/src/toplevel.c).


## [Julia Execution](#Julia-Execution)
8.  `jl_toplevel_eval_flex()` decides whether the code is a "toplevel" action (such as `using` or `module`), which would be invalid inside a function. If so, it passes off the code to the toplevel interpreter.
9.  `jl_toplevel_eval_flex()` then [expands](#dev-macro-expansion) the code to eliminate any macros and to "lower" the AST to make it simpler to execute.
10. `jl_toplevel_eval_flex()` then uses some simple heuristics to decide whether to JIT compile the AST or to interpret it directly.
11. The bulk of the work to interpret code is handled by [`eval` in `interpreter.c`](https://github.com/JuliaLang/julia/blob/master/src/interpreter.c).
12. If instead, the code is compiled, the bulk of the work is handled by `codegen.cpp`. Whenever a Julia function is called for the first time with a given set of argument types, [type inference](#dev-type-inference) will be run on that function. This information is used by the [codegen](#dev-codegen) step to generate faster code.
13. Eventually, the user quits the REPL, or the end of the program is reached, and the `_start()` method returns.
14. Just before exiting, `main()` calls [`jl_atexit_hook(exit_code)`](https://github.com/JuliaLang/julia/blob/master/src/init.c). This calls `Base._atexit()` (which calls any functions registered to [`atexit()`](../../base/base/#Base.atexit) inside Julia). Then it calls [`jl_gc_run_all_finalizers()`](https://github.com/JuliaLang/julia/blob/master/src/gc.c). Finally, it gracefully cleans up all `libuv` handles and waits for them to flush and close.


## [Parsing](#dev-parsing)
The Julia parser is a small lisp program written in femtolisp, the source-code for which is distributed inside Julia in [src/flisp](https://github.com/JuliaLang/julia/tree/master/src/flisp).
The interface functions for this are primarily defined in [`jlfrontend.scm`](https://github.com/JuliaLang/julia/blob/master/src/jlfrontend.scm). The code in [`ast.c`](https://github.com/JuliaLang/julia/blob/master/src/ast.c) handles this handoff on the Julia side.
The other relevant files at this stage are [`julia-parser.scm`](https://github.com/JuliaLang/julia/blob/master/src/julia-parser.scm), which handles tokenizing Julia code and turning it into an AST, and [`julia-syntax.scm`](https://github.com/JuliaLang/julia/blob/master/src/julia-syntax.scm), which handles transforming complex AST representations into simpler, "lowered" AST representations which are more suitable for analysis and execution.
If you want to test the parser without re-building Julia in its entirety, you can run the frontend on its own as follows:
```julia
$ cd src
$ flisp/flisp
> (load "jlfrontend.scm")
> (jl-parse-file "<filename>")
```


## [Macro Expansion](#dev-macro-expansion)
When [`eval()`](../../base/base/#eval) encounters a macro, it expands that AST node before attempting to evaluate the expression. Macro expansion involves a handoff from [`eval()`](../../base/base/#eval) (in Julia), to the parser function `jl_macroexpand()` (written in `flisp`) to the Julia macro itself (written in - what else - Julia) via `fl_invoke_julia_macro()`, and back.
Typically, macro expansion is invoked as a first step during a call to [`Meta.lower()`](../../base/base/#Base.Meta.lower)/`jl_expand()`, although it can also be invoked directly by a call to [`macroexpand()`](../../base/base/#Base.macroexpand)/`jl_macroexpand()`.


## [Type Inference](#dev-type-inference)
Type inference is implemented in Julia by [`typeinf()` in `compiler/typeinfer.jl`](https://github.com/JuliaLang/julia/blob/master/base/compiler/typeinfer.jl). Type inference is the process of examining a Julia function and determining bounds for the types of each of its variables, as well as bounds on the type of the return value from the function. This enables many future optimizations, such as unboxing of known immutable values, and compile-time hoisting of various run-time operations such as computing field offsets and function pointers. Type inference may also include other steps such as constant propagation and inlining.
-   JIT
    Just-In-Time Compilation The process of generating native-machine code into memory right when it is needed.
-   LLVM
    Low-Level Virtual Machine (a compiler) The Julia JIT compiler is a program/library called libLLVM. Codegen in Julia refers both to the process of taking a Julia AST and turning it into LLVM instructions, and the process of LLVM optimizing that and turning it into native assembly instructions.
-   C++
    The programming language that LLVM is implemented in, which means that codegen is also implemented in this language. The rest of Julia's library is implemented in C, in part because its smaller feature set makes it more usable as a cross-language interface layer.
-   box
    This term is used to describe the process of taking a value and allocating a wrapper around the data that is tracked by the garbage collector (gc) and is tagged with the object's type.
-   unbox


## [Type Inference](#dev-type-inference)
    The reverse of boxing a value. This operation enables more efficient manipulation of data when the type of that data is fully known at compile-time (through type inference).
-   generic function
    A Julia function composed of multiple "methods" that are selected for dynamic dispatch based on the argument type-signature
-   anonymous function or "method"
    A Julia function without a name and without type-dispatch capabilities
-   primitive function
    A function implemented in C but exposed in Julia as a named function "method" (albeit without generic function dispatch capabilities, similar to a anonymous function)
-   intrinsic function
    A low-level operation exposed as a function in Julia. These pseudo-functions implement operations on raw bits such as add and sign extend that cannot be expressed directly in any other way. Since they operate on bits directly, they must be compiled into a function and surrounded by a call to `Core.Intrinsics.box(T, ...)` to reassign type information to the value.


## [JIT Code Generation](#dev-codegen)
Codegen is the process of turning a Julia AST into native machine code.
The JIT environment is initialized by an early call to [`jl_init_codegen` in `codegen.cpp`](https://github.com/JuliaLang/julia/blob/master/src/codegen.cpp).
On demand, a Julia method is converted into a native function by the function `emit_function(jl_method_instance_t*)`. (note, when using the MCJIT (in LLVM v3.4+), each function must be JIT into a new module.) This function recursively calls `emit_expr()` until the entire function has been emitted.
Much of the remaining bulk of this file is devoted to various manual optimizations of specific code patterns. For example, `emit_known_call()` knows how to inline many of the primitive functions (defined in [`builtins.c`](https://github.com/JuliaLang/julia/blob/master/src/builtins.c)) for various combinations of argument types.
Other parts of codegen are handled by various helper files:
-   [`debuginfo.cpp`](https://github.com/JuliaLang/julia/blob/master/src/debuginfo.cpp)
    Handles backtraces for JIT functions
-   [`ccall.cpp`](https://github.com/JuliaLang/julia/blob/master/src/ccall.cpp)
    Handles the ccall and llvmcall FFI, along with various `abi_*.cpp` files
-   [`intrinsics.cpp`](https://github.com/JuliaLang/julia/blob/master/src/intrinsics.cpp)
    Handles the emission of various low-level intrinsic functions
The process of creating a new system image is called "bootstrapping".


## [JIT Code Generation](#dev-codegen)
The etymology of this word comes from the phrase "pulling oneself up by the bootstraps", and refers to the idea of starting from a very limited set of available functions and definitions and ending with the creation of a full-featured environment.


## [System Image](#dev-sysimg)
The system image is a precompiled archive of a set of Julia files. The `sys.ji` file distributed with Julia is one such system image, generated by executing the file [`sysimg.jl`](https://github.com/JuliaLang/julia/blob/master/base/sysimg.jl), and serializing the resulting environment (including Types, Functions, Modules, and all other defined values) into a file. Therefore, it contains a frozen version of the `Main`, `Core`, and `Base` modules (and whatever else was in the environment at the end of bootstrapping). This serializer/deserializer is implemented by [`jl_save_system_image`/`jl_restore_system_image` in `staticdata.c`](https://github.com/JuliaLang/julia/blob/master/src/staticdata.c).
If there is no sysimg file (`jl_options.image_file == NULL`), this also implies that `--build` was given on the command line, so the final result should be a new sysimg file. During Julia initialization, minimal `Core` and `Main` modules are created. Then a file named `boot.jl` is evaluated from the current directory. Julia then evaluates any file given as a command line argument until it reaches the end. Finally, it saves the resulting environment to a "sysimg" file for use as a starting point for a future Julia run.
------------------------------------------------------------------------


# Calling Conventions · The Julia Language
Source: https://docs.julialang.org/en/v1/devdocs/callconv/


# [Calling Conventions](#Calling-Conventions)
Julia uses three calling conventions for four distinct purposes:
| Name    | Prefix    | Purpose                          |
|:--------|:----------|:---------------------------------|
| Native  | `julia_`  | Speed via specialized signatures |
| JL Call | `jlcall_` | Wrapper for generic calls        |
| JL Call | `jl_`     | Builtins                         |
| C ABI   | `jlcapi_` | Wrapper callable from C          |


## [Julia Native Calling Convention](#Julia-Native-Calling-Convention)
The native calling convention is designed for fast non-generic calls. It usually uses a specialized signature.
-   LLVM ghosts (zero-length types) are omitted.
-   LLVM scalars and vectors are passed by value.
-   LLVM aggregates (arrays and structs) are passed by reference.
A small return values is returned as LLVM return values. A large return values is returned via the "structure return" (`sret`) convention, where the caller provides a pointer to a return slot.
An argument or return values that is a homogeneous tuple is sometimes represented as an LLVM vector instead of an LLVM array.


## [JL Call Convention](#JL-Call-Convention)
The JL Call convention is for builtins and generic dispatch. Hand-written functions using this convention are declared via the macro `JL_CALLABLE`. The convention uses exactly 3 parameters:
-   `F` - Julia representation of function that is being applied
-   `args` - pointer to array of pointers to boxes
-   `nargs` - length of the array
The return value is a pointer to a box.


## [C ABI](#C-ABI)
C ABI wrappers enable calling Julia from C. The wrapper calls a function using the native calling convention.
Tuples are always represented as C arrays.
------------------------------------------------------------------------


# High-level Overview of the Native-Code Generation Process · The Julia Language
Source: https://docs.julialang.org/en/v1/devdocs/compiler/


# [High-level Overview of the Native-Code Generation Process](#High-level-Overview-of-the-Native-Code-Generation-Process)


## [Representation of Pointers](#Representation-of-Pointers)
When emitting code to an object file, pointers will be emitted as relocations. The deserialization code will ensure any object that pointed to one of these constants gets recreated and contains the right runtime pointer.
Otherwise, they will be emitted as literal constants.
To emit one of these objects, call `literal_pointer_val`. It'll handle tracking the Julia value and the LLVM global, ensuring they are valid both for the current runtime and after deserialization.
When emitted into the object file, these globals are stored as references in a large `gvals` table. This allows the deserializer to reference them by index, and implement a custom manual mechanism similar to a Global Offset Table (GOT) to restore them.
Function pointers are handled similarly. They are stored as values in a large `fvals` table. Like globals, this allows the deserializer to reference them by index.
Note that `extern` functions are handled separately, with names, via the usual symbol resolution mechanism in the linker.
Note too that `ccall` functions are also handled separately, via a manual GOT and Procedure Linkage Table (PLT).


## [Representation of Intermediate Values](#Representation-of-Intermediate-Values)
Values are passed around in a `jl_cgval_t` struct. This represents an R-value, and includes enough information to determine how to assign or pass it somewhere.
They are created via one of the helper constructors, usually: `mark_julia_type` (for immediate values) and `mark_julia_slot` (for pointers to values).
The function `convert_julia_type` can transform between any two types. It returns an R-value with `cgval.typ` set to `typ`. It'll cast the object to the requested representation, making heap boxes, allocating stack copies, and computing tagged unions as needed to change the representation.
By contrast `update_julia_type` will change `cgval.typ` to `typ`, only if it can be done at zero-cost (i.e. without emitting any code).


## [Union representation](#Union-representation)
Inferred union types may be stack allocated via a tagged type representation.
The primitive routines that need to be able to handle tagged unions are:
-   mark-type
-   load-local
-   store-local
-   isa
-   is
-   emit_typeof
-   emit_sizeof
-   boxed
-   unbox
-   specialized cc-ret
Everything else should be possible to handle in inference by using these primitives to implement union-splitting.
The representation of the tagged-union is as a pair of `< void* union, byte selector >`. The selector is fixed-size as `byte & 0x7f`, and will union-tag the first 126 isbits. It records the one-based depth-first count into the type-union of the isbits objects inside. An index of zero indicates that the `union*` is actually a tagged heap-allocated `jl_value_t*`, and needs to be treated as normal for a boxed object rather than as a tagged union.
The high bit of the selector (`byte & 0x80`) can be tested to determine if the `void*` is actually a heap-allocated (`jl_value_t*`) box, thus avoiding the cost of re-allocating a box, while maintaining the ability to efficiently handle union-splitting based on the low bits.
It is guaranteed that `byte & 0x7f` is an exact test for the type, if the value can be represented by a tag – it will never be marked `byte = 0x80`. It is not necessary to also test the type-tag when testing `isa`.


## [Union representation](#Union-representation)
The `union*` memory region may be allocated at *any* size. The only constraint is that it is big enough to contain the data currently specified by `selector`. It might not be big enough to contain the union of all types that could be stored there according to the associated Union type field. Use appropriate care when copying.


## [Specialized Calling Convention Signature Representation](#Specialized-Calling-Convention-Signature-Representation)
A `jl_returninfo_t` object describes the calling convention details of any callable.
If any of the arguments or return type of a method can be represented unboxed, and the method is not varargs, it'll be given an optimized calling convention signature based on its `specTypes` and `rettype` fields.
The general principles are that:
-   Primitive types get passed in int/float registers.
-   Tuples of VecElement types get passed in vector registers.
-   Structs get passed on the stack.
-   Return values are handle similarly to arguments, with a size-cutoff at which they will instead be returned via a hidden sret argument.
The total logic for this is implemented by `get_specsig_function` and `deserves_sret`.
Additionally, if the return type is a union, it may be returned as a pair of values (a pointer and a tag). If the union values can be stack-allocated, then sufficient space to store them will also be passed as a hidden first argument. It is up to the callee whether the returned pointer will point to this space, a boxed object, or even other constant memory.
------------------------------------------------------------------------


# Julia Functions · The Julia Language
Source: https://docs.julialang.org/en/v1/devdocs/functions/


# [Julia Functions](#Julia-Functions)
This document will explain how functions, method definitions, and method tables work.


## [Method Tables](#Method-Tables)
Every function in Julia is a generic function. A generic function is conceptually a single function, but consists of many definitions, or methods. The methods of a generic function are stored in a method table. Method tables (type `MethodTable`) are associated with `TypeName`s. A `TypeName` describes a family of parameterized types. For example `Complex{Float32}` and `Complex{Float64}` share the same `Complex` type name object.
All objects in Julia are potentially callable, because every object has a type, which in turn has a `TypeName`.


## [Function calls](#Function-calls)
Given the call `f(x, y)`, the following steps are performed: first, the method table to use is accessed as `typeof(f).name.mt`. Second, an argument tuple type is formed, `Tuple{typeof(f), typeof(x), typeof(y)}`. Note that the type of the function itself is the first element. This is because the type might have parameters, and so needs to take part in dispatch. This tuple type is looked up in the method table.
This dispatch process is performed by `jl_apply_generic`, which takes two arguments: a pointer to an array of the values `f`, `x`, and `y`, and the number of values (in this case 3).
Throughout the system, there are two kinds of APIs that handle functions and argument lists: those that accept the function and arguments separately, and those that accept a single argument structure. In the first kind of API, the "arguments" part does *not* contain information about the function, since that is passed separately. In the second kind of API, the function is the first element of the argument structure.
For example, the following function for performing a call accepts just an `args` pointer, so the first element of the args array will be the function to call:
```c
jl_value_t *jl_apply(jl_value_t **args, uint32_t nargs)
```
This entry point for the same functionality accepts the function separately, so the `args` array does not contain the function:
```c
jl_value_t *jl_call(jl_function_t *f, jl_value_t **args, int32_t nargs);
```


## [Adding methods](#Adding-methods)
Given the above dispatch process, conceptually all that is needed to add a new method is (1) a tuple type, and (2) code for the body of the method. `jl_method_def` implements this operation. `jl_method_table_for` is called to extract the relevant method table from what would be the type of the first argument. This is much more complicated than the corresponding procedure during dispatch, since the argument tuple type might be abstract. For example, we can define:
```julia
(::Union{Foo{Int},Foo{Int8}})(x) = 0
```
which works since all possible matching methods would belong to the same method table.


## [Creating generic functions](#Creating-generic-functions)
Since every object is callable, nothing special is needed to create a generic function. Therefore `jl_new_generic_function` simply creates a new singleton (0 size) subtype of `Function` and returns its instance. A function can have a mnemonic "display name" which is used in debug info and when printing objects. For example the name of `Base.sin` is `sin`. By convention, the name of the created *type* is the same as the function name, with a `#` prepended. So `typeof(sin)` is `Base.#sin`.


## [Closures](#Closures)
A closure is simply a callable object with field names corresponding to captured variables. For example, the following code:
```julia
function adder(x)
    return y->x+y
end
```
is lowered to (roughly):
```julia
struct ##1{T}
    x::T
end

(_::##1)(y) = _.x + y

function adder(x)
    return ##1(x)
end
```


## [Constructors](#Constructors)
A constructor call is just a call to a type. The method table for `Type` contains all constructor definitions. All subtypes of `Type` (`Type`, `UnionAll`, `Union`, and `DataType`) currently share a method table via special arrangement.


## [Builtins](#Builtins)
The "builtin" functions, defined in the `Core` module, are:
```julia
<: === _abstracttype _apply_iterate _apply_pure _call_in_world
_call_in_world_total _call_latest _compute_sparams _equiv_typedef _expr
_primitivetype _setsuper! _structtype _svec_ref _typebody! _typevar applicable
apply_type compilerbarrier current_scope donotdelete fieldtype finalizer
get_binding_type getfield getglobal ifelse invoke isa isdefined
memoryref_isassigned memoryrefget memoryrefmodify! memoryrefnew memoryrefoffset
memoryrefreplace! memoryrefset! memoryrefsetonce! memoryrefswap! modifyfield!
modifyglobal! nfields replacefield! replaceglobal! set_binding_type! setfield!
setfieldonce! setglobal! setglobalonce! sizeof svec swapfield! swapglobal! throw
tuple typeassert typeof
```
These are all singleton objects whose types are subtypes of `Builtin`, which is a subtype of `Function`. Their purpose is to expose entry points in the run time that use the "jlcall" calling convention:
```c
jl_value_t *(jl_value_t*, jl_value_t**, uint32_t)
```
The method tables of builtins are empty. Instead, they have a single catch-all method cache entry (`Tuple{Vararg{Any}}`) whose jlcall fptr points to the correct function. This is kind of a hack but works reasonably well.


## [Keyword arguments](#Keyword-arguments)
Keyword arguments work by adding methods to the kwcall function. This function is usually the "keyword argument sorter" or "keyword sorter", which then calls the inner body of the function (defined anonymously). Every definition in the kwsorter function has the same arguments as some definition in the normal method table, except with a single `NamedTuple` argument prepended, which gives the names and values of passed keyword arguments. The kwsorter's job is to move keyword arguments into their canonical positions based on name, plus evaluate and substitute any needed default value expressions. The result is a normal positional argument list, which is then passed to yet another compiler-generated function.
The easiest way to understand the process is to look at how a keyword argument method definition is lowered. The code:
```julia
function circle(center, radius; color = black, fill::Bool = true, options...)
    # draw
end
```
actually produces *three* method definitions. The first is a function that accepts all arguments (including keyword arguments) as positional arguments, and includes the code for the method body. It has an auto-generated name:
```julia
function #circle#1(color, fill::Bool, options, circle, center, radius)
    # draw
end
```
The second method is an ordinary definition for the original `circle` function, which handles the case where no keyword arguments are passed:
```julia
function circle(center, radius)
    #circle#1(black, true, pairs(NamedTuple()), circle, center, radius)
end
```


## [Keyword arguments](#Keyword-arguments)
This simply dispatches to the first method, passing along default values. `pairs` is applied to the named tuple of rest arguments to provide key-value pair iteration. Note that if the method doesn't accept rest keyword arguments then this argument is absent.
Finally there is the kwsorter definition:
```julia
function (::Core.kwftype(typeof(circle)))(kws, circle, center, radius)
    if haskey(kws, :color)
        color = kws.color
    else
        color = black
    end
    # etc.

    # put remaining kwargs in `options`
    options = structdiff(kws, NamedTuple{(:color, :fill)})

    # if the method doesn't accept rest keywords, throw an error
    # unless `options` is empty

    #circle#1(color, fill, pairs(options), circle, center, radius)
end
```
The function `Core.kwftype(t)` creates the field `t.name.mt.kwsorter` (if it hasn't been created yet), and returns the type of that function.
This design has the feature that call sites that don't use keyword arguments require no special handling; everything works as if they were not part of the language at all. Call sites that do use keyword arguments are dispatched directly to the called function's kwsorter. For example the call:
```julia
circle((0, 0), 1.0, color = red; other...)
```
is lowered to:
```julia
kwcall(merge((color = red,), other), circle, (0, 0), 1.0)
```


## [Keyword arguments](#Keyword-arguments)
`kwcall` (also in`Core`) denotes a kwcall signature and dispatch. The keyword splatting operation (written as `other...`) calls the named tuple `merge` function. This function further unpacks each *element* of `other`, expecting each one to contain two values (a symbol and a value). Naturally, a more efficient implementation is available if all splatted arguments are named tuples. Notice that the original `circle` function is passed through, to handle closures.


## [Compiler efficiency issues](#compiler-efficiency-issues)
Generating a new type for every function has potentially serious consequences for compiler resource use when combined with Julia's "specialize on all arguments by default" design. Indeed, the initial implementation of this design suffered from much longer build and test times, higher memory use, and a system image nearly 2x larger than the baseline. In a naive implementation, the problem is bad enough to make the system nearly unusable. Several significant optimizations were needed to make the design practical.
The first issue is excessive specialization of functions for different values of function-valued arguments. Many functions simply "pass through" an argument to somewhere else, e.g. to another function or to a storage location. Such functions do not need to be specialized for every closure that might be passed in. Fortunately this case is easy to distinguish by simply considering whether a function *calls* one of its arguments (i.e. the argument appears in "head position" somewhere). Performance-critical higher-order functions like `map` certainly call their argument function and so will still be specialized as expected. This optimization is implemented by recording which arguments are called during the `analyze-variables` pass in the front end. When `cache_method` sees an argument in the `Function` type hierarchy passed to a slot declared as `Any` or `Function`, it behaves as if the `@nospecialize` annotation were applied. This heuristic seems to be extremely effective in practice.


## [Compiler efficiency issues](#compiler-efficiency-issues)
The next issue concerns the structure of method cache hash tables. Empirical studies show that the vast majority of dynamically-dispatched calls involve one or two arguments. In turn, many of these cases can be resolved by considering only the first argument. (Aside: proponents of single dispatch would not be surprised by this at all. However, this argument means "multiple dispatch is easy to optimize in practice", and that we should therefore use it, *not* "we should use single dispatch"!) So the method cache uses the type of the first argument as its primary key. Note, however, that this corresponds to the *second* element of the tuple type for a function call (the first element being the type of the function itself). Typically, type variation in head position is extremely low – indeed, the majority of functions belong to singleton types with no parameters. However, this is not the case for constructors, where a single method table holds constructors for every type. Therefore the `Type` method table is special-cased to use the *first* tuple type element instead of the second.


## [Compiler efficiency issues](#compiler-efficiency-issues)
The front end generates type declarations for all closures. Initially, this was implemented by generating normal type declarations. However, this produced an extremely large number of constructors, all of which were trivial (simply passing all arguments through to [`new`](../../base/base/#new)). Since methods are partially ordered, inserting all of these methods is O(n²), plus there are just too many of them to keep around. This was optimized by generating `struct_type` expressions directly (bypassing default constructor generation), and using `new` directly to create closure instances. Not the prettiest thing ever, but you do what you gotta do.
The next problem was the `@test` macro, which generated a 0-argument closure for each test case. This is not really necessary, since each test case is simply run once in place. Therefore, `@test` was modified to expand to a try-catch block that records the test result (true, false, or exception raised) and calls the test suite handler on it.
------------------------------------------------------------------------


# Base.Cartesian · The Julia Language
Source: https://docs.julialang.org/en/v1/devdocs/cartesian/


# [Base.Cartesian](#Base.Cartesian)
The (non-exported) Cartesian module provides macros that facilitate writing multidimensional algorithms. Most often you can write such algorithms with [straightforward techniques](https://julialang.org/blog/2016/02/iteration); however, there are a few cases where `Base.Cartesian` is still useful or necessary.


## [Principles of usage](#Principles-of-usage)
A simple example of usage is:
```julia
@nloops 3 i A begin
    s += @nref 3 A i
end
```
which generates the following code:
```julia
for i_3 = axes(A, 3)
    for i_2 = axes(A, 2)
        for i_1 = axes(A, 1)
            s += A[i_1, i_2, i_3]
        end
    end
end
```
In general, Cartesian allows you to write generic code that contains repetitive elements, like the nested loops in this example. Other applications include repeated expressions (e.g., loop unwinding) or creating function calls with variable numbers of arguments without using the "splat" construct (`i...`).