https://github.com/JuliaLang/julia
Tip revision: 1a8513cbb5166c3d096043de9d6e28e8e14ebb4d authored by Kristoffer Carlsson on 09 July 2022, 19:40:59 UTC
only locate packages in envs at or above in the load path where they were identified
only locate packages in envs at or above in the load path where they were identified
Tip revision: 1a8513c
rtutils.c
// This file is a part of Julia. License is MIT: https://julialang.org/license
/*
utility functions used by the runtime system, generated code, and Base library
*/
#include "platform.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <setjmp.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#if defined(_OS_WINDOWS_)
#include <malloc.h>
#else
#include <unistd.h>
#endif
#include <ctype.h>
#include "julia.h"
#include "julia_internal.h"
#include "julia_assert.h"
#ifdef __cplusplus
extern "C" {
#endif
// exceptions -----------------------------------------------------------------
JL_DLLEXPORT void JL_NORETURN jl_error(const char *str)
{
if (jl_errorexception_type == NULL) {
jl_printf(JL_STDERR, "ERROR: %s\n", str);
jl_exit(1);
}
jl_value_t *msg = jl_pchar_to_string((char*)str, strlen(str));
JL_GC_PUSH1(&msg);
jl_throw(jl_new_struct(jl_errorexception_type, msg));
}
extern int vasprintf(char **str, const char *fmt, va_list ap);
jl_value_t *jl_vexceptionf(jl_datatype_t *exception_type,
const char *fmt, va_list args)
{
if (exception_type == NULL) {
jl_printf(JL_STDERR, "ERROR: ");
jl_vprintf(JL_STDERR, fmt, args);
jl_printf(JL_STDERR, "\n");
jl_exit(1);
}
char *str = NULL;
int ok = vasprintf(&str, fmt, args);
jl_value_t *msg;
if (ok < 0) { // vasprintf failed
msg = jl_cstr_to_string("internal error: could not display error message");
}
else {
msg = jl_pchar_to_string(str, strlen(str));
free(str);
}
JL_GC_PUSH1(&msg);
jl_value_t *e = jl_new_struct(exception_type, msg);
JL_GC_POP();
return e;
}
JL_DLLEXPORT void JL_NORETURN jl_errorf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
jl_value_t *e = jl_vexceptionf(jl_errorexception_type, fmt, args);
va_end(args);
jl_throw(e);
}
JL_DLLEXPORT void JL_NORETURN jl_exceptionf(jl_datatype_t *exception_type,
const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
jl_value_t *e = jl_vexceptionf(exception_type, fmt, args);
va_end(args);
jl_throw(e);
}
jl_value_t *jl_get_exceptionf(jl_datatype_t *exception_type,
const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
jl_value_t *e = jl_vexceptionf(exception_type, fmt, args);
va_end(args);
return e;
}
JL_DLLEXPORT void JL_NORETURN jl_too_few_args(const char *fname, int min)
{
jl_exceptionf(jl_argumenterror_type, "%s: too few arguments (expected %d)", fname, min);
}
JL_DLLEXPORT void JL_NORETURN jl_too_many_args(const char *fname, int max)
{
jl_exceptionf(jl_argumenterror_type, "%s: too many arguments (expected %d)", fname, max);
}
// with function name / location description, plus extra context
JL_DLLEXPORT void JL_NORETURN jl_type_error_rt(const char *fname, const char *context,
jl_value_t *expected JL_MAYBE_UNROOTED,
jl_value_t *got JL_MAYBE_UNROOTED)
{
jl_value_t *ctxt=NULL;
JL_GC_PUSH3(&ctxt, &expected, &got);
ctxt = jl_pchar_to_string((char*)context, strlen(context));
jl_value_t *ex = jl_new_struct(jl_typeerror_type, jl_symbol(fname), ctxt, expected, got);
jl_throw(ex);
}
// with function name or description only
JL_DLLEXPORT void JL_NORETURN jl_type_error(const char *fname,
jl_value_t *expected JL_MAYBE_UNROOTED,
jl_value_t *got JL_MAYBE_UNROOTED)
{
jl_type_error_rt(fname, "", expected, got);
}
JL_DLLEXPORT void JL_NORETURN jl_undefined_var_error(jl_sym_t *var)
{
jl_throw(jl_new_struct(jl_undefvarerror_type, var));
}
JL_DLLEXPORT void JL_NORETURN jl_atomic_error(char *str) // == jl_exceptionf(jl_atomicerror_type, "%s", str)
{
jl_value_t *msg = jl_pchar_to_string((char*)str, strlen(str));
JL_GC_PUSH1(&msg);
jl_throw(jl_new_struct(jl_atomicerror_type, msg));
}
JL_DLLEXPORT void JL_NORETURN jl_bounds_error(jl_value_t *v, jl_value_t *t)
{
JL_GC_PUSH2(&v, &t); // root arguments so the caller doesn't need to
jl_throw(jl_new_struct((jl_datatype_t*)jl_boundserror_type, v, t));
}
JL_DLLEXPORT void JL_NORETURN jl_bounds_error_v(jl_value_t *v, jl_value_t **idxs, size_t nidxs)
{
jl_value_t *t = NULL;
// items in idxs are assumed to already be rooted
JL_GC_PUSH2(&v, &t); // root v so the caller doesn't need to
t = jl_f_tuple(NULL, idxs, nidxs);
jl_throw(jl_new_struct((jl_datatype_t*)jl_boundserror_type, v, t));
}
JL_DLLEXPORT void JL_NORETURN jl_bounds_error_tuple_int(jl_value_t **v, size_t nv, size_t i)
{
// values in v are expected to already be gc-rooted
jl_bounds_error_int(jl_f_tuple(NULL, v, nv), i);
}
JL_DLLEXPORT void JL_NORETURN jl_bounds_error_unboxed_int(void *data, jl_value_t *vt, size_t i)
{
jl_value_t *t = NULL, *v = NULL;
// data is expected to be gc-safe (either gc-rooted, or alloca)
// vt is expected to be gc-rooted (in a linfo-root probably)
JL_GC_PUSH2(&v, &t);
v = jl_new_bits(vt, data);
t = jl_box_long(i);
jl_throw(jl_new_struct((jl_datatype_t*)jl_boundserror_type, v, t));
}
JL_DLLEXPORT void JL_NORETURN jl_bounds_error_int(jl_value_t *v JL_MAYBE_UNROOTED, size_t i)
{
jl_value_t *t = NULL;
JL_GC_PUSH2(&v, &t); // root arguments so the caller doesn't need to
t = jl_box_long(i);
jl_throw(jl_new_struct((jl_datatype_t*)jl_boundserror_type, v, t));
}
JL_DLLEXPORT void JL_NORETURN jl_bounds_error_ints(jl_value_t *v JL_MAYBE_UNROOTED,
size_t *idxs, size_t nidxs)
{
size_t i;
jl_value_t *t = NULL;
JL_GC_PUSH2(&v, &t); // root arguments so the caller doesn't need to
t = (jl_value_t*)jl_alloc_svec(nidxs);
for (i = 0; i < nidxs; i++) {
jl_svecset(t, i, jl_box_long(idxs[i]));
}
t = jl_f_tuple(NULL, jl_svec_data(t), nidxs);
jl_throw(jl_new_struct((jl_datatype_t*)jl_boundserror_type, v, t));
}
JL_DLLEXPORT void JL_NORETURN jl_eof_error(void)
{
jl_datatype_t *eof_error =
(jl_datatype_t*)jl_get_global(jl_base_module, jl_symbol("EOFError"));
assert(eof_error != NULL);
jl_throw(jl_new_struct(eof_error));
}
// get kwsorter field, with appropriate error check and message
JL_DLLEXPORT jl_value_t *jl_get_keyword_sorter(jl_value_t *f)
{
return jl_get_kwsorter(jl_typeof(f));
}
JL_DLLEXPORT void jl_typeassert(jl_value_t *x, jl_value_t *t)
{
if (!jl_isa(x,t))
jl_type_error("typeassert", t, x);
}
#ifndef HAVE_SSP
JL_DLLEXPORT uintptr_t __stack_chk_guard = (uintptr_t)0xBAD57ACCBAD67ACC; // 0xBADSTACKBADSTACK
JL_DLLEXPORT void __stack_chk_fail(void)
{
/* put your panic function or similar in here */
fprintf(stderr, "fatal error: stack corruption detected\n");
jl_gc_debug_critical_error();
abort(); // end with abort, since the compiler destroyed the stack upon entry to this function, there's no going back now
}
#endif
// exceptions -----------------------------------------------------------------
JL_DLLEXPORT void jl_enter_handler(jl_handler_t *eh)
{
jl_task_t *ct = jl_current_task;
// Must have no safepoint
eh->prev = ct->eh;
eh->gcstack = ct->gcstack;
eh->gc_state = jl_atomic_load_relaxed(&ct->ptls->gc_state);
eh->locks_len = ct->ptls->locks.len;
eh->defer_signal = ct->ptls->defer_signal;
eh->world_age = ct->world_age;
ct->eh = eh;
#ifdef ENABLE_TIMINGS
eh->timing_stack = ct->ptls->timing_stack;
#endif
}
// Restore thread local state to saved state in error handler `eh`.
// This is executed in two circumstances:
// * We leave a try block through normal control flow
// * An exception causes a nonlocal jump to the catch block. In this case
// there's additional cleanup required, eg pushing the exception stack.
JL_DLLEXPORT void jl_eh_restore_state(jl_handler_t *eh)
{
jl_task_t *ct = jl_current_task;
#ifdef _OS_WINDOWS_
if (ct->ptls->needs_resetstkoflw) {
_resetstkoflw();
ct->ptls->needs_resetstkoflw = 0;
}
#endif
// `eh` may be not equal to `ct->eh`. See `jl_pop_handler`
// This function should **NOT** have any safepoint before the ones at the
// end.
sig_atomic_t old_defer_signal = ct->ptls->defer_signal;
int8_t old_gc_state = jl_atomic_load_relaxed(&ct->ptls->gc_state);
ct->eh = eh->prev;
ct->gcstack = eh->gcstack;
small_arraylist_t *locks = &ct->ptls->locks;
int unlocks = locks->len > eh->locks_len;
if (unlocks) {
for (size_t i = locks->len; i > eh->locks_len; i--)
jl_mutex_unlock_nogc((jl_mutex_t*)locks->items[i - 1]);
locks->len = eh->locks_len;
}
ct->world_age = eh->world_age;
ct->ptls->defer_signal = eh->defer_signal;
if (old_gc_state != eh->gc_state) {
jl_atomic_store_release(&ct->ptls->gc_state, eh->gc_state);
if (old_gc_state) {
jl_gc_safepoint_(ct->ptls);
}
}
if (old_defer_signal && !eh->defer_signal) {
jl_sigint_safepoint(ct->ptls);
}
if (jl_atomic_load_relaxed(&jl_gc_have_pending_finalizers) &&
unlocks && eh->locks_len == 0) {
jl_gc_run_pending_finalizers(ct);
}
}
JL_DLLEXPORT void jl_pop_handler(int n)
{
jl_task_t *ct = jl_current_task;
if (__unlikely(n <= 0))
return;
jl_handler_t *eh = ct->eh;
while (--n > 0)
eh = eh->prev;
jl_eh_restore_state(eh);
}
JL_DLLEXPORT size_t jl_excstack_state(void) JL_NOTSAFEPOINT
{
jl_task_t *ct = jl_current_task;
jl_excstack_t *s = ct->excstack;
return s ? s->top : 0;
}
JL_DLLEXPORT void jl_restore_excstack(size_t state) JL_NOTSAFEPOINT
{
jl_task_t *ct = jl_current_task;
jl_excstack_t *s = ct->excstack;
if (s) {
assert(s->top >= state);
s->top = state;
}
}
static void jl_copy_excstack(jl_excstack_t *dest, jl_excstack_t *src) JL_NOTSAFEPOINT
{
assert(dest->reserved_size >= src->top);
memcpy(jl_excstack_raw(dest), jl_excstack_raw(src), sizeof(jl_bt_element_t)*src->top);
dest->top = src->top;
}
static void jl_reserve_excstack(jl_excstack_t **stack JL_REQUIRE_ROOTED_SLOT,
size_t reserved_size)
{
jl_excstack_t *s = *stack;
if (s && s->reserved_size >= reserved_size)
return;
size_t bufsz = sizeof(jl_excstack_t) + sizeof(uintptr_t)*reserved_size;
jl_task_t *ct = jl_current_task;
jl_excstack_t *new_s = (jl_excstack_t*)jl_gc_alloc_buf(ct->ptls, bufsz);
new_s->top = 0;
new_s->reserved_size = reserved_size;
if (s)
jl_copy_excstack(new_s, s);
*stack = new_s;
}
void jl_push_excstack(jl_excstack_t **stack JL_REQUIRE_ROOTED_SLOT JL_ROOTING_ARGUMENT,
jl_value_t *exception JL_ROOTED_ARGUMENT,
jl_bt_element_t *bt_data, size_t bt_size)
{
jl_reserve_excstack(stack, (*stack ? (*stack)->top : 0) + bt_size + 2);
jl_excstack_t *s = *stack;
jl_bt_element_t *rawstack = jl_excstack_raw(s);
memcpy(rawstack + s->top, bt_data, sizeof(jl_bt_element_t)*bt_size);
s->top += bt_size + 2;
rawstack[s->top-2].uintptr = bt_size;
rawstack[s->top-1].jlvalue = exception;
}
// conversion -----------------------------------------------------------------
JL_DLLEXPORT void *(jl_symbol_name)(jl_sym_t *s)
{
return jl_symbol_name(s);
}
// WARNING: THIS FUNCTION IS NEVER CALLED BUT INLINE BY CCALL
JL_DLLEXPORT void *jl_array_ptr(jl_array_t *a)
{
return a->data;
}
JL_DLLEXPORT jl_value_t *jl_value_ptr(jl_value_t *a)
{
return a;
}
// optimization of setfield which bypasses boxing of the idx (and checking field type validity)
JL_DLLEXPORT void jl_set_nth_field(jl_value_t *v, size_t idx0, jl_value_t *rhs)
{
jl_datatype_t *st = (jl_datatype_t*)jl_typeof(v);
if (!st->name->mutabl)
jl_errorf("setfield!: immutable struct of type %s cannot be changed", jl_symbol_name(st->name->name));
if (idx0 >= jl_datatype_nfields(st))
jl_bounds_error_int(v, idx0 + 1);
//jl_value_t *ft = jl_field_type(st, idx0);
//if (!jl_isa(rhs, ft)) {
// jl_type_error("setfield!", ft, rhs);
//}
//int isatomic = jl_field_isatomic(st, idx0);
//if (isatomic) ...
set_nth_field(st, v, idx0, rhs, 0);
}
// parsing --------------------------------------------------------------------
static int substr_isspace(char *p, char *pend)
{
while (p != pend) {
if (!isspace((unsigned char)*p)) {
return 0;
}
p++;
}
return 1;
}
JL_DLLEXPORT jl_nullable_float64_t jl_try_substrtod(char *str, size_t offset, size_t len)
{
char *p;
char *bstr = str+offset;
char *pend = bstr+len;
char *tofree = NULL;
int hasvalue = 0;
errno = 0;
if (!(*pend == '\0' || isspace((unsigned char)*pend) || *pend == ',')) {
// confusing data outside substring. must copy.
char *newstr;
if (len + 1 < jl_page_size) {
newstr = (char*)alloca(len + 1);
}
else {
newstr = tofree = (char*)malloc_s(len + 1);
}
memcpy(newstr, bstr, len);
newstr[len] = 0;
bstr = newstr;
pend = bstr+len;
}
double out = jl_strtod_c(bstr, &p);
if (errno==ERANGE && (out==0 || out==HUGE_VAL || out==-HUGE_VAL)) {
hasvalue = 0;
}
else if (p == bstr) {
hasvalue = 0;
}
else {
// Deal with case where the substring might be something like "1 ",
// which is OK, and "1 X", which we don't allow.
hasvalue = substr_isspace(p, pend) ? 1 : 0;
}
if (__unlikely(tofree))
free(tofree);
jl_nullable_float64_t ret = {(uint8_t)hasvalue, out};
return ret;
}
JL_DLLEXPORT int jl_substrtod(char *str, size_t offset, size_t len, double *out)
{
jl_nullable_float64_t nd = jl_try_substrtod(str, offset, len);
if (0 != nd.hasvalue) {
*out = nd.value;
return 0;
}
return 1;
}
// MSVC pre-2013 did not define HUGE_VALF
#ifndef HUGE_VALF
#define HUGE_VALF (1e25f * 1e25f)
#endif
JL_DLLEXPORT jl_nullable_float32_t jl_try_substrtof(char *str, size_t offset, size_t len)
{
char *p;
char *bstr = str+offset;
char *pend = bstr+len;
char *tofree = NULL;
int hasvalue = 0;
errno = 0;
if (!(*pend == '\0' || isspace((unsigned char)*pend) || *pend == ',')) {
// confusing data outside substring. must copy.
char *newstr;
if (len + 1 < jl_page_size) {
newstr = (char*)alloca(len + 1);
}
else {
newstr = tofree = (char*)malloc_s(len + 1);
}
memcpy(newstr, bstr, len);
newstr[len] = 0;
bstr = newstr;
pend = bstr+len;
}
#if defined(_OS_WINDOWS_) && !defined(_COMPILER_GCC_)
float out = (float)jl_strtod_c(bstr, &p);
#else
float out = jl_strtof_c(bstr, &p);
#endif
if (errno==ERANGE && (out==0 || out==HUGE_VALF || out==-HUGE_VALF)) {
hasvalue = 0;
}
else if (p == bstr) {
hasvalue = 0;
}
else {
// Deal with case where the substring might be something like "1 ",
// which is OK, and "1 X", which we don't allow.
hasvalue = substr_isspace(p, pend) ? 1 : 0;
}
if (__unlikely(tofree))
free(tofree);
jl_nullable_float32_t ret = {(uint8_t)hasvalue, out};
return ret;
}
JL_DLLEXPORT int jl_substrtof(char *str, int offset, size_t len, float *out)
{
jl_nullable_float32_t nf = jl_try_substrtof(str, offset, len);
if (0 != nf.hasvalue) {
*out = nf.value;
return 0;
}
return 1;
}
// showing --------------------------------------------------------------------
JL_DLLEXPORT void jl_flush_cstdio(void) JL_NOTSAFEPOINT
{
fflush(stdout);
fflush(stderr);
}
JL_DLLEXPORT jl_value_t *jl_stdout_obj(void) JL_NOTSAFEPOINT
{
if (jl_base_module == NULL)
return NULL;
jl_binding_t *stdout_obj = jl_get_module_binding(jl_base_module, jl_symbol("stdout"));
return stdout_obj ? jl_atomic_load_relaxed(&stdout_obj->value) : NULL;
}
JL_DLLEXPORT jl_value_t *jl_stderr_obj(void) JL_NOTSAFEPOINT
{
if (jl_base_module == NULL)
return NULL;
jl_binding_t *stderr_obj = jl_get_module_binding(jl_base_module, jl_symbol("stderr"));
return stderr_obj ? jl_atomic_load_relaxed(&stderr_obj->value) : NULL;
}
// toys for debugging ---------------------------------------------------------
static size_t jl_show_svec(JL_STREAM *out, jl_svec_t *t, const char *head, const char *opn, const char *cls) JL_NOTSAFEPOINT
{
size_t i, n=0, len = jl_svec_len(t);
n += jl_printf(out, "%s", head);
n += jl_printf(out, "%s", opn);
for (i = 0; i < len; i++) {
jl_value_t *v = jl_svecref(t,i);
n += jl_static_show(out, v);
if (i != len-1)
n += jl_printf(out, ", ");
}
n += jl_printf(out, "%s", cls);
return n;
}
struct recur_list {
struct recur_list *prev;
jl_value_t *v;
};
static size_t jl_static_show_x(JL_STREAM *out, jl_value_t *v, struct recur_list *depth) JL_NOTSAFEPOINT;
static size_t jl_static_show_next_(JL_STREAM *out, jl_value_t *v, jl_value_t *prev, struct recur_list *depth) JL_NOTSAFEPOINT;
JL_DLLEXPORT int jl_id_start_char(uint32_t wc) JL_NOTSAFEPOINT;
JL_DLLEXPORT int jl_id_char(uint32_t wc) JL_NOTSAFEPOINT;
JL_DLLEXPORT int jl_is_identifier(char *str) JL_NOTSAFEPOINT
{
size_t i = 0;
uint32_t wc = u8_nextchar(str, &i);
if (!jl_id_start_char(wc))
return 0;
while ((wc = u8_nextchar(str, &i)) != 0) {
if (!jl_id_char(wc))
return 0;
}
return 1;
}
static jl_datatype_t *first_arg_datatype(jl_value_t *a JL_PROPAGATES_ROOT, int got_tuple1) JL_NOTSAFEPOINT
{
if (jl_is_datatype(a)) {
if (got_tuple1)
return (jl_datatype_t*)a;
if (jl_is_tuple_type(a)) {
if (jl_nparams(a) < 1)
return NULL;
return first_arg_datatype(jl_tparam0(a), 1);
}
return NULL;
}
else if (jl_is_typevar(a)) {
return first_arg_datatype(((jl_tvar_t*)a)->ub, got_tuple1);
}
else if (jl_is_unionall(a)) {
return first_arg_datatype(((jl_unionall_t*)a)->body, got_tuple1);
}
else if (jl_is_uniontype(a)) {
jl_uniontype_t *u = (jl_uniontype_t*)a;
jl_datatype_t *d1 = first_arg_datatype(u->a, got_tuple1);
if (d1 == NULL) return NULL;
jl_datatype_t *d2 = first_arg_datatype(u->b, got_tuple1);
if (d2 == NULL || d1->name != d2->name)
return NULL;
return d1;
}
return NULL;
}
// get DataType of first tuple element (if present), or NULL if cannot be determined
JL_DLLEXPORT jl_datatype_t *jl_first_argument_datatype(jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT
{
return first_arg_datatype(argtypes, 0);
}
// get DataType implied by a single given type, or `nothing`
JL_DLLEXPORT jl_value_t *jl_argument_datatype(jl_value_t *argt JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT
{
jl_datatype_t *dt = first_arg_datatype(argt, 1);
if (dt == NULL)
return jl_nothing;
return (jl_value_t*)dt;
}
static int is_globname_binding(jl_value_t *v, jl_datatype_t *dv) JL_NOTSAFEPOINT
{
jl_sym_t *globname = dv->name->mt != NULL ? dv->name->mt->name : NULL;
if (globname && dv->name->module && jl_binding_resolved_p(dv->name->module, globname)) {
jl_binding_t *b = jl_get_module_binding(dv->name->module, globname);
if (b && b->constp) {
jl_value_t *bv = jl_atomic_load_relaxed(&b->value);
// The `||` makes this function work for both function instances and function types.
if (bv == v || jl_typeof(bv) == v)
return 1;
}
}
return 0;
}
static int is_globfunction(jl_value_t *v, jl_datatype_t *dv, jl_sym_t **globname_out) JL_NOTSAFEPOINT
{
jl_sym_t *globname = dv->name->mt != NULL ? dv->name->mt->name : NULL;
*globname_out = globname;
if (globname && !strchr(jl_symbol_name(globname), '#') && !strchr(jl_symbol_name(globname), '@')) {
return 1;
}
return 0;
}
static size_t jl_static_show_x_sym_escaped(JL_STREAM *out, jl_sym_t *name) JL_NOTSAFEPOINT
{
size_t n = 0;
char *sn = jl_symbol_name(name);
int hidden = 0;
if (!(jl_is_identifier(sn) || jl_is_operator(sn))) {
hidden = 1;
}
if (hidden) {
n += jl_printf(out, "var\"");
}
n += jl_printf(out, "%s", sn);
if (hidden) {
n += jl_printf(out, "\"");
}
return n;
}
// `jl_static_show()` cannot call `jl_subtype()`, for the GC reasons
// explained in the comment on `jl_static_show_x_()`, below.
// This function checks if `vt <: Function` without triggering GC.
static int jl_static_is_function_(jl_datatype_t *vt) JL_NOTSAFEPOINT {
if (!jl_function_type) { // Make sure there's a Function type defined.
return 0;
}
int _iter_count = 0; // To prevent infinite loops from corrupt type objects.
while (vt != jl_any_type) {
if (vt == NULL) {
return 0;
} else if (_iter_count > 10000) {
// We are very likely stuck in a cyclic datastructure, so we assume this is
// _not_ a Function.
return 0;
} else if (vt == jl_function_type) {
return 1;
}
vt = vt->super;
_iter_count += 1;
}
return 0;
}
// `v` might be pointing to a field inlined in a structure therefore
// `jl_typeof(v)` may not be the same with `vt` and only `vt` should be
// used to determine the type of the value.
// This is necessary to make sure that this function doesn't allocate any
// memory through the Julia GC
static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt,
struct recur_list *depth) JL_NOTSAFEPOINT
{
size_t n = 0;
if ((uintptr_t)vt < 4096U) {
n += jl_printf(out, "<?#%p::%p>", (void*)v, (void*)vt);
}
else if ((uintptr_t)v < 4096U) {
n += jl_printf(out, "<?#%p::", (void*)v);
n += jl_static_show_x(out, (jl_value_t*)vt, depth);
n += jl_printf(out, ">");
}
// These need to be special cased because they
// exist only by pointer identity in early startup
else if (v == (jl_value_t*)jl_simplevector_type) {
n += jl_printf(out, "Core.SimpleVector");
}
else if (v == (jl_value_t*)jl_typename_type) {
n += jl_printf(out, "Core.TypeName");
}
else if (v == (jl_value_t*)jl_symbol_type) {
n += jl_printf(out, "Symbol");
}
else if (v == (jl_value_t*)jl_methtable_type) {
n += jl_printf(out, "Core.MethodTable");
}
else if (v == (jl_value_t*)jl_any_type) {
n += jl_printf(out, "Any");
}
else if (v == (jl_value_t*)jl_type_type) {
n += jl_printf(out, "Type");
}
else if (vt == jl_method_type) {
jl_method_t *m = (jl_method_t*)v;
n += jl_static_show_func_sig(out, m->sig);
}
else if (vt == jl_method_instance_type) {
jl_method_instance_t *li = (jl_method_instance_t*)v;
if (jl_is_method(li->def.method)) {
n += jl_static_show_func_sig(out, li->specTypes);
n += jl_printf(out, " from ");
n += jl_static_show_func_sig(out, li->def.method->sig);
}
else {
n += jl_static_show_x(out, (jl_value_t*)li->def.module, depth);
n += jl_printf(out, ".<toplevel thunk> -> ");
n += jl_static_show_x(out, li->uninferred, depth);
}
}
else if (vt == jl_typename_type) {
n += jl_static_show_x(out, jl_unwrap_unionall(((jl_typename_t*)v)->wrapper), depth);
n += jl_printf(out, ".name");
}
else if (vt == jl_simplevector_type) {
n += jl_show_svec(out, (jl_svec_t*)v, "svec", "(", ")");
}
else if (v == (jl_value_t*)jl_unionall_type) {
// avoid printing `typeof(Type)` for `UnionAll`.
n += jl_printf(out, "UnionAll");
}
else if (vt == jl_vararg_type) {
jl_vararg_t *vm = (jl_vararg_t*)v;
n += jl_printf(out, "Vararg");
if (vm->T) {
n += jl_printf(out, "{");
n += jl_static_show_x(out, vm->T, depth);
if (vm->N) {
n += jl_printf(out, ", ");
n += jl_static_show_x(out, vm->N, depth);
}
n += jl_printf(out, "}");
}
}
else if (vt == jl_datatype_type) {
// typeof(v) == DataType, so v is a Type object.
// Types are printed as a fully qualified name, with parameters, e.g.
// `Base.Set{Int}`, and function types are printed as e.g. `typeof(Main.f)`
jl_datatype_t *dv = (jl_datatype_t*)v;
jl_sym_t *globname;
int globfunc = is_globname_binding(v, dv) && is_globfunction(v, dv, &globname);
jl_sym_t *sym = globfunc ? globname : dv->name->name;
char *sn = jl_symbol_name(sym);
size_t quote = 0;
if (dv->name == jl_tuple_typename) {
if (dv == jl_tuple_type)
return jl_printf(out, "Tuple");
int taillen = 1, tlen = jl_nparams(dv), i;
for (i = tlen-2; i >= 0; i--) {
if (jl_tparam(dv, i) == jl_tparam(dv, tlen-1))
taillen++;
else
break;
}
if (taillen == tlen && taillen > 3) {
n += jl_printf(out, "NTuple{%d, ", tlen);
n += jl_static_show_x(out, jl_tparam0(dv), depth);
n += jl_printf(out, "}");
}
else {
n += jl_printf(out, "Tuple{");
for (i = 0; i < (taillen > 3 ? tlen-taillen : tlen); i++) {
if (i > 0)
n += jl_printf(out, ", ");
n += jl_static_show_x(out, jl_tparam(dv, i), depth);
}
if (taillen > 3) {
n += jl_printf(out, ", Vararg{");
n += jl_static_show_x(out, jl_tparam(dv, tlen-1), depth);
n += jl_printf(out, ", %d}", taillen);
}
n += jl_printf(out, "}");
}
return n;
}
if (globfunc) {
n += jl_printf(out, "typeof(");
}
if (jl_core_module && (dv->name->module != jl_core_module || !jl_module_exports_p(jl_core_module, sym))) {
n += jl_static_show_x(out, (jl_value_t*)dv->name->module, depth);
n += jl_printf(out, ".");
size_t i = 0;
if (globfunc && !jl_id_start_char(u8_nextchar(sn, &i))) {
n += jl_printf(out, ":(");
quote = 1;
}
}
n += jl_static_show_x_sym_escaped(out, sym);
if (globfunc) {
n += jl_printf(out, ")");
if (quote) {
n += jl_printf(out, ")");
}
}
if (dv->parameters && (jl_value_t*)dv != dv->name->wrapper) {
size_t j, tlen = jl_nparams(dv);
if (tlen > 0) {
n += jl_printf(out, "{");
for (j = 0; j < tlen; j++) {
jl_value_t *p = jl_tparam(dv,j);
n += jl_static_show_x(out, p, depth);
if (j != tlen-1)
n += jl_printf(out, ", ");
}
n += jl_printf(out, "}");
}
}
}
else if (vt == jl_intrinsic_type) {
int f = *(uint32_t*)jl_data_ptr(v);
n += jl_printf(out, "#<intrinsic #%d %s>", f, jl_intrinsic_name(f));
}
else if (vt == jl_int64_type) {
n += jl_printf(out, "%" PRId64, *(int64_t*)v);
}
else if (vt == jl_int32_type) {
n += jl_printf(out, "%" PRId32, *(int32_t*)v);
}
else if (vt == jl_int16_type) {
n += jl_printf(out, "%" PRId16, *(int16_t*)v);
}
else if (vt == jl_int8_type) {
n += jl_printf(out, "%" PRId8, *(int8_t*)v);
}
else if (vt == jl_uint64_type) {
n += jl_printf(out, "0x%016" PRIx64, *(uint64_t*)v);
}
else if (vt == jl_uint32_type) {
n += jl_printf(out, "0x%08" PRIx32, *(uint32_t*)v);
}
else if (vt == jl_uint16_type) {
n += jl_printf(out, "0x%04" PRIx16, *(uint16_t*)v);
}
else if (vt == jl_uint8_type) {
n += jl_printf(out, "0x%02" PRIx8, *(uint8_t*)v);
}
else if (jl_pointer_type && jl_is_cpointer_type((jl_value_t*)vt)) {
#ifdef _P64
n += jl_printf(out, "0x%016" PRIx64, *(uint64_t*)v);
#else
n += jl_printf(out, "0x%08" PRIx32, *(uint32_t*)v);
#endif
}
else if (vt == jl_float32_type) {
n += jl_printf(out, "%gf", *(float*)v);
}
else if (vt == jl_float64_type) {
n += jl_printf(out, "%g", *(double*)v);
}
else if (vt == jl_bool_type) {
n += jl_printf(out, "%s", *(uint8_t*)v ? "true" : "false");
}
else if (v == jl_nothing || (jl_nothing && (jl_value_t*)vt == jl_typeof(jl_nothing))) {
n += jl_printf(out, "nothing");
}
else if (vt == jl_string_type) {
n += jl_printf(out, "\"");
jl_uv_puts(out, jl_string_data(v), jl_string_len(v)); n += jl_string_len(v);
n += jl_printf(out, "\"");
}
else if (v == jl_bottom_type) {
n += jl_printf(out, "Union{}");
}
else if (vt == jl_uniontype_type) {
n += jl_printf(out, "Union{");
while (jl_is_uniontype(v)) {
// tail-recurse on b to flatten the printing of the Union structure in the common case
n += jl_static_show_x(out, ((jl_uniontype_t*)v)->a, depth);
n += jl_printf(out, ", ");
v = ((jl_uniontype_t*)v)->b;
}
n += jl_static_show_x(out, v, depth);
n += jl_printf(out, "}");
}
else if (vt == jl_unionall_type) {
jl_unionall_t *ua = (jl_unionall_t*)v;
n += jl_static_show_x(out, ua->body, depth);
n += jl_printf(out, " where ");
n += jl_static_show_x(out, (jl_value_t*)ua->var, depth->prev);
}
else if (vt == jl_typename_type) {
n += jl_printf(out, "typename(");
n += jl_static_show_x(out, jl_unwrap_unionall(((jl_typename_t*)v)->wrapper), depth);
n += jl_printf(out, ")");
}
else if (vt == jl_tvar_type) {
// show type-var bounds only if they aren't going to be printed by UnionAll later
jl_tvar_t *var = (jl_tvar_t*)v;
struct recur_list *p;
int showbounds = 1;
for (p = depth; p != NULL; p = p->prev) {
if (jl_is_unionall(p->v) && ((jl_unionall_t*)p->v)->var == var) {
showbounds = 0;
break;
}
}
jl_value_t *lb = var->lb, *ub = var->ub;
if (showbounds && lb != jl_bottom_type) {
// show type-var lower bound if it is defined
int ua = jl_is_unionall(lb);
if (ua)
n += jl_printf(out, "(");
n += jl_static_show_x(out, lb, depth);
if (ua)
n += jl_printf(out, ")");
n += jl_printf(out, "<:");
}
n += jl_static_show_x_sym_escaped(out, var->name);
if (showbounds && (ub != (jl_value_t*)jl_any_type || lb != jl_bottom_type)) {
// show type-var upper bound if it is defined, or if we showed the lower bound
int ua = jl_is_unionall(ub);
n += jl_printf(out, "<:");
if (ua)
n += jl_printf(out, "(");
n += jl_static_show_x(out, ub, depth);
if (ua)
n += jl_printf(out, ")");
}
}
else if (vt == jl_module_type) {
jl_module_t *m = (jl_module_t*)v;
if (m->parent != m && m->parent != jl_main_module) {
n += jl_static_show_x(out, (jl_value_t*)m->parent, depth);
n += jl_printf(out, ".");
}
n += jl_printf(out, "%s", jl_symbol_name(m->name));
}
else if (vt == jl_symbol_type) {
char *sn = jl_symbol_name((jl_sym_t*)v);
int quoted = !jl_is_identifier(sn) && jl_operator_precedence(sn) == 0;
if (quoted)
n += jl_printf(out, "Symbol(\"");
else
n += jl_printf(out, ":");
n += jl_printf(out, "%s", sn);
if (quoted)
n += jl_printf(out, "\")");
}
else if (vt == jl_ssavalue_type) {
n += jl_printf(out, "SSAValue(%" PRIuPTR ")",
(uintptr_t)((jl_ssavalue_t*)v)->id);
}
else if (vt == jl_globalref_type) {
n += jl_static_show_x(out, (jl_value_t*)jl_globalref_mod(v), depth);
char *name = jl_symbol_name(jl_globalref_name(v));
n += jl_printf(out, jl_is_identifier(name) ? ".%s" : ".:(%s)", name);
}
else if (vt == jl_gotonode_type) {
n += jl_printf(out, "goto %" PRIuPTR, jl_gotonode_label(v));
}
else if (vt == jl_quotenode_type) {
jl_value_t *qv = *(jl_value_t**)v;
if (!jl_is_symbol(qv)) {
n += jl_printf(out, "quote ");
}
else {
n += jl_printf(out, ":(");
}
n += jl_static_show_x(out, qv, depth);
if (!jl_is_symbol(qv)) {
n += jl_printf(out, " end");
}
else {
n += jl_printf(out, ")");
}
}
else if (vt == jl_newvarnode_type) {
n += jl_printf(out, "<newvar ");
n += jl_static_show_x(out, *(jl_value_t**)v, depth);
n += jl_printf(out, ">");
}
else if (vt == jl_linenumbernode_type) {
n += jl_printf(out, "#= ");
n += jl_static_show_x(out, jl_linenode_file(v), depth);
n += jl_printf(out, ":%" PRIuPTR " =#", jl_linenode_line(v));
}
else if (vt == jl_expr_type) {
jl_expr_t *e = (jl_expr_t*)v;
if (e->head == jl_assign_sym && jl_array_len(e->args) == 2) {
n += jl_static_show_x(out, jl_exprarg(e,0), depth);
n += jl_printf(out, " = ");
n += jl_static_show_x(out, jl_exprarg(e,1), depth);
}
else {
char sep = ' ';
n += jl_printf(out, "Expr(:%s", jl_symbol_name(e->head));
size_t i, len = jl_array_len(e->args);
for (i = 0; i < len; i++) {
n += jl_printf(out, ",%c", sep);
n += jl_static_show_x(out, jl_exprarg(e,i), depth);
}
n += jl_printf(out, ")");
}
}
else if (jl_array_type && jl_is_array_type(vt)) {
n += jl_printf(out, "Array{");
n += jl_static_show_x(out, (jl_value_t*)jl_tparam0(vt), depth);
n += jl_printf(out, ", (");
size_t i, ndims = jl_array_ndims(v);
if (ndims == 1)
n += jl_printf(out, "%" PRIdPTR ",", jl_array_dim0(v));
else
for (i = 0; i < ndims; i++)
n += jl_printf(out, (i > 0 ? ", %" PRIdPTR : "%" PRIdPTR), jl_array_dim(v, i));
n += jl_printf(out, ")}[");
size_t j, tlen = jl_array_len(v);
jl_array_t *av = (jl_array_t*)v;
jl_value_t *el_type = jl_tparam0(vt);
char *typetagdata = (!av->flags.ptrarray && jl_is_uniontype(el_type)) ? jl_array_typetagdata(av) : NULL;
int nlsep = 0;
if (av->flags.ptrarray) {
// print arrays with newlines, unless the elements are probably small
for (j = 0; j < tlen; j++) {
jl_value_t **ptr = ((jl_value_t**)av->data) + j;
jl_value_t *p = *ptr;
if (p != NULL && (uintptr_t)p >= 4096U) {
jl_value_t *p_ty = jl_typeof(p);
if ((uintptr_t)p_ty >= 4096U) {
if (!jl_isbits(p_ty)) {
nlsep = 1;
break;
}
}
}
}
}
if (nlsep && tlen > 1)
n += jl_printf(out, "\n ");
for (j = 0; j < tlen; j++) {
if (av->flags.ptrarray) {
jl_value_t **ptr = ((jl_value_t**)av->data) + j;
n += jl_static_show_x(out, *ptr, depth);
}
else {
char *ptr = ((char*)av->data) + j * av->elsize;
n += jl_static_show_x_(out, (jl_value_t*)ptr,
typetagdata ? (jl_datatype_t*)jl_nth_union_component(el_type, typetagdata[j]) : (jl_datatype_t*)el_type,
depth);
}
if (j != tlen - 1)
n += jl_printf(out, nlsep ? ",\n " : ", ");
}
n += jl_printf(out, "]");
}
else if (vt == jl_loaderror_type) {
n += jl_printf(out, "LoadError(at ");
n += jl_static_show_x(out, *(jl_value_t**)v, depth);
// Access the field directly to avoid allocation
n += jl_printf(out, " line %" PRIdPTR, ((intptr_t*)v)[1]);
n += jl_printf(out, ": ");
n += jl_static_show_x(out, ((jl_value_t**)v)[2], depth);
n += jl_printf(out, ")");
}
else if (vt == jl_errorexception_type) {
n += jl_printf(out, "ErrorException(");
n += jl_static_show_x(out, *(jl_value_t**)v, depth);
n += jl_printf(out, ")");
}
else if (jl_static_is_function_(vt) && is_globname_binding(v, (jl_datatype_t*)vt)) {
// v is function instance (an instance of a Function type).
jl_datatype_t *dv = (jl_datatype_t*)vt;
jl_sym_t *sym;
int globfunc = is_globfunction(v, dv, &sym);
int quote = 0;
if (jl_core_module && (dv->name->module != jl_core_module || !jl_module_exports_p(jl_core_module, sym))) {
n += jl_static_show_x(out, (jl_value_t*)dv->name->module, depth);
n += jl_printf(out, ".");
size_t i = 0;
char *sn = jl_symbol_name(sym);
if (globfunc && !jl_id_start_char(u8_nextchar(sn, &i))) {
n += jl_printf(out, ":(");
quote = 1;
}
}
n += jl_static_show_x_sym_escaped(out, sym);
if (globfunc) {
if (quote) {
n += jl_printf(out, ")");
}
}
}
else if (jl_datatype_type && jl_is_datatype(vt)) {
// typeof(v) isa DataType, so v is an *instance of* a type that is a Datatype,
// meaning v is e.g. an instance of a struct. These are printed as a call to a
// type constructor, such as e.g. `Base.UnitRange{Int64}(start=1, stop=2)`
int istuple = jl_is_tuple_type(vt), isnamedtuple = jl_is_namedtuple_type(vt);
size_t tlen = jl_datatype_nfields(vt);
if (isnamedtuple) {
if (tlen == 0)
n += jl_printf(out, "NamedTuple");
}
else if (!istuple) {
n += jl_static_show_x(out, (jl_value_t*)vt, depth);
}
n += jl_printf(out, "(");
size_t nb = jl_datatype_size(vt);
if (nb > 0 && tlen == 0) {
uint8_t *data = (uint8_t*)v;
n += jl_printf(out, "0x");
for(int i = nb - 1; i >= 0; --i)
n += jl_printf(out, "%02" PRIx8, data[i]);
}
else {
size_t i = 0;
if (vt == jl_typemap_entry_type)
i = 1;
jl_value_t *names = isnamedtuple ? jl_tparam0(vt) : (jl_value_t*)jl_field_names(vt);
for (; i < tlen; i++) {
if (!istuple) {
jl_value_t *fname = isnamedtuple ? jl_fieldref_noalloc(names, i) : jl_svecref(names, i);
n += jl_printf(out, "%s=", jl_symbol_name((jl_sym_t*)fname));
}
size_t offs = jl_field_offset(vt, i);
char *fld_ptr = (char*)v + offs;
if (jl_field_isptr(vt, i)) {
n += jl_static_show_x(out, *(jl_value_t**)fld_ptr, depth);
}
else {
jl_datatype_t *ft = (jl_datatype_t*)jl_field_type_concrete(vt, i);
if (jl_is_uniontype(ft)) {
uint8_t sel = ((uint8_t*)fld_ptr)[jl_field_size(vt, i) - 1];
ft = (jl_datatype_t*)jl_nth_union_component((jl_value_t*)ft, sel);
}
n += jl_static_show_x_(out, (jl_value_t*)fld_ptr, ft, depth);
}
if ((istuple || isnamedtuple) && tlen == 1)
n += jl_printf(out, ",");
else if (i != tlen - 1)
n += jl_printf(out, ", ");
}
if (vt == jl_typemap_entry_type) {
n += jl_printf(out, ", next=↩︎\n ");
jl_value_t *next = (jl_value_t*)jl_atomic_load_relaxed(&((jl_typemap_entry_t*)v)->next);
n += jl_static_show_next_(out, next, v, depth);
}
}
n += jl_printf(out, ")");
}
else {
n += jl_printf(out, "<?#%p::", (void*)v);
n += jl_static_show_x(out, (jl_value_t*)vt, depth);
n += jl_printf(out, ">");
}
return n;
}
static size_t jl_static_show_x(JL_STREAM *out, jl_value_t *v, struct recur_list *depth) JL_NOTSAFEPOINT
{
// show values without calling a julia method or allocating through the GC
return jl_static_show_next_(out, v, NULL, depth);
}
static size_t jl_static_show_next_(JL_STREAM *out, jl_value_t *v, jl_value_t *prev, struct recur_list *depth) JL_NOTSAFEPOINT
{
// helper for showing a typemap list by following the next pointers
// while being careful about avoiding any recursion due to malformed (circular) references
if (v == NULL) {
return jl_printf(out, "#<null>");
}
else if ((uintptr_t)v < 4096U) {
return jl_printf(out, "#<%d>", (int)(uintptr_t)v);
}
unsigned int dist = 1;
struct recur_list this_item = {depth, v},
*newdepth = &this_item,
*p = depth;
while (p) {
if (jl_typeis(v, jl_typemap_entry_type) && newdepth == &this_item) {
jl_value_t *m = p->v;
unsigned nid = 1;
while (m && jl_typeis(m, jl_typemap_entry_type)) {
if (m == v) {
return jl_printf(out, "<typemap reference #%u @-%u ", nid, dist) +
jl_static_show_x(out, (jl_value_t*)((jl_typemap_entry_t*)m)->sig, depth) +
jl_printf(out, ">");
}
if (m == prev) {
newdepth = depth;
break;
}
// verify that we aren't trying to follow a circular list
// by following the list again, and ensuring this is the only link to next
jl_value_t *mnext = (jl_value_t*)jl_atomic_load_relaxed(&((jl_typemap_entry_t*)m)->next);
jl_value_t *m2 = p->v;
if (m2 == mnext)
break;
while (m2 && jl_typeis(m2, jl_typemap_entry_type)) {
jl_value_t *mnext2 = (jl_value_t*)jl_atomic_load_relaxed(&((jl_typemap_entry_t*)m2)->next);
if (mnext2 == mnext) {
if (m2 != m)
mnext = NULL;
break;
}
m2 = mnext2;
}
m = mnext;
nid++;
}
}
if (p->v == v)
return jl_printf(out, "<circular reference @-%u>", dist);
dist++;
p = p->prev;
}
return jl_static_show_x_(out, v, (jl_datatype_t*)jl_typeof(v), newdepth);
}
JL_DLLEXPORT size_t jl_static_show(JL_STREAM *out, jl_value_t *v) JL_NOTSAFEPOINT
{
return jl_static_show_x(out, v, 0);
}
JL_DLLEXPORT size_t jl_static_show_func_sig(JL_STREAM *s, jl_value_t *type) JL_NOTSAFEPOINT
{
size_t n = 0;
size_t i;
jl_value_t *ftype = (jl_value_t*)jl_first_argument_datatype(type);
if (ftype == NULL)
return jl_static_show(s, type);
jl_unionall_t *tvars = (jl_unionall_t*)type;
int nvars = jl_subtype_env_size(type);
struct recur_list *depth = NULL;
if (nvars > 0) {
depth = (struct recur_list*)alloca(sizeof(struct recur_list) * nvars);
for (i = 0; i < nvars; i++) {
depth[i].prev = i == 0 ? NULL : &depth[i - 1];
depth[i].v = type;
type = ((jl_unionall_t*)type)->body;
}
depth += nvars - 1;
}
if (!jl_is_datatype(type)) {
n += jl_static_show(s, type);
return n;
}
if (jl_nparams(ftype) == 0 || ftype == ((jl_datatype_t*)ftype)->name->wrapper) {
n += jl_printf(s, "%s", jl_symbol_name(((jl_datatype_t*)ftype)->name->mt->name));
}
else {
n += jl_printf(s, "(::");
n += jl_static_show_x(s, ftype, depth);
n += jl_printf(s, ")");
}
size_t tl = jl_nparams(type);
n += jl_printf(s, "(");
for (i = 1; i < tl; i++) {
jl_value_t *tp = jl_tparam(type, i);
if (i != tl - 1) {
n += jl_static_show_x(s, tp, depth);
n += jl_printf(s, ", ");
}
else {
if (jl_vararg_kind(tp) == JL_VARARG_UNBOUND) {
tp = jl_unwrap_vararg(tp);
if (jl_is_unionall(tp))
n += jl_printf(s, "(");
n += jl_static_show_x(s, tp, depth);
if (jl_is_unionall(tp))
n += jl_printf(s, ")");
n += jl_printf(s, "...");
}
else {
n += jl_static_show_x(s, tp, depth);
}
}
}
n += jl_printf(s, ")");
if (jl_is_unionall(tvars)) {
depth -= nvars - 1;
int first = 1;
n += jl_printf(s, " where {");
while (jl_is_unionall(tvars)) {
if (!first)
n += jl_printf(s, ", ");
n += jl_static_show_x(s, (jl_value_t*)tvars->var, first ? NULL : depth);
tvars = (jl_unionall_t*)tvars->body;
if (!first)
depth += 1;
first = 0;
}
n += jl_printf(s, "}");
}
return n;
}
JL_DLLEXPORT void jl_(void *jl_value) JL_NOTSAFEPOINT
{
jl_jmp_buf *old_buf = jl_get_safe_restore();
jl_jmp_buf buf;
jl_set_safe_restore(&buf);
if (!jl_setjmp(buf, 0)) {
jl_static_show((JL_STREAM*)STDERR_FILENO, (jl_value_t*)jl_value);
jl_printf((JL_STREAM*)STDERR_FILENO,"\n");
}
else {
jl_printf((JL_STREAM*)STDERR_FILENO, "\n!!! ERROR in jl_ -- ABORTING !!!\n");
}
jl_set_safe_restore(old_buf);
}
JL_DLLEXPORT void jl_breakpoint(jl_value_t *v)
{
// put a breakpoint in your debugger here
}
JL_DLLEXPORT void jl_test_failure_breakpoint(jl_value_t *v)
{
// put a breakpoint in your debugger here
}
// logging tools --------------------------------------------------------------
void jl_log(int level, jl_value_t *module, jl_value_t *group, jl_value_t *id,
jl_value_t *file, jl_value_t *line, jl_value_t *kwargs,
jl_value_t *msg)
{
static jl_value_t *logmsg_func = NULL;
if (!logmsg_func && jl_base_module) {
jl_value_t *corelogging = jl_get_global(jl_base_module, jl_symbol("CoreLogging"));
if (corelogging && jl_is_module(corelogging)) {
logmsg_func = jl_get_global((jl_module_t*)corelogging, jl_symbol("logmsg_shim"));
}
}
if (!logmsg_func) {
ios_t str_;
ios_mem(&str_, 300);
JL_STREAM* str = (JL_STREAM*)&str_;
if (jl_is_string(msg)) {
jl_uv_puts(str, jl_string_data(msg), jl_string_len(msg));
}
else if (jl_is_symbol(msg)) {
jl_printf(str, "%s", jl_symbol_name((jl_sym_t*)msg));
}
jl_printf(str, "\n@ ");
if (jl_is_string(file)) {
jl_uv_puts(str, jl_string_data(file), jl_string_len(file));
}
else if (jl_is_symbol(file)) {
jl_printf(str, "%s", jl_symbol_name((jl_sym_t*)file));
}
jl_printf(str, ":");
jl_static_show(str, line);
jl_safe_printf("%s [Fallback logging]: %.*s\n",
level < JL_LOGLEVEL_INFO ? "Debug" :
level < JL_LOGLEVEL_WARN ? "Info" :
level < JL_LOGLEVEL_ERROR ? "Warning" : "Error",
(int)str_.size, str_.buf);
ios_close(&str_);
return;
}
jl_value_t **args;
const int nargs = 9;
JL_GC_PUSHARGS(args, nargs);
args[0] = logmsg_func;
args[1] = jl_box_long(level);
args[2] = msg;
// Would some of the jl_nothing here be better as `missing` instead?
args[3] = module ? module : jl_nothing;
args[4] = group ? group : jl_nothing;
args[5] = id ? id : jl_nothing;
args[6] = file ? file : jl_nothing;
args[7] = line ? line : jl_nothing;
args[8] = kwargs ? kwargs : (jl_value_t*)jl_alloc_vec_any(0);
jl_apply(args, nargs);
JL_GC_POP();
}
#ifdef __cplusplus
}
#endif