Skip to content

Refactor bytecode representation #4220

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

Merged
merged 6 commits into from
May 10, 2025
Merged

Refactor bytecode representation #4220

merged 6 commits into from
May 10, 2025

Conversation

raskad
Copy link
Member

@raskad raskad commented Mar 30, 2025

This PR changes the bytecode encoding / decoding, the bytecode emitting and the opcode execution logic.

In addition to this change in bytecode encoding, I took the chance to add two further changes:

  1. Move arguments decoding into defined central types. This enables us to reuse arguments decoding code and geet rid of alot of the per opcode boilerplate that was error prone to write manually.
  2. Generate emit functions for every opcode that can be used in the bytecompiler to get rid of error prone manual emit code.
  3. Move the handling of different CompletionTypes into the opcode code itself. This results in the CompletionType enum being removed. This moves the handling code out of the hot loop that is iterating trough the opcodes. Also many opcodes can only return a limited possibility of completions. Moving the handling into the opcodes enables a more specific handling, in some cases basically removing any handling at all.

Copy link

github-actions bot commented Mar 30, 2025

Test262 conformance changes

Test result main count PR count difference
Total 50,254 50,254 0
Passed 46,857 46,857 0
Ignored 1,634 1,634 0
Failed 1,763 1,763 0
Panics 0 0 0
Conformance 93.24% 93.24% 0.00%

@raskad
Copy link
Member Author

raskad commented Mar 30, 2025

This is not finished in any way. I just wanted to put it out to get some feedback on the overal concept. All of the flowgraph / trace code is still missing from the new appoach. If the feedback is positive, I will see how to best implement that / possibly also move into macros. In addition spend_budget_and_execute is also not implemented yet and some arguments are not represented optimally (I wanted to see if there are performance gains first, before spending more time on that).

To get an overview / feeling for the changes:

  • look at some changes in the bytecompiler code for the new emit code.
  • look at some individual opcode files for the execution code
  • see some of the major changes in core/engine/src/vm/opcode/mod.rs and core/engine/src/vm/opcode/args.rs.

@raskad raskad force-pushed the refactor-bytecode-u64-wip branch from e45496f to 55c225e Compare April 13, 2025 00:37
@raskad raskad marked this pull request as ready for review April 13, 2025 01:16
@raskad raskad added this to the next-release milestone Apr 13, 2025
@raskad raskad requested a review from a team April 13, 2025 01:16
Copy link
Member

@HalidOdat HalidOdat left a comment

Choose a reason for hiding this comment

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

Really liking the direction of this PR, simplifying the arguments and generating the opcode functions is a great step forward. 😄

That said, I did notice that the bytecode size increases by about 3x (based on checking the combined.js output). While some of that overhead might be reduced by encoding multiple instructions into a single one, it's still likely to end up at least twice as large overall. Additionally, splitting the bytecode into two arrays could have a negative impact on cache locality.

Overall, I think the approach we're taking is aligned with what engines like V8 and JavaScriptCore are doing. There's a great article from the JavaScriptCore team that touches on a similar idea with prefix opcodes: A new bytecode format for JavaScriptCore.

In terms of performance, I suspect the bigger issue isn't so much unaligned reads, but rather how we read arguments — currently it's done one at a time, with a bounds check on each access. We might see a noticeable performance boost if we check bounds ahead of time and read the arguments in bulk.

Would love to hear your thoughts! :)

EDIT: Here is the code I used to get the size :)

@raskad raskad force-pushed the refactor-bytecode-u64-wip branch from 55c225e to a42bb06 Compare May 9, 2025 01:18
@raskad
Copy link
Member Author

raskad commented May 9, 2025

In terms of performance, I suspect the bigger issue isn't so much unaligned reads, but rather how we read arguments — currently it's done one at a time, with a bounds check on each access. We might see a noticeable performance boost if we check bounds ahead of time and read the arguments in bulk.

I think that is probably the case. I switched back to the u8 bytecode format and I still get a slight performance increase in my first tests.

Switching back to the u8 format was much easier with the new macro based opcode emit functions and the new opcode execution dispatching. So I think just for that it would make sense to merge this.

@raskad raskad requested a review from a team May 9, 2025 01:24
Copy link
Member

@HalidOdat HalidOdat left a comment

Choose a reason for hiding this comment

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

Awesome work! Really love the removal of the execute_* functions with arguments definitions and the type-safe compiler functions 🤩

Just had some comments on how we could improve it, see if they make any sense, the rest looks good to me :)

@HalidOdat HalidOdat added technical debt execution Issues or PRs related to code execution vm Issues and PRs related to the Boa Virtual Machine. Internal Category for changelog labels May 10, 2025
@HalidOdat
Copy link
Member

HalidOdat commented May 10, 2025

This PR resolves #2561 🥳

@HalidOdat HalidOdat linked an issue May 10, 2025 that may be closed by this pull request
@@ -0,0 +1,736 @@
use thin_vec::ThinVec;
Copy link
Member

@nekevss nekevss May 10, 2025

Choose a reason for hiding this comment

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

nit (non-blocking): add some unit tests here or an issue should be opened to add tests for the unsafe code here.

Still working my reading through this, so I'm familiar with it. 😆 It may come up in the future if we have some unsafe code here but no unit tests in the module. I wouldn't block merging this on lack of tests, but if none are added, we should at least open up an issue. Plus, adding the unit tests themselves could make a good first issue for someone looking to contribute.

Copy link
Member Author

Choose a reason for hiding this comment

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

Definitely. I will open an issue after the merge.

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

@HalidOdat HalidOdat left a comment

Choose a reason for hiding this comment

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

Besides the nitpick, this looks perfect to me! 😄

@raskad raskad added this pull request to the merge queue May 10, 2025
Merged via the queue into main with commit 2a59eb3 May 10, 2025
14 checks passed
@raskad raskad deleted the refactor-bytecode-u64-wip branch May 10, 2025 21:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
execution Issues or PRs related to code execution Internal Category for changelog technical debt vm Issues and PRs related to the Boa Virtual Machine.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make bytecode generation more typesafe
3 participants