static Value *runtime_sym_lookup(PointerType *funcptype, char *f_lib, char *f_name, jl_codectx_t *ctx) { // in pseudo-code, this function emits the following: // global uv_lib_t **libptrgv // global void **llvmgv // if (*llvmgv == NULL) { // *llvmgv = jl_load_and_lookup(f_lib, f_name, libptrgv); // } // return (*llvmgv) Constant *initnul = ConstantPointerNull::get((PointerType*)T_pint8); uv_lib_t *libsym = NULL; bool runtime_lib = false; GlobalVariable *libptrgv; #ifdef _OS_WINDOWS_ if ((intptr_t)f_lib == 1) { libptrgv = prepare_global(jlexe_var); libsym = jl_exe_handle; } else if ((intptr_t)f_lib == 2) { libptrgv = prepare_global(jldll_var); libsym = jl_dl_handle; } else #endif if (f_lib == NULL) { libptrgv = prepare_global(jlRTLD_DEFAULT_var); libsym = jl_RTLD_DEFAULT_handle; } else { runtime_lib = true; libptrgv = libMapGV[f_lib]; if (libptrgv == NULL) { libptrgv = new GlobalVariable(*jl_Module, T_pint8, false, GlobalVariable::PrivateLinkage, initnul, f_lib); libMapGV[f_lib] = libptrgv; libsym = get_library(f_lib); assert(libsym != NULL); #ifdef USE_MCJIT llvm_to_jl_value[libptrgv] = libsym; #else *((uv_lib_t**)jl_ExecutionEngine->getPointerToGlobal(libptrgv)) = libsym; #endif } } if (libsym == NULL) { #ifdef USE_MCJIT libsym = (uv_lib_t*)llvm_to_jl_value[libptrgv]; #else libsym = *((uv_lib_t**)jl_ExecutionEngine->getPointerToGlobal(libptrgv)); #endif } assert(libsym != NULL); GlobalVariable *llvmgv = symMapGV[f_name]; if (llvmgv == NULL) { // MCJIT forces this to have external linkage eventually, so we would clobber // the symbol of the actual function. std::string name = f_name; name = "ccall_" + name; llvmgv = new GlobalVariable(*jl_Module, T_pint8, false, GlobalVariable::PrivateLinkage, initnul, name); symMapGV[f_name] = llvmgv; #ifdef USE_MCJIT llvm_to_jl_value[llvmgv] = jl_dlsym_e(libsym, f_name); #else *((void**)jl_ExecutionEngine->getPointerToGlobal(llvmgv)) = jl_dlsym_e(libsym, f_name); #endif } BasicBlock *dlsym_lookup = BasicBlock::Create(getGlobalContext(), "dlsym"), *ccall_bb = BasicBlock::Create(getGlobalContext(), "ccall"); builder.CreateCondBr(builder.CreateICmpNE(builder.CreateLoad(llvmgv), initnul), ccall_bb, dlsym_lookup); ctx->f->getBasicBlockList().push_back(dlsym_lookup); builder.SetInsertPoint(dlsym_lookup); Value *libname; if (runtime_lib) { libname = builder.CreateGlobalStringPtr(f_lib); } else { libname = literal_static_pointer_val(f_lib, T_pint8); } Value *llvmf = builder.CreateCall3(prepare_call(jldlsym_func), libname, builder.CreateGlobalStringPtr(f_name), libptrgv); builder.CreateStore(llvmf, llvmgv); builder.CreateBr(ccall_bb); ctx->f->getBasicBlockList().push_back(ccall_bb); builder.SetInsertPoint(ccall_bb); llvmf = builder.CreateLoad(llvmgv); return builder.CreatePointerCast(llvmf,funcptype); }
static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv, jl_value_t *argex, bool addressOf, int argn, jl_codectx_t *ctx, bool *mightNeedTempSpace, bool *needStackRestore) { Type *vt = jv->getType(); if (ty == jl_pvalue_llvmt) { return boxed(jv,ctx); } else if (ty == vt && !addressOf) { return jv; } else if (vt != jl_pvalue_llvmt) { // argument value is unboxed if (addressOf) { if (ty->isPointerTy() && ty->getContainedType(0)==vt) { // pass the address of an alloca'd thing, not a box // since those are immutable. *needStackRestore = true; Value *slot = builder.CreateAlloca(vt); builder.CreateStore(jv, slot); return builder.CreateBitCast(slot, ty); } } else if ((vt->isIntegerTy() && ty->isIntegerTy()) || (vt->isFloatingPointTy() && ty->isFloatingPointTy()) || (vt->isPointerTy() && ty->isPointerTy())) { if (vt->getPrimitiveSizeInBits() == ty->getPrimitiveSizeInBits()) { return builder.CreateBitCast(jv, ty); } } // error. box for error handling. jv = boxed(jv,ctx); } else if (jl_is_cpointer_type(jt)) { assert(ty->isPointerTy()); jl_value_t *aty = expr_type(argex, ctx); if (jl_is_array_type(aty) && (jl_tparam0(jt) == jl_tparam0(aty) || jl_tparam0(jt) == (jl_value_t*)jl_bottom_type)) { // array to pointer return builder.CreateBitCast(emit_arrayptr(jv), ty); } if (aty == (jl_value_t*)jl_ascii_string_type || aty == (jl_value_t*)jl_utf8_string_type) { return builder.CreateBitCast(emit_arrayptr(emit_nthptr(jv,1,tbaa_const)), ty); } if (jl_is_structtype(aty) && jl_is_leaf_type(aty) && !jl_is_array_type(aty)) { if (!addressOf) { emit_error("ccall: expected & on argument", ctx); return literal_pointer_val(jl_nothing); } return builder.CreateBitCast(emit_nthptr_addr(jv, (size_t)1), ty); // skip type tag field } *mightNeedTempSpace = true; Value *p = builder.CreateCall4(prepare_call(value_to_pointer_func), literal_pointer_val(jl_tparam0(jt)), jv, ConstantInt::get(T_int32, argn), ConstantInt::get(T_int32, (int)addressOf)); return builder.CreateBitCast(p, ty); } else if (jl_is_structtype(jt)) { if (addressOf) jl_error("ccall: unexpected & on argument"); // the only "safe" thing to emit here is the expected struct assert (ty->isStructTy() && (Type*)((jl_datatype_t*)jt)->struct_decl == ty); jl_value_t *aty = expr_type(argex, ctx); if (aty != jt) { std::stringstream msg; msg << "ccall argument "; msg << argn; emit_typecheck(jv, jt, msg.str(), ctx); } //TODO: check instead that prefix matches //if (!jl_is_structtype(aty)) // emit_typecheck(emit_typeof(jv), (jl_value_t*)jl_struct_kind, "ccall: Struct argument called with something that isn't a struct", ctx); // //safe thing would be to also check that jl_typeof(aty)->size > sizeof(ty) here and/or at runtime Value *pjv = builder.CreateBitCast(emit_nthptr_addr(jv, (size_t)1), PointerType::get(ty,0)); return builder.CreateLoad(pjv, false); } else if (jl_is_tuple(jt)) { return emit_unbox(ty,jv,jt); } // TODO: error for & with non-pointer argument type assert(jl_is_bitstype(jt)); std::stringstream msg; msg << "ccall argument "; msg << argn; emit_typecheck(jv, jt, msg.str(), ctx); Value *p = data_pointer(jv); return builder.CreateLoad(builder.CreateBitCast(p, PointerType::get(ty,0)), false); }
void load_file(FILE *fp, char *name, TBOOLEAN can_do_args) { int len; int start, left; int more; int stop = FALSE; lf_push(fp, name, NULL); /* save state for errors and recursion */ do_load_arg_substitution = can_do_args; if (fp == (FILE *) NULL) { os_error(NO_CARET, "Cannot open %s file '%s'", can_do_args ? "call" : "load", name); } else if (fp == stdin) { /* DBT 10-6-98 go interactive if "-" named as load file */ interactive = TRUE; while (!com_line()); } else { call_argc = 0; if (can_do_args) { prepare_call(); lf_head->c_token = c_token; /* update after prepare_call() */ } /* things to do after lf_push */ inline_num = 0; /* go into non-interactive mode during load */ /* will be undone below, or in load_file_error */ interactive = FALSE; while (!stop) { /* read all lines in file */ left = gp_input_line_len; start = 0; more = TRUE; /* read one logical line */ while (more) { if (fgets(&(gp_input_line[start]), left, fp) == (char *) NULL) { stop = TRUE; /* EOF in file */ gp_input_line[start] = '\0'; more = FALSE; } else { inline_num++; len = strlen(gp_input_line) - 1; if (gp_input_line[len] == '\n') { /* remove any newline */ gp_input_line[len] = '\0'; /* Look, len was 1-1 = 0 before, take care here! */ if (len > 0) --len; if (gp_input_line[len] == '\r') { /* remove any carriage return */ gp_input_line[len] = NUL; if (len > 0) --len; } } else if (len + 2 >= left) { extend_input_line(); left = gp_input_line_len - len - 1; start = len + 1; continue; /* don't check for '\' */ } if (gp_input_line[len] == '\\') { /* line continuation */ start = len; left = gp_input_line_len - start; } else { /* EAM May 2011 - handle multi-line bracketed clauses {...}. * Introduces a requirement for scanner.c and scanner.h * This code is redundant with part of do_line(), * but do_line() assumes continuation lines come from stdin. */ /* macros in a clause are problematic, as they are */ /* only expanded once even if the clause is replayed */ string_expand_macros(); /* Strip off trailing comment and count curly braces */ num_tokens = scanner(&gp_input_line, &gp_input_line_len); if (gp_input_line[token[num_tokens].start_index] == '#') { gp_input_line[token[num_tokens].start_index] = NUL; start = token[num_tokens].start_index; left = gp_input_line_len - start; } /* Read additional lines if necessary to complete a * bracketed clause {...} */ if (curly_brace_count < 0) int_error(NO_CARET, "Unexpected }"); if (curly_brace_count > 0) { if (len + 4 > gp_input_line_len) extend_input_line(); strcat(gp_input_line,";\n"); start = strlen(gp_input_line); left = gp_input_line_len - start; continue; } more = FALSE; } } } /* process line */ if (strlen(gp_input_line) > 0) { if (can_do_args) expand_call_args(); screen_ok = FALSE; /* make sure command line is echoed on error */ if (do_line()) stop = TRUE; } } } /* pop state */ (void) lf_pop(); /* also closes file fp */ }
/* * load_file() is called from * (1) the "load" command, no arguments substitution is done * (2) the "call" command, arguments are substituted for $0, $1, etc. * (3) on program entry to load initialization files (acts like "load") * (4) to execute script files given on the command line (acts like "load") * (5) to execute a single script file given with -c (acts like "call") */ void load_file(FILE *fp, char *name, int calltype) { int len; int start, left; int more; int stop = FALSE; /* Provide a user-visible copy of the current line number in the input file */ udvt_entry *gpval_lineno = add_udv_by_name("GPVAL_LINENO"); Ginteger(&gpval_lineno->udv_value, 0); gpval_lineno->udv_undef = FALSE; lf_push(fp, name, NULL); /* save state for errors and recursion */ if (fp == (FILE *) NULL) { int_error(NO_CARET, "Cannot open script file '%s'", name); return; /* won't actually reach here */ } if (fp == stdin) { /* DBT 10-6-98 go interactive if "-" named as load file */ interactive = TRUE; while (!com_line()); (void) lf_pop(); return; } /* We actually will read from a file */ prepare_call(calltype); /* things to do after lf_push */ inline_num = 0; /* go into non-interactive mode during load */ /* will be undone below, or in load_file_error */ interactive = FALSE; while (!stop) { /* read all lines in file */ left = gp_input_line_len; start = 0; more = TRUE; /* read one logical line */ while (more) { if (fgets(&(gp_input_line[start]), left, fp) == (char *) NULL) { stop = TRUE; /* EOF in file */ gp_input_line[start] = '\0'; more = FALSE; } else { inline_num++; gpval_lineno->udv_value.v.int_val = inline_num; /* User visible copy */ len = strlen(gp_input_line) - 1; if (gp_input_line[len] == '\n') { /* remove any newline */ gp_input_line[len] = '\0'; /* Look, len was 1-1 = 0 before, take care here! */ if (len > 0) --len; if (gp_input_line[len] == '\r') { /* remove any carriage return */ gp_input_line[len] = NUL; if (len > 0) --len; } } else if (len + 2 >= left) { extend_input_line(); left = gp_input_line_len - len - 1; start = len + 1; continue; /* don't check for '\' */ } if (gp_input_line[len] == '\\') { /* line continuation */ start = len; left = gp_input_line_len - start; } else { /* EAM May 2011 - handle multi-line bracketed clauses {...}. * Introduces a requirement for scanner.c and scanner.h * This code is redundant with part of do_line(), * but do_line() assumes continuation lines come from stdin. */ /* macros in a clause are problematic, as they are */ /* only expanded once even if the clause is replayed */ string_expand_macros(); /* Strip off trailing comment and count curly braces */ num_tokens = scanner(&gp_input_line, &gp_input_line_len); if (gp_input_line[token[num_tokens].start_index] == '#') { gp_input_line[token[num_tokens].start_index] = NUL; start = token[num_tokens].start_index; left = gp_input_line_len - start; } /* Read additional lines if necessary to complete a * bracketed clause {...} */ if (curly_brace_count < 0) int_error(NO_CARET, "Unexpected }"); if (curly_brace_count > 0) { if ((len + 4) > gp_input_line_len) extend_input_line(); strcat(gp_input_line,";\n"); start = strlen(gp_input_line); left = gp_input_line_len - start; continue; } more = FALSE; } } } /* process line */ if (strlen(gp_input_line) > 0) { #ifdef OLD_STYLE_CALL_ARGS if (calltype == 2 || calltype == 5) expand_call_args(); #endif screen_ok = FALSE; /* make sure command line is echoed on error */ if (do_line()) stop = TRUE; } } /* pop state */ (void) lf_pop(); /* also closes file fp */ }
const Array::Temp Call_stack::unpack(const Raw_string pattern, const Raw_string value) { prepare_call(); int count = unpackstring(const_cast<char*>(pattern.value), const_cast<char*>(pattern.value + pattern.length), const_cast<char*>(value.value), const_cast<char*>(value.value + value.length), value.utf8 && !IN_BYTES ? FLAG_UNPACK_DO_UTF8 : 0); finish_call(); return Array::Temp(interp, av_make(count, SP - count + 1), true); }
int Call_stack::method_call(const char* name, intptr_t flags) { prepare_call(); const int ret = call_method(name, flags); finish_call(); return ret; }
int Call_stack::sub_call(SV* ref, intptr_t flags) { prepare_call(); const int ret = call_sv(ref, flags|G_EVAL); finish_call(); return ret; }
int Call_stack::sub_call(const char* name, intptr_t flags) { prepare_call(); const int ret = call_pv(name, flags|G_EVAL); finish_call(); return ret; }