Skip to content

Commit

Permalink
make eval and method_exists no longer builtins
Browse files Browse the repository at this point in the history
switch `arraylen` from builtin to intrinsic
  • Loading branch information
JeffBezanson committed Oct 25, 2015
1 parent 37dad15 commit f1664bc
Show file tree
Hide file tree
Showing 19 changed files with 64 additions and 99 deletions.
11 changes: 7 additions & 4 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,15 @@ export
Expr, GotoNode, LabelNode, LineNumberNode, QuoteNode, SymbolNode, TopNode,
GlobalRef, NewvarNode, GenSym,
# object model functions
fieldtype, getfield, setfield!, nfields, throw, tuple, is, ===, isdefined,
# arraylen, arrayref, arrayset, arraysize,
fieldtype, getfield, setfield!, nfields, throw, tuple, is, ===, isdefined, eval,
# arrayref, arrayset, arraysize,
# _apply, kwcall,
# sizeof # not exported, to avoid conflicting with Base.sizeof
# type reflection
issubtype, typeof, isa,
# typeassert, apply_type,
# method reflection
applicable, invoke, method_exists,
applicable, invoke,
# constants
nothing, Main,
# intrinsics module
Expand All @@ -174,7 +174,7 @@ export
#mul_int, ne_float, ne_int, neg_float, neg_int, not_int, or_int, rem_float,
#sdiv_int, shl_int, sitofp, sle_int, slt_int, smod_int,
#srem_int, sub_float, sub_int, trunc_int, udiv_int, uitofp,
#ule_int, ult_int, unbox, urem_int, xor_int, sext_int, zext_int
#ule_int, ult_int, unbox, urem_int, xor_int, sext_int, zext_int, arraylen


const (===) = is
Expand Down Expand Up @@ -260,6 +260,9 @@ typealias ByteString Union{ASCIIString,UTF8String}

include(fname::ByteString) = ccall(:jl_load_, Any, (Any,), fname)

eval(e::ANY) = eval(Main, e)
eval(m::Module, e::ANY) = ccall(:jl_toplevel_eval_in, Any, (Any, Any), m, e)

# constructors for built-in types

type WeakRef
Expand Down
2 changes: 1 addition & 1 deletion base/coreimg.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This file is a part of Julia. License is MIT: http://julialang.org/license

Main.Core.eval(Main.Core, :(baremodule Inference
using Core: Intrinsics, arraylen, arrayref, arrayset, arraysize, _expr,
using Core: Intrinsics, arrayref, arrayset, arraysize, _expr,
kwcall, _apply, typeassert, apply_type, svec
ccall(:jl_set_istopmod, Void, (Bool,), false)

Expand Down
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,7 @@ export
isgeneric,
isinteractive,
less,
method_exists,
methods,
methodswith,
module_name,
Expand Down
5 changes: 2 additions & 3 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ cmp_tfunc = (x,y)->Bool
isType(t::ANY) = isa(t,DataType) && is((t::DataType).name,Type.name)

const IInf = typemax(Int) # integer infinity
const n_ifunc = reinterpret(Int32,llvmcall)+1
const n_ifunc = reinterpret(Int32,arraylen)+1
const t_ifunc = Array{Tuple{Int,Int,Function},1}(n_ifunc)
const t_ffunc_key = Array{Function,1}(0)
const t_ffunc_val = Array{Tuple{Int,Int,Function},1}(0)
Expand Down Expand Up @@ -162,16 +162,15 @@ add_tfunc(eval(Core.Intrinsics,:cglobal), 1, 2,
add_tfunc(eval(Core.Intrinsics,:select_value), 3, 3,
# TODO: return Bottom if cnd is definitely not a Bool
(cnd, x, y)->Union{x,y})
add_tfunc(eval(Core.Intrinsics,:arraylen), 1, 1, x->Int)
add_tfunc(is, 2, 2, cmp_tfunc)
add_tfunc(issubtype, 2, 2, cmp_tfunc)
add_tfunc(isa, 2, 2, cmp_tfunc)
add_tfunc(isdefined, 1, IInf, (args...)->Bool)
add_tfunc(Core.sizeof, 1, 1, x->Int)
add_tfunc(nfields, 1, 1, x->Int)
add_tfunc(_expr, 1, IInf, (args...)->Expr)
add_tfunc(method_exists, 2, 2, cmp_tfunc)
add_tfunc(applicable, 1, IInf, (f, args...)->Bool)
add_tfunc(arraylen, 1, 1, x->Int)
#add_tfunc(arrayref, 2,IInf,(a,i...)->(isa(a,DataType) && a<:Array ?
# a.parameters[1] : Any))
#add_tfunc(arrayset, 3, IInf, (a,v,i...)->a)
Expand Down
11 changes: 11 additions & 0 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,14 @@ function function_module(f, types::ANY)
end
m[1].func.code.module
end

function method_exists(f::ANY, t::ANY)
t = to_tuple_type(t)
if !isa(f,Function)
t = Tuple{isa(f,Type) ? Type{f} : typeof(f), t.parameters...}
f = call
elseif !isgeneric(f)
throw(ArgumentError("argument is not a generic function"))
end
return ccall(:jl_method_exists, Cint, (Any, Any), f.env, t) != 0
end
2 changes: 1 addition & 1 deletion base/sysimg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Core.Intrinsics.ccall

baremodule Base

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

Expand Down
7 changes: 0 additions & 7 deletions src/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -404,13 +404,6 @@ DLLEXPORT size_t jl_array_len_(jl_array_t *a)
}
#endif

JL_CALLABLE(jl_f_arraylen)
{
JL_NARGS(arraylen, 1, 1);
JL_TYPECHK(arraylen, array, args[0]);
return jl_box_long(jl_array_len((jl_array_t*)args[0]));
}

JL_CALLABLE(jl_f_arraysize)
{
JL_NARGS(arraysize, 2, 2);
Expand Down
3 changes: 0 additions & 3 deletions src/builtin_proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,17 @@ JL_CALLABLE(jl_f_isa);
JL_CALLABLE(jl_f_typeassert);
JL_CALLABLE(jl_f_apply);
JL_CALLABLE(jl_f_kwcall);
JL_CALLABLE(jl_f_top_eval);
JL_CALLABLE(jl_f_isdefined);
JL_CALLABLE(jl_f_tuple);
JL_CALLABLE(jl_f_svec);
JL_CALLABLE(jl_f_get_field);
JL_CALLABLE(jl_f_set_field);
JL_CALLABLE(jl_f_field_type);
JL_CALLABLE(jl_f_arraylen);
JL_CALLABLE(jl_f_arrayref);
JL_CALLABLE(jl_f_arrayset);
JL_CALLABLE(jl_f_arraysize);
JL_CALLABLE(jl_f_instantiate_type);
JL_CALLABLE(jl_f_typevar);
JL_CALLABLE(jl_f_methodexists);
JL_CALLABLE(jl_f_applicable);
JL_CALLABLE(jl_f_invoke);
JL_CALLABLE(jl_f_new_expr);
Expand Down
70 changes: 18 additions & 52 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,12 @@ JL_CALLABLE(jl_f_kwcall)

extern int jl_lineno;

DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex, int delay_warn)
DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex)
{
return jl_toplevel_eval_in_warn(m, ex, 0);
}

DLLEXPORT jl_value_t *jl_toplevel_eval_in_warn(jl_module_t *m, jl_value_t *ex, int delay_warn)
{
static int jl_warn_on_eval = 0;
int last_delay_warn = jl_warn_on_eval;
Expand Down Expand Up @@ -587,23 +592,6 @@ DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex, int de
return v;
}

JL_CALLABLE(jl_f_top_eval)
{
jl_module_t *m;
jl_value_t *ex;
if (nargs == 1) {
m = jl_main_module;
ex = args[0];
}
else {
JL_NARGS(eval, 2, 2);
JL_TYPECHK(eval, module, args[0]);
m = (jl_module_t*)args[0];
ex = args[1];
}
return jl_toplevel_eval_in(m, ex, 0);
}

JL_CALLABLE(jl_f_isdefined)
{
jl_module_t *m = jl_current_module;
Expand Down Expand Up @@ -1057,29 +1045,6 @@ static void jl_check_type_tuple(jl_value_t *t, jl_sym_t *name, const char *ctx)
jl_type_error_rt(name->name, ctx, (jl_value_t*)jl_type_type, t);
}

JL_CALLABLE(jl_f_methodexists)
{
JL_NARGS(method_exists, 2, 2);
JL_TYPECHK(method_exists, function, args[0]);
if (!jl_is_gf(args[0]))
jl_error("method_exists: not a generic function");
jl_value_t *argtypes = args[1];
JL_GC_PUSH1(&argtypes);
if (jl_is_tuple(args[1])) {
// TODO: maybe deprecation warning, better checking
argtypes = (jl_value_t*)jl_apply_tuple_type_v((jl_value_t**)jl_data_ptr(argtypes),
jl_nfields(argtypes));
}
else {
jl_check_type_tuple(args[1], jl_gf_name(args[0]), "method_exists");
}
jl_value_t *res = jl_method_lookup_by_type(jl_gf_mtable(args[0]),
(jl_tupletype_t*)argtypes,0,0)!=jl_bottom_func ?
jl_true : jl_false;
JL_GC_POP();
return res;
}

JL_CALLABLE(jl_f_applicable)
{
JL_NARGSV(applicable, 1);
Expand Down Expand Up @@ -1228,30 +1193,31 @@ void jl_init_primitives(void)
add_builtin_func("issubtype", jl_f_subtype);
add_builtin_func("isa", jl_f_isa);
add_builtin_func("typeassert", jl_f_typeassert);
add_builtin_func("_apply", jl_f_apply);
add_builtin_func("kwcall", jl_f_kwcall);
add_builtin_func("throw", jl_f_throw);
add_builtin_func("tuple", jl_f_tuple);
add_builtin_func("svec", jl_f_svec);
add_builtin_func("method_exists", jl_f_methodexists);
add_builtin_func("applicable", jl_f_applicable);
add_builtin_func("invoke", jl_f_invoke);
add_builtin_func("eval", jl_f_top_eval);
add_builtin_func("isdefined", jl_f_isdefined);

// functions for internal use
// field access
add_builtin_func("getfield", jl_f_get_field);
add_builtin_func("setfield!", jl_f_set_field);
add_builtin_func("fieldtype", jl_f_field_type);
add_builtin_func("nfields", jl_f_nfields);
add_builtin_func("_expr", jl_f_new_expr);
add_builtin_func("isdefined", jl_f_isdefined);

add_builtin_func("arraylen", jl_f_arraylen);
// array primitives
add_builtin_func("arrayref", jl_f_arrayref);
add_builtin_func("arrayset", jl_f_arrayset);
add_builtin_func("arraysize", jl_f_arraysize);

// method table utils
add_builtin_func("applicable", jl_f_applicable);
add_builtin_func("invoke", jl_f_invoke);

// internal functions
add_builtin_func("apply_type", jl_f_instantiate_type);
add_builtin_func("_apply", jl_f_apply);
add_builtin_func("kwcall", jl_f_kwcall);
add_builtin_func("_expr", jl_f_new_expr);
add_builtin_func("svec", jl_f_svec);

// builtin types
add_builtin("Any", (jl_value_t*)jl_any_type);
Expand Down
14 changes: 0 additions & 14 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2374,17 +2374,6 @@ static bool emit_known_call(jl_cgval_t *ret, jl_value_t *ff,
return true;
}

else if (f->fptr == &jl_f_arraylen && nargs==1) {
jl_value_t *aty = expr_type(args[1], ctx); rt1 = aty;
if (jl_is_array_type(aty)) {
// todo: also allow e.g. Union of several array types
jl_cgval_t arg1 = emit_expr(args[1], ctx);
*ret = mark_julia_type(emit_arraylen(arg1, args[1], ctx), false, jl_long_type);
JL_GC_POP();
return true;
}
}

else if (f->fptr == &jl_f_arraysize && nargs==2) {
jl_value_t *aty = expr_type(args[1], ctx); rt1 = aty;
jl_value_t *ity = expr_type(args[2], ctx); rt2 = ity;
Expand Down Expand Up @@ -5535,17 +5524,14 @@ static void init_julia_llvm_env(Module *m)
builtin_func_map[jl_f_throw] = jlcall_func_to_llvm("jl_f_throw", (void*)&jl_f_throw, m);
builtin_func_map[jl_f_tuple] = jlcall_func_to_llvm("jl_f_tuple", (void*)&jl_f_tuple, m);
builtin_func_map[jl_f_svec] = jlcall_func_to_llvm("jl_f_svec", (void*)&jl_f_svec, m);
builtin_func_map[jl_f_methodexists] = jlcall_func_to_llvm("jl_f_methodexists", (void*)&jl_f_methodexists, m);
builtin_func_map[jl_f_applicable] = jlcall_func_to_llvm("jl_f_applicable", (void*)&jl_f_applicable, m);
builtin_func_map[jl_f_invoke] = jlcall_func_to_llvm("jl_f_invoke", (void*)&jl_f_invoke, m);
builtin_func_map[jl_f_top_eval] = jlcall_func_to_llvm("jl_f_top_eval", (void*)&jl_f_top_eval, m);
builtin_func_map[jl_f_isdefined] = jlcall_func_to_llvm("jl_f_isdefined", (void*)&jl_f_isdefined, m);
builtin_func_map[jl_f_get_field] = jlcall_func_to_llvm("jl_f_get_field", (void*)&jl_f_get_field, m);
builtin_func_map[jl_f_set_field] = jlcall_func_to_llvm("jl_f_set_field", (void*)&jl_f_set_field, m);
builtin_func_map[jl_f_field_type] = jlcall_func_to_llvm("jl_f_field_type", (void*)&jl_f_field_type, m);
builtin_func_map[jl_f_nfields] = jlcall_func_to_llvm("jl_f_nfields", (void*)&jl_f_nfields, m);
builtin_func_map[jl_f_new_expr] = jlcall_func_to_llvm("jl_f_new_expr", (void*)&jl_f_new_expr, m);
builtin_func_map[jl_f_arraylen] = jlcall_func_to_llvm("jl_f_arraylen", (void*)&jl_f_arraylen, m);
builtin_func_map[jl_f_arrayref] = jlcall_func_to_llvm("jl_f_arrayref", (void*)&jl_f_arrayref, m);
builtin_func_map[jl_f_arrayset] = jlcall_func_to_llvm("jl_f_arrayset", (void*)&jl_f_arrayset, m);
builtin_func_map[jl_f_arraysize] = jlcall_func_to_llvm("jl_f_arraysize", (void*)&jl_f_arraysize, m);
Expand Down
10 changes: 4 additions & 6 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,11 @@ static htable_t fptr_to_id;
// (reverse of fptr_to_id)
static jl_fptr_t id_to_fptrs[] = {
NULL, NULL,
jl_f_throw, jl_f_is, jl_f_no_function, jl_f_typeof,
jl_f_subtype, jl_f_isa, jl_f_typeassert, jl_f_apply,
jl_f_top_eval, jl_f_isdefined, jl_f_tuple, jl_f_svec,
jl_f_throw, jl_f_is, jl_f_no_function, jl_f_typeof, jl_f_subtype, jl_f_isa,
jl_f_typeassert, jl_f_apply, jl_f_isdefined, jl_f_tuple, jl_f_svec,
jl_f_get_field, jl_f_set_field, jl_f_field_type, jl_f_nfields,
jl_f_arraylen, jl_f_arrayref, jl_f_arrayset, jl_f_arraysize,
jl_f_instantiate_type, jl_f_kwcall, jl_trampoline,
jl_f_methodexists, jl_f_applicable, jl_f_invoke,
jl_f_arrayref, jl_f_arrayset, jl_f_arraysize, jl_f_instantiate_type,
jl_f_kwcall, jl_trampoline, jl_f_applicable, jl_f_invoke,
jl_apply_generic, jl_unprotect_stack, jl_f_sizeof, jl_f_new_expr,
jl_f_intrinsic_call,
NULL };
Expand Down
7 changes: 6 additions & 1 deletion src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ DLLEXPORT jl_function_t *jl_instantiate_staged(jl_methlist_t *m, jl_tupletype_t
}
ex = oldast;
}
func = (jl_function_t*)jl_toplevel_eval_in(m->func->linfo->module, (jl_value_t*)ex, 1); // 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`
func = (jl_function_t*)jl_toplevel_eval_in_warn(m->func->linfo->module, (jl_value_t*)ex, 1); // 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`
func->linfo->name = m->func->linfo->name;
JL_GC_POP();
return func;
Expand Down Expand Up @@ -1416,6 +1416,11 @@ jl_function_t *jl_method_lookup_by_type(jl_methtable_t *mt, jl_tupletype_t *type
return sf;
}

DLLEXPORT int jl_method_exists(jl_methtable_t *mt, jl_tupletype_t *types)
{
return jl_method_lookup_by_type(mt, types, 0, 0) != jl_bottom_func;
}

jl_function_t *jl_method_lookup(jl_methtable_t *mt, jl_value_t **args, size_t nargs, int cache)
{
jl_function_t *sf = jl_method_table_assoc_exact(mt, args, nargs);
Expand Down
2 changes: 0 additions & 2 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -594,8 +594,6 @@ void _julia_init(JL_IMAGE_SEARCH rel)
if (jl_base_module != NULL) {
jl_add_standard_imports(jl_main_module);
}
// eval() uses Main by default, so Main.eval === Core.eval
jl_module_import(jl_main_module, jl_core_module, jl_symbol("eval"));
jl_current_module = jl_main_module;
jl_root_task->current_module = jl_current_module;

Expand Down
3 changes: 3 additions & 0 deletions src/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,9 @@ static jl_cgval_t emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs,
case ccall: return emit_ccall(args, nargs, ctx);
case cglobal: return emit_cglobal(args, nargs, ctx);
case llvmcall: return emit_llvmcall(args, nargs, ctx);
case arraylen:
return mark_julia_type(emit_arraylen(emit_expr(args[1], ctx), args[1], ctx), false,
jl_long_type);
#if 0 // this section enables runtime-intrinsics (e.g. for testing), and disables their llvm counterparts
default:
int ldepth = ctx->gc.argDepth;
Expand Down
2 changes: 2 additions & 0 deletions src/intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@
ALIAS(ccall, ccall) \
ALIAS(cglobal, cglobal) \
ALIAS(llvmcall, llvmcall) \
/* object access */ \
ADD_I(arraylen, 1) \
/* hidden intrinsics */ \
ADD_HIDDEN(fptoui_auto, 1) \
ADD_HIDDEN(fptosi_auto, 1)
Expand Down
3 changes: 2 additions & 1 deletion src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -1249,7 +1249,8 @@ DLLEXPORT const char *jl_lookup_soname(const char *pfx, size_t n);
// compiler
void jl_compile(jl_function_t *f);
DLLEXPORT jl_value_t *jl_toplevel_eval(jl_value_t *v);
DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex, int delay_warn);
DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex);
DLLEXPORT jl_value_t *jl_toplevel_eval_in_warn(jl_module_t *m, jl_value_t *ex, int delay_warn);
jl_value_t *jl_eval_global_var(jl_module_t *m, jl_sym_t *e);
DLLEXPORT jl_value_t *jl_load(const char *fname, size_t len);
jl_value_t *jl_parse_eval_all(const char *fname, size_t len);
Expand Down
3 changes: 1 addition & 2 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,7 @@ DLLEXPORT jl_value_t *jl_copysign_float(jl_value_t *a, jl_value_t *b);
DLLEXPORT jl_value_t *jl_flipsign_int(jl_value_t *a, jl_value_t *b);

DLLEXPORT jl_value_t *jl_select_value(jl_value_t *isfalse, jl_value_t *a, jl_value_t *b);


DLLEXPORT jl_value_t *jl_arraylen(jl_value_t *a);

#ifdef __cplusplus
}
Expand Down
5 changes: 5 additions & 0 deletions src/runtime_intrinsics.c
Original file line number Diff line number Diff line change
Expand Up @@ -931,3 +931,8 @@ DLLEXPORT jl_value_t *jl_select_value(jl_value_t *isfalse, jl_value_t *a, jl_val
JL_TYPECHK(isfalse, bool, isfalse);
return (isfalse == jl_false ? b : a);
}

