Skip to content

Commit

Permalink
make (top x) node always refer to Base.x
Browse files Browse the repository at this point in the history
consistently wrap all calls generated by the front end in (top ). this
makes them behave like macros defined in Base, which is reasonable.
related to #1484. this at least prevents such collisions for now, but
it may not be the final behavior we settle on. we may want some names
(like ref) evaluated in the context where they occur.
  • Loading branch information
JeffBezanson committed Nov 21, 2012
1 parent c4d199d commit c696629
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 44 deletions.
58 changes: 40 additions & 18 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,18 @@ _ieval(x) = eval((inference_stack::CallStack).mod, x)
_iisdefined(x) = isdefined((inference_stack::CallStack).mod, x)

_iisconst(s::SymbolNode) = _iisconst(s.name)
_iisconst(s::TopNode) = _iisconst(s.name)
_iisconst(s::TopNode) = isconst(_basemod(), s.name)
_iisconst(x::Expr) = false
_iisconst(x) = true

function _basemod()
m = (inference_stack::CallStack).mod
if m === Core || m === Base
return m
end
return Main.Base
end

cmp_tfunc = (x,y)->Bool

isType(t::ANY) = isa(t,AbstractKind) && is((t::AbstractKind).name,Type.name)
Expand Down Expand Up @@ -397,7 +405,8 @@ end

function isconstantfunc(f, sv::StaticVarInfo)
if isa(f,TopNode)
return _iisconst(f.name) && f.name
m = _basemod()
return isconst(m, f.name) && isdefined(m, f.name) && f
end
if isa(f,GetfieldNode) && isa(f.value,Module)
M = f.value; s = f.name
Expand Down Expand Up @@ -710,7 +719,7 @@ function abstract_eval(e::QuoteNode, vtypes, sv::StaticVarInfo)
end

function abstract_eval(e::TopNode, vtypes, sv::StaticVarInfo)
return abstract_eval_global(e.name)
return abstract_eval_global(_basemod(), e.name)
end

const _jl_Type_Array = Type{Array}
Expand All @@ -732,11 +741,14 @@ end
# type Undef, only None.
# typealias Top Union(Any,Undef)

function abstract_eval_global(s::Symbol)
if _iisconst(s)
return abstract_eval_constant(_ieval(s))
abstract_eval_global(s::Symbol) =
abstract_eval_global((inference_stack::CallStack).mod, s)

function abstract_eval_global(M, s::Symbol)
if isconst(M,s)
return abstract_eval_constant(eval(M,s))
end
if !_iisdefined(s)
if !isdefined(M,s)
return Top
end
# TODO: change to Undef if there's a way to clear variables
Expand Down Expand Up @@ -1359,14 +1371,23 @@ end

sym_replace(x, from1, from2, to1, to2) = x

# see if a symbol resolves the same in two modules
function resolves_same(sym, from, to)
# return an expr to evaluate "from.sym" in module "to"
function resolve_relative(sym, from, to, typ, orig)
if is(from,to)
return true
return orig
end
const_from = (isconst(from,sym) && isdefined(from,sym))
const_to = (isconst(to,sym) && isdefined(to,sym))
if const_from
if const_to && is(eval(from,sym), eval(to,sym))
return orig
end
m = _basemod()
if is(from,m) || is(from,Core)
return _jl_tn(sym)
end
end
# todo: better
return (isconst(from,sym) && isconst(to,sym) && isdefined(from,sym) &&
isdefined(to,sym) && is(eval(from,sym),eval(to,sym)))
return GetfieldNode(from, sym, typ)
end

# annotate symbols with their original module for inlining
Expand All @@ -1383,14 +1404,15 @@ function resolve_globals(s::Symbol, from, to, env1, env2)
if contains_is(env1, s) || contains_is(env2, s)
return s
end
resolves_same(s, from, to) ? s : GetfieldNode(from, s, Any)
resolve_relative(s, from, to, Any, s)
end

function resolve_globals(s::SymbolNode, from, to, env1, env2)
if contains_is(env1, s.name) || contains_is(env2, s.name)
name = s.name
if contains_is(env1, name) || contains_is(env2, name)
return s
end
resolves_same(s.name, from, to) ? s : GetfieldNode(from, s.name, s.typ)
resolve_relative(name, from, to, s.typ, s)
end

resolve_globals(x, from, to, env1, env2) = x
Expand All @@ -1416,7 +1438,7 @@ function exprtype(x::ANY)
elseif isa(x,SymbolNode)
return x.typ
elseif isa(x,TopNode)
return abstract_eval_global(x.name)
return abstract_eval_global(_basemod(), x.name)
elseif isa(x,Symbol)
sv = inference_stack.sv
if is_local(sv, x)
Expand Down Expand Up @@ -1763,7 +1785,7 @@ function is_known_call(e::Expr, func, sv)
return false
end
f = isconstantfunc(e.args[1], sv)
return isa(f,Symbol) && is(_ieval(f), func)
return !is(f,false) && is(_ieval(f), func)
end

# compute set of vars assigned once
Expand Down
22 changes: 19 additions & 3 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,11 @@ static Value *julia_bool(Value *cond)

static jl_value_t *static_eval(jl_value_t *ex, jl_codectx_t *ctx, bool sparams=true);

static inline jl_module_t *topmod(jl_codectx_t *ctx)
{
return jl_base_relative_to(ctx->module);
}

