From 78ebf06f55eff05db6939166973bbfa08641300b Mon Sep 17 00:00:00 2001 From: relrelb Date: Sat, 9 Jul 2022 11:49:07 +0300 Subject: [PATCH] avm2: Extract `MethodFlags` enum --- core/src/avm2/activation.rs | 24 ++++++++++++++++++------ core/src/avm2/method.rs | 11 +++++++---- swf/src/avm2/read.rs | 11 ++++------- swf/src/avm2/types.rs | 19 +++++++++++++++---- swf/src/avm2/write.rs | 13 +------------ swf/src/test_data.rs | 10 ++-------- 6 files changed, 47 insertions(+), 41 deletions(-) diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index ff129d565..3f307dc3e 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -22,8 +22,8 @@ use std::borrow::Cow; use std::cmp::{min, Ordering}; use swf::avm2::read::Reader; use swf::avm2::types::{ - Class as AbcClass, Index, Method as AbcMethod, Multiname as AbcMultiname, - Namespace as AbcNamespace, Op, + Class as AbcClass, Index, Method as AbcMethod, MethodFlags as AbcMethodFlags, + Multiname as AbcMultiname, Namespace as AbcNamespace, Op, }; /// Represents a particular register set. @@ -407,7 +407,11 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { *write.get_mut(0).unwrap() = this.map(|t| t.into()).unwrap_or(Value::Null); } - let activation_class = if method.method().needs_activation { + let activation_class = if method + .method() + .flags + .contains(AbcMethodFlags::NEED_ACTIVATION) + { let translation_unit = method.translation_unit(); let abc_method = method.method(); let mut dummy_activation = Activation::from_nothing(context.reborrow()); @@ -454,9 +458,13 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { } if has_rest_or_args { - let args_array = if method.method().needs_arguments_object { + let args_array = if method + .method() + .flags + .contains(AbcMethodFlags::NEED_ARGUMENTS) + { ArrayStorage::from_args(&arguments_list) - } else if method.method().needs_rest { + } else if method.method().flags.contains(AbcMethodFlags::NEED_REST) { if let Some(rest_args) = arguments_list.get(signature.len()..) { ArrayStorage::from_args(rest_args) } else { @@ -468,7 +476,11 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { let mut args_object = ArrayObject::from_storage(&mut activation, args_array)?; - if method.method().needs_arguments_object { + if method + .method() + .flags + .contains(AbcMethodFlags::NEED_ARGUMENTS) + { args_object.set_property( &QName::new(Namespace::public(), "callee").into(), callee.into(), diff --git a/core/src/avm2/method.rs b/core/src/avm2/method.rs index eeda2f373..fbd50d96b 100644 --- a/core/src/avm2/method.rs +++ b/core/src/avm2/method.rs @@ -11,7 +11,8 @@ use gc_arena::{Collect, CollectionContext, Gc, MutationContext}; use std::fmt; use std::rc::Rc; use swf::avm2::types::{ - AbcFile, Index, Method as AbcMethod, MethodBody as AbcMethodBody, MethodParam as AbcMethodParam, + AbcFile, Index, Method as AbcMethod, MethodBody as AbcMethodBody, + MethodFlags as AbcMethodFlags, MethodParam as AbcMethodParam, }; /// Represents a function defined in Ruffle's code. @@ -241,7 +242,9 @@ impl<'gc> BytecodeMethod<'gc> { /// /// Variadic methods shove excess parameters into a final register. pub fn is_variadic(&self) -> bool { - self.method().needs_arguments_object || self.method().needs_rest + self.method() + .flags + .intersects(AbcMethodFlags::NEED_ARGUMENTS | AbcMethodFlags::NEED_REST) } /// Determine if a given method is unchecked. @@ -262,7 +265,7 @@ impl<'gc> BytecodeMethod<'gc> { } } - !self.method().needs_rest + !self.method().flags.contains(AbcMethodFlags::NEED_REST) } } @@ -371,7 +374,7 @@ impl<'gc> Method<'gc> { pub fn needs_arguments_object(&self) -> bool { match self { Method::Native { .. } => false, - Method::Bytecode(bm) => bm.method().needs_arguments_object, + Method::Bytecode(bm) => bm.method().flags.contains(AbcMethodFlags::NEED_ARGUMENTS), } } } diff --git a/swf/src/avm2/read.rs b/swf/src/avm2/read.rs index ecae00b22..cc6a233ad 100644 --- a/swf/src/avm2/read.rs +++ b/swf/src/avm2/read.rs @@ -253,9 +253,9 @@ impl<'a> Reader<'a> { }) } let name = self.read_index()?; - let flags = self.read_u8()?; + let flags = MethodFlags::from_bits_truncate(self.read_u8()?); - if flags & 0x08 != 0 { + if flags.contains(MethodFlags::HAS_OPTIONAL) { let num_optional_params = self.read_u30()? as usize; if let Some(start) = params.len().checked_sub(num_optional_params) { for param in &mut params[start..] { @@ -266,7 +266,7 @@ impl<'a> Reader<'a> { } } - if flags & 0x80 != 0 { + if flags.contains(MethodFlags::HAS_PARAM_NAMES) { for param in &mut params { param.name = Some(self.read_index()?); } @@ -276,10 +276,7 @@ impl<'a> Reader<'a> { name, params, return_type, - needs_arguments_object: flags & 0x01 != 0, - needs_activation: flags & 0x02 != 0, - needs_rest: flags & 0x04 != 0, - needs_dxns: flags & 0x40 != 0, + flags, }) } diff --git a/swf/src/avm2/types.rs b/swf/src/avm2/types.rs index 9a3676d22..e45a9003b 100644 --- a/swf/src/avm2/types.rs +++ b/swf/src/avm2/types.rs @@ -1,3 +1,4 @@ +use bitflags::bitflags; use std::marker::PhantomData; #[derive(Clone, Debug, PartialEq)] @@ -98,10 +99,20 @@ pub struct Method { pub name: Index, pub params: Vec, pub return_type: Index, - pub needs_arguments_object: bool, - pub needs_activation: bool, - pub needs_rest: bool, - pub needs_dxns: bool, + pub flags: MethodFlags, +} + +bitflags! { + pub struct MethodFlags: u8 { + const NEED_ARGUMENTS = 1 << 0; + const NEED_ACTIVATION = 1 << 1; + const NEED_REST = 1 << 2; + const HAS_OPTIONAL = 1 << 3; + const IGNORE_REST = 1 << 4; + const NATIVE = 1 << 5; + const SET_DXNS = 1 << 6; + const HAS_PARAM_NAMES = 1 << 7; + } } #[derive(Clone, Debug, PartialEq)] diff --git a/swf/src/avm2/write.rs b/swf/src/avm2/write.rs index c2882e510..e4e82fb3d 100644 --- a/swf/src/avm2/write.rs +++ b/swf/src/avm2/write.rs @@ -341,18 +341,7 @@ impl Writer { } } self.write_index(&method.name)?; - self.write_u8( - if has_param_names { 0x80 } else { 0 } - | if method.needs_dxns { 0x40 } else { 0 } - | if num_optional_params > 0 { 0x08 } else { 0 } - | if method.needs_rest { 0x04 } else { 0 } - | if method.needs_activation { 0x02 } else { 0 } - | if method.needs_arguments_object { - 0x01 - } else { - 0 - }, - )?; + self.write_u8(method.flags.bits())?; if num_optional_params > 0 { self.write_u30(num_optional_params)?; diff --git a/swf/src/test_data.rs b/swf/src/test_data.rs index 035415212..797a13197 100644 --- a/swf/src/test_data.rs +++ b/swf/src/test_data.rs @@ -2803,19 +2803,13 @@ pub fn avm2_tests() -> Vec { name: Index::new(0), params: vec![], return_type: Index::new(1), - needs_arguments_object: false, - needs_activation: false, - needs_rest: false, - needs_dxns: false, + flags: MethodFlags::empty(), }, Method { name: Index::new(0), params: vec![], return_type: Index::new(0), - needs_arguments_object: false, - needs_activation: false, - needs_rest: false, - needs_dxns: false, + flags: MethodFlags::empty(), }, ], metadata: vec![],