DLLEXPORT jl_value_t *jl_arraylen(jl_value_t *a)
{
return jl_box_long(jl_array_len((jl_array_t*)a));

This comment has been minimized.

Copy link
@vtjnash

vtjnash Oct 25, 2015

Member

probably would be best to have a typecheck here that a::Array

This comment has been minimized.

Copy link
@JeffBezanson

JeffBezanson Oct 26, 2015

Author Member

Intrinsics don't generally validate their arguments. This should be handled by the method system where possible.

This comment has been minimized.

Copy link
@vtjnash

vtjnash Oct 26, 2015

Member

"don't generally" isn't necessarily a good policy (#12832). all of the functions in this file (except the one you just added) do full validation of their arguments. the only reason the functions in this file should be called from codegen is to trigger the runtime check if the validity couldn't be statically determined.

This comment has been minimized.

Copy link
@JeffBezanson

JeffBezanson Oct 26, 2015

Author Member

I would say that was a bug in reinterpret, which was not itself an intrinsic at the time. Traditionally, all uses of intrinsics had to be correct; they are not first-class functions and are not considered user-facing. The design is that checks should be done by dispatch or by julia code that prints a friendly error, and intrinsics are the low-level work protected by those checks.

For example, the code in intrinsics.cpp does very few checks, but it checks the number of arguments to an intrinsic and throws the error at compile time, since I saw this as more of an assertion failure. More checks are always good, so I think it's ok to have the checks in this file but they should maybe be assertions instead.

}
2 changes: 0 additions & 2 deletions src/toplevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ jl_module_t *jl_new_main_module(void)
(jl_value_t*)jl_main_module);
jl_current_task->current_module = jl_main_module;

jl_module_import(jl_main_module, jl_core_module, jl_symbol("eval"));

return old_main;
}

Expand Down

0 comments on commit f1664bc

Please sign in to comment.