DLLEXPORT int jl_putc(unsigned char c, uv_stream_t *stream) { if (stream!=0) { if (stream->type<UV_HANDLE_TYPE_MAX) { //is uv handle if (stream->type == UV_FILE) { JL_SIGATOMIC_BEGIN(); jl_uv_file_t *file = (jl_uv_file_t *)stream; // Do a blocking write for now uv_fs_t req; int err = uv_fs_write(file->loop, &req, file->file, &c, 1, -1, NULL); JL_SIGATOMIC_END(); return err ? 0 : 1; } else { JL_SIGATOMIC_BEGIN(); uv_write_t *uvw = malloc(sizeof(uv_write_t) + 1); char *data = (char*)(uvw+1); *data = c; uv_buf_t buf[] = {{.base = data,.len=1}}; uvw->data = data; int err = uv_write(uvw,stream,buf,1,&jl_free_buffer); JL_SIGATOMIC_END(); return err ? 0 : 1; } } else {
DLLEXPORT int jl_putc(char c, uv_stream_t *stream) { int err; if (stream!=0) { if (stream->type<UV_HANDLE_TYPE_MAX) { //is uv handle if (stream->type == UV_FILE) { JL_SIGATOMIC_BEGIN(); jl_uv_file_t *file = (jl_uv_file_t *)stream; // Do a blocking write for now uv_fs_t req; uv_buf_t buf[1]; buf[0].base = &c; buf[0].len = 1; err = uv_fs_write(file->loop, &req, file->file, buf, 1, -1, NULL); JL_SIGATOMIC_END(); return err ? 0 : 1; } else { uv_write_t *uvw = (uv_write_t*)malloc(sizeof(uv_write_t)+1); err = jl_write_copy(stream,(char*)&c,1,uvw, (void*)&jl_uv_writecb); if (err < 0) { free(uvw); return 0; } return 1; } } else { ios_t *handle = (ios_t*)stream; return ios_putc(c,handle); } } return 0; }
DLLEXPORT size_t jl_write(uv_stream_t *stream, const char *str, size_t n) { int err; //TODO: BAD!! Needed because Julia can't yet detect null stdio if (stream == 0) return 0; if (stream->type<UV_HANDLE_TYPE_MAX) { //is uv handle if (stream->type == UV_FILE) { JL_SIGATOMIC_BEGIN(); jl_uv_file_t *file = (jl_uv_file_t *)stream; // Do a blocking write for now uv_fs_t req; uv_buf_t buf[1]; buf[0].base = (char*)str; buf[0].len = n; err = uv_fs_write(file->loop, &req, file->file, buf, 1, -1, NULL); JL_SIGATOMIC_END(); return err ? 0 : n; } else { uv_write_t *uvw = (uv_write_t*)malloc(sizeof(uv_write_t)+n); err = jl_write_copy(stream,str,n,uvw, (void*)&jl_uv_writecb); if (err < 0) { free(uvw); return 0; } return n; } } else { ios_t *handle = (ios_t*)stream; return ios_write(handle,str,n); } }
JL_DLLEXPORT void jl_sigatomic_end(void) { jl_ptls_t ptls = jl_get_ptls_states(); if (ptls->defer_signal == 0) jl_error("sigatomic_end called in non-sigatomic region"); JL_SIGATOMIC_END(); }
void jl_gc_collect(void) { size_t actual_allocd = allocd_bytes; total_allocd_bytes += allocd_bytes; allocd_bytes = 0; if (is_gc_enabled) { JL_SIGATOMIC_BEGIN(); jl_in_gc = 1; #if defined(GCTIME) || defined(GC_FINAL_STATS) double t0 = clock_now(); #endif gc_mark(); #ifdef GCTIME JL_PRINTF(JL_STDERR, "mark time %.3f ms\n", (clock_now()-t0)*1000); #endif #if defined(MEMPROFILE) all_pool_stats(); big_obj_stats(); #endif #ifdef GCTIME t0 = clock_now(); #endif sweep_weak_refs(); gc_sweep(); #ifdef GCTIME JL_PRINTF(JL_STDERR, "sweep time %.3f ms\n", (clock_now()-t0)*1000); #endif int nfinal = to_finalize.len; run_finalizers(); jl_in_gc = 0; JL_SIGATOMIC_END(); #if defined(GC_FINAL_STATS) total_gc_time += (clock_now()-t0); total_freed_bytes += freed_bytes; #endif #ifdef OBJPROFILE print_obj_profile(); htable_reset(&obj_counts, 0); #endif // tune collect interval based on current live ratio #if defined(MEMPROFILE) jl_printf(JL_STDERR, "allocd %ld, freed %ld, interval %ld, ratio %.2f\n", actual_allocd, freed_bytes, collect_interval, (double)freed_bytes/(double)actual_allocd); #endif if (freed_bytes < (7*(actual_allocd/10))) { if (collect_interval <= 2*(max_collect_interval/5)) collect_interval = 5*(collect_interval/2); } else { collect_interval = default_collect_interval; } freed_bytes = 0; // if a lot of objects were finalized, re-run GC to finish freeing // their storage if possible. if (nfinal > 100000) jl_gc_collect(); } }
void jl_gc_collect(void) { allocd_bytes = 0; if (is_gc_enabled) { JL_SIGATOMIC_BEGIN(); #ifdef GCTIME double t0 = clock_now(); #endif gc_mark(); #ifdef GCTIME ios_printf(ios_stderr, "mark time %.3f ms\n", (clock_now()-t0)*1000); #endif #if defined(MEMPROFILE) all_pool_stats(); big_obj_stats(); #endif #ifdef GCTIME t0 = clock_now(); #endif sweep_weak_refs(); gc_sweep(); #ifdef GCTIME ios_printf(ios_stderr, "sweep time %.3f ms\n", (clock_now()-t0)*1000); #endif run_finalizers(); JL_SIGATOMIC_END(); #ifdef OBJPROFILE print_obj_profile(); htable_reset(&obj_counts, 0); #endif } }
JL_DLLEXPORT int jl_fs_rename(const char *src_path, const char *dst_path) { uv_fs_t req; JL_SIGATOMIC_BEGIN(); int ret = uv_fs_rename(jl_io_loop, &req, src_path, dst_path, NULL); uv_fs_req_cleanup(&req); JL_SIGATOMIC_END(); return ret; }
JL_DLLEXPORT int jl_fs_unlink(char *path) { uv_fs_t req; JL_SIGATOMIC_BEGIN(); int ret = uv_fs_unlink(jl_io_loop, &req, path, NULL); uv_fs_req_cleanup(&req); JL_SIGATOMIC_END(); return ret; }
DLLEXPORT int jl_uv_write(uv_stream_t *stream, const char *data, size_t n, uv_write_t *uvw, void *writecb) { uv_buf_t buf[1]; buf[0].base = (char*)data; buf[0].len = n; JL_SIGATOMIC_BEGIN(); int err = uv_write(uvw,stream,buf,1,(uv_write_cb)writecb); JL_SIGATOMIC_END(); return err; }
JL_DLLEXPORT int jl_fs_sendfile(int src_fd, int dst_fd, int64_t in_offset, size_t len) { uv_fs_t req; JL_SIGATOMIC_BEGIN(); int ret = uv_fs_sendfile(jl_io_loop, &req, dst_fd, src_fd, in_offset, len, NULL); uv_fs_req_cleanup(&req); JL_SIGATOMIC_END(); return ret; }
DLLEXPORT int jl_write_no_copy(uv_stream_t *stream, char *data, size_t n, uv_write_t *uvw, void *writecb) { uv_buf_t buf[1]; buf[0].base = data; buf[0].len = n; JL_SIGATOMIC_BEGIN(); int err = uv_write(uvw,stream,buf,1,(uv_write_cb)writecb); uvw->data = NULL; JL_SIGATOMIC_END(); return err; }
static void jl_ast_ctx_leave(jl_ast_context_t *ctx) { JL_SIGATOMIC_END(); if (--ctx->ref) return; JL_LOCK_NOGC(&flisp_lock); ctx->task = NULL; jl_ast_context_list_t *node = &ctx->list; jl_ast_context_list_delete(node); jl_ast_context_list_insert(&jl_ast_ctx_freed, node); JL_UNLOCK_NOGC(&flisp_lock); }
void jl_enter_handler(jl_handler_t *eh) { JL_SIGATOMIC_BEGIN(); eh->prev = jl_current_task->eh; #ifdef JL_GC_MARKSWEEP eh->gcstack = jl_pgcstack; #endif jl_current_task->eh = eh; // TODO: this should really go after setjmp(). see comment in // ctx_switch in task.c. JL_SIGATOMIC_END(); }
DLLEXPORT int jl_putc(unsigned char c, uv_stream_t *stream) { if (stream!=0) { if (stream->type<UV_HANDLE_TYPE_MAX) { //is uv handle JL_SIGATOMIC_BEGIN(); uv_write_t *uvw = malloc(sizeof(uv_write_t)); uvw->data=0; uv_buf_t buf[] = {{.base = chars+c,.len=1}}; int err = uv_write(uvw,stream,buf,1,&jl_free_buffer); JL_SIGATOMIC_END(); return err ? 0 : 1; }
DLLEXPORT int jl_write_copy(uv_stream_t *stream, const char *str, size_t n, uv_write_t *uvw, void *writecb) { JL_SIGATOMIC_BEGIN(); char *data = (char*)(uvw+1); memcpy(data,str,n); uv_buf_t buf[1]; buf[0].base = data; buf[0].len = n; uvw->data = NULL; int err = uv_write(uvw,stream,buf,1,(uv_write_cb)writecb); JL_SIGATOMIC_END(); return err; }
JL_DLLEXPORT void jl_uv_puts(uv_stream_t *stream, const char *str, size_t n) { assert(stream); static_assert(offsetof(uv_stream_t,type) == offsetof(ios_t,bm) && sizeof(((uv_stream_t*)0)->type) == sizeof(((ios_t*)0)->bm), "UV and ios layout mismatch"); uv_file fd = 0; // Fallback for output during early initialisation... if (stream == (void*)STDOUT_FILENO || stream == (void*)STDERR_FILENO) { if (!jl_io_loop) jl_io_loop = uv_default_loop(); fd = (uv_file)(size_t)stream; } else if (stream->type == UV_FILE) { fd = ((jl_uv_file_t*)stream)->file; } if (fd) { // Write to file descriptor... jl_fs_write(fd, str, n, -1); } else if (stream->type > UV_HANDLE_TYPE_MAX) { // Write to ios.c stream... // This is needed because caller jl_static_show() in builtins.c can be // called from fl_print in flisp/print.c (via cvalue_printdata()), // and cvalue_printdata() passes ios_t* to jl_static_show(). ios_write((ios_t*)stream, str, n); } else { // Write to libuv stream... uv_write_t *req = (uv_write_t*)malloc(sizeof(uv_write_t)+n); char *data = (char*)(req+1); memcpy(data,str,n); uv_buf_t buf[1]; buf[0].base = data; buf[0].len = n; req->data = NULL; JL_SIGATOMIC_BEGIN(); int status = uv_write(req, stream, buf, 1, (uv_write_cb)jl_uv_writecb); JL_SIGATOMIC_END(); if (status < 0) { jl_uv_writecb(req, status); } } }
void jl_gc_collect(void) { allocd_bytes = 0; if (is_gc_enabled) { freed_bytes = 0; JL_SIGATOMIC_BEGIN(); #if defined(GCTIME) || defined(GC_FINAL_STATS) double t0 = clock_now(); #endif gc_mark(); #ifdef GCTIME JL_PRINTF(JL_STDERR, "mark time %.3f ms\n", (clock_now()-t0)*1000); #endif #if defined(MEMPROFILE) all_pool_stats(); big_obj_stats(); #endif #ifdef GCTIME t0 = clock_now(); #endif sweep_weak_refs(); gc_sweep(); #ifdef GCTIME JL_PRINTF(JL_STDERR, "sweep time %.3f ms\n", (clock_now()-t0)*1000); #endif run_finalizers(); JL_SIGATOMIC_END(); #if defined(GC_FINAL_STATS) total_gc_time += (clock_now()-t0); total_freed_bytes += freed_bytes; #endif #ifdef OBJPROFILE print_obj_profile(); htable_reset(&obj_counts, 0); #endif // tune collect interval based on current live ratio if (freed_bytes < ((2*collect_interval)/5)) { if (collect_interval <= (2*max_collect_interval)/5) collect_interval = (5*collect_interval)/2; } else { collect_interval = default_collect_interval; } } }
void jl_enter_handler(jl_savestate_t *ss, jmp_buf *handlr) { JL_SIGATOMIC_BEGIN(); ss->eh_task = jl_current_task->state.eh_task; ss->eh_ctx = jl_current_task->state.eh_ctx; ss->ostream_obj = jl_current_task->state.ostream_obj; ss->current_output_stream = jl_current_task->state.current_output_stream; ss->prev = jl_current_task->state.prev; #ifdef JL_GC_MARKSWEEP ss->gcstack = jl_pgcstack; #endif jl_current_task->state.prev = ss; jl_current_task->state.eh_task = jl_current_task; jl_current_task->state.eh_ctx = handlr; // TODO: this should really go after setjmp(). see comment in // ctx_switch in task.c. JL_SIGATOMIC_END(); }
static void jl_typemap_list_insert_sorted(jl_typemap_entry_t **pml, jl_value_t *parent, jl_typemap_entry_t *newrec, const struct jl_typemap_info *tparams) { jl_typemap_entry_t *l, **pl; pl = pml; l = *pml; jl_value_t *pa = parent; while (l != (void*)jl_nothing) { if (!l->isleafsig) { if (jl_args_morespecific((jl_value_t*)newrec->sig, (jl_value_t*)l->sig)) break; } pl = &l->next; pa = (jl_value_t*)l; l = l->next; } JL_SIGATOMIC_BEGIN(); newrec->next = l; jl_gc_wb(newrec, l); *pl = newrec; jl_gc_wb(pa, newrec); // if this contains Union types, methods after it might actually be // more specific than it. we need to re-sort them. if (has_unions(newrec->sig)) { jl_value_t *item_parent = (jl_value_t*)newrec; jl_value_t *next_parent = 0; jl_typemap_entry_t *item = newrec->next, *next; jl_typemap_entry_t **pitem = &newrec->next, **pnext; while (item != (void*)jl_nothing) { pl = pml; l = *pml; pa = parent; next = item->next; pnext = &item->next; next_parent = (jl_value_t*)item; while (l != newrec->next) { if (jl_args_morespecific((jl_value_t*)item->sig, (jl_value_t*)l->sig)) { // reinsert item earlier in the list *pitem = next; jl_gc_wb(item_parent, next); item->next = l; jl_gc_wb(item, item->next); *pl = item; jl_gc_wb(pa, item); pnext = pitem; next_parent = item_parent; break; } pl = &l->next; pa = (jl_value_t*)l; l = l->next; } item = next; pitem = pnext; item_parent = next_parent; } } JL_SIGATOMIC_END(); return; }
DLLEXPORT void jl_sigatomic_end(void) { if (jl_defer_signal == 0) jl_error("sigatomic_end called in non-sigatomic region"); JL_SIGATOMIC_END(); }
// parse and eval a whole file, possibly reading from a string (`content`) jl_value_t *jl_parse_eval_all(const char *fname, const char *content, size_t contentlen, jl_module_t *inmodule) { jl_ptls_t ptls = jl_get_ptls_states(); if (ptls->in_pure_callback) jl_error("cannot use include inside a generated function"); jl_ast_context_t *ctx = jl_ast_ctx_enter(); fl_context_t *fl_ctx = &ctx->fl; value_t f, ast, expression; size_t len = strlen(fname); f = cvalue_static_cstrn(fl_ctx, fname, len); fl_gc_handle(fl_ctx, &f); if (content != NULL) { JL_TIMING(PARSING); value_t t = cvalue_static_cstrn(fl_ctx, content, contentlen); fl_gc_handle(fl_ctx, &t); ast = fl_applyn(fl_ctx, 2, symbol_value(symbol(fl_ctx, "jl-parse-string-stream")), t, f); fl_free_gc_handles(fl_ctx, 1); } else { JL_TIMING(PARSING); assert(memchr(fname, 0, len) == NULL); // was checked already in jl_load ast = fl_applyn(fl_ctx, 1, symbol_value(symbol(fl_ctx, "jl-parse-file")), f); } fl_free_gc_handles(fl_ctx, 1); if (ast == fl_ctx->F) { jl_ast_ctx_leave(ctx); jl_errorf("could not open file %s", fname); } fl_gc_handle(fl_ctx, &ast); fl_gc_handle(fl_ctx, &expression); int last_lineno = jl_lineno; const char *last_filename = jl_filename; size_t last_age = jl_get_ptls_states()->world_age; jl_lineno = 0; jl_filename = fname; jl_module_t *old_module = ctx->module; ctx->module = inmodule; jl_value_t *form = NULL; jl_value_t *result = jl_nothing; int err = 0; JL_GC_PUSH2(&form, &result); JL_TRY { assert(iscons(ast) && car_(ast) == symbol(fl_ctx, "toplevel")); ast = cdr_(ast); while (iscons(ast)) { expression = car_(ast); { JL_TIMING(LOWERING); if (fl_ctx->T == fl_applyn(fl_ctx, 1, symbol_value(symbol(fl_ctx, "contains-macrocall")), expression)) { form = scm_to_julia(fl_ctx, expression, inmodule); form = jl_expand_macros(form, inmodule, NULL, 0); expression = julia_to_scm(fl_ctx, form); } // expand non-final expressions in statement position (value unused) expression = fl_applyn(fl_ctx, 1, symbol_value(symbol(fl_ctx, iscons(cdr_(ast)) ? "jl-expand-to-thunk-stmt" : "jl-expand-to-thunk")), expression); } jl_get_ptls_states()->world_age = jl_world_counter; form = scm_to_julia(fl_ctx, expression, inmodule); JL_SIGATOMIC_END(); jl_get_ptls_states()->world_age = jl_world_counter; if (jl_is_linenode(form)) jl_lineno = jl_linenode_line(form); else result = jl_toplevel_eval_flex(inmodule, form, 1, 1); JL_SIGATOMIC_BEGIN(); ast = cdr_(ast); } } JL_CATCH { form = jl_pchar_to_string(fname, len); result = jl_box_long(jl_lineno); err = 1; } jl_get_ptls_states()->world_age = last_age; jl_lineno = last_lineno; jl_filename = last_filename; fl_free_gc_handles(fl_ctx, 2); ctx->module = old_module; jl_ast_ctx_leave(ctx); if (err) { if (jl_loaderror_type == NULL) jl_rethrow(); else jl_rethrow_other(jl_new_struct(jl_loaderror_type, form, result, ptls->exception_in_transit)); } JL_GC_POP(); return result; }
jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache, jl_value_t *parent, jl_tupletype_t *type, jl_svec_t *tvars, jl_tupletype_t *simpletype, jl_svec_t *guardsigs, jl_value_t *newvalue, int8_t offs, const struct jl_typemap_info *tparams, jl_value_t **overwritten) { assert(jl_is_tuple_type(type)); if (!simpletype) simpletype = (jl_tupletype_t*)jl_nothing; jl_typemap_entry_t *ml = jl_typemap_assoc_by_type(*cache, type, NULL, 1, 0, offs); if (ml) { if (overwritten != NULL) *overwritten = ml->func.value; if (newvalue == NULL) // don't overwrite with guard entries return ml; JL_SIGATOMIC_BEGIN(); ml->sig = type; jl_gc_wb(ml, ml->sig); ml->simplesig = simpletype; jl_gc_wb(ml, ml->simplesig); ml->tvars = tvars; jl_gc_wb(ml, ml->tvars); ml->va = jl_is_va_tuple(type); // TODO: `l->func` or `l->func->roots` might need to be rooted ml->func.value = newvalue; if (newvalue) jl_gc_wb(ml, newvalue); JL_SIGATOMIC_END(); return ml; } if (overwritten != NULL) *overwritten = NULL; jl_typemap_entry_t *newrec = (jl_typemap_entry_t*)jl_gc_allocobj(sizeof(jl_typemap_entry_t)); jl_set_typeof(newrec, jl_typemap_entry_type); newrec->sig = type; newrec->simplesig = simpletype; newrec->tvars = tvars; newrec->func.value = newvalue; newrec->guardsigs = guardsigs; newrec->next = (jl_typemap_entry_t*)jl_nothing; // compute the complexity of this type signature newrec->va = jl_is_va_tuple(type); newrec->issimplesig = (tvars == jl_emptysvec); // a TypeVar environment needs an complex matching test newrec->isleafsig = newrec->issimplesig && !newrec->va; // entirely leaf types don't need to be sorted JL_GC_PUSH1(&newrec); size_t i, l; for (i = 0, l = jl_datatype_nfields(type); i < l && newrec->issimplesig; i++) { jl_value_t *decl = jl_field_type(type, i); if (decl == (jl_value_t*)jl_datatype_type) newrec->isleafsig = 0; // Type{} may have a higher priority than DataType else if (jl_is_type_type(decl)) newrec->isleafsig = 0; // Type{} may need special processing to compute the match else if (jl_is_vararg_type(decl)) newrec->isleafsig = 0; // makes iteration easier when the endpoints are the same else if (decl == (jl_value_t*)jl_any_type) newrec->isleafsig = 0; // Any needs to go in the general cache else if (!jl_is_leaf_type(decl)) // anything else can go through the general subtyping test newrec->isleafsig = newrec->issimplesig = 0; } jl_typemap_insert_generic(cache, parent, newrec, NULL, offs, tparams); JL_GC_POP(); return newrec; }
static void jl_typemap_list_insert_sorted(jl_typemap_entry_t **pml, jl_value_t *parent, jl_typemap_entry_t *newrec, const struct jl_typemap_info *tparams) { jl_typemap_entry_t *l, **pl; pl = pml; l = *pml; jl_value_t *pa = parent; while (l != (void*)jl_nothing) { if (!l->isleafsig) { // quickly ignore all of the leafsig entries (these were handled by caller) if (jl_args_morespecific((jl_value_t*)newrec->sig, (jl_value_t*)l->sig)) { if (l->simplesig == (void*)jl_nothing || newrec->simplesig != (void*)jl_nothing || !sigs_eq((jl_value_t*)l->sig, (jl_value_t*)newrec->sig, 1)) { // might need to insert multiple entries for a lookup differing only by their simplesig // when simplesig contains a kind // TODO: make this test more correct or figure out a better way to compute this break; } } } pl = &l->next; pa = (jl_value_t*)l; l = l->next; } JL_SIGATOMIC_BEGIN(); newrec->next = l; jl_gc_wb(newrec, l); *pl = newrec; jl_gc_wb(pa, newrec); // if this contains Union types, methods after it might actually be // more specific than it. we need to re-sort them. if (has_unions(newrec->sig)) { jl_value_t *item_parent = (jl_value_t*)newrec; jl_value_t *next_parent = 0; jl_typemap_entry_t *item = newrec->next, *next; jl_typemap_entry_t **pitem = &newrec->next, **pnext; while (item != (void*)jl_nothing) { pl = pml; l = *pml; pa = parent; next = item->next; pnext = &item->next; next_parent = (jl_value_t*)item; while (l != newrec->next) { if (jl_args_morespecific((jl_value_t*)item->sig, (jl_value_t*)l->sig)) { // reinsert item earlier in the list *pitem = next; jl_gc_wb(item_parent, next); item->next = l; jl_gc_wb(item, item->next); *pl = item; jl_gc_wb(pa, item); pnext = pitem; next_parent = item_parent; break; } pl = &l->next; pa = (jl_value_t*)l; l = l->next; } item = next; pitem = pnext; item_parent = next_parent; } } JL_SIGATOMIC_END(); return; }
// parse and eval a whole file, possibly reading from a string (`content`) jl_value_t *jl_parse_eval_all(const char *fname, const char *content, size_t contentlen) { if (in_pure_callback) jl_error("cannot use include inside a generated function"); jl_ast_context_t *ctx = jl_ast_ctx_enter(); fl_context_t *fl_ctx = &ctx->fl; value_t f, ast; size_t len = strlen(fname); f = cvalue_static_cstrn(fl_ctx, fname, len); fl_gc_handle(fl_ctx, &f); if (content != NULL) { value_t t = cvalue_static_cstrn(fl_ctx, content, contentlen); fl_gc_handle(fl_ctx, &t); ast = fl_applyn(fl_ctx, 2, symbol_value(symbol(fl_ctx, "jl-parse-string-stream")), t, f); fl_free_gc_handles(fl_ctx, 1); } else { assert(memchr(fname, 0, len) == NULL); // was checked already in jl_load ast = fl_applyn(fl_ctx, 1, symbol_value(symbol(fl_ctx, "jl-parse-file")), f); } fl_free_gc_handles(fl_ctx, 1); if (ast == fl_ctx->F) { jl_ast_ctx_leave(ctx); jl_errorf("could not open file %s", fname); } fl_gc_handle(fl_ctx, &ast); int last_lineno = jl_lineno; const char *last_filename = jl_filename; jl_lineno = 0; jl_filename = fname; jl_array_t *roots = NULL; jl_array_t **old_roots = ctx->roots; ctx->roots = &roots; jl_value_t *form=NULL, *result=jl_nothing; int err = 0; JL_GC_PUSH3(&roots, &form, &result); JL_TRY { assert(iscons(ast) && car_(ast) == symbol(fl_ctx,"toplevel")); ast = cdr_(ast); while (iscons(ast)) { value_t expansion = fl_applyn(fl_ctx, 1, symbol_value(symbol(fl_ctx, "jl-expand-to-thunk")), car_(ast)); form = scm_to_julia(fl_ctx, expansion, 0); jl_sym_t *head = NULL; if (jl_is_expr(form)) head = ((jl_expr_t*)form)->head; JL_SIGATOMIC_END(); if (head == jl_incomplete_sym) jl_errorf("syntax: %s", jl_string_data(jl_exprarg(form,0))); else if (head == error_sym) jl_interpret_toplevel_expr(form); else if (head == line_sym) jl_lineno = jl_unbox_long(jl_exprarg(form,0)); else if (jl_is_linenode(form)) jl_lineno = jl_linenode_line(form); else result = jl_toplevel_eval_flex(form, 1, 1); JL_SIGATOMIC_BEGIN(); ast = cdr_(ast); } } JL_CATCH { form = jl_pchar_to_string(fname, len); result = jl_box_long(jl_lineno); err = 1; } jl_lineno = last_lineno; jl_filename = last_filename; fl_free_gc_handles(fl_ctx, 1); ctx->roots = old_roots; jl_ast_ctx_leave(ctx); if (err) { if (jl_loaderror_type == NULL) jl_rethrow(); else jl_rethrow_other(jl_new_struct(jl_loaderror_type, form, result, jl_exception_in_transit)); } JL_GC_POP(); return result; }