Skip to content

Commit

Permalink
redefine TopNode so that there can be multiple independent top modules
Browse files Browse the repository at this point in the history
making inference separate from base required modifying the definition of
TopNode to be more general, since Base may not even exist at points and
it is desirable for Core.Inference to be wholly separate from Base.
rather than special-casing Base, this introduces the concept that any
module can indicate that it is valid as a top module and will define
appropriate functions, as expected by the julia parser, to make this
legal. At the start of the module definition,
modules can ccall jl_set_istopmod(isprimary) to indicate this.
The primary top module will be used to resolve the top module for any
code that is not contained in another top module.
Only one module can be the primary top module at a time,
typically it will be Base.
  • Loading branch information
vtjnash authored and ihnorton committed May 20, 2015
1 parent 18fa555 commit 63849fd
Show file tree
Hide file tree
Showing 11 changed files with 98 additions and 58 deletions.
2 changes: 2 additions & 0 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -296,3 +296,5 @@ convert(::Type{Any}, x::ANY) = x
convert{T}(::Type{T}, x::T) = x
cconvert(T::Type, x) = convert(T, x)
unsafe_convert{T}(::Type{T}, x::T) = x

ccall(:jl_set_istopmod, Void, (Bool,), true)
99 changes: 56 additions & 43 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ function _iisconst(s::Symbol)
isdefined(m,s) && (ccall(:jl_is_const, Int32, (Any, Any), m, s) != 0)
end
_iisconst(s::SymbolNode) = _iisconst(s.name)
_iisconst(s::TopNode) = isconst(_basemod(), s.name)
_iisconst(s::TopNode) = isconst(_topmod(), s.name)
_iisconst(x::Expr) = false
_iisconst(x::ANY) = true

Expand All @@ -91,12 +91,18 @@ _ieval(x::ANY) =
(inference_stack::CallStack).mod, x, C_NULL, 0)
_iisdefined(x::ANY) = isdefined((inference_stack::CallStack).mod, x)

function _basemod()
function _topmod()
m = (inference_stack::CallStack).mod
if m === Core || m === Base
return m
return ccall(:jl_base_relative_to, Any, (Any,), m)::Module
end

function istopfunction(topmod, f, sym)
if isdefined(Main, :Base) && isdefined(Main.Base, sym) && f === getfield(Main.Base, sym)
return true
elseif isdefined(topmod, sym) && f === getfield(topmod, sym)
return true
end
return Main.Base
return false
end

cmp_tfunc = (x,y)->Bool
Expand Down Expand Up @@ -489,7 +495,7 @@ end

function isconstantfunc(f::ANY, sv::StaticVarInfo)
if isa(f,TopNode)
m = _basemod()
m = _topmod()
return isconst(m, f.name) && isdefined(m, f.name) && f
end
if isa(f,GlobalRef)
Expand Down Expand Up @@ -583,22 +589,22 @@ end

function abstract_call_gf(f, fargs, argtype, e)
argtypes = argtype.parameters
tm = _topmod()
if length(argtypes)>1 && (argtypes[1] <: Tuple) && argtypes[2]===Int
# allow tuple indexing functions to take advantage of constant
# index arguments.
if f === Main.Base.getindex
if istopfunction(tm, f, :getindex)
isa(e,Expr) && (e.head = :call1)
return getfield_tfunc(fargs, argtypes[1], argtypes[2])[1]
elseif f === Main.Base.next
elseif istopfunction(tm, f, :next)
isa(e,Expr) && (e.head = :call1)
return Tuple{getfield_tfunc(fargs, argtypes[1], argtypes[2])[1], Int}
elseif f === Main.Base.indexed_next
elseif istopfunction(tm, f, :indexed_next)
isa(e,Expr) && (e.head = :call1)
return Tuple{getfield_tfunc(fargs, argtypes[1], argtypes[2])[1], Int}
end
end
if (isdefined(Main.Base,:promote_type) && f === Main.Base.promote_type) ||
(isdefined(Main.Base,:typejoin) && f === Main.Base.typejoin)
if istopfunction(tm, f, :promote_type) || istopfunction(tm, f, :typejoin)
la = length(argtypes)
c = cell(la)
for i = 1:la
Expand All @@ -609,7 +615,7 @@ function abstract_call_gf(f, fargs, argtype, e)
return Type
end
end
if isdefined(Main.Base,:promote_type) && f === Main.Base.promote_type
if istopfunction(tm, f, :promote_type)
try
RT = Type{f(c...)}
isa(e,Expr) && (e.head = :call1)
Expand Down Expand Up @@ -676,20 +682,22 @@ function abstract_call_gf(f, fargs, argtype, e)
sp = sp.prev
end
ls = length(sig.parameters)
if limit && ls > lsig+1 && !(isdefined(Main.Base,:promote_typeof) && f === Main.Base.promote_typeof)
fst = sig.parameters[lsig+1]
allsame = true
# allow specializing on longer arglists if all the trailing
# arguments are the same, since there is no exponential
# blowup in this case.
for i = lsig+2:ls
if sig.parameters[i] != fst
allsame = false
break
if limit && ls > lsig+1
if !istopfunction(tm, f, :promote_typeof)
fst = sig.parameters[lsig+1]
allsame = true
# allow specializing on longer arglists if all the trailing
# arguments are the same, since there is no exponential
# blowup in this case.
for i = lsig+2:ls
if sig.parameters[i] != fst
allsame = false
break
end
end
if !allsame
sig = limit_tuple_type_n(sig, lsig+1)
end
end
if !allsame
sig = limit_tuple_type_n(sig, lsig+1)
end
end
#print(m,"\n")
Expand Down Expand Up @@ -899,7 +907,7 @@ function abstract_eval_call(e, vtypes, sv::StaticVarInfo)
end
return Any
end
#print("call ", e.args[1], argtypes, " ")
#print("call ", e.args[1], argtypes, "\n\n")
f = _ieval(func)
return abstract_call(f, fargs, argtypes, vtypes, sv, e)
end
Expand All @@ -908,7 +916,7 @@ function abstract_eval(e::ANY, vtypes, sv::StaticVarInfo)
if isa(e,QuoteNode)
return typeof((e::QuoteNode).value)
elseif isa(e,TopNode)
return abstract_eval_global(_basemod(), (e::TopNode).name)
return abstract_eval_global(_topmod(), (e::TopNode).name)
elseif isa(e,Symbol)
return abstract_eval_symbol(e::Symbol, vtypes, sv)
elseif isa(e,SymbolNode)
Expand Down Expand Up @@ -1917,8 +1925,8 @@ function resolve_relative(sym, locals, args, from, to, orig)
if const_to && is(eval(from,sym), eval(to,sym))
return orig
end
m = _basemod()
if is(from,m) || is(from,Core)
m = _topmod()
if is(from, m) || is(from, Core)
return TopNode(sym)
end
end
Expand Down Expand Up @@ -2003,7 +2011,7 @@ function exprtype(x::ANY, sv::StaticVarInfo)
elseif isa(x,GenSym)
return abstract_eval_gensym(x::GenSym, sv)
elseif isa(x,TopNode)
return abstract_eval_global(_basemod(), (x::TopNode).name)
return abstract_eval_global(_topmod(), (x::TopNode).name)
elseif isa(x,Symbol)
sv = inference_stack.sv
if is_local(sv, x::Symbol)
Expand Down Expand Up @@ -2180,16 +2188,16 @@ function inlineable(f::ANY, e::Expr, atype::ANY, sv::StaticVarInfo, enclosing_as
# remove redundant unbox
return (e.args[3],())
end
if isdefined(Main.Base,:isbits) && is(f,Main.Base.isbits) &&
length(atypes)==1 && isType(atypes[1]) && effect_free(argexprs[1],sv,true) &&
isleaftype(atypes[1].parameters[1])
topmod = _topmod()
if istopfunction(topmod, f, :isbits) && length(atypes)==1 && isType(atypes[1]) &&
effect_free(argexprs[1],sv,true) && isleaftype(atypes[1].parameters[1])
return (isbits(atypes[1].parameters[1]),())
end
# special-case inliners for known pure functions that compute types
if isType(e.typ)
if (is(f,apply_type) || is(f,fieldtype) ||
(isdefined(Main.Base,:typejoin) && is(f,Main.Base.typejoin)) ||
(isdefined(Main.Base,:promote_type) && is(f,Main.Base.promote_type))) &&
istopfunction(topmod, f, :typejoin) ||
istopfunction(topmod, f, :promote_type)) &&
isleaftype(e.typ.parameters[1])
return (e.typ.parameters[1],())
end
Expand Down Expand Up @@ -2265,7 +2273,9 @@ function inlineable(f::ANY, e::Expr, atype::ANY, sv::StaticVarInfo, enclosing_as
nm = length(methargs)
if !(atype <: metharg)
incompletematch = true
if !inline_incompletematch_allowed
if !inline_incompletematch_allowed || !isdefined(Main,:Base)
# provide global disable if this optimization is not desirable
# need Main.Base defined for MethodError
return NF
end
else
Expand Down Expand Up @@ -2439,7 +2449,7 @@ function inlineable(f::ANY, e::Expr, atype::ANY, sv::StaticVarInfo, enclosing_as
argexprs2 = t.args
icall = LabelNode(label_counter(body.args)+1)
partmatch = Expr(:gotoifnot, false, icall.label)
thrw = Expr(:call, :throw, Expr(:call, TopNode(:MethodError), Expr(:call, top_tuple, e.args[1], QuoteNode(:inline)), t))
thrw = Expr(:call, :throw, Expr(:call, GlobalRef(Main.Base,:MethodError), Expr(:call, top_tuple, e.args[1], QuoteNode(:inline)), t))
thrw.typ = Bottom
end

Expand Down Expand Up @@ -2712,7 +2722,7 @@ function mk_tuplecall(args, sv::StaticVarInfo)
e
end

const basenumtype = Union(Int32,Int64,Float32,Float64,Complex64,Complex128,Rational)
const corenumtype = Union(Int32,Int64,Float32,Float64)

function inlining_pass(e::Expr, sv, ast)
if e.head == :method
Expand Down Expand Up @@ -2814,17 +2824,20 @@ function inlining_pass(e::Expr, sv, ast)
e.args = Any[is_global(sv,:call) ? (:call) : GlobalRef((inference_stack::CallStack).mod, :call), e.args...]
end

if is(f, ^) || is(f, .^)
if isdefined(Main, :Base) &&
((isdefined(Main.Base, :^) && is(f, Main.Base.(:^))) ||
(isdefined(Main.Base, :.^) && is(f, Main.Base.(:.^))))
if length(e.args) == 3 && isa(e.args[3],Union(Int32,Int64))
a1 = e.args[2]
basenumtype = Union(corenumtype, Main.Base.Complex64, Main.Base.Complex128, Main.Base.Rational)
if isa(a1,basenumtype) || ((isa(a1,Symbol) || isa(a1,SymbolNode) || isa(a1,GenSym)) &&
exprtype(a1,sv) <: basenumtype)
if e.args[3]==2
e.args = Any[TopNode(:*), a1, a1]
f = *
e.args = Any[GlobalRef(Main.Base,:*), a1, a1]
f = Main.Base.(:*)
elseif e.args[3]==3
e.args = Any[TopNode(:*), a1, a1, a1]
f = *
e.args = Any[GlobalRef(Main.Base,:*), a1, a1, a1]
f = Main.Base.(:*)
end
end
end
Expand Down
1 change: 1 addition & 0 deletions base/sysimg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ baremodule Base

using Core: Intrinsics, arraylen, arrayref, arrayset, arraysize, _expr,
kwcall, _apply, typeassert, apply_type, svec
ccall(:jl_set_istopmod, Void, (Bool,), true)

include = Core.include

Expand Down
16 changes: 11 additions & 5 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ static void jl_serialize_module(ios_t *s, jl_module_t *m)
}
}
jl_serialize_value(s, m->constant_table);
write_uint8(s, m->istopmod);
write_uint64(s, m->uuid);
}

Expand Down Expand Up @@ -1253,6 +1254,7 @@ static jl_value_t *jl_deserialize_value_(ios_t *s, jl_value_t *vtag, jl_value_t
}
m->constant_table = (jl_array_t*)jl_deserialize_value(s, (jl_value_t**)&m->constant_table);
if (m->constant_table != NULL) gc_wb(m, m->constant_table);
m->istopmod = read_uint8(s);
m->uuid = read_uint64(s);
return (jl_value_t*)m;
}
Expand Down Expand Up @@ -1424,9 +1426,11 @@ DLLEXPORT void jl_save_system_image(const char *fname)
// orphan old Base module if present
jl_base_module = (jl_module_t*)jl_get_global(jl_main_module, jl_symbol("Base"));

jl_idtable_type = jl_get_global(jl_base_module, jl_symbol("ObjectIdDict"));
jl_idtable_type = jl_base_module ? jl_get_global(jl_base_module, jl_symbol("ObjectIdDict")) : NULL;

jl_serialize_value(&f, jl_main_module);
jl_serialize_value(&f, jl_top_module);
jl_serialize_value(&f, jl_typeinf_func);

// ensure everything in deser_tag is reassociated with its GlobalValue
ptrint_t i=2;
Expand Down Expand Up @@ -1527,7 +1531,9 @@ void jl_restore_system_image(const char *fname)
datatype_list = jl_alloc_cell_1d(0);

