Skip to content

Commit

Permalink
wip: convert staticdata to support codeinstance for recursion instead…
Browse files Browse the repository at this point in the history
… of badly guessing

needs some more work with handling cycles, and some ordering questions,
but seems mostly working now
  • Loading branch information
vtjnash committed Oct 28, 2024
1 parent 32e41fc commit c8c6cd1
Show file tree
Hide file tree
Showing 6 changed files with 296 additions and 327 deletions.
56 changes: 44 additions & 12 deletions base/compiler/stmtinfo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,38 +60,69 @@ function add_edges_impl(edges::Vector{Any}, info::MethodMatchInfo)
end
nmatches = length(info.results)
if nmatches == length(info.edges) == 1
# try the optimized format for the representation, if possible and applicable
# if this doesn't succeed, the backedge will be less precise,
# but the forward edge will maintain the precision
edge = info.edges[1]
if edge !== nothing
# try the optimized format for the representation, if possible and applicable
# if this doesn't succeed, the backedge will be less precise,
# but the forward edge will maintain the precision
if edge.def.specTypes === info.results[1].spec_types
add_one_edge!(edges, edge)
return nothing
end
m = info.results[1]
if edge === nothing
mi = specialize_method(m)
edge = mi
else
mi = edge.def
end
if mi.specTypes === m.spec_types
add_one_edge!(edges, edge)
return nothing
end
end
# add check for whether this lookup already existed in the edges list
for i in 1:length(edges)
if edges[i] === nmatches && edges[i+1] == info.atype
# TODO: must also verify the CodeInstance match too
return nothing
end
end
push!(edges, nmatches, info.atype)
for i = 1:nmatches
edge = info.edges[i]
if edge !== nothing
m = info.results[i]
if edge === nothing
# push!(edges, m.method)
mi = specialize_method(m)
push!(edges, mi)
else
@assert edge.def.def === m.method
push!(edges, edge)
end
end
nothing
end
function add_one_edge!(edges::Vector{Any}, edge::MethodInstance)
for i in 1:length(edges)
edgeᵢ = edges[i]
edgeᵢ isa CodeInstance && (edgeᵢ = edgeᵢ.def)
edgeᵢ isa MethodInstance || continue
if edgeᵢ === edge && !(i > 1 && edges[i-1] isa Type)
return # found existing covered edge
end
end
push!(edges, edge)
nothing
end
function add_one_edge!(edges::Vector{Any}, edge::CodeInstance)
for i in 1:length(edges)
edgeᵢ = edges[i]
# XXX compare `CodeInstance` identify?
if edgeᵢ isa CodeInstance && edgeᵢ.def === edge.def && !(i > 1 && edges[i-1] isa Type)
return
edgeᵢ isa CodeInstance && (edgeᵢ = edgeᵢ.def)
edgeᵢ isa MethodInstance || continue
if edgeᵢ === edge.def && !(i > 1 && edges[i-1] isa Type)
if edges[i] isa MethodInstance
# found edge we can upgrade
edges[i] = edge
return
elseif true # XXX compare `CodeInstance` identify?
return
end
end
end
push!(edges, edge)
Expand Down Expand Up @@ -301,6 +332,7 @@ function add_edges_impl(edges::Vector{Any}, info::OpaqueClosureCallInfo)
if edge !== nothing
add_one_edge!(edges, edge)
end
nothing
end