static jl_value_t *expr_type(jl_value_t *e, jl_codectx_t *ctx)
{
if (jl_is_expr(e))
Expand All @@ -440,7 +445,20 @@ static jl_value_t *expr_type(jl_value_t *e, jl_codectx_t *ctx)
e = v;
goto type_of_constant;
}
if (jl_is_topnode(e) || jl_is_symbol(e)) {
if (jl_is_topnode(e)) {
e = jl_fieldref(e,0);
jl_binding_t *b = jl_get_binding(topmod(ctx), (jl_sym_t*)e);
if (!b || !b->value)
return jl_top_type;
if (b->constp) {
e = b->value;
goto type_of_constant;
}
else {
return (jl_value_t*)jl_any_type;
}
}
if (jl_is_symbol(e)) {
if (jl_is_symbol(e)) {
if (is_global((jl_sym_t*)e, ctx)) {
// look for static parameter
Expand All @@ -456,8 +474,6 @@ static jl_value_t *expr_type(jl_value_t *e, jl_codectx_t *ctx)
return (jl_value_t*)jl_any_type;
}
}
if (jl_is_topnode(e))
e = jl_fieldref(e,0);
jl_binding_t *b = jl_get_binding(ctx->module, (jl_sym_t*)e);
if (!b || !b->value)
return jl_top_type;
Expand Down
10 changes: 5 additions & 5 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ static jl_value_t *static_eval(jl_value_t *ex, jl_codectx_t *ctx, bool sparams)
return NULL;
}
if (jl_is_topnode(ex)) {
jl_binding_t *b = jl_get_binding(ctx->module,
jl_binding_t *b = jl_get_binding(topmod(ctx),
(jl_sym_t*)jl_fieldref(ex,0));
if (b == NULL) return NULL;
if (b->constp)
Expand Down Expand Up @@ -428,8 +428,7 @@ static bool is_constant(jl_value_t *ex, jl_codectx_t *ctx, bool sparams=true)
static bool symbol_eq(jl_value_t *e, jl_sym_t *sym)
{
return ((jl_is_symbol(e) && ((jl_sym_t*)e)==sym) ||
(jl_is_symbolnode(e) && jl_symbolnode_sym(e)==sym) ||
(jl_is_topnode(e) && ((jl_sym_t*)jl_fieldref(e,0))==sym));
(jl_is_symbolnode(e) && jl_symbolnode_sym(e)==sym));
}

// --- find volatile variables ---
Expand Down Expand Up @@ -1486,9 +1485,10 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed,
else if (jl_is_topnode(expr)) {
jl_sym_t *var = (jl_sym_t*)jl_fieldref(expr,0);
jl_value_t *etype = expr_type(expr, ctx);
jl_binding_t *b = jl_get_binding(ctx->module, var);
jl_module_t *mod = topmod(ctx);
jl_binding_t *b = jl_get_binding(mod, var);
if (b == NULL)
b = jl_get_binding_wr(ctx->module, var);
b = jl_get_binding_wr(mod, var);
Value *bp = literal_pointer_val(&b->value, jl_ppvalue_llvmt);
if ((b->constp && b->value!=NULL) ||
(etype!=(jl_value_t*)jl_any_type &&
Expand Down
2 changes: 1 addition & 1 deletion src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ void julia_init(char *imageFile)

// the Main module is the one which is always open, and set as the
// current module for bare (non-module-wrapped) toplevel expressions.
// it does import Base.* if Base is available.
// it does "using Base" if Base is available.
if (jl_base_module != NULL)
jl_module_using(jl_main_module, jl_base_module);
jl_current_module = jl_main_module;
Expand Down
6 changes: 3 additions & 3 deletions src/interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,10 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl)
return jl_fieldref(e,0);
}
if (jl_is_topnode(e)) {
jl_value_t *v = jl_get_global(jl_current_module,
(jl_sym_t*)jl_fieldref(e,0));
jl_sym_t *s = (jl_sym_t*)jl_fieldref(e,0);
jl_value_t *v = jl_get_global(jl_base_relative_to(jl_current_module),s);
if (v == NULL)
jl_errorf("%s not defined", ((jl_sym_t*)jl_fieldref(e,0))->name);
jl_errorf("%s not defined", s->name);
return v;
}
if (!jl_is_expr(e)) {
Expand Down
14 changes: 7 additions & 7 deletions src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,7 @@
(cadr x)
(tuple-wrap (cdr a) '())))
(tuple-wrap (cdr a) (cons x run))))))
`(call apply ,f ,@(tuple-wrap argl '()))))
`(call (top apply) ,f ,@(tuple-wrap argl '()))))

; tuple syntax (a, b...)
; note, directly inside tuple ... means sequence type
Expand Down Expand Up @@ -958,14 +958,14 @@
(= ,cnt ,a)
,@(if (eq? lim b) '() `((= ,lim ,b)))
(break-block loop-exit
(_while (call <= ,cnt ,lim)
(_while (call (top <=) ,cnt ,lim)
(block
(= ,lhs ,cnt)
(break-block loop-cont
,body)
(= ,cnt (call (top convert)
(call (top typeof) ,cnt)
(call + 1 ,cnt)))))))))))
(call (top +) 1 ,cnt)))))))))))