jl_main_module = (jl_module_t*)jl_deserialize_value(&f, NULL);
jl_top_module = (jl_module_t*)jl_deserialize_value(&f, NULL);
jl_internal_main_module = jl_main_module;
jl_typeinf_func = (jl_function_t*)jl_deserialize_value(&f, NULL);
jl_core_module = (jl_module_t*)jl_get_global(jl_main_module,
jl_symbol("Core"));
jl_base_module = (jl_module_t*)jl_get_global(jl_main_module,
Expand All @@ -1554,11 +1560,11 @@ void jl_restore_system_image(const char *fname)
datatype_list = NULL;

jl_get_builtin_hooks();
jl_get_system_hooks();
jl_get_uv_hooks();
if (jl_base_module) {
jl_get_system_hooks();
jl_get_uv_hooks();
}
jl_boot_file_loaded = 1;
jl_typeinf_func = (jl_function_t*)jl_get_global(jl_base_module,
jl_symbol("typeinf_ext"));
jl_init_box_caches();

jl_set_t_uid_ctr(read_int32(&f));
Expand Down
2 changes: 0 additions & 2 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,8 +399,6 @@ jl_function_t *jl_method_cache_insert(jl_methtable_t *mt, jl_tupletype_t *type,
return jl_method_list_insert(pml, type, method, jl_emptysvec, 0, 0, cache_array ? cache_array : (jl_value_t*)mt)->func;
}

extern jl_function_t *jl_typeinf_func;

/*
run type inference on lambda "li" in-place, for given argument types.
"def" is the original method definition of which this is an instance;
Expand Down
1 change: 1 addition & 0 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -1029,6 +1029,7 @@ void _julia_init(JL_IMAGE_SEARCH rel)

if (!jl_options.image_file) {
jl_core_module = jl_new_module(jl_symbol("Core"));
jl_top_module = jl_core_module;
jl_init_intrinsic_functions();
jl_init_primitives();

Expand Down
2 changes: 1 addition & 1 deletion src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -1684,7 +1684,7 @@
(expand-forms
(lower-tuple-assignment
(list lhs st)
`(call (|.| (top Base) (quote indexed_next))
`(call (top indexed_next)
,xx ,(+ i 1) ,st))))
(iota (length lhss))
lhss)
Expand Down
4 changes: 3 additions & 1 deletion src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ typedef struct _jl_module_t {
arraylist_t usings; // modules with all bindings potentially imported
jl_array_t *constant_table;
jl_function_t *call_func; // cached lookup of `call` within this module
uint8_t istopmod;
uint64_t uuid;
} jl_module_t;

Expand Down Expand Up @@ -1069,6 +1070,7 @@ extern DLLEXPORT jl_module_t *jl_main_module;
extern DLLEXPORT jl_module_t *jl_internal_main_module;
extern DLLEXPORT jl_module_t *jl_core_module;
extern DLLEXPORT jl_module_t *jl_base_module;
extern DLLEXPORT jl_module_t *jl_top_module;
extern DLLEXPORT jl_module_t *jl_current_module;
DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name);
// get binding for reading
Expand Down Expand Up @@ -1229,7 +1231,7 @@ DLLEXPORT jl_value_t *jl_interpret_toplevel_expr_in(jl_module_t *m, jl_value_t *
jl_value_t *jl_static_eval(jl_value_t *ex, void *ctx_, jl_module_t *mod,
jl_value_t *sp, jl_expr_t *ast, int sparams, int allow_alloc);
int jl_is_toplevel_only_expr(jl_value_t *e);
jl_module_t *jl_base_relative_to(jl_module_t *m);
DLLEXPORT jl_module_t *jl_base_relative_to(jl_module_t *m);
void jl_type_infer(jl_lambda_info_t *li, jl_tupletype_t *argtypes, jl_lambda_info_t *def);

jl_function_t *jl_method_lookup_by_type(jl_methtable_t *mt, jl_tupletype_t *types,
Expand Down
1 change: 1 addition & 0 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ extern "C" {
#endif

extern size_t jl_page_size;
extern jl_function_t *jl_typeinf_func;

STATIC_INLINE jl_value_t *newobj(jl_value_t *type, size_t nfields)
{
Expand Down
14 changes: 14 additions & 0 deletions src/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ extern "C" {
jl_module_t *jl_main_module=NULL;
jl_module_t *jl_core_module=NULL;
jl_module_t *jl_base_module=NULL;
jl_module_t *jl_top_module=NULL;
jl_module_t *jl_current_module=NULL;

jl_module_t *jl_new_module(jl_sym_t *name)
Expand All @@ -26,6 +27,7 @@ jl_module_t *jl_new_module(jl_sym_t *name)
m->parent = NULL;
m->constant_table = NULL;
m->call_func = NULL;
m->istopmod = 0;
m->uuid = uv_now(uv_default_loop());
htable_new(&m->bindings, 0);
arraylist_new(&m->usings, 0);
Expand All @@ -48,6 +50,18 @@ DLLEXPORT jl_value_t *jl_f_new_module(jl_sym_t *name, uint8_t std_imports)
return (jl_value_t*)m;
}

DLLEXPORT void jl_set_istopmod(uint8_t isprimary)
{
jl_current_module->istopmod = 1;
if (isprimary)
jl_top_module = jl_current_module;
}

DLLEXPORT uint8_t jl_istopmod(jl_module_t *mod)
{
return mod->istopmod;
}

static jl_binding_t *new_binding(jl_sym_t *name)
{
assert(jl_is_symbol(name));
Expand Down
Loading

0 comments on commit 63849fd

Please sign in to comment.