"""
Expand Down
9 changes: 1 addition & 8 deletions base/compiler/typeinfer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,7 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState;
if !@isdefined di
di = DebugInfo(result.linfo)
end
istoplevel = !(caller.linfo.def isa Method) # don't add backedges to toplevel method instance
if istoplevel
edges = empty_edges
else
# TODO remove the next line once we make staticdata_utils.c able to handle `CodeInstance` edge directly
edges = Any[edge isa CodeInstance ? edge.def : edge for edge in caller.edges]
edges = Core.svec(edges...)
end
edges = Core.svec(caller.edges...)
min_world, max_world = first(valid_worlds), last(valid_worlds)
effects_bits = encode_effects(result.ipo_effects)
ccall(:jl_update_codeinst, Cvoid, (Any, Any, Int32, UInt, UInt, UInt32, Any, UInt8, Any, Any),
Expand Down
10 changes: 7 additions & 3 deletions base/compiler/utilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,13 @@ function iterate(iter::BackedgeIterator, i::Int=1)
i > length(backedges) && return nothing
item = backedges[i]
item isa Int && (i += 2; continue) # ignore the query information if present
isa(item, CodeInstance) && return BackedgePair(nothing, item.def), i+1 # regular dispatch
isa(item, MethodTable) && return BackedgePair(backedges[i+1], item), i+2 # abstract dispatch
return BackedgePair(item, (backedges[i+1]::CodeInstance).def), i+2 # `invoke` calls
isa(item, MethodInstance) && (i += 1; continue) # ignore edges which don't contribute info (future style edges)
isa(item, CodeInstance) && (item = item.def)
isa(item, MethodInstance) && return BackedgePair(nothing, item), i+1 # regular dispatch
isa(item, MethodTable) && return BackedgePair(backedges[i+1], item), i+2 # abstract dispatch (legacy style edges)
target = backedges[i+1]
isa(target, CodeInstance) && (target = target.def)
return BackedgePair(item, target::MethodInstance), i+2 # `invoke` calls
end
end

Expand Down
5 changes: 5 additions & 0 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,8 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst(
uint8_t relocatability,
jl_debuginfo_t *di, jl_svec_t *edges /*, int absolute_max*/)
{
assert(min_world <= max_world && "attempting to set invalid world constraints");
assert((!(jl_is_method(mi->def.value) && max_world == ~(size_t)0 && min_world > 1) || edges == NULL || jl_svec_len(edges) != 0) && "missing edges");
jl_task_t *ct = jl_current_task;
assert(min_world <= max_world && "attempting to set invalid world constraints");
jl_code_instance_t *codeinst = (jl_code_instance_t*)jl_gc_alloc(ct->ptls, sizeof(jl_code_instance_t),
Expand Down Expand Up @@ -569,6 +571,8 @@ JL_DLLEXPORT void jl_update_codeinst(
uint32_t effects, jl_value_t *analysis_results,
uint8_t relocatability, jl_debuginfo_t *di, jl_svec_t *edges /* , int absolute_max*/)
{
assert(min_world <= max_world && "attempting to set invalid world constraints");
//assert((!jl_is_method(codeinst->def->def.value) || max_world != ~(size_t)0 || min_world <= 1 || jl_svec_len(edges) != 0) && "missing edges");
codeinst->relocatability = relocatability;
codeinst->analysis_results = analysis_results;
jl_gc_wb(codeinst, analysis_results);
Expand Down Expand Up @@ -596,6 +600,7 @@ JL_DLLEXPORT void jl_fill_codeinst(
jl_debuginfo_t *di, jl_svec_t *edges /* , int absolute_max*/)
{
assert(min_world <= max_world && "attempting to set invalid world constraints");
assert((!jl_is_method(codeinst->def->def.value) || max_world != ~(size_t)0 || min_world <= 1 || jl_svec_len(edges) != 0) && "missing edges");
codeinst->rettype = rettype;
jl_gc_wb(codeinst, rettype);
codeinst->exctype = exctype;
Expand Down
13 changes: 3 additions & 10 deletions src/staticdata.c
Original file line number Diff line number Diff line change
Expand Up @@ -548,9 +548,6 @@ typedef struct {
jl_array_t *link_ids_gvars;
jl_array_t *link_ids_external_fnvars;
jl_ptls_t ptls;
// Set (implemented has a hasmap of MethodInstances to themselves) of which MethodInstances have (forward) edges
// to other MethodInstances.
htable_t callers_with_edges;
jl_image_t *image;
int8_t incremental;
} jl_serializer_state;
Expand Down Expand Up @@ -1767,6 +1764,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
if (s->incremental) {
if (jl_atomic_load_relaxed(&ci->max_world) == ~(size_t)0) {
if (jl_atomic_load_relaxed(&newci->min_world) > 1) {
assert(ci->edges != jl_emptysvec);
jl_atomic_store_release(&newci->min_world, ~(size_t)0);
jl_atomic_store_release(&newci->max_world, WORLD_AGE_REVALIDATION_SENTINEL);
arraylist_push(&s->fixup_objs, (void*)reloc_offset);
Expand Down Expand Up @@ -2828,13 +2826,12 @@ static void jl_prepare_serialization_data(jl_array_t *mod_array, jl_array_t *new

if (edges) {
size_t world = jl_atomic_load_acquire(&jl_world_counter);
// jl_collect_extext_methods_from_mod accumulate data in callers_with_edges.
// Process this to extract `new_ext_cis` and `edges`
// Extract `new_ext_cis` and `edges` now (from info prepared by jl_collect_methcache_from_mod)
*method_roots_list = jl_alloc_vec_any(0);
// Collect the new method roots for external specializations
jl_collect_new_roots(&relocatable_ext_cis, *method_roots_list, *new_ext_cis, worklist_key);
*edges = jl_alloc_vec_any(0);
jl_collect_edges(*edges, *new_ext_cis, world);
jl_collect_internal_cis(*edges, world);
}
internal_methods = NULL;

Expand Down Expand Up @@ -2965,7 +2962,6 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
s.link_ids_gctags = jl_alloc_array_1d(jl_array_int32_type, 0);
s.link_ids_gvars = jl_alloc_array_1d(jl_array_int32_type, 0);
s.link_ids_external_fnvars = jl_alloc_array_1d(jl_array_int32_type, 0);
htable_new(&s.callers_with_edges, 0);
jl_value_t **const*const tags = get_tags(); // worklist == NULL ? get_tags() : NULL;


Expand Down Expand Up @@ -3005,8 +3001,6 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
// Queue the worklist itself as the first item we serialize
jl_queue_for_serialization(&s, worklist);
jl_queue_for_serialization(&s, jl_module_init_order);
// Classify the CodeInstances with respect to their need for validation
classify_callers(&s.callers_with_edges, edges);
}
// step 1.1: as needed, serialize the data needed for insertion into the running system
if (extext_methods) {
Expand Down Expand Up @@ -3108,7 +3102,6 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
);
jl_exit(1);
}
htable_free(&s.callers_with_edges);

// step 3: combine all of the sections into one file
assert(ios_pos(f) % JL_CACHE_BYTE_ALIGNMENT == 0);
Expand Down
Loading

0 comments on commit c8c6cd1

Please sign in to comment.