jl_value_t *jl_interpret_toplevel_expr(jl_value_t *e) { size_t last_age = jl_get_ptls_states()->world_age; jl_get_ptls_states()->world_age = jl_world_counter; jl_value_t *ret = eval(e, NULL); jl_get_ptls_states()->world_age = last_age; return ret; }
JL_DLLEXPORT jl_value_t *jl_apply_with_saved_exception_state(jl_value_t **args, uint32_t nargs, int drop_exceptions) { jl_ptls_t ptls = jl_get_ptls_states(); jl_value_t *exc = ptls->exception_in_transit; jl_array_t *bt = NULL; JL_GC_PUSH2(&exc, &bt); if (ptls->bt_size > 0) bt = (jl_array_t*)jl_get_backtrace(); jl_value_t *v; JL_TRY { v = jl_apply(args, nargs); } JL_CATCH { if (!drop_exceptions) { jl_printf(JL_STDERR, "Internal error: encountered unexpected error in runtime:\n"); jl_static_show(JL_STDERR, ptls->exception_in_transit); jl_printf(JL_STDERR, "\n"); jlbacktrace(); // written to STDERR_FILENO } v = NULL; } ptls->exception_in_transit = exc; if (bt != NULL) { ptls->bt_size = jl_array_len(bt); memcpy(ptls->bt_data, bt->data, ptls->bt_size * sizeof(void*)); } JL_GC_POP(); return v; }
JL_DLLEXPORT void jlbacktrace(void) { jl_ptls_t ptls = jl_get_ptls_states(); size_t i, n = ptls->bt_size; // ptls->bt_size > 400 ? 400 : ptls->bt_size; for (i = 0; i < n; i++) jl_gdblookup(ptls->bt_data[i] - 1); }
JL_DLLEXPORT jl_value_t *jl_lookup_code_address(void *ip, int skipC) { jl_ptls_t ptls = jl_get_ptls_states(); jl_frame_t *frames = NULL; int8_t gc_state = jl_gc_safe_enter(ptls); int n = jl_getFunctionInfo(&frames, (uintptr_t)ip, skipC, 0); jl_gc_safe_leave(ptls, gc_state); jl_value_t *rs = (jl_value_t*)jl_alloc_svec(n); JL_GC_PUSH1(&rs); for (int i = 0; i < n; i++) { jl_frame_t frame = frames[i]; jl_value_t *r = (jl_value_t*)jl_alloc_svec(7); jl_svecset(rs, i, r); if (frame.func_name) jl_svecset(r, 0, jl_symbol(frame.func_name)); else jl_svecset(r, 0, empty_sym); free(frame.func_name); if (frame.file_name) jl_svecset(r, 1, jl_symbol(frame.file_name)); else jl_svecset(r, 1, empty_sym); free(frame.file_name); jl_svecset(r, 2, jl_box_long(frame.line)); jl_svecset(r, 3, frame.linfo != NULL ? (jl_value_t*)frame.linfo : jl_nothing); jl_svecset(r, 4, jl_box_bool(frame.fromC)); jl_svecset(r, 5, jl_box_bool(frame.inlined)); jl_svecset(r, 6, jl_box_long((intptr_t)ip)); } free(frames); JL_GC_POP(); return rs; }
JL_DLLEXPORT jl_module_t *jl_new_main_module(void) { jl_ptls_t ptls = jl_get_ptls_states(); if (jl_generating_output() && jl_options.incremental) jl_error("cannot call workspace() in incremental compile mode"); // switch to a new top-level module if (ptls->current_module != jl_main_module && ptls->current_module != NULL && jl_main_module != NULL) jl_error("Main can only be replaced from the top level"); jl_module_t *old_main = jl_main_module; jl_main_module = jl_new_module(jl_symbol("Main")); jl_main_module->parent = jl_main_module; if (old_main) // don't block continued loading of incremental caches jl_main_module->uuid = old_main->uuid; ptls->current_module = jl_main_module; jl_core_module->parent = jl_main_module; jl_set_const(jl_main_module, jl_symbol("Core"), (jl_value_t*)jl_core_module); jl_set_global(jl_core_module, jl_symbol("Main"), (jl_value_t*)jl_main_module); ptls->current_task->current_module = jl_main_module; return old_main; }
int jl_safepoint_start_gc(void) { #ifdef JULIA_ENABLE_THREADING // The thread should have set this already assert(jl_get_ptls_states()->gc_state == JL_GC_STATE_WAITING); jl_mutex_lock_nogc(&safepoint_lock); // In case multiple threads enter the GC at the same time, only allow // one of them to actually run the collection. We can't just let the // master thread do the GC since it might be running unmanaged code // and can take arbitrarily long time before hitting a safe point. if (jl_atomic_compare_exchange(&jl_gc_running, 0, 1) != 0) { jl_mutex_unlock_nogc(&safepoint_lock); jl_safepoint_wait_gc(); return 0; } jl_safepoint_enable(1); jl_safepoint_enable(2); jl_mutex_unlock_nogc(&safepoint_lock); return 1; #else // For single thread, GC should not call itself (in finalizers) before // setting `jl_gc_running` to false so this should never happen. assert(!jl_gc_running); jl_gc_running = 1; return 1; #endif }
JL_DLLEXPORT jl_array_t *jl_string_to_array(jl_value_t *str) { jl_ptls_t ptls = jl_get_ptls_states(); jl_array_t *a; int ndimwords = jl_array_ndimwords(1); int tsz = JL_ARRAY_ALIGN(sizeof(jl_array_t) + ndimwords*sizeof(size_t) + sizeof(void*), JL_SMALL_BYTE_ALIGNMENT); a = (jl_array_t*)jl_gc_alloc(ptls, tsz, jl_array_uint8_type); a->flags.pooled = tsz <= GC_MAX_SZCLASS; a->flags.ndims = 1; a->offset = 0; a->data = jl_string_data(str); a->flags.isaligned = 0; a->elsize = 1; a->flags.ptrarray = 0; jl_array_data_owner(a) = str; a->flags.how = 3; a->flags.isshared = 1; size_t l = jl_string_len(str); #ifdef STORE_ARRAY_LEN a->length = l; #endif a->nrows = a->maxsize = l; return a; }
static void ti_initthread(int16_t tid) { jl_tls_states_t *ptls = jl_get_ptls_states(); #ifndef _OS_WINDOWS_ ptls->system_id = pthread_self(); #endif ptls->tid = tid; ptls->pgcstack = NULL; ptls->gc_state = 0; // GC unsafe // Conditionally initialize the safepoint address. See comment in // `safepoint.c` if (tid == 0) { ptls->safepoint = (size_t*)(jl_safepoint_pages + jl_page_size); } else { ptls->safepoint = (size_t*)(jl_safepoint_pages + jl_page_size * 2 + sizeof(size_t)); } ptls->defer_signal = 0; ptls->current_module = NULL; void *bt_data = malloc(sizeof(uintptr_t) * (JL_MAX_BT_SIZE + 1)); if (bt_data == NULL) { jl_printf(JL_STDERR, "could not allocate backtrace buffer\n"); gc_debug_critical_error(); abort(); } ptls->bt_data = (uintptr_t*)bt_data; jl_mk_thread_heap(ptls); jl_install_thread_signal_handler(); jl_all_tls_states[tid] = ptls; }
// used by boot.jl JL_DLLEXPORT jl_value_t *jl_typemax_uint(jl_value_t *bt) { uint64_t data = 0xffffffffffffffffULL; jl_value_t *v = jl_gc_alloc(jl_get_ptls_states(), sizeof(size_t), bt); memcpy(v, &data, sizeof(size_t)); return v; }
JL_DLLEXPORT jl_value_t *jl_new_bits(jl_value_t *dt, void *data) { // data may not have the alignment required by the size // but will always have the alignment required by the datatype jl_ptls_t ptls = jl_get_ptls_states(); assert(jl_is_datatype(dt)); jl_datatype_t *bt = (jl_datatype_t*)dt; size_t nb = jl_datatype_size(bt); // some types have special pools to minimize allocations if (nb == 0) return jl_new_struct_uninit(bt); // returns bt->instance if (bt == jl_bool_type) return (1 & *(int8_t*)data) ? jl_true : jl_false; if (bt == jl_uint8_type) return jl_box_uint8(*(uint8_t*)data); if (bt == jl_int64_type) return jl_box_int64(*(int64_t*)data); if (bt == jl_int32_type) return jl_box_int32(*(int32_t*)data); if (bt == jl_int8_type) return jl_box_int8(*(int8_t*)data); if (bt == jl_int16_type) return jl_box_int16(*(int16_t*)data); if (bt == jl_uint64_type) return jl_box_uint64(*(uint64_t*)data); if (bt == jl_uint32_type) return jl_box_uint32(*(uint32_t*)data); if (bt == jl_uint16_type) return jl_box_uint16(*(uint16_t*)data); if (bt == jl_char_type) return jl_box_char(*(uint32_t*)data); jl_value_t *v = jl_gc_alloc(ptls, nb, bt); switch (nb) { case 1: *(uint8_t*) v = *(uint8_t*)data; break; case 2: *(uint16_t*)v = jl_load_unaligned_i16(data); break; case 4: *(uint32_t*)v = jl_load_unaligned_i32(data); break; case 8: *(uint64_t*)v = jl_load_unaligned_i64(data); break; case 16: memcpy(jl_assume_aligned(v, 16), data, 16); break; default: memcpy(v, data, nb); } return v; }
STATIC_INLINE void jl_allocate_singleton_instance(jl_datatype_t *st) { if (jl_is_datatype_make_singleton(st)) { st->instance = jl_gc_alloc(jl_get_ptls_states(), 0, st); jl_gc_wb(st, st->instance); } }
/* multiq_insert() */ static inline int multiq_insert(jl_task_t *task, int16_t priority) { jl_ptls_t ptls = jl_get_ptls_states(); uint64_t rn; task->prio = priority; do { rn = cong(heap_p, cong_unbias, &ptls->rngseed); } while (!jl_mutex_trylock_nogc(&heaps[rn].lock)); if (heaps[rn].ntasks >= tasks_per_heap) { jl_mutex_unlock_nogc(&heaps[rn].lock); jl_error("multiq insertion failed, increase #tasks per heap"); return -1; } heaps[rn].tasks[heaps[rn].ntasks++] = task; sift_up(&heaps[rn], heaps[rn].ntasks-1); jl_mutex_unlock_nogc(&heaps[rn].lock); int16_t prio = jl_atomic_load(&heaps[rn].prio); if (task->prio < prio) jl_atomic_compare_exchange(&heaps[rn].prio, prio, task->prio); return 0; }
void fpe_handler(int sig, siginfo_t *info, void *context) { (void)info; jl_ptls_t ptls = jl_get_ptls_states(); jl_unblock_signal(sig); jl_throw_in_ctx(ptls, jl_diverror_exception, context); }
JL_DLLEXPORT jl_value_t *jl_alloc_string(size_t len) { jl_value_t *s = jl_gc_alloc(jl_get_ptls_states(), sizeof(size_t)+len+1, jl_string_type); *(size_t*)s = len; ((char*)s + sizeof(size_t))[len] = 0; return s; }
JL_DLLEXPORT jl_value_t *jl_new_structv(jl_datatype_t *type, jl_value_t **args, uint32_t na) { jl_ptls_t ptls = jl_get_ptls_states(); if (type->instance != NULL) return type->instance; size_t nf = jl_datatype_nfields(type); jl_value_t *jv = jl_gc_alloc(ptls, jl_datatype_size(type), type); JL_GC_PUSH1(&jv); for (size_t i = 0; i < na; i++) { jl_value_t *ft = jl_field_type(type, i); if (!jl_isa(args[i], ft)) jl_type_error("new", ft, args[i]); jl_set_nth_field(jv, i, args[i]); } for(size_t i=na; i < nf; i++) { if (jl_field_isptr(type, i)) { *(jl_value_t**)((char*)jl_data_ptr(jv)+jl_field_offset(type,i)) = NULL; } else { jl_value_t *ft = jl_field_type(type, i); if (jl_is_uniontype(ft)) { uint8_t *psel = &((uint8_t *)jv)[jl_field_offset(type, i) + jl_field_size(type, i) - 1]; *psel = 0; } } } JL_GC_POP(); return jv; }
JL_DLLEXPORT jl_lambda_info_t *jl_new_lambda_info_uninit(void) { jl_ptls_t ptls = jl_get_ptls_states(); jl_lambda_info_t *li = (jl_lambda_info_t*)jl_gc_alloc(ptls, sizeof(jl_lambda_info_t), jl_lambda_info_type); li->code = NULL; li->slotnames = NULL; li->slotflags = NULL; li->slottypes = NULL; li->ssavaluetypes = NULL; li->rettype = (jl_value_t*)jl_any_type; li->sparam_syms = jl_emptysvec; li->sparam_vals = jl_emptysvec; li->fptr = NULL; li->jlcall_api = 0; li->compile_traced = 0; li->functionObjectsDecls.functionObject = NULL; li->functionObjectsDecls.specFunctionObject = NULL; li->specTypes = NULL; li->unspecialized_ducttape = NULL; li->inferred = 0; li->inInference = 0; li->inCompile = 0; li->def = NULL; li->constval = NULL; li->pure = 0; li->inlineable = 0; return li; }
// Note that this function updates len static jl_value_t *jl_new_bits_internal(jl_value_t *dt, void *data, size_t *len) { jl_ptls_t ptls = jl_get_ptls_states(); assert(jl_is_datatype(dt)); jl_datatype_t *bt = (jl_datatype_t*)dt; size_t nb = jl_datatype_size(bt); if (nb == 0) return jl_new_struct_uninit(bt); *len = LLT_ALIGN(*len, bt->layout->alignment); data = (char*)data + (*len); *len += nb; if (bt == jl_uint8_type) return jl_box_uint8(*(uint8_t*)data); if (bt == jl_int64_type) return jl_box_int64(*(int64_t*)data); if (bt == jl_bool_type) return (*(int8_t*)data) ? jl_true:jl_false; if (bt == jl_int32_type) return jl_box_int32(*(int32_t*)data); if (bt == jl_float64_type) return jl_box_float64(*(double*)data); jl_value_t *v = jl_gc_alloc(ptls, nb, bt); switch (nb) { case 1: *(int8_t*) jl_data_ptr(v) = *(int8_t*)data; break; case 2: *(int16_t*) jl_data_ptr(v) = *(int16_t*)data; break; case 4: *(int32_t*) jl_data_ptr(v) = *(int32_t*)data; break; case 8: *(int64_t*) jl_data_ptr(v) = *(int64_t*)data; break; case 16: *(bits128_t*)jl_data_ptr(v) = *(bits128_t*)data; break; default: memcpy(jl_data_ptr(v), data, nb); } return v; }
static void segv_handler(int sig, siginfo_t *info, void *context) { assert(sig == SIGSEGV || sig == SIGBUS); #ifdef JULIA_ENABLE_THREADING if (info->si_addr == jl_gc_signal_page) { jl_unblock_signal(sig); jl_gc_signal_wait(); return; } #endif if (jl_safe_restore || is_addr_on_stack(jl_get_ptls_states(), info->si_addr)) { // stack overflow, or restarting jl_ jl_unblock_signal(sig); jl_throw(jl_stackovf_exception); } else if (sig == SIGSEGV && info->si_code == SEGV_ACCERR) { // writing to read-only memory (e.g., mmap) jl_unblock_signal(sig); jl_throw(jl_readonlymemory_exception); } else { #ifdef SEGV_EXCEPTION jl_unblock_signal(sig); jl_throw(jl_segv_exception); #else sigdie_handler(sig, info, context); #endif } }
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 __cdecl crt_sig_handler(int sig, int num) { jl_ptls_t ptls = jl_get_ptls_states(); CONTEXT Context; switch (sig) { case SIGFPE: fpreset(); signal(SIGFPE, (void (__cdecl *)(int))crt_sig_handler); switch(num) { case _FPE_INVALID: case _FPE_OVERFLOW: case _FPE_UNDERFLOW: default: jl_errorf("Unexpected FPE Error 0x%X", num); break; case _FPE_ZERODIVIDE: jl_throw(jl_diverror_exception); break; } break; case SIGINT: signal(SIGINT, (void (__cdecl *)(int))crt_sig_handler); if (exit_on_sigint) jl_exit(130); // 128 + SIGINT jl_try_throw_sigint(); break; default: // SIGSEGV, (SSIGTERM, IGILL) memset(&Context, 0, sizeof(Context)); RtlCaptureContext(&Context); jl_critical_error(sig, &Context, ptls->bt_data, &ptls->bt_size); raise(sig); } }
jl_value_t *jl_interpret_toplevel_expr_in(jl_module_t *m, jl_value_t *e, jl_code_info_t *src, jl_svec_t *sparam_vals) { jl_ptls_t ptls = jl_get_ptls_states(); jl_value_t *v=NULL; jl_module_t *last_m = ptls->current_module; jl_module_t *task_last_m = ptls->current_task->current_module; interpreter_state s; s.src = src; s.module = m; s.locals = NULL; s.sparam_vals = sparam_vals; JL_TRY { ptls->current_task->current_module = ptls->current_module = m; v = eval(e, &s); } JL_CATCH { ptls->current_module = last_m; ptls->current_task->current_module = task_last_m; jl_rethrow(); } ptls->current_module = last_m; ptls->current_task->current_module = task_last_m; assert(v); return v; }
JL_DLLEXPORT void jl_set_istopmod(uint8_t isprimary) { jl_ptls_t ptls = jl_get_ptls_states(); ptls->current_module->istopmod = 1; if (isprimary) jl_top_module = ptls->current_module; }
JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var) { jl_ptls_t ptls = jl_get_ptls_states(); if (m == NULL) m = ptls->current_module; jl_binding_t *b = jl_get_binding(m, var); return b && b->constp; }
JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name) { jl_ptls_t ptls = jl_get_ptls_states(); jl_module_t *m = (jl_module_t*)jl_gc_alloc(ptls, sizeof(jl_module_t), jl_module_type); JL_GC_PUSH1(&m); assert(jl_is_symbol(name)); m->name = name; m->parent = NULL; m->istopmod = 0; static unsigned int mcounter; // simple counter backup, in case hrtime is not incrementing m->uuid = jl_hrtime() + (++mcounter); if (!m->uuid) m->uuid++; // uuid 0 is invalid m->counter = 0; htable_new(&m->bindings, 0); arraylist_new(&m->usings, 0); if (jl_core_module) { jl_module_using(m, jl_core_module); } // export own name, so "using Foo" makes "Foo" itself visible jl_set_const(m, name, (jl_value_t*)m); jl_module_export(m, name); JL_GC_POP(); return m; }
// request: // 0: nothing // 1: get state // 3: throw sigint if `!defer_signal && io_wait` or if force throw threshold // is reached void usr2_handler(int sig, siginfo_t *info, void *ctx) { jl_tls_states_t *ptls = jl_get_ptls_states(); sig_atomic_t request = jl_atomic_exchange(&ptls->signal_request, 0); if (request == 1) { signal_context = jl_to_bt_context(ctx); pthread_mutex_lock(&in_signal_lock); pthread_cond_broadcast(&signal_caught_cond); pthread_cond_wait(&exit_signal_cond, &in_signal_lock); request = jl_atomic_exchange(&ptls->signal_request, 0); assert(request == 1); (void)request; pthread_cond_broadcast(&signal_caught_cond); pthread_mutex_unlock(&in_signal_lock); } else if (request == 2) { jl_unblock_signal(sig); int force = jl_check_force_sigint(); if (force || (!ptls->defer_signal && ptls->io_wait)) { jl_safepoint_consume_sigint(); if (force) jl_safe_printf("WARNING: Force throwing a SIGINT\n"); // Force a throw jl_clear_force_sigint(); jl_throw_in_ctx(jl_interrupt_exception, ctx); } } }
static inline jl_value_t *jl_intrinsiclambda_ty1(jl_value_t *ty, void *pa, unsigned osize, unsigned osize2, const void *voidlist) { jl_ptls_t ptls = jl_get_ptls_states(); jl_value_t *newv = jl_gc_alloc(ptls, ((jl_datatype_t*)ty)->size, ty); intrinsic_1_t op = select_intrinsic_1(osize2, (const intrinsic_1_t*)voidlist); op(osize * host_char_bit, pa, jl_data_ptr(newv)); return newv; }
JL_DLLEXPORT jl_value_t *jl_call0(jl_function_t *f) { jl_value_t *v; JL_TRY { JL_GC_PUSH1(&f); size_t last_age = jl_get_ptls_states()->world_age; jl_get_ptls_states()->world_age = jl_get_world_counter(); v = jl_apply(&f, 1); jl_get_ptls_states()->world_age = last_age; JL_GC_POP(); jl_exception_clear(); } JL_CATCH { v = NULL; } return v; }
JL_DLLEXPORT jl_value_t *jl_pchar_to_string(const char *str, size_t len) { jl_value_t *s = jl_gc_alloc(jl_get_ptls_states(), sizeof(size_t)+len+1, jl_string_type); *(size_t*)s = len; memcpy((char*)s + sizeof(size_t), str, len); ((char*)s + sizeof(size_t))[len] = 0; return s; }
JL_DLLEXPORT jl_value_t *jl_array_to_string(jl_array_t *a) { jl_ptls_t ptls = jl_get_ptls_states(); if (!jl_typeis(a, jl_array_uint8_type)) jl_type_error("jl_array_to_string", (jl_value_t*)jl_array_uint8_type, (jl_value_t*)a); jl_value_t *s = jl_gc_alloc(ptls, sizeof(void*), jl_string_type); jl_set_nth_field(s, 0, (jl_value_t*)a); return s; }
JL_DLLEXPORT void jl_run_event_loop(uv_loop_t *loop) { jl_tls_states_t *ptls = jl_get_ptls_states(); if (loop) { loop->stop_flag = 0; jl_gc_safepoint_(ptls); uv_run(loop,UV_RUN_DEFAULT); } }