Skip to content

avm1: Dynamically resolve builtin classes (1/N: preliminaries) - #24327

Open
moulins wants to merge 3 commits into
ruffle-rs:masterfrom
moulins:avm1-dyn-global-access
Open

avm1: Dynamically resolve builtin classes (1/N: preliminaries)#24327
moulins wants to merge 3 commits into
ruffle-rs:masterfrom
moulins:avm1-dyn-global-access

Conversation

@moulins

@moulins moulins commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Description

When Ruffle's native code needs to instantiate an AVM1 object, it selects the prototype to use from the static list stored in the SystemPrototypes struct.

However, this is incorrect, as testing in FP shows that overwriting builtin classes in the _global scope affects the prototype of objects instantiated by the player.

This PR lays the foundations for this change by:

  • adding a test, demonstrating the behavior
  • adding the Activation::resolve_prototype method, to lookup a class prototype on the global scope
  • changing the InitObject action to rely on the above method instead of SystemPrototypes, as a proof of concept.

Follow-up PRs will switch more instantiations to use resolve_prototype; in the long term I expect the SystemPrototypes struct to be entirely phased out.

Testing

The added test (avm1/globals_monkeypatch) only exercises a few examples, it will be expanded upon in future PRs.

Checklist

  • I, a human, have self-reviewed this PR and fully understand the changes within.
  • I have made or updated tests where possible.
  • All of my commits are properly scoped, compile successfully, and pass all tests.
  • This PR does not make sense to split up into smaller PRs.
  • An LLM was involved in the authoring of this code.

@moulins moulins added A-avm1 Area: AVM1 (ActionScript 1 & 2) T-compat Type: Compatibility with Flash Player waiting-on-review Waiting on review from a Ruffle team member labels Jul 29, 2026
@kjarosh

kjarosh commented Jul 29, 2026

Copy link
Copy Markdown
Member

I think there was a discussion about it with @adrian17 at some point because we were worried it will negatively impact performance by a lot. There was this idea to keep SystemPrototypes but make it possible to change them, have you done any perf tests regarding that?

v = _global.Object;

trace("// Object = {}");
_global.Object = {};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What if Object is a virtual property? We could add a getter here and see exactly when FP resolves classes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The monkeyPatch function adds a getter, so this is already tested afterwards.

@moulins

moulins commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

I think there was a discussion about it with @adrian17 at some point because we were worried it will negatively impact performance by a lot. There was this idea to keep SystemPrototypes but make it possible to change them, have you done any perf tests regarding that?

I just wrote this micro-benchmark:

Code

    var i = 1000;
    var o;
    while (i--) {
      o = {}; o = {}; o = {}; o = {};
      o = {}; o = {}; o = {}; o = {};
      o = {}; o = {}; o = {}; o = {};
      o = {}; o = {}; o = {}; o = {};
      o = {}; o = {}; o = {}; o = {};
    }

Results

Target ms / iter
Ruffle (master) 3.2
Ruffle (this PR) 4.0
Flash Player 6.9
FP (debugger) 13

There is some performance loss (roughly -33%), but I think it's acceptable, as:

  • the code is very artificial and pretty much the worst-case scenario
  • we're still quite a bit faster than Flash Player

There are also some avenues to improve object lookup performance in the future, e.g. in case sensitive mode we could store keys as interned strings to get cheaper hashing and equality tests in PropertyMap.

@moulins
moulins force-pushed the avm1-dyn-global-access branch from 09796c7 to 2ba925b Compare July 30, 2026 09:39
@moulins

moulins commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

Update: I did further tests on more realistic code, and any performance cost gets lost in the noise.

moulins added 3 commits August 3, 2026 03:19
Unlike what Ruffle implements (with the `SystemPrototypes` struct), Flash Player
appears to always resolve classes on the global object, allowing for builtins
to be monkeypatched at runtime.

For now, this only tests a small part of the API surface, but this will be expanded
upon in the future.
...instead of using the pre-cached object prototype.
This is needed to properly distinguish between no `prototype` and
`prototype = undefined` when resolving builtin classes.
@moulins
moulins force-pushed the avm1-dyn-global-access branch from 2ba925b to f07aa5a Compare August 3, 2026 01:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-avm1 Area: AVM1 (ActionScript 1 & 2) T-compat Type: Compatibility with Flash Player waiting-on-review Waiting on review from a Ruffle team member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants