Skip to content

Introduce function-level pruning algorithm - #65

Open
pguyot wants to merge 1 commit into
atomvm:masterfrom
pguyot:w38/prune-functions
Open

pguyot wants to merge 1 commit into
atomvm:masterfrom
pguyot:w38/prune-functions

Conversation

@pguyot

@pguyot pguyot commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator

Works better with atomvm/AtomVM#2404

These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).

SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later

@pguyot
pguyot force-pushed the w38/prune-functions branch from 2170cd0 to c42c932 Compare September 25, 2026 15:09

@UncleGrumpy UncleGrumpy left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We should also update UPDATING.md with the change in pruning behavior, since this could break some apps that expect module level pruning - especially where some functions from a module not called directly by the app are expected to be available for use as disterl rpc calls.

We way want to open an issue after this merges to automate the regeneration of src/packbeam_drivers.hrl from the AtomVM repo, so master stays in sync with AtomVM current release branch or main - which is something we will need to decide on since sometimes they diverge quite far.

Comment thread src/packbeam_prune.erl
Comment thread src/packbeam_prune.erl
Comment thread src/packbeam_beam.erl
Comment thread src/packbeam_prune.erl
Comment thread src/packbeam_drivers.erl
Comment thread src/packbeam_beam.erl
Comment thread src/packbeam_api.erl
@pguyot
pguyot force-pushed the w38/prune-functions branch from c42c932 to 50aabee Compare October 10, 2026 17:21
@pguyot

pguyot commented Oct 10, 2026

Copy link
Copy Markdown
Collaborator Author

We way want to open an issue after this merges to automate the regeneration of src/packbeam_drivers.hrl from the AtomVM repo, so master stays in sync with AtomVM current release branch or main - which is something we will need to decide on since sometimes they diverge quite far.

Very true. And I realize that what I created didn't match the release branch. Let's use a CI script for this.

@pguyot
pguyot force-pushed the w38/prune-functions branch 2 times, most recently from f97d837 to a2120f2 Compare October 10, 2026 17:25

@UncleGrumpy UncleGrumpy left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Since this was a large and complicated PR, I had CodeRabbit do a review and a few things turned up, several of which may need to be checked for validity.

Comment thread src/packbeam.erl Outdated
Comment thread src/packbeam_beam.erl
Keep -> Keep;
More -> close_references(Fs, M, More)
end.
op_labels(Name, [A | _], Funs) when Name =:= make_fun2; Name =:= make_fun3 ->

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

A CodeRabbit review turned this up, which should be verified as accurate:

Include call_fun2 targets in the keep closure.

call_fun2 uses its first operand as a FunT index. trim/2 retains that row, but op_labels/3 does not retain its target label. If the target has no retained make_fun* instruction, rebuilding FunT can fail at maps:get(L, LM).
🐛 Suggested fix

--- "a/src/packbeam_beam.erl"
+++ "b/src/packbeam_beam.erl"
@@ -124,7 +124,9 @@
Keep -> Keep;
More -> close_references(Fs, M, More)
end.
-op_labels(Name, [A | _], Funs) when Name =:= make_fun2; Name =:= make_fun3 ->
+op_labels(Name, [A | _], Funs) when

  • Name =:= make_fun2; Name =:= make_fun3; Name =:= call_fun2
    +->
    {?COMPACT_LITERAL, I} = value(A),
    [L || [_, _, L, _, _, ] <- [maps:get(I, Funs)]];
    op_labels(
    , As, _) ->

Comment thread src/packbeam_beam.erl
enc(T, V) when V < 2048 -> <<((V bsr 8) bsl 5 bor 8 bor T), (V band 255)>>;
enc(T, V) ->
B = binary:encode_unsigned(V),
N = byte_size(B),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This was another CodeRabbit suggestions that may or may not be accurate, I haven't spent enough time studying the internals of the beam compiler:

Preserve the sign byte when re-encoding large positive operands.

At V = 32768, binary:encode_unsigned/1 produces <<16#80, 0>>. This encoder writes those bytes without the leading zero used by the BEAM assembler for a positive compact operand. A pruned module with a relocated index or label at that boundary can therefore contain an invalid operand. Prefix a zero byte when the high bit is set.

case maps:get(received, G) andalso lists:member({F, A}, ?SENDS) of
true -> 1 bsl (A - 1);
false -> 0
end;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

CodeRabbit also suggests:

Select the message operand by function, not by last position.

When a receive makes messages relevant, message_arg/2 selects the last argument for every function in ?SENDS. The message is argument 2 for erlang:send/3 and argument 3 for erlang:send_after/4 and erlang:start_timer/4; their last arguments are options. If a call’s result is unused, this pass can miss the message value that determines a later dynamic call target and prune that target. Select the documented message position for each function.

@UncleGrumpy

Copy link
Copy Markdown
Collaborator

We also may want to broaden the test scope to cover any cases that would have failed before these requested changes to prevent any future regression.

@pguyot
pguyot force-pushed the w38/prune-functions branch 2 times, most recently from 1f1f6a4 to b211b79 Compare October 19, 2026 05:06
Signed-off-by: Paul Guyot <pguyot@kallisys.net>
@pguyot
pguyot force-pushed the w38/prune-functions branch from b211b79 to 12d1cfe Compare October 19, 2026 05:11

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants