Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Compiler/src/effects.jl
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ is_inaccessiblemem_or_argmemonly(effects::Effects) = effects.inaccessiblememonly

is_consistent_overlay(effects::Effects) = effects.nonoverlayed === CONSISTENT_OVERLAY

# (sync this with codegen.cpp and staticdata.c effects_foldable functions)
function encode_effects(e::Effects)
return ((e.consistent % UInt32) << 0) |
((e.effect_free % UInt32) << 3) |
Expand Down
8 changes: 4 additions & 4 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10182,10 +10182,10 @@ jl_llvm_functions_t jl_emit_codeinst(
else if (jl_is_method(def) && // don't delete toplevel code
def->source != NULL && // don't delete code from optimized opaque closures that can't be reconstructed
inferred != jl_nothing && // and there is something to delete (test this before calling jl_ir_inlining_cost)
!effects_foldable(jl_atomic_load_relaxed(&codeinst->ipo_purity_bits)) && // don't delete code we may want for irinterp
((jl_ir_inlining_cost(inferred) == UINT16_MAX) || // don't delete inlineable code
jl_atomic_load_relaxed(&codeinst->invoke) == jl_fptr_const_return_addr) && // unless it is constant
!(params.imaging_mode || jl_options.incremental)) { // don't delete code when generating a precompile file
((!effects_foldable(jl_atomic_load_relaxed(&codeinst->ipo_purity_bits)) && // don't delete code we may want for irinterp
(jl_ir_inlining_cost(inferred) == UINT16_MAX) && // don't delete inlineable code
!jl_generating_output()) || // don't delete code when generating a precompile file, trading memory in the short term for avoiding likely duplicating inference work for aotcompile
jl_atomic_load_relaxed(&codeinst->invoke) == jl_fptr_const_return_addr)) { // unless it is constant (although this shouldn't have had code in the first place)
// Never end up in a situation where the codeinst has no invoke, but also no source, so we never fall
// through the cracks of SOURCE_MODE_ABI.
jl_callptr_t expected = NULL;
Expand Down
30 changes: 28 additions & 2 deletions src/staticdata.c
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,16 @@ static uintptr_t jl_fptr_id(void *fptr)
return *(uintptr_t*)pbp;
}

static int effects_foldable(uint32_t effects)
{
// N.B.: This needs to be kept in sync with Core.Compiler.is_foldable(effects, true)
return ((effects & 0x7) == 0) && // is_consistent(effects)
(((effects >> 10) & 0x03) == 0) && // is_noub(effects)
(((effects >> 3) & 0x03) == 0) && // is_effect_free(effects)
((effects >> 6) & 0x01); // is_terminates(effects)
}


// `jl_queue_for_serialization` adds items to `serialization_order`
#define jl_queue_for_serialization(s, v) jl_queue_for_serialization_((s), (jl_value_t*)(v), 1, 0)
static void jl_queue_for_serialization_(jl_serializer_state *s, jl_value_t *v, int recursive, int immediate) JL_GC_DISABLED;
Expand Down Expand Up @@ -908,8 +918,24 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_
// TODO: if (ci in ci->defs->cache)
record_field_change((jl_value_t**)&ci->next, NULL);
}
if (jl_atomic_load_relaxed(&ci->inferred) && !is_relocatable_ci(&relocatable_ext_cis, ci))
record_field_change((jl_value_t**)&ci->inferred, jl_nothing);
jl_value_t *inferred = jl_atomic_load_relaxed(&ci->inferred);
if (inferred && inferred != jl_nothing) { // disregard if there is nothing here to delete (e.g. builtins, unspecialized)
if (!is_relocatable_ci(&relocatable_ext_cis, ci))
record_field_change((jl_value_t**)&ci->inferred, jl_nothing);
else if (jl_is_method(ci->def->def.method) && // don't delete toplevel code
ci->def->def.method->source) { // don't delete code from optimized opaque closures that can't be reconstructed (and builtins)
if (jl_atomic_load_relaxed(&ci->max_world) != ~(size_t)0 || // delete all code that cannot run
jl_atomic_load_relaxed(&ci->invoke) == jl_fptr_const_return) { // delete all code that just returns a constant
record_field_change((jl_value_t**)&ci->inferred, jl_nothing);
}
else if (native_functions && // don't delete any code if making a ji file
!effects_foldable(jl_atomic_load_relaxed(&ci->ipo_purity_bits)) && // don't delete code we may want for irinterp
jl_ir_inlining_cost(inferred) == UINT16_MAX) { // don't delete inlineable code
// delete the code now: if we thought it was worth keeping, it would have been converted to object code
record_field_change((jl_value_t**)&ci->inferred, jl_nothing);
}
}
}
Comment on lines -911 to +938
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the fact that this change is so effective in reducing the sysimg size imply that some CodeInstance objects being serialized are not codegen’d?

My understanding was that the similar deletion code in codegen.cpp should have been sufficient for this purpose.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That delete only applies when code is generated for params.cache===true, which doesn't occur when doing serialization for codegen

}

if (immediate) // must be things that can be recursively handled, and valid as type parameters
Expand Down
Loading