diff --git a/base/expr.jl b/base/expr.jl index 875bf5b56f965..e4d8a255fec99 100644 --- a/base/expr.jl +++ b/base/expr.jl @@ -133,7 +133,7 @@ end function popmeta!(body::Expr, sym::Symbol) body.head == :block || return false, [] - found, metaex = findmeta_block(body) + found, metaex = findmeta_block(body.args) if !found return false, [] end @@ -151,23 +151,29 @@ function popmeta!(body::Expr, sym::Symbol) false, [] end popmeta!(arg, sym) = (false, []) +function popmeta!(body::Array{Any,1}, sym::Symbol) + ex = Expr(:block); ex.args = body + popmeta!(ex, sym) +end function findmeta(ex::Expr) if ex.head == :function || (ex.head == :(=) && typeof(ex.args[1]) == Expr && ex.args[1].head == :call) body::Expr = ex.args[2] body.head == :block || error(body, " is not a block expression") - return findmeta_block(ex) + return findmeta_block(ex.args) end error(ex, " is not a function expression") end -function findmeta_block(ex::Expr) - for a in ex.args +findmeta(ex::Array{Any,1}) = findmeta_block(ex) + +function findmeta_block(exargs) + for a in exargs if isa(a, Expr) if (a::Expr).head == :meta return true, a::Expr elseif (a::Expr).head == :block - found, exb = findmeta_block(a) + found, exb = findmeta_block(a.args) if found return found, exb end diff --git a/base/inference.jl b/base/inference.jl index a7421d11bb7eb..e7d524bb694ac 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -20,11 +20,8 @@ end type InferenceState atypes #::Type # type sig - ast #::Expr - body::Array{Any,1} # ast body sp::SimpleVector # static parameters gensym_types::Array{Any,1} # types of the GenSym's in this function - vinfo::Array{Any,1} # variable properties label_counter::Int # index of the current highest label for this function fedbackvars::Dict{GenSym, Bool} mod::Module @@ -33,6 +30,7 @@ type InferenceState # info on the state of inference and the linfo linfo::LambdaInfo + destination::LambdaInfo # results need to be copied here when we finish nargs::Int stmt_types::Vector{Any} # return type @@ -60,15 +58,10 @@ type InferenceState inferred::Bool tfunc_idx::Int - function InferenceState(linfo::LambdaInfo, atypes::ANY, sparams::SimpleVector, ast, optimize::Bool) - if !isa(ast,Expr) - ast = ccall(:jl_uncompress_ast, Any, (Any,Any), linfo, ast) - end - assert(is(ast.head,:lambda)) - vinflist = ast.args[2][1]::Array{Any,1} - nslots = length(vinflist) - body = (ast.args[3].args)::Array{Any,1} - nl = label_counter(body)+1 + function InferenceState(linfo::LambdaInfo, atypes::ANY, sparams::SimpleVector, optimize::Bool) + @assert isa(linfo.code,Array{Any,1}) + nslots = length(linfo.slotnames) + nl = label_counter(linfo.code)+1 if length(linfo.sparam_vals) > 0 sp = linfo.sparam_vals @@ -78,15 +71,14 @@ type InferenceState sp = sparams end - n = length(body) + n = length(linfo.code) s = Any[ () for i=1:n ] # initial types s[1] = Any[ VarState(Bottom,true) for i=1:nslots ] - la = length(ast.args[1]) + la = linfo.nargs if la > 0 - lastarg = ast.args[1][la] - if is_rest_arg(lastarg) + if linfo.isva if atypes === Tuple if la > 1 atypes = Tuple{Any[Any for i=1:la-1]..., Tuple.parameters[1]} @@ -126,8 +118,8 @@ type InferenceState @assert la == 0 # wrong number of arguments end - gensym_uses = find_gensym_uses(body) - gensym_types = Any[ NF for i=1:length(gensym_uses) ] + gensym_uses = find_gensym_uses(linfo.code) + gensym_types = linfo.gensymtypes gensym_init = copy(gensym_types) # exception handlers @@ -139,9 +131,9 @@ type InferenceState push!(W, 1) #initial pc to visit frame = new( - atypes, ast, body, sp, gensym_types, vinflist, nl, Dict{GenSym, Bool}(), linfo.module, 0, false, + atypes, sp, gensym_types, nl, Dict{GenSym, Bool}(), linfo.module, 0, false, - linfo, la, s, Union{}, W, n, + linfo, linfo, la, s, Union{}, W, n, cur_hand, handler_at, n_handlers, gensym_uses, gensym_init, ObjectIdDict(), #Dict{InferenceState, Vector{LineNum}}(), @@ -1504,8 +1496,34 @@ function newvar!(sv::InferenceState, typ) return GenSym(id) end -is_rest_arg(arg::ANY) = (ccall(:jl_is_rest_arg,Int32,(Any,), arg) != 0) - +# copy a LambdaInfo just enough to make it not share data with li.def +function unshare_linfo(li::LambdaInfo) + if li.nargs > 0 + if li === li.def + li = ccall(:jl_copy_lambda_info, Any, (Any,), li)::LambdaInfo + end + if !isa(li.code, Array{Any,1}) + li.code = ccall(:jl_uncompress_ast, Any, (Any,Any), li, li.code) + elseif li.code === li.def.code && li !== li.def + li.code = astcopy(li.code) + end + li.slotnames = copy(li.slotnames) + li.slotflags = copy(li.slotflags) + if isa(li.slottypes,Array) + li.slottypes = copy(li.slottypes) + end + if isa(li.gensymtypes,Array) + li.gensymtypes = copy(li.gensymtypes) + end + end + if !isa(li.slottypes,Array) + li.slottypes = Any[ Any for i = 1:length(li.slotnames) ] + end + if !isa(li.gensymtypes,Array) + li.gensymtypes = Any[ NF for i = 1:(li.gensymtypes::Int) ] + end + return li +end #### entry points for inferring a LambdaInfo given a type signature #### @@ -1514,8 +1532,8 @@ function typeinf_edge(linfo::LambdaInfo, atypes::ANY, sparams::SimpleVector, nee if linfo.module === Core && isempty(sparams) && isempty(linfo.sparam_vals) atypes = Tuple end - local ast::Expr, tfunc_idx = -1 - curtype = Bottom + local tfunc_idx = -1 + local frame # check cached t-functions # linfo.def is the original unspecialized version of a method. # we aggregate all saved type inference data there. @@ -1528,33 +1546,22 @@ function typeinf_edge(linfo::LambdaInfo, atypes::ANY, sparams::SimpleVector, nee if isa(code, InferenceState) # inference on this signature is in progress frame = code - tfunc_idx = i if linfo.inInference # record the LambdaInfo where this result should be cached when it is finished - @assert !frame.linfo.inInference - frame.linfo = linfo + @assert frame.destination === frame.linfo || frame.destination === linfo + frame.destination = linfo end + tfunc_idx = i + break elseif isa(code, Type) - curtype = code::Type # sometimes just a return type is stored here. if a full AST # is not needed, we can return it. if !needtree return (nothing, code, true) end - elseif isa(code,Tuple) - inftree, inftyp = code - if linfo.inInference - linfo.inferred = true - linfo.ast = inftree - linfo.rettype = inftyp - linfo.inInference = false - if !isa(inftree,Expr) - inftree = ccall(:jl_uncompress_ast, Any, (Any,Any), linfo, inftree) - end - linfo.nslots = length(inftree.args[2][1]) - linfo.ngensym = length(inftree.args[2][3]) - end - return (inftree, inftyp, true) # code is a tuple (ast, type) + elseif isa(code,LambdaInfo) + @assert code.inferred + return (code, code.rettype, true) else # otherwise this is an InferenceState from a different bootstrap stage's # copy of the inference code; ignore it. @@ -1591,9 +1598,9 @@ function typeinf_edge(linfo::LambdaInfo, atypes::ANY, sparams::SimpleVector, nee end end # add lam to be inferred and record the edge - ast = ccall(:jl_prepare_ast, Any, (Any,), linfo)::Expr + linfo = unshare_linfo(linfo) # our stack frame inference context - frame = InferenceState(linfo, atypes, sparams, ast, optimize) + frame = InferenceState(linfo, atypes, sparams, optimize) if cached #println(linfo) @@ -1627,7 +1634,7 @@ function typeinf_edge(linfo::LambdaInfo, atypes::ANY, sparams::SimpleVector, nee end end typeinf_loop(frame) - return (frame.ast, frame.bestguess, frame.inferred) + return (frame.linfo, frame.bestguess, frame.inferred) end function typeinf_edge(linfo::LambdaInfo, atypes::ANY, sparams::SimpleVector, caller) @@ -1644,7 +1651,21 @@ function typeinf_uncached(linfo::LambdaInfo, atypes::ANY, sparams::SimpleVector, return typeinf_edge(linfo, atypes, sparams, true, optimize, false, nothing) end function typeinf_ext(linfo::LambdaInfo, toplevel::Bool) - return typeinf_edge(linfo, linfo.specTypes, svec(), true, true, true, nothing) + (code, _t, _) = typeinf_edge(linfo, linfo.specTypes, svec(), true, true, true, nothing) + if code.inferred + linfo.inferred = true + linfo.inInference = false + if linfo !== code + linfo.code = code.code + linfo.slotnames = code.slotnames + linfo.slottypes = code.slottypes + linfo.slotflags = code.slotflags + linfo.gensymtypes = code.gensymtypes + linfo.rettype = code.rettype + linfo.pure = code.pure + end + end + nothing end @@ -1728,7 +1749,7 @@ function typeinf_frame(frame) else frame.cur_hand = frame.handler_at[pc] end - stmt = frame.body[pc] + stmt = frame.linfo.code[pc] changes = abstract_interpret(stmt, s[pc]::Array{Any,1}, frame) if changes === () # if there was a Expr(:static_typeof) on this line, @@ -1955,41 +1976,46 @@ function finish(me::InferenceState) me.gensym_types[i] = Union{} end end - fulltree = type_annotate(me.ast, me.stmt_types, me, me.bestguess, me.nargs) + type_annotate!(me.linfo, me.stmt_types, me, me.bestguess, me.nargs) # make sure (meta pure) is stripped from full tree - @assert fulltree.args[3].head === :body - body = Expr(:block) - body.args = fulltree.args[3].args::Array{Any,1} - ispure = popmeta!(body, :pure)[1] + ispure = popmeta!(me.linfo.code, :pure)[1] # run optimization passes on fulltree if me.optimize if JLOptions().can_inline == 1 - fulltree.args[3] = inlining_pass(fulltree.args[3], me, fulltree)[1] - inbounds_meta_elim_pass(fulltree.args[3]) + inlining_pass!(me.linfo, me) + inbounds_meta_elim_pass!(me.linfo.code) end - alloc_elim_pass(fulltree, me) - getfield_elim_pass(fulltree.args[3], me) - reindex_labels!(fulltree.args[3], me) + alloc_elim_pass!(me.linfo, me) + getfield_elim_pass!(me.linfo, me) + reindex_labels!(me.linfo, me) end # finalize and record the linfo result - me.ast = fulltree me.inferred = true - compressedtree = ccall(:jl_compress_ast, Any, (Any,Any), me.linfo.def, fulltree) - if me.linfo.inInference - me.linfo.inferred = true - me.linfo.pure = ispure - me.linfo.ast = compressedtree - me.linfo.rettype = me.bestguess - me.linfo.inInference = false - me.linfo.nslots = length(fulltree.args[2][1]) - me.linfo.ngensym = length(me.gensym_types) + me.linfo.inferred = true + me.linfo.inInference = false + me.linfo.pure = ispure + compressedtree = ccall(:jl_compress_ast, Any, (Any,Any), me.linfo.def, me.linfo.code) + me.linfo.code = compressedtree + me.linfo.rettype = me.bestguess + + if me.destination !== me.linfo + out = me.destination + out.inferred = true + out.inInference = false + out.code = me.linfo.code + out.slotnames = me.linfo.slotnames + out.slottypes = me.linfo.slottypes + out.slotflags = me.linfo.slotflags + out.gensymtypes = me.linfo.gensymtypes + out.rettype = me.linfo.rettype + out.pure = me.linfo.pure end if me.tfunc_idx != -1 - me.linfo.def.tfunc[me.tfunc_idx + 1] = (compressedtree, me.bestguess) + me.linfo.def.tfunc[me.tfunc_idx + 1] = me.linfo me.linfo.def.tfunc[me.tfunc_idx + 2] = false end @@ -2064,7 +2090,7 @@ function eval_annotate(e::ANY, vtypes::ANY, sv::InferenceState, decls, undefs) end # annotate types of all symbols in AST -function type_annotate(ast::Expr, states::Array{Any,1}, sv::ANY, rettype::ANY, nargs) +function type_annotate!(linfo::LambdaInfo, states::Array{Any,1}, sv::ANY, rettype::ANY, nargs) nslots = length(states[1]) decls = Any[ NF for i = 1:nslots ] undefs = fill(false, nslots) @@ -2072,7 +2098,7 @@ function type_annotate(ast::Expr, states::Array{Any,1}, sv::ANY, rettype::ANY, n for i = 1:nargs decls[i] = states[1][i].typ end - body = ast.args[3].args::Array{Any,1} + body = linfo.code for i=1:length(body) st_i = states[i] if st_i !== () @@ -2080,21 +2106,17 @@ function type_annotate(ast::Expr, states::Array{Any,1}, sv::ANY, rettype::ANY, n body[i] = eval_annotate(body[i], st_i, sv, decls, undefs) end end - ast.args[3].typ = rettype # add declarations for variables that are always the same type for i = 1:nslots - vi = ast.args[2][1][i] if decls[i] !== NF - vi[2] = decls[i] + linfo.slottypes[i] = decls[i] end if undefs[i] - vi[3] |= 32 + linfo.slotflags[i] |= 32 end end - ast.args[2][3] = sv.gensym_types - - return ast + nothing end # replace slots 1:na with argexprs, static params with spvals, and increment @@ -2281,7 +2303,7 @@ end # static parameters are ok if all the static parameter values are leaf types, # meaning they are fully known. # `ft` is the type of the function. `f` is the exact function if known, or else `nothing`. -function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::InferenceState, enclosing_ast::Expr) +function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::InferenceState, enclosing::LambdaInfo) local linfo, metharg::Type, argexprs = e.args, @@ -2403,7 +2425,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference # # check call stack to see if this argument list is growing # st = inference_stack # while !isa(st, EmptyCallStack) - # if st.ast === linfo.def.ast && length(atypes) > length(st.types) + # if st.code === linfo.def.code && length(atypes) > length(st.types) # atypes = limit_tuple_type(atypes) # meth = _methods(f, atypes, 1) # if meth === false || length(meth) != 1 @@ -2424,21 +2446,21 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference methargs = metharg.parameters nm = length(methargs) - (ast, ty, inferred) = typeinf(linfo, metharg, methsp, true) - if is(ast,nothing) || !inferred + (linfo, ty, inferred) = typeinf(linfo, metharg, methsp, true) + if is(linfo,nothing) || !inferred return NF end + ast = linfo.code - if !isa(ast,Expr) + if !isa(ast,Array{Any,1}) ast = ccall(:jl_uncompress_ast, Any, (Any,Any), linfo, ast) else ast = astcopy(ast) end - ast = ast::Expr - vinflist = ast.args[2][1]::Array{Any,1} + ast = ast::Array{Any,1} body = Expr(:block) - body.args = ast.args[3].args::Array{Any,1} + body.args = ast propagate_inbounds, _ = popmeta!(body, :propagate_inbounds) cost::Int = 1000 if incompletematch @@ -2483,12 +2505,11 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference filter!(x->!(isa(x,Expr) && x.head === :meta && isempty(x.args)), body.args) - enc_vinflist = enclosing_ast.args[2][1]::Array{Any,1} - na = length(ast.args[1]) + na = linfo.nargs # check for vararg function isva = false - if na > 0 && is_rest_arg(ast.args[1][na]) + if na > 0 && linfo.isva if length(argexprs) < na - 1 return (Expr(:call, TopNode(:error), "too few arguments"), []) end @@ -2592,9 +2613,9 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference islocal = false # if the argument name is also used as a local variable, # we need to keep it as a variable name - if vinflist[i][3] != 0 + if linfo.slotflags[i] != 0 islocal = true - aeitype = tmerge(aeitype, vinflist[i][2]) + aeitype = tmerge(aeitype, linfo.slottypes[i]) end # ok for argument to occur more than once if the actual argument @@ -2647,7 +2668,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference vnew = newvar!(sv, aeitype) argexprs[i] = vnew else - vnew = add_slot!(enclosing_ast, aeitype, #=SSA=#false) + vnew = add_slot!(enclosing, aeitype, #=SSA=#false) argexprs[i] = vnew end unshift!(stmts, Expr(:(=), vnew, aei)) @@ -2669,23 +2690,20 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference end # re-number the GenSyms and copy their type-info to the new ast - gensym_types = ast.args[2][3] - if gensym_types != 0 - if (isa(gensym_types,Integer)) - gensym_types = Any[Any for i = 1:ast.args[2][3]] - end - if !isempty(gensym_types) - incr = length(sv.gensym_types) - if incr != 0 - body = gensym_increment(body, incr) - end - append!(sv.gensym_types, ast.args[2][3]) + gensym_types = linfo.gensymtypes + if !isempty(gensym_types) + incr = length(sv.gensym_types) + if incr != 0 + body = gensym_increment(body, incr) end + append!(sv.gensym_types, gensym_types) end # ok, substitute argument expressions for argument names in the body - body = substitute!(body, na, argexprs, spvals, length(enc_vinflist)-na) - append!(enc_vinflist, vinflist[na+1:end]) + body = substitute!(body, na, argexprs, spvals, length(enclosing.slotnames)-na) + append!(enclosing.slotnames, linfo.slotnames[na+1:end]) + append!(enclosing.slottypes, linfo.slottypes[na+1:end]) + append!(enclosing.slotflags, linfo.slotflags[na+1:end]) # make labels / goto statements unique newlabels = zeros(Int,label_counter(body.args)+1) @@ -2715,7 +2733,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference # convert return statements into a series of goto's retstmt = genlabel(sv) - rettype = (ast.args[3]::Expr).typ + rettype = linfo.rettype local retval multiret = false lastexpr = pop!(body.args) @@ -2734,7 +2752,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference if a.head === :return if !multiret # create slot first time - retval = add_slot!(enclosing_ast, rettype, false) + retval = add_slot!(enclosing, rettype, false) end multiret = true unshift!(a.args, retval) @@ -2838,7 +2856,31 @@ end const corenumtype = Union{Int32,Int64,Float32,Float64} -function inlining_pass(e::Expr, sv, ast) +function inlining_pass!(linfo::LambdaInfo, sv::InferenceState) + eargs = linfo.code + stmts = [] + i = 1 + while i <= length(eargs) + ei = eargs[i] + if isa(ei,Expr) + res = inlining_pass(ei, sv, linfo) + eargs[i] = res[1] + else + i += 1 + continue + end + if isa(res[2],Array) + sts = res[2]::Array{Any,1} + for j = 1:length(sts) + insert!(eargs, i, sts[j]) + i += 1 + end + end + i += 1 + end +end + +function inlining_pass(e::Expr, sv, linfo) if e.head === :method # avoid running the inlining pass on function definitions return (e,()) @@ -2848,25 +2890,6 @@ function inlining_pass(e::Expr, sv, ast) return (e,()) end stmts = [] - if e.head === :body - i = 1 - while i <= length(eargs) - ei = eargs[i] - if isa(ei,Expr) - res = inlining_pass(ei, sv, ast) - eargs[i] = res[1] - if isa(res[2],Array) - sts = res[2]::Array{Any,1} - for j = 1:length(sts) - insert!(eargs, i, sts[j]) - i += 1 - end - end - end - i += 1 - end - return (e, stmts) - end arg1 = eargs[1] # don't inline first (global) arguments of ccall, as this needs to be evaluated # by the interpreter and inlining might put in something it can't handle, @@ -2895,7 +2918,7 @@ function inlining_pass(e::Expr, sv, ast) else argloc = eargs end - res = inlining_pass(ei::Expr, sv, ast) + res = inlining_pass(ei::Expr, sv, linfo) res1 = res[1] if has_stmts && !effect_free(res1, sv, false) restype = exprtype(res1,sv) @@ -2970,7 +2993,7 @@ function inlining_pass(e::Expr, sv, ast) (a === Bottom || isvarargtype(a)) && return (e, stmts) ata[i] = a end - res = inlineable(f, ft, e, ata, sv, ast) + res = inlineable(f, ft, e, ata, sv, linfo) if isa(res,Tuple) if isa(res[2],Array) && !isempty(res[2]) append!(stmts,res[2]) @@ -3029,10 +3052,11 @@ function inlining_pass(e::Expr, sv, ast) return (e,stmts) end -function add_slot!(ast, typ, is_sa) - vinflist = ast.args[2][1]::Array{Any,1} - id = length(vinflist)+1 - push!(vinflist, Any[:__temp__, typ, 2+16*is_sa]) +function add_slot!(linfo::LambdaInfo, typ, is_sa) + id = length(linfo.slotnames)+1 + push!(linfo.slotnames, :__temp__) + push!(linfo.slottypes, typ) + push!(linfo.slotflags, 2+16*is_sa) Slot(id, typ) end @@ -3052,68 +3076,73 @@ function is_known_call_p(e::Expr, pred, sv) return !is(f,false) && pred(_ieval(f,sv)) end -is_var_assigned(ast, v) = isa(v,Slot) && ast.args[2][1][v.id][3]&2 != 0 +is_var_assigned(linfo, v) = isa(v,Slot) && linfo.slotflags[v.id]&2 != 0 -function delete_var!(ast, id, T) +function delete_var!(linfo, id, T) filter!(x->!(isa(x,Expr) && (x.head === :(=) || x.head === :const) && isa(x.args[1],T) && x.args[1].id == id), - ast.args[3].args) - ast + linfo.code) + linfo +end + +function slot_replace!(linfo::LambdaInfo, id, rhs, T) + for i = 1:length(linfo.code) + linfo.code[i] = _slot_replace!(linfo.code[i], id, rhs, T) + end + linfo end -function slot_replace!(e, id, rhs, T) +function _slot_replace!(e, id, rhs, T) if isa(e,T) && e.id == id return rhs end if isa(e,Expr) for i = 1:length(e.args) - e.args[i] = slot_replace!(e.args[i], id, rhs, T) + e.args[i] = _slot_replace!(e.args[i], id, rhs, T) end end return e end -occurs_undef(var::Int, expr, varinfo) = - varinfo[var][3]&32 != 0 && occurs_more(expr, e->(isa(e,Slot) && e.id==var), 0)>0 +occurs_undef(var::Int, expr, flags) = + flags[var]&32 != 0 && occurs_more(expr, e->(isa(e,Slot) && e.id==var), 0)>0 # remove all single-assigned vars v in "v = x" where x is an argument # and not assigned. # "sa" is the result of find_sa_vars # T: Slot or Gensym -function remove_redundant_temp_vars(ast, sa, T) - varinfo = ast.args[2][1] - gensym_types = ast.args[2][3] - body = ast.args[3] +function remove_redundant_temp_vars(linfo, sa, T) + flags = linfo.slotflags + gensym_types = linfo.gensymtypes + bexpr = Expr(:block); bexpr.args = linfo.code for (v,init) in sa - if (isa(init, Slot) && !is_var_assigned(ast, init)) + if (isa(init, Slot) && !is_var_assigned(linfo, init)) # this transformation is not valid for vars used before def. # we need to preserve the point of assignment to know where to # throw errors (issue #4645). - if T===GenSym || !occurs_undef(v, body, varinfo) + if T===GenSym || !occurs_undef(v, bexpr, flags) # the transformation is not ideal if the assignment # is present for the auto-unbox functionality # (from inlining improved type inference information) # and this transformation would worsen the type information # everywhere later in the function - if init.typ <: (T===GenSym ? gensym_types[v+1] : varinfo[v][2]) - delete_var!(ast, v, T) - slot_replace!(body, v, init, T) + if init.typ <: (T===GenSym ? gensym_types[v+1] : linfo.slottypes[v]) + delete_var!(linfo, v, T) + slot_replace!(linfo, v, init, T) end end end end - ast + linfo end # compute set of slots assigned once -function find_sa_vars(ast) - body = ast.args[3].args +function find_sa_vars(linfo::LambdaInfo) + body = linfo.code av = ObjectIdDict() av2 = ObjectIdDict() gss = ObjectIdDict() - vinfos = ast.args[2][1]::Array{Any,1} - nargs = length(ast.args[1]) - args = ast.args[1] + nargs = linfo.nargs for i = 1:length(body) e = body[i] if isa(e,Expr) && is(e.head,:(=)) @@ -3171,60 +3200,67 @@ end # removes inbounds metadata if we never encounter an inbounds=true or # boundscheck context in the method body -function inbounds_meta_elim_pass(e::Expr) +function inbounds_meta_elim_pass!(code::Array{Any,1}) if findfirst(x -> isa(x, Expr) && ((x.head === :inbounds && x.args[1] == true) || x.head === :boundscheck), - e.args) == 0 - filter!(x -> !(isa(x, Expr) && x.head === :inbounds), e.args) + code) == 0 + filter!(x -> !(isa(x, Expr) && x.head === :inbounds), code) end end # does the same job as alloc_elim_pass for allocations inline in getfields # TODO can probably be removed when we switch to a linear IR -function getfield_elim_pass(e::Expr, sv) +function getfield_elim_pass!(linfo::LambdaInfo, sv) + body = linfo.code + for i = 1:length(body) + body[i] = _getfield_elim_pass!(body[i], sv) + end +end + +function _getfield_elim_pass!(e::Expr, sv) for i = 1:length(e.args) - ei = e.args[i] - if isa(ei,Expr) - getfield_elim_pass(ei, sv) - if is_known_call(ei, getfield, sv) && length(ei.args)==3 && - (isa(ei.args[3],Int) || isa(ei.args[3],QuoteNode)) - e1 = ei.args[2] - j = ei.args[3] - if isa(e1,Expr) - alloc = is_immutable_allocation(e1, sv) - if !is(alloc, false) - flen, fnames = alloc - if isa(j,QuoteNode) - j = findfirst(fnames, j.value) - end - if 1 <= j <= flen - ok = true - for k = 2:length(e1.args) - k == j+1 && continue - if !effect_free(e1.args[k], sv, true) - ok = false; break - end - end - if ok - e.args[i] = e1.args[j+1] - end + e.args[i] = _getfield_elim_pass!(e.args[i], sv) + end + if is_known_call(e, getfield, sv) && length(e.args)==3 && + (isa(e.args[3],Int) || isa(e.args[3],QuoteNode)) + e1 = e.args[2] + j = e.args[3] + if isa(e1,Expr) + alloc = is_immutable_allocation(e1, sv) + if !is(alloc, false) + flen, fnames = alloc + if isa(j,QuoteNode) + j = findfirst(fnames, j.value) + end + if 1 <= j <= flen + ok = true + for k = 2:length(e1.args) + k == j+1 && continue + if !effect_free(e1.args[k], sv, true) + ok = false; break end end - elseif isa(e1,Tuple) && isa(j,Int) && (1 <= j <= length(e1)) - e1j = e1[j] - if !(isa(e1j,Number) || isa(e1j,AbstractString) || isa(e1j,Tuple) || - isa(e1j,Type)) - e1j = QuoteNode(e1j) + if ok + return e1.args[j+1] end - e.args[i] = e1j - elseif isa(e1,QuoteNode) && isa(e1.value,Tuple) && isa(j,Int) && (1 <= j <= length(e1.value)) - e.args[i] = QuoteNode(e1.value[j]) end end + elseif isa(e1,Tuple) && isa(j,Int) && (1 <= j <= length(e1)) + e1j = e1[j] + if !(isa(e1j,Number) || isa(e1j,AbstractString) || isa(e1j,Tuple) || + isa(e1j,Type)) + e1j = QuoteNode(e1j) + end + return e1j + elseif isa(e1,QuoteNode) && isa(e1.value,Tuple) && isa(j,Int) && (1 <= j <= length(e1.value)) + return QuoteNode(e1.value[j]) end end + return e end +_getfield_elim_pass!(e::ANY, sv) = e + # check if e is a successful allocation of an immutable struct # if it is, returns (n,f) such that it is always valid to call # getfield(..., 1 <= x <= n) or getfield(..., x in f) on the result @@ -3250,14 +3286,15 @@ function is_immutable_allocation(e :: ANY, sv::InferenceState) end false end + # eliminate allocation of unnecessary immutables # that are only used as arguments to safe getfield calls -function alloc_elim_pass(ast::Expr, sv::InferenceState) - bexpr = ast.args[3]::Expr - body = (ast.args[3].args)::Array{Any,1} - vs, gs = find_sa_vars(ast) - remove_redundant_temp_vars(ast, vs, Slot) - remove_redundant_temp_vars(ast, gs, GenSym) +function alloc_elim_pass!(linfo::LambdaInfo, sv::InferenceState) + body = linfo.code + bexpr = Expr(:block); bexpr.args = body + vs, gs = find_sa_vars(linfo) + remove_redundant_temp_vars(linfo, vs, Slot) + remove_redundant_temp_vars(linfo, gs, GenSym) i = 1 while i < length(body) e = body[i] @@ -3295,14 +3332,14 @@ function alloc_elim_pass(ast::Expr, sv::InferenceState) end end i += n_ins - replace_getfield!(ast, bexpr, var, vals, field_names, sv, i) + replace_getfield!(linfo, bexpr, var, vals, field_names, sv, i) else i += 1 end end end -function replace_getfield!(ast, e::Expr, tupname, vals, field_names, sv, i0) +function replace_getfield!(linfo::LambdaInfo, e::Expr, tupname, vals, field_names, sv, i0) for i = i0:length(e.args) a = e.args[i] if isa(a,Expr) && is_known_call(a, getfield, sv) && @@ -3321,7 +3358,7 @@ function replace_getfield!(ast, e::Expr, tupname, vals, field_names, sv, i0) val = val::Slot if a.typ <: val.typ && !typeseq(a.typ,val.typ) val.typ = a.typ - ast.args[2][1][val.id][2] = a.typ + linfo.slottypes[val.id] = a.typ end elseif isa(val,GenSym) val = val::GenSym @@ -3332,25 +3369,26 @@ function replace_getfield!(ast, e::Expr, tupname, vals, field_names, sv, i0) end e.args[i] = val elseif isa(a, Expr) - replace_getfield!(ast, a::Expr, tupname, vals, field_names, sv, 1) + replace_getfield!(linfo, a::Expr, tupname, vals, field_names, sv, 1) end end end # fix label numbers to always equal the statement index of the label -function reindex_labels!(e, sv) +function reindex_labels!(linfo::LambdaInfo, sv::InferenceState) + body = linfo.code mapping = zeros(Int, sv.label_counter) - for i = 1:length(e.args) - el = e.args[i] + for i = 1:length(body) + el = body[i] if isa(el,LabelNode) mapping[el.label] = i - e.args[i] = LabelNode(i) + body[i] = LabelNode(i) end end - for i = 1:length(e.args) - el = e.args[i] + for i = 1:length(body) + el = body[i] if isa(el,GotoNode) - e.args[i] = GotoNode(mapping[el.label]) + body[i] = GotoNode(mapping[el.label]) elseif isa(el,Expr) if el.head === :gotoifnot el.args[2] = mapping[el.args[2]] diff --git a/base/interactiveutil.jl b/base/interactiveutil.jl index d23997108a5d0..89aee2e807507 100644 --- a/base/interactiveutil.jl +++ b/base/interactiveutil.jl @@ -225,17 +225,19 @@ versioninfo(verbose::Bool) = versioninfo(STDOUT,verbose) function code_warntype(io::IO, f, t::ANY) emph_io = IOContext(io, :TYPEEMPHASIZE => true) - ct = code_typed(f, t) - for ast in ct + for li in code_typed(f, t) println(emph_io, "Variables:") - vars = ast.args[2][1] - for v in vars - print(emph_io, " ", v[1]) - show_expr_type(emph_io, v[2], true) + for i = 1:length(li.slotnames) + print(emph_io, " ", li.slotnames[i]) + if isa(li.slottypes,Array) + show_expr_type(emph_io, li.slottypes[i], true) + end print(emph_io, '\n') end print(emph_io, "\nBody:\n ") - show_unquoted(emph_io, ast.args[3], 2) + body = Expr(:body); body.args = uncompressed_ast(li) + body.typ = li.rettype + show_unquoted(emph_io, body, 2) print(emph_io, '\n') end nothing diff --git a/base/methodshow.jl b/base/methodshow.jl index 9b9b52eaaa24d..5ebb194722512 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -34,8 +34,7 @@ function arg_decl_parts(m::Method) tv = Any[tv...] end li = m.func - e = uncompressed_ast(li) - argnames = e.args[1] + argnames = li.slotnames[1:li.nargs] s = symbol("?") decls = [argtype_decl(:tvar_env => tv, get(argnames,i,s), m.sig.parameters[i]) for i = 1:length(m.sig.parameters)] @@ -49,11 +48,7 @@ function kwarg_decl(m::Method, kwtype::DataType) while d !== nothing if typeseq(d.sig, sig) li = d.func - e = uncompressed_ast(li) - argnames = Any[(isa(n,Expr) ? n.args[1] : n) for n in e.args[1]] - kwargs = filter!(x->!(x in argnames || '#' in string(x)), - Any[x[1] for x in e.args[2][1]]) - return kwargs + return filter(x->!('#' in string(x)), li.slotnames[li.nargs+1:end]) end d = d.next end diff --git a/base/reflection.jl b/base/reflection.jl index 633fd41f937da..f9c7ffa9cf693 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -170,7 +170,7 @@ end tt_cons(t::ANY, tup::ANY) = (@_pure_meta; Tuple{t, (isa(tup, Type) ? tup.parameters : tup)...}) -code_lowered(f, t::ANY=Tuple) = map(m->uncompressed_ast(m.func), methods(f, t)) +code_lowered(f, t::ANY=Tuple) = map(m->m.func, methods(f, t)) function methods(f::ANY,t::ANY) if isa(f,Builtin) throw(ArgumentError("argument is not a generic function")) @@ -249,7 +249,7 @@ done(mt::MethodTable, m::Method) = false done(mt::MethodTable, i::Void) = true uncompressed_ast(l::LambdaInfo) = - isa(l.ast,Expr) ? l.ast : ccall(:jl_uncompress_ast, Any, (Any,Any), l, l.ast) + isa(l.code,Array{Any,1}) ? l.code : ccall(:jl_uncompress_ast, Any, (Any,Any), l, l.code) # Printing code representations in IR and assembly function _dump_function(f, t::ANY, native, wrapper, strip_ir_metadata, dump_module) @@ -295,14 +295,11 @@ function code_typed(f::ANY, types::ANY=Tuple; optimize=true) for x in _methods(f,types,-1) linfo = func_for_method_checked(x, types) if optimize - (tree, ty) = Core.Inference.typeinf(linfo, x[1], x[2], true) + (li, ty) = Core.Inference.typeinf(linfo, x[1], x[2], true) else - (tree, ty) = Core.Inference.typeinf_uncached(linfo, x[1], x[2], optimize=false) + (li, ty) = Core.Inference.typeinf_uncached(linfo, x[1], x[2], optimize=false) end - if !isa(tree, Expr) - tree = ccall(:jl_uncompress_ast, Any, (Any,Any), linfo, tree) - end - push!(asts, tree) + push!(asts, li) end asts end @@ -312,7 +309,7 @@ function return_types(f::ANY, types::ANY=Tuple) rt = [] for x in _methods(f,types,-1) linfo = func_for_method_checked(x,types) - (tree, ty) = Core.Inference.typeinf(linfo, x[1], x[2]) + (_li, ty) = Core.Inference.typeinf(linfo, x[1], x[2]) push!(rt, ty) end rt diff --git a/base/serialize.jl b/base/serialize.jl index a43320b237513..27a21e4fd3c56 100644 --- a/base/serialize.jl +++ b/base/serialize.jl @@ -310,6 +310,10 @@ function serialize(s::SerializationState, linfo::LambdaInfo) writetag(s.io, LAMBDASTATICDATA_TAG) serialize(s, object_number(linfo)) serialize(s, uncompressed_ast(linfo)) + serialize(s, linfo.slotnames) + serialize(s, linfo.slottypes) + serialize(s, linfo.slotflags) + serialize(s, linfo.gensymtypes) if isdefined(linfo.def, :roots) serialize(s, linfo.def.roots::Vector{Any}) else @@ -323,6 +327,8 @@ function serialize(s::SerializationState, linfo::LambdaInfo) serialize(s, linfo.file) serialize(s, linfo.line) serialize(s, linfo.pure) + serialize(s, linfo.nargs) + serialize(s, linfo.isva) end function serialize(s::SerializationState, t::Task) @@ -552,7 +558,11 @@ function deserialize(s::SerializationState, ::Type{LambdaInfo}) makenew = true end deserialize_cycle(s, linfo) - ast = deserialize(s)::Expr + code = deserialize(s) + slotnames = deserialize(s) + slottypes = deserialize(s) + slotflags = deserialize(s) + gensymtypes = deserialize(s) roots = deserialize(s)::Vector{Any} sparam_syms = deserialize(s)::SimpleVector sparam_vals = deserialize(s)::SimpleVector @@ -562,17 +572,26 @@ function deserialize(s::SerializationState, ::Type{LambdaInfo}) file = deserialize(s) line = deserialize(s) pure = deserialize(s) + nargs = deserialize(s) + isva = deserialize(s) if makenew - linfo.module = mod + linfo.code = code + linfo.slotnames = slotnames + linfo.slottypes = slottypes + linfo.slotflags = slotflags + linfo.gensymtypes = gensymtypes + linfo.roots = roots linfo.sparam_syms = sparam_syms linfo.sparam_vals = sparam_vals - ccall(:jl_lambda_info_set_ast, Void, (Any, Any), linfo, ast) linfo.inferred = infr - linfo.roots = roots + linfo.module = mod linfo.name = name linfo.file = file linfo.line = line linfo.pure = pure + linfo.nargs = nargs + linfo.isva = isva + ccall(:jl_lambda_info_init_properties, Void, (Any,), linfo) known_object_data[lnumber] = linfo end return linfo diff --git a/base/show.jl b/base/show.jl index f37afb0c6dca7..236caeeb875ce 100644 --- a/base/show.jl +++ b/base/show.jl @@ -209,9 +209,10 @@ function show(io::IO, m::Module) end function show(io::IO, l::LambdaInfo) - print(io, "AST(") - show(io, uncompressed_ast(l)) - print(io, ")") + println(io, "LambdaInfo for ", l.name) + body = Expr(:body); body.args = uncompressed_ast(l) + body.typ = l.rettype + show(io, body) end function show_delim_array(io::IO, itr::Union{AbstractArray,SimpleVector}, op, delim, cl, delim_one, diff --git a/base/stacktraces.jl b/base/stacktraces.jl index a3a7a503a37ac..47db91d98a54e 100644 --- a/base/stacktraces.jl +++ b/base/stacktraces.jl @@ -165,8 +165,8 @@ function show_spec_linfo(io::IO, frame::StackFrame) print(io, frame.func !== empty_sym ? frame.func : "?") else linfo = get(frame.outer_linfo) - if isdefined(linfo, 8) - params = linfo.(#=specTypes=#8).parameters + if isdefined(linfo, :specTypes) + params = linfo.specTypes.parameters ft = params[1] if ft <: Function && isempty(ft.parameters) && isdefined(ft.name.module, ft.name.mt.name) && diff --git a/src/alloc.c b/src/alloc.c index 12be244b90ada..71a49cea8d820 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -96,7 +96,7 @@ jl_sym_t *dot_sym; jl_sym_t *newvar_sym; jl_sym_t *boundscheck_sym; jl_sym_t *inbounds_sym; jl_sym_t *copyast_sym; jl_sym_t *fastmath_sym; jl_sym_t *pure_sym; jl_sym_t *simdloop_sym; -jl_sym_t *meta_sym; +jl_sym_t *meta_sym; jl_sym_t *compiler_temp_sym; jl_sym_t *inert_sym; jl_sym_t *vararg_sym; jl_sym_t *unused_sym; jl_sym_t *static_parameter_sym; @@ -271,12 +271,24 @@ JL_DLLEXPORT jl_value_t *jl_new_struct_uninit(jl_datatype_t *type) return jv; } +JL_DLLEXPORT void jl_lambda_info_init_properties(jl_lambda_info_t *li) +{ + int i; + uint8_t called=0; + for(i=1; i < li->nargs && i <= 8; i++) { + jl_value_t *ai = jl_cellref(li->slotnames,i); + if (ai == (jl_value_t*)unused_sym) continue; + if (jl_array_uint8_ref(li->slotflags,i)&64) + called |= (1<<(i-1)); + } + li->called = called; +} + JL_DLLEXPORT void jl_lambda_info_set_ast(jl_lambda_info_t *li, jl_value_t *ast) { - li->ast = ast; jl_gc_wb(li, ast); - if (!jl_is_expr(ast)) - return; + assert(jl_is_expr(ast)); jl_array_t *body = jl_lam_body((jl_expr_t*)ast)->args; + li->code = body; jl_gc_wb(li, li->code); if (has_meta(body, pure_sym)) li->pure = 1; jl_value_t *body1 = skip_meta(body); @@ -288,25 +300,38 @@ JL_DLLEXPORT void jl_lambda_info_set_ast(jl_lambda_info_t *li, jl_value_t *ast) li->file = (jl_sym_t*)jl_exprarg(body1, 1); li->line = jl_unbox_long(jl_exprarg(body1, 0)); } - jl_array_t *vis = jl_lam_vinfo((jl_expr_t*)li->ast); - jl_array_t *args = jl_lam_args((jl_expr_t*)li->ast); - li->nslots = jl_array_len(vis); - jl_value_t *gensym_types = jl_lam_gensyms((jl_expr_t*)li->ast); - li->ngensym = (jl_is_array(gensym_types) ? jl_array_len(gensym_types) : jl_unbox_long(gensym_types)); + jl_array_t *vis = jl_lam_vinfo((jl_expr_t*)ast); + jl_array_t *args = jl_lam_args((jl_expr_t*)ast); + size_t nslots = jl_array_len(vis); size_t narg = jl_array_len(args); - uint8_t called=0; - int i, j=0; - for(i=1; i < narg && i <= 8; i++) { - jl_value_t *ai = jl_cellref(args,i); - if (ai == (jl_value_t*)unused_sym || !jl_is_symbol(ai)) continue; - jl_value_t *vj; - do { - vj = jl_cellref(vis, j++); - } while (jl_cellref(vj,0) != ai); - if (jl_unbox_long(jl_cellref(vj,2))&64) - called |= (1<<(i-1)); + li->nargs = narg; + li->isva = narg>0 && jl_is_rest_arg(jl_cellref(args, narg-1)); + jl_value_t *gensym_types = jl_lam_gensyms((jl_expr_t*)ast); + size_t ngensym = (jl_is_array(gensym_types) ? jl_array_len(gensym_types) : jl_unbox_long(gensym_types)); + li->slotnames = jl_alloc_cell_1d(nslots); + li->slottypes = jl_nothing; + li->slotflags = jl_alloc_array_1d(jl_array_uint8_type, nslots); + li->gensymtypes = jl_box_long(ngensym); + int i; + for(i=0; i < nslots; i++) { + jl_value_t *vi = jl_cellref(vis, i); + jl_sym_t *name = (jl_sym_t*)jl_cellref(vi, 0); + assert(jl_is_symbol(name)); + char *str = jl_symbol_name(name); + if (i > 0 && name != unused_sym) { + if (str[0] == '#') { + // convention for renamed variables: #...#original_name + char *nxt = strchr(str + 1, '#'); + if (nxt) + name = jl_symbol(nxt+1); + else if (str[1] == 's') // compiler-generated temporaries, #sXXX + name = compiler_temp_sym; + } + } + jl_cellset(li->slotnames, i, name); + jl_array_uint8_set(li->slotflags, i, jl_unbox_long(jl_cellref(vi, 2))); } - li->called = called; + jl_lambda_info_init_properties(li); } JL_DLLEXPORT @@ -316,7 +341,9 @@ jl_lambda_info_t *jl_new_lambda_info(jl_value_t *ast, jl_svec_t *tvars, jl_svec_ jl_lambda_info_t *li = (jl_lambda_info_t*)newobj((jl_value_t*)jl_lambda_info_type, NWORDS(sizeof(jl_lambda_info_t))); - li->ast = ast; + li->code = NULL; + li->slotnames = li->slotflags = NULL; + li->slottypes = li->gensymtypes = NULL; li->rettype = (jl_value_t*)jl_any_type; li->file = null_sym; li->module = ctx; @@ -343,15 +370,27 @@ jl_lambda_info_t *jl_new_lambda_info(jl_value_t *ast, jl_svec_t *tvars, jl_svec_ li->pure = 0; li->called = 0xff; li->needs_sparam_vals_ducttape = 2; - if (ast != NULL) + if (ast != NULL) { + JL_GC_PUSH1(&li); jl_lambda_info_set_ast(li, ast); + JL_GC_POP(); + } return li; } -jl_lambda_info_t *jl_copy_lambda_info(jl_lambda_info_t *linfo) +JL_DLLEXPORT jl_lambda_info_t *jl_copy_lambda_info(jl_lambda_info_t *linfo) { jl_lambda_info_t *new_linfo = - jl_new_lambda_info(linfo->ast, linfo->sparam_syms, linfo->sparam_vals, linfo->module); + jl_new_lambda_info(NULL, linfo->sparam_syms, linfo->sparam_vals, linfo->module); + new_linfo->code = linfo->code; + new_linfo->slotnames = linfo->slotnames; + new_linfo->slottypes = linfo->slottypes; + new_linfo->slotflags = linfo->slotflags; + new_linfo->gensymtypes = linfo->gensymtypes; + new_linfo->called = linfo->called; + new_linfo->nargs = linfo->nargs; + new_linfo->isva = linfo->isva; + new_linfo->pure = linfo->pure; new_linfo->rettype = linfo->rettype; new_linfo->tfunc = linfo->tfunc; new_linfo->name = linfo->name; @@ -679,6 +718,8 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype(jl_sym_t *name, jl_datatype_t *super t = jl_int64_type; else if (!strcmp(jl_symbol_name((jl_sym_t*)name), "Bool")) t = jl_bool_type; + else if (!strcmp(jl_symbol_name((jl_sym_t*)name), "UInt8")) + t = jl_uint8_type; } if (t == NULL) t = jl_new_uninitialized_datatype(jl_svec_len(fnames), 2); // TODO @@ -880,6 +921,9 @@ void jl_init_int32_int64_cache(void) boxed_gensym_cache[i] = jl_box32(jl_gensym_type, i); #endif } + for(i=0; i < 256; i++) { + boxed_uint8_cache[i] = jl_box8(jl_uint8_type, i); + } } void jl_init_box_caches(void) @@ -887,7 +931,6 @@ void jl_init_box_caches(void) int64_t i; for(i=0; i < 256; i++) { boxed_int8_cache[i] = jl_box8(jl_int8_type, i); - boxed_uint8_cache[i] = jl_box8(jl_uint8_type, i); } for(i=0; i < NBOX_C; i++) { boxed_int16_cache[i] = jl_box16(jl_int16_type, i-NBOX_C/2); diff --git a/src/ast.c b/src/ast.c index ae8e1d47a83e8..dbafa41d894a8 100644 --- a/src/ast.c +++ b/src/ast.c @@ -486,7 +486,7 @@ static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, int eo) e = cdr_(e); } nli = jl_new_lambda_info((jl_value_t*)ex, tvars, jl_emptysvec, jl_current_module); - jl_preresolve_globals(nli->ast, nli); + jl_preresolve_globals((jl_value_t*)nli, nli); JL_GC_POP(); return (jl_value_t*)nli; } @@ -918,18 +918,6 @@ jl_array_t *jl_lam_args(jl_expr_t *l) return (jl_array_t*)ae; } -jl_sym_t *jl_lam_argname(jl_lambda_info_t *li, int i) -{ - jl_expr_t *ast; - if (jl_is_expr(li->ast)) - ast = (jl_expr_t*)li->ast; - else - ast = (jl_expr_t*)jl_uncompress_ast(li, li->ast); - // NOTE (gc root): `ast` is not rooted here, but jl_lam_args and jl_cellref - // do not allocate. - return (jl_sym_t*)jl_cellref(jl_lam_args(ast),i); -} - // get array of var info records (for args and locals) jl_array_t *jl_lam_vinfo(jl_expr_t *l) { @@ -961,13 +949,6 @@ jl_expr_t *jl_lam_body(jl_expr_t *l) return (jl_expr_t*)be; } -jl_sym_t *jl_decl_var(jl_value_t *ex) -{ - if (jl_is_symbol(ex)) return (jl_sym_t*)ex; - assert(jl_is_expr(ex)); - return (jl_sym_t*)jl_exprarg(ex, 0); -} - JL_DLLEXPORT int jl_is_rest_arg(jl_value_t *ex) { if (!jl_is_expr(ex)) return 0; @@ -1018,25 +999,6 @@ JL_DLLEXPORT jl_value_t *jl_copy_ast(jl_value_t *expr) return expr; } -// given a new lambda_info with static parameter values, make a copy -// of the tree with declared types evaluated and static parameters passed -// on to all enclosed functions. -// this tree can then be further mutated by optimization passes. -JL_DLLEXPORT jl_value_t *jl_prepare_ast(jl_lambda_info_t *li) -{ - jl_value_t *ast = li->ast; - if (ast == NULL) return NULL; - JL_GC_PUSH1(&ast); - if (!jl_is_expr(ast)) { - ast = jl_uncompress_ast(li, ast); - } - else { - ast = jl_copy_ast(ast); - } - JL_GC_POP(); - return ast; -} - JL_DLLEXPORT int jl_is_operator(char *sym) { jl_ast_context_t *ctx = jl_ast_ctx_enter(); @@ -1088,6 +1050,15 @@ jl_value_t *jl_preresolve_globals(jl_value_t *expr, jl_lambda_info_t *lam) return expr; return jl_module_globalref(lam->module, (jl_sym_t*)expr); } + else if (jl_is_lambda_info(expr)) { + jl_array_t *exprs = ((jl_lambda_info_t*)expr)->code; + if (jl_typeis(exprs, jl_array_any_type)) { + size_t l = jl_array_len(exprs); + size_t i; + for(i=0; i < l; i++) + jl_cellset(exprs, i, jl_preresolve_globals(jl_cellref(exprs,i), lam)); + } + } else if (jl_is_expr(expr)) { jl_expr_t *e = (jl_expr_t*)expr; if (e->head == lambda_sym) { diff --git a/src/builtins.c b/src/builtins.c index 5eca771687f09..e12cd4a1fbe1e 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -113,12 +113,6 @@ JL_DLLEXPORT void JL_NORETURN jl_type_error(const char *fname, jl_value_t *expec JL_DLLEXPORT void JL_NORETURN jl_undefined_var_error(jl_sym_t *var) { - if (jl_symbol_name(var)[0] == '#') { - // convention for renamed variables: #...#original_name - char *nxt = strchr(jl_symbol_name(var) + 1, '#'); - if (nxt) - var = jl_symbol(nxt+1); - } jl_throw(jl_new_struct(jl_undefvarerror_type, var)); } @@ -1084,11 +1078,11 @@ jl_value_t *jl_mk_builtin_func(const char *name, jl_fptr_t fptr) { jl_sym_t *sname = jl_symbol(name); jl_value_t *f = jl_new_generic_function_with_supertype(sname, jl_core_module, jl_builtin_type, 0); - jl_lambda_info_t *li = jl_new_lambda_info(jl_nothing, jl_emptysvec, jl_emptysvec, jl_core_module); + jl_lambda_info_t *li = jl_new_lambda_info(NULL, jl_emptysvec, jl_emptysvec, jl_core_module); li->fptr = fptr; li->name = sname; // TODO jb/functions: what should li->ast be? - li->ast = (jl_value_t*)jl_exprn(lambda_sym,0); jl_gc_wb(li, li->ast); + li->code = (jl_array_t*)jl_an_empty_cell; jl_gc_wb(li, li->code); jl_method_cache_insert(jl_gf_mtable(f), jl_anytuple_type, li); return f; } diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 6e4affa00f061..071adbb3243fc 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -849,9 +849,12 @@ static inline jl_module_t *topmod(jl_codectx_t *ctx) static jl_value_t *expr_type(jl_value_t *e, jl_codectx_t *ctx) { if (jl_is_gensym(e)) { + if (jl_is_long(ctx->linfo->gensymtypes)) + return (jl_value_t*)jl_any_type; int idx = ((jl_gensym_t*)e)->id; - jl_value_t *gensym_types = jl_lam_gensyms(ctx->ast); - return (jl_is_array(gensym_types) ? jl_cellref(gensym_types, idx) : (jl_value_t*)jl_any_type); + assert(jl_is_array(ctx->linfo->gensymtypes)); + jl_array_t *gensym_types = (jl_array_t*)ctx->linfo->gensymtypes; + return jl_cellref(gensym_types, idx); } if (jl_typeis(e, jl_slot_type)) { jl_value_t *typ = jl_slot_get_type(e); diff --git a/src/codegen.cpp b/src/codegen.cpp index 416b3a9624d95..e9433b0867986 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -556,7 +556,6 @@ typedef struct { std::map<int, BasicBlock*> *labels; std::map<int, Value*> *handlers; jl_module_t *module; - jl_expr_t *ast; jl_lambda_info_t *linfo; Value *spvals_ptr; Value *argArray; @@ -742,7 +741,7 @@ static bool store_unboxed_p(int s, jl_codectx_t *ctx) static jl_sym_t *slot_symbol(int s, jl_codectx_t *ctx) { - return (jl_sym_t*)jl_cellref(jl_cellref(jl_lam_vinfo(ctx->ast), s), 0); + return (jl_sym_t*)jl_cellref(ctx->linfo->slotnames, s); } static Value *alloc_local(int s, jl_codectx_t *ctx) @@ -759,7 +758,8 @@ static Value *alloc_local(int s, jl_codectx_t *ctx) // CreateAlloca is OK here because alloc_local is only called during prologue setup Value *lv = builder.CreateAlloca(vtype, 0, jl_symbol_name(slot_symbol(s,ctx))); vi.value = mark_julia_slot(lv, jt); - vi.value.isimmutable &= vi.isSA; // slot is not immutable if there are multiple assignments + // slot is not immutable if there are multiple assignments + vi.value.isimmutable &= (vi.isSA && s >= ctx->linfo->nargs); assert(vi.value.isboxed == false); return lv; } @@ -3018,7 +3018,7 @@ static void emit_assignment(jl_value_t *l, jl_value_t *r, jl_codectx_t *ctx) } if (slot.isboxed && slot.isimmutable) { // see if inference had a better type for the gensym than the expression (after inlining getfield on a Tuple) - jl_value_t *gensym_types = jl_lam_gensyms(ctx->ast); + jl_value_t *gensym_types = (jl_value_t*)ctx->linfo->gensymtypes; if (jl_is_array(gensym_types)) { jl_value_t *declType = jl_cellref(gensym_types, idx); if (declType != slot.typ) { @@ -3860,7 +3860,7 @@ static Function *gen_cfun_wrapper(jl_lambda_info_t *lam, jl_function_t *ff, jl_v } // generate a julia-callable function that calls f (AKA lam) -static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, jl_expr_t *ast, Function *f, bool sret, Module *M) +static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, Function *f, bool sret, Module *M) { std::stringstream funcName; const std::string &fname = f->getName().str(); @@ -3893,7 +3893,7 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, jl_expr_t *ast, Funct ctx.spvals_ptr = NULL; allocate_gc_frame(b0, &ctx); - size_t nargs = jl_array_dim0(jl_lam_args(ast)); + size_t nargs = lam->nargs; size_t nfargs = f->getFunctionType()->getNumParams(); Value **args = (Value**) alloca(nfargs*sizeof(Value*)); unsigned idx = 0; @@ -3945,12 +3945,10 @@ static std::unique_ptr<Module> emit_function(jl_lambda_info_t *lam, jl_llvm_func assert(declarations && "Capturing declarations is always required"); // step 1. unpack AST and allocate codegen context for this function - jl_expr_t *ast = (jl_expr_t*)lam->ast; - JL_GC_PUSH1(&ast); - if (!jl_is_expr(ast)) { - ast = (jl_expr_t*)jl_uncompress_ast(lam, (jl_value_t*)ast); - } - assert(jl_is_expr(ast)); + jl_array_t *code = lam->code; + JL_GC_PUSH1(&code); + if (!jl_typeis(code,jl_array_any_type)) + code = jl_uncompress_ast(lam, code); //jl_static_show(JL_STDOUT, (jl_value_t*)ast); //jl_printf(JL_STDOUT, "\n"); std::map<int, jl_arrayvar_t> arrayvars; @@ -3961,7 +3959,6 @@ static std::unique_ptr<Module> emit_function(jl_lambda_info_t *lam, jl_llvm_func ctx.labels = &labels; ctx.handlers = &handlers; ctx.module = lam->module; - ctx.ast = ast; ctx.linfo = lam; ctx.funcName = jl_symbol_name(lam->name); ctx.vaSlot = -1; @@ -3971,12 +3968,9 @@ static std::unique_ptr<Module> emit_function(jl_lambda_info_t *lam, jl_llvm_func ctx.spvals_ptr = NULL; // step 2. process var-info lists to see what vars need boxing - jl_value_t *gensym_types = jl_lam_gensyms(ast); - int n_gensyms = (jl_is_array(gensym_types) ? jl_array_len(gensym_types) : jl_unbox_gensym(gensym_types)); - jl_array_t *largs = jl_lam_args(ast); - size_t largslen = jl_array_dim0(largs); - jl_array_t *vinfos = jl_lam_vinfo(ast); - size_t vinfoslen = jl_array_dim0(vinfos); + int n_gensyms = jl_is_long(lam->gensymtypes) ? jl_unbox_long(lam->gensymtypes) : jl_array_len(lam->gensymtypes); + size_t largslen = lam->nargs; + size_t vinfoslen = jl_array_dim0(lam->slotnames); ctx.slots.resize(vinfoslen); size_t nreq = largslen; int va = 0; @@ -3986,10 +3980,10 @@ static std::unique_ptr<Module> emit_function(jl_lambda_info_t *lam, jl_llvm_func // compiling this would cause all specializations to inherit // this code and could create an broken compile / function cache - if (nreq > 0 && jl_is_rest_arg(jl_cellref(largs,largslen-1))) { + if (nreq > 0 && lam->isva) { nreq--; va = 1; - jl_sym_t *vn = jl_decl_var(jl_cellref(largs,largslen-1)); + jl_sym_t *vn = (jl_sym_t*)jl_cellref(lam->slotnames,largslen-1); if (vn != unused_sym) ctx.vaSlot = largslen-1; } @@ -4002,8 +3996,7 @@ static std::unique_ptr<Module> emit_function(jl_lambda_info_t *lam, jl_llvm_func // step 3. some variable analysis size_t i; for(i=0; i < nreq; i++) { - jl_value_t *arg = jl_cellref(largs,i); - jl_sym_t *argname = jl_decl_var(arg); + jl_sym_t *argname = (jl_sym_t*)jl_cellref(lam->slotnames,i); if (argname == unused_sym) continue; jl_varinfo_t &varinfo = ctx.slots[i]; varinfo.isArgument = true; @@ -4017,28 +4010,28 @@ static std::unique_ptr<Module> emit_function(jl_lambda_info_t *lam, jl_llvm_func } for(i=0; i < vinfoslen; i++) { - jl_array_t *vi = (jl_array_t*)jl_cellref(vinfos, i); - assert(jl_is_array(vi)); - jl_sym_t *vname = ((jl_sym_t*)jl_cellref(vi,0)); - assert(jl_is_symbol(vname)); jl_varinfo_t &varinfo = ctx.slots[i]; - varinfo.isAssigned = (jl_vinfo_assigned(vi)!=0); + uint8_t flags = jl_array_uint8_ref(lam->slotflags, i); + varinfo.isAssigned = (jl_vinfo_assigned(flags)!=0); varinfo.escapes = false; - varinfo.isSA = (jl_vinfo_sa(vi)!=0); - varinfo.usedUndef = (jl_vinfo_usedundef(vi)!=0) || (!varinfo.isArgument && !lam->inferred); + varinfo.isSA = (jl_vinfo_sa(flags)!=0); + varinfo.usedUndef = (jl_vinfo_usedundef(flags)!=0) || (!varinfo.isArgument && !lam->inferred); if (!varinfo.isArgument || varinfo.isAssigned) { - jl_value_t *typ = jl_cellref(vi,1); + jl_value_t *typ = jl_is_array(lam->slottypes) ? jl_cellref(lam->slottypes,i) : (jl_value_t*)jl_any_type; if (!jl_is_type(typ)) typ = (jl_value_t*)jl_any_type; varinfo.value = mark_julia_type((Value*)NULL, false, typ, &ctx); } } + jl_array_t *stmts = code; + size_t stmtslen = jl_array_dim0(stmts); + // finish recording escape info - simple_escape_analysis((jl_value_t*)ast, true, &ctx); + for(i=0; i < stmtslen; i++) + simple_escape_analysis(jl_cellref(stmts,i), true, &ctx); // determine which vars need to be volatile - jl_array_t *stmts = jl_lam_body(ast)->args; mark_volatile_vars(stmts, ctx.slots); // step 4. determine function signature @@ -4106,7 +4099,7 @@ static std::unique_ptr<Module> emit_function(jl_lambda_info_t *lam, jl_llvm_func #ifdef LLVM37 f->addFnAttr("no-frame-pointer-elim", "true"); #endif - fwrap = gen_jlcall_wrapper(lam, ast, f, ctx.sret, M); + fwrap = gen_jlcall_wrapper(lam, f, ctx.sret, M); declarations->functionObject = function_proto(fwrap); declarations->specFunctionObject = function_proto(f); } @@ -4283,7 +4276,7 @@ static std::unique_ptr<Module> emit_function(jl_lambda_info_t *lam, jl_llvm_func const bool AlwaysPreserve = true; // Go over all arguments and local variables and initialize their debug information for(i=0; i < nreq; i++) { - jl_sym_t *argname = jl_decl_var(jl_cellref(largs,i)); + jl_sym_t *argname = (jl_sym_t*)jl_cellref(lam->slotnames,i); if (argname == unused_sym) continue; jl_varinfo_t &varinfo = ctx.slots[i]; #ifdef LLVM38 @@ -4335,7 +4328,7 @@ static std::unique_ptr<Module> emit_function(jl_lambda_info_t *lam, jl_llvm_func #endif } for(i=0; i < vinfoslen; i++) { - jl_sym_t *s = (jl_sym_t*)jl_cellref(jl_cellref(vinfos,i),0); + jl_sym_t *s = (jl_sym_t*)jl_cellref(lam->slotnames,i); jl_varinfo_t &varinfo = ctx.slots[i]; if (varinfo.isArgument) continue; @@ -4397,7 +4390,6 @@ static std::unique_ptr<Module> emit_function(jl_lambda_info_t *lam, jl_llvm_func allocate_gc_frame(b0, &ctx); // step 8. allocate space for exception handler contexts - size_t stmtslen = jl_array_dim0(stmts); for(i=0; i < stmtslen; i++) { jl_value_t *stmt = jl_cellref(stmts,i); if (jl_is_expr(stmt) && ((jl_expr_t*)stmt)->head == enter_sym) { @@ -4416,7 +4408,7 @@ static std::unique_ptr<Module> emit_function(jl_lambda_info_t *lam, jl_llvm_func // get pointers for locals stored in the gc frame array (argTemp) for(i=0; i < vinfoslen; i++) { - jl_sym_t *s = (jl_sym_t*)jl_cellref(jl_cellref(vinfos,i),0); + jl_sym_t *s = slot_symbol(i, &ctx); if (s == unused_sym) continue; jl_varinfo_t &varinfo = ctx.slots[i]; assert(!varinfo.memloc); // variables shouldn't also have memory locs already @@ -4450,7 +4442,7 @@ static std::unique_ptr<Module> emit_function(jl_lambda_info_t *lam, jl_llvm_func if (varinfo.isAssigned || // always need a slot if the variable is assigned specsig || // for arguments, give them stack slots if then aren't in `argArray` (otherwise, will use that pointer) (va && (int)i == ctx.vaSlot && varinfo.escapes) || // or it's the va arg tuple - (s != unused_sym && s == jl_decl_var(jl_cellref(largs, 0)))) { // or it is the first argument (which isn't in `argArray`) + (s != unused_sym && i == 0)) { // or it is the first argument (which isn't in `argArray`) AllocaInst *av = new AllocaInst(T_pjlvalue, jl_symbol_name(s), /*InsertBefore*/ctx.ptlsStates); varinfo.memloc = av; #ifdef LLVM36 @@ -4480,7 +4472,7 @@ static std::unique_ptr<Module> emit_function(jl_lambda_info_t *lam, jl_llvm_func if (ctx.sret) AI++; // skip sret slot for(i=0; i < nreq; i++) { - jl_sym_t *s = jl_decl_var(jl_cellref(largs,i)); + jl_sym_t *s = (jl_sym_t*)jl_cellref(lam->slotnames,i); jl_value_t *argType = jl_nth_slot_type(lam->specTypes, i); bool isboxed; Type *llvmArgType = julia_type_to_llvm(argType, &isboxed); diff --git a/src/dump.c b/src/dump.c index 54447cd374fcb..8a5d4ae0fe46f 100644 --- a/src/dump.c +++ b/src/dump.c @@ -515,6 +515,8 @@ static void jl_serialize_datatype(ios_t *s, jl_datatype_t *dt) tag = 3; else if (dt == jl_int64_type) tag = 4; + else if (dt == jl_uint8_type) + tag = 8; writetag(s, (jl_value_t*)SmallDataType_tag); write_uint8(s, 0); // virtual size jl_serialize_value(s, (jl_value_t*)jl_datatype_type); @@ -608,14 +610,6 @@ static void jl_serialize_module(ios_t *s, jl_module_t *m) static int is_ast_node(jl_value_t *v) { - if (jl_is_lambda_info(v)) { - jl_lambda_info_t *li = (jl_lambda_info_t*)v; - if (jl_is_expr(li->ast)) { - li->ast = jl_compress_ast(li, li->ast); - jl_gc_wb(li, li->ast); - } - return 0; - } return jl_is_symbol(v) || jl_is_slot(v) || jl_is_gensym(v) || jl_is_expr(v) || jl_is_newvarnode(v) || jl_is_svec(v) || jl_typeis(v, jl_array_any_type) || jl_is_tuple(v) || @@ -791,7 +785,11 @@ static void jl_serialize_value_(ios_t *s, jl_value_t *v) else if (jl_is_lambda_info(v)) { writetag(s, jl_lambda_info_type); jl_lambda_info_t *li = (jl_lambda_info_t*)v; - jl_serialize_value(s, li->ast); + jl_serialize_value(s, li->code); + jl_serialize_value(s, li->slotnames); + jl_serialize_value(s, li->slottypes); + jl_serialize_value(s, li->slotflags); + jl_serialize_value(s, li->gensymtypes); jl_serialize_value(s, li->rettype); jl_serialize_value(s, (jl_value_t*)li->sparam_syms); jl_serialize_value(s, (jl_value_t*)li->sparam_vals); @@ -810,10 +808,10 @@ static void jl_serialize_value_(ios_t *s, jl_value_t *v) for(i=0; i < l; i += 3) { if (!jl_is_leaf_type(jl_cellref(tf,i))) { jl_value_t *ret = jl_cellref(tf,i+1); - if (jl_is_tuple(ret)) { - jl_value_t *ast = jl_fieldref(ret, 0); - if (jl_is_array(ast) && jl_array_len(ast) > 500) - jl_cellset(tf, i+1, jl_fieldref(ret,1)); + if (jl_is_lambda_info(ret)) { + jl_array_t *code = ((jl_lambda_info_t*)ret)->code; + if (jl_is_array(code) && jl_array_len(code) > 500) + jl_cellset(tf, i+1, ((jl_lambda_info_t*)ret)->rettype); } } } @@ -826,10 +824,10 @@ static void jl_serialize_value_(ios_t *s, jl_value_t *v) write_int8(s, li->inferred); write_int8(s, li->pure); write_int8(s, li->called); + write_int8(s, li->isva); jl_serialize_value(s, (jl_value_t*)li->file); write_int32(s, li->line); - write_int32(s, li->nslots); - write_int32(s, li->ngensym); + write_int32(s, li->nargs); jl_serialize_value(s, (jl_value_t*)li->module); jl_serialize_value(s, (jl_value_t*)li->roots); jl_serialize_value(s, (jl_value_t*)li->def); @@ -1186,6 +1184,8 @@ static jl_value_t *jl_deserialize_datatype(ios_t *s, int pos, jl_value_t **loc) dt = jl_bool_type; else if (tag == 4) dt = jl_int64_type; + else if (tag == 8) + dt = jl_uint8_type; else dt = jl_new_uninitialized_datatype(nf, fielddesc_type); assert(tree_literal_values==NULL && mode != MODE_AST); @@ -1422,8 +1422,11 @@ static jl_value_t *jl_deserialize_value_(ios_t *s, jl_value_t *vtag, jl_value_t NWORDS(sizeof(jl_lambda_info_t))); if (usetable) arraylist_push(&backref_list, li); - li->ast = jl_deserialize_value(s, &li->ast); - jl_gc_wb(li, li->ast); + li->code = (jl_array_t*)jl_deserialize_value(s, (jl_value_t**)&li->code); jl_gc_wb(li, li->code); + li->slotnames = (jl_array_t*)jl_deserialize_value(s, (jl_value_t**)&li->slotnames); jl_gc_wb(li, li->slotnames); + li->slottypes = jl_deserialize_value(s, &li->slottypes); jl_gc_wb(li, li->slottypes); + li->slotflags = (jl_array_t*)jl_deserialize_value(s, (jl_value_t**)&li->slotflags); jl_gc_wb(li, li->slotflags); + li->gensymtypes = jl_deserialize_value(s, &li->gensymtypes); jl_gc_wb(li, li->gensymtypes); li->rettype = jl_deserialize_value(s, &li->rettype); jl_gc_wb(li, li->rettype); li->sparam_syms = (jl_svec_t*)jl_deserialize_value(s, (jl_value_t**)&li->sparam_syms); @@ -1441,11 +1444,11 @@ static jl_value_t *jl_deserialize_value_(ios_t *s, jl_value_t *vtag, jl_value_t li->inferred = read_int8(s); li->pure = read_int8(s); li->called = read_int8(s); + li->isva = read_int8(s); li->file = (jl_sym_t*)jl_deserialize_value(s, NULL); jl_gc_wb(li, li->file); li->line = read_int32(s); - li->nslots = read_int32(s); - li->ngensym = read_int32(s); + li->nargs = read_int32(s); li->module = (jl_module_t*)jl_deserialize_value(s, (jl_value_t**)&li->module); jl_gc_wb(li, li->module); li->roots = (jl_array_t*)jl_deserialize_value(s, (jl_value_t**)&li->roots); @@ -2032,7 +2035,7 @@ JL_DLLEXPORT void jl_restore_system_image_data(const char *buf, size_t len) JL_SIGATOMIC_END(); } -JL_DLLEXPORT jl_value_t *jl_compress_ast(jl_lambda_info_t *li, jl_value_t *ast) +JL_DLLEXPORT jl_array_t *jl_compress_ast(jl_lambda_info_t *li, jl_array_t *ast) { JL_SIGATOMIC_BEGIN(); JL_LOCK(dump); // Might GC @@ -2054,7 +2057,7 @@ JL_DLLEXPORT jl_value_t *jl_compress_ast(jl_lambda_info_t *li, jl_value_t *ast) //jl_printf(JL_STDERR, "%d bytes, %d values\n", dest.size, vals->length); - jl_value_t *v = (jl_value_t*)jl_takebuf_array(&dest); + jl_array_t *v = jl_takebuf_array(&dest); if (jl_array_len(tree_literal_values) == 0 && last_tlv == NULL) { li->def->roots = NULL; } @@ -2067,7 +2070,7 @@ JL_DLLEXPORT jl_value_t *jl_compress_ast(jl_lambda_info_t *li, jl_value_t *ast) return v; } -JL_DLLEXPORT jl_value_t *jl_uncompress_ast(jl_lambda_info_t *li, jl_value_t *data) +JL_DLLEXPORT jl_array_t *jl_uncompress_ast(jl_lambda_info_t *li, jl_array_t *data) { JL_SIGATOMIC_BEGIN(); JL_LOCK(dump); // Might GC @@ -2082,7 +2085,7 @@ JL_DLLEXPORT jl_value_t *jl_uncompress_ast(jl_lambda_info_t *li, jl_value_t *dat ios_setbuf(&src, (char*)bytes->data, jl_array_len(bytes), 0); src.size = jl_array_len(bytes); int en = jl_gc_enable(0); // Might GC - jl_value_t *v = jl_deserialize_value(&src, NULL); + jl_array_t *v = (jl_array_t*)jl_deserialize_value(&src, NULL); jl_gc_enable(en); tree_literal_values = NULL; tree_enclosing_module = NULL; @@ -2400,7 +2403,7 @@ void jl_init_serializer(void) jl_box_int32(39), jl_box_int32(40), jl_box_int32(41), jl_box_int32(42), jl_box_int32(43), jl_box_int32(44), jl_box_int32(45), jl_box_int32(46), jl_box_int32(47), - jl_box_int32(48), jl_box_int32(49), jl_box_int32(50), + jl_box_int32(48), jl_box_int32(49), #endif jl_box_int64(0), jl_box_int64(1), jl_box_int64(2), jl_box_int64(3), jl_box_int64(4), jl_box_int64(5), @@ -2419,7 +2422,7 @@ void jl_init_serializer(void) jl_box_int64(39), jl_box_int64(40), jl_box_int64(41), jl_box_int64(42), jl_box_int64(43), jl_box_int64(44), jl_box_int64(45), jl_box_int64(46), jl_box_int64(47), - jl_box_int64(48), jl_box_int64(49), jl_box_int64(50), + jl_box_int64(48), jl_box_int64(49), #endif jl_labelnode_type, jl_linenumbernode_type, jl_gotonode_type, jl_quotenode_type, jl_topnode_type, @@ -2431,7 +2434,7 @@ void jl_init_serializer(void) jl_ANY_flag, jl_array_any_type, jl_intrinsic_type, jl_method_type, jl_methtable_type, jl_voidpointer_type, jl_newvarnode_type, jl_array_symbol_type, jl_anytuple_type, jl_tparam0(jl_anytuple_type), - jl_typeof(jl_emptytuple), + jl_typeof(jl_emptytuple), jl_array_uint8_type, jl_symbol_type->name, jl_gensym_type->name, jl_tuple_typename, jl_ref_type->name, jl_pointer_type->name, jl_simplevector_type->name, jl_datatype_type->name, jl_uniontype_type->name, jl_array_type->name, diff --git a/src/gf.c b/src/gf.c index 880c807f26d63..ad29e0ed625ad 100644 --- a/src/gf.c +++ b/src/gf.c @@ -293,7 +293,7 @@ static jl_lambda_info_t *jl_add_static_parameters(jl_lambda_info_t *l, jl_svec_t for example, if an unspecialized method is needed, the slow compiled code should be associated with method->unspecialized, not method */ - assert(!nli->ast || + assert(!nli->code || (nli->fptr == NULL && nli->jlcall_api == 0 && nli->functionObjects.functionObject == NULL && @@ -330,11 +330,18 @@ jl_lambda_info_t *jl_get_unspecialized(jl_lambda_info_t *method) return method->unspecialized; if (method->specTypes && def->sparam_syms != jl_emptysvec) { if (def->needs_sparam_vals_ducttape == 2) { - jl_value_t *code = method->ast; + jl_array_t *code = method->code; JL_GC_PUSH1(&code); - if (!jl_is_expr(code)) + if (!jl_typeis(code, jl_array_any_type)) code = jl_uncompress_ast(def, code); - def->needs_sparam_vals_ducttape = jl_has_intrinsics(method, (jl_expr_t*)code, method->module); + size_t i, l = jl_array_len(code); + def->needs_sparam_vals_ducttape = 0; + for(i=0; i < l; i++) { + if (jl_has_intrinsics(method, jl_cellref(code,i), method->module)) { + def->needs_sparam_vals_ducttape = 1; + break; + } + } JL_GC_POP(); } if (method->needs_sparam_vals_ducttape) { @@ -815,7 +822,7 @@ static jl_lambda_info_t *cache_method(jl_methtable_t *mt, jl_tupletype_t *type, else (void)jl_method_cache_insert(mt, type, newmeth); - if (newmeth->ast != NULL) { + if (newmeth->code != NULL) { jl_array_t *spe = method->specializations; if (spe == NULL) { spe = jl_alloc_cell_1d(1); @@ -895,11 +902,12 @@ JL_DLLEXPORT jl_lambda_info_t *jl_instantiate_staged(jl_lambda_info_t *generator ex = jl_exprn(lambda_sym, 2); - jl_expr_t *generatorast = (jl_expr_t*)generator->ast; - if (!jl_is_expr(generatorast)) - generatorast = (jl_expr_t*)jl_uncompress_ast(generator, (jl_value_t*)generatorast); - jl_array_t *argnames = jl_lam_args(generatorast); + int nargs = generator->nargs; + jl_array_t *argnames = jl_alloc_cell_1d(nargs); jl_cellset(ex->args, 0, argnames); + size_t i; + for(i=0; i < nargs; i++) + jl_cellset(argnames, i, jl_cellref(generator->slotnames,i)); jl_expr_t *scopeblock = jl_exprn(jl_symbol("scope-block"), 1); jl_cellset(ex->args, 1, scopeblock); @@ -913,8 +921,7 @@ JL_DLLEXPORT jl_lambda_info_t *jl_instantiate_staged(jl_lambda_info_t *generator // invoke code generator assert(jl_nparams(tt) == jl_array_len(argnames) || - (jl_is_rest_arg(jl_cellref(argnames, jl_array_len(argnames)-1)) && - (jl_nparams(tt) >= jl_array_len(argnames) - 1))); + (generator->isva && (jl_nparams(tt) >= jl_array_len(argnames) - 1))); jl_cellset(body->args, 1, jl_call_unspecialized(sparam_vals, generator, jl_svec_data(tt->parameters), jl_nparams(tt))); if (generator->sparam_syms != jl_emptysvec) { @@ -930,6 +937,8 @@ JL_DLLEXPORT jl_lambda_info_t *jl_instantiate_staged(jl_lambda_info_t *generator // need to eval macros in the right module, but not give a warning for the `eval` call unless that results in a call to `eval` jl_lambda_info_t *func = (jl_lambda_info_t*)jl_toplevel_eval_in_warn(generator->module, (jl_value_t*)ex, 1); func->name = generator->name; + if (generator->isva) + func->isva = 1; JL_GC_POP(); return func; } @@ -1446,7 +1455,7 @@ jl_lambda_info_t *jl_get_specialization1(jl_tupletype_t *types) } JL_CATCH { goto not_found; } - if (sf == NULL || sf->ast == NULL || sf->inInference) + if (sf == NULL || sf->code == NULL || sf->inInference) goto not_found; if (sf->functionObjects.functionObject == NULL) { if (sf->fptr != NULL) diff --git a/src/init.c b/src/init.c index 90166c4e4ed7a..aa92a14cb4fa5 100644 --- a/src/init.c +++ b/src/init.c @@ -808,7 +808,6 @@ void jl_get_builtin_hooks(void) jl_char_type = (jl_datatype_t*)core("Char"); jl_int8_type = (jl_datatype_t*)core("Int8"); - jl_uint8_type = (jl_datatype_t*)core("UInt8"); jl_int16_type = (jl_datatype_t*)core("Int16"); jl_uint16_type = (jl_datatype_t*)core("UInt16"); jl_uint32_type = (jl_datatype_t*)core("UInt32"); @@ -841,9 +840,6 @@ void jl_get_builtin_hooks(void) jl_ascii_string_type = (jl_datatype_t*)core("ASCIIString"); jl_utf8_string_type = (jl_datatype_t*)core("UTF8String"); jl_weakref_type = (jl_datatype_t*)core("WeakRef"); - - jl_array_uint8_type = jl_apply_type((jl_value_t*)jl_array_type, - jl_svec2(jl_uint8_type, jl_box_long(1))); } JL_DLLEXPORT void jl_get_system_hooks(void) diff --git a/src/interpreter.c b/src/interpreter.c index 246529dad632c..1e7ccd285fcd0 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -112,7 +112,17 @@ void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) jl_gc_wb(tt, tt->super); } - static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, jl_lambda_info_t *lam) +static int jl_linfo_nslots(jl_lambda_info_t *li) +{ + return jl_array_len(li->slotflags); +} + +static int jl_linfo_ngensyms(jl_lambda_info_t *li) +{ + return jl_is_long(li->gensymtypes) ? jl_unbox_long(li->gensymtypes) : jl_array_len(li->gensymtypes); +} + +static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, jl_lambda_info_t *lam) { if (jl_is_symbol(e)) { jl_value_t *v = jl_get_global(jl_current_module, (jl_sym_t*)e); @@ -122,10 +132,10 @@ void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) } if (jl_is_gensym(e)) { ssize_t genid = ((jl_gensym_t*)e)->id; - if (genid >= lam->ngensym || genid < 0) + if (genid >= jl_linfo_ngensyms(lam) || genid < 0) jl_error("access to invalid GenSym location"); else - return locals[lam->nslots + genid]; + return locals[jl_linfo_nslots(lam) + genid]; } if (jl_is_quotenode(e)) { return jl_fieldref(e,0); @@ -140,11 +150,11 @@ void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) if (!jl_is_expr(e)) { if (jl_typeis(e, jl_slot_type)) { ssize_t n = jl_slot_number(e); - if (n > lam->nslots || n < 1) + if (n > jl_linfo_nslots(lam) || n < 1) jl_error("access to invalid slot number"); jl_value_t *v = locals[n-1]; - if (v == NULL) // TODO get var name from `lam` - jl_undefined_var_error(anonymous_sym); + if (v == NULL) + jl_undefined_var_error((jl_sym_t*)jl_cellref(lam->slotnames,n-1)); return v; } if (jl_is_globalref(e)) { @@ -158,7 +168,7 @@ void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) jl_value_t *var = jl_fieldref(e,0); assert(jl_typeis(var,jl_slot_type)); ssize_t n = jl_slot_number(var); - assert(n <= lam->nslots && n > 0); + assert(n <= jl_linfo_nslots(lam) && n > 0); locals[n-1] = NULL; return (jl_value_t*)jl_nothing; } @@ -175,13 +185,13 @@ void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) jl_value_t *rhs = eval(args[1], locals, lam); if (jl_is_gensym(sym)) { ssize_t genid = ((jl_gensym_t*)sym)->id; - if (genid >= lam->ngensym || genid < 0) + if (genid >= jl_linfo_ngensyms(lam) || genid < 0) jl_error("assignment to invalid GenSym location"); - locals[lam->nslots + genid] = rhs; + locals[jl_linfo_nslots(lam) + genid] = rhs; } else if (jl_typeis(sym,jl_slot_type)) { ssize_t n = jl_slot_number(sym); - assert(n <= lam->nslots && n > 0); + assert(n <= jl_linfo_nslots(lam) && n > 0); locals[n-1] = rhs; } else { @@ -520,10 +530,9 @@ static jl_value_t *eval_body(jl_array_t *stmts, jl_value_t **locals, jl_lambda_i jl_value_t *jl_interpret_toplevel_thunk(jl_lambda_info_t *lam) { - jl_expr_t *ast = (jl_expr_t*)lam->ast; - jl_array_t *stmts = jl_lam_body(ast)->args; + jl_array_t *stmts = lam->code; jl_value_t **locals; - JL_GC_PUSHARGS(locals, lam->nslots + lam->ngensym); + JL_GC_PUSHARGS(locals, jl_linfo_nslots(lam) + jl_linfo_ngensyms(lam)); jl_value_t *r = eval_body(stmts, locals, lam, 0, 1); JL_GC_POP(); return r; diff --git a/src/jltypes.c b/src/jltypes.c index 1bc170ca3ee8b..d974caab9aadd 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3370,6 +3370,10 @@ void jl_init_types(void) jl_int64_type = jl_new_bitstype((jl_value_t*)jl_symbol("Int64"), jl_any_type, jl_emptysvec, 64); + jl_uint8_type = NULL; + jl_uint8_type = jl_new_bitstype((jl_value_t*)jl_symbol("UInt8"), + jl_any_type, jl_emptysvec, 8); + jl_gensym_type = jl_new_datatype(jl_symbol("GenSym"), jl_any_type, jl_emptysvec, jl_svec1(jl_symbol("id")), jl_svec1(jl_long_type), 0, 0, 1); @@ -3431,6 +3435,9 @@ void jl_init_types(void) jl_svec(2, jl_symbol_type, jl_box_long(1))); + jl_array_uint8_type = jl_apply_type((jl_value_t*)jl_array_type, + jl_svec2(jl_uint8_type, jl_box_long(1))); + jl_expr_type = jl_new_datatype(jl_symbol("Expr"), jl_any_type, jl_emptysvec, @@ -3486,7 +3493,9 @@ void jl_init_types(void) jl_lambda_info_type = jl_new_datatype(jl_symbol("LambdaInfo"), jl_any_type, jl_emptysvec, - jl_svec(19, jl_symbol("ast"), jl_symbol("rettype"), + jl_svec(23, jl_symbol("code"), jl_symbol("slotnames"), + jl_symbol("slottypes"), jl_symbol("slotflags"), + jl_symbol("gensymtypes"), jl_symbol("rettype"), jl_symbol("sparam_syms"), jl_symbol("sparam_vals"), jl_symbol("tfunc"), jl_symbol("name"), jl_symbol("roots"), @@ -3495,20 +3504,21 @@ void jl_init_types(void) jl_symbol("specializations"), jl_symbol("module"), jl_symbol("def"), jl_symbol("file"), jl_symbol("line"), - jl_symbol("nslots"), jl_symbol("ngensym"), - jl_symbol("inferred"), - jl_symbol("pure"), + jl_symbol("nargs"), jl_symbol("inferred"), + jl_symbol("pure"), jl_symbol("isva"), jl_symbol("inInference")), - jl_svec(19, jl_any_type, jl_any_type, + jl_svec(23, jl_any_type, jl_array_any_type, + jl_any_type, jl_array_uint8_type, + jl_any_type, jl_any_type, jl_simplevector_type, jl_simplevector_type, jl_any_type, jl_sym_type, jl_any_type, jl_any_type, jl_any_type, jl_array_any_type, jl_module_type, jl_any_type, jl_sym_type, jl_int32_type, - jl_int32_type, jl_int32_type, + jl_int32_type, jl_bool_type, jl_bool_type, jl_bool_type, jl_bool_type), - 0, 1, 5); + 0, 1, 10); jl_typector_type = jl_new_datatype(jl_symbol("TypeConstructor"), @@ -3628,6 +3638,7 @@ void jl_init_types(void) unused_sym = jl_symbol("#unused#"); slot_sym = jl_symbol("slot"); static_parameter_sym = jl_symbol("static_parameter"); + compiler_temp_sym = jl_symbol("#temp#"); } #ifdef __cplusplus diff --git a/src/julia.h b/src/julia.h index 49e30d140123c..a590d5b0677d7 100644 --- a/src/julia.h +++ b/src/julia.h @@ -175,7 +175,11 @@ typedef struct _jl_lambda_info_t { // a function pointer. // this is the stuff that's shared among different instantiations // (different environments) of a closure. - jl_value_t *ast; + jl_array_t *code; // compressed uint8 array, or Any array of statements + jl_array_t *slotnames; // names of local variables + jl_value_t *slottypes; + jl_array_t *slotflags; // local var bit flags + jl_value_t *gensymtypes; jl_value_t *rettype; // sparams is a vector of values indexed by symbols jl_svec_t *sparam_syms; @@ -192,14 +196,14 @@ typedef struct _jl_lambda_info_t { struct _jl_lambda_info_t *def; // original this is specialized from jl_sym_t *file; int32_t line; - int32_t nslots; - int32_t ngensym; + int32_t nargs; int8_t inferred; int8_t pure; + int8_t isva; int8_t inInference; // flags to tell if inference is running on this function - uint8_t called; // bit flags: whether each of the first 8 arguments is called // hidden fields: + uint8_t called; // bit flags: whether each of the first 8 arguments is called uint8_t jlcall_api : 1; // the c-abi for fptr; 0 = jl_fptr_t, 1 = jl_fptr_sparam_t uint8_t inCompile : 1; // if there are intrinsic calls, sparams are probably required to compile successfully, @@ -487,7 +491,7 @@ extern jl_sym_t *null_sym; extern jl_sym_t *body_sym; extern jl_sym_t *method_sym; extern jl_sym_t *slot_sym; extern jl_sym_t *enter_sym; extern jl_sym_t *leave_sym; extern jl_sym_t *exc_sym; extern jl_sym_t *new_sym; -extern jl_sym_t *static_typeof_sym; +extern jl_sym_t *static_typeof_sym; extern jl_sym_t *compiler_temp_sym; extern jl_sym_t *const_sym; extern jl_sym_t *thunk_sym; extern jl_sym_t *anonymous_sym; extern jl_sym_t *underscore_sym; extern jl_sym_t *abstracttype_sym; extern jl_sym_t *bitstype_sym; @@ -644,6 +648,19 @@ STATIC_INLINE jl_value_t *jl_cellset(void *a, size_t i, void *x) return (jl_value_t*)x; } +STATIC_INLINE uint8_t jl_array_uint8_ref(void *a, size_t i) +{ + assert(i < jl_array_len(a)); + assert(jl_typeis(a, jl_array_uint8_type)); + return ((uint8_t*)(jl_array_data(a)))[i]; +} +STATIC_INLINE void jl_array_uint8_set(void *a, size_t i, uint8_t x) +{ + assert(i < jl_array_len(a)); + assert(jl_typeis(a, jl_array_uint8_type)); + ((uint8_t*)(jl_array_data(a)))[i] = x; +} + #define jl_exprarg(e,n) (((jl_value_t**)jl_array_data(((jl_expr_t*)(e))->args))[n]) #define jl_exprargset(e, n, v) jl_cellset(((jl_expr_t*)(e))->args, n, v) #define jl_expr_nargs(e) jl_array_len(((jl_expr_t*)(e))->args) @@ -1228,28 +1245,27 @@ JL_DLLEXPORT jl_module_t *jl_base_relative_to(jl_module_t *m); // AST access JL_DLLEXPORT int jl_is_rest_arg(jl_value_t *ex); -JL_DLLEXPORT jl_value_t *jl_prepare_ast(jl_lambda_info_t *li); JL_DLLEXPORT jl_value_t *jl_copy_ast(jl_value_t *expr); -JL_DLLEXPORT jl_value_t *jl_compress_ast(jl_lambda_info_t *li, jl_value_t *ast); -JL_DLLEXPORT jl_value_t *jl_uncompress_ast(jl_lambda_info_t *li, jl_value_t *data); +JL_DLLEXPORT jl_array_t *jl_compress_ast(jl_lambda_info_t *li, jl_array_t *ast); +JL_DLLEXPORT jl_array_t *jl_uncompress_ast(jl_lambda_info_t *li, jl_array_t *data); JL_DLLEXPORT int jl_is_operator(char *sym); JL_DLLEXPORT int jl_operator_precedence(char *sym); -STATIC_INLINE int jl_vinfo_assigned(jl_array_t *vi) +STATIC_INLINE int jl_vinfo_assigned(uint8_t vi) { - return (jl_unbox_long(jl_cellref(vi,2))&2)!=0; + return (vi&2)!=0; } -STATIC_INLINE int jl_vinfo_sa(jl_array_t *vi) +STATIC_INLINE int jl_vinfo_sa(uint8_t vi) { - return (jl_unbox_long(jl_cellref(vi,2))&16)!=0; + return (vi&16)!=0; } -STATIC_INLINE int jl_vinfo_usedundef(jl_array_t *vi) +STATIC_INLINE int jl_vinfo_usedundef(uint8_t vi) { - return (jl_unbox_long(jl_cellref(vi,2))&32)!=0; + return (vi&32)!=0; } // calling into julia --------------------------------------------------------- diff --git a/src/julia_internal.h b/src/julia_internal.h index f9a3dda8a04a9..6ea7ae0f0a581 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -194,19 +194,17 @@ jl_lambda_info_t *jl_method_lookup_by_type(jl_methtable_t *mt, jl_tupletype_t *t int cache, int inexact); jl_lambda_info_t *jl_method_lookup(jl_methtable_t *mt, jl_value_t **args, size_t nargs, int cache); jl_value_t *jl_gf_invoke(jl_tupletype_t *types, jl_value_t **args, size_t nargs); -jl_sym_t *jl_decl_var(jl_value_t *ex); jl_array_t *jl_lam_args(jl_expr_t *l); jl_array_t *jl_lam_vinfo(jl_expr_t *l); jl_array_t *jl_lam_capt(jl_expr_t *l); jl_value_t *jl_lam_gensyms(jl_expr_t *l); jl_array_t *jl_lam_staticparams(jl_expr_t *l); -jl_sym_t *jl_lam_argname(jl_lambda_info_t *li, int i); int jl_lam_vars_captured(jl_expr_t *ast); jl_expr_t *jl_lam_body(jl_expr_t *l); jl_value_t *jl_first_argument_datatype(jl_value_t *argtypes); jl_value_t *jl_preresolve_globals(jl_value_t *expr, jl_lambda_info_t *lam); -int jl_has_intrinsics(jl_lambda_info_t *li, jl_expr_t *e, jl_module_t *m); +int jl_has_intrinsics(jl_lambda_info_t *li, jl_value_t *v, jl_module_t *m); jl_value_t *jl_nth_slot_type(jl_tupletype_t *sig, size_t i); void jl_compute_field_offsets(jl_datatype_t *st); diff --git a/src/toplevel.c b/src/toplevel.c index 44a010370fc5b..9f66e6adeacd6 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -240,8 +240,10 @@ JL_DLLEXPORT jl_module_t *jl_base_relative_to(jl_module_t *m) return jl_top_module; } -int jl_has_intrinsics(jl_lambda_info_t *li, jl_expr_t *e, jl_module_t *m) +int jl_has_intrinsics(jl_lambda_info_t *li, jl_value_t *v, jl_module_t *m) { + if (!jl_is_expr(v)) return 0; + jl_expr_t *e = (jl_expr_t*)v; if (jl_array_len(e->args) == 0) return 0; if (e->head == static_typeof_sym) @@ -261,7 +263,7 @@ int jl_has_intrinsics(jl_lambda_info_t *li, jl_expr_t *e, jl_module_t *m) int i; for (i=0; i < jl_array_len(e->args); i++) { jl_value_t *a = jl_exprarg(e,i); - if (jl_is_expr(a) && jl_has_intrinsics(li, (jl_expr_t*)a, m)) + if (jl_is_expr(a) && jl_has_intrinsics(li, a, m)) return 1; } return 0; @@ -269,51 +271,49 @@ int jl_has_intrinsics(jl_lambda_info_t *li, jl_expr_t *e, jl_module_t *m) // heuristic for whether a top-level input should be evaluated with // the compiler or the interpreter. -static int jl_eval_with_compiler_p(jl_lambda_info_t *li, jl_expr_t *expr, int compileloops, jl_module_t *m) +static int jl_eval_with_compiler_p(jl_lambda_info_t *li, jl_array_t *body, int compileloops, jl_module_t *m) { - assert(jl_is_expr(expr)); - if (expr->head==body_sym && compileloops) { - jl_array_t *body = expr->args; - size_t i, maxlabl=0; - // compile if there are backwards branches - for(i=0; i < jl_array_len(body); i++) { - jl_value_t *stmt = jl_cellref(body,i); - if (jl_is_labelnode(stmt)) { - int l = jl_labelnode_label(stmt); - if (l > maxlabl) maxlabl = l; - } + size_t i, maxlabl=0; + // compile if there are backwards branches + for(i=0; i < jl_array_len(body); i++) { + jl_value_t *stmt = jl_cellref(body,i); + if (jl_is_labelnode(stmt)) { + int l = jl_labelnode_label(stmt); + if (l > maxlabl) maxlabl = l; + } + } + size_t sz = (maxlabl+1+7)/8; + char *labls = (char*)alloca(sz); memset(labls,0,sz); + for(i=0; i < jl_array_len(body); i++) { + jl_value_t *stmt = jl_cellref(body,i); + if (jl_is_labelnode(stmt)) { + int l = jl_labelnode_label(stmt); + labls[l/8] |= (1<<(l&7)); } - size_t sz = (maxlabl+1+7)/8; - char *labls = (char*)alloca(sz); memset(labls,0,sz); - for(i=0; i < jl_array_len(body); i++) { - jl_value_t *stmt = jl_cellref(body,i); - if (jl_is_labelnode(stmt)) { - int l = jl_labelnode_label(stmt); - labls[l/8] |= (1<<(l&7)); + else if (compileloops && jl_is_gotonode(stmt)) { + int l = jl_gotonode_label(stmt); + if (labls[l/8]&(1<<(l&7))) { + return 1; } - else if (compileloops && jl_is_gotonode(stmt)) { - int l = jl_gotonode_label(stmt); + } + else if (jl_is_expr(stmt)) { + if (compileloops && ((jl_expr_t*)stmt)->head==goto_ifnot_sym) { + int l = jl_unbox_long(jl_exprarg(stmt,1)); if (labls[l/8]&(1<<(l&7))) { return 1; } } - else if (jl_is_expr(stmt)) { - if (compileloops && ((jl_expr_t*)stmt)->head==goto_ifnot_sym) { - int l = jl_unbox_long(jl_exprarg(stmt,1)); - if (labls[l/8]&(1<<(l&7))) { - return 1; - } - } - // to compile code that uses exceptions - /* - if (((jl_expr_t*)stmt)->head == enter_sym) { - return 1; - } - */ - } } + if (jl_has_intrinsics(li, stmt, m)) return 1; } - if (jl_has_intrinsics(li, expr, m)) return 1; + return 0; +} + +static int jl_eval_expr_with_compiler_p(jl_value_t *e, int compileloops, jl_module_t *m) +{ + if (jl_is_expr(e) && ((jl_expr_t*)e)->head == body_sym) + return jl_eval_with_compiler_p(NULL, ((jl_expr_t*)e)->args, compileloops, m); + if (jl_has_intrinsics(NULL, e, m)) return 1; return 0; } @@ -519,14 +519,11 @@ jl_value_t *jl_toplevel_eval_flex(jl_value_t *e, int fast) if (head == thunk_sym) { thk = (jl_lambda_info_t*)jl_exprarg(ex,0); assert(jl_is_lambda_info(thk)); - if (!jl_is_expr(thk->ast)) { - thk->ast = jl_uncompress_ast(thk, thk->ast); - jl_gc_wb(thk, thk->ast); - } - ewc = jl_eval_with_compiler_p(thk, jl_lam_body((jl_expr_t*)thk->ast), fast, jl_current_module); + assert(jl_typeis(thk->code, jl_array_any_type)); + ewc = jl_eval_with_compiler_p(thk, thk->code, fast, jl_current_module); } else { - if (head && jl_eval_with_compiler_p(NULL, (jl_expr_t*)ex, fast, jl_current_module)) { + if (head && jl_eval_expr_with_compiler_p((jl_value_t*)ex, fast, jl_current_module)) { thk = jl_wrap_expr((jl_value_t*)ex); ewc = 1; } @@ -616,25 +613,19 @@ void print_func_loc(JL_STREAM *s, jl_lambda_info_t *li); void jl_check_static_parameter_conflicts(jl_lambda_info_t *li, jl_svec_t *t, jl_sym_t *fname) { - jl_array_t *vinfo; - size_t nvars; - - if (li->ast && jl_is_expr(li->ast)) { - vinfo = jl_lam_vinfo((jl_expr_t*)li->ast); - nvars = jl_array_len(vinfo); - for(size_t i=0; i < jl_svec_len(t); i++) { - for(size_t j=0; j < nvars; j++) { - jl_value_t *tv = jl_svecref(t,i); - if (jl_is_typevar(tv)) { - if ((jl_sym_t*)jl_cellref((jl_array_t*)jl_cellref(vinfo,j),0) == - ((jl_tvar_t*)tv)->name) { - jl_printf(JL_STDERR, - "WARNING: local variable %s conflicts with a static parameter in %s", - jl_symbol_name(((jl_tvar_t*)tv)->name), - jl_symbol_name(fname)); - print_func_loc(JL_STDERR, li); - jl_printf(JL_STDERR, ".\n"); - } + size_t nvars = jl_array_len(li->slotnames); + + for(size_t i=0; i < jl_svec_len(t); i++) { + for(size_t j=0; j < nvars; j++) { + jl_value_t *tv = jl_svecref(t,i); + if (jl_is_typevar(tv)) { + if ((jl_sym_t*)jl_cellref(li->slotnames, j) == ((jl_tvar_t*)tv)->name) { + jl_printf(JL_STDERR, + "WARNING: local variable %s conflicts with a static parameter in %s", + jl_symbol_name(((jl_tvar_t*)tv)->name), + jl_symbol_name(fname)); + print_func_loc(JL_STDERR, li); + jl_printf(JL_STDERR, ".\n"); } } } @@ -726,7 +717,7 @@ static jl_lambda_info_t *expr_to_lambda(jl_expr_t *f) } // wrap in a LambdaInfo jl_lambda_info_t *li = jl_new_lambda_info((jl_value_t*)f, tvar_syms, jl_emptysvec, jl_current_module); - jl_preresolve_globals(li->ast, li); + jl_preresolve_globals((jl_value_t*)li, li); JL_GC_POP(); return li; } @@ -771,7 +762,7 @@ JL_DLLEXPORT void jl_method_def(jl_svec_t *argdata, jl_lambda_info_t *f, jl_valu jl_value_t *elt = jl_tparam(argtypes,i); if (!jl_is_type(elt) && !jl_is_typevar(elt)) { jl_exceptionf(jl_argumenterror_type, "invalid type for argument %s in method definition for %s at %s:%d", - jl_symbol_name(jl_lam_argname(f,i)), + jl_symbol_name((jl_sym_t*)jl_cellref(f->slotnames,i)), jl_symbol_name(name), jl_symbol_name(f->file), f->line); } @@ -792,9 +783,9 @@ JL_DLLEXPORT void jl_method_def(jl_svec_t *argdata, jl_lambda_info_t *f, jl_valu } jl_add_method_to_table(mt, argtypes, f, tvars, isstaged == jl_true); - if (jl_boot_file_loaded && f->ast && jl_is_expr(f->ast)) { - f->ast = jl_compress_ast(f, f->ast); - jl_gc_wb(f, f->ast); + if (jl_boot_file_loaded && f->code && jl_typeis(f->code, jl_array_any_type)) { + f->code = jl_compress_ast(f, f->code); + jl_gc_wb(f, f->code); } JL_GC_POP(); } diff --git a/test/core.jl b/test/core.jl index dca1c6d3b2aa6..34049084b52fd 100644 --- a/test/core.jl +++ b/test/core.jl @@ -3189,7 +3189,7 @@ typealias PossiblyInvalidUnion{T} Union{T,Int} @test split(string(gensym("abc")),'#')[3] == "abc" # meta nodes for optional positional arguments -@test Base.uncompressed_ast(expand(:(@inline f(p::Int=2) = 3)).args[2].args[3]).args[3].args[1].args[1] === :inline +@test Base.uncompressed_ast(expand(:(@inline f(p::Int=2) = 3)).args[2].args[3])[1].args[1] === :inline # issue #13007 call13007{T,N}(::Type{Array{T,N}}) = 0 diff --git a/test/inference.jl b/test/inference.jl index c3afe6ffd9223..71f1641187755 100644 --- a/test/inference.jl +++ b/test/inference.jl @@ -185,9 +185,7 @@ end end let ast12474 = code_typed(f12474, Tuple{Float64}) - for (_, vartype) in ast12474[1].args[2][1] - @test isleaftype(vartype) - end + @test all(isleaftype, ast12474[1].slottypes) end @@ -200,7 +198,7 @@ end @eval f15259(x,y) = (a = $(Expr(:new, :A15259, :x, :y)); (a.x, a.y, getfield(a,1), getfield(a, 2))) @test isempty(filter(x -> isa(x,Expr) && x.head === :(=) && isa(x.args[2], Expr) && x.args[2].head === :new, - code_typed(f15259, (Any,Int))[1].args[3].args)) + code_typed(f15259, (Any,Int))[1].code)) @test f15259(1,2) == (1,2,1,2) # check that error cases are still correct @eval g15259(x,y) = (a = $(Expr(:new, :A15259, :x, :y)); a.z) diff --git a/test/inline.jl b/test/inline.jl index 917dc4e045171..c66ada585dadb 100644 --- a/test/inline.jl +++ b/test/inline.jl @@ -20,9 +20,8 @@ Helper to test that every slot is in range after inlining. """ function test_inlined_symbols(func, argtypes) linfo = code_typed(func, argtypes)[1] - locals = linfo.args[2][1] - nl = length(locals) - ast = linfo.args[3] + nl = length(linfo.slottypes) + ast = Expr(:body); ast.args = Base.uncompressed_ast(linfo) walk(ast) do e if isa(e, Slot) @test 1 <= e.id <= nl diff --git a/test/meta.jl b/test/meta.jl index e1e076aec6cac..46f47eb7832ac 100644 --- a/test/meta.jl +++ b/test/meta.jl @@ -61,7 +61,7 @@ asts = code_lowered(dummy, Tuple{}) ast = asts[1] body = Expr(:block) -body.args = ast.args[3].args +body.args = Base.uncompressed_ast(ast) @test popmeta!(body, :test) == (true, [42]) @test popmeta!(body, :nonexistent) == (false, [])