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

avm2: Implement support for native methods in playerglobal #7244

Merged
merged 1 commit into from
Jul 15, 2022

Conversation

Aaron1011
Copy link
Member

@Aaron1011 Aaron1011 commented Jun 16, 2022

This commit adds support for marking methods as native
in ActionScript classes defined in playerglobal. The
build_playerglobal now checks for native methods, and
generates Rust code linking them to a corresponding Rust
function definition in the codebase.

To test this functionality, I've reimplemented several
functions as native methods (and moved related code to
pure ActionScript).

@Aaron1011 Aaron1011 force-pushed the playerglobal-native branch 2 times, most recently from cc2fe1d to 3653144 Compare June 18, 2022 15:56
@Aaron1011 Aaron1011 force-pushed the playerglobal-native branch from 3653144 to 9c6fe81 Compare June 19, 2022 19:45
Copy link
Member

@kmeisthax kmeisthax left a comment

Choose a reason for hiding this comment

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

I'd mark this as approved but the prior PR this depends on hasn't been merged in first. But this is absolutely fantastic work. Much appreciated.

@Aaron1011 Aaron1011 force-pushed the playerglobal-native branch from 9c6fe81 to e7f8fac Compare June 23, 2022 16:35
@Aaron1011
Copy link
Member Author

@kmeisthax Now that the other PR has been merged, do you think that this is ready to merge?

@Aaron1011 Aaron1011 force-pushed the playerglobal-native branch 2 times, most recently from 7b80213 to 9974af4 Compare June 24, 2022 18:18
@Aaron1011 Aaron1011 force-pushed the playerglobal-native branch 4 times, most recently from 4610a11 to 33d2a95 Compare July 2, 2022 21:12
// instance methods, class methods, and freestanding functions.
// We're going to insert them into an `FnvHashMap`, so the order
// that we visit them in doesn't matter.
for (i, instance) in abc.instances.iter().enumerate() {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not entirely sure how it's matters, but it seems like nativegen.py recursively traverses through Script -> Method/Class, rather than a linear Instance scan.

Copy link
Member Author

Choose a reason for hiding this comment

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

Nothing depends on the iteration order, since we just use the method ids.

let mut reader = swf::avm2::read::Reader::new(data);
let abc = reader.read()?;

let mut rust_paths = FnvHashMap::default();
Copy link
Contributor

@relrelb relrelb Jul 9, 2022

Choose a reason for hiding this comment

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

How about turning this FnvHashMap into a simple Vec? This way we can get rid of the fnv dependency.

I suggest turning this into a native_methods: Vec<&Method>, which will be gathered in check_trait.
Then the Rust-path logic of check_trait will be moved out of it, next to the Rust code generation.

Copy link
Member Author

Choose a reason for hiding this comment

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

We need the parent in order to construct the Rust path, so I think it would be simpler to keep that in check_trait. However, I can change it to directly construct a Vec<Option<TokenStream>> with 'holes' for missing methods.

@Aaron1011 Aaron1011 force-pushed the playerglobal-native branch 2 times, most recently from 008df66 to dec04b1 Compare July 9, 2022 17:40
@Aaron1011
Copy link
Member Author

@relrelb I've addressed your comments

@Aaron1011 Aaron1011 force-pushed the playerglobal-native branch 2 times, most recently from 00f8367 to 6ad342e Compare July 9, 2022 17:49
@Aaron1011
Copy link
Member Author

@relrelb Are there any other changes that you'd like me to make?


let mut method = None;
if is_global {
if let Some(native) = activation.avm2().native_table[method_index.0 as usize] {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe this can be included in the generated NATIVE_TABLE itself? Though it would require Method to be constructible at a const context.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think this is nearly as easy, with GC in the way.
One minor thing I think we could do would be move the props (esp signature) from BytecodeMethod to the NativeMethod without cloning them.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've refactored this to move out of signature.

@Aaron1011 Aaron1011 force-pushed the playerglobal-native branch from d00a061 to 07c4195 Compare July 10, 2022 15:56
@Aaron1011
Copy link
Member Author

@relrelb I've addressed your most recent comments.

@Herschel Herschel self-assigned this Jul 10, 2022
Copy link
Member

@Herschel Herschel left a comment

Choose a reason for hiding this comment

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

Thanks for your work! Looks good here, okay with you @relrelb ?

Comment on lines +240 to +247
let make_native_table = quote! {
const NATIVE_TABLE: &[Option<crate::avm2::method::NativeMethodImpl>] = &[
#(#rust_paths,)*
];
}
.to_string();

// Each table entry ends with ') ,' - insert a newline so that
// each entry is on its own line. This makes error messages more readable.
let make_native_table = make_native_table.replace(") ,", ") ,\n");
Copy link
Member

@Herschel Herschel Jul 14, 2022

Choose a reason for hiding this comment

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

I wonder if it's worth using, for example, prettyplease to make the output nicer in the future. Overkill for this specific case, but I expect we will be generating more and more code that it might be worthwhile at some point.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, it might be worth adding along with custom instance allocator support (which I'm working on in a follow-up PR).

@Herschel Herschel removed their assignment Jul 15, 2022
@Aaron1011 Aaron1011 force-pushed the playerglobal-native branch from 5431644 to 72db741 Compare July 15, 2022 03:46
Copy link
Contributor

@relrelb relrelb left a comment

Choose a reason for hiding this comment

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

Looks good, able to merge in my opinion, just please rebase/square before merging.

This commit adds support for marking methods as `native`
in ActionScript classes defined in playerglobal. The
`build_playerglobal` now checks for native methods, and
generates Rust code linking them to a corresponding Rust
function definition in the codebase.

To test this functionality, I've reimplemented several
functions as native methods (and moved related code to
pure ActionScript).
@Aaron1011 Aaron1011 force-pushed the playerglobal-native branch from 72db741 to 880ea71 Compare July 15, 2022 15:48
@Aaron1011
Copy link
Member Author

The Nightly failure is due to the regression rust-lang/rust#99286

@Aaron1011 Aaron1011 merged commit af4f181 into ruffle-rs:master Jul 15, 2022
@Aaron1011 Aaron1011 deleted the playerglobal-native branch July 15, 2022 22:15
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.

5 participants