Skip to content

Commit

Permalink
add a new Expr head for directly calling a LambdaInfo
Browse files Browse the repository at this point in the history
Expr(:invoke, LambdaInfo, call-args...)

is a more primitive form of Expr(:call)
for which the dispatch logic has been pre-determined

this is not used by lowering, but is used by inference
to allowing moving of this logic out of codegen

also fix the tfunc for kwfunc, since it was all munged up
and making the invoke inlining unhappy

also fixes a number of bugs caused by deleting code
not preserving various invariants or not testing correctly for them

also fixes a number of bugs that have accumulated in --compile=all
operation since that configuration stopped being tested on CI
  • Loading branch information
vtjnash committed Jun 17, 2016
1 parent 979f4d8 commit 0f0d8e2
Show file tree
Hide file tree
Showing 18 changed files with 296 additions and 155 deletions.
77 changes: 47 additions & 30 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -977,10 +977,8 @@ function abstract_call(f::ANY, fargs, argtypes::Vector{Any}, vtypes::VarTable, s
elseif is(f,Core.kwfunc)
if length(fargs) == 2
ft = widenconst(argtypes[2])
if isa(ft,DataType) && !ft.abstract
if isdefined(ft.name.mt, :kwsorter)
return typeof(ft.name.mt.kwsorter)
end
if isa(ft,DataType) && isdefined(ft.name, :mt) && isdefined(ft.name.mt, :kwsorter)
return Const(ft.name.mt.kwsorter)
end
end
return Any
Expand Down Expand Up @@ -1017,7 +1015,7 @@ function abstract_call(f::ANY, fargs, argtypes::Vector{Any}, vtypes::VarTable, s
return abstract_call_gf_by_type(f, atype, sv)
end

function abstract_eval_call(e, vtypes::VarTable, sv::InferenceState)
function abstract_eval_call(e::Expr, vtypes::VarTable, sv::InferenceState)
argtypes = Any[abstract_eval(a, vtypes, sv) for a in e.args]
#print("call ", e.args[1], argtypes, "\n\n")
for x in argtypes
Expand Down Expand Up @@ -1548,16 +1546,17 @@ function typeinf_ext(linfo::LambdaInfo)
# This case occurs when the IR for a function has been deleted.
# `code` will be a newly-created LambdaInfo, and we need to copy its
# contents to the existing one to copy the info to the method cache.
linfo.inferred = true
linfo.inInference = false
linfo.inInference = true
linfo.code = code.code
linfo.slotnames = code.slotnames
linfo.slottypes = code.slottypes
linfo.slotflags = code.slotflags
linfo.ssavaluetypes = code.ssavaluetypes
linfo.rettype = code.rettype
linfo.pure = code.pure
linfo.inlineable = code.inlineable
ccall(:jl_set_lambda_rettype, Void, (Any, Any), linfo, code.rettype)
linfo.inferred = true
linfo.inInference = false
end
return code
else
Expand Down Expand Up @@ -1931,15 +1930,15 @@ function finish(me::InferenceState)
# determine and cache inlineability
me.linfo.inlineable = isinlineable(me.linfo)

me.linfo.inferred = true
me.linfo.inInference = false
me.linfo.pure = ispure
if isdefined(me.linfo, :def)
# compress code for non-toplevel thunks
compressedtree = ccall(:jl_compress_ast, Any, (Any,Any), me.linfo, me.linfo.code)
me.linfo.code = compressedtree
end
me.linfo.rettype = me.bestguess
me.linfo.pure = ispure
ccall(:jl_set_lambda_rettype, Void, (Any, Any), me.linfo, me.bestguess)
me.linfo.inferred = true
me.linfo.inInference = false

# lazy-delete the item from active for several reasons:
# efficiency, correctness, and recursion-safety
Expand Down Expand Up @@ -2310,27 +2309,47 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
end
# special-case inliners for known pure functions that compute types
if isType(e.typ) && !has_typevars(e.typ.parameters[1],true)
if (is(f,apply_type) || is(f,fieldtype) || is(f,typeof) ||
if (is(f, apply_type) || is(f, fieldtype) || is(f, typeof) ||
istopfunction(topmod, f, :typejoin) ||
istopfunction(topmod, f, :promote_type))
# XXX: compute effect_free for the actual arguments
if length(argexprs) < 2 || effect_free(argexprs[2], sv, true)
return (e.typ.parameters[1],())
else
return (e.typ.parameters[1], Any[argexprs[2]])
end
end
end
if isa(f,IntrinsicFunction) || ft IntrinsicFunction
if is(f, Core.kwfunc) && length(argexprs) == 2 && isa(e.typ, Const)
if effect_free(argexprs[2], sv, true)
return (e.typ.val, ())
else
return (e.typ.val, Any[argexprs[2]])
end
end
if isa(f, IntrinsicFunction) || ft IntrinsicFunction ||
isa(f, Builtin) || ft Builtin
return NF
end

atype = argtypes_to_type(atypes)
if length(atype.parameters) - 1 > MAX_TUPLETYPE_LEN
atype = limit_tuple_type(atype)
atype_unlimited = argtypes_to_type(atypes)
if length(atype_unlimited.parameters) - 1 > MAX_TUPLETYPE_LEN
atype = limit_tuple_type(atype_unlimited)
else
atype = atype_unlimited
end
function invoke_NF()
# converts a :call to :invoke
cache_linfo = ccall(:jl_get_spec_lambda, Any, (Any,), atype_unlimited)
if cache_linfo !== nothing
e.head = :invoke
unshift!(e.args, cache_linfo)
end
return NF
end
meth = _methods_by_ftype(atype, 1)
if meth === false || length(meth) != 1
return NF
return invoke_NF()
end
meth = meth[1]::SimpleVector
metharg = meth[1]::Type
Expand Down Expand Up @@ -2364,7 +2383,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
if !inline_incompletematch_allowed || !isdefined(Main,:Base)
# provide global disable if this optimization is not desirable
# need Main.Base defined for MethodError
return NF
return invoke_NF()
end
end

Expand Down Expand Up @@ -2395,9 +2414,10 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
# end

(linfo, ty, inferred) = typeinf(method, metharg, methsp, false)
if !inferred || linfo === nothing
return NF
elseif !linfo.inlineable
if linfo === nothing || !inferred
return invoke_NF()
end
if !linfo.inlineable
# TODO
#=
if incompletematch
Expand All @@ -2420,15 +2440,15 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
body.args = Any[Expr(:return, newcall)]
ast = Expr(:lambda, newnames, Any[[], locals, [], 0], body)
else
return NF
return invoke_NF()
end
=#
return NF
return invoke_NF()
elseif linfo.code === nothing
(linfo, ty, inferred) = typeinf(method, metharg, methsp, true)
end
if linfo === nothing || !inferred || !linfo.inlineable
return NF
if linfo === nothing || !inferred || !linfo.inlineable || (ast = linfo.code) === nothing
return invoke_NF()
end

na = linfo.nargs
Expand Down Expand Up @@ -2468,10 +2488,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
methargs = metharg.parameters
nm = length(methargs)

ast = linfo.code
if ast === nothing
return NF
elseif !isa(ast,Array{Any,1})
if !isa(ast, Array{Any,1})
ast = ccall(:jl_uncompress_ast, Any, (Any,Any), linfo, ast)
else
ast = copy_exprargs(ast)
Expand Down
45 changes: 43 additions & 2 deletions base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,15 @@ end

function show(io::IO, l::LambdaInfo)
if isdefined(l, :def)
println(io, "LambdaInfo for ", l.def.name)
if (l === l.def.lambda_template)
print(io, "LambdaInfo template for ")
show(io, l.def)
println(io)
else
print(io, "LambdaInfo for ")
show_lambda_types(io, l.specTypes.parameters)
println(io)
end
else
println(io, "Toplevel LambdaInfo thunk")
end
Expand Down Expand Up @@ -946,11 +954,40 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int)
show(io, ex.head)
for arg in args
print(io, ", ")
show(io, arg)
if isa(arg, LambdaInfo) && isdefined(arg, :specTypes)
show_lambda_types(io, arg.specTypes.parameters)
else
show(io, arg)
end
end
print(io, "))")
end
show_type && show_expr_type(io, ex.typ, emphstate)
nothing
end

function show_lambda_types(io::IO, sig::SimpleVector)
# print a method signature tuple
ft = sig[1]
if ft <: Function && isempty(ft.parameters) &&
isdefined(ft.name.module, ft.name.mt.name) &&
ft == typeof(getfield(ft.name.module, ft.name.mt.name))
print(io, ft.name.mt.name)
elseif isa(ft, DataType) && is(ft.name, Type.name) && isleaftype(ft)
f = ft.parameters[1]
print(io, f)
else
print(io, "(::", ft, ")")
end
first = true
print(io, '(')
for i = 2:length(sig) # fixme (iter): `eachindex` with offset?
first || print(io, ", ")
first = false
print(io, "::", sig[i])
end
print(io, ')')
nothing
end

function ismodulecall(ex::Expr)
Expand Down Expand Up @@ -988,6 +1025,7 @@ function show(io::IO, tv::TypeVar)
print(io, "<:")
show(io, tv.ub)
end
nothing
end

function dump(io::IO, x::SimpleVector, n::Int, indent)
Expand All @@ -1007,6 +1045,7 @@ function dump(io::IO, x::SimpleVector, n::Int, indent)
end
end
end
nothing
end

function dump(io::IO, x::ANY, n::Int, indent)
Expand Down Expand Up @@ -1068,6 +1107,7 @@ function dump(io::IO, x::Array, n::Int, indent)
end
end
end
nothing
end
dump(io::IO, x::Symbol, n::Int, indent) = print(io, typeof(x), " ", x)

Expand All @@ -1089,6 +1129,7 @@ function dump(io::IO, x::DataType, n::Int, indent)
end
end
end
nothing
end

# dumptype is for displaying abstract type hierarchies like Jameson
Expand Down
28 changes: 2 additions & 26 deletions base/stacktraces.jl
Original file line number Diff line number Diff line change
Expand Up @@ -162,32 +162,8 @@ function show_spec_linfo(io::IO, frame::StackFrame)
end
else
linfo = get(frame.linfo)
params =
if isdefined(linfo, :specTypes)
linfo.specTypes.parameters
else
nothing
end
if params !== nothing
ft = params[1]
if ft <: Function && isempty(ft.parameters) &&
isdefined(ft.name.module, ft.name.mt.name) &&
ft == typeof(getfield(ft.name.module, ft.name.mt.name))
print(io, ft.name.mt.name)
elseif isa(ft, DataType) && is(ft.name, Type.name) && isleaftype(ft)
f = ft.parameters[1]
print(io, f)
else
print(io, "(::", ft, ")")
end
first = true
print(io, '(')
for i = 2:length(params)
first || print(io, ", ")
first = false
print(io, "::", params[i])
end
print(io, ')')
if isdefined(linfo, :specTypes)
Base.show_lambda_types(io, linfo.specTypes.parameters)
else
print(io, linfo.name)
end
Expand Down
5 changes: 5 additions & 0 deletions base/strings/string.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@

## basic UTF-8 decoding & iteration ##

is_surrogate_lead(c::Unsigned) = ((c & ~0x003ff) == 0xd800)
is_surrogate_trail(c::Unsigned) = ((c & ~0x003ff) == 0xdc00)
is_surrogate_codeunit(c::Unsigned) = ((c & ~0x007ff) == 0xd800)
is_valid_continuation(c) = ((c & 0xc0) == 0x80)

const utf8_offset = [
0x00000000, 0x00003080,
0x000e2080, 0x03c82080,
Expand Down
2 changes: 1 addition & 1 deletion base/sysimg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ include("iobuffer.jl")

# strings & printing
include("char.jl")
include("intfuncs.jl")
include("strings/strings.jl")
include("unicode/unicode.jl")
include("parse.jl")
Expand All @@ -151,7 +152,6 @@ using .Libc: getpid, gethostname, time
include("libdl.jl")
using .Libdl: DL_LOAD_PATH
include("env.jl")
include("intfuncs.jl")

# nullable types
include("nullable.jl")
Expand Down
5 changes: 0 additions & 5 deletions base/unicode/checkstring.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@
## Functions to check validity of UTF-8, UTF-16, and UTF-32 encoded strings,
# and also to return information necessary to convert to other encodings

is_surrogate_lead(c::Unsigned) = ((c & ~0x003ff) == 0xd800)
is_surrogate_trail(c::Unsigned) = ((c & ~0x003ff) == 0xdc00)
is_surrogate_codeunit(c::Unsigned) = ((c & ~0x007ff) == 0xd800)
is_valid_continuation(c) = ((c & 0xc0) == 0x80)

## Return flags for check_string function

const UTF_LONG = 1 ##< Long encodings are present
Expand Down
3 changes: 2 additions & 1 deletion src/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ jl_value_t *jl_memory_exception;
jl_value_t *jl_readonlymemory_exception;
union jl_typemap_t jl_cfunction_list;

jl_sym_t *call_sym; jl_sym_t *dots_sym;
jl_sym_t *call_sym; jl_sym_t *invoke_sym;
jl_sym_t *dots_sym;
jl_sym_t *module_sym; jl_sym_t *slot_sym;
jl_sym_t *empty_sym;
jl_sym_t *export_sym; jl_sym_t *import_sym;
Expand Down
6 changes: 3 additions & 3 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1355,12 +1355,12 @@ static Value *init_bits_value(Value *newv, Value *jt, Value *v, MDNode *tbaa)
return newv;
}
static Value *as_value(Type *t, const jl_cgval_t&);
static Value *init_bits_cgval(Value *newv, const jl_cgval_t& v, MDNode *tbaa, Type *t, jl_codectx_t *ctx)
static Value *init_bits_cgval(Value *newv, const jl_cgval_t& v, MDNode *tbaa, jl_codectx_t *ctx)
{
Value *jt = literal_pointer_val(v.typ);
if (v.ispointer()) {
init_tag(newv, jt);
builder.CreateMemCpy(newv, data_pointer(v,ctx,PointerType::get(t,0)), jl_datatype_size(v.typ), sizeof(void*));
builder.CreateMemCpy(newv, data_pointer(v, ctx, T_pint8), jl_datatype_size(v.typ), sizeof(void*));
return newv;
}
else {
Expand Down Expand Up @@ -1530,7 +1530,7 @@ static Value *boxed(const jl_cgval_t &vinfo, jl_codectx_t *ctx, bool gcrooted)
return literal_pointer_val(jb->instance);
}
else {
box = init_bits_cgval(emit_allocobj(jl_datatype_size(jt)), vinfo, jb->mutabl ? tbaa_mutab : tbaa_immut, t, ctx);
box = init_bits_cgval(emit_allocobj(jl_datatype_size(jt)), vinfo, jb->mutabl ? tbaa_mutab : tbaa_immut, ctx);
}

if (gcrooted) {
Expand Down
Loading

0 comments on commit 0f0d8e2

Please sign in to comment.