Skip to content

Commit

Permalink
stage 1 bootstrapping now works
Browse files Browse the repository at this point in the history
to try it, run "julia stage1.j", then "julia -J sys.ji.new".
stage 0 is still the default until more testing has been done.

eliminate all C-implemented generic function methods
  some were replaced with ccalls, which can be removed entirely or
  kept for debugging during stage0 bootstrapping.
separate top-level binding lookup for read vs. assignment. allows
  using different import rules for assign, i.e. assignments go to the
  current environment rather than existing bindings in imported envs.
removing more unused code
move more stuff out of boot.j
simplify recursive function type inference; just use a loop
  • Loading branch information
JeffBezanson committed Jan 18, 2012
1 parent ec7571d commit 6571654
Show file tree
Hide file tree
Showing 18 changed files with 362 additions and 480 deletions.
65 changes: 65 additions & 0 deletions j/base.j
Original file line number Diff line number Diff line change
@@ -1,5 +1,67 @@
# important core definitions

convert(T, x) = convert_default(T, x, convert)
convert(T::Tuple, x::Tuple) = convert_tuple(T, x, convert)

type ErrorException <: Exception
msg::String
end

type SystemError <: Exception
prefix::String
errnum::Int32
SystemError(p::String, e::Integer) = new(p, int32(e))
SystemError(p::String) = new(p, errno())
end

type TypeError <: Exception
func::Symbol
context::String
expected::Type
got
end

type ParseError <: Exception
msg::String
end

type ArgumentError <: Exception
msg::String
end

type UnboundError <: Exception
var::Symbol
end

type KeyError <: Exception
key
end

type LoadError <: Exception
file::String
line::Int32
error
end

type MethodError <: Exception
f
args
end

type UnionTooComplexError <: Exception
types::Tuple
end

type BackTrace <: Exception
e
trace::Array{Any,1}
end

method_missing(f, args...) = throw(MethodError(f, args))

ccall(:jl_get_system_hooks, Void, ())


int(x) = convert(Int, x)
int(x::Int) = x
uint(x) = convert(Uint, x)
Expand Down Expand Up @@ -72,6 +134,9 @@ function compile_hint(f, args::Tuple)
nothing
end

# we share Array with Base so we can add definitions to it
const Array = eval(Base, :Array)

Array{T} (::Type{T}, d::(Integer,)) =
ccall(:jl_alloc_array_1d, Array{T,1}, (Any,Int), Array{T,1},
int(d[1]))
Expand Down
124 changes: 60 additions & 64 deletions j/inference.j
Original file line number Diff line number Diff line change
Expand Up @@ -158,23 +158,27 @@ function static_convert(to::ANY, from::ANY)
end
# tuple conversion calls convert recursively
if isseqtype(ce)
R = abstract_call_gf(convert, (), (Type{pe}, ce.parameters[1]), ())
#R = abstract_call_gf(convert, (), (Type{pe}, ce.parameters[1]), ())
R = static_convert(pe, ce.parameters[1])
isType(R) && (R = R.parameters[1])
result[i] = ...{R}
else
R = abstract_call_gf(convert, (), (Type{pe}, ce), ())
#R = abstract_call_gf(convert, (), (Type{pe}, ce), ())
R = static_convert(pe, ce)
isType(R) && (R = R.parameters[1])
result[i] = R
end
end
a2t(result)
end
t_func[:convert] =
(2, 2, (t,x)->(if isa(t,Tuple) && allp(isType,t)
t = Type{map(t->t.parameters[1],t)}
end;
isType(t) ? static_convert(t.parameters[1],x) :
Any))
t_func[convert_default] =
(3, 3, (t,x,f)->(isType(t) ? static_convert(t.parameters[1],x) : Any))
t_func[convert_tuple] =
(3, 3, (t,x,f)->(if isa(t,Tuple) && allp(isType,t)
t = Type{map(t->t.parameters[1],t)}
end;
isType(t) ? static_convert(t.parameters[1],x) :
Any))
typeof_tfunc = function (t)
if isType(t)
t = t.parameters[1]
Expand Down Expand Up @@ -486,6 +490,9 @@ function abstract_call(f, fargs, argtypes, vtypes, sv::StaticVarInfo, e)
end
end
end
if !is(f,apply) && isa(e,Expr) && isa(f,Function)
e.head = :call1
end
rt = builtin_tfunction(f, fargs, argtypes)
#print("=> ", rt, "\n")
return rt
Expand All @@ -497,8 +504,8 @@ function abstract_call(f, fargs, argtypes, vtypes, sv::StaticVarInfo, e)
end
end

ft_tfunc(ft, argtypes) = ccall(:jl_func_type_tfunc, Any,
(Any, Any), ft, argtypes)
ft_tfunc(ft, argtypes) = ccall(:jl_func_type_tfunc, Any, (Any, Any),
ft, argtypes)

