avm2: Extract `MethodFlags` enum

This commit is contained in:
relrelb 2022-07-09 11:49:07 +03:00 committed by relrelb
parent afd24cad12
commit 78ebf06f55
6 changed files with 47 additions and 41 deletions

View File

@ -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(),

View File

@ -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),
}
}
}

View File

@ -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,
})
}

View File

@ -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<String>,
pub params: Vec<MethodParam>,
pub return_type: Index<Multiname>,
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)]

View File

@ -341,18 +341,7 @@ impl<W: Write> Writer<W> {
}
}
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)?;

View File

@ -2803,19 +2803,13 @@ pub fn avm2_tests() -> Vec<Avm2TestData> {
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![],