This repository has been archived by the owner on Dec 6, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #37 from timholy/teh/localmt
Towards a semi-performant recursive interpreter
- Loading branch information
Showing
21 changed files
with
1,567 additions
and
320 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,6 @@ | |
*.jl.mem | ||
expected.out | ||
failed.out | ||
src/builtins.jl | ||
deps/build.log | ||
docs/build/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
using InteractiveUtils | ||
|
||
const srcpath = joinpath(dirname(@__DIR__), "src") | ||
include(joinpath(srcpath, "generate_builtins.jl")) | ||
open(joinpath(srcpath, "builtins.jl"), "w") do io | ||
generate_builtins(io) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using Documenter, ASTInterpreter2 | ||
|
||
makedocs( | ||
modules = [ASTInterpreter2], | ||
clean = false, | ||
format = Documenter.HTML(prettyurls = get(ENV, "CI", nothing) == "true"), | ||
sitename = "ASTInterpreter2.jl", | ||
authors = "Keno Fischer, Tim Holy, and others", | ||
linkcheck = !("skiplinks" in ARGS), | ||
pages = [ | ||
"Home" => "index.md", | ||
"ast.md", | ||
"internals.md", | ||
"dev_reference.md", | ||
], | ||
) | ||
|
||
deploydocs( | ||
repo = "github.com/JuliaDebug/ASTInterpreter2.jl.git", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
# Lowered representation | ||
|
||
Let's start with a demonstration on simple function: | ||
|
||
```julia | ||
function summer(A::AbstractArray{T}) where T | ||
s = zero(T) | ||
for a in A | ||
s += a | ||
end | ||
return s | ||
end | ||
|
||
A = [1, 2, 5] | ||
``` | ||
|
||
ASTIntepreter2 uses the lowered representation of code: | ||
|
||
```julia | ||
julia> code = @code_lowered summer(A) | ||
CodeInfo( | ||
1 ─ s = (Main.zero)($(Expr(:static_parameter, 1))) | ||
│ %2 = A | ||
│ #temp# = (Base.iterate)(%2) | ||
│ %4 = #temp# === nothing | ||
│ %5 = (Base.not_int)(%4) | ||
└── goto #4 if not %5 | ||
2 ┄ %7 = #temp# | ||
│ a = (Core.getfield)(%7, 1) | ||
│ %9 = (Core.getfield)(%7, 2) | ||
│ s = s + a | ||
│ #temp# = (Base.iterate)(%2, %9) | ||
│ %12 = #temp# === nothing | ||
│ %13 = (Base.not_int)(%12) | ||
└── goto #4 if not %13 | ||
3 ─ goto #2 | ||
4 ┄ return s | ||
) | ||
``` | ||
|
||
To understand this package's internals, you need to familiarize yourself with these | ||
`CodeInfo` objects. The numbers on the left correspond to [basic blocks](https://en.wikipedia.org/wiki/Basic_block); | ||
when used in statements these are printed with a hash, e.g., in `goto #4 if not %6`, the | ||
`#4` refers to basic block 4. | ||
The numbers in the next column--e.g., `%1`, refer to [single static assignment (SSA) values](https://en.wikipedia.org/wiki/Static_single_assignment_form). | ||
Each statement (each line of this printout) corresponds to a single SSA value, | ||
but only those used later in the code are printed using assignment syntax. | ||
Wherever a previous SSA value is used, it's referenced by an `SSAValue` and printed as `%6`; | ||
for example, in `goto #4 if not %6`, the `%6` is the result of evaluating the 6th statement, | ||
which is `(Base.not_int)(%5)`, which in turn refers to the result of statement 5. | ||
Together lines 5 and 6 correspond to `!(#temp# === nothing)`. | ||
(The `#temp#` means that this was a generated variable name not present explicitly in the original source code.) | ||
|
||
Before diving into the details, let's first look at the statements themselves: | ||
|
||
```julia | ||
julia> code.code | ||
16-element Array{Any,1}: | ||
:(_3 = (Main.zero)($(Expr(:static_parameter, 1)))) | ||
:(_2) | ||
:(_4 = (Base.iterate)(%2)) | ||
:(_4 === nothing) | ||
:((Base.not_int)(%4)) | ||
:(unless %5 goto %16) | ||
:(_4) | ||
:(_5 = (Core.getfield)(%7, 1)) | ||
:((Core.getfield)(%7, 2)) | ||
:(_3 = _3 + _5) | ||
:(_4 = (Base.iterate)(%2, %9)) | ||
:(_4 === nothing) | ||
:((Base.not_int)(%12)) | ||
:(unless %13 goto %16) | ||
:(goto %7) | ||
:(return _3) | ||
``` | ||
|
||
You can see directly that the SSA assignments are implicit; they are not directly | ||
present in the statement list. | ||
The most noteworthy change here is the appearance of objects like `_3`, which are | ||
references that index into local variable slots: | ||
|
||
```julia | ||
julia> code.slotnames | ||
5-element Array{Any,1}: | ||
Symbol("#self#") | ||
:A | ||
:s | ||
Symbol("#temp#") | ||
:a | ||
``` | ||
|
||
When printing the whole `CodeInfo` object, these `slotnames` are substituted in. | ||
The types of objects that can be in `code.code` is well-described in the [Julia AST](https://docs.julialang.org/en/latest/devdocs/ast/) documentation. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# Function reference | ||
|
||
## Top-level | ||
|
||
```@docs | ||
@interpret | ||
``` | ||
|
||
## Frame creation | ||
|
||
```@docs | ||
ASTInterpreter2.enter_call | ||
ASTInterpreter2.enter_call_expr | ||
ASTInterpreter2.build_frame | ||
ASTInterpreter2.determine_method_for_expr | ||
ASTInterpreter2.prepare_args | ||
ASTInterpreter2.prepare_call | ||
ASTInterpreter2.get_call_framecode | ||
ASTInterpreter2.optimize! | ||
``` | ||
|
||
## Frame execution | ||
|
||
```@docs | ||
ASTInterpreter2.Compiled | ||
ASTInterpreter2.step_expr! | ||
ASTInterpreter2.finish! | ||
ASTInterpreter2.finish_and_return! | ||
ASTInterpreter2.next_until! | ||
ASTInterpreter2.evaluate_call! | ||
ASTInterpreter2.evaluate_foreigncall! | ||
ASTInterpreter2.maybe_evaluate_builtin | ||
ASTInterpreter2.@eval_rhs | ||
``` | ||
|
||
## Types | ||
|
||
```@docs | ||
ASTInterpreter2.JuliaStackFrame | ||
ASTInterpreter2.JuliaFrameCode | ||
ASTInterpreter2.JuliaProgramCounter | ||
``` | ||
|
||
## Internal storage | ||
|
||
```@docs | ||
ASTInterpreter2.framedict | ||
ASTInterpreter2.genframedict | ||
``` | ||
|
||
## Utilities | ||
|
||
```@docs | ||
ASTInterpreter2.iswrappercall | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# ASTInterpreter2 | ||
|
||
This package implements an [interpreter](https://en.wikipedia.org/wiki/Interpreter_(computing)) for Julia code. | ||
Normally, Julia compiles your code when you first execute it; using ASTInterpreter2 you can | ||
avoid compilation and execute the expressions that define your code directly. | ||
Interpreters have a number of applications, including support for stepping debuggers. | ||
|
||
At a pure user level, there is not much to know: | ||
|
||
```jldoctest | ||
julia> using ASTInterpreter2 | ||
julia> a = [1, 2, 5] | ||
3-element Array{Int64,1}: | ||
1 | ||
2 | ||
5 | ||
julia> sum(a) | ||
8 | ||
julia> @interpret sum(a) | ||
8 | ||
``` | ||
|
||
Those who want to dive deeper should continue reading. |
Oops, something went wrong.