// this is a heuristic for allowing "redefining" a type to something identical static int equiv_type(jl_datatype_t *dta, jl_datatype_t *dtb) { if (!(jl_typeof(dta) == jl_typeof(dtb) && dta->name->name == dtb->name->name && dta->abstract == dtb->abstract && dta->mutabl == dtb->mutabl && dta->size == dtb->size && dta->ninitialized == dtb->ninitialized && jl_egal((jl_value_t*)dta->name->names, (jl_value_t*)dtb->name->names) && jl_nparams(dta) == jl_nparams(dtb) && jl_field_count(dta) == jl_field_count(dtb))) return 0; jl_value_t *a=NULL, *b=NULL; int ok = 1; size_t i, nf = jl_field_count(dta); JL_GC_PUSH2(&a, &b); a = jl_rewrap_unionall((jl_value_t*)dta->super, dta->name->wrapper); b = jl_rewrap_unionall((jl_value_t*)dtb->super, dtb->name->wrapper); if (!jl_types_equal(a, b)) goto no; JL_TRY { a = jl_apply_type(dtb->name->wrapper, jl_svec_data(dta->parameters), jl_nparams(dta)); } JL_CATCH { ok = 0; } if (!ok) goto no; assert(jl_is_datatype(a)); a = dta->name->wrapper; b = dtb->name->wrapper; while (jl_is_unionall(a)) { jl_unionall_t *ua = (jl_unionall_t*)a; jl_unionall_t *ub = (jl_unionall_t*)b; if (!jl_egal(ua->var->lb, ub->var->lb) || !jl_egal(ua->var->ub, ub->var->ub) || ua->var->name != ub->var->name) goto no; a = jl_instantiate_unionall(ua, (jl_value_t*)ub->var); b = ub->body; } assert(jl_is_datatype(a) && jl_is_datatype(b)); for (i=0; i < nf; i++) { jl_value_t *ta = jl_svecref(((jl_datatype_t*)a)->types, i); jl_value_t *tb = jl_svecref(((jl_datatype_t*)b)->types, i); if (jl_has_free_typevars(ta)) { if (!jl_has_free_typevars(tb) || !jl_egal(ta, tb)) goto no; } else if (jl_has_free_typevars(tb) || jl_typeof(ta) != jl_typeof(tb) || !jl_types_equal(ta, tb)) { goto no; } } JL_GC_POP(); return 1; no: JL_GC_POP(); return 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; }
// this is a heuristic for allowing "redefining" a type to something identical static int equiv_type(jl_datatype_t *dta, jl_datatype_t *dtb) { return (jl_typeof(dta) == jl_typeof(dtb) && // TODO: can't yet handle parametric types due to how constructors work dta->parameters == jl_null && dta->name->name == dtb->name->name && jl_egal((jl_value_t*)dta->types, (jl_value_t*)dtb->types) && dta->abstract == dtb->abstract && dta->mutabl == dtb->mutabl && dta->size == dtb->size && jl_egal((jl_value_t*)dta->super, (jl_value_t*)dtb->super) && jl_egal((jl_value_t*)dta->names, (jl_value_t*)dtb->names) && jl_egal((jl_value_t*)dta->parameters, (jl_value_t*)dtb->parameters)); }
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_bits_type(ta)) { size_t nb = jl_bitstype_nbits(ta)/8; switch (nb) { case 1: return *(int8_t*)jl_bits_data(a) == *(int8_t*)jl_bits_data(b); case 2: return *(int16_t*)jl_bits_data(a) == *(int16_t*)jl_bits_data(b); case 4: return *(int32_t*)jl_bits_data(a) == *(int32_t*)jl_bits_data(b); case 8: return *(int64_t*)jl_bits_data(a) == *(int64_t*)jl_bits_data(b); default: return memcmp(jl_bits_data(a), jl_bits_data(b), nb)==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; } return 0; }
// See comment above for an explanation of NOINLINE. static int NOINLINE compare_fields(jl_value_t *a, jl_value_t *b, jl_datatype_t *dt) { size_t nf = jl_datatype_nfields(dt); for (size_t f=0; f < nf; f++) { size_t offs = jl_field_offset(dt, f); char *ao = (char*)jl_data_ptr(a) + offs; char *bo = (char*)jl_data_ptr(b) + offs; int eq; if (jl_field_isptr(dt, f)) { 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 { jl_datatype_t *ft = (jl_datatype_t*)jl_field_type(dt, f); if (!ft->layout->haspadding) { eq = bits_equal(ao, bo, jl_field_size(dt, f)); } else { assert(jl_datatype_nfields(ft) > 0); eq = compare_fields((jl_value_t*)ao, (jl_value_t*)bo, ft); } } if (!eq) return 0; } return 1; }
static int literal_val_id(jl_value_t *v) { for(int i=0; i < jl_array_len(tree_literal_values); i++) { if (jl_egal(jl_cellref(tree_literal_values,i), v)) return i; } jl_cell_1d_push(tree_literal_values, v); return jl_array_len(tree_literal_values)-1; }
// The frequently used jl_egal function deserves special attention when it // comes to performance which is made challenging by the fact that the // function has to handle quite a few different cases and because it is // called recursively. To optimize performance many special cases are // handle with separate comparisons which can dramatically reduce the run // time of the function. The compiler can translate these simple tests // with little effort, e.g., few registers are used. // // The complex cases require more effort and more registers to be translated // efficiently. The effected cases include comparing tuples and fields. If // the code to perform these operation would be inlined in the jl_egal // function then the compiler would generate at the or close to the top of // the function a prologue which saves all the callee-save registers and at // the end the respective epilogue. The result is that even the fast cases // are slowed down. // // The solution is to keep the code in jl_egal simple and split out the // (more) complex cases into their own functions which are marked with // NOINLINE. static int NOINLINE compare_svec(jl_svec_t *a, jl_svec_t *b) { size_t l = jl_svec_len(a); if (l != jl_svec_len(b)) return 0; for(size_t i=0; i < l; i++) { if (!jl_egal(jl_svecref(a,i),jl_svecref(b,i))) return 0; } return 1; }
DLLEXPORT void jl_checked_assignment(jl_binding_t *b, jl_value_t *rhs) { if (b->constp && b->value != NULL) { if (!jl_egal(rhs, b->value)) { if (jl_typeof(rhs) != jl_typeof(b->value) || jl_is_type(rhs) || jl_is_function(rhs) || jl_is_module(rhs)) { jl_errorf("invalid redefinition of constant %s", b->name->name); } JL_PRINTF(JL_STDERR,"Warning: redefining constant %s\n",b->name->name); } } b->value = rhs; }
static int equiv_type(jl_datatype_t *dta, jl_datatype_t *dtb) { return (jl_typeof(dta) == jl_typeof(dtb) && dta->name->name == dtb->name->name && dta->abstract == dtb->abstract && dta->mutabl == dtb->mutabl && dta->size == dtb->size && dta->ninitialized == dtb->ninitialized && equiv_svec_dt(dta->parameters, dtb->parameters) && equiv_svec_dt(dta->types, dtb->types) && jl_subtype((jl_value_t*)dta->super, (jl_value_t*)dtb->super, 0) && jl_subtype((jl_value_t*)dtb->super, (jl_value_t*)dta->super, 0) && jl_egal((jl_value_t*)dta->name->names, (jl_value_t*)dtb->name->names)); }
JL_DLLEXPORT void jl_checked_assignment(jl_binding_t *b, jl_value_t *rhs) { if (b->constp && b->value != NULL) { if (!jl_egal(rhs, b->value)) { if (jl_typeof(rhs) != jl_typeof(b->value) || jl_is_type(rhs) || jl_is_function(rhs) || jl_is_module(rhs)) { jl_errorf("invalid redefinition of constant %s", jl_symbol_name(b->name)); } jl_printf(JL_STDERR, "WARNING: redefining constant %s\n", jl_symbol_name(b->name)); } } b->value = rhs; jl_gc_wb_binding(b, rhs); }
static int egal_types(jl_value_t *a, jl_value_t *b, jl_typeenv_t *env) { if (a == b) return 1; jl_datatype_t *dt = (jl_datatype_t*)jl_typeof(a); if (dt != (jl_datatype_t*)jl_typeof(b)) return 0; if (dt == jl_tvar_type) { jl_typeenv_t *pe = env; while (pe != NULL) { if (pe->var == (jl_tvar_t*)a) return pe->val == b; pe = pe->prev; } return 0; } if (dt == jl_uniontype_type) { return egal_types(((jl_uniontype_t*)a)->a, ((jl_uniontype_t*)b)->a, env) && egal_types(((jl_uniontype_t*)a)->b, ((jl_uniontype_t*)b)->b, env); } if (dt == jl_unionall_type) { jl_unionall_t *ua = (jl_unionall_t*)a; jl_unionall_t *ub = (jl_unionall_t*)b; if (ua->var->name != ub->var->name) return 0; if (!(egal_types(ua->var->lb, ub->var->lb, env) && egal_types(ua->var->ub, ub->var->ub, env))) return 0; jl_typeenv_t e = { ua->var, (jl_value_t*)ub->var, env }; return egal_types(ua->body, ub->body, &e); } if (dt == jl_datatype_type) { jl_datatype_t *dta = (jl_datatype_t*)a; jl_datatype_t *dtb = (jl_datatype_t*)b; if (dta->name != dtb->name) return 0; size_t i, l = jl_nparams(dta); if (jl_nparams(dtb) != l) return 0; for (i = 0; i < l; i++) { if (!egal_types(jl_tparam(dta, i), jl_tparam(dtb, i), env)) return 0; } return 1; } return jl_egal(a, b); }
// See comment above for an explanation of NOINLINE. static int NOINLINE compare_fields(jl_value_t *a, jl_value_t *b, jl_datatype_t *dt) { size_t f, nf = jl_datatype_nfields(dt); for (f = 0; f < nf; f++) { size_t offs = jl_field_offset(dt, f); char *ao = (char*)jl_data_ptr(a) + offs; char *bo = (char*)jl_data_ptr(b) + offs; if (jl_field_isptr(dt, f)) { jl_value_t *af = *(jl_value_t**)ao; jl_value_t *bf = *(jl_value_t**)bo; if (af != bf) { if (af == NULL || bf == NULL) return 0; if (!jl_egal(af, bf)) return 0; } } else { jl_datatype_t *ft = (jl_datatype_t*)jl_field_type(dt, f); if (jl_is_uniontype(ft)) { uint8_t asel = ((uint8_t*)ao)[jl_field_size(dt, f) - 1]; uint8_t bsel = ((uint8_t*)bo)[jl_field_size(dt, f) - 1]; if (asel != bsel) return 0; ft = (jl_datatype_t*)jl_nth_union_component((jl_value_t*)ft, asel); } if (!ft->layout->haspadding) { if (!bits_equal(ao, bo, ft->size)) return 0; } else { assert(jl_datatype_nfields(ft) > 0); if (!compare_fields((jl_value_t*)ao, (jl_value_t*)bo, ft)) return 0; } } } return 1; }