// copy a :lambda Expr into its LambdaInfo representation static void jl_lambda_info_set_ast(jl_lambda_info_t *li, jl_expr_t *ast) { assert(jl_is_expr(ast)); jl_expr_t *bodyex = (jl_expr_t*)jl_exprarg(ast, 2); assert(jl_is_expr(bodyex)); jl_array_t *body = bodyex->args; li->code = (jl_value_t*)body; jl_gc_wb(li, li->code); if (has_meta(body, pure_sym)) li->pure = 1; jl_array_t *vinfo = (jl_array_t*)jl_exprarg(ast, 1); jl_array_t *vis = (jl_array_t*)jl_array_ptr_ref(vinfo, 0); size_t nslots = jl_array_len(vis); jl_value_t *ssavalue_types = jl_array_ptr_ref(vinfo, 2); assert(jl_is_long(ssavalue_types)); size_t nssavalue = jl_unbox_long(ssavalue_types); li->slotnames = jl_alloc_vec_any(nslots); jl_gc_wb(li, li->slotnames); li->slottypes = jl_nothing; li->slotflags = jl_alloc_array_1d(jl_array_uint8_type, nslots); jl_gc_wb(li, li->slotflags); li->ssavaluetypes = jl_box_long(nssavalue); jl_gc_wb(li, li->ssavaluetypes); int i; for(i=0; i < nslots; i++) { jl_value_t *vi = jl_array_ptr_ref(vis, i); jl_sym_t *name = (jl_sym_t*)jl_array_ptr_ref(vi, 0); assert(jl_is_symbol(name)); char *str = jl_symbol_name(name); if (i > 0 && name != unused_sym) { if (str[0] == '#') { // convention for renamed variables: #...#original_name char *nxt = strchr(str + 1, '#'); if (nxt) name = jl_symbol(nxt+1); else if (str[1] == 's') // compiler-generated temporaries, #sXXX name = compiler_temp_sym; } } jl_array_ptr_set(li->slotnames, i, name); jl_array_uint8_set(li->slotflags, i, jl_unbox_long(jl_array_ptr_ref(vi, 2))); } jl_array_t *sparams = (jl_array_t*)jl_array_ptr_ref(vinfo, 3); assert(jl_is_array(sparams)); li->sparam_syms = jl_alloc_svec_uninit(jl_array_len(sparams)); jl_gc_wb(li, li->sparam_syms); for(i=0; i < jl_array_len(sparams); i++) { jl_svecset(li->sparam_syms, i, jl_array_ptr_ref(sparams, i)); } jl_array_t *args = (jl_array_t*)jl_exprarg(ast, 0); size_t narg = jl_array_len(args); li->nargs = narg; li->isva = narg > 0 && jl_is_rest_arg(jl_array_ptr_ref(args, narg - 1)); }
static void jl_typemap_list_insert_(jl_typemap_entry_t **pml, jl_value_t *parent, jl_typemap_entry_t *newrec, const struct jl_typemap_info *tparams) { if (*pml == (void*)jl_nothing || newrec->isleafsig) { newrec->next = *pml; jl_gc_wb(newrec, newrec->next); *pml = newrec; jl_gc_wb(parent, newrec); } else { jl_typemap_list_insert_sorted(pml, parent, newrec, tparams); } }
static void mtcache_rehash(jl_array_t **pa, jl_value_t *parent, int8_t tparam, int8_t offs) { size_t i, len = jl_array_len(*pa); size_t newlen = next_power_of_two(len) * 2; jl_value_t **d = (jl_value_t**)jl_array_data(*pa); jl_array_t *n = jl_alloc_vec_any(newlen); for (i = 1; i <= len; i++) { union jl_typemap_t ml; ml.unknown = d[i - 1]; if (ml.unknown != NULL && ml.unknown != jl_nothing) { jl_value_t *t; if (jl_typeof(ml.unknown) == (jl_value_t*)jl_typemap_level_type) { t = ml.node->key; } else { t = jl_field_type(ml.leaf->sig, offs); if (tparam) t = jl_tparam0(t); } uintptr_t uid = ((jl_datatype_t*)t)->uid; size_t idx = uid & (newlen - 1); if (((jl_value_t**)n->data)[idx] == NULL) { ((jl_value_t**)n->data)[idx] = ml.unknown; } else { // hash collision: start over after doubling the size again i = 0; newlen *= 2; n = jl_alloc_vec_any(newlen); } } } *pa = n; jl_gc_wb(parent, n); }
JL_DLLEXPORT jl_array_t *jl_idtable_rehash(jl_array_t *a, size_t newsz) { // Assume *pa don't need a write barrier // pa doesn't have to be a GC slot but *pa needs to be rooted size_t sz = jl_array_len(a); size_t i; void **ol = (void**)a->data; jl_array_t *newa = jl_alloc_vec_any(newsz); // keep the original array in the original slot since we need `ol` // to be valid in the loop below. JL_GC_PUSH1(&newa); for(i=0; i < sz; i+=2) { if (ol[i+1] != NULL) { (*jl_table_lookup_bp(&newa, ol[i])) = ol[i+1]; jl_gc_wb(newa, ol[i+1]); // it is however necessary here because allocation // can (and will) occur in a recursive call inside table_lookup_bp } } // we do not check the write barrier here // because pa always points to a C stack location // (see jl_eqtable_put and jl_finalize_deserializer) // it should be changed if this assumption no longer holds JL_GC_POP(); return newa; }
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); } }
static void mtcache_rehash(struct jl_ordereddict_t *pa, size_t newlen, jl_value_t *parent, int8_t tparam, int8_t offs) { size_t i, nval = jl_array_len(pa->values); jl_array_t *n = jl_alloc_int_1d(nval + 1, newlen); for (i = 1; i <= nval; i++) { union jl_typemap_t ml; ml.unknown = jl_array_ptr_ref(pa->values, i - 1); if (ml.unknown == jl_nothing) continue; jl_value_t *t; if (jl_typeof(ml.unknown) == (jl_value_t*)jl_typemap_level_type) { t = ml.node->key; } else { assert(jl_typeof(ml.unknown) == (jl_value_t*)jl_typemap_entry_type); t = jl_field_type(ml.leaf->sig, offs); if (tparam) t = jl_tparam0(t); } uintptr_t uid = ((jl_datatype_t*)t)->uid; size_t newi = uid & (newlen - 1); if (jl_intref(n, newi) == 0) { jl_intset(n, newi, i); } else { // hash collision: start over after doubling the size again i = 0; newlen *= 2; n = jl_alloc_int_1d(nval + 1, newlen); } } pa->indexes = n; jl_gc_wb(parent, n); }
static union jl_typemap_t *mtcache_hash_bp(struct jl_ordereddict_t *pa, jl_value_t *ty, int8_t tparam, int8_t offs, jl_value_t *parent) { if (jl_is_datatype(ty)) { uintptr_t uid = ((jl_datatype_t*)ty)->uid; if (!uid || is_kind(ty) || jl_has_typevars(ty)) // be careful not to put non-leaf types or DataType/TypeConstructor in the cache here, // since they should have a lower priority and need to go into the sorted list return NULL; if (pa->values == (void*)jl_nothing) { pa->indexes = jl_alloc_int_1d(0, INIT_CACHE_SIZE); jl_gc_wb(parent, pa->indexes); pa->values = jl_alloc_vec_any(0); jl_gc_wb(parent, pa->values); } while (1) { size_t slot = uid & (pa->indexes->nrows - 1); size_t idx = jl_intref(pa->indexes, slot); if (idx == 0) { jl_array_ptr_1d_push(pa->values, jl_nothing); idx = jl_array_len(pa->values); if (idx > jl_max_int(pa->indexes)) mtcache_rehash(pa, jl_array_len(pa->indexes), parent, tparam, offs); jl_intset(pa->indexes, slot, idx); return &((union jl_typemap_t*)jl_array_data(pa->values))[idx - 1]; } union jl_typemap_t *pml = &((union jl_typemap_t*)jl_array_data(pa->values))[idx - 1]; if (pml->unknown == jl_nothing) return pml; jl_value_t *t; if (jl_typeof(pml->unknown) == (jl_value_t*)jl_typemap_level_type) { t = pml->node->key; } else { assert(jl_typeof(pml->unknown) == (jl_value_t*)jl_typemap_entry_type); t = jl_field_type(pml->leaf->sig, offs); if (tparam) t = jl_tparam0(t); } if (t == ty) return pml; mtcache_rehash(pa, jl_array_len(pa->indexes) * 2, parent, tparam, offs); } } return NULL; }
void jl_set_global(jl_module_t *m, jl_sym_t *var, jl_value_t *val) { jl_binding_t *bp = jl_get_binding_wr(m, var); if (!bp->constp) { bp->value = val; jl_gc_wb(m, val); } }
JL_DLLEXPORT jl_array_t *jl_eqtable_put(jl_array_t *h, void *key, void *val) { void **bp = jl_table_lookup_bp(&h, key); *bp = val; jl_gc_wb(h, val); return h; }
JL_DLLEXPORT void jl_set_const(jl_module_t *m, jl_sym_t *var, jl_value_t *val) { jl_binding_t *bp = jl_get_binding_wr(m, var); if (!bp->constp) { bp->value = val; bp->constp = 1; jl_gc_wb(m, val); } }
DLLEXPORT jl_value_t *jl_f_new_module(jl_sym_t *name, uint8_t std_imports) { jl_module_t *m = jl_new_module(name); JL_GC_PUSH1(&m); m->parent = jl_main_module; jl_gc_wb(m, m->parent); if (std_imports) jl_add_standard_imports(m); JL_GC_POP(); return (jl_value_t*)m; }
JL_DLLEXPORT jl_array_t *jl_eqtable_put(jl_array_t *h, void *key, void *val) { JL_GC_PUSH1(&h); // &h may be assigned to in jl_idtable_rehash so it need to be rooted void **bp = jl_table_lookup_bp(&h, key); *bp = val; jl_gc_wb(h, val); JL_GC_POP(); return h; }
JL_DLLEXPORT jl_value_t *jl_module_globalref(jl_module_t *m, jl_sym_t *var) { jl_binding_t *b = (jl_binding_t*)ptrhash_get(&m->bindings, var); if (b == HT_NOTFOUND) { return jl_new_struct(jl_globalref_type, m, var); } if (b->globalref == NULL) { b->globalref = jl_new_struct(jl_globalref_type, m, var); jl_gc_wb(m, b->globalref); } return b->globalref; }
JL_DLLEXPORT void jl_set_nth_field(jl_value_t *v, size_t i, jl_value_t *rhs) { jl_datatype_t *st = (jl_datatype_t*)jl_typeof(v); size_t offs = jl_field_offset(st,i); if (jl_field_isptr(st,i)) { *(jl_value_t**)((char*)v + offs) = rhs; if (rhs != NULL) jl_gc_wb(v, rhs); } else { jl_assign_bits((char*)v + offs, rhs); } }
static jl_sym_t *_jl_symbol(const char *str, size_t len) { jl_sym_t **pnode; jl_sym_t *parent; pnode = symtab_lookup(&symtab, str, len, &parent); if (*pnode == NULL) { *pnode = mk_symbol(str, len); if (parent != NULL) jl_gc_wb(parent, *pnode); } return *pnode; }
jl_method_t *jl_new_method(jl_lambda_info_t *definition, jl_sym_t *name, jl_tupletype_t *sig, jl_svec_t *tvars, int isstaged) { assert(definition->code); jl_method_t *m = jl_new_method_uninit(); m->isstaged = isstaged; m->name = name; m->sig = sig; if (jl_svec_len(tvars) == 1) tvars = (jl_svec_t*)jl_svecref(tvars, 0); m->tvars = tvars; m->ambig = jl_nothing; JL_GC_PUSH1(&m); // the front end may add this lambda to multiple methods; make a copy if so jl_method_t *oldm = definition->def; int reused = oldm != NULL; if (reused) definition = jl_copy_lambda(definition); definition->specTypes = isstaged ? jl_anytuple_type : sig; m->lambda_template = definition; jl_gc_wb(m, definition); definition->def = m; jl_gc_wb(definition, m); if (reused) { m->file = oldm->file; m->line = oldm->line; m->called = oldm->called; } else { jl_array_t *stmts = (jl_array_t*)definition->code; int i, l; for(i = 0, l = jl_array_len(stmts); i < l; i++) { jl_array_ptr_set(stmts, i, jl_resolve_globals(jl_array_ptr_ref(stmts, i), definition)); } jl_method_init_properties(m); } JL_GC_POP(); return m; }
JL_DLLEXPORT jl_value_t *jl_f_new_module(jl_sym_t *name, uint8_t std_imports) { // TODO: should we prohibit this during incremental compilation? jl_module_t *m = jl_new_module(name); JL_GC_PUSH1(&m); m->parent = jl_main_module; // TODO: this is a lie jl_gc_wb(m, m->parent); if (std_imports) jl_add_standard_imports(m); JL_GC_POP(); // TODO: should we somehow try to gc-root this correctly? return (jl_value_t*)m; }
void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) { if (!jl_is_datatype(super) || !jl_is_abstracttype(super) || tt->name == ((jl_datatype_t*)super)->name || jl_subtype(super,(jl_value_t*)jl_vararg_type,0) || jl_is_tuple_type(super) || jl_subtype(super,(jl_value_t*)jl_type_type,0) || super == (jl_value_t*)jl_builtin_type) { jl_errorf("invalid subtyping in definition of %s", jl_symbol_name(tt->name->name)); } tt->super = (jl_datatype_t*)super; jl_gc_wb(tt, tt->super); }
JL_DLLEXPORT void jl_arrayset(jl_array_t *a, jl_value_t *rhs, size_t i) { assert(i < jl_array_len(a)); jl_value_t *el_type = jl_tparam0(jl_typeof(a)); if (el_type != (jl_value_t*)jl_any_type) { if (!jl_subtype(rhs, el_type, 1)) jl_type_error("arrayset", el_type, rhs); } if (!a->flags.ptrarray) { jl_assign_bits(&((char*)a->data)[i*a->elsize], rhs); } else { ((jl_value_t**)a->data)[i] = rhs; jl_gc_wb(jl_array_owner(a), rhs); } }
void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) { if (!jl_is_datatype(super) || !jl_is_abstracttype(super) || tt->name == ((jl_datatype_t*)super)->name || jl_subtype(super,(jl_value_t*)jl_vararg_type,0) || jl_is_tuple_type(super) || jl_subtype(super,(jl_value_t*)jl_type_type,0)) { jl_errorf("invalid subtyping in definition of %s",tt->name->name->name); } tt->super = (jl_datatype_t*)super; jl_gc_wb(tt, tt->super); if (jl_svec_len(tt->parameters) > 0) { tt->name->cache = jl_emptysvec; tt->name->linearcache = jl_emptysvec; jl_reinstantiate_inner_types(tt); } }
void jl_idtable_rehash(jl_array_t **pa, size_t newsz) { size_t sz = jl_array_len(*pa); size_t i; void **ol = (void**)(*pa)->data; *pa = jl_alloc_cell_1d(newsz); // we do not check the write barrier here // because pa always points to a C stack location // (see eqtable_put) // it should be changed if this assumption no longer holds for(i=0; i < sz; i+=2) { if (ol[i+1] != NULL) { (*jl_table_lookup_bp(pa, ol[i])) = ol[i+1]; jl_gc_wb(*pa, ol[i+1]); // it is however necessary here because allocation // can (and will) occur in a recursive call inside table_lookup_bp } } }
static void jl_typemap_insert_generic(union jl_typemap_t *pml, jl_value_t *parent, jl_typemap_entry_t *newrec, jl_value_t *key, int8_t offs, const struct jl_typemap_info *tparams) { if (jl_typeof(pml->unknown) == (jl_value_t*)jl_typemap_level_type) { jl_typemap_level_insert_(pml->node, newrec, offs, tparams); return; } unsigned count = jl_typemap_list_count(pml->leaf); if (count > MAX_METHLIST_COUNT) { pml->node = jl_method_convert_list_to_cache(pml->leaf, key, offs); jl_gc_wb(parent, pml->node); jl_typemap_level_insert_(pml->node, newrec, offs, tparams); return; } jl_typemap_list_insert_(&pml->leaf, parent, newrec, tparams); }
void jl_arrayset(jl_array_t *a, jl_value_t *rhs, size_t i) { assert(i < jl_array_len(a)); jl_value_t *el_type = jl_tparam0(jl_typeof(a)); if (el_type != (jl_value_t*)jl_any_type) { if (!jl_subtype(rhs, el_type, 1)) jl_type_error("arrayset", el_type, rhs); } if (!a->ptrarray) { jl_assign_bits(&((char*)a->data)[i*a->elsize], rhs); } else { ((jl_value_t**)a->data)[i] = rhs; jl_value_t *owner = (jl_value_t*)a; if (a->how == 3) { owner = jl_array_data_owner(a); } jl_gc_wb(owner, rhs); } }
static void _compile_all_deq(jl_array_t *found) { int found_i, found_l = jl_array_len(found); jl_printf(JL_STDERR, "found %d uncompiled methods for compile-all\n", (int)found_l); jl_method_instance_t *linfo = NULL; jl_value_t *src = NULL; JL_GC_PUSH2(&linfo, &src); for (found_i = 0; found_i < found_l; found_i++) { if (found_i % (1 + found_l / 300) == 0 || found_i == found_l - 1) // show 300 progress steps, to show progress without overwhelming log files jl_printf(JL_STDERR, " %d / %d\r", found_i + 1, found_l); jl_typemap_entry_t *ml = (jl_typemap_entry_t*)jl_array_ptr_ref(found, found_i); jl_method_t *m = ml->func.method; if (m->isstaged) // TODO: generic implementations of generated functions continue; linfo = m->unspecialized; if (!linfo) { linfo = jl_get_specialized(m, (jl_value_t*)m->sig, jl_emptysvec); m->unspecialized = linfo; jl_gc_wb(m, linfo); } if (linfo->jlcall_api == 2) continue; src = m->source; // TODO: the `unspecialized` field is not yet world-aware, so we can't store // an inference result there. //src = jl_type_infer(&linfo, jl_world_counter, 1); //m->unspecialized = linfo; //jl_gc_wb(m, linfo); //if (linfo->jlcall_api == 2) // continue; // first try to create leaf signatures from the signature declaration and compile those _compile_all_union((jl_value_t*)ml->sig); // then also compile the generic fallback jl_compile_linfo(&linfo, (jl_code_info_t*)src, jl_world_counter, &jl_default_cgparams); assert(linfo->functionObjectsDecls.functionObject != NULL); } JL_GC_POP(); jl_printf(JL_STDERR, "\n"); }
JL_DLLEXPORT void jl_set_nth_field(jl_value_t *v, size_t i, jl_value_t *rhs) { jl_datatype_t *st = (jl_datatype_t*)jl_typeof(v); size_t offs = jl_field_offset(st, i); if (jl_field_isptr(st, i)) { *(jl_value_t**)((char*)v + offs) = rhs; if (rhs != NULL) jl_gc_wb(v, rhs); } else { jl_value_t *ty = jl_field_type(st, i); if (jl_is_uniontype(ty)) { uint8_t *psel = &((uint8_t*)v)[offs + jl_field_size(st, i) - 1]; unsigned nth = 0; if (!jl_find_union_component(ty, jl_typeof(rhs), &nth)) assert(0 && "invalid field assignment to isbits union"); *psel = nth; if (jl_is_datatype_singleton((jl_datatype_t*)jl_typeof(rhs))) return; } jl_assign_bits((char*)v + offs, rhs); } }
// empty generic function def // TODO: maybe have jl_method_def call this DLLEXPORT jl_value_t *jl_generic_function_def(jl_sym_t *name, jl_value_t **bp, jl_value_t *bp_owner, jl_binding_t *bnd) { jl_value_t *gf=NULL; if (bnd && bnd->value != NULL && !bnd->constp) jl_errorf("cannot define function %s; it already has a value", bnd->name->name); if (*bp != NULL) { gf = *bp; if (!jl_is_gf(gf)) jl_errorf("cannot define function %s; it already has a value", name->name); } if (bnd) bnd->constp = 1; if (*bp == NULL) { jl_module_t *module = (bnd ? bnd->owner : NULL); gf = (jl_value_t*)jl_new_generic_function(name, module); *bp = gf; if (bp_owner) jl_gc_wb(bp_owner, gf); } return gf; }
JL_DLLEXPORT jl_value_t *jl_copy_ast(jl_value_t *expr) { if (expr == NULL) { return NULL; } else if (jl_is_expr(expr)) { jl_expr_t *e = (jl_expr_t*)expr; size_t i, l = jl_array_len(e->args); jl_expr_t *ne = NULL; JL_GC_PUSH2(&ne, &expr); ne = jl_exprn(e->head, l); if (l == 0) { ne->args = jl_alloc_vec_any(0); jl_gc_wb(ne, ne->args); } else { for(i=0; i < l; i++) { jl_exprargset(ne, i, jl_copy_ast(jl_exprarg(e,i))); } } JL_GC_POP(); return (jl_value_t*)ne; } else if (jl_typeis(expr,jl_array_any_type)) { jl_array_t *a = (jl_array_t*)expr; size_t i, l = jl_array_len(a); jl_array_t *na = NULL; JL_GC_PUSH2(&na, &expr); na = jl_alloc_vec_any(l); for(i=0; i < l; i++) jl_array_ptr_set(na, i, jl_copy_ast(jl_array_ptr_ref(a,i))); JL_GC_POP(); return (jl_value_t*)na; } return expr; }
static union jl_typemap_t *mtcache_hash_bp(jl_array_t **pa, jl_value_t *ty, int8_t tparam, int8_t offs, jl_value_t *parent) { if (jl_is_datatype(ty)) { uintptr_t uid = ((jl_datatype_t*)ty)->uid; if (!uid || is_kind(ty) || jl_has_typevars(ty)) // be careful not to put non-leaf types or DataType/TypeConstructor in the cache here, // since they should have a lower priority and need to go into the sorted list return NULL; if (*pa == (void*)jl_nothing) { *pa = jl_alloc_vec_any(INIT_CACHE_SIZE); jl_gc_wb(parent, *pa); } while (1) { union jl_typemap_t *pml = &((union jl_typemap_t*)jl_array_data(*pa))[uid & ((*pa)->nrows-1)]; union jl_typemap_t ml = *pml; if (ml.unknown == NULL || ml.unknown == jl_nothing) { pml->unknown = jl_nothing; return pml; } jl_value_t *t; if (jl_typeof(ml.unknown) == (jl_value_t*)jl_typemap_level_type) { t = ml.node->key; } else { t = jl_field_type(ml.leaf->sig, offs); if (tparam) t = jl_tparam0(t); } if (t == ty) return pml; mtcache_rehash(pa, parent, tparam, offs); } } return NULL; }
static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl, size_t ngensym) { if (jl_is_symbol(e)) { jl_value_t *v; size_t i; for(i=0; i < nl; i++) { if (locals[i*2] == e) { v = locals[i*2+1]; break; } } if (i >= nl) { v = jl_get_global(jl_current_module, (jl_sym_t*)e); } if (v == NULL) { jl_undefined_var_error((jl_sym_t*)e); } return v; } if (jl_is_symbolnode(e)) { return eval((jl_value_t*)jl_symbolnode_sym(e), locals, nl, ngensym); } if (jl_is_gensym(e)) { ssize_t genid = ((jl_gensym_t*)e)->id; if (genid >= ngensym || genid < 0) jl_error("access to invalid GenSym location"); else return locals[nl*2 + genid]; } if (jl_is_quotenode(e)) { return jl_fieldref(e,0); } if (jl_is_topnode(e)) { jl_sym_t *s = (jl_sym_t*)jl_fieldref(e,0); jl_value_t *v = jl_get_global(jl_base_relative_to(jl_current_module),s); if (v == NULL) jl_undefined_var_error(s); return v; } if (!jl_is_expr(e)) { if (jl_is_globalref(e)) { jl_value_t *gfargs[2] = {(jl_value_t*)jl_globalref_mod(e), (jl_value_t*)jl_globalref_name(e)}; return jl_f_get_field(NULL, gfargs, 2); } if (jl_is_lambda_info(e)) { jl_lambda_info_t *li = (jl_lambda_info_t*)e; if (jl_boot_file_loaded && li->ast && jl_is_expr(li->ast)) { li->ast = jl_compress_ast(li, li->ast); jl_gc_wb(li, li->ast); } return (jl_value_t*)jl_new_closure(NULL, (jl_value_t*)jl_emptysvec, li); } if (jl_is_linenode(e)) { jl_lineno = jl_linenode_line(e); } if (jl_is_newvarnode(e)) { jl_value_t *var = jl_fieldref(e,0); assert(!jl_is_gensym(var)); assert(jl_is_symbol(var)); for(size_t i=0; i < nl; i++) { if (locals[i*2] == var) { locals[i*2+1] = NULL; break; } } return (jl_value_t*)jl_nothing; } return e; } jl_expr_t *ex = (jl_expr_t*)e; jl_value_t **args = (jl_value_t**)jl_array_data(ex->args); size_t nargs = jl_array_len(ex->args); if (ex->head == call_sym) { if (jl_is_lambda_info(args[0])) { // directly calling an inner function ("let") jl_lambda_info_t *li = (jl_lambda_info_t*)args[0]; if (jl_is_expr(li->ast) && !jl_lam_vars_captured((jl_expr_t*)li->ast) && !jl_has_intrinsics((jl_expr_t*)li->ast, (jl_expr_t*)li->ast, jl_current_module)) { size_t na = nargs-1; if (na == 0) return jl_interpret_toplevel_thunk(li); jl_array_t *formals = jl_lam_args((jl_expr_t*)li->ast); size_t nreq = jl_array_len(formals); if (nreq==0 || !jl_is_rest_arg(jl_cellref(formals,nreq-1))) { jl_value_t **ar; JL_GC_PUSHARGS(ar, na*2); for(int i=0; i < na; i++) { ar[i*2+1] = eval(args[i+1], locals, nl, ngensym); jl_gc_wb(ex->args, ar[i*2+1]); } if (na != nreq) { jl_error("wrong number of arguments"); } for(int i=0; i < na; i++) { jl_value_t *v = jl_cellref(formals, i); ar[i*2] = (jl_is_gensym(v)) ? v : (jl_value_t*)jl_decl_var(v); } jl_value_t *ret = jl_interpret_toplevel_thunk_with(li, ar, na); JL_GC_POP(); return ret; } } } jl_function_t *f = (jl_function_t*)eval(args[0], locals, nl, ngensym); if (jl_is_func(f)) return do_call(f, &args[1], nargs-1, NULL, locals, nl, ngensym); else return do_call(jl_module_call_func(jl_current_module), args, nargs, (jl_value_t*)f, locals, nl, ngensym); } else if (ex->head == assign_sym) { jl_value_t *sym = args[0]; jl_value_t *rhs = eval(args[1], locals, nl, ngensym); if (jl_is_gensym(sym)) { ssize_t genid = ((jl_gensym_t*)sym)->id; if (genid >= ngensym || genid < 0) jl_error("assignment to invalid GenSym location"); locals[nl*2 + genid] = rhs; return rhs; } if (jl_is_symbol(sym)) { size_t i; for (i=0; i < nl; i++) { if (locals[i*2] == sym) { locals[i*2+1] = rhs; return rhs; } } } jl_module_t *m = jl_current_module; if (jl_is_globalref(sym)) { m = jl_globalref_mod(sym); sym = (jl_value_t*)jl_globalref_name(sym); } assert(jl_is_symbol(sym)); JL_GC_PUSH1(&rhs); jl_binding_t *b = jl_get_binding_wr(m, (jl_sym_t*)sym); jl_checked_assignment(b, rhs); JL_GC_POP(); return rhs; } else if (ex->head == new_sym) { jl_value_t *thetype = eval(args[0], locals, nl, ngensym); jl_value_t *v=NULL; JL_GC_PUSH2(&thetype, &v); assert(jl_is_structtype(thetype)); v = jl_new_struct_uninit((jl_datatype_t*)thetype); for(size_t i=1; i < nargs; i++) { jl_set_nth_field(v, i-1, eval(args[i], locals, nl, ngensym)); } JL_GC_POP(); return v; } else if (ex->head == null_sym) { return (jl_value_t*)jl_nothing; } else if (ex->head == body_sym) { return eval_body(ex->args, locals, nl, ngensym, 0, 0); } else if (ex->head == exc_sym) { return jl_exception_in_transit; } else if (ex->head == static_typeof_sym) { return (jl_value_t*)jl_any_type; } else if (ex->head == method_sym) { jl_sym_t *fname = (jl_sym_t*)args[0]; jl_value_t **bp=NULL; jl_value_t *bp_owner=NULL; jl_binding_t *b=NULL; jl_value_t *gf=NULL; int kw=0; if (jl_is_expr(fname) || jl_is_globalref(fname)) { if (jl_is_expr(fname) && ((jl_expr_t*)fname)->head == kw_sym) { kw = 1; fname = (jl_sym_t*)jl_exprarg(fname, 0); } gf = eval((jl_value_t*)fname, locals, nl, ngensym); if (jl_is_expr(fname)) fname = (jl_sym_t*)jl_fieldref(jl_exprarg(fname, 2), 0); bp = &gf; assert(jl_is_symbol(fname)); } else { for (size_t i=0; i < nl; i++) { if (locals[i*2] == (jl_value_t*)fname) { bp = &locals[i*2+1]; break; } } if (bp == NULL) { b = jl_get_binding_for_method_def(jl_current_module, fname); bp = &b->value; bp_owner = (jl_value_t*)jl_current_module; } } if (jl_expr_nargs(ex) == 1) return jl_generic_function_def(fname, bp, bp_owner, b); jl_value_t *atypes=NULL, *meth=NULL; JL_GC_PUSH2(&atypes, &meth); atypes = eval(args[1], locals, nl, ngensym); if (jl_is_lambda_info(args[2])) { jl_check_static_parameter_conflicts((jl_lambda_info_t*)args[2], (jl_svec_t*)jl_svecref(atypes,1), fname); } meth = eval(args[2], locals, nl, ngensym); jl_method_def(fname, bp, bp_owner, b, (jl_svec_t*)atypes, (jl_function_t*)meth, args[3], NULL, kw); JL_GC_POP(); return *bp; } else if (ex->head == copyast_sym) { return jl_copy_ast(eval(args[0], locals, nl, ngensym)); } else if (ex->head == const_sym) { jl_value_t *sym = args[0]; assert(jl_is_symbol(sym)); for (size_t i=0; i < nl; i++) { if (locals[i*2] == sym) { return (jl_value_t*)jl_nothing; } } jl_binding_t *b = jl_get_binding_wr(jl_current_module, (jl_sym_t*)sym); jl_declare_constant(b); return (jl_value_t*)jl_nothing; } else if (ex->head == global_sym) { // create uninitialized mutable binding for "global x" decl // TODO: handle type decls for (size_t i=0; i < jl_array_len(ex->args); i++) { assert(jl_is_symbol(args[i])); jl_get_binding_wr(jl_current_module, (jl_sym_t*)args[i]); } return (jl_value_t*)jl_nothing; } else if (ex->head == abstracttype_sym) { jl_value_t *name = args[0]; jl_value_t *para = eval(args[1], locals, nl, ngensym); jl_value_t *super = NULL; jl_value_t *temp = NULL; jl_datatype_t *dt = NULL; JL_GC_PUSH4(¶, &super, &temp, &dt); assert(jl_is_svec(para)); assert(jl_is_symbol(name)); dt = jl_new_abstracttype(name, jl_any_type, (jl_svec_t*)para); jl_binding_t *b = jl_get_binding_wr(jl_current_module, (jl_sym_t*)name); temp = b->value; check_can_assign_type(b); b->value = (jl_value_t*)dt; jl_gc_wb_binding(b, dt); super = eval(args[2], locals, nl, ngensym); jl_set_datatype_super(dt, super); b->value = temp; if (temp==NULL || !equiv_type(dt, (jl_datatype_t*)temp)) { jl_checked_assignment(b, (jl_value_t*)dt); } JL_GC_POP(); return (jl_value_t*)jl_nothing; } else if (ex->head == bitstype_sym) { jl_value_t *name = args[0]; jl_value_t *super = NULL, *para = NULL, *vnb = NULL, *temp = NULL; jl_datatype_t *dt = NULL; JL_GC_PUSH4(¶, &super, &temp, &dt); assert(jl_is_symbol(name)); para = eval(args[1], locals, nl, ngensym); assert(jl_is_svec(para)); vnb = eval(args[2], locals, nl, ngensym); if (!jl_is_long(vnb)) jl_errorf("invalid declaration of bits type %s", ((jl_sym_t*)name)->name); ssize_t nb = jl_unbox_long(vnb); if (nb < 1 || nb>=(1<<23) || (nb&7) != 0) jl_errorf("invalid number of bits in type %s", ((jl_sym_t*)name)->name); dt = jl_new_bitstype(name, jl_any_type, (jl_svec_t*)para, nb); jl_binding_t *b = jl_get_binding_wr(jl_current_module, (jl_sym_t*)name); temp = b->value; check_can_assign_type(b); b->value = (jl_value_t*)dt; jl_gc_wb_binding(b, dt); super = eval(args[3], locals, nl, ngensym); jl_set_datatype_super(dt, super); b->value = temp; if (temp==NULL || !equiv_type(dt, (jl_datatype_t*)temp)) { jl_checked_assignment(b, (jl_value_t*)dt); } JL_GC_POP(); return (jl_value_t*)jl_nothing; } else if (ex->head == compositetype_sym) { jl_value_t *name = args[0]; assert(jl_is_symbol(name)); jl_value_t *para = eval(args[1], locals, nl, ngensym); assert(jl_is_svec(para)); jl_value_t *temp = NULL; jl_value_t *super = NULL; jl_datatype_t *dt = NULL; JL_GC_PUSH4(¶, &super, &temp, &dt); temp = eval(args[2], locals, nl, ngensym); // field names dt = jl_new_datatype((jl_sym_t*)name, jl_any_type, (jl_svec_t*)para, (jl_svec_t*)temp, NULL, 0, args[5]==jl_true ? 1 : 0, jl_unbox_long(args[6])); jl_binding_t *b = jl_get_binding_wr(jl_current_module, (jl_sym_t*)name); temp = b->value; // save old value // temporarily assign so binding is available for field types check_can_assign_type(b); b->value = (jl_value_t*)dt; jl_gc_wb_binding(b,dt); JL_TRY { // operations that can fail inside_typedef = 1; dt->types = (jl_svec_t*)eval(args[4], locals, nl, ngensym); jl_gc_wb(dt, dt->types); inside_typedef = 0; for(size_t i=0; i < jl_svec_len(dt->types); i++) { jl_value_t *elt = jl_svecref(dt->types, i); if (!jl_is_type(elt) && !jl_is_typevar(elt)) jl_type_error_rt(dt->name->name->name, "type definition", (jl_value_t*)jl_type_type, elt); } super = eval(args[3], locals, nl, ngensym); jl_set_datatype_super(dt, super); } JL_CATCH { b->value = temp; jl_rethrow(); } for(size_t i=0; i < jl_svec_len(para); i++) { ((jl_tvar_t*)jl_svecref(para,i))->bound = 0; } jl_compute_field_offsets(dt); if (para == (jl_value_t*)jl_emptysvec && jl_is_datatype_singleton(dt)) { dt->instance = newstruct(dt); jl_gc_wb(dt, dt->instance); } b->value = temp; if (temp==NULL || !equiv_type(dt, (jl_datatype_t*)temp)) { jl_checked_assignment(b, (jl_value_t*)dt); } else { // TODO: remove all old ctors and set temp->name->ctor_factory = dt->name->ctor_factory } JL_GC_POP(); return (jl_value_t*)jl_nothing; }
JL_DLLEXPORT jl_datatype_t *jl_new_datatype(jl_sym_t *name, jl_datatype_t *super, jl_svec_t *parameters, jl_svec_t *fnames, jl_svec_t *ftypes, int abstract, int mutabl, int ninitialized) { jl_datatype_t *t=NULL; jl_typename_t *tn=NULL; JL_GC_PUSH2(&t, &tn); if (!jl_boot_file_loaded && jl_is_symbol(name)) { // hack to avoid making two versions of basic types needed // during bootstrapping if (!strcmp(jl_symbol_name((jl_sym_t*)name), "Int32")) t = jl_int32_type; else if (!strcmp(jl_symbol_name((jl_sym_t*)name), "Int64")) t = jl_int64_type; else if (!strcmp(jl_symbol_name((jl_sym_t*)name), "Bool")) t = jl_bool_type; else if (!strcmp(jl_symbol_name((jl_sym_t*)name), "UInt8")) t = jl_uint8_type; } if (t == NULL) t = jl_new_uninitialized_datatype(jl_svec_len(fnames), 2); // TODO else tn = t->name; // init before possibly calling jl_new_typename t->super = super; if (super != NULL) jl_gc_wb(t, t->super); t->parameters = parameters; jl_gc_wb(t, t->parameters); t->types = ftypes; if (ftypes != NULL) jl_gc_wb(t, t->types); t->abstract = abstract; t->mutabl = mutabl; t->pointerfree = 0; t->ninitialized = ninitialized; t->instance = NULL; t->struct_decl = NULL; t->ditype = NULL; t->size = 0; t->alignment = 1; t->haspadding = 0; if (tn == NULL) { t->name = NULL; if (jl_is_typename(name)) { tn = (jl_typename_t*)name; } else { tn = jl_new_typename((jl_sym_t*)name); if (!abstract) { tn->mt = jl_new_method_table(name, jl_current_module); jl_gc_wb(tn, tn->mt); } } t->name = tn; jl_gc_wb(t, t->name); } t->name->names = fnames; jl_gc_wb(t->name, t->name->names); if (t->name->primary == NULL) { t->name->primary = (jl_value_t*)t; jl_gc_wb(t->name, t); } jl_precompute_memoized_dt(t); if (abstract || jl_svec_len(parameters) > 0) { t->uid = 0; } else { t->uid = jl_assign_type_uid(); if (t->types != NULL) jl_compute_field_offsets(t); } JL_GC_POP(); return t; }