; for loop over arbitrary vectors
(pattern-lambda
Expand Down Expand Up @@ -1093,9 +1093,9 @@
(if (null? ranges)
(list)
(if (eq? (car ranges) `:)
(cons `(call size ,oneresult ,oneresult-dim)
(cons `(call (top size) ,oneresult ,oneresult-dim)
(compute-dims (cdr ranges) (+ oneresult-dim 1)))
(cons `(call length ,(caddr (car ranges)))
(cons `(call (top length) ,(caddr (car ranges)))
(compute-dims (cdr ranges) oneresult-dim)) )))

;; construct loops to cycle over all dimensions of an n-d comprehension
Expand All @@ -1108,7 +1108,7 @@
(+= ,ri 1)) )
(if (eq? (car ranges) `:)
(let ((i (gensy)))
`(for (= ,i (: 1 (call size ,oneresult ,oneresult-dim)))
`(for (= ,i (: 1 (call (top size) ,oneresult ,oneresult-dim)))
,(construct-loops (cdr ranges) (cons i iters) (+ oneresult-dim 1)) ))
`(for ,(car ranges)
,(construct-loops (cdr ranges) iters oneresult-dim) ))))
Expand Down Expand Up @@ -1150,7 +1150,7 @@

;; compute the dimensions of the result
(define (compute-dims ranges)
(map (lambda (r) `(call length ,(caddr r)))
(map (lambda (r) `(call (top length) ,(caddr r)))
ranges))

;; construct loops to cycle over all dimensions of an n-d comprehension
Expand Down
1 change: 1 addition & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,7 @@ jl_value_t *jl_interpret_toplevel_expr_with(jl_value_t *e,
jl_value_t **locals, size_t nl);
jl_value_t *jl_interpret_toplevel_expr_in(jl_module_t *m, jl_value_t *e,
jl_value_t **locals, size_t nl);
jl_module_t *jl_base_relative_to(jl_module_t *m);
void jl_type_infer(jl_lambda_info_t *li, jl_tuple_t *argtypes,
jl_lambda_info_t *def);

Expand Down
2 changes: 1 addition & 1 deletion src/task.c
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ static jl_value_t *build_backtrace(void)

unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
while (unw_step(&cursor) && n < 10000) {
while (unw_step(&cursor) && n < 80000) {
unw_get_reg(&cursor, UNW_REG_IP, &ip);
push_frame_info_from_ip(a, ip);
n++;
Expand Down
23 changes: 17 additions & 6 deletions src/toplevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ DLLEXPORT char *julia_home = NULL;
// current line number in a file
int jl_lineno = 0;

jl_module_t *jl_old_base_module = NULL;

jl_value_t *jl_toplevel_eval_flex(jl_value_t *e, int fast);

jl_value_t *jl_eval_module_expr(jl_expr_t *ex)
Expand All @@ -42,8 +44,8 @@ jl_value_t *jl_eval_module_expr(jl_expr_t *ex)
jl_module_t *newm = jl_new_module(name);
newm->parent = parent_module;
b->value = (jl_value_t*)newm;
if (parent_module == jl_main_module && name == jl_symbol("Base") &&
jl_base_module == NULL) {
if (parent_module == jl_main_module && name == jl_symbol("Base")) {
jl_old_base_module = jl_base_module;
// pick up Base module during bootstrap
jl_base_module = newm;
}
Expand Down Expand Up @@ -88,21 +90,30 @@ jl_value_t *jl_eval_module_expr(jl_expr_t *ex)
return jl_nothing;
}

static int is_intrinsic(jl_sym_t *s)
static int is_intrinsic(jl_module_t *m, jl_sym_t *s)
{
jl_value_t *v = jl_get_global(jl_current_module, s);
jl_value_t *v = jl_get_global(m, s);
return (v != NULL && jl_typeof(v)==(jl_type_t*)jl_intrinsic_type);
}

// module referenced by TopNode from within m
// this is only needed because of the bootstrapping process:
// - initially Base doesn't exist and top === Core
// - later, it refers to either old Base or new Base
jl_module_t *jl_base_relative_to(jl_module_t *m)
{
return (m==jl_core_module||m==jl_old_base_module||jl_base_module==NULL) ? m : jl_base_module;
}

static int has_intrinsics(jl_expr_t *e)
{
if (e->args->length == 0)
return 0;
if (e->head == static_typeof_sym) return 1;
jl_value_t *e0 = jl_exprarg(e,0);
if (e->head == call_sym &&
((jl_is_symbol(e0) && is_intrinsic((jl_sym_t*)e0)) ||
(jl_is_topnode(e0) && is_intrinsic((jl_sym_t*)jl_fieldref(e0,0)))))
((jl_is_symbol(e0) && is_intrinsic(jl_current_module,(jl_sym_t*)e0)) ||
(jl_is_topnode(e0) && is_intrinsic(jl_base_relative_to(jl_current_module),(jl_sym_t*)jl_fieldref(e0,0)))))
return 1;
int i;
for(i=0; i < e->args->length; i++) {
Expand Down

0 comments on commit c696629

Please sign in to comment.