function abstract_eval_call(e, vtypes, sv::StaticVarInfo)
fargs = a2t_butfirst(e.args)
Expand Down Expand Up @@ -828,10 +835,6 @@ end
typeinf(linfo,atypes,sparams) = typeinf(linfo,atypes,sparams,linfo,true)
typeinf(linfo,atypes,sparams,linfo) = typeinf(linfo,atypes,sparams,linfo,true)

abstract RecPending{T}

isRecPending(t) = isa(t, AbstractKind) && is(t.name, RecPending.name)

ast_rettype(ast) = ast.args[3].typ

# def is the original unspecialized version of a method. we aggregate all
Expand All @@ -840,8 +843,6 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop)
#dbg =
#dotrace = true#is(linfo,sizestr)
local ast::Expr
redo = false
curtype = None
# check cached t-functions
tf = def.tfunc
while !is(tf,())
Expand All @@ -853,15 +854,9 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop)
# if the frame above this one recurred, rerun type inf
# here instead of returning, and update the cache, until the new
# inferred type equals the cached type (fixed point)
rt = ast_rettype(tf[2])
if isRecPending(rt)
curtype = rt.parameters[1]
redo = true
ast = tf[2]
break
else
return (tf[2], rt)
end
ast = tf[2]
rt = ast_rettype(ast)
return (ast, rt)
end
tf = tf[3]
end
Expand Down Expand Up @@ -893,12 +888,9 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop)
f = f.prev
end

rec = false

#print("typeinf ", linfo.name, " ", atypes, "\n")

if redo
elseif cop
if cop
sparams = append(sparams, linfo.sparams)
ast = ccall(:jl_prepare_ast, Any, (Any,Any), linfo, sparams)::Expr
else
Expand All @@ -910,8 +902,20 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop)
locals = (ast.args[2].args[1].args)::Array{Any,1}
vars = append(args, locals)
body = (ast.args[3].args)::Array{Any,1}

n = length(body)

# our stack frame
frame = CallStack(ast0, linfo.module, atypes, inference_stack)
inference_stack = frame
curtype = None
frame.result = curtype

local s, sv

while true

rec = false

s = { () | i=1:n }
recpts = IntSet(n+1) # statements that depend recursively on our value
W = IntSet(n+1)
Expand Down Expand Up @@ -958,11 +962,6 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop)
end
sv = StaticVarInfo(sparams, cenv)

# our stack frame
frame = CallStack(ast0, linfo.module, atypes, inference_stack)
frame.result = curtype
inference_stack = frame

# exception handlers
cur_hand = ()
handler_at = { () | i=1:n }
Expand Down Expand Up @@ -1069,23 +1068,23 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop)
end
#print("\n",ast,"\n")
#print("==> ", frame.result,"\n")
if redo && typeseq(curtype, frame.result)
rec = false
end
fulltree = type_annotate(ast, s, sv,
rec ? RecPending{frame.result} : frame.result,
vars)
if !rec
fulltree.args[3] = inlining_pass(fulltree.args[3], s[1])
tuple_elim_pass(fulltree)
linfo.inferred = true
end
if !redo
compressed = ccall(:jl_compress_ast, Any, (Any,), fulltree)
fulltree = compressed
#compressed = fulltree
def.tfunc = (atypes, compressed, def.tfunc)
end
if !rec || typeseq(curtype, frame.result)
break
end
curtype = frame.result
end # while

fulltree = type_annotate(ast, s, sv, frame.result, vars)

fulltree.args[3] = inlining_pass(fulltree.args[3], s[1])
tuple_elim_pass(fulltree)
linfo.inferred = true

compressed = ccall(:jl_compress_ast, Any, (Any,), fulltree)
fulltree = compressed
#compressed = fulltree
def.tfunc = (atypes, compressed, def.tfunc)

