From 5cd866bcbcf98ccbf7f0cb627e3efb70aebc9065 Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Wed, 31 Jul 2019 10:15:22 -0400 Subject: [PATCH 01/20] Initial version: trying to add edges to all generated functions --- base/boot.jl | 1 + src/julia_internal.h | 5 +++++ src/method.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/base/boot.jl b/base/boot.jl index a9f33562ee481..ba45daf6f1fc4 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -522,6 +522,7 @@ end # invoke and wrap the results of @generated function (g::GeneratedFunctionStub)(@nospecialize args...) body = g.gen(args...) + #body = Core._apply_pure(g.gen, (args...,)) if body isa CodeInfo return body end diff --git a/src/julia_internal.h b/src/julia_internal.h index c8101dce8a73f..84233311c782a 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -991,6 +991,11 @@ void jl_log(int level, jl_value_t *module, jl_value_t *group, jl_value_t *id, int isabspath(const char *in); +JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup(jl_value_t *types JL_PROPAGATES_ROOT, size_t world); +JL_CALLABLE(jl_f__apply_pure); +JL_CALLABLE(jl_f__apply_latest); + + extern jl_sym_t *call_sym; extern jl_sym_t *invoke_sym; extern jl_sym_t *empty_sym; extern jl_sym_t *top_sym; extern jl_sym_t *module_sym; extern jl_sym_t *slot_sym; diff --git a/src/method.c b/src/method.c index c9f00617f2cd1..5902bfa9bcecc 100644 --- a/src/method.c +++ b/src/method.c @@ -420,6 +420,37 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) jl_resolve_globals_in_ir(stmts, def->module, linfo->sparam_vals, 1); } + // Get generator function body + jl_value_t* gen_func = jl_get_field(generator, "gen"); + //jl_static_show(JL_STDERR, (jl_value_t*)gen_func); + + // Get jl_method_t for generator + jl_value_t *types = NULL; + JL_GC_PUSH1(&types); + types = jl_argtype_with_function(gen_func, tt); + //jl_static_show(JL_STDERR, (jl_value_t*)types); + + jl_typemap_entry_t *entry = (jl_typemap_entry_t*)jl_gf_invoke_lookup(types, -1); + + //jl_static_show(JL_STDERR, (jl_value_t*)entry); + //if ((jl_value_t*)entry == jl_nothing) { + //jl_method_error_bare(gf, types0, world); + //// unreachable + //} + + // now we have found the matching definition. + // next look for or create a specialization of this definition. + JL_GC_POP(); + jl_method_t *method = entry->func.method; + //jl_static_show(JL_STDERR, (jl_value_t*)method); + + jl_method_instance_t *edge = jl_specializations_get_linfo(method, tt, linfo->sparam_vals); + //jl_printf(JL_STDERR, "\nNATHAN: edge: %p\n", edge); + //jl_static_show(JL_STDERR, (jl_value_t*)edge); + + + jl_method_instance_add_backedge(edge, linfo); + ptls->in_pure_callback = last_in; jl_lineno = last_lineno; ptls->world_age = last_age; From f98ed40478cfeb311784770f493183323894d31f Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Wed, 31 Jul 2019 13:03:46 -0400 Subject: [PATCH 02/20] Changed to have a weird manually constructed Tuple type, which seems to fix it for StagedFunctions, but not here yet... --- src/method.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/method.c b/src/method.c index 5902bfa9bcecc..2a6f513fd30a0 100644 --- a/src/method.c +++ b/src/method.c @@ -424,13 +424,36 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) jl_value_t* gen_func = jl_get_field(generator, "gen"); //jl_static_show(JL_STDERR, (jl_value_t*)gen_func); - // Get jl_method_t for generator - jl_value_t *types = NULL; - JL_GC_PUSH1(&types); - types = jl_argtype_with_function(gen_func, tt); - //jl_static_show(JL_STDERR, (jl_value_t*)types); + //// Main user-named staged function + //jl_value_t* staged_function = def->sig; + //jl_printf(JL_STDERR, "\nstaged_function: "); + //jl_static_show(JL_STDERR, (jl_value_t*)staged_function); + //jl_printf(JL_STDERR, "\n"); + + // Get jl_method_t for generator body + // The generator body takes two arguments: (typeof(func), T) + // So types should be e.g.: Tuple{getfield(Main, Symbol("##s4#3")), typeof(Main.foo), Float64} + + // BUT --- THIS IS THE WEIRD PART: + // Apparently the backedge needs to be from `##s4#3(typeof(func), Type)` instead of + // the actual types of the aruments! Who knows why!! Weirdness. + // Manually construct that weird signature, here: + jl_printf(JL_STDERR, "\nttdt: "); + jl_static_show(JL_STDERR, (jl_value_t*)ttdt); + jl_printf(JL_STDERR, "\n"); + ssize_t numargs = jl_svec_len(ttdt->parameters); // TODO: is there a better way to get the length of a Tuple? + jl_value_t* weird_types_tuple = jl_tupletype_fill(numargs, (jl_value_t*)jl_type_type); + jl_printf(JL_STDERR, "\nWeird Tuple types: "); + jl_static_show(JL_STDERR, (jl_value_t*)weird_types_tuple); + jl_printf(JL_STDERR, "\n"); + // One would expect to be able to just use `tt` here, but we have to use the weird + // thing instead. + //jl_value_t* types = jl_argtype_with_function(gen_func, tt); + jl_value_t* types = jl_argtype_with_function(gen_func, weird_types_tuple); + jl_static_show(JL_STDERR, (jl_value_t*)types); jl_typemap_entry_t *entry = (jl_typemap_entry_t*)jl_gf_invoke_lookup(types, -1); + JL_GC_POP(); //jl_static_show(JL_STDERR, (jl_value_t*)entry); //if ((jl_value_t*)entry == jl_nothing) { @@ -440,11 +463,10 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) // now we have found the matching definition. // next look for or create a specialization of this definition. - JL_GC_POP(); jl_method_t *method = entry->func.method; - //jl_static_show(JL_STDERR, (jl_value_t*)method); + jl_static_show(JL_STDERR, (jl_value_t*)method); - jl_method_instance_t *edge = jl_specializations_get_linfo(method, tt, linfo->sparam_vals); + jl_method_instance_t *edge = jl_specializations_get_linfo(method, types, linfo->sparam_vals); //jl_printf(JL_STDERR, "\nNATHAN: edge: %p\n", edge); //jl_static_show(JL_STDERR, (jl_value_t*)edge); From bb7966f2682213446499ac1a4e0452be9c87369e Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Wed, 31 Jul 2019 13:05:52 -0400 Subject: [PATCH 03/20] AHA!! Apparently b/c the generator is never specialized, all the types need to be Any to get the right method! Everything works now!!!! :'D --- src/method.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/method.c b/src/method.c index 2a6f513fd30a0..67409ddc38ebd 100644 --- a/src/method.c +++ b/src/method.c @@ -442,7 +442,7 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) jl_static_show(JL_STDERR, (jl_value_t*)ttdt); jl_printf(JL_STDERR, "\n"); ssize_t numargs = jl_svec_len(ttdt->parameters); // TODO: is there a better way to get the length of a Tuple? - jl_value_t* weird_types_tuple = jl_tupletype_fill(numargs, (jl_value_t*)jl_type_type); + jl_value_t* weird_types_tuple = jl_tupletype_fill(numargs, (jl_value_t*)jl_any_type); jl_printf(JL_STDERR, "\nWeird Tuple types: "); jl_static_show(JL_STDERR, (jl_value_t*)weird_types_tuple); jl_printf(JL_STDERR, "\n"); From 84eb92ef9c4830bad7956997bf98af82c9e7f8dd Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Wed, 31 Jul 2019 13:07:57 -0400 Subject: [PATCH 04/20] Remove printlns --- src/method.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/method.c b/src/method.c index 67409ddc38ebd..89dfc46089b47 100644 --- a/src/method.c +++ b/src/method.c @@ -438,19 +438,19 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) // Apparently the backedge needs to be from `##s4#3(typeof(func), Type)` instead of // the actual types of the aruments! Who knows why!! Weirdness. // Manually construct that weird signature, here: - jl_printf(JL_STDERR, "\nttdt: "); - jl_static_show(JL_STDERR, (jl_value_t*)ttdt); - jl_printf(JL_STDERR, "\n"); + //jl_printf(JL_STDERR, "\nttdt: "); + //jl_static_show(JL_STDERR, (jl_value_t*)ttdt); + //jl_printf(JL_STDERR, "\n"); ssize_t numargs = jl_svec_len(ttdt->parameters); // TODO: is there a better way to get the length of a Tuple? jl_value_t* weird_types_tuple = jl_tupletype_fill(numargs, (jl_value_t*)jl_any_type); - jl_printf(JL_STDERR, "\nWeird Tuple types: "); - jl_static_show(JL_STDERR, (jl_value_t*)weird_types_tuple); - jl_printf(JL_STDERR, "\n"); + //jl_printf(JL_STDERR, "\nWeird Tuple types: "); + //jl_static_show(JL_STDERR, (jl_value_t*)weird_types_tuple); + //jl_printf(JL_STDERR, "\n"); // One would expect to be able to just use `tt` here, but we have to use the weird // thing instead. //jl_value_t* types = jl_argtype_with_function(gen_func, tt); jl_value_t* types = jl_argtype_with_function(gen_func, weird_types_tuple); - jl_static_show(JL_STDERR, (jl_value_t*)types); + //jl_static_show(JL_STDERR, (jl_value_t*)types); jl_typemap_entry_t *entry = (jl_typemap_entry_t*)jl_gf_invoke_lookup(types, -1); JL_GC_POP(); @@ -464,7 +464,7 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) // now we have found the matching definition. // next look for or create a specialization of this definition. jl_method_t *method = entry->func.method; - jl_static_show(JL_STDERR, (jl_value_t*)method); + //jl_static_show(JL_STDERR, (jl_value_t*)method); jl_method_instance_t *edge = jl_specializations_get_linfo(method, types, linfo->sparam_vals); //jl_printf(JL_STDERR, "\nNATHAN: edge: %p\n", edge); From f6702958d3d321bdeb44c45ba5816a7e97fa81cd Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Wed, 31 Jul 2019 14:09:11 -0400 Subject: [PATCH 05/20] Change implementation to add forward edges to CodeInfo, rather than directly add backedges --- base/boot.jl | 4 ++-- src/method.c | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index ba45daf6f1fc4..99cda41c24800 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -521,8 +521,8 @@ end # invoke and wrap the results of @generated function (g::GeneratedFunctionStub)(@nospecialize args...) - body = g.gen(args...) - #body = Core._apply_pure(g.gen, (args...,)) + #body = g.gen(args...) + body = Core._apply_pure(g.gen, (args...,)) if body isa CodeInfo return body end diff --git a/src/method.c b/src/method.c index 89dfc46089b47..941bf2a5060eb 100644 --- a/src/method.c +++ b/src/method.c @@ -466,12 +466,21 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) jl_method_t *method = entry->func.method; //jl_static_show(JL_STDERR, (jl_value_t*)method); - jl_method_instance_t *edge = jl_specializations_get_linfo(method, types, linfo->sparam_vals); - //jl_printf(JL_STDERR, "\nNATHAN: edge: %p\n", edge); - //jl_static_show(JL_STDERR, (jl_value_t*)edge); - + //jl_printf(JL_STDERR, "\nedges: "); jl_static_show(JL_STDERR, (jl_value_t*)func->edges); jl_printf(JL_STDERR, "\n"); + if (func->edges == jl_nothing) { + // TODO: How to construct this array type properly + jl_value_t* array_mi_type = jl_apply_type2((jl_value_t*)jl_array_type, + (jl_value_t*)jl_method_instance_type, jl_box_long(1)); + + //jl_static_show(JL_STDERR, array_mi_type); + func->edges = (jl_value_t*)jl_alloc_array_1d(array_mi_type, 0); + } + //jl_static_show(JL_STDERR, (jl_value_t*)func->edges); - jl_method_instance_add_backedge(edge, linfo); + jl_method_instance_t *edge = jl_specializations_get_linfo(method, types, linfo->sparam_vals); + //jl_method_instance_add_backedge(edge, linfo); + jl_array_ptr_1d_push((jl_array_t*)func->edges, (jl_value_t*)edge); + //jl_static_show(JL_STDERR, (jl_value_t*)func->edges); ptls->in_pure_callback = last_in; jl_lineno = last_lineno; From 5f57247f4047a8033f643a1d3ccb54256bfa77a6 Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Thu, 1 Aug 2019 11:01:43 -0400 Subject: [PATCH 06/20] reenabled print statements and reorderded for clarity --- src/julia_internal.h | 4 +--- src/method.c | 40 +++++++++++++++++++++++----------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/julia_internal.h b/src/julia_internal.h index 84233311c782a..0533b9af7200d 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -991,10 +991,8 @@ void jl_log(int level, jl_value_t *module, jl_value_t *group, jl_value_t *id, int isabspath(const char *in); +// TODO(NHDALY): Find the right place for this. JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup(jl_value_t *types JL_PROPAGATES_ROOT, size_t world); -JL_CALLABLE(jl_f__apply_pure); -JL_CALLABLE(jl_f__apply_latest); - extern jl_sym_t *call_sym; extern jl_sym_t *invoke_sym; extern jl_sym_t *empty_sym; extern jl_sym_t *top_sym; diff --git a/src/method.c b/src/method.c index 941bf2a5060eb..daa86087cf536 100644 --- a/src/method.c +++ b/src/method.c @@ -419,10 +419,11 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) jl_array_t *stmts = (jl_array_t*)func->code; jl_resolve_globals_in_ir(stmts, def->module, linfo->sparam_vals, 1); } + jl_printf(JL_STDERR, "\nHELLO\n"); // Get generator function body jl_value_t* gen_func = jl_get_field(generator, "gen"); - //jl_static_show(JL_STDERR, (jl_value_t*)gen_func); + jl_static_show(JL_STDERR, (jl_value_t*)gen_func); //// Main user-named staged function //jl_value_t* staged_function = def->sig; @@ -438,35 +439,41 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) // Apparently the backedge needs to be from `##s4#3(typeof(func), Type)` instead of // the actual types of the aruments! Who knows why!! Weirdness. // Manually construct that weird signature, here: - //jl_printf(JL_STDERR, "\nttdt: "); - //jl_static_show(JL_STDERR, (jl_value_t*)ttdt); - //jl_printf(JL_STDERR, "\n"); + jl_printf(JL_STDERR, "\nttdt: "); + jl_static_show(JL_STDERR, (jl_value_t*)ttdt); + jl_printf(JL_STDERR, "\n"); ssize_t numargs = jl_svec_len(ttdt->parameters); // TODO: is there a better way to get the length of a Tuple? jl_value_t* weird_types_tuple = jl_tupletype_fill(numargs, (jl_value_t*)jl_any_type); - //jl_printf(JL_STDERR, "\nWeird Tuple types: "); - //jl_static_show(JL_STDERR, (jl_value_t*)weird_types_tuple); - //jl_printf(JL_STDERR, "\n"); + jl_printf(JL_STDERR, "\nWeird Tuple types: "); + jl_static_show(JL_STDERR, (jl_value_t*)weird_types_tuple); + jl_printf(JL_STDERR, "\n"); // One would expect to be able to just use `tt` here, but we have to use the weird // thing instead. //jl_value_t* types = jl_argtype_with_function(gen_func, tt); jl_value_t* types = jl_argtype_with_function(gen_func, weird_types_tuple); - //jl_static_show(JL_STDERR, (jl_value_t*)types); + jl_static_show(JL_STDERR, (jl_value_t*)types); + // TODO: The bootstrap segfault comes from jl_gf_invoke_lookup. We can't call + // this at this point! Try something else. jl_typemap_entry_t *entry = (jl_typemap_entry_t*)jl_gf_invoke_lookup(types, -1); - JL_GC_POP(); + //return ccall(:jl_matching_methods, Any, (Any, Cint, Cint, UInt, Ptr{UInt}, Ptr{UInt}), t, lim, 0, world, min, max) + //size_t min_valid = 0; + //size_t max_valid = ~(size_t)0; + //jl_value_t *matches = jl_matching_methods((jl_tupletype_t*)sig, -1, 1, 0, &min_valid, &max_valid); + //if (matches == jl_false) + // valid = 0; - //jl_static_show(JL_STDERR, (jl_value_t*)entry); - //if ((jl_value_t*)entry == jl_nothing) { - //jl_method_error_bare(gf, types0, world); - //// unreachable - //} + JL_GC_POP(); // now we have found the matching definition. // next look for or create a specialization of this definition. jl_method_t *method = entry->func.method; - //jl_static_show(JL_STDERR, (jl_value_t*)method); + jl_static_show(JL_STDERR, (jl_value_t*)method); + jl_method_instance_t *edge = jl_specializations_get_linfo(method, types, linfo->sparam_vals); + - //jl_printf(JL_STDERR, "\nedges: "); jl_static_show(JL_STDERR, (jl_value_t*)func->edges); jl_printf(JL_STDERR, "\n"); + // Now create the edges array and set the edge! + jl_printf(JL_STDERR, "\nedges: "); jl_static_show(JL_STDERR, (jl_value_t*)func->edges); jl_printf(JL_STDERR, "\n"); if (func->edges == jl_nothing) { // TODO: How to construct this array type properly jl_value_t* array_mi_type = jl_apply_type2((jl_value_t*)jl_array_type, @@ -477,7 +484,6 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) } //jl_static_show(JL_STDERR, (jl_value_t*)func->edges); - jl_method_instance_t *edge = jl_specializations_get_linfo(method, types, linfo->sparam_vals); //jl_method_instance_add_backedge(edge, linfo); jl_array_ptr_1d_push((jl_array_t*)func->edges, (jl_value_t*)edge); //jl_static_show(JL_STDERR, (jl_value_t*)func->edges); From 1e2b78e078d7be1547ed386d20d28eece1fb7fb8 Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Thu, 1 Aug 2019 11:08:13 -0400 Subject: [PATCH 07/20] Cool: fix segfault in boostrap -- use different function to specialize method Now it fails in a different way, still needs to be investigated. --- src/julia_internal.h | 3 --- src/method.c | 40 +++++++++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/julia_internal.h b/src/julia_internal.h index 0533b9af7200d..c8101dce8a73f 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -991,9 +991,6 @@ void jl_log(int level, jl_value_t *module, jl_value_t *group, jl_value_t *id, int isabspath(const char *in); -// TODO(NHDALY): Find the right place for this. -JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup(jl_value_t *types JL_PROPAGATES_ROOT, size_t world); - extern jl_sym_t *call_sym; extern jl_sym_t *invoke_sym; extern jl_sym_t *empty_sym; extern jl_sym_t *top_sym; extern jl_sym_t *module_sym; extern jl_sym_t *slot_sym; diff --git a/src/method.c b/src/method.c index daa86087cf536..b84384b9811fd 100644 --- a/src/method.c +++ b/src/method.c @@ -453,23 +453,33 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) jl_value_t* types = jl_argtype_with_function(gen_func, weird_types_tuple); jl_static_show(JL_STDERR, (jl_value_t*)types); - // TODO: The bootstrap segfault comes from jl_gf_invoke_lookup. We can't call - // this at this point! Try something else. - jl_typemap_entry_t *entry = (jl_typemap_entry_t*)jl_gf_invoke_lookup(types, -1); - //return ccall(:jl_matching_methods, Any, (Any, Cint, Cint, UInt, Ptr{UInt}, Ptr{UInt}), t, lim, 0, world, min, max) - //size_t min_valid = 0; - //size_t max_valid = ~(size_t)0; - //jl_value_t *matches = jl_matching_methods((jl_tupletype_t*)sig, -1, 1, 0, &min_valid, &max_valid); - //if (matches == jl_false) - // valid = 0; +// // TODO: The bootstrap segfault comes from jl_gf_invoke_lookup. We can't call +// // this at this point! Try something else. +// jl_typemap_entry_t *entry = (jl_typemap_entry_t*)jl_gf_invoke_lookup(types, -1); +// //return ccall(:jl_matching_methods, Any, (Any, Cint, Cint, UInt, Ptr{UInt}, Ptr{UInt}), t, lim, 0, world, min, max) +// //size_t min_valid = 0; +// //size_t max_valid = ~(size_t)0; +// //jl_value_t *matches = jl_matching_methods((jl_tupletype_t*)sig, -1, 1, 0, &min_valid, &max_valid); +// //if (matches == jl_false) +// // valid = 0; +// +// +// // now we have found the matching definition. +// // next look for or create a specialization of this definition. +// jl_method_t *method = entry->func.method; +// jl_static_show(JL_STDERR, (jl_value_t*)method); +// jl_method_instance_t *edge = jl_specializations_get_linfo(method, types, linfo->sparam_vals); - JL_GC_POP(); - - // now we have found the matching definition. // next look for or create a specialization of this definition. - jl_method_t *method = entry->func.method; - jl_static_show(JL_STDERR, (jl_value_t*)method); - jl_method_instance_t *edge = jl_specializations_get_linfo(method, types, linfo->sparam_vals); + size_t min_valid = 0; + size_t max_valid = ~(size_t)0; + jl_method_instance_t *edge = jl_get_specialization1((jl_tupletype_t*)types, -1, + &min_valid, &max_valid, + 1 /* store new specialization */); + + jl_printf(JL_STDERR, "\nedge: "); jl_static_show(JL_STDERR, (jl_value_t*)edge); jl_printf(JL_STDERR, "\n"); + + JL_GC_POP(); // Now create the edges array and set the edge! From e2a086d0157ebf0d7a7152e65e27602704d1f7ea Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Thu, 1 Aug 2019 14:15:23 -0400 Subject: [PATCH 08/20] OOPS remove spurious JL_GC_POP --- src/method.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/method.c b/src/method.c index b84384b9811fd..37b91ebb66cdf 100644 --- a/src/method.c +++ b/src/method.c @@ -479,8 +479,6 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) jl_printf(JL_STDERR, "\nedge: "); jl_static_show(JL_STDERR, (jl_value_t*)edge); jl_printf(JL_STDERR, "\n"); - JL_GC_POP(); - // Now create the edges array and set the edge! jl_printf(JL_STDERR, "\nedges: "); jl_static_show(JL_STDERR, (jl_value_t*)func->edges); jl_printf(JL_STDERR, "\n"); From 037eb797eb0da645b32fe1fc0d634c2454b2456f Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Thu, 1 Aug 2019 15:13:18 -0400 Subject: [PATCH 09/20] Switch to using jl_specializations_get_linfo b/c (I thought) this will create specializations even if they don't exist. But it's not doing that either... --- src/julia.h | 1 + src/method.c | 97 +++++++++++++++++++++++++++------------------------- 2 files changed, 52 insertions(+), 46 deletions(-) diff --git a/src/julia.h b/src/julia.h index 3c10c398ab1d2..cfc252f2c4ac9 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1202,6 +1202,7 @@ JL_DLLEXPORT jl_svec_t *jl_alloc_svec(size_t n); JL_DLLEXPORT jl_svec_t *jl_alloc_svec_uninit(size_t n); JL_DLLEXPORT jl_svec_t *jl_svec_copy(jl_svec_t *a); JL_DLLEXPORT jl_svec_t *jl_svec_fill(size_t n, jl_value_t *x); +// Construct the DataType for `Tuple{v, v, v...}` JL_DLLEXPORT jl_value_t *jl_tupletype_fill(size_t n, jl_value_t *v); JL_DLLEXPORT jl_sym_t *jl_symbol(const char *str) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_sym_t *jl_symbol_lookup(const char *str) JL_NOTSAFEPOINT; diff --git a/src/method.c b/src/method.c index 37b91ebb66cdf..b54cc655d559d 100644 --- a/src/method.c +++ b/src/method.c @@ -420,10 +420,11 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) jl_resolve_globals_in_ir(stmts, def->module, linfo->sparam_vals, 1); } jl_printf(JL_STDERR, "\nHELLO\n"); + jl_printf(JL_STDERR, "def: "); jl_static_show(JL_STDERR, (jl_value_t*)def); jl_printf(JL_STDERR, "\n"); // Get generator function body jl_value_t* gen_func = jl_get_field(generator, "gen"); - jl_static_show(JL_STDERR, (jl_value_t*)gen_func); + jl_printf(JL_STDERR, "gen_func: "); jl_static_show(JL_STDERR, (jl_value_t*)gen_func); jl_printf(JL_STDERR, "\n"); //// Main user-named staged function //jl_value_t* staged_function = def->sig; @@ -439,62 +440,66 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) // Apparently the backedge needs to be from `##s4#3(typeof(func), Type)` instead of // the actual types of the aruments! Who knows why!! Weirdness. // Manually construct that weird signature, here: - jl_printf(JL_STDERR, "\nttdt: "); - jl_static_show(JL_STDERR, (jl_value_t*)ttdt); - jl_printf(JL_STDERR, "\n"); + jl_printf(JL_STDERR, "\nttdt: "); jl_static_show(JL_STDERR, (jl_value_t*)ttdt); jl_printf(JL_STDERR, "\n"); ssize_t numargs = jl_svec_len(ttdt->parameters); // TODO: is there a better way to get the length of a Tuple? jl_value_t* weird_types_tuple = jl_tupletype_fill(numargs, (jl_value_t*)jl_any_type); - jl_printf(JL_STDERR, "\nWeird Tuple types: "); - jl_static_show(JL_STDERR, (jl_value_t*)weird_types_tuple); - jl_printf(JL_STDERR, "\n"); + jl_printf(JL_STDERR, "\nWeird Tuple types: "); jl_static_show(JL_STDERR, (jl_value_t*)weird_types_tuple); jl_printf(JL_STDERR, "\n"); // One would expect to be able to just use `tt` here, but we have to use the weird // thing instead. //jl_value_t* types = jl_argtype_with_function(gen_func, tt); - jl_value_t* types = jl_argtype_with_function(gen_func, weird_types_tuple); - jl_static_show(JL_STDERR, (jl_value_t*)types); - -// // TODO: The bootstrap segfault comes from jl_gf_invoke_lookup. We can't call -// // this at this point! Try something else. -// jl_typemap_entry_t *entry = (jl_typemap_entry_t*)jl_gf_invoke_lookup(types, -1); -// //return ccall(:jl_matching_methods, Any, (Any, Cint, Cint, UInt, Ptr{UInt}, Ptr{UInt}), t, lim, 0, world, min, max) -// //size_t min_valid = 0; -// //size_t max_valid = ~(size_t)0; -// //jl_value_t *matches = jl_matching_methods((jl_tupletype_t*)sig, -1, 1, 0, &min_valid, &max_valid); -// //if (matches == jl_false) -// // valid = 0; -// -// -// // now we have found the matching definition. -// // next look for or create a specialization of this definition. -// jl_method_t *method = entry->func.method; -// jl_static_show(JL_STDERR, (jl_value_t*)method); -// jl_method_instance_t *edge = jl_specializations_get_linfo(method, types, linfo->sparam_vals); + jl_tupletype_t* types = (jl_tupletype_t*)jl_argtype_with_function(gen_func, weird_types_tuple); + jl_printf(JL_STDERR, "\ntypes: "); jl_static_show(JL_STDERR, (jl_value_t*)types); jl_printf(JL_STDERR, "\n"); - // next look for or create a specialization of this definition. - size_t min_valid = 0; - size_t max_valid = ~(size_t)0; - jl_method_instance_t *edge = jl_get_specialization1((jl_tupletype_t*)types, -1, - &min_valid, &max_valid, - 1 /* store new specialization */); + // TODO: The bootstrap segfault comes from jl_gf_invoke_lookup. We can't call + // this at this point! Try something else. - jl_printf(JL_STDERR, "\nedge: "); jl_static_show(JL_STDERR, (jl_value_t*)edge); jl_printf(JL_STDERR, "\n"); +// // next look for or create a specialization of this definition. +// size_t min_valid = 0; +// size_t max_valid = ~(size_t)0; +// jl_method_instance_t *edge = jl_get_specialization1((jl_tupletype_t*)types, -1, +// &min_valid, &max_valid, +// 1 /* store new specialization */); - // Now create the edges array and set the edge! - jl_printf(JL_STDERR, "\nedges: "); jl_static_show(JL_STDERR, (jl_value_t*)func->edges); jl_printf(JL_STDERR, "\n"); - if (func->edges == jl_nothing) { - // TODO: How to construct this array type properly - jl_value_t* array_mi_type = jl_apply_type2((jl_value_t*)jl_array_type, - (jl_value_t*)jl_method_instance_type, jl_box_long(1)); + size_t min_valid = 0; + size_t max_valid = ~(size_t)0; + jl_value_t *matches = jl_matching_methods(types, /*limit*/ 1, /*ambiguous*/ 1, + /*world age*/ -1, &min_valid, &max_valid); + jl_printf(JL_STDERR, "matches: "); jl_static_show(JL_STDERR, (jl_value_t*)matches); jl_printf(JL_STDERR, "\n"); + + if (matches != jl_false) { + jl_value_t *method_match = jl_arrayref((jl_array_t*)matches, 0); + jl_printf(JL_STDERR, "method_match: %p:", method_match); jl_static_show(JL_STDERR, (jl_value_t*)method_match); jl_printf(JL_STDERR, "\n"); + jl_printf(JL_STDERR, "jl_typeof(method_match):"); jl_static_show(JL_STDERR, (jl_value_t*)jl_typeof(method_match)); jl_printf(JL_STDERR, "\n"); + jl_printf(JL_STDERR, "svec_len(method_match): %d\n", jl_svec_len(method_match)); + //jl_value_t *tt = jl_svecref(method_match, 0); // unused, already have `types`. + jl_svec_t *spvals = (jl_svec_t*)jl_svecref(method_match, 1); + jl_printf(JL_STDERR, "spvals: "); jl_static_show(JL_STDERR, (jl_value_t*)spvals); jl_printf(JL_STDERR, "\n"); + jl_method_t *method = (jl_method_t*)jl_svecref(method_match, 2); + jl_printf(JL_STDERR, "method: "); jl_static_show(JL_STDERR, (jl_value_t*)method); jl_printf(JL_STDERR, "\n"); + + // now we have found the matching definition. + // next look for or create a specialization of this definition. + jl_method_instance_t *edge = jl_specializations_get_linfo(method, (jl_value_t*)types, spvals); + jl_printf(JL_STDERR, "edge: "); jl_static_show(JL_STDERR, (jl_value_t*)edge); jl_printf(JL_STDERR, "\n"); + + if (edge != NULL && (jl_value_t*)edge != jl_nothing) { + // Now create the edges array and set the edge! + jl_printf(JL_STDERR, "\nedges: "); jl_static_show(JL_STDERR, (jl_value_t*)func->edges); jl_printf(JL_STDERR, "\n"); + if (func->edges == jl_nothing) { + // TODO: How to construct this array type properly + jl_value_t* array_mi_type = jl_apply_type2((jl_value_t*)jl_array_type, + (jl_value_t*)jl_method_instance_type, jl_box_long(1)); + + //jl_static_show(JL_STDERR, array_mi_type); + func->edges = (jl_value_t*)jl_alloc_array_1d(array_mi_type, 0); + } - //jl_static_show(JL_STDERR, array_mi_type); - func->edges = (jl_value_t*)jl_alloc_array_1d(array_mi_type, 0); + //jl_method_instance_add_backedge(edge, linfo); + jl_array_ptr_1d_push((jl_array_t*)func->edges, (jl_value_t*)edge); + jl_printf(JL_STDERR, "\nedges: "); jl_static_show(JL_STDERR, (jl_value_t*)func->edges); jl_printf(JL_STDERR, "\n"); + } } - //jl_static_show(JL_STDERR, (jl_value_t*)func->edges); - - //jl_method_instance_add_backedge(edge, linfo); - jl_array_ptr_1d_push((jl_array_t*)func->edges, (jl_value_t*)edge); - //jl_static_show(JL_STDERR, (jl_value_t*)func->edges); ptls->in_pure_callback = last_in; jl_lineno = last_lineno; From 0f32fea32941509304fe44a1c8e2bae6d0b4d18d Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Thu, 1 Aug 2019 15:21:18 -0400 Subject: [PATCH 10/20] Remove printlns from my tests --- src/method.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/method.c b/src/method.c index b54cc655d559d..f3e4160730acf 100644 --- a/src/method.c +++ b/src/method.c @@ -419,12 +419,12 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) jl_array_t *stmts = (jl_array_t*)func->code; jl_resolve_globals_in_ir(stmts, def->module, linfo->sparam_vals, 1); } - jl_printf(JL_STDERR, "\nHELLO\n"); - jl_printf(JL_STDERR, "def: "); jl_static_show(JL_STDERR, (jl_value_t*)def); jl_printf(JL_STDERR, "\n"); + //jl_printf(JL_STDERR, "\nHELLO\n"); + //jl_printf(JL_STDERR, "def: "); jl_static_show(JL_STDERR, (jl_value_t*)def); jl_printf(JL_STDERR, "\n"); // Get generator function body jl_value_t* gen_func = jl_get_field(generator, "gen"); - jl_printf(JL_STDERR, "gen_func: "); jl_static_show(JL_STDERR, (jl_value_t*)gen_func); jl_printf(JL_STDERR, "\n"); + //jl_printf(JL_STDERR, "gen_func: "); jl_static_show(JL_STDERR, (jl_value_t*)gen_func); jl_printf(JL_STDERR, "\n"); //// Main user-named staged function //jl_value_t* staged_function = def->sig; @@ -440,15 +440,15 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) // Apparently the backedge needs to be from `##s4#3(typeof(func), Type)` instead of // the actual types of the aruments! Who knows why!! Weirdness. // Manually construct that weird signature, here: - jl_printf(JL_STDERR, "\nttdt: "); jl_static_show(JL_STDERR, (jl_value_t*)ttdt); jl_printf(JL_STDERR, "\n"); + //jl_printf(JL_STDERR, "\nttdt: "); jl_static_show(JL_STDERR, (jl_value_t*)ttdt); jl_printf(JL_STDERR, "\n"); ssize_t numargs = jl_svec_len(ttdt->parameters); // TODO: is there a better way to get the length of a Tuple? jl_value_t* weird_types_tuple = jl_tupletype_fill(numargs, (jl_value_t*)jl_any_type); - jl_printf(JL_STDERR, "\nWeird Tuple types: "); jl_static_show(JL_STDERR, (jl_value_t*)weird_types_tuple); jl_printf(JL_STDERR, "\n"); + //jl_printf(JL_STDERR, "\nWeird Tuple types: "); jl_static_show(JL_STDERR, (jl_value_t*)weird_types_tuple); jl_printf(JL_STDERR, "\n"); // One would expect to be able to just use `tt` here, but we have to use the weird // thing instead. //jl_value_t* types = jl_argtype_with_function(gen_func, tt); jl_tupletype_t* types = (jl_tupletype_t*)jl_argtype_with_function(gen_func, weird_types_tuple); - jl_printf(JL_STDERR, "\ntypes: "); jl_static_show(JL_STDERR, (jl_value_t*)types); jl_printf(JL_STDERR, "\n"); + //jl_printf(JL_STDERR, "\ntypes: "); jl_static_show(JL_STDERR, (jl_value_t*)types); jl_printf(JL_STDERR, "\n"); // TODO: The bootstrap segfault comes from jl_gf_invoke_lookup. We can't call // this at this point! Try something else. @@ -465,27 +465,27 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) size_t max_valid = ~(size_t)0; jl_value_t *matches = jl_matching_methods(types, /*limit*/ 1, /*ambiguous*/ 1, /*world age*/ -1, &min_valid, &max_valid); - jl_printf(JL_STDERR, "matches: "); jl_static_show(JL_STDERR, (jl_value_t*)matches); jl_printf(JL_STDERR, "\n"); + //jl_printf(JL_STDERR, "matches: "); jl_static_show(JL_STDERR, (jl_value_t*)matches); jl_printf(JL_STDERR, "\n"); if (matches != jl_false) { jl_value_t *method_match = jl_arrayref((jl_array_t*)matches, 0); - jl_printf(JL_STDERR, "method_match: %p:", method_match); jl_static_show(JL_STDERR, (jl_value_t*)method_match); jl_printf(JL_STDERR, "\n"); - jl_printf(JL_STDERR, "jl_typeof(method_match):"); jl_static_show(JL_STDERR, (jl_value_t*)jl_typeof(method_match)); jl_printf(JL_STDERR, "\n"); - jl_printf(JL_STDERR, "svec_len(method_match): %d\n", jl_svec_len(method_match)); + //jl_printf(JL_STDERR, "method_match: %p:", method_match); jl_static_show(JL_STDERR, (jl_value_t*)method_match); jl_printf(JL_STDERR, "\n"); + //jl_printf(JL_STDERR, "jl_typeof(method_match):"); jl_static_show(JL_STDERR, (jl_value_t*)jl_typeof(method_match)); jl_printf(JL_STDERR, "\n"); + //jl_printf(JL_STDERR, "svec_len(method_match): %d\n", jl_svec_len(method_match)); //jl_value_t *tt = jl_svecref(method_match, 0); // unused, already have `types`. jl_svec_t *spvals = (jl_svec_t*)jl_svecref(method_match, 1); - jl_printf(JL_STDERR, "spvals: "); jl_static_show(JL_STDERR, (jl_value_t*)spvals); jl_printf(JL_STDERR, "\n"); + //jl_printf(JL_STDERR, "spvals: "); jl_static_show(JL_STDERR, (jl_value_t*)spvals); jl_printf(JL_STDERR, "\n"); jl_method_t *method = (jl_method_t*)jl_svecref(method_match, 2); - jl_printf(JL_STDERR, "method: "); jl_static_show(JL_STDERR, (jl_value_t*)method); jl_printf(JL_STDERR, "\n"); + //jl_printf(JL_STDERR, "method: "); jl_static_show(JL_STDERR, (jl_value_t*)method); jl_printf(JL_STDERR, "\n"); // now we have found the matching definition. // next look for or create a specialization of this definition. jl_method_instance_t *edge = jl_specializations_get_linfo(method, (jl_value_t*)types, spvals); - jl_printf(JL_STDERR, "edge: "); jl_static_show(JL_STDERR, (jl_value_t*)edge); jl_printf(JL_STDERR, "\n"); + //jl_printf(JL_STDERR, "edge: "); jl_static_show(JL_STDERR, (jl_value_t*)edge); jl_printf(JL_STDERR, "\n"); if (edge != NULL && (jl_value_t*)edge != jl_nothing) { // Now create the edges array and set the edge! - jl_printf(JL_STDERR, "\nedges: "); jl_static_show(JL_STDERR, (jl_value_t*)func->edges); jl_printf(JL_STDERR, "\n"); + //jl_printf(JL_STDERR, "\nedges: "); jl_static_show(JL_STDERR, (jl_value_t*)func->edges); jl_printf(JL_STDERR, "\n"); if (func->edges == jl_nothing) { // TODO: How to construct this array type properly jl_value_t* array_mi_type = jl_apply_type2((jl_value_t*)jl_array_type, @@ -497,7 +497,7 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) //jl_method_instance_add_backedge(edge, linfo); jl_array_ptr_1d_push((jl_array_t*)func->edges, (jl_value_t*)edge); - jl_printf(JL_STDERR, "\nedges: "); jl_static_show(JL_STDERR, (jl_value_t*)func->edges); jl_printf(JL_STDERR, "\n"); + //jl_printf(JL_STDERR, "\nedges: "); jl_static_show(JL_STDERR, (jl_value_t*)func->edges); jl_printf(JL_STDERR, "\n"); } } From 576b14c16b8c656c41ed604ae2dd8cecb8f940d4 Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Thu, 1 Aug 2019 15:28:43 -0400 Subject: [PATCH 11/20] ACTUALLY, it looks like jl_get_specialization1 works! --- src/method.c | 64 ++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/src/method.c b/src/method.c index f3e4160730acf..aff0eac80f50b 100644 --- a/src/method.c +++ b/src/method.c @@ -450,38 +450,44 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) jl_tupletype_t* types = (jl_tupletype_t*)jl_argtype_with_function(gen_func, weird_types_tuple); //jl_printf(JL_STDERR, "\ntypes: "); jl_static_show(JL_STDERR, (jl_value_t*)types); jl_printf(JL_STDERR, "\n"); - // TODO: The bootstrap segfault comes from jl_gf_invoke_lookup. We can't call - // this at this point! Try something else. + // TODO: I still don't know what the right way to specialize the method is. + // I've tried `jl_gf_invoke_lookup` (but that segfaults during bootstrap), + // `jl_get_specialization1` and `jl_specializations_get_linfo.` The last two seem + // to behave identically, so I don't know which is better. Certainly + // jl_get_specialization1 is simpler. + // UPDATE: Actually jl_specializations_get_linfo seems to also cause an error during + // boostrap, complaining about `UndefRefError()`. So maybe jl_get_specialization1. + + // next look for or create a specialization of this definition. + size_t min_valid = 0; + size_t max_valid = ~(size_t)0; + jl_method_instance_t *edge = jl_get_specialization1((jl_tupletype_t*)types, -1, + &min_valid, &max_valid, + 1 /* store new specialization */); + { // To offset the if-statement below -// // next look for or create a specialization of this definition. +// // size_t min_valid = 0; // size_t max_valid = ~(size_t)0; -// jl_method_instance_t *edge = jl_get_specialization1((jl_tupletype_t*)types, -1, -// &min_valid, &max_valid, -// 1 /* store new specialization */); - - - size_t min_valid = 0; - size_t max_valid = ~(size_t)0; - jl_value_t *matches = jl_matching_methods(types, /*limit*/ 1, /*ambiguous*/ 1, - /*world age*/ -1, &min_valid, &max_valid); - //jl_printf(JL_STDERR, "matches: "); jl_static_show(JL_STDERR, (jl_value_t*)matches); jl_printf(JL_STDERR, "\n"); - - if (matches != jl_false) { - jl_value_t *method_match = jl_arrayref((jl_array_t*)matches, 0); - //jl_printf(JL_STDERR, "method_match: %p:", method_match); jl_static_show(JL_STDERR, (jl_value_t*)method_match); jl_printf(JL_STDERR, "\n"); - //jl_printf(JL_STDERR, "jl_typeof(method_match):"); jl_static_show(JL_STDERR, (jl_value_t*)jl_typeof(method_match)); jl_printf(JL_STDERR, "\n"); - //jl_printf(JL_STDERR, "svec_len(method_match): %d\n", jl_svec_len(method_match)); - //jl_value_t *tt = jl_svecref(method_match, 0); // unused, already have `types`. - jl_svec_t *spvals = (jl_svec_t*)jl_svecref(method_match, 1); - //jl_printf(JL_STDERR, "spvals: "); jl_static_show(JL_STDERR, (jl_value_t*)spvals); jl_printf(JL_STDERR, "\n"); - jl_method_t *method = (jl_method_t*)jl_svecref(method_match, 2); - //jl_printf(JL_STDERR, "method: "); jl_static_show(JL_STDERR, (jl_value_t*)method); jl_printf(JL_STDERR, "\n"); - - // now we have found the matching definition. - // next look for or create a specialization of this definition. - jl_method_instance_t *edge = jl_specializations_get_linfo(method, (jl_value_t*)types, spvals); - //jl_printf(JL_STDERR, "edge: "); jl_static_show(JL_STDERR, (jl_value_t*)edge); jl_printf(JL_STDERR, "\n"); +// jl_value_t *matches = jl_matching_methods(types, /*limit*/ 1, /*ambiguous*/ 1, +// /*world age*/ -1, &min_valid, &max_valid); +// //jl_printf(JL_STDERR, "matches: "); jl_static_show(JL_STDERR, (jl_value_t*)matches); jl_printf(JL_STDERR, "\n"); +// +// if (matches != jl_false) { +// jl_value_t *method_match = jl_arrayref((jl_array_t*)matches, 0); +// //jl_printf(JL_STDERR, "method_match: %p:", method_match); jl_static_show(JL_STDERR, (jl_value_t*)method_match); jl_printf(JL_STDERR, "\n"); +// //jl_printf(JL_STDERR, "jl_typeof(method_match):"); jl_static_show(JL_STDERR, (jl_value_t*)jl_typeof(method_match)); jl_printf(JL_STDERR, "\n"); +// //jl_printf(JL_STDERR, "svec_len(method_match): %d\n", jl_svec_len(method_match)); +// //jl_value_t *tt = jl_svecref(method_match, 0); // unused, already have `types`. +// jl_svec_t *spvals = (jl_svec_t*)jl_svecref(method_match, 1); +// //jl_printf(JL_STDERR, "spvals: "); jl_static_show(JL_STDERR, (jl_value_t*)spvals); jl_printf(JL_STDERR, "\n"); +// jl_method_t *method = (jl_method_t*)jl_svecref(method_match, 2); +// //jl_printf(JL_STDERR, "method: "); jl_static_show(JL_STDERR, (jl_value_t*)method); jl_printf(JL_STDERR, "\n"); +// +// // now we have found the matching definition. +// // next look for or create a specialization of this definition. +// jl_method_instance_t *edge = jl_specializations_get_linfo(method, (jl_value_t*)types, spvals); +// //jl_printf(JL_STDERR, "edge: "); jl_static_show(JL_STDERR, (jl_value_t*)edge); jl_printf(JL_STDERR, "\n"); if (edge != NULL && (jl_value_t*)edge != jl_nothing) { // Now create the edges array and set the edge! From 063c920d7f785cb136a3b0d1a7428ce26f0c0af0 Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Thu, 1 Aug 2019 16:15:31 -0400 Subject: [PATCH 12/20] Cleanup --- src/method.c | 78 ++++++++++++++-------------------------------------- 1 file changed, 20 insertions(+), 58 deletions(-) diff --git a/src/method.c b/src/method.c index aff0eac80f50b..4d79689b9b60b 100644 --- a/src/method.c +++ b/src/method.c @@ -419,36 +419,26 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) jl_array_t *stmts = (jl_array_t*)func->code; jl_resolve_globals_in_ir(stmts, def->module, linfo->sparam_vals, 1); } - //jl_printf(JL_STDERR, "\nHELLO\n"); - //jl_printf(JL_STDERR, "def: "); jl_static_show(JL_STDERR, (jl_value_t*)def); jl_printf(JL_STDERR, "\n"); + + // -------------------------------------------------------------------------------- + // Set code_info.edges = [MethodInstance for gen_func(::Any, ::Any...)] + // -------------------------------------------------------------------------------- // Get generator function body jl_value_t* gen_func = jl_get_field(generator, "gen"); - //jl_printf(JL_STDERR, "gen_func: "); jl_static_show(JL_STDERR, (jl_value_t*)gen_func); jl_printf(JL_STDERR, "\n"); - - //// Main user-named staged function - //jl_value_t* staged_function = def->sig; - //jl_printf(JL_STDERR, "\nstaged_function: "); - //jl_static_show(JL_STDERR, (jl_value_t*)staged_function); - //jl_printf(JL_STDERR, "\n"); // Get jl_method_t for generator body // The generator body takes two arguments: (typeof(func), T) - // So types should be e.g.: Tuple{getfield(Main, Symbol("##s4#3")), typeof(Main.foo), Float64} - + // So types should be, e.g.: Tuple{getfield(Main, Symbol("##s4#3")), typeof(Main.foo), Float64} // BUT --- THIS IS THE WEIRD PART: - // Apparently the backedge needs to be from `##s4#3(typeof(func), Type)` instead of + // Apparently the backedge needs to be from `##s4#3(::Any, ::Any)` instead of // the actual types of the aruments! Who knows why!! Weirdness. + // (EDIT: I _think_ this is because the generatorbody is marked nospecialize?) // Manually construct that weird signature, here: - //jl_printf(JL_STDERR, "\nttdt: "); jl_static_show(JL_STDERR, (jl_value_t*)ttdt); jl_printf(JL_STDERR, "\n"); - ssize_t numargs = jl_svec_len(ttdt->parameters); // TODO: is there a better way to get the length of a Tuple? + ssize_t numargs = jl_svec_len(ttdt->parameters); // TODO: is there a better way to get the length of a Tuple type? (jl_nfields?) + // Construct Tuple{typeof(gen_func), ::Any, ::Any} for correct number of args. jl_value_t* weird_types_tuple = jl_tupletype_fill(numargs, (jl_value_t*)jl_any_type); - //jl_printf(JL_STDERR, "\nWeird Tuple types: "); jl_static_show(JL_STDERR, (jl_value_t*)weird_types_tuple); jl_printf(JL_STDERR, "\n"); - // One would expect to be able to just use `tt` here, but we have to use the weird - // thing instead. - //jl_value_t* types = jl_argtype_with_function(gen_func, tt); jl_tupletype_t* types = (jl_tupletype_t*)jl_argtype_with_function(gen_func, weird_types_tuple); - //jl_printf(JL_STDERR, "\ntypes: "); jl_static_show(JL_STDERR, (jl_value_t*)types); jl_printf(JL_STDERR, "\n"); // TODO: I still don't know what the right way to specialize the method is. // I've tried `jl_gf_invoke_lookup` (but that segfaults during bootstrap), @@ -464,47 +454,19 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) jl_method_instance_t *edge = jl_get_specialization1((jl_tupletype_t*)types, -1, &min_valid, &max_valid, 1 /* store new specialization */); - { // To offset the if-statement below - -// -// size_t min_valid = 0; -// size_t max_valid = ~(size_t)0; -// jl_value_t *matches = jl_matching_methods(types, /*limit*/ 1, /*ambiguous*/ 1, -// /*world age*/ -1, &min_valid, &max_valid); -// //jl_printf(JL_STDERR, "matches: "); jl_static_show(JL_STDERR, (jl_value_t*)matches); jl_printf(JL_STDERR, "\n"); -// -// if (matches != jl_false) { -// jl_value_t *method_match = jl_arrayref((jl_array_t*)matches, 0); -// //jl_printf(JL_STDERR, "method_match: %p:", method_match); jl_static_show(JL_STDERR, (jl_value_t*)method_match); jl_printf(JL_STDERR, "\n"); -// //jl_printf(JL_STDERR, "jl_typeof(method_match):"); jl_static_show(JL_STDERR, (jl_value_t*)jl_typeof(method_match)); jl_printf(JL_STDERR, "\n"); -// //jl_printf(JL_STDERR, "svec_len(method_match): %d\n", jl_svec_len(method_match)); -// //jl_value_t *tt = jl_svecref(method_match, 0); // unused, already have `types`. -// jl_svec_t *spvals = (jl_svec_t*)jl_svecref(method_match, 1); -// //jl_printf(JL_STDERR, "spvals: "); jl_static_show(JL_STDERR, (jl_value_t*)spvals); jl_printf(JL_STDERR, "\n"); -// jl_method_t *method = (jl_method_t*)jl_svecref(method_match, 2); -// //jl_printf(JL_STDERR, "method: "); jl_static_show(JL_STDERR, (jl_value_t*)method); jl_printf(JL_STDERR, "\n"); -// -// // now we have found the matching definition. -// // next look for or create a specialization of this definition. -// jl_method_instance_t *edge = jl_specializations_get_linfo(method, (jl_value_t*)types, spvals); -// //jl_printf(JL_STDERR, "edge: "); jl_static_show(JL_STDERR, (jl_value_t*)edge); jl_printf(JL_STDERR, "\n"); - - if (edge != NULL && (jl_value_t*)edge != jl_nothing) { - // Now create the edges array and set the edge! - //jl_printf(JL_STDERR, "\nedges: "); jl_static_show(JL_STDERR, (jl_value_t*)func->edges); jl_printf(JL_STDERR, "\n"); - if (func->edges == jl_nothing) { - // TODO: How to construct this array type properly - jl_value_t* array_mi_type = jl_apply_type2((jl_value_t*)jl_array_type, - (jl_value_t*)jl_method_instance_type, jl_box_long(1)); - - //jl_static_show(JL_STDERR, array_mi_type); - func->edges = (jl_value_t*)jl_alloc_array_1d(array_mi_type, 0); - } - //jl_method_instance_add_backedge(edge, linfo); - jl_array_ptr_1d_push((jl_array_t*)func->edges, (jl_value_t*)edge); - //jl_printf(JL_STDERR, "\nedges: "); jl_static_show(JL_STDERR, (jl_value_t*)func->edges); jl_printf(JL_STDERR, "\n"); + if (edge != NULL && (jl_value_t*)edge != jl_nothing) { + // Now create the edges array and set the edge! + if (func->edges == jl_nothing) { + // TODO: How to construct this array type properly + jl_value_t* array_mi_type = jl_apply_type2((jl_value_t*)jl_array_type, + (jl_value_t*)jl_method_instance_type, jl_box_long(1)); + + func->edges = (jl_value_t*)jl_alloc_array_1d(array_mi_type, 0); } + + //jl_method_instance_add_backedge(edge, linfo); + jl_array_ptr_1d_push((jl_array_t*)func->edges, (jl_value_t*)edge); } ptls->in_pure_callback = last_in; From 9b10e0dd924eb4cb69064a86562615c99081737f Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Thu, 1 Aug 2019 16:28:09 -0400 Subject: [PATCH 13/20] Move all this logic into a function --- src/method.c | 104 +++++++++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 48 deletions(-) diff --git a/src/method.c b/src/method.c index 4d79689b9b60b..316a0586c9300 100644 --- a/src/method.c +++ b/src/method.c @@ -376,54 +376,12 @@ STATIC_INLINE jl_value_t *jl_call_staged(jl_method_t *def, jl_value_t *generator return code; } -// return a newly allocated CodeInfo for the function signature -// effectively described by the tuple (specTypes, env, Method) inside linfo -JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) -{ - JL_TIMING(STAGED_FUNCTION); - jl_value_t *tt = linfo->specTypes; - jl_method_t *def = linfo->def.method; - jl_value_t *generator = def->generator; - assert(generator != NULL); - assert(jl_is_method(def)); - jl_code_info_t *func = NULL; - jl_value_t *ex = NULL; - JL_GC_PUSH2(&ex, &func); - jl_ptls_t ptls = jl_get_ptls_states(); - int last_lineno = jl_lineno; - int last_in = ptls->in_pure_callback; - size_t last_age = jl_get_ptls_states()->world_age; - - JL_TRY { - ptls->in_pure_callback = 1; - // and the right world - ptls->world_age = def->primary_world; - - // invoke code generator - jl_tupletype_t *ttdt = (jl_tupletype_t*)jl_unwrap_unionall(tt); - ex = jl_call_staged(def, generator, linfo->sparam_vals, jl_svec_data(ttdt->parameters), jl_nparams(ttdt)); - - if (jl_is_code_info(ex)) { - func = (jl_code_info_t*)ex; - } - else { - func = (jl_code_info_t*)jl_expand((jl_value_t*)ex, def->module); - if (!jl_is_code_info(func)) { - if (jl_is_expr(func) && ((jl_expr_t*)func)->head == error_sym) { - ptls->in_pure_callback = 0; - jl_toplevel_eval(def->module, (jl_value_t*)func); - } - jl_error("The function body AST defined by this @generated function is not pure. This likely means it contains a closure or comprehension."); - } - - jl_array_t *stmts = (jl_array_t*)func->code; - jl_resolve_globals_in_ir(stmts, def->module, linfo->sparam_vals, 1); - } - - // -------------------------------------------------------------------------------- - // Set code_info.edges = [MethodInstance for gen_func(::Any, ::Any...)] - // -------------------------------------------------------------------------------- - +// Sets func.edges = MethodInstance[MethodInstance for generator(::Any, ::Any...)] +// This is so that @generated functions will be re-generated if any functions called from +// the generator body are invalidated. +static void set_codeinfo_forward_edge_to_generator(jl_code_info_t *func, + jl_value_t *generator, + jl_tupletype_t *ttdt) { // Get generator function body jl_value_t* gen_func = jl_get_field(generator, "gen"); @@ -468,6 +426,56 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) //jl_method_instance_add_backedge(edge, linfo); jl_array_ptr_1d_push((jl_array_t*)func->edges, (jl_value_t*)edge); } +} + +// return a newly allocated CodeInfo for the function signature +// effectively described by the tuple (specTypes, env, Method) inside linfo +JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) +{ + JL_TIMING(STAGED_FUNCTION); + jl_value_t *tt = linfo->specTypes; + jl_method_t *def = linfo->def.method; + jl_value_t *generator = def->generator; + assert(generator != NULL); + assert(jl_is_method(def)); + jl_code_info_t *func = NULL; + jl_value_t *ex = NULL; + JL_GC_PUSH2(&ex, &func); + jl_ptls_t ptls = jl_get_ptls_states(); + int last_lineno = jl_lineno; + int last_in = ptls->in_pure_callback; + size_t last_age = jl_get_ptls_states()->world_age; + + JL_TRY { + ptls->in_pure_callback = 1; + // and the right world + ptls->world_age = def->primary_world; + + // invoke code generator + jl_tupletype_t *ttdt = (jl_tupletype_t*)jl_unwrap_unionall(tt); + ex = jl_call_staged(def, generator, linfo->sparam_vals, jl_svec_data(ttdt->parameters), jl_nparams(ttdt)); + + if (jl_is_code_info(ex)) { + func = (jl_code_info_t*)ex; + } + else { + func = (jl_code_info_t*)jl_expand((jl_value_t*)ex, def->module); + if (!jl_is_code_info(func)) { + if (jl_is_expr(func) && ((jl_expr_t*)func)->head == error_sym) { + ptls->in_pure_callback = 0; + jl_toplevel_eval(def->module, (jl_value_t*)func); + } + jl_error("The function body AST defined by this @generated function is not pure. This likely means it contains a closure or comprehension."); + } + + jl_array_t *stmts = (jl_array_t*)func->code; + jl_resolve_globals_in_ir(stmts, def->module, linfo->sparam_vals, 1); + } + + // Set forward edge from the staged func `func` to the generator, so that the + // generator will be rerun if any dependent functions called from the generator body + // are invalidated. This keeps generated functions up-to-date, like other functions. + set_codeinfo_forward_edge_to_generator(func, generator, ttdt); ptls->in_pure_callback = last_in; jl_lineno = last_lineno; From 06a7011b5486c0ae9753ddbb0e5e9475a188980d Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Fri, 2 Aug 2019 12:25:38 -0400 Subject: [PATCH 14/20] Start adding unit tests for invalidating generated functions. There are still some broken cases -- working through them slowly. --- test/method.jl | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 test/method.jl diff --git a/test/method.jl b/test/method.jl new file mode 100644 index 0000000000000..e23401d4ba6b5 --- /dev/null +++ b/test/method.jl @@ -0,0 +1,68 @@ +using Test + +@testset "Normal generated functions" begin + @generated g1(x) = :(x) + @test g1(1) == 1 + @test g1("hi") == "hi" +end + +# Invalidating Generated Functions +# TODO: For some reason this doesn't work inside a testset right now (See below) +@generated foo() = bar() +bar() = 2 +# We can still call foo() even though bar() was defined after! Hooray! :) +@test foo() == 2 +# Now we can change bar(), and foo() is also updated! Woohoo! :D +bar() = 3 +@test foo() == 3 + + +@testset "invalidating generated functions in a testset" begin + @generated foo() = bar() + bar() = 2 + + # TODO: It seems like this doesn't work becuase of the @testset. Is that expected? + # Would this work for regular functions? I think it's broken... + @test foo() == 2 + bar() = 3 + @test_broken foo() == 3 +end + + +# Functions that take arguments +@generated f(x) = f2(x) + f2(x) +f2(x::Type) = sizeof(x) +@test f(1) == 16 +f2(x::Type) = sizeof(x)÷2 +@test f(1) == 8 + + +# Method at bottom of call-stack accepts ::Type, not ::Any +# The simple case -- bar(::Any): +@generated foo(x) = bar(x) +bar(x) = 2 +@test foo(1) == 2 +bar(x) = 3 +@test foo(1) == 3 +# TODO: This doesn't work for some reason +# The complex case -- bar(::Type): +@generated f_type(x) = t1(x) +t1(::Type{Int}) = 2 +@test f_type(1) == 2 +t(::Type) = 3 +@test_broken f_type(1) == 3 + + +## Functions with type params +#@generated f(x::T) where T<:Number = biggest(T) +#biggest(::Type{T}) where T = typemax(T) +#f(10) +## It also works for newly defined types +#struct MyNum <: Number x::Int end +#Base.typemax(::Type{MyNum}) = MyNum(typemax(Int)) +#f(MyNum(10)) +## And still allows users to interactively change their mind about these definitions +#Base.typemax(::Type{MyNum}) = MyNum(100) +#biggest(::Type{MyNum}) = MyNum(100) +#f(MyNum(10)) +# From ba6c2542b2013df89c64fde52ff53be9efc03c4f Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Fri, 2 Aug 2019 13:23:32 -0400 Subject: [PATCH 15/20] Fix MWE broken test to _actually_ show the problem --- test/method.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/method.jl b/test/method.jl index e23401d4ba6b5..e077c2edf4b33 100644 --- a/test/method.jl +++ b/test/method.jl @@ -49,7 +49,7 @@ bar(x) = 3 @generated f_type(x) = t1(x) t1(::Type{Int}) = 2 @test f_type(1) == 2 -t(::Type) = 3 +t(::Type{Int}) = 3 @test_broken f_type(1) == 3 From e75224ba6f0cd7fa28e26ae5c83e2b499eed4995 Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Fri, 2 Aug 2019 13:16:23 -0400 Subject: [PATCH 16/20] Remove world-age freezing when calling generator Instead of calling the generator via Core._apply_pure in julia, just don't set a weird world-age --- base/boot.jl | 4 ++-- src/method.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index 99cda41c24800..ba45daf6f1fc4 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -521,8 +521,8 @@ end # invoke and wrap the results of @generated function (g::GeneratedFunctionStub)(@nospecialize args...) - #body = g.gen(args...) - body = Core._apply_pure(g.gen, (args...,)) + body = g.gen(args...) + #body = Core._apply_pure(g.gen, (args...,)) if body isa CodeInfo return body end diff --git a/src/method.c b/src/method.c index 316a0586c9300..8054b8077c8c4 100644 --- a/src/method.c +++ b/src/method.c @@ -444,12 +444,12 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) jl_ptls_t ptls = jl_get_ptls_states(); int last_lineno = jl_lineno; int last_in = ptls->in_pure_callback; - size_t last_age = jl_get_ptls_states()->world_age; + //size_t last_age = jl_get_ptls_states()->world_age; JL_TRY { ptls->in_pure_callback = 1; // and the right world - ptls->world_age = def->primary_world; + //ptls->world_age = def->primary_world; // invoke code generator jl_tupletype_t *ttdt = (jl_tupletype_t*)jl_unwrap_unionall(tt); @@ -479,7 +479,7 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) ptls->in_pure_callback = last_in; jl_lineno = last_lineno; - ptls->world_age = last_age; + //ptls->world_age = last_age; jl_linenumber_to_lineinfo(func, (jl_value_t*)def->name); } JL_CATCH { From 58c60ac1fae33ad9ca9f47f597fb502830d64bc4 Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Fri, 2 Aug 2019 14:06:46 -0400 Subject: [PATCH 17/20] Revert "Remove world-age freezing when calling generator" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 4df638db6e37b90364ada09f2cdd734dab8f3b5b. It caused a weird error during julia's precompilation: ``` Generating precompile statements...┌ Error: Failed to precompile precompile(Tuple{getfield(Dates, Symbol("##s624#32")), Type{Tuple{Dates.DatePart{Char(0x59000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x6d000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x64000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x48000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x4d000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x53000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x73000000)}}}, Type{typeof(Dates.format)}, Type{Base.GenericIOBuffer{Array{UInt8, 1}}}, Type{Dates.DateTime}, Type{Dates.DateFormat{Symbol("YYYY-mm-dd\THH:MM:SS.s"), Tuple{Dates.DatePart{Char(0x59000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x6d000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x64000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x48000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x4d000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x53000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x73000000)}}}}}) └ @ Main.anonymous /Users/nathan.daly/src/julia2/contrib/generate_precompile.jl:167 ERROR: LoadError: LoadError: syntax: invalid escape sequence ``` Also, I'm not 100% sure _what_ the right world-age should be to run these functions in. I _think_ it makes sense to just use the current world-age, like a regular function, but it could also be reasonable to run them always at the latest world age (which is close to what we're currently doing) since they're currently run as pure functions. But if we run them at the latest world-age, will this behave weirdly?: ```julia julia> @generated foo(x) = baz(x) foo (generic function with 1 method) julia> baz(x) = 1 baz (generic function with 1 method) julia> function f() @eval baz(x) = 2 foo(1) end f (generic function with 1 method) julia> f() # Should be 1, but if `foo()` is always run at latest world-age, will this be 2? Maybe this would work just-fine, actually? ``` --- base/boot.jl | 4 ++-- src/method.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index ba45daf6f1fc4..99cda41c24800 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -521,8 +521,8 @@ end # invoke and wrap the results of @generated function (g::GeneratedFunctionStub)(@nospecialize args...) - body = g.gen(args...) - #body = Core._apply_pure(g.gen, (args...,)) + #body = g.gen(args...) + body = Core._apply_pure(g.gen, (args...,)) if body isa CodeInfo return body end diff --git a/src/method.c b/src/method.c index 8054b8077c8c4..316a0586c9300 100644 --- a/src/method.c +++ b/src/method.c @@ -444,12 +444,12 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) jl_ptls_t ptls = jl_get_ptls_states(); int last_lineno = jl_lineno; int last_in = ptls->in_pure_callback; - //size_t last_age = jl_get_ptls_states()->world_age; + size_t last_age = jl_get_ptls_states()->world_age; JL_TRY { ptls->in_pure_callback = 1; // and the right world - //ptls->world_age = def->primary_world; + ptls->world_age = def->primary_world; // invoke code generator jl_tupletype_t *ttdt = (jl_tupletype_t*)jl_unwrap_unionall(tt); @@ -479,7 +479,7 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) ptls->in_pure_callback = last_in; jl_lineno = last_lineno; - //ptls->world_age = last_age; + ptls->world_age = last_age; jl_linenumber_to_lineinfo(func, (jl_value_t*)def->name); } JL_CATCH { From 12687d8c6e54959358edc94da4b5e0353f4dec77 Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Fri, 2 Aug 2019 18:56:43 -0400 Subject: [PATCH 18/20] Fix unit tests to _actually_ show broken behavior --- test/method.jl | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/test/method.jl b/test/method.jl index e077c2edf4b33..20f1074593a7f 100644 --- a/test/method.jl +++ b/test/method.jl @@ -44,13 +44,19 @@ bar(x) = 2 @test foo(1) == 2 bar(x) = 3 @test foo(1) == 3 -# TODO: This doesn't work for some reason -# The complex case -- bar(::Type): -@generated f_type(x) = t1(x) -t1(::Type{Int}) = 2 +# This also works, with t(::Type{Int}) +@generated f_type(x) = t(x) +t(::Type{Int}) = 2 @test f_type(1) == 2 t(::Type{Int}) = 3 -@test_broken f_type(1) == 3 +@test f_type(1) == 3 +# Yet for some reason this does not work: +# Somehow having t1(T) call typemax prevents forming a backedge from t1 to the generator. +@generated f_type2(x) = t1(x) +t1(T) = typemax(T) +@test f_type2(1) == typemax(Int) +t1(T) = 3 +@test_broken f_type2(1) == 3 ## Functions with type params From 8c05fc6fc458a85e01cd282125bfd99551f2fb3d Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Mon, 5 Aug 2019 13:59:31 -0400 Subject: [PATCH 19/20] Fix redef generated for functions with type sparams --- src/method.c | 17 ++++++++++++----- test/method.jl | 26 +++++++++++++------------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/method.c b/src/method.c index 316a0586c9300..d0b134c10a43d 100644 --- a/src/method.c +++ b/src/method.c @@ -381,21 +381,24 @@ STATIC_INLINE jl_value_t *jl_call_staged(jl_method_t *def, jl_value_t *generator // the generator body are invalidated. static void set_codeinfo_forward_edge_to_generator(jl_code_info_t *func, jl_value_t *generator, + jl_svec_t *sparam_vals, jl_tupletype_t *ttdt) { // Get generator function body jl_value_t* gen_func = jl_get_field(generator, "gen"); // Get jl_method_t for generator body - // The generator body takes two arguments: (typeof(func), T) - // So types should be, e.g.: Tuple{getfield(Main, Symbol("##s4#3")), typeof(Main.foo), Float64} + // The generator body takes three sets of arguments: (typeof(func), params..., T...) + // For example, for `foo(x::Array{T}) where T`: + // Tuple{getfield(Main, Symbol("##s4#3")), typeof(Main.foo), Int64, Array{Int64}} // BUT --- THIS IS THE WEIRD PART: // Apparently the backedge needs to be from `##s4#3(::Any, ::Any)` instead of // the actual types of the aruments! Who knows why!! Weirdness. // (EDIT: I _think_ this is because the generatorbody is marked nospecialize?) // Manually construct that weird signature, here: - ssize_t numargs = jl_svec_len(ttdt->parameters); // TODO: is there a better way to get the length of a Tuple type? (jl_nfields?) + size_t numargs = jl_svec_len(ttdt->parameters); // TODO: is there a better way to get the length of a Tuple type? (jl_nfields?) + size_t n_sparams = jl_svec_len(sparam_vals); // Construct Tuple{typeof(gen_func), ::Any, ::Any} for correct number of args. - jl_value_t* weird_types_tuple = jl_tupletype_fill(numargs, (jl_value_t*)jl_any_type); + jl_value_t* weird_types_tuple = jl_tupletype_fill(numargs + n_sparams, (jl_value_t*)jl_any_type); jl_tupletype_t* types = (jl_tupletype_t*)jl_argtype_with_function(gen_func, weird_types_tuple); // TODO: I still don't know what the right way to specialize the method is. @@ -426,6 +429,10 @@ static void set_codeinfo_forward_edge_to_generator(jl_code_info_t *func, //jl_method_instance_add_backedge(edge, linfo); jl_array_ptr_1d_push((jl_array_t*)func->edges, (jl_value_t*)edge); } + else { + jl_printf(JL_STDERR, "WARNING: no edge for generated function body "); + jl_static_show(JL_STDERR, gen_func); jl_printf(JL_STDERR, "\n"); + } } // return a newly allocated CodeInfo for the function signature @@ -475,7 +482,7 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) // Set forward edge from the staged func `func` to the generator, so that the // generator will be rerun if any dependent functions called from the generator body // are invalidated. This keeps generated functions up-to-date, like other functions. - set_codeinfo_forward_edge_to_generator(func, generator, ttdt); + set_codeinfo_forward_edge_to_generator(func, generator, linfo->sparam_vals, ttdt); ptls->in_pure_callback = last_in; jl_lineno = last_lineno; diff --git a/test/method.jl b/test/method.jl index 20f1074593a7f..3efd3d769a6fa 100644 --- a/test/method.jl +++ b/test/method.jl @@ -59,16 +59,16 @@ t1(T) = 3 @test_broken f_type2(1) == 3 -## Functions with type params -#@generated f(x::T) where T<:Number = biggest(T) -#biggest(::Type{T}) where T = typemax(T) -#f(10) -## It also works for newly defined types -#struct MyNum <: Number x::Int end -#Base.typemax(::Type{MyNum}) = MyNum(typemax(Int)) -#f(MyNum(10)) -## And still allows users to interactively change their mind about these definitions -#Base.typemax(::Type{MyNum}) = MyNum(100) -#biggest(::Type{MyNum}) = MyNum(100) -#f(MyNum(10)) -# +# Functions with type params +@generated f(x::T) where T<:Number = width(T) +width(::Type{Int}) where T = 5 +@test f(10) == 5 +width(::Type{Int}) where T = 100 +@test f(10) == 100 + +# It also works for newly defined types +struct MyNum <: Number x::Int end +width(::Type{MyNum}) where T = MyNum(5) +@test f(MyNum(10)) == MyNum(5) +width(::Type{MyNum}) where T = MyNum(100) +@test f(MyNum(10)) == MyNum(100) From f20d374071ba871cbe1cebb90e939372ca01e555 Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Mon, 5 Aug 2019 15:09:10 -0400 Subject: [PATCH 20/20] Fix recompiling generated functions w/ varargs... ```julia @generated f(a::T, b, c...) where T<:Number = bar(T) + bar(a) + bar(b) + sum(bar(v) for v in c) bar(x) = 2 @test f(2,3,4) == 8 bar(x) = 3 @test f(2,3,4) == 12 @test f(2,3,4,5) == 15 ``` --- src/method.c | 18 ++++++++++-------- test/method.jl | 11 ++++++++++- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/method.c b/src/method.c index d0b134c10a43d..820a702af92bf 100644 --- a/src/method.c +++ b/src/method.c @@ -379,11 +379,12 @@ STATIC_INLINE jl_value_t *jl_call_staged(jl_method_t *def, jl_value_t *generator // Sets func.edges = MethodInstance[MethodInstance for generator(::Any, ::Any...)] // This is so that @generated functions will be re-generated if any functions called from // the generator body are invalidated. -static void set_codeinfo_forward_edge_to_generator(jl_code_info_t *func, +static void set_codeinfo_forward_edge_to_generator(jl_method_t *def, + jl_code_info_t *func, jl_value_t *generator, jl_svec_t *sparam_vals, jl_tupletype_t *ttdt) { - // Get generator function body + // Get generator function body (not GeneratedFunctionStub) to attach an edge to it jl_value_t* gen_func = jl_get_field(generator, "gen"); // Get jl_method_t for generator body @@ -395,11 +396,12 @@ static void set_codeinfo_forward_edge_to_generator(jl_code_info_t *func, // the actual types of the aruments! Who knows why!! Weirdness. // (EDIT: I _think_ this is because the generatorbody is marked nospecialize?) // Manually construct that weird signature, here: - size_t numargs = jl_svec_len(ttdt->parameters); // TODO: is there a better way to get the length of a Tuple type? (jl_nfields?) size_t n_sparams = jl_svec_len(sparam_vals); + // Get def->nargs, not number of args in ttdt, to correctly count varargs. + size_t numargs = n_sparams + def->nargs; // Construct Tuple{typeof(gen_func), ::Any, ::Any} for correct number of args. - jl_value_t* weird_types_tuple = jl_tupletype_fill(numargs + n_sparams, (jl_value_t*)jl_any_type); - jl_tupletype_t* types = (jl_tupletype_t*)jl_argtype_with_function(gen_func, weird_types_tuple); + jl_value_t* weird_types_tuple = jl_tupletype_fill(numargs, (jl_value_t*)jl_any_type); + jl_tupletype_t* typesig = (jl_tupletype_t*)jl_argtype_with_function(gen_func, weird_types_tuple); // TODO: I still don't know what the right way to specialize the method is. // I've tried `jl_gf_invoke_lookup` (but that segfaults during bootstrap), @@ -412,7 +414,7 @@ static void set_codeinfo_forward_edge_to_generator(jl_code_info_t *func, // next look for or create a specialization of this definition. size_t min_valid = 0; size_t max_valid = ~(size_t)0; - jl_method_instance_t *edge = jl_get_specialization1((jl_tupletype_t*)types, -1, + jl_method_instance_t *edge = jl_get_specialization1((jl_tupletype_t*)typesig, -1, &min_valid, &max_valid, 1 /* store new specialization */); @@ -431,7 +433,7 @@ static void set_codeinfo_forward_edge_to_generator(jl_code_info_t *func, } else { jl_printf(JL_STDERR, "WARNING: no edge for generated function body "); - jl_static_show(JL_STDERR, gen_func); jl_printf(JL_STDERR, "\n"); + jl_static_show(JL_STDERR, (jl_value_t*)def); jl_printf(JL_STDERR, "\n"); } } @@ -482,7 +484,7 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) // Set forward edge from the staged func `func` to the generator, so that the // generator will be rerun if any dependent functions called from the generator body // are invalidated. This keeps generated functions up-to-date, like other functions. - set_codeinfo_forward_edge_to_generator(func, generator, linfo->sparam_vals, ttdt); + set_codeinfo_forward_edge_to_generator(def, func, generator, linfo->sparam_vals, ttdt); ptls->in_pure_callback = last_in; jl_lineno = last_lineno; diff --git a/test/method.jl b/test/method.jl index 3efd3d769a6fa..1a4010c761669 100644 --- a/test/method.jl +++ b/test/method.jl @@ -21,7 +21,7 @@ bar() = 3 @generated foo() = bar() bar() = 2 - # TODO: It seems like this doesn't work becuase of the @testset. Is that expected? + # TODO: It seems like this doesn't work because of the @testset. Is that expected? # Would this work for regular functions? I think it's broken... @test foo() == 2 bar() = 3 @@ -72,3 +72,12 @@ width(::Type{MyNum}) where T = MyNum(5) @test f(MyNum(10)) == MyNum(5) width(::Type{MyNum}) where T = MyNum(100) @test f(MyNum(10)) == MyNum(100) + + +# Functions with varargs +@generated f(a::T, b, c...) where T<:Number = bar(T) + bar(a) + bar(b) + sum(bar(v) for v in c) +bar(x) = 2 +@test f(2,3,4) == 8 +bar(x) = 3 +@test f(2,3,4) == 12 +@test f(2,3,4,5) == 15