https://github.com/JuliaLang/julia
Tip revision: c8ceeefcc1dc25953a644622a895a3adcbc80dad authored by Tony Kelman on 24 June 2015, 13:45:01 UTC
Tag v0.3.10
Tag v0.3.10
Tip revision: c8ceeef
builtins.c
/*
implementations of some built-in functions and utilities
*/
#include "platform.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <setjmp.h>
#include <assert.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#if defined(_OS_WINDOWS_)
#include <malloc.h>
#if defined(_COMPILER_INTEL_)
#include <mathimf.h>
#else
#include <math.h>
#endif
#else
#include <unistd.h>
#include <math.h>
#endif
#include <ctype.h>
#include "julia.h"
#include "julia_internal.h"
#include "builtin_proto.h"
#ifdef __cplusplus
extern "C" {
#endif
// exceptions -----------------------------------------------------------------
DLLEXPORT void jl_error(const char *str)
{
if (jl_errorexception_type == NULL) {
JL_PRINTF(JL_STDERR, "%s", 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));
}
void jl_errorf(const char *fmt, ...)
{
va_list args;
ios_t buf;
ios_mem(&buf, 0);
va_start(args, fmt);
ios_vprintf(&buf, fmt, args);
va_end(args);
if (jl_errorexception_type == NULL) {
JL_PRINTF(JL_STDERR, "%s", buf.buf);
jl_exit(1);
}
jl_value_t *msg = jl_takebuf_string(&buf);
JL_GC_PUSH1(&msg);
jl_throw(jl_new_struct(jl_errorexception_type, msg));
}
void jl_too_few_args(const char *fname, int min)
{
// TODO: ArgumentError
jl_errorf("%s: too few arguments (expected %d)", fname, min);
}
void jl_too_many_args(const char *fname, int max)
{
jl_errorf("%s: too many arguments (expected %d)", fname, max);
}
void jl_type_error_rt(const char *fname, const char *context,
jl_value_t *ty, jl_value_t *got)
{
jl_value_t *ctxt=NULL;
JL_GC_PUSH2(&ctxt, &got);
ctxt = jl_pchar_to_string((char*)context, strlen(context));
jl_value_t *ex = jl_new_struct(jl_typeerror_type, jl_symbol(fname),
ctxt, ty, got);
jl_throw(ex);
}
void jl_type_error_rt_line(const char *fname, const char *context,
jl_value_t *ty, jl_value_t *got, int line)
{
jl_type_error_rt(fname, context, ty, got);
}
void jl_type_error(const char *fname, jl_value_t *expected, jl_value_t *got)
{
jl_type_error_rt(fname, "", expected, got);
}
void jl_undefined_var_error(jl_sym_t *var)
{
if (var->name[0] == '#') {
// convention for renamed variables: #...#original_name
char *nxt = strchr(var->name+1, '#');
if (nxt)
var = jl_symbol(nxt+1);
}
jl_throw(jl_new_struct(jl_undefvarerror_type, var));
}
JL_CALLABLE(jl_f_throw)
{
JL_NARGS(throw, 1, 1);
jl_throw(args[0]);
return (jl_value_t*)jl_null;
}
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();
}
void jl_pop_handler(int n)
{
while (n > 0) {
jl_eh_restore_state(jl_current_task->eh);
n--;
}
}
// primitives -----------------------------------------------------------------
static int bits_equal(void *a, void *b, int sz)
{
switch (sz) {
case 1: return *(int8_t*)a == *(int8_t*)b;
case 2: return *(int16_t*)a == *(int16_t*)b;
case 4: return *(int32_t*)a == *(int32_t*)b;
case 8: return *(int64_t*)a == *(int64_t*)b;
default: return memcmp(a, b, sz)==0;
}
}
int jl_egal(jl_value_t *a, jl_value_t *b)
{
if (a == b)
return 1;
jl_value_t *ta = (jl_value_t*)jl_typeof(a);
if (ta != (jl_value_t*)jl_typeof(b))
return 0;
if (jl_is_tuple(a)) {
size_t l = jl_tuple_len(a);
if (l != jl_tuple_len(b))
return 0;
for(size_t i=0; i < l; i++) {
if (!jl_egal(jl_tupleref(a,i),jl_tupleref(b,i)))
return 0;
}
return 1;
}
jl_datatype_t *dt = (jl_datatype_t*)ta;
if (dt == jl_datatype_type) {
jl_datatype_t *dta = (jl_datatype_t*)a;
jl_datatype_t *dtb = (jl_datatype_t*)b;
return dta->name == dtb->name &&
jl_egal((jl_value_t*)dta->parameters, (jl_value_t*)dtb->parameters);
}
if (dt->mutabl) return 0;
size_t sz = dt->size;
if (sz == 0) return 1;
size_t nf = jl_tuple_len(dt->names);
if (nf == 0) {
return bits_equal(jl_data_ptr(a), jl_data_ptr(b), sz);
}
for (size_t f=0; f < nf; f++) {
size_t offs = dt->fields[f].offset;
char *ao = (char*)jl_data_ptr(a) + offs;
char *bo = (char*)jl_data_ptr(b) + offs;
int eq;
if (dt->fields[f].isptr) {
jl_value_t *af = *(jl_value_t**)ao;
jl_value_t *bf = *(jl_value_t**)bo;
if (af == bf) eq = 1;
else if (af==NULL || bf==NULL) eq = 0;
else eq = jl_egal(af, bf);
}
else {
eq = bits_equal(ao, bo, dt->fields[f].size);
}
if (!eq) return 0;
}
return 1;
}
JL_CALLABLE(jl_f_is)
{
JL_NARGS(is, 2, 2);
if (args[0] == args[1])
return jl_true;
return jl_egal(args[0],args[1]) ? jl_true : jl_false;
}
JL_CALLABLE(jl_f_no_function)
{
jl_error("type cannot be constructed");
return (jl_value_t*)jl_null;
}
JL_CALLABLE(jl_f_typeof)
{
JL_NARGS(typeof, 1, 1);
return jl_full_type(args[0]);
}
JL_CALLABLE(jl_f_subtype)
{
JL_NARGS(subtype, 2, 2);
if (!jl_is_typevar(args[0]))
JL_TYPECHK(subtype, type, args[0]);
if (!jl_is_typevar(args[1]))
JL_TYPECHK(subtype, type, args[1]);
return (jl_subtype(args[0],args[1],0) ? jl_true : jl_false);
}
JL_CALLABLE(jl_f_isa)
{
JL_NARGS(isa, 2, 2);
JL_TYPECHK(isa, type, args[1]);
return (jl_subtype(args[0],args[1],1) ? jl_true : jl_false);
}
DLLEXPORT void jl_typeassert(jl_value_t *x, jl_value_t *t)
{
if (!jl_subtype(x,t,1))
jl_type_error("typeassert", t, x);
}
JL_CALLABLE(jl_f_typeassert)
{
JL_NARGS(typeassert, 2, 2);
JL_TYPECHK(typeassert, type, args[1]);
if (!jl_subtype(args[0],args[1],1))
jl_type_error("typeassert", args[1], args[0]);
return args[0];
}
static jl_function_t *jl_append_any_func;
extern size_t jl_page_size;
JL_CALLABLE(jl_f_apply)
{
JL_NARGSV(apply, 1);
JL_TYPECHK(apply, function, args[0]);
if (nargs == 2) {
if (((jl_function_t*)args[0])->fptr == &jl_f_tuple) {
if (jl_is_tuple(args[1]))
return args[1];
if (jl_is_array(args[1])) {
size_t n = jl_array_len(args[1]);
jl_tuple_t *t = jl_alloc_tuple(n);
JL_GC_PUSH1(&t);
for(size_t i=0; i < n; i++) {
jl_tupleset(t, i, jl_arrayref((jl_array_t*)args[1], i));
}
JL_GC_POP();
return (jl_value_t*)t;
}
}
if (jl_is_tuple(args[1])) {
return jl_apply((jl_function_t*)args[0], &jl_tupleref(args[1],0),
jl_tuple_len(args[1]));
}
}
jl_value_t *argarr = NULL;
JL_GC_PUSH1(&argarr);
jl_value_t *result;
jl_value_t **newargs;
size_t n=0, i, j;
for(i=1; i < nargs; i++) {
if (jl_is_tuple(args[i])) {
n += jl_tuple_len(args[i]);
}
else if (jl_typeis(args[i], jl_array_any_type)) {
n += jl_array_len(args[i]);
}
else {
if (jl_append_any_func == NULL) {
jl_append_any_func =
(jl_function_t*)jl_get_global(jl_base_module,
jl_symbol("append_any"));
if (jl_append_any_func == NULL) {
// error if append_any not available
JL_TYPECHK(apply, tuple, args[i]);
}
}
argarr = jl_apply(jl_append_any_func, &args[1], nargs-1);
assert(jl_typeis(argarr, jl_array_any_type));
result = jl_apply((jl_function_t*)args[0], jl_cell_data(argarr), jl_array_len(argarr));
JL_GC_POP();
return result;
}
}
if (n > jl_page_size/sizeof(jl_value_t*)) {
// put arguments on the heap if there are too many
argarr = (jl_value_t*)jl_alloc_cell_1d(n);
newargs = jl_cell_data(argarr);
}
else {
newargs = (jl_value_t**)alloca(n * sizeof(jl_value_t*));
}
n = 0;
for(i=1; i < nargs; i++) {
if (jl_is_tuple(args[i])) {
jl_tuple_t *t = (jl_tuple_t*)args[i];
size_t al = jl_tuple_len(t);
for(j=0; j < al; j++)
newargs[n++] = jl_tupleref(t, j);
}
else {
size_t al = jl_array_len(args[i]);
for (j = 0;j < al;j++) {
jl_value_t *arg = jl_cellref(args[i], j);
// apply with array splatting may have embedded NULL value
// #11772
if (__unlikely(arg == NULL)) {
jl_throw(jl_undefref_exception);
}
newargs[n++] = arg;
}
}
}
result = jl_apply((jl_function_t*)args[0], newargs, n);
JL_GC_POP();
return result;
}
void jl_add_constructors(jl_datatype_t *t);
JL_CALLABLE(jl_f_kwcall)
{
if (nargs < 3)
jl_error("internal error: malformed keyword argument call");
JL_TYPECHK(apply, function, args[0]);
jl_function_t *f = (jl_function_t*)args[0];
if (f->fptr == jl_f_ctor_trampoline)
jl_add_constructors((jl_datatype_t*)f);
if (!jl_is_gf(f))
jl_error("function does not accept keyword arguments");
jl_function_t *sorter = ((jl_methtable_t*)f->env)->kwsorter;
if (sorter == NULL) {
jl_errorf("function %s does not accept keyword arguments",
jl_gf_name(f)->name);
}
size_t nkeys = jl_unbox_long(args[1]);
size_t pa = 3 + 2*nkeys;
jl_array_t *container = (jl_array_t*)args[pa-1];
assert(jl_array_len(container) > 0);
for(size_t i=0; i < nkeys*2; i+=2) {
jl_cellset(container, i , args[2+i]);
jl_cellset(container, i+1, args[2+i+1]);
}
assert(jl_is_gf(sorter));
jl_function_t *m = jl_method_lookup((jl_methtable_t*)sorter->env, &args[pa-1], nargs-(pa-1), 1);
if (m == jl_bottom_func) {
return jl_no_method_error(f, &args[pa], nargs-pa);
}
return jl_apply(m, &args[pa-1], nargs-(pa-1));
}
// eval -----------------------------------------------------------------------
extern int jl_lineno;
JL_CALLABLE(jl_f_top_eval)
{
jl_module_t *m;
jl_value_t *ex;
if (nargs == 1) {
m = jl_main_module;
ex = args[0];
}
else {
JL_NARGS(eval, 2, 2);
JL_TYPECHK(eval, module, args[0]);
m = (jl_module_t*)args[0];
ex = args[1];
}
if (jl_is_symbol(ex)) {
return jl_eval_global_var(m, (jl_sym_t*)ex);
}
jl_value_t *v=NULL;
int last_lineno = jl_lineno;
jl_module_t *last_m = jl_current_module;
jl_module_t *task_last_m = jl_current_task->current_module;
JL_TRY {
jl_current_task->current_module = jl_current_module = m;
v = jl_toplevel_eval(ex);
}
JL_CATCH {
jl_lineno = last_lineno;
jl_current_module = last_m;
jl_current_task->current_module = task_last_m;
jl_rethrow();
}
jl_lineno = last_lineno;
jl_current_module = last_m;
jl_current_task->current_module = task_last_m;
assert(v);
return v;
}
JL_CALLABLE(jl_f_isdefined)
{
jl_module_t *m = jl_current_module;
jl_sym_t *s=NULL;
JL_NARGSV(isdefined, 1);
if (jl_is_array(args[0])) {
return jl_array_isdefined(args, nargs) ? jl_true : jl_false;
}
if (nargs == 1) {
JL_TYPECHK(isdefined, symbol, args[0]);
s = (jl_sym_t*)args[0];
}
if (nargs != 2) {
JL_NARGS(isdefined, 1, 1);
}
else {
if (!jl_is_module(args[0])) {
jl_datatype_t *vt = (jl_datatype_t*)jl_typeof(args[0]);
if (!jl_is_datatype(vt)) {
jl_type_error("isdefined", (jl_value_t*)jl_datatype_type, args[0]);
}
size_t idx;
if (jl_is_long(args[1])) {
idx = jl_unbox_long(args[1])-1;
if (idx >= jl_tuple_len(vt->names))
return jl_false;
}
else {
JL_TYPECHK(isdefined, symbol, args[1]);
idx = jl_field_index(vt, (jl_sym_t*)args[1], 0);
if ((int)idx == -1)
return jl_false;
}
return jl_field_isdefined(args[0], idx) ? jl_true : jl_false;
}
JL_TYPECHK(isdefined, module, args[0]);
JL_TYPECHK(isdefined, symbol, args[1]);
m = (jl_module_t*)args[0];
s = (jl_sym_t*)args[1];
}
assert(s);
return jl_boundp(m, s) ? jl_true : jl_false;
}
// tuples ---------------------------------------------------------------------
JL_CALLABLE(jl_f_tuple)
{
size_t i;
if (nargs == 0) return (jl_value_t*)jl_null;
jl_tuple_t *t = jl_alloc_tuple_uninit(nargs);
for(i=0; i < nargs; i++) {
jl_tupleset(t, i, args[i]);
}
return (jl_value_t*)t;
}
JL_CALLABLE(jl_f_tupleref)
{
JL_NARGS(tupleref, 2, 2);
JL_TYPECHK(tupleref, tuple, args[0]);
JL_TYPECHK(tupleref, long, args[1]);
jl_tuple_t *t = (jl_tuple_t*)args[0];
size_t i = jl_unbox_long(args[1])-1;
if (i >= jl_tuple_len(t))
jl_throw(jl_bounds_exception);
return jl_tupleref(t, i);
}
JL_CALLABLE(jl_f_tuplelen)
{
JL_NARGS(tuplelen, 1, 1);
JL_TYPECHK(tuplelen, tuple, args[0]);
return jl_box_long(jl_tuple_len(args[0]));
}
// composite types ------------------------------------------------------------
JL_CALLABLE(jl_f_get_field)
{
JL_NARGS(getfield, 2, 2);
jl_value_t *v = args[0];
jl_value_t *vt = (jl_value_t*)jl_typeof(v);
if (vt == (jl_value_t*)jl_module_type) {
JL_TYPECHK(getfield, symbol, args[1]);
return jl_eval_global_var((jl_module_t*)v, (jl_sym_t*)args[1]);
}
if (!jl_is_datatype(vt))
jl_type_error("getfield", (jl_value_t*)jl_datatype_type, v);
jl_datatype_t *st = (jl_datatype_t*)vt;
size_t idx;
if (jl_is_long(args[1])) {
idx = jl_unbox_long(args[1])-1;
if (idx >= jl_tuple_len(st->names))
jl_throw(jl_bounds_exception);
}
else {
JL_TYPECHK(getfield, symbol, args[1]);
jl_sym_t *fld = (jl_sym_t*)args[1];
idx = jl_field_index(st, fld, 1);
}
jl_value_t *fval = jl_get_nth_field(v, idx);
if (fval == NULL)
jl_throw(jl_undefref_exception);
return fval;
}
JL_CALLABLE(jl_f_set_field)
{
JL_NARGS(setfield!, 3, 3);
jl_value_t *v = args[0];
jl_value_t *vt = (jl_value_t*)jl_typeof(v);
if (vt == (jl_value_t*)jl_module_type)
jl_error("cannot assign variables in other modules");
if (!jl_is_datatype(vt))
jl_type_error("setfield!", (jl_value_t*)jl_datatype_type, v);
jl_datatype_t *st = (jl_datatype_t*)vt;
if (!st->mutabl)
jl_errorf("type %s is immutable", st->name->name->name);
size_t idx;
if (jl_is_long(args[1])) {
idx = jl_unbox_long(args[1])-1;
if (idx >= jl_tuple_len(st->names))
jl_throw(jl_bounds_exception);
}
else {
JL_TYPECHK(setfield!, symbol, args[1]);
idx = jl_field_index(st, (jl_sym_t*)args[1], 1);
}
jl_value_t *ft = jl_tupleref(st->types, idx);
if (!jl_subtype(args[2], ft, 1)) {
jl_type_error("setfield!", ft, args[2]);
}
jl_set_nth_field(v, idx, args[2]);
return args[2];
}
JL_CALLABLE(jl_f_field_type)
{
JL_NARGS(fieldtype, 2, 2);
jl_value_t *v = args[0];
jl_value_t *vt = (jl_value_t*)jl_typeof(v);
if (vt == (jl_value_t*)jl_module_type)
jl_error("cannot assign variables in other modules");
if (!jl_is_datatype(vt))
jl_type_error("fieldtype", (jl_value_t*)jl_datatype_type, v);
jl_datatype_t *st = (jl_datatype_t*)vt;
int field_index;
if (jl_is_long(args[1])) {
field_index = jl_unbox_long(args[1]) - 1;
if (field_index < 0 || field_index >= jl_tuple_len(st->names))
jl_throw(jl_bounds_exception);
}
else {
JL_TYPECHK(fieldtype, symbol, args[1]);
field_index = jl_field_index(st, (jl_sym_t*)args[1], 1);
}
return jl_tupleref(st->types, field_index);
}
// conversion -----------------------------------------------------------------
JL_CALLABLE(jl_f_convert_default)
{
jl_value_t *to = args[0];
jl_value_t *x = args[1];
if (!jl_subtype(x, (jl_value_t*)to, 1)) {
jl_no_method_error((jl_function_t*)args[2], args, 2);
}
return x;
}
DLLEXPORT void *jl_symbol_name(jl_sym_t *s)
{
return s->name;
}
//WARNING: THIS FUNCTION IS NEVER CALLED BUT INLINE BY CCALL
DLLEXPORT void *jl_array_ptr(jl_array_t *a)
{
return a->data;
}
DLLEXPORT void *jl_value_ptr(jl_value_t *a)
{
return (void*)a;
}
// printing -------------------------------------------------------------------
DLLEXPORT void jl_print_symbol(JL_STREAM *s, jl_sym_t *sym)
{
JL_PUTS(sym->name,s);
}
// for bootstrap
DLLEXPORT void jl_print_int64(JL_STREAM *s, int64_t i)
{
JL_PRINTF(s, "%lld", i);
}
DLLEXPORT int jl_substrtod(char *str, size_t offset, int len, double *out)
{
char *p;
errno = 0;
char *bstr = str+offset;
char *pend = bstr+len;
int err = 0;
if (!(*pend == '\0' || isspace((unsigned char)*pend) || *pend == ',')) {
// confusing data outside substring. must copy.
char *newstr = malloc(len+1);
memcpy(newstr, bstr, len);
newstr[len] = 0;
bstr = newstr;
pend = bstr+len;
}
*out = strtod_c(bstr, &p);
if (p == bstr ||
(errno==ERANGE && (*out==0 || *out==HUGE_VAL || *out==-HUGE_VAL)))
err = 1;
// Deal with case where the substring might be something like "1 ",
// which is OK, and "1 X", which we don't allow.
while (p != pend) {
if (!isspace((unsigned char)*p)) {
err = 1;
break;
}
p++;
}
if (bstr != str+offset)
free(bstr);
return err;
}
DLLEXPORT int jl_strtod(char *str, double *out)
{
char *p;
errno = 0;
*out = strtod_c(str, &p);
if (p == str ||
(errno==ERANGE && (*out==0 || *out==HUGE_VAL || *out==-HUGE_VAL)))
return 1;
while (*p != '\0') {
if (!isspace((unsigned char)*p))
return 1;
p++;
}
return 0;
}
// MSVC pre-2013 did not define HUGE_VALF
#ifndef HUGE_VALF
#define HUGE_VALF (1e25f * 1e25f)
#endif
DLLEXPORT int jl_substrtof(char *str, int offset, int len, float *out)
{
char *p;
errno = 0;
char *bstr = str+offset;
char *pend = bstr+len;
int err = 0;
if (!(*pend == '\0' || isspace((unsigned char)*pend) || *pend == ',')) {
// confusing data outside substring. must copy.
char *newstr = malloc(len+1);
memcpy(newstr, bstr, len);
newstr[len] = 0;
bstr = newstr;
pend = bstr+len;
}
#if defined(_OS_WINDOWS_) && !defined(_COMPILER_MINGW_)
*out = (float)strtod_c(bstr, &p);
#else
*out = strtof_c(bstr, &p);
#endif
if (p == bstr ||
(errno==ERANGE && (*out==0 || *out==HUGE_VALF || *out==-HUGE_VALF)))
err = 1;
// Deal with case where the substring might be something like "1 ",
// which is OK, and "1 X", which we don't allow.
while (p != pend) {
if (!isspace((unsigned char)*p)) {
err = 1;
break;
}
p++;
}
if (bstr != str+offset)
free(bstr);
return err;
}
DLLEXPORT int jl_strtof(char *str, float *out)
{
char *p;
errno = 0;
#if defined(_OS_WINDOWS_) && !defined(_COMPILER_MINGW_)
*out = (float)strtod_c(str, &p);
#else
*out = strtof_c(str, &p);
#endif
if (p == str ||
(errno==ERANGE && (*out==0 || *out==HUGE_VALF || *out==-HUGE_VALF)))
return 1;
while (*p != '\0') {
if (!isspace((unsigned char)*p))
return 1;
p++;
}
return 0;
}
// showing --------------------------------------------------------------------
void jl_flush_cstdio(void)
{
fflush(stdout);
fflush(stderr);
}
jl_value_t *jl_stdout_obj(void)
{
jl_value_t *stdout_obj = jl_get_global(jl_base_module, jl_symbol("STDOUT"));
if (stdout_obj != NULL) return stdout_obj;
return jl_get_global(jl_base_module, jl_symbol("OUTPUT_STREAM"));
}
jl_value_t *jl_stderr_obj(void)
{
jl_value_t *stderr_obj = jl_get_global(jl_base_module, jl_symbol("STDERR"));
if (stderr_obj != NULL) return stderr_obj;
return jl_get_global(jl_base_module, jl_symbol("OUTPUT_STREAM"));
}
static jl_function_t *jl_show_gf=NULL;
void jl_show(jl_value_t *stream, jl_value_t *v)
{
if (jl_base_module) {
if (jl_show_gf == NULL) {
jl_show_gf = (jl_function_t*)jl_get_global(jl_base_module, jl_symbol("show"));
}
if (jl_show_gf==NULL || stream==NULL) {
JL_PRINTF(JL_STDERR, " could not show value of type %s",
jl_is_tuple(v) ? "Tuple" :
((jl_datatype_t*)jl_typeof(v))->name->name->name);
return;
}
jl_value_t *args[2] = {stream,v};
jl_apply(jl_show_gf, args, 2);
}
}
// internal functions ---------------------------------------------------------
extern int jl_in_inference;
extern int jl_boot_file_loaded;
int jl_eval_with_compiler_p(jl_expr_t *expr, int compileloops);
JL_CALLABLE(jl_trampoline)
{
assert(jl_is_func(F));
jl_function_t *f = (jl_function_t*)F;
assert(f->linfo != NULL);
// to run inference on all thunks. slows down loading files.
// NOTE: if this call to inference is removed, type_annotate in inference.jl
// needs to be updated to infer inner functions.
if (f->linfo->inferred == 0) {
if (!jl_in_inference) {
if (!jl_is_expr(f->linfo->ast)) {
f->linfo->ast = jl_uncompress_ast(f->linfo, f->linfo->ast);
}
if (jl_eval_with_compiler_p(jl_lam_body((jl_expr_t*)f->linfo->ast),1)) {
jl_type_infer(f->linfo, jl_tuple_type, f->linfo);
}
}
}
jl_compile(f);
// this assertion is probably not correct; the fptr could have been assigned
// by a recursive invocation from inference above.
//assert(f->fptr == &jl_trampoline);
jl_generate_fptr(f);
if (jl_boot_file_loaded && jl_is_expr(f->linfo->ast)) {
f->linfo->ast = jl_compress_ast(f->linfo, f->linfo->ast);
}
return jl_apply(f, args, nargs);
}
JL_CALLABLE(jl_f_instantiate_type)
{
JL_NARGSV(instantiate_type, 1);
if (!jl_is_datatype(args[0]))
JL_TYPECHK(instantiate_type, typector, args[0]);
return jl_apply_type_(args[0], &args[1], nargs-1);
}
JL_CALLABLE(jl_f_new_type_constructor)
{
JL_NARGS(new_type_constructor, 2, 2);
JL_TYPECHK(new_type_constructor, tuple, args[0]);
if (!jl_is_type(args[1]))
jl_type_error("typealias", (jl_value_t*)jl_type_type, args[1]);
jl_tuple_t *p = (jl_tuple_t*)args[0];
jl_value_t *tc = (jl_value_t*)jl_new_type_ctor(p, args[1]);
int i;
for(i=0; i < jl_tuple_len(p); i++)
((jl_tvar_t*)jl_tupleref(p,i))->bound = 0;
return tc;
}
JL_CALLABLE(jl_f_typevar)
{
if (nargs < 1 || nargs > 3) {
JL_NARGS(TypeVar, 1, 1);
}
JL_TYPECHK(TypeVar, symbol, args[0]);
jl_value_t *lb = (jl_value_t*)jl_bottom_type;
jl_value_t *ub = (jl_value_t*)jl_any_type;
int b = 0;
if (args[nargs-1] == jl_true) {
b = 1;
nargs--;
}
if (nargs > 1) {
JL_TYPECHK(TypeVar, type, args[1]);
if (nargs > 2) {
JL_TYPECHK(TypeVar, type, args[2]);
lb = args[1];
ub = args[2];
}
else {
ub = args[1];
}
}
jl_tvar_t *tv = jl_new_typevar((jl_sym_t*)args[0], lb, ub);
tv->bound = b;
return (jl_value_t*)tv;
}
JL_CALLABLE(jl_f_union)
{
if (nargs == 0) return (jl_value_t*)jl_bottom_type;
if (nargs == 1) return args[0];
size_t i;
jl_tuple_t *argt = jl_alloc_tuple_uninit(nargs);
for(i=0; i < nargs; i++) {
if (!jl_is_type(args[i]) && !jl_is_typevar(args[i])) {
jl_error("invalid union type");
}
else {
jl_tupleset(argt, i, args[i]);
}
}
JL_GC_PUSH1(&argt);
jl_value_t *u = jl_type_union(argt);
JL_GC_POP();
return u;
}
// generic function reflection ------------------------------------------------
JL_CALLABLE(jl_f_methodexists)
{
JL_NARGS(method_exists, 2, 2);
JL_TYPECHK(method_exists, function, args[0]);
if (!jl_is_gf(args[0]))
jl_error("method_exists: not a generic function");
JL_TYPECHK(method_exists, tuple, args[1]);
jl_check_type_tuple((jl_tuple_t*)args[1], jl_gf_name(args[0]),
"method_exists");
return jl_method_lookup_by_type(jl_gf_mtable(args[0]),
(jl_tuple_t*)args[1],0,0)!=jl_bottom_func ?
jl_true : jl_false;
}
JL_CALLABLE(jl_f_applicable)
{
JL_NARGSV(applicable, 1);
JL_TYPECHK(applicable, function, args[0]);
if (!jl_is_gf(args[0]))
jl_error("applicable: not a generic function");
return jl_method_lookup(jl_gf_mtable(args[0]),
&args[1], nargs-1, 1) != jl_bottom_func ?
jl_true : jl_false;
}
JL_CALLABLE(jl_f_invoke)
{
JL_NARGSV(invoke, 2);
JL_TYPECHK(invoke, function, args[0]);
if (!jl_is_gf(args[0]))
jl_error("invoke: not a generic function");
JL_TYPECHK(invoke, tuple, args[1]);
jl_check_type_tuple((jl_tuple_t*)args[1], jl_gf_name(args[0]), "invoke");
if (!jl_tuple_subtype(&args[2], nargs-2, &jl_tupleref(args[1],0),
jl_tuple_len(args[1]), 1))
jl_error("invoke: argument type error");
return jl_gf_invoke((jl_function_t*)args[0],
(jl_tuple_t*)args[1], &args[2], nargs-2);
}
// eq hash table --------------------------------------------------------------
#include "table.c"
// hashing --------------------------------------------------------------------
#ifdef _P64
#define bitmix(a,b) int64hash((a)^bswap_64(b))
#define hash64(a) int64hash(a)
#else
#define bitmix(a,b) int64to32hash((((uint64_t)a)<<32)|((uint64_t)b))
#define hash64(a) int64to32hash(a)
#endif
static uptrint_t bits_hash(void *b, size_t sz)
{
switch (sz) {
case 1: return int32hash(*(int8_t*)b);
case 2: return int32hash(*(int16_t*)b);
case 4: return int32hash(*(int32_t*)b);
case 8: return hash64(*(int64_t*)b);
default:
#ifdef _P64
return memhash((char*)b, sz);
#else
return memhash32((char*)b, sz);
#endif
}
}
DLLEXPORT uptrint_t jl_object_id(jl_value_t *v)
{
if (jl_is_symbol(v))
return ((jl_sym_t*)v)->hash;
jl_value_t *tv = (jl_value_t*)jl_typeof(v);
if (tv == (jl_value_t*)jl_tuple_type) {
uptrint_t h = 0;
size_t l = jl_tuple_len(v);
for(size_t i = 0; i < l; i++) {
uptrint_t u = jl_object_id(jl_tupleref(v,i));
h = bitmix(h, u);
}
return h;
}
jl_datatype_t *dt = (jl_datatype_t*)tv;
if (dt == jl_datatype_type) {
jl_datatype_t *dtv = (jl_datatype_t*)v;
uptrint_t h = inthash((uptrint_t)tv);
return bitmix(bitmix(h, jl_object_id((jl_value_t*)dtv->name)),
jl_object_id((jl_value_t*)dtv->parameters));
}
if (dt->mutabl) return inthash((uptrint_t)v);
size_t sz = jl_datatype_size(tv);
uptrint_t h = inthash((uptrint_t)tv);
if (sz == 0) return ~h;
size_t nf = jl_tuple_len(dt->names);
if (nf == 0) {
return bits_hash(jl_data_ptr(v), sz) ^ h;
}
for (size_t f=0; f < nf; f++) {
size_t offs = dt->fields[f].offset;
char *vo = (char*)jl_data_ptr(v) + offs;
uptrint_t u;
if (dt->fields[f].isptr) {
jl_value_t *f = *(jl_value_t**)vo;
u = f==NULL ? 0 : jl_object_id(f);
}
else {
u = bits_hash(vo, dt->fields[f].size);
}
h = bitmix(h, u);
}
return h;
}
// init -----------------------------------------------------------------------
static void add_builtin(const char *name, jl_value_t *v)
{
jl_set_const(jl_core_module, jl_symbol(name), v);
}
static void add_builtin_func(const char *name, jl_fptr_t f)
{
add_builtin(name, (jl_value_t*)
jl_new_closure(f, (jl_value_t*)jl_symbol(name), NULL));
}
void jl_init_primitives(void)
{
add_builtin_func("is", jl_f_is);
add_builtin_func("typeof", jl_f_typeof);
add_builtin_func("issubtype", jl_f_subtype);
add_builtin_func("isa", jl_f_isa);
add_builtin_func("typeassert", jl_f_typeassert);
add_builtin_func("apply", jl_f_apply);
add_builtin_func("kwcall", jl_f_kwcall);
add_builtin_func("throw", jl_f_throw);
add_builtin_func("tuple", jl_f_tuple);
add_builtin_func("Union", jl_f_union);
add_builtin_func("method_exists", jl_f_methodexists);
add_builtin_func("applicable", jl_f_applicable);
add_builtin_func("invoke", jl_f_invoke);
add_builtin_func("eval", jl_f_top_eval);
add_builtin_func("isdefined", jl_f_isdefined);
add_builtin_func("yieldto", jl_f_yieldto);
// functions for internal use
add_builtin_func("convert_default", jl_f_convert_default);
add_builtin_func("tupleref", jl_f_tupleref);
add_builtin_func("tuplelen", jl_f_tuplelen);
add_builtin_func("getfield", jl_f_get_field);
add_builtin_func("setfield!", jl_f_set_field);
add_builtin_func("fieldtype", jl_f_field_type);
add_builtin_func("arraylen", jl_f_arraylen);
add_builtin_func("arrayref", jl_f_arrayref);
add_builtin_func("arrayset", jl_f_arrayset);
add_builtin_func("arraysize", jl_f_arraysize);
add_builtin_func("apply_type", jl_f_instantiate_type);
// builtin types
add_builtin("Any", (jl_value_t*)jl_any_type);
add_builtin("None", (jl_value_t*)jl_bottom_type);
add_builtin("Void", (jl_value_t*)jl_bottom_type);
add_builtin("Top", (jl_value_t*)jl_top_type);
add_builtin("TypeVar", (jl_value_t*)jl_tvar_type);
add_builtin("TypeName", (jl_value_t*)jl_typename_type);
add_builtin("TypeConstructor", (jl_value_t*)jl_typector_type);
add_builtin("Tuple", (jl_value_t*)jl_tuple_type);
add_builtin("NTuple", (jl_value_t*)jl_ntuple_type);
add_builtin("Type", (jl_value_t*)jl_type_type);
add_builtin("Vararg", (jl_value_t*)jl_vararg_type);
add_builtin("DataType", (jl_value_t*)jl_datatype_type);
add_builtin("UnionType", (jl_value_t*)jl_uniontype_type);
add_builtin("Undef", (jl_value_t*)jl_undef_type);
add_builtin("Module", (jl_value_t*)jl_module_type);
add_builtin("Method", (jl_value_t*)jl_method_type);
add_builtin("MethodTable", (jl_value_t*)jl_methtable_type);
add_builtin("Symbol", (jl_value_t*)jl_sym_type);
add_builtin("IntrinsicFunction", (jl_value_t*)jl_intrinsic_type);
add_builtin("Function", (jl_value_t*)jl_function_type);
add_builtin("LambdaStaticData", (jl_value_t*)jl_lambda_info_type);
add_builtin("Ptr", (jl_value_t*)jl_pointer_type);
add_builtin("Box", (jl_value_t*)jl_box_type);
add_builtin("Task", (jl_value_t*)jl_task_type);
add_builtin("AbstractArray", (jl_value_t*)jl_abstractarray_type);
add_builtin("DenseArray", (jl_value_t*)jl_densearray_type);
add_builtin("Array", (jl_value_t*)jl_array_type);
add_builtin("Expr", (jl_value_t*)jl_expr_type);
add_builtin("LineNumberNode", (jl_value_t*)jl_linenumbernode_type);
add_builtin("LabelNode", (jl_value_t*)jl_labelnode_type);
add_builtin("GotoNode", (jl_value_t*)jl_gotonode_type);
add_builtin("QuoteNode", (jl_value_t*)jl_quotenode_type);
add_builtin("TopNode", (jl_value_t*)jl_topnode_type);
add_builtin("NewvarNode", (jl_value_t*)jl_newvarnode_type);
#ifdef _P64
add_builtin("Int", (jl_value_t*)jl_int64_type);
#else
add_builtin("Int", (jl_value_t*)jl_int32_type);
#endif
add_builtin("ANY", jl_ANY_flag);
}
// toys for debugging ---------------------------------------------------------
// comma_one prints a comma for 1 element, e.g. "(x,)"
static size_t jl_show_tuple(JL_STREAM *out, jl_tuple_t *t, char *opn, char *cls, int comma_one)
{
size_t i, n=0, len = jl_tuple_len(t);
n += JL_PRINTF(out, "(");
for (i = 0; i < len; i++) {
jl_value_t *v = jl_tupleref(t,i);
n += jl_static_show(out, v);
if (len == 1)
n += JL_PRINTF(out, ",");
else if (i != len-1)
n += JL_PRINTF(out, ", ");
}
n += JL_PRINTF(out, ")");
return n;
}
DLLEXPORT size_t jl_static_show(JL_STREAM *out, jl_value_t *v)
{
// mimic jl_show, but never calling a julia method
size_t n = 0;
if (v == NULL) {
n += JL_PRINTF(out, "#<null>");
}
else if (jl_is_lambda_info(v)) {
jl_lambda_info_t *li = (jl_lambda_info_t*)v;
n += jl_static_show(out, (jl_value_t*)li->module);
n += JL_PRINTF(out, ".%s", li->name->name);
if (li->specTypes) {
n += jl_static_show(out, (jl_value_t*)li->specTypes);
}
else {
n += JL_PRINTF(out, "(?)");
}
}
else if (jl_is_tuple(v)) {
n += jl_show_tuple(out, (jl_tuple_t*)v, "(", ")", 1);
}
else if (jl_is_vararg_type(v)) {
n += jl_static_show(out, jl_tparam0(v));
n += JL_PRINTF(out, "...");
}
else if (jl_is_datatype(v)) {
jl_datatype_t *dv = (jl_datatype_t*)v;
if (dv->name->module != jl_core_module) {
n += jl_static_show(out, (jl_value_t*)dv->name->module);
JL_PUTS(".", out); n += 1;
}
n += JL_PRINTF(out, "%s", dv->name->name->name);
if (dv->parameters) {
size_t j, tlen = jl_tuple_len(dv->parameters);
if (tlen > 0) {
n += JL_PRINTF(out, "{");
for (j = 0; j < tlen; j++) {
jl_value_t *p = jl_tupleref(dv->parameters,j);
n += jl_static_show(out, p);
if (j != tlen-1)
n += JL_PRINTF(out, ", ");
}
n += JL_PRINTF(out, "}");
}
}
}
else if (jl_is_func(v)) {
if (jl_is_gf(v)) {
n += JL_PRINTF(out, "%s", jl_gf_name(v)->name);
}
else {
n += JL_PRINTF(out, "#<function>");
}
}
else if (jl_typeis(v, jl_intrinsic_type)) {
n += JL_PRINTF(out, "#<intrinsic function %d>", *(uint32_t*)jl_data_ptr(v));
}
else if (jl_is_int64(v)) {
n += JL_PRINTF(out, "%d", jl_unbox_int64(v));
}
else if (jl_is_int32(v)) {
n += JL_PRINTF(out, "%d", jl_unbox_int32(v));
}
else if (jl_typeis(v,jl_int16_type)) {
n += JL_PRINTF(out, "%d", jl_unbox_int16(v));
}
else if (jl_typeis(v,jl_int8_type)) {
n += JL_PRINTF(out, "%d", jl_unbox_int8(v));
}
else if (jl_is_uint64(v)) {
n += JL_PRINTF(out, "0x%016x", jl_unbox_uint64(v));
}
else if (jl_is_uint32(v)) {
n += JL_PRINTF(out, "0x%08x", jl_unbox_uint32(v));
}
else if (jl_typeis(v,jl_uint16_type)) {
n += JL_PRINTF(out, "0x%04x", jl_unbox_uint16(v));
}
else if (jl_typeis(v,jl_uint8_type)) {
n += JL_PRINTF(out, "0x%02x", jl_unbox_uint8(v));
}
else if (jl_is_cpointer(v)) {
#ifdef _P64
n += JL_PRINTF(out, "0x%016x", jl_unbox_voidpointer(v));
#else
n += JL_PRINTF(out, "0x%08x", jl_unbox_voidpointer(v));
#endif
}
else if (jl_is_float32(v)) {
n += JL_PRINTF(out, "%g", jl_unbox_float32(v));
}
else if (jl_is_float64(v)) {
n += JL_PRINTF(out, "%g", jl_unbox_float64(v));
}
else if (v == jl_true) {
n += JL_PRINTF(out, "true");
}
else if (v == jl_false) {
n += JL_PRINTF(out, "false");
}
else if (jl_is_byte_string(v)) {
n += JL_PRINTF(out, "\"%s\"", jl_iostr_data(v));
}
else if (v == jl_bottom_type) {
n += JL_PRINTF(out, "Void");
}
else if (jl_is_uniontype(v)) {
n += JL_PRINTF(out, "Union");
n += jl_static_show(out, (jl_value_t*)((jl_uniontype_t*)v)->types);
}
else if (jl_is_typector(v)) {
n += jl_static_show(out, ((jl_typector_t*)v)->body);
}
else if (jl_is_typevar(v)) {
n += jl_static_show(out, ((jl_tvar_t*)v)->lb);
n += JL_PRINTF(out, "<:%s<:", ((jl_tvar_t*)v)->name->name);
n += jl_static_show(out, ((jl_tvar_t*)v)->ub);
}
else if (jl_is_module(v)) {
jl_module_t *m = (jl_module_t*)v;
if (m->parent != m && m->parent != jl_main_module) {
n += jl_static_show(out, (jl_value_t*)m->parent);
n += JL_PRINTF(out, ".");
}
n += JL_PRINTF(out, "%s", m->name->name);
}
else if (jl_is_symbol(v)) {
n += JL_PRINTF(out, ":%s", ((jl_sym_t*)v)->name);
}
else if (jl_is_symbolnode(v)) {
n += JL_PRINTF(out, "%s::", jl_symbolnode_sym(v)->name);
n += jl_static_show(out, jl_symbolnode_type(v));
}
else if (jl_is_getfieldnode(v)) {
n += jl_static_show(out, jl_getfieldnode_val(v));
n += JL_PRINTF(out, ".%s", jl_getfieldnode_name(v)->name);
n += JL_PRINTF(out, "::");
n += jl_static_show(out, jl_getfieldnode_type(v));
}
else if (jl_is_labelnode(v)) {
n += JL_PRINTF(out, "%d:", jl_labelnode_label(v));
}
else if (jl_is_gotonode(v)) {
n += JL_PRINTF(out, "goto %d", jl_gotonode_label(v));
}
else if (jl_is_quotenode(v)) {
jl_value_t *qv = jl_fieldref(v,0);
if (!jl_is_symbol(qv)) { n += JL_PRINTF(out, "quote "); }
n += jl_static_show(out, qv);
if (!jl_is_symbol(qv)) { n += JL_PRINTF(out, " end"); }
}
else if (jl_is_topnode(v)) {
n += JL_PRINTF(out, "top(");
n += jl_static_show(out, jl_fieldref(v,0));
n += JL_PRINTF(out, ")");
}
else if (jl_is_linenode(v)) {
n += JL_PRINTF(out, "# line %d", jl_linenode_line(v));
}
else if (jl_is_expr(v)) {
jl_expr_t *e = (jl_expr_t*)v;
if (e->head == assign_sym && jl_array_len(e->args) == 2) {
n += jl_static_show(out, jl_exprarg(e,0));
n += JL_PRINTF(out, " = ");
n += jl_static_show(out, jl_exprarg(e,1));
}
else {
char sep = ' ';
if (e->head == body_sym)
sep = '\n';
n += JL_PRINTF(out, "Expr(:%s", e->head->name);
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(out, jl_exprarg(e,i));
}
n += JL_PRINTF(out, ")::");
n += jl_static_show(out, e->etype);
}
}
else if (jl_is_array(v)) {
n += jl_static_show(out, jl_typeof(v));
n += JL_PRINTF(out, "[");
size_t j, tlen = jl_array_len(v);
for (j = 0; j < tlen; j++) {
jl_value_t *elt;
if (((jl_array_t*)v)->ptrarray)
elt = jl_cellref(v, j);
else
elt = jl_arrayref((jl_array_t*)v,j);
n += jl_static_show(out, elt);
if (j != tlen-1)
n += JL_PRINTF(out, ", ");
}
n += JL_PRINTF(out, "]");
}
else if (jl_typeis(v,jl_loaderror_type)) {
n += JL_PRINTF(out, "LoadError(at ");
n += jl_static_show(out, jl_fieldref(v, 0));
n += JL_PRINTF(out, " line ");
n += jl_static_show(out, jl_fieldref(v, 1));
n += JL_PRINTF(out, ": ");
n += jl_static_show(out, jl_fieldref(v, 2));
n += JL_PRINTF(out, ")");
}
else if (jl_typeis(v,jl_errorexception_type)) {
n += JL_PRINTF(out, "ErrorException(");
n += jl_static_show(out, jl_fieldref(v, 0));
n += JL_PRINTF(out, ")");
}
else if (jl_is_datatype(jl_typeof(v))) {
jl_datatype_t *t = (jl_datatype_t*)jl_typeof(v);
n += jl_static_show(out, (jl_value_t*)t);
n += JL_PRINTF(out, "(");
size_t nb = jl_datatype_size(t);
size_t tlen = jl_tuple_len(t->names);
if (nb > 0 && tlen == 0) {
char *data = (char*)jl_data_ptr(v);
n += JL_PRINTF(out, "0x");
for(int i=nb-1; i >= 0; --i)
n += JL_PRINTF(out, "%02hhx", data[i]);
}
else {
jl_value_t *fldval=NULL;
JL_GC_PUSH1(&fldval);
for (size_t i = 0; i < tlen; i++) {
n += JL_PRINTF(out, ((jl_sym_t*)jl_tupleref(t->names, i))->name);
//jl_fielddesc_t f = t->fields[i];
n += JL_PRINTF(out, "=");
fldval = jl_get_nth_field(v, i);
n += jl_static_show(out, fldval);
if (i != tlen-1)
n += JL_PRINTF(out, ", ");
}
JL_GC_POP();
}
n += JL_PRINTF(out, ")");
}
else {
n += JL_PRINTF(out, "<?::");
n += jl_static_show(out, jl_typeof(v));
n += JL_PRINTF(out, ">");
}
return n;
}
int in_jl_ = 0;
DLLEXPORT void jl_(void *jl_value)
{
in_jl_++;
JL_TRY {
(void)jl_static_show(JL_STDOUT, (jl_value_t*)jl_value);
JL_PRINTF(JL_STDOUT,"\n");
}
JL_CATCH {
JL_PRINTF(JL_STDOUT, "\n!!! ERROR in jl_ -- ABORTING !!!\n");
}
in_jl_--;
}
DLLEXPORT void jl_breakpoint(jl_value_t *v)
{
// put a breakpoint in you debugger here
}
#ifdef __cplusplus
}
#endif