inference_stack = (inference_stack::CallStack).prev
return (fulltree, frame.result)
end
Expand Down Expand Up @@ -1173,11 +1172,6 @@ function type_annotate(ast::Expr, states::Array{Any,1},
end
end

# do inference on inner functions
if isRecPending(rettype)
return ast
end

for li in closures
if !li.inferred
a = li.ast
Expand Down Expand Up @@ -1286,6 +1280,15 @@ end
function inlineable(f, e::Expr, vars)
argexprs = a2t_butfirst(e.args)
atypes = map(exprtype, argexprs)
if is(f, convert_default) && length(atypes)==3
# builtin case of convert. convert(T,x::S) => x, when S<:T
if isType(atypes[1]) && subtype(atypes[2],atypes[1].parameters[1])
# todo: if T expression has side effects??!
return e.args[3]
end
end
meth = getmethods(f, atypes)
if length(meth) != 1
return NF
Expand All @@ -1297,13 +1300,6 @@ function inlineable(f, e::Expr, vars)
if !subtype(atypes, meth[1])
return NF
end
if is(meth[3],:convert) && length(atypes)==2
# builtin case of convert. convert(T,x::S) => x, when S<:T
if isType(atypes[1]) && subtype(atypes[2],atypes[1].parameters[1])
# todo: if T expression has side effects??!
return e.args[3]
end
end
if !isa(meth[3],LambdaStaticData) || !is(meth[4],())
return NF
end
Expand Down
7 changes: 6 additions & 1 deletion j/show.j
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# formerly built-in methods. can be replaced any time.
print(a::Array{Uint8,1}) = ccall(:jl_print_array_uint8, Void, (Any,), a)
print(s::Symbol) = ccall(:jl_print_symbol, Void, (Any,), s)
show(x) = ccall(:jl_show_any, Void, (Any,), x)

print(x) = show(x)
showcompact(x) = show(x)
show_to_string(x) = print_to_string(show, x)
Expand All @@ -7,7 +12,7 @@ show(s::Symbol) = print(s)
show(tn::TypeName) = show(tn.name)
show(::Nothing) = print("nothing")
show(b::Bool) = print(b ? "true" : "false")
show(n::Integer) = show(int64(n))
show(n::Integer) = print(dec(int64(n)))

function show_trailing_hex(n::Uint64, ndig::Integer)
for s = ndig-1:-1:0
Expand Down
5 changes: 4 additions & 1 deletion j/stage0.j
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ if false
# simple print definitions for debugging. enable these if something
# goes wrong during bootstrap before printing code is available.
length(a::Array) = arraylen(a)
print(a::Array{Uint8,1}) = ccall(:jl_print_array_uint8, Void, (Any,), a)
print(s::Symbol) = ccall(:jl_print_symbol, Void, (Any,), s)
print(s::ASCIIString) = print(s.data)
print(x) = show(x)
println(x) = (print(x);print("\n"))
show(x) = ccall(:jl_show_any, Void, (Any,), x)
show(s::ASCIIString) = print(s.data)
show(s::Symbol) = print(s)
show(b::Bool) = print(b ? "true" : "false")
show(n::Int64) = ccall(:jl_print_int64, Void, (Int64,), n)
show(n::Integer) = show(int64(n))
show(n::Unsigned) = show(uint64(n))
print(a...) = for x=a; print(x); end
function show(e::Expr)
print(e.head)
Expand Down
15 changes: 1 addition & 14 deletions src/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ jl_typename_t *jl_array_typename;
jl_type_t *jl_array_uint8_type;
jl_type_t *jl_array_any_type;
jl_struct_type_t *jl_weakref_type;
jl_tag_type_t *jl_string_type;
jl_struct_type_t *jl_ascii_string_type;
jl_struct_type_t *jl_utf8_string_type;
jl_struct_type_t *jl_expr_type;
Expand Down Expand Up @@ -70,7 +69,7 @@ jl_sym_t *goto_sym; jl_sym_t *goto_ifnot_sym;
jl_sym_t *label_sym; jl_sym_t *return_sym;
jl_sym_t *lambda_sym; jl_sym_t *assign_sym;
jl_sym_t *null_sym; jl_sym_t *body_sym;
jl_sym_t *isbound_sym; jl_sym_t *macro_sym;
jl_sym_t *macro_sym;
jl_sym_t *locals_sym; jl_sym_t *colons_sym;
jl_sym_t *Any_sym; jl_sym_t *method_sym;
jl_sym_t *enter_sym; jl_sym_t *leave_sym;
Expand Down Expand Up @@ -625,18 +624,6 @@ jl_typector_t *jl_new_type_ctor(jl_tuple_t *params, jl_type_t *body)
return (jl_typector_t*)tc;
}

// struct constructors --------------------------------------------------------

JL_CALLABLE(jl_weakref_ctor)
{
if (nargs > 1) {
JL_NARGS(WeakRef, 1, 1);
}
if (nargs == 1)
return (jl_value_t*)jl_gc_new_weakref(args[0]);
return (jl_value_t*)jl_gc_new_weakref((jl_value_t*)jl_nothing);
}

// bits constructors ----------------------------------------------------------

#define BOX_FUNC(typ,c_type,pfx,nw) \
Expand Down
Loading

2 comments on commit 6571654

@JeffBezanson
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would just like to point out that the net code size change for this massive commit was -118 lines!

@StefanKarpinski
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's amazing. It's been fascinating watching the incredible code churn going on — with no discernible visible effect! Of course, I know it is all so that we can be self-hosting and have a real module system, both highly worthy goals.

Please sign in to comment.