Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

khepri_fun: Resolve label inside {call_fun2, {u,Idx}, ...} instruction #149

Merged
merged 1 commit into from
Oct 11, 2022

Conversation

dumbbell
Copy link
Member

In pull request #134, the {u,Idx} argument was discarded and replaced by {atom, safe} because the module was already compiled successfully and the register used in the instruction must point to a valid function.

Idx is an offset in the Lambda table ("FunT" in the beam chunks). In this patch, we decode this table. This allows us to resolve the label used by call_fun2 and replace {u,Idx} by a valid {f,Label}.

This is probably a small optimization of the resulting code, but it closer to what the Erlang compiler would do.

The testcase is expanded to execute the extracted function to make sure it still works.

@dumbbell dumbbell added the enhancement New feature or request label Oct 11, 2022
@dumbbell dumbbell self-assigned this Oct 11, 2022
@codecov
Copy link

codecov bot commented Oct 11, 2022

Codecov Report

Base: 90.82% // Head: 90.99% // Increases project coverage by +0.16% 🎉

Coverage data is based on head (958169b) compared to base (dc09766).
Patch coverage: 94.73% of modified lines in pull request are covered.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #149      +/-   ##
==========================================
+ Coverage   90.82%   90.99%   +0.16%     
==========================================
  Files          16       16              
  Lines        2868     2886      +18     
==========================================
+ Hits         2605     2626      +21     
+ Misses        263      260       -3     
Flag Coverage Δ
erlang-24 89.57% <63.15%> (-0.08%) ⬇️
erlang-25 89.53% <94.73%> (+0.17%) ⬆️
os-ubuntu-latest 90.92% <94.73%> (+0.09%) ⬆️
os-windows-latest 89.53% <94.73%> (+0.27%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
src/khepri_fun.erl 93.09% <94.44%> (+0.02%) ⬆️
src/khepri_tx_adv.erl 80.24% <100.00%> (+0.04%) ⬆️
src/khepri_machine.erl 93.95% <0.00%> (+0.60%) ⬆️

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

@dumbbell
Copy link
Member Author

dumbbell commented Oct 11, 2022

FTR, beam_lib knows how to decode some of the beam chunks, but not all of them. In this patch, we need to decode two of them:

  • the Atom table ("Atom" or "AtU8" more recently)
  • the Lambda table ("FunT")

beam_lib knows how to decode the former, but not the latter.

The code to decode all chunks is in beam_file.c. That's what I used as the reference to decode all chunks we need here and in previous commits ("StrT", "Line", "FunT").

src/khepri_fun.erl Outdated Show resolved Hide resolved
In pull request #134, the `{u,Idx}` argument was discarded and replaced
by `{atom, safe}` because the module was already compiled successfully
and the register used in the instruction must point to a valid function.

`Idx` is an offset in the Lambda table ("FunT" in the beam chunks). In
this patch, we decode this table. This allows us to resolve the label
used by `call_fun2` and replace `{u,Idx}` by a valid `{f,Label}`.

This is probably a small optimization of the resulting code, but it
closer to what the Erlang compiler would do.

The testcase is expanded to execute the extracted function to make sure
it still works.
@dumbbell dumbbell marked this pull request as ready for review October 11, 2022 16:05
@dumbbell dumbbell merged commit 7dc9fd4 into main Oct 11, 2022
@dumbbell dumbbell deleted the resolve-label-in-call_fun2 branch October 11, 2022 16:06
@dumbbell dumbbell added this to the v0.6.0 milestone Oct 11, 2022
dumbbell added a commit that referenced this pull request Nov 2, 2022
Since #149, we resolve and adjust the jump label inside the `call_fun2`
instruction. This way we are as close as possible to the code originally
produced by the compiler and benefit from its optimizations.

However, there is one situation where we can't keep the jump label: it
is when the called local function is not local anymore after extraction.

To avoid many almost identical copies of the same anonymous function
where only the environment changes, `khepri_fun` will extract the
function in a dedicated module and keep the environment separate. If
there is another anonymous function inside this environment, it will
become its own module.

Therefore, it's possible that in the original Beam code, the two
anonymous functions were inside the same module. If the compiler emitted
a `call_fun2` instruction, it could use a jump label in the outer
function to call the inner function passed in the environment.

After extraction by `khepri_fun`, this is no longer possible because the
inner function will be in another module. `call_fun2` must use the
`{atom, safe}` argument instead.
dumbbell added a commit that referenced this pull request Nov 2, 2022
Since #149, we resolve and adjust the jump label inside the `call_fun2`
instruction. This way we are as close as possible to the code originally
produced by the compiler and benefit from its optimizations.

However, there is one situation where we can't keep the jump label: it
is when the called local function is not local anymore after extraction.

To avoid many almost identical copies of the same anonymous function
where only the environment changes, `khepri_fun` will extract the
function in a dedicated module and keep the environment separate. If
there is another anonymous function inside this environment, it will
become its own module.

Therefore, it's possible that in the original Beam code, the two
anonymous functions were inside the same module. If the compiler emitted
a `call_fun2` instruction, it could use a jump label in the outer
function to call the inner function passed in the environment.

After extraction by `khepri_fun`, this is no longer possible because the
inner function will be in another module. `call_fun2` must use the
`{atom, safe}` argument instead.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants