From bc2d48d52e6442bc3037342076229b515f7097c5 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 12 Jun 2017 13:30:19 -0400 Subject: [PATCH] incremental deserialize: fix backedge insertion the previous attempt to preserve the backedge map was being too cute it is more reliable to simply flatten the whole map into the new caller also corrects the validation that the backedge is not already invalid make sure internal backedges are only internal: this preserves the expected invariant for jl_insert_backedges/jl_method_instance_delete that any backedges encountered there are purely internal / new enable GC slightly sooner when loading precompiled modules (part of #20671) reverts 11a984bb301e14d6fbd572cb63eea494cf6ab733 - but who needed that anyways --- src/array.c | 13 ++ src/dump.c | 377 ++++++++++++++++++++----------------------- src/gf.c | 5 +- src/julia.h | 1 + src/julia_internal.h | 2 + test/compile.jl | 18 ++- 6 files changed, 210 insertions(+), 206 deletions(-) diff --git a/src/array.c b/src/array.c index c1050609a7cd8a..3e77a0e9cbc30f 100644 --- a/src/array.c +++ b/src/array.c @@ -1016,6 +1016,19 @@ JL_DLLEXPORT void jl_array_ptr_1d_push(jl_array_t *a, jl_value_t *item) jl_array_ptr_set(a, n - 1, item); } +JL_DLLEXPORT void jl_array_ptr_1d_append(jl_array_t *a, jl_array_t *a2) +{ + assert(jl_typeis(a, jl_array_any_type)); + assert(jl_typeis(a2, jl_array_any_type)); + size_t i; + size_t n = jl_array_nrows(a); + size_t n2 = jl_array_nrows(a2); + jl_array_grow_end(a, n2); + for (i = 0; i < n2; i++) { + jl_array_ptr_set(a, n + i, jl_array_ptr_ref(a2, i)); + } +} + JL_DLLEXPORT void jl_array_ptr_1d_push2(jl_array_t *a, jl_value_t *b, jl_value_t *c) { assert(jl_typeis(a, jl_array_any_type)); diff --git a/src/dump.c b/src/dump.c index e5b26b1ab0db53..b0943dcdd78472 100644 --- a/src/dump.c +++ b/src/dump.c @@ -991,7 +991,24 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li jl_serialize_value(s, li->inferred_const); jl_serialize_value(s, li->rettype); jl_serialize_value(s, (jl_value_t*)li->sparam_vals); - jl_serialize_value(s, (jl_value_t*)li->backedges); + jl_array_t *backedges = li->backedges; + if (s->mode == MODE_MODULE && backedges) { + // filter backedges to only contain pointers + // to items that we will actually store (internal == 2) + size_t ins, i, l = jl_array_len(backedges); + jl_method_instance_t **b_edges = (jl_method_instance_t**)jl_array_data(backedges); + for (ins = i = 0; i < l; i++) { + jl_method_instance_t *backedge = b_edges[i]; + if (module_in_worklist(backedge->def.method->module)) { + b_edges[ins++] = backedge; + } + } + if (ins != l) + jl_array_del_end(backedges, l - ins); + if (ins == 0) + backedges = NULL; + } + jl_serialize_value(s, (jl_value_t*)backedges); if (s->mode != MODE_MODULE) { write_int32(s->s, li->min_world); write_int32(s->s, li->max_world); @@ -1158,7 +1175,7 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li } } -static void jl_serialize_missing_backedges_to_mod(jl_serializer_state *s, jl_methtable_t *mt) +static void jl_collect_missing_backedges_to_mod(jl_methtable_t *mt) { jl_array_t *backedges = mt->backedges; if (backedges) { @@ -1177,7 +1194,8 @@ static void jl_serialize_missing_backedges_to_mod(jl_serializer_state *s, jl_met } // the intent of this function is to invert the backedges tree -static void serialize_backedges(jl_method_instance_t *callee) +// for anything that points to a method not part of the worklist +static void collect_backedges(jl_method_instance_t *callee) { jl_array_t *backedges = callee->backedges; if (backedges) { @@ -1196,34 +1214,34 @@ static void serialize_backedges(jl_method_instance_t *callee) } -static int jl_serialize_backedges_to_mod(jl_typemap_entry_t *ml, void *closure) +static int jl_collect_backedges_to_mod(jl_typemap_entry_t *ml, void *closure) { - (void)(jl_serializer_state*)closure; + (void)(jl_array_t*)closure; jl_method_instance_t *callee = ml->func.linfo; - serialize_backedges(callee); + collect_backedges(callee); return 1; } -static int jl_serialize_methcache_from_mod(jl_typemap_entry_t *ml, void *closure) +static int jl_collect_methcache_from_mod(jl_typemap_entry_t *ml, void *closure) { - jl_serializer_state *s = (jl_serializer_state*)closure; + jl_array_t *s = (jl_array_t*)closure; jl_method_t *m = ml->func.method; if (module_in_worklist(m->module)) { - jl_serialize_value(s, m); - jl_serialize_value(s, ml->simplesig); + jl_array_ptr_1d_push(s, (jl_value_t*)m); + jl_array_ptr_1d_push(s, (jl_value_t*)ml->simplesig); } else { - jl_typemap_visitor(m->specializations, jl_serialize_backedges_to_mod, closure); + jl_typemap_visitor(m->specializations, jl_collect_backedges_to_mod, closure); } return 1; } -static void jl_serialize_methtable_from_mod(jl_serializer_state *s, jl_typename_t *tn) +static void jl_collect_methtable_from_mod(jl_array_t *s, jl_typename_t *tn) { - jl_typemap_visitor(tn->mt->defs, jl_serialize_methcache_from_mod, (void*)s); + jl_typemap_visitor(tn->mt->defs, jl_collect_methcache_from_mod, (void*)s); } -static void jl_serialize_lambdas_from_mod(jl_serializer_state *s, jl_module_t *m) +static void jl_collect_lambdas_from_mod(jl_array_t *s, jl_module_t *m) { if (module_in_worklist(m)) return; @@ -1241,8 +1259,8 @@ static void jl_serialize_lambdas_from_mod(jl_serializer_state *s, jl_module_t *m if (mt != NULL && (jl_value_t*)mt != jl_nothing && (mt != jl_type_type_mt || tn == jl_type_typename)) { - jl_serialize_methtable_from_mod(s, tn); - jl_serialize_missing_backedges_to_mod(s, mt); + jl_collect_methtable_from_mod(s, tn); + jl_collect_missing_backedges_to_mod(mt); } } } @@ -1250,7 +1268,7 @@ static void jl_serialize_lambdas_from_mod(jl_serializer_state *s, jl_module_t *m jl_module_t *child = (jl_module_t*)b->value; if (child != m && child->parent == m && child->name == b->name) { // this is the original/primary binding for the submodule - jl_serialize_lambdas_from_mod(s, (jl_module_t*)b->value); + jl_collect_lambdas_from_mod(s, (jl_module_t*)b->value); } } } @@ -1258,31 +1276,48 @@ static void jl_serialize_lambdas_from_mod(jl_serializer_state *s, jl_module_t *m } } -static void jl_serialize_backedges(jl_serializer_state *s) +// flatten the backedge map reachable from caller into callees +static void jl_collect_backedges_to(jl_method_instance_t *caller, jl_array_t *direct_callees, arraylist_t *to_restore) { - arraylist_t worklist; - arraylist_new(&worklist, 0); + jl_array_t **pcallees = (jl_array_t**)ptrhash_bp(&edges_map, (void*)caller), + *callees = *pcallees; + if (callees != HT_NOTFOUND) { + arraylist_push(to_restore, (void*)pcallees); + arraylist_push(to_restore, (void*)callees); + *pcallees = (jl_array_t*) HT_NOTFOUND; + jl_array_ptr_1d_append(direct_callees, callees); + size_t i, l = jl_array_len(callees); + for (i = 0; i < l; i++) { + jl_value_t *c = jl_array_ptr_ref(callees, i); + if (jl_is_method_instance(c)) { + jl_collect_backedges_to((jl_method_instance_t*)c, direct_callees, to_restore); + } + } + } +} + +static void jl_collect_backedges(jl_array_t *s) +{ + arraylist_t to_restore; + arraylist_new(&to_restore, 0); size_t i; void **table = edges_map.table; for (i = 0; i < edges_map.size; i += 2) { jl_method_instance_t *caller = (jl_method_instance_t*)table[i]; - jl_array_t *callee = (jl_array_t*)table[i + 1]; - if (callee != HT_NOTFOUND && module_in_worklist(caller->def.method->module)) { - arraylist_push(&worklist, (void*)caller); - } - } - while (worklist.len) { - jl_method_instance_t *caller = (jl_method_instance_t*)arraylist_pop(&worklist); - jl_array_t **pcallee = (jl_array_t**)ptrhash_bp(&edges_map, (void*)caller), - *callee = *pcallee; - if (callee != HT_NOTFOUND) { - jl_serialize_value(s, caller); - jl_serialize_value(s, callee); - *pcallee = (jl_array_t*) HT_NOTFOUND; - for (i = 0; i < jl_array_len(callee); i++) { - jl_value_t *c = jl_array_ptr_ref(callee, i); - if (jl_is_method_instance(c)) - arraylist_push(&worklist, (void*)c); + jl_array_t *callees = (jl_array_t*)table[i + 1]; + if (callees != HT_NOTFOUND && module_in_worklist(caller->def.method->module)) { + size_t i, l = jl_array_len(callees); // length may change during iteration + for (i = 0; i < l; i++) { // only consider the initial list + jl_value_t *c = jl_array_ptr_ref(callees, i); + if (jl_is_method_instance(c)) { + jl_collect_backedges_to((jl_method_instance_t*)c, callees, &to_restore); + } + } + jl_array_ptr_1d_push(s, (jl_value_t*)caller); + jl_array_ptr_1d_push(s, (jl_value_t*)callees); + while (to_restore.len) { + void **pp = (void**)arraylist_pop(&to_restore); + *pp = arraylist_pop(&to_restore); } } } @@ -2144,130 +2179,94 @@ static jl_value_t *jl_deserialize_value_(jl_serializer_state *s, jl_value_t *vta } } -JL_EXTENSION typedef struct _linkedlist_t { - struct _linkedlist_t *next; - union { - struct { - jl_method_t *meth; - jl_tupletype_t *simpletype; - }; - struct { - jl_method_instance_t *caller; - jl_array_t *callee; - }; - } def[100]; - size_t count; -} linkedlist_t; - -static void jl_deserialize_methods_from_mod(jl_serializer_state *s, linkedlist_t *list) +static void jl_insert_methods(jl_array_t *list) { - list->count = 0; - list->next = NULL; - while (1) { - if (list->count == sizeof(list->def) / sizeof(list->def[0])) { - list->next = (linkedlist_t*)malloc(sizeof(linkedlist_t)); - list = list->next; - list->count = 0; - list->next = NULL; - } - // using a linked list so that we can take these addresses - // and have them remain constant (arraylist reallocates) - jl_value_t **loc_meth = (jl_value_t**)&list->def[list->count].meth; - jl_value_t **loc_styp = (jl_value_t**)&list->def[list->count].simpletype; - *loc_meth = jl_deserialize_value(s, loc_meth); - if (*loc_meth == NULL) - return; - *loc_styp = jl_deserialize_value(s, loc_styp); - list->count++; + size_t i, l = jl_array_len(list); + for (i = 0; i < l; i += 2) { + jl_method_t *meth = (jl_method_t*)jl_array_ptr_ref(list, i); + jl_tupletype_t *simpletype = (jl_tupletype_t*)jl_array_ptr_ref(list, i + 1); + assert(jl_is_method(meth)); + jl_datatype_t *gf = jl_first_argument_datatype((jl_value_t*)meth->sig); + assert(jl_is_datatype(gf) && gf->name->mt); + jl_method_table_insert(gf->name->mt, meth, simpletype); } } -static void jl_insert_methods(linkedlist_t *list) +static size_t lowerbound_dependent_world_set(size_t world, arraylist_t *dependent_worlds) { - while (list) { - size_t i; - for (i = 0; i < list->count; i++) { - assert(jl_is_method(list->def[i].meth)); - jl_method_t *meth = list->def[i].meth; - jl_datatype_t *gf = jl_first_argument_datatype((jl_value_t*)meth->sig); - assert(jl_is_datatype(gf) && gf->name->mt); - jl_method_table_insert(gf->name->mt, meth, list->def[i].simpletype); - } - list = list->next; + size_t i, l = dependent_worlds->len; + if (world <= (size_t)dependent_worlds->items[l - 1]) + return world; + for (i = 0; i < l; i++) { + size_t depworld = (size_t)dependent_worlds->items[i]; + if (depworld <= world) + return depworld; } + abort(); // unreachable } void jl_method_instance_delete(jl_method_instance_t *mi); -static void jl_insert_backedges(linkedlist_t *list) -{ - while (list) { - size_t i, j; - for (i = 0; i < list->count; i++) { - jl_method_instance_t *caller = list->def[i].caller; - assert(jl_is_method_instance(caller)); - jl_array_t *callees = list->def[i].callee; - assert(jl_is_array(callees)); - if (!caller->inferred || module_in_worklist(caller->def.method->module)) { - for (j = 0; j < jl_array_len(callees); j++) { - jl_value_t *callee = jl_array_ptr_ref(callees, j); - if (jl_is_method_instance(callee)) { - jl_method_instance_t *callee_mi = (jl_method_instance_t*)callee; - if (!module_in_worklist(callee_mi->def.method->module)) { - // verify that this MethodInstance is still the correct lookup for this callee sig - jl_value_t *sig = callee_mi->specTypes; - jl_method_t *m = NULL; - if (jl_is_datatype(sig)) { - jl_datatype_t *ftype = jl_first_argument_datatype(sig); - jl_methtable_t *mt = ftype->name->mt; - jl_typemap_entry_t *entry = jl_typemap_assoc_by_type( - mt->defs, (jl_datatype_t*)sig, - NULL, /*inexact*/0, /*subtype*/1, 0, jl_world_counter); - if (entry != NULL) - m = entry->func.method; - } - if (m != callee_mi->def.method) { - // probably no good, just invalidate everything now - jl_method_instance_delete(caller); - break; - } - } - if (callee_mi->max_world == ~(size_t)0) { - // if this callee is still valid, just add a backedge - jl_method_instance_add_backedge(callee_mi, caller); - } - else if (caller->min_world == jl_world_counter) { - // if this caller was just added, delete everything associated with it - jl_method_instance_delete(caller); - break; - } - else { - // the caller must have been something pre-existing - // assume that it'll take care of deleting the deserialized code - // whenever we process it here - } - } - else { - jl_datatype_t *gf = jl_first_argument_datatype(callee); - assert(jl_is_datatype(gf) && gf->name->mt); - jl_method_table_add_backedge(gf->name->mt, callee, (jl_value_t*)caller); - } +static void jl_insert_backedges(jl_array_t *list, arraylist_t *dependent_worlds) +{ + size_t i, l = jl_array_len(list); + for (i = 0; i < l; i += 2) { + jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(list, i); + assert(jl_is_method_instance(caller)); + assert(caller->min_world == jl_world_counter); // caller should be new + jl_array_t *callees = (jl_array_t*)jl_array_ptr_ref(list, i + 1); + assert(jl_is_array(callees)); + int valid = 1; + size_t j; + for (j = 0; valid && j < jl_array_len(callees); j++) { + jl_value_t *callee = jl_array_ptr_ref(callees, j); + jl_method_instance_t *callee_mi = (jl_method_instance_t*)callee; + jl_value_t *sig; + if (jl_is_method_instance(callee)) { + sig = callee_mi->specTypes; + assert(!module_in_worklist(callee_mi->def.method->module)); + assert(callee_mi->max_world == ~(size_t)0); + } + else { + sig = callee; + } + // verify that this backedge doesn't intersect with any new methods + size_t min_valid = 0; + size_t max_valid = ~(size_t)0; + jl_value_t *matches = jl_matching_methods((jl_tupletype_t*)sig, 50, 1, jl_world_counter, &min_valid, &max_valid); + if (matches == jl_false) + valid = 0; + size_t k; + for (k = 0; valid && k < jl_array_len(matches); k++) { + jl_method_t *m = (jl_method_t*)jl_svecref(jl_array_ptr_ref(matches, k), 2); + if (lowerbound_dependent_world_set(m->min_world, dependent_worlds) != m->min_world) { + // intersection has a new method and is now probably no good, just invalidate everything now + valid = 0; + } + } + } + if (valid) { + // if this callee is still valid, add all the backedges + for (j = 0; j < jl_array_len(callees); j++) { + jl_value_t *callee = jl_array_ptr_ref(callees, j); + if (jl_is_method_instance(callee)) { + jl_method_instance_add_backedge((jl_method_instance_t*)callee, caller); + } + else { + jl_datatype_t *ftype = jl_first_argument_datatype(callee); + jl_methtable_t *mt = ftype->name->mt; + assert(jl_is_datatype(ftype) && mt); + jl_method_table_add_backedge(mt, callee, (jl_value_t*)caller); } } } - list = list->next; + else { + // otherwise delete it + jl_method_instance_delete(caller); + } } } -static void free_linkedlist(linkedlist_t *list) -{ - while (list) { - linkedlist_t *prev = list; - list = list->next; - free(prev); - } -} - static int size_isgreater(const void *a, const void *b) { return *(size_t*)b - *(size_t*)a; @@ -2908,17 +2907,20 @@ JL_DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist) backref_table_numel = 1; jl_idtable_type = jl_base_module ? jl_get_global(jl_base_module, jl_symbol("ObjectIdDict")) : NULL; - int en = jl_gc_enable(0); + int en = jl_gc_enable(0); // edges map is not gc-safe + jl_array_t *lambdas = jl_alloc_vec_any(0); + jl_array_t *edges = jl_alloc_vec_any(0); + jl_collect_lambdas_from_mod(lambdas, jl_main_module); + jl_collect_backedges(edges); + jl_serializer_state s = { &f, MODE_MODULE, NULL, NULL, jl_get_ptls_states() }; jl_serialize_value(&s, worklist); - jl_serialize_lambdas_from_mod(&s, jl_main_module); - jl_serialize_value(&s, NULL); // signal end of lambdas - jl_serialize_backedges(&s); - jl_serialize_value(&s, NULL); // signal end of backedges + jl_serialize_value(&s, lambdas); + jl_serialize_value(&s, edges); jl_finalize_serializer(&s); // done with f serializer_worklist = NULL; @@ -3111,17 +3113,6 @@ static void jl_update_backref_list(jl_value_t *old, jl_value_t *_new, size_t sta } } -static size_t lowerbound_dependent_world_set(size_t world, arraylist_t *dependent_worlds) -{ - size_t i, l = dependent_worlds->len; - for (i = 0; i < l; i++) { - size_t depworld = (size_t)dependent_worlds->items[i]; - if (depworld <= world) - return depworld; - } - return jl_main_module->primary_world; -} - // repeatedly look up older methods until we come to one that existed // at the time this module was serialized static jl_method_t *jl_lookup_method_worldset(jl_methtable_t *mt, jl_datatype_t *sig, arraylist_t *dependent_worlds) @@ -3131,28 +3122,6 @@ static jl_method_t *jl_lookup_method_worldset(jl_methtable_t *mt, jl_datatype_t while (1) { _new = (jl_method_t*)jl_methtable_lookup(mt, sig, world); assert(_new && jl_is_method(_new)); - if (_new->min_world == jl_world_counter) - return _new; - if (_new->min_world <= jl_main_module->primary_world) - return _new; - world = lowerbound_dependent_world_set(_new->min_world, dependent_worlds); - if (world == _new->min_world) - return _new; - } -} - -// repeated look up older methods until we come to one that was valid -// at the time this module was serialized -static jl_method_instance_t *jl_lookup_methodinstance_worldset(jl_method_t *m, jl_datatype_t *argtypes, jl_svec_t *env, arraylist_t *dependent_worlds) -{ - size_t world = jl_world_counter; - jl_method_instance_t *_new; - while (1) { - _new = jl_specializations_get_linfo(m, (jl_value_t*)argtypes, env, world); - if (_new->min_world == jl_world_counter) - return _new; - if (_new->min_world <= jl_main_module->primary_world) - return _new; world = lowerbound_dependent_world_set(_new->min_world, dependent_worlds); if (world == _new->min_world) return _new; @@ -3185,7 +3154,7 @@ static jl_method_instance_t *jl_recache_method_instance(jl_method_instance_t *li //assert(ti != jl_bottom_type); (void)ti; if (ti == jl_bottom_type) env = jl_emptysvec; // the intersection may fail now if the type system had made an incorrect subtype env in the past - jl_method_instance_t *_new = jl_lookup_methodinstance_worldset(m, argtypes, env, dependent_worlds); + jl_method_instance_t *_new = jl_specializations_get_linfo(m, (jl_value_t*)argtypes, env, jl_world_counter); jl_update_backref_list((jl_value_t*)li, (jl_value_t*)_new, start); return _new; } @@ -3225,6 +3194,7 @@ static int trace_method(jl_typemap_entry_t *entry, void *closure) static jl_value_t *_jl_restore_incremental(ios_t *f) { + jl_ptls_t ptls = jl_get_ptls_states(); if (ios_eof(f) || !jl_read_verify_header(f)) { ios_close(f); return jl_get_exceptionf(jl_errorexception_type, @@ -3253,28 +3223,28 @@ static jl_value_t *_jl_restore_incremental(ios_t *f) } // prepare to deserialize + int en = jl_gc_enable(0); + jl_gc_enable_finalizers(ptls, 0); + ++jl_world_counter; // reserve a world age for the deserialization + arraylist_new(&backref_list, 4000); arraylist_push(&backref_list, jl_main_module); arraylist_new(&flagref_list, 0); + arraylist_push(&dependent_worlds, (void*)jl_world_counter); + arraylist_push(&dependent_worlds, (void*)jl_main_module->primary_world); qsort(dependent_worlds.items, dependent_worlds.len, sizeof(size_t), size_isgreater); - int en = jl_gc_enable(0); - ++jl_world_counter; // reserve a world age for the deserialization jl_serializer_state s = { f, MODE_MODULE, NULL, NULL, - jl_get_ptls_states() + ptls }; - jl_array_t *restored = NULL; - jl_array_t *init_order = NULL; - restored = (jl_array_t*)jl_deserialize_value(&s, (jl_value_t**)&restored); + jl_array_t *restored = (jl_array_t*)jl_deserialize_value(&s, (jl_value_t**)&restored); serializer_worklist = restored; // get list of external generic functions - linkedlist_t external_methods; - jl_deserialize_methods_from_mod(&s, &external_methods); - linkedlist_t external_backedges; - jl_deserialize_methods_from_mod(&s, &external_backedges); + jl_value_t *external_methods = jl_deserialize_value(&s, &external_methods); + jl_value_t *external_backedges = jl_deserialize_value(&s, &external_backedges); arraylist_t *tracee_list = NULL; if (jl_newmeth_tracer) @@ -3283,21 +3253,22 @@ static jl_value_t *_jl_restore_incremental(ios_t *f) // at this point, the AST is fully reconstructed, but still completely disconnected // now all of the interconnects will be created jl_recache_types(); // make all of the types identities correct - jl_recache_other(&dependent_worlds); // make all of the other objects identities correct (needs to be after recache types) - init_order = jl_finalize_deserializer(&s, tracee_list); // done with f and s (needs to be after recache types) - jl_insert_methods(&external_methods); // hook up methods of external generic functions (needs to be after recache other) - jl_insert_backedges(&external_backedges); // restore external backedges (needs to be after insert methods) - free_linkedlist(external_methods.next); - free_linkedlist(external_backedges.next); - serializer_worklist = NULL; + jl_insert_methods((jl_array_t*)external_methods); // hook up methods of external generic functions (needs to be after recache types) + jl_recache_other(&dependent_worlds); // make all of the other objects identities correct (needs to be after insert methods) + jl_array_t *init_order = jl_finalize_deserializer(&s, tracee_list); // done with f and s (needs to be after recache) + + JL_GC_PUSH3(&init_order, &restored, &external_backedges); + jl_gc_enable(en); // subtyping can allocate a lot, not valid before recache-other + + jl_insert_backedges((jl_array_t*)external_backedges, &dependent_worlds); // restore external backedges (needs to be last) + serializer_worklist = NULL; arraylist_free(&flagref_list); arraylist_free(&backref_list); arraylist_free(&dependent_worlds); ios_close(f); - JL_GC_PUSH2(&init_order, &restored); - jl_gc_enable(en); + jl_gc_enable_finalizers(ptls, 1); // make sure we don't run any Julia code concurrently before this point if (tracee_list) { jl_methtable_t *mt; while ((mt = (jl_methtable_t*)arraylist_pop(tracee_list)) != NULL) diff --git a/src/gf.c b/src/gf.c index 800901649870b0..1247383b24c476 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1249,6 +1249,8 @@ static int JL_DEBUG_METHOD_INVALIDATION = 0; // invalidate cached methods that had an edge to a replaced method static void invalidate_method_instance(jl_method_instance_t *replaced, size_t max_world, int depth) { + if (!jl_is_method(replaced->def.method)) + return; JL_LOCK_NOGC(&replaced->def.method->writelock); jl_array_t *backedges = replaced->backedges; if (replaced->max_world > max_world) { @@ -1599,7 +1601,8 @@ jl_method_instance_t *jl_method_lookup(jl_methtable_t *mt, jl_value_t **args, si // // lim is the max # of methods to return. if there are more, returns jl_false. // -1 for no limit. -JL_DLLEXPORT jl_value_t *jl_matching_methods(jl_tupletype_t *types, int lim, int include_ambiguous, size_t world, size_t *min_valid, size_t *max_valid) +JL_DLLEXPORT jl_value_t *jl_matching_methods(jl_tupletype_t *types, int lim, int include_ambiguous, + size_t world, size_t *min_valid, size_t *max_valid) { jl_value_t *unw = jl_unwrap_unionall((jl_value_t*)types); if (jl_is_tuple_type(unw) && jl_tparam0(unw) == jl_bottom_type) diff --git a/src/julia.h b/src/julia.h index 5545ac17307abb..7ff84ae234f0f9 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1225,6 +1225,7 @@ JL_DLLEXPORT void jl_array_del_beg(jl_array_t *a, size_t dec); JL_DLLEXPORT void jl_array_sizehint(jl_array_t *a, size_t sz); JL_DLLEXPORT void jl_array_ptr_1d_push(jl_array_t *a, jl_value_t *item); JL_DLLEXPORT void jl_array_ptr_1d_push2(jl_array_t *a, jl_value_t *b, jl_value_t *c); +JL_DLLEXPORT void jl_array_ptr_1d_append(jl_array_t *a, jl_array_t *a2); JL_DLLEXPORT jl_value_t *jl_apply_array_type(jl_value_t *type, size_t dim); // property access JL_DLLEXPORT void *jl_array_ptr(jl_array_t *a); diff --git a/src/julia_internal.h b/src/julia_internal.h index 4689211efd850c..eb9f91420dc646 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -487,6 +487,8 @@ jl_method_instance_t *jl_method_lookup_by_type(jl_methtable_t *mt, jl_tupletype_ jl_method_instance_t *jl_method_lookup(jl_methtable_t *mt, jl_value_t **args, size_t nargs, int cache, size_t world); jl_value_t *jl_gf_invoke(jl_tupletype_t *types, jl_value_t **args, size_t nargs); jl_method_instance_t *jl_lookup_generic(jl_value_t **args, uint32_t nargs, uint32_t callsite, size_t world); +JL_DLLEXPORT jl_value_t *jl_matching_methods(jl_tupletype_t *types, int lim, int include_ambiguous, + size_t world, size_t *min_valid, size_t *max_valid); JL_DLLEXPORT jl_datatype_t *jl_first_argument_datatype(jl_value_t *argtypes); jl_datatype_t *jl_argument_datatype(jl_value_t *argt); diff --git a/test/compile.jl b/test/compile.jl index acbf869a5b52c9..c4d2f5353cafe7 100644 --- a/test/compile.jl +++ b/test/compile.jl @@ -30,6 +30,14 @@ try __precompile__(true) module $FooBase_module + import Base: hash, > + struct fmpz end + struct typeA end + >(x::fmpz, y::Int) = Base.cmp(x, y) > 0 + function hash(a::typeA, h::UInt) + d = den(a) + return h + end end """) write(Foo2_file, @@ -47,8 +55,14 @@ try __precompile__(true) module $Foo_module - using $FooBase_module + using $FooBase_module, $FooBase_module.typeA import $Foo2_module: $Foo2_module, override + import $FooBase_module.hash + + struct typeB + y::typeA + end + hash(x::typeB) = hash(x.y) # test that docs get reconnected @doc "foo function" foo(x) = x + 1 @@ -157,7 +171,7 @@ try cachefile = joinpath(dir, "$Foo_module.ji") # use _require_from_serialized to ensure that the test fails if # the module doesn't reload from the image: - @test_warn "WARNING: replacing module Foo4b3a94a1a081a8cb.\nWARNING: Method definition " begin + @test_warn "WARNING: replacing module $Foo_module." begin @test isa(Base._require_from_serialized(myid(), Foo_module, cachefile, #=broadcast-load=#false), Array{Any,1}) end