jl_expr_t *jl_exprn(jl_sym_t *head, size_t n) { jl_array_t *ar = n==0 ? (jl_array_t*)jl_an_empty_cell : jl_alloc_cell_1d(n); JL_GC_PUSH(&ar); jl_expr_t *ex = (jl_expr_t*)alloc_4w(); ex->type = (jl_type_t*)jl_expr_type; ex->head = head; ex->args = ar; ex->etype = (jl_value_t*)jl_any_type; JL_GC_POP(); return ex; }
DLLEXPORT jl_value_t *jl_call1(jl_function_t *f, jl_value_t *a) { jl_value_t *v; JL_TRY { JL_GC_PUSH(&f,&a); v = jl_apply(f, &a, 1); JL_GC_POP(); } JL_CATCH { v = NULL; } return v; }
DLLEXPORT jl_value_t *jl_new_closure_internal(jl_lambda_info_t *li, jl_value_t *env) { assert(jl_is_lambda_info(li)); assert(jl_is_tuple(env)); jl_function_t *f=NULL; // note: env is pushed here to make codegen a little easier JL_GC_PUSH(&f, &env); f = jl_new_closure(li->fptr ? li->fptr : jl_trampoline, env); f->linfo = li; JL_GC_POP(); return (jl_value_t*)f; }
void jl_load(const char *fname) { char *fpath = jl_find_file_in_path(fname); jl_value_t *ast = jl_parse_file(fpath); if (ast == (jl_value_t*)jl_null) { if (fpath != fname) free(fpath); jl_errorf("could not open file %s", fpath); } JL_GC_PUSH(&ast); jl_load_file_expr(fpath, ast); JL_GC_POP(); if (fpath != fname) free(fpath); }
jl_value_t *jl_eval_module_expr(jl_expr_t *ex, int *plineno) { assert(ex->head == module_sym); jl_module_t *last_module = jl_current_module; jl_sym_t *name = (jl_sym_t*)jl_exprarg(ex, 0); if (!jl_is_symbol(name)) { jl_type_error("module", (jl_value_t*)jl_sym_type, (jl_value_t*)name); } if (name == jl_current_module->name) { jl_errorf("module name %s conflicts with enclosing module", name->name); } jl_binding_t *b = jl_get_binding_wr(jl_current_module, name); jl_declare_constant(b); if (b->value != NULL) { JL_PRINTF(JL_STDERR, "Warning: redefinition of module %s ignored\n", name->name); return jl_nothing; } jl_module_t *newm = jl_new_module(name); b->value = (jl_value_t*)newm; if (jl_current_module == jl_core_module && name == jl_symbol("Base")) { // pick up Base module during bootstrap, and stay within it // after loading. jl_base_module = last_module = newm; } JL_GC_PUSH(&last_module); jl_current_module = newm; jl_array_t *exprs = ((jl_expr_t*)jl_exprarg(ex, 1))->args; JL_TRY { for(int i=0; i < exprs->length; i++) { // process toplevel form jl_value_t *form = jl_cellref(exprs, i); if (jl_is_linenode(form)) { if (plineno) *plineno = jl_linenode_line(form); } else { (void)jl_toplevel_eval_flex(form, 0, plineno); } } } JL_CATCH { JL_GC_POP(); jl_current_module = last_module; jl_raise(jl_exception_in_transit); } JL_GC_POP(); jl_current_module = last_module; return jl_nothing; }
// return a new lambda-info that has some extra static parameters // merged in. jl_lambda_info_t *jl_add_static_parameters(jl_lambda_info_t *l, jl_tuple_t *sp) { JL_GC_PUSH(&sp); if (l->sparams->length > 0) sp = jl_tuple_append(sp, l->sparams); jl_lambda_info_t *nli = jl_new_lambda_info(l->ast, sp); nli->name = l->name; nli->fptr = l->fptr; nli->module = l->module; nli->file = l->file; nli->line = l->line; JL_GC_POP(); return nli; }
DLLEXPORT jl_value_t *jl_call2(jl_function_t *f, jl_value_t *a, jl_value_t *b) { jl_value_t *v; JL_TRY { JL_GC_PUSH(&f,&a,&b); jl_value_t *args[2] = {a,b}; v = jl_apply(f, args, 2); JL_GC_POP(); } JL_CATCH { v = NULL; } return v; }
static jl_value_t *R_Julia_MD_NA_Factor(SEXP Var, const char *VarName) { SEXP levels = getAttrib(Var, R_LevelsSymbol); if (levels == R_NilValue) return jl_nothing; //create string array for levels in julia jl_array_t *ret1 = jl_alloc_array_1d(jl_apply_array_type(jl_ascii_string_type, 1), LENGTH(levels)); jl_value_t **retData1 = jl_array_data(ret1); for (size_t i = 0; i < jl_array_len(ret1); i++) if (!IS_ASCII(Var)) retData1[i] = jl_cstr_to_string(translateChar0(STRING_ELT(levels, i))); else retData1[i] = jl_cstr_to_string(CHAR(STRING_ELT(levels, i))); if ((LENGTH(Var)) != 0) { switch (TYPEOF(Var)) { case INTSXP: { jl_array_t *ret = jl_alloc_array_1d(jl_apply_array_type(jl_uint32_type, 1), LENGTH(Var)); JL_GC_PUSH(&ret, &ret1); int *retData = (int *)jl_array_data(ret); for (size_t i = 0; i < jl_array_len(ret); i++) { if (INTEGER(Var)[i] == NA_INTEGER) { //NA in poolarray is 0 retData[i] = 0; } else { retData[i] = INTEGER(Var)[i]; } } JL_GC_POP(); return TransArrayToPoolDataArray(ret, ret1, LENGTH(Var), VarName); break; } default: return (jl_value_t *) jl_nothing; break; }//case end return (jl_value_t *) jl_nothing; }//if length !=0 return (jl_value_t *) jl_nothing; }
void jl_errorf(const char *fmt, ...) { char buf[1024]; va_list args; va_start(args, fmt); int nc = vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); if (jl_errorexception_type == NULL) { JL_PRINTF(JL_STDERR, "%s", &buf); jl_exit(1); } jl_value_t *msg = jl_pchar_to_string(buf, nc); JL_GC_PUSH(&msg); jl_raise(jl_new_struct(jl_errorexception_type, msg)); }
jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_t *bnd, jl_tuple_t *argtypes, jl_function_t *f, jl_tuple_t *t) { jl_value_t *gf; if (bnd) { //jl_declare_constant(bnd); if (bnd->value != NULL && !bnd->constp) { jl_errorf("cannot define function %s; it already has a value", bnd->name->name); } bnd->constp = 1; } if (*bp == NULL) { gf = (jl_value_t*)jl_new_generic_function(name); *bp = gf; } else { gf = *bp; if (!jl_is_gf(gf)) { if (jl_is_struct_type(gf) && ((jl_function_t*)gf)->fptr == jl_f_ctor_trampoline) { jl_add_constructors((jl_struct_type_t*)gf); } if (!jl_is_gf(gf)) { jl_error("invalid method definition: not a generic function"); } } } JL_GC_PUSH(&gf); assert(jl_is_function(f)); assert(jl_is_tuple(argtypes)); assert(jl_is_tuple(t)); jl_check_type_tuple(argtypes, name, "method definition"); for(size_t i=0; i < t->length; i++) { if (!jl_is_typevar(jl_tupleref(t,i))) jl_type_error_rt(name->name, "method definition", (jl_value_t*)jl_tvar_type, jl_tupleref(t,i)); } jl_add_method((jl_function_t*)gf, argtypes, f, t); if (jl_boot_file_loaded && f->linfo && f->linfo->ast && jl_is_expr(f->linfo->ast)) { jl_lambda_info_t *li = f->linfo; li->ast = jl_compress_ast(li, li->ast); } JL_GC_POP(); return gf; }
// load toplevel expressions, from (file ...) void jl_load_file_expr(char *fname, jl_value_t *ast) { jl_array_t *b = ((jl_expr_t*)ast)->args; size_t i; volatile size_t lineno=0; if (((jl_expr_t*)ast)->head == jl_continue_sym) { jl_errorf("syntax error: %s", jl_string_data(jl_exprarg(ast,0))); } char oldcwd[512]; char newcwd[512]; get_cwd(oldcwd, sizeof(oldcwd)); char *sep = strrchr(fname, PATHSEP); if (sep) { size_t n = (sep - fname)+1; if (n > sizeof(newcwd)-1) n = sizeof(newcwd)-1; strncpy(newcwd, fname, n); newcwd[n] = '\0'; set_cwd(newcwd); } JL_TRY { jl_register_toplevel_eh(); // handle syntax error if (((jl_expr_t*)ast)->head == error_sym) { jl_interpret_toplevel_expr(ast); } for(i=0; i < b->length; i++) { // process toplevel form jl_value_t *form = jl_cellref(b, i); if (jl_is_linenode(form)) { lineno = jl_linenode_line(form); } else { (void)jl_toplevel_eval_flex(form, 0, &lineno); } } } JL_CATCH { if (sep) set_cwd(oldcwd); jl_value_t *fn=NULL, *ln=NULL; JL_GC_PUSH(&fn, &ln); fn = jl_pchar_to_string(fname, strlen(fname)); ln = jl_box_long(lineno); jl_raise(jl_new_struct(jl_loaderror_type, fn, ln, jl_exception_in_transit)); } if (sep) set_cwd(oldcwd); }
// 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. DLLEXPORT jl_value_t *jl_prepare_ast(jl_lambda_info_t *li, jl_tuple_t *sparams) { jl_tuple_t *spenv = NULL; jl_value_t *l_ast = li->ast; if (l_ast == NULL) return NULL; jl_value_t *ast = l_ast; JL_GC_PUSH(&spenv, &ast); if (jl_is_tuple(ast)) ast = jl_uncompress_ast((jl_tuple_t*)ast); spenv = jl_tuple_tvars_to_symbols(sparams); ast = copy_ast(ast, sparams); eval_decl_types(jl_lam_vinfo((jl_expr_t*)ast), spenv); eval_decl_types(jl_lam_capt((jl_expr_t*)ast), spenv); JL_GC_POP(); return ast; }
jl_bits_type_t *jl_new_bitstype(jl_value_t *name, jl_tag_type_t *super, jl_tuple_t *parameters, size_t nbits) { jl_bits_type_t *t=NULL; jl_typename_t *tn=NULL; JL_GC_PUSH(&t, &tn); if (!jl_boot_file_loaded && jl_is_symbol(name)) { // hack to avoid making two versions of basic types needed // during bootstrapping if (!strcmp(((jl_sym_t*)name)->name, "Int32")) t = jl_int32_type; else if (!strcmp(((jl_sym_t*)name)->name, "Int64")) t = jl_int64_type; else if (!strcmp(((jl_sym_t*)name)->name, "Bool")) t = jl_bool_type; } int makenew = (t==NULL); if (makenew) { t = (jl_bits_type_t*)newobj((jl_type_t*)jl_bits_kind, BITS_TYPE_NW); if (jl_is_typename(name)) tn = (jl_typename_t*)name; else tn = jl_new_typename((jl_sym_t*)name); t->name = tn; } t->super = super; unbind_tvars(parameters); t->parameters = parameters; if (jl_int32_type != NULL) t->bnbits = jl_box_int32(nbits); else t->bnbits = (jl_value_t*)jl_null; t->nbits = nbits; if (!jl_is_leaf_type((jl_value_t*)t)) t->uid = 0; else if (makenew) t->uid = jl_assign_type_uid(); t->fptr = NULL; t->env = NULL; t->linfo = NULL; if (t->name->primary == NULL) t->name->primary = (jl_value_t*)t; JL_GC_POP(); return t; }
jl_value_t *jl_toplevel_eval_flex(jl_value_t *ex, int fast) { //jl_show(ex); //ios_printf(ios_stdout, "\n"); jl_lambda_info_t *thk; int ewc = 0; if (jl_typeof(ex) != (jl_type_t*)jl_lambda_info_type) { if (jl_is_expr(ex) && eval_with_compiler_p((jl_expr_t*)ex, fast)) { thk = jl_wrap_expr(ex); ewc = 1; } else { return jl_interpret_toplevel_expr(ex); } } else { thk = (jl_lambda_info_t*)ex; ewc = eval_with_compiler_p(jl_lam_body((jl_expr_t*)thk->ast), fast); if (!ewc) { jl_array_t *vinfos = jl_lam_vinfo((jl_expr_t*)thk->ast); int i; for(i=0; i < vinfos->length; i++) { if (jl_vinfo_capt((jl_array_t*)jl_cellref(vinfos,i))) { // interpreter doesn't handle closure environment ewc = 1; break; } } } } jl_value_t *thunk=NULL; jl_function_t *gf=NULL; jl_value_t *result; JL_GC_PUSH(&thunk, &gf, &thk); if (ewc) { thunk = jl_new_closure_internal(thk, (jl_value_t*)jl_null); result = jl_apply((jl_function_t*)thunk, NULL, 0); } else { result = jl_interpret_toplevel_thunk(thk); } JL_GC_POP(); return result; }
DLLEXPORT void jl_eval_user_input(jl_value_t *ast, int show_value) { if (jl_have_event_loop) { // with multi.j loaded the command line input callback can return // before the command finishes running, so we have to // disable rl to prevent the prompt from reappearing too soon. repl_callback_disable(); } JL_GC_PUSH(&ast); assert(ast != NULL); int iserr = 0; again: ; JL_TRY { jl_register_toplevel_eh(); if (have_color) { ios_printf(ios_stdout, jl_color_normal); } if (iserr) { jl_show(jl_exception_in_transit); ios_printf(ios_stdout, "\n"); JL_EH_POP(); break; // leave JL_TRY } jl_value_t *value = jl_toplevel_eval(ast); jl_set_global(jl_system_module, jl_symbol("ans"), value); if (value != (jl_value_t*)jl_nothing && show_value) { if (have_color) { ios_printf(ios_stdout, jl_answer_color()); } repl_show_value(value); ios_printf(ios_stdout, "\n"); } } JL_CATCH { iserr = 1; goto again; } ios_printf(ios_stdout, "\n"); JL_GC_POP(); repl_callback_enable(); }
void jl_add_constructors(jl_struct_type_t *t) { if (t->name == jl_array_typename) { t->fptr = jl_f_no_function; return; } jl_initialize_generic_function((jl_function_t*)t, t->name->name); if (t->ctor_factory == (jl_value_t*)jl_nothing || t->ctor_factory == (jl_value_t*)jl_null) { assert(jl_tuple_len(t->parameters) == 0); } else { assert(jl_tuple_len(t->parameters) > 0); if (t != (jl_struct_type_t*)t->name->primary) { // instantiating assert(jl_is_function(t->ctor_factory)); // add type's static parameters to the ctor factory size_t np = jl_tuple_len(t->parameters); jl_tuple_t *sparams = jl_alloc_tuple_uninit(np*2); jl_function_t *cfactory = NULL; JL_GC_PUSH(&sparams, &cfactory); size_t i; for(i=0; i < np; i++) { jl_tupleset(sparams, i*2+0, jl_tupleref(((jl_struct_type_t*)t->name->primary)->parameters, i)); jl_tupleset(sparams, i*2+1, jl_tupleref(t->parameters, i)); } cfactory = jl_instantiate_method((jl_function_t*)t->ctor_factory, sparams); cfactory->linfo->ast = jl_prepare_ast(cfactory->linfo, cfactory->linfo->sparams); // call user-defined constructor factory on (type,) jl_value_t *cfargs[1] = { (jl_value_t*)t }; jl_apply(cfactory, cfargs, 1); JL_GC_POP(); } } }
// this is a run-time function // warning: cannot allocate memory except using alloc_temp_arg_space extern "C" void *jl_value_to_pointer(jl_value_t *jt, jl_value_t *v, int argn) { if ((jl_value_t*)jl_typeof(v) == jt) { assert(jl_is_bits_type(jt)); size_t osz = jl_bitstype_nbits(jt)/8; return alloc_temp_arg_copy(jl_bits_data(v), osz); } if (((jl_value_t*)jl_uint8_type == jt || (jl_value_t*)jl_int8_type == jt) && jl_is_byte_string(v)) { return jl_string_data(v); } if (jl_is_array(v)) { if (jl_tparam0(jl_typeof(v)) == jt || jt==(jl_value_t*)jl_bottom_type) return ((jl_array_t*)v)->data; if (jl_is_cpointer_type(jt)) { jl_array_t *ar = (jl_array_t*)v; void **temp=(void**)alloc_temp_arg_space(ar->length*sizeof(void*)); size_t i; for(i=0; i < ar->length; i++) { temp[i] = jl_value_to_pointer(jl_tparam0(jt), jl_arrayref(ar, i), argn); } return temp; } } std::map<int, std::string>::iterator it = argNumberStrings.find(argn); if (it == argNumberStrings.end()) { std::stringstream msg; msg << "argument "; msg << argn; argNumberStrings[argn] = msg.str(); it = argNumberStrings.find(argn); } jl_value_t *targ=NULL, *pty=NULL; JL_GC_PUSH(&targ, &pty); targ = (jl_value_t*)jl_tuple1(jt); pty = (jl_value_t*)jl_apply_type((jl_value_t*)jl_pointer_type, (jl_tuple_t*)targ); jl_type_error_rt("ccall", (*it).second.c_str(), pty, v); // doesn't return return (jl_value_t*)jl_null; }
DLLEXPORT jl_value_t *jl_new_closure_internal(jl_lambda_info_t *li, jl_value_t *env) { assert(jl_is_lambda_info(li)); assert(jl_is_tuple(env)); jl_function_t *f=NULL; // note: env is pushed here to make codegen a little easier JL_GC_PUSH(&f, &env); if (li->fptr != NULL) { // function has been compiled f = jl_new_closure(li->fptr, env); } else { f = jl_new_closure(jl_trampoline, NULL); f->env = (jl_value_t*)jl_tuple2((jl_value_t*)f, env); } f->linfo = li; JL_GC_POP(); return (jl_value_t*)f; }
static jl_module_t *eval_import_path_(jl_array_t *args, int retrying) { // in A.B.C, first find a binding for A in the chain of module scopes // following parent links. then evaluate the rest of the path from there. jl_sym_t *var = (jl_sym_t*)jl_cellref(args,0); assert(jl_is_symbol(var)); jl_module_t *m = jl_current_module; while (1) { jl_binding_t *mb = jl_get_binding(m, var); if (mb != NULL) { if (mb->value == NULL || !jl_is_module(mb->value)) jl_errorf("invalid module path"); m = (jl_module_t*)mb->value; break; } if (m == jl_main_module) { if (!retrying) { if (require_func == NULL && jl_base_module != NULL) require_func = jl_get_global(jl_base_module, jl_symbol("require")); if (require_func != NULL) { jl_value_t *str = jl_cstr_to_string(var->name); JL_GC_PUSH(&str); jl_apply((jl_function_t*)require_func, &str, 1); JL_GC_POP(); return eval_import_path_(args, 1); } } jl_errorf("in module path: %s not defined", var->name); } m = m->parent; } for(size_t i=1; i < jl_array_len(args)-1; i++) { jl_value_t *s = jl_cellref(args,i); assert(jl_is_symbol(s)); m = (jl_module_t*)jl_eval_global_var(m, (jl_sym_t*)s); if (!jl_is_module(m)) jl_errorf("invalid import statement"); } return m; }
// this is for parsing one expression out of a string, keeping track of // the current position. DLLEXPORT jl_value_t *jl_parse_string(const char *str, int pos0, int greedy) { value_t s = cvalue_static_cstring(str); value_t p = fl_applyn(3, symbol_value(symbol("jl-parse-one-string")), s, fixnum(pos0), greedy?FL_T:FL_F); jl_value_t *expr=NULL, *pos1=NULL; JL_GC_PUSH(&expr, &pos1); value_t e = car_(p); if (e == FL_T || e == FL_F || e == FL_EOF) { expr = (jl_value_t*)jl_null; } else { expr = scm_to_julia(e); } pos1 = jl_box_long(toulong(cdr_(p),"parse")); jl_value_t *result = (jl_value_t*)jl_tuple2(expr, pos1); JL_GC_POP(); return result; }
DLLEXPORT void *jl_eval_string(char *str) { #ifdef COPY_STACKS jl_root_task->stackbase = (char*)&str; if (jl_setjmp(jl_root_task->base_ctx, 1)) { jl_switch_stack(jl_current_task, jl_jmp_target); } #endif jl_value_t *r; JL_TRY { jl_value_t *ast = jl_parse_input_line(str); JL_GC_PUSH(&ast); r = jl_toplevel_eval(ast); JL_GC_POP(); } JL_CATCH { //jl_show(jl_stderr_obj(), jl_exception_in_transit); r = NULL; } return r; }
/* warn about ambiguous method priorities the relative priority of A and B is ambiguous if !subtype(A,B) && !subtype(B,A) && no corresponding tuple elements are disjoint. for example, (AbstractArray, AbstractMatrix) and (AbstractMatrix, AbstractArray) are ambiguous. however, (AbstractArray, AbstractMatrix, Foo) and (AbstractMatrix, AbstractArray, Bar) are fine since Foo and Bar are disjoint, so there would be no confusion over which one to call. There is also this kind of ambiguity: foo{T,S}(T, S) vs. foo(Any,Any) In this case jl_types_equal() is true, but one is jl_type_morespecific or jl_type_match_morespecific than the other. To check this, jl_types_equal_generic needs to be more sophisticated so (T,T) is not equivalent to (Any,Any). (TODO) */ static void check_ambiguous(jl_methlist_t *ml, jl_tuple_t *type, jl_tuple_t *sig, jl_sym_t *fname) { // we know !jl_args_morespecific(type, sig) if ((type->length==sig->length || (type->length==sig->length+1 && is_va_tuple(type)) || (type->length+1==sig->length && is_va_tuple(sig))) && !jl_args_morespecific((jl_value_t*)sig, (jl_value_t*)type)) { jl_value_t *isect = jl_type_intersection((jl_value_t*)type, (jl_value_t*)sig); if (isect == (jl_value_t*)jl_bottom_type) return; JL_GC_PUSH(&isect); jl_methlist_t *l = ml; while (l != NULL) { if (sigs_eq(isect, (jl_value_t*)l->sig)) goto done_chk_amb; // ok, intersection is covered l = l->next; } char *n = fname->name; jl_value_t *errstream = jl_get_global(jl_system_module, jl_symbol("stderr_stream")); JL_TRY { if (errstream) jl_set_current_output_stream_obj(errstream); ios_t *s = jl_current_output_stream(); ios_printf(s, "Warning: New definition %s", n); jl_show((jl_value_t*)type); ios_printf(s, " is ambiguous with %s", n); jl_show((jl_value_t*)sig); ios_printf(s, ".\n Make sure %s", n); jl_show(isect); ios_printf(s, " is defined first.\n"); } JL_CATCH { jl_raise(jl_exception_in_transit); } done_chk_amb: JL_GC_POP(); }
jl_tag_type_t *jl_new_tagtype(jl_value_t *name, jl_tag_type_t *super, jl_tuple_t *parameters) { jl_typename_t *tn=NULL; JL_GC_PUSH(&tn); if (jl_is_typename(name)) tn = (jl_typename_t*)name; else tn = jl_new_typename((jl_sym_t*)name); jl_tag_type_t *t = (jl_tag_type_t*)newobj((jl_type_t*)jl_tag_kind, TAG_TYPE_NW); t->name = tn; t->super = super; t->parameters = parameters; t->fptr = NULL; t->env = NULL; t->linfo = NULL; if (t->name->primary == NULL) t->name->primary = (jl_value_t*)t; JL_GC_POP(); return t; }
// repeatedly call jl_parse_next and eval everything void jl_parse_eval_all(char *fname) { //ios_printf(ios_stderr, "***** loading %s\n", fname); int last_lineno = jl_lineno; jl_lineno=0; jl_value_t *fn=NULL, *ln=NULL, *form=NULL; JL_GC_PUSH(&fn, &ln, &form); JL_TRY { jl_register_toplevel_eh(); // handle syntax error while (1) { form = jl_parse_next(); if (form == NULL) break; if (jl_is_expr(form)) { if (((jl_expr_t*)form)->head == jl_continue_sym) { jl_errorf("syntax error: %s", jl_string_data(jl_exprarg(form,0))); } if (((jl_expr_t*)form)->head == error_sym) { jl_interpret_toplevel_expr(form); } } (void)jl_toplevel_eval_flex(form, 1); } } JL_CATCH { jl_stop_parsing(); fn = jl_pchar_to_string(fname, strlen(fname)); ln = jl_box_long(jl_lineno); jl_lineno = last_lineno; jl_raise(jl_new_struct(jl_loaderror_type, fn, ln, jl_exception_in_transit)); } jl_stop_parsing(); jl_lineno = last_lineno; JL_GC_POP(); }
// wrap expr in a thunk AST jl_lambda_info_t *jl_wrap_expr(jl_value_t *expr) { // `(lambda () (() () ()) ,expr) jl_expr_t *le=NULL, *bo=NULL; jl_value_t *vi=NULL; jl_value_t *mt = jl_an_empty_cell; JL_GC_PUSH(&le, &vi, &bo); le = jl_exprn(lambda_sym, 3); jl_cellset(le->args, 0, mt); vi = (jl_value_t*)jl_alloc_cell_1d(3); jl_cellset(vi, 0, mt); jl_cellset(vi, 1, mt); jl_cellset(vi, 2, mt); jl_cellset(le->args, 1, vi); if (!jl_is_expr(expr) || ((jl_expr_t*)expr)->head != body_sym) { bo = jl_exprn(body_sym, 1); jl_cellset(bo->args, 0, (jl_value_t*)jl_exprn(return_sym, 1)); jl_cellset(((jl_expr_t*)jl_exprarg(bo,0))->args, 0, expr); expr = (jl_value_t*)bo; } jl_cellset(le->args, 2, expr); jl_lambda_info_t *li = jl_new_lambda_info((jl_value_t*)le, jl_null); JL_GC_POP(); return li; }
jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_t *bnd, jl_tuple_t *argtypes, jl_function_t *f) { jl_value_t *gf; if (bnd) { jl_declare_constant(bnd); } if (*bp == NULL) { gf = (jl_value_t*)jl_new_generic_function(name); *bp = gf; } else { gf = *bp; if (!jl_is_gf(gf)) jl_error("in method definition: not a generic function"); } JL_GC_PUSH(&gf); assert(jl_is_function(f)); assert(jl_is_tuple(argtypes)); check_type_tuple(argtypes, name, "method definition"); jl_add_method((jl_function_t*)gf, argtypes, f); JL_GC_POP(); return gf; }
jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_t *bnd, jl_tuple_t *argtypes, jl_function_t *f, jl_tuple_t *t) { jl_value_t *gf; if (bnd) { jl_declare_constant(bnd); } if (*bp == NULL) { gf = (jl_value_t*)jl_new_generic_function(name); *bp = gf; } else { gf = *bp; if (!jl_is_gf(gf)) { if (jl_is_struct_type(gf) && ((jl_function_t*)gf)->fptr == jl_f_ctor_trampoline) { jl_add_constructors((jl_struct_type_t*)gf); } if (!jl_is_gf(gf)) { jl_error("invalid method definition: not a generic function"); } } } JL_GC_PUSH(&gf); assert(jl_is_function(f)); assert(jl_is_tuple(argtypes)); jl_check_type_tuple(argtypes, name, "method definition"); jl_add_method((jl_function_t*)gf, argtypes, f, t); if (jl_boot_file_loaded && f->linfo && f->linfo->ast && jl_is_expr(f->linfo->ast)) { jl_lambda_info_t *li = f->linfo; li->ast = jl_compress_ast(li, li->ast); } JL_GC_POP(); return gf; }
// ccall(pointer, rettype, (argtypes...), args...) static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) { JL_NARGSV(ccall, 3); jl_value_t *ptr=NULL, *rt=NULL, *at=NULL; Value *jl_ptr=NULL; JL_GC_PUSH(&ptr, &rt, &at); ptr = static_eval(args[1], ctx, true); if (ptr == NULL) { jl_value_t *ptr_ty = expr_type(args[1], ctx); Value *arg1 = emit_unboxed(args[1], ctx); if (!jl_is_cpointer_type(ptr_ty)) { emit_typecheck(arg1, (jl_value_t*)jl_voidpointer_type, "ccall: function argument not a pointer or valid constant", ctx); } jl_ptr = emit_unbox(T_size, T_psize, arg1); } rt = jl_interpret_toplevel_expr_in(ctx->module, args[2], &jl_tupleref(ctx->sp,0), jl_tuple_len(ctx->sp)/2); if (jl_is_tuple(rt)) { std::string msg = "in " + ctx->funcName + ": ccall: missing return type"; jl_error(msg.c_str()); } at = jl_interpret_toplevel_expr_in(ctx->module, args[3], &jl_tupleref(ctx->sp,0), jl_tuple_len(ctx->sp)/2); void *fptr=NULL; char *f_name=NULL, *f_lib=NULL; if (ptr != NULL) { if (jl_is_tuple(ptr) && jl_tuple_len(ptr)==1) { ptr = jl_tupleref(ptr,0); } if (jl_is_symbol(ptr)) f_name = ((jl_sym_t*)ptr)->name; else if (jl_is_byte_string(ptr)) f_name = jl_string_data(ptr); if (f_name != NULL) { // just symbol, default to JuliaDLHandle #ifdef __WIN32__ fptr = jl_dlsym_e(jl_dl_handle, f_name); if (!fptr) { //TODO: when one of these succeeds, store the f_lib name (and clear fptr) fptr = jl_dlsym_e(jl_kernel32_handle, f_name); if (!fptr) { fptr = jl_dlsym_e(jl_ntdll_handle, f_name); if (!fptr) { fptr = jl_dlsym_e(jl_crtdll_handle, f_name); if (!fptr) { fptr = jl_dlsym(jl_winsock_handle, f_name); } } } } else { // available in process symbol table fptr = NULL; } #else // will look in process symbol table #endif } else if (jl_is_cpointer_type(jl_typeof(ptr))) { fptr = *(void**)jl_bits_data(ptr); } else if (jl_is_tuple(ptr) && jl_tuple_len(ptr)>1) { jl_value_t *t0 = jl_tupleref(ptr,0); jl_value_t *t1 = jl_tupleref(ptr,1); if (jl_is_symbol(t0)) f_name = ((jl_sym_t*)t0)->name; else if (jl_is_byte_string(t0)) f_name = jl_string_data(t0); else JL_TYPECHK(ccall, symbol, t0); if (jl_is_symbol(t1)) f_lib = ((jl_sym_t*)t1)->name; else if (jl_is_byte_string(t1)) f_lib = jl_string_data(t1); else JL_TYPECHK(ccall, symbol, t1); } else { JL_TYPECHK(ccall, pointer, ptr); } } if (f_name == NULL && fptr == NULL && jl_ptr == NULL) { JL_GC_POP(); emit_error("ccall: null function pointer", ctx); return literal_pointer_val(jl_nothing); } JL_TYPECHK(ccall, type, rt); JL_TYPECHK(ccall, tuple, at); JL_TYPECHK(ccall, type, at); jl_tuple_t *tt = (jl_tuple_t*)at; std::vector<Type *> fargt(0); std::vector<Type *> fargt_sig(0); Type *lrt = julia_type_to_llvm(rt); if (lrt == NULL) { JL_GC_POP(); return literal_pointer_val(jl_nothing); } size_t i; bool haspointers = false; bool isVa = false; size_t nargt = jl_tuple_len(tt); std::vector<AttributeWithIndex> attrs; for(i=0; i < nargt; i++) { jl_value_t *tti = jl_tupleref(tt,i); if (jl_is_seq_type(tti)) { isVa = true; tti = jl_tparam0(tti); } if (jl_is_bits_type(tti)) { // see pull req #978. need to annotate signext/zeroext for // small integer arguments. jl_bits_type_t *bt = (jl_bits_type_t*)tti; if (bt->nbits < 32) { if (jl_signed_type == NULL) { jl_signed_type = jl_get_global(jl_core_module,jl_symbol("Signed")); } #ifdef LLVM32 Attributes::AttrVal av; if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0)) av = Attributes::SExt; else av = Attributes::ZExt; attrs.push_back(AttributeWithIndex::get(getGlobalContext(), i+1, ArrayRef<Attributes::AttrVal>(&av, 1))); #else Attribute::AttrConst av; if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0)) av = Attribute::SExt; else av = Attribute::ZExt; attrs.push_back(AttributeWithIndex::get(i+1, av)); #endif } } Type *t = julia_type_to_llvm(tti); if (t == NULL) { JL_GC_POP(); return literal_pointer_val(jl_nothing); } fargt.push_back(t); if (!isVa) fargt_sig.push_back(t); } // check for calling convention specifier CallingConv::ID cc = CallingConv::C; jl_value_t *last = args[nargs]; if (jl_is_expr(last)) { jl_sym_t *lhd = ((jl_expr_t*)last)->head; if (lhd == jl_symbol("stdcall")) { cc = CallingConv::X86_StdCall; nargs--; } else if (lhd == jl_symbol("cdecl")) { cc = CallingConv::C; nargs--; } else if (lhd == jl_symbol("fastcall")) { cc = CallingConv::X86_FastCall; nargs--; } else if (lhd == jl_symbol("thiscall")) { cc = CallingConv::X86_ThisCall; nargs--; } } if ((!isVa && jl_tuple_len(tt) != (nargs-2)/2) || ( isVa && jl_tuple_len(tt)-1 > (nargs-2)/2)) jl_error("ccall: wrong number of arguments to C function"); // some special functions if (fptr == &jl_array_ptr) { Value *ary = emit_expr(args[4], ctx); JL_GC_POP(); return mark_julia_type(builder.CreateBitCast(emit_arrayptr(ary),lrt), rt); } // see if there are & arguments for(i=4; i < nargs+1; i+=2) { jl_value_t *argi = args[i]; if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) { haspointers = true; break; } } // make LLVM function object for the target Value *llvmf; FunctionType *functype = FunctionType::get(lrt, fargt_sig, isVa); if (jl_ptr != NULL) { null_pointer_check(jl_ptr,ctx); Type *funcptype = PointerType::get(functype,0); llvmf = builder.CreateIntToPtr(jl_ptr, funcptype); } else if (fptr != NULL) { Type *funcptype = PointerType::get(functype,0); llvmf = literal_pointer_val(fptr, funcptype); } else { void *symaddr; if (f_lib != NULL) symaddr = add_library_sym(f_name, f_lib); else symaddr = sys::DynamicLibrary::SearchForAddressOfSymbol(f_name); if (symaddr == NULL) { JL_GC_POP(); std::stringstream msg; msg << "ccall: could not find function "; msg << f_name; if (f_lib != NULL) { msg << " in library "; msg << f_lib; } emit_error(msg.str(), ctx); return literal_pointer_val(jl_nothing); } llvmf = jl_Module->getOrInsertFunction(f_name, functype); } // save temp argument area stack pointer Value *saveloc=NULL; Value *stacksave=NULL; if (haspointers) { // TODO: inline this saveloc = builder.CreateCall(save_arg_area_loc_func); stacksave = builder.CreateCall(Intrinsic::getDeclaration(jl_Module, Intrinsic::stacksave)); } // emit arguments Value *argvals[(nargs-3)/2]; int last_depth = ctx->argDepth; int nargty = jl_tuple_len(tt); for(i=4; i < nargs+1; i+=2) { int ai = (i-4)/2; jl_value_t *argi = args[i]; bool addressOf = false; if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) { addressOf = true; argi = jl_exprarg(argi,0); } Type *largty; jl_value_t *jargty; if (isVa && ai >= nargty-1) { largty = fargt[nargty-1]; jargty = jl_tparam0(jl_tupleref(tt,nargty-1)); } else { largty = fargt[ai]; jargty = jl_tupleref(tt,ai); } Value *arg; if (largty == jl_pvalue_llvmt) { arg = emit_expr(argi, ctx, true); } else { arg = emit_unboxed(argi, ctx); if (jl_is_bits_type(expr_type(argi, ctx))) { if (addressOf) arg = emit_unbox(largty->getContainedType(0), largty, arg); else arg = emit_unbox(largty, PointerType::get(largty,0), arg); } } /* #ifdef JL_GC_MARKSWEEP // make sure args are rooted if (largty->isPointerTy() && (largty == jl_pvalue_llvmt || !jl_is_bits_type(expr_type(args[i], ctx)))) { make_gcroot(boxed(arg), ctx); } #endif */ argvals[ai] = julia_to_native(largty, jargty, arg, argi, addressOf, ai+1, ctx); } // the actual call Value *result = builder.CreateCall(llvmf, ArrayRef<Value*>(&argvals[0],(nargs-3)/2)); if (cc != CallingConv::C) ((CallInst*)result)->setCallingConv(cc); #ifdef LLVM32 ((CallInst*)result)->setAttributes(AttrListPtr::get(getGlobalContext(), ArrayRef<AttributeWithIndex>(attrs))); #else ((CallInst*)result)->setAttributes(AttrListPtr::get(attrs.data(),attrs.size())); #endif // restore temp argument area stack pointer if (haspointers) { assert(saveloc != NULL); builder.CreateCall(restore_arg_area_loc_func, saveloc); assert(stacksave != NULL); builder.CreateCall(Intrinsic::getDeclaration(jl_Module, Intrinsic::stackrestore), stacksave); } ctx->argDepth = last_depth; if (0) { // Enable this to turn on SSPREQ (-fstack-protector) on the function containing this ccall #ifdef LLVM32 ctx->f->addFnAttr(Attributes::StackProtectReq); #else ctx->f->addFnAttr(Attribute::StackProtectReq); #endif } JL_GC_POP(); if (lrt == T_void) return literal_pointer_val((jl_value_t*)jl_nothing); return mark_julia_type(result, rt); }
jl_value_t *jl_eval_module_expr(jl_expr_t *ex, int *plineno) { assert(ex->head == module_sym); jl_module_t *last_module = jl_current_module; jl_sym_t *name = (jl_sym_t*)jl_exprarg(ex, 0); if (!jl_is_symbol(name)) { jl_type_error("module", (jl_value_t*)jl_sym_type, (jl_value_t*)name); } jl_module_t *parent_module; if (jl_current_module == jl_core_module || jl_current_module == jl_main_module) { parent_module = jl_root_module; } else { parent_module = jl_current_module; } jl_binding_t *b = jl_get_binding_wr(parent_module, name); jl_declare_constant(b); if (b->value != NULL) { JL_PRINTF(JL_STDERR, "Warning: replacing module %s\n", name->name); } jl_module_t *newm = jl_new_module(name); newm->parent = (jl_value_t*)parent_module; b->value = (jl_value_t*)newm; if (parent_module == jl_root_module && name == jl_symbol("Base") && jl_base_module == NULL) { // pick up Base module during bootstrap jl_base_module = newm; } JL_GC_PUSH(&last_module); jl_current_module = newm; jl_array_t *exprs = ((jl_expr_t*)jl_exprarg(ex, 1))->args; JL_TRY { for(int i=0; i < exprs->length; i++) { // process toplevel form jl_value_t *form = jl_cellref(exprs, i); if (jl_is_linenode(form)) { if (plineno) *plineno = jl_linenode_line(form); } else { (void)jl_toplevel_eval_flex(form, 1, plineno); } } } JL_CATCH { JL_GC_POP(); jl_current_module = last_module; jl_raise(jl_exception_in_transit); } JL_GC_POP(); jl_current_module = last_module; size_t i; void **table = newm->bindings.table; for(i=1; i < newm->bindings.size; i+=2) { if (table[i] != HT_NOTFOUND) { jl_binding_t *b = (jl_binding_t*)table[i]; // remove non-exported macros if (b->name->name[0]=='@' && !b->exportp) b->value = NULL; // error for unassigned exports /* if (b->exportp && b->owner==newm && b->value==NULL) jl_errorf("identifier %s exported from %s is not initialized", b->name->name, newm->name->name); */ } } return jl_nothing; }
jl_value_t *jl_toplevel_eval_flex(jl_value_t *e, int fast, int *plineno) { //jl_show(ex); //JL_PRINTF(JL_STDOUT, "\n"); if (!jl_is_expr(e)) return jl_interpret_toplevel_expr(e); jl_expr_t *ex = (jl_expr_t*)e; if (ex->head == null_sym || ex->head == error_sym) { // expression types simple enough not to need expansion return jl_interpret_toplevel_expr(e); } if (ex->head == module_sym) { return jl_eval_module_expr(ex, plineno); } // handle import, export toplevel-only forms if (ex->head == importall_sym) { jl_module_t *m = eval_import_path(ex->args); jl_sym_t *name = (jl_sym_t*)jl_cellref(ex->args, ex->args->length-1); assert(jl_is_symbol(name)); m = (jl_module_t*)jl_eval_global_var(m, name); if (!jl_is_module(m)) jl_errorf("invalid import statement"); jl_module_importall(jl_current_module, m); return jl_nothing; } if (ex->head == import_sym) { jl_module_t *m = eval_import_path(ex->args); jl_sym_t *name = (jl_sym_t*)jl_cellref(ex->args, ex->args->length-1); assert(jl_is_symbol(name)); jl_module_import(jl_current_module, m, name); return jl_nothing; } if (ex->head == export_sym) { for(size_t i=0; i < ex->args->length; i++) { jl_module_export(jl_current_module, (jl_sym_t*)jl_cellref(ex->args, i)); } return jl_nothing; } jl_value_t *thunk=NULL; jl_value_t *result; jl_lambda_info_t *thk=NULL; int ewc = 0; JL_GC_PUSH(&thunk, &thk, &ex); if (ex->head != body_sym && ex->head != thunk_sym) { // not yet expanded ex = (jl_expr_t*)jl_expand(e); } if (jl_is_expr(ex) && ex->head == thunk_sym) { thk = (jl_lambda_info_t*)jl_exprarg(ex,0); assert(jl_is_lambda_info(thk)); ewc = jl_eval_with_compiler_p(jl_lam_body((jl_expr_t*)thk->ast), fast); if (!ewc) { jl_array_t *vinfos = jl_lam_vinfo((jl_expr_t*)thk->ast); int i; for(i=0; i < vinfos->length; i++) { if (jl_vinfo_capt((jl_array_t*)jl_cellref(vinfos,i))) { // interpreter doesn't handle closure environment ewc = 1; break; } } } } else { if (jl_is_expr(ex) && jl_eval_with_compiler_p((jl_expr_t*)ex, fast)) { thk = jl_wrap_expr((jl_value_t*)ex); ewc = 1; } else { result = jl_interpret_toplevel_expr((jl_value_t*)ex); JL_GC_POP(); return result; } } if (ewc) { thunk = (jl_value_t*)jl_new_closure(NULL, (jl_value_t*)jl_null, thk); if (!jl_in_inference) { jl_type_infer(thk, jl_tuple_type, thk); } result = jl_apply((jl_function_t*)thunk, NULL, 0); } else { result = jl_interpret_toplevel_thunk(thk); } JL_GC_POP(); return result; }