swf: Use bitflags for Function flags

This commit is contained in:
Mike Welsh 2021-05-30 17:22:49 -07:00
parent 2b98c878f0
commit f173b81e38
4 changed files with 50 additions and 88 deletions

View File

@ -12,7 +12,10 @@ use crate::tag_utils::SwfSlice;
use gc_arena::{Collect, CollectionContext, Gc, GcCell, MutationContext};
use std::borrow::Cow;
use std::fmt;
use swf::{avm1::types::FunctionParam, SwfStr};
use swf::{
avm1::types::{FunctionFlags, FunctionParam},
SwfStr,
};
/// Represents a function defined in Ruffle's code.
///
@ -61,16 +64,6 @@ pub struct Avm1Function<'gc> {
/// set. Any register beyond this ID will be served from the global one.
register_count: u8,
preload_parent: bool,
preload_root: bool,
suppress_super: bool,
preload_super: bool,
suppress_arguments: bool,
preload_arguments: bool,
suppress_this: bool,
preload_this: bool,
preload_global: bool,
/// The names of the function parameters and their register mappings.
/// r0 indicates that no register shall be written and the parameter stored
/// as a Variable instead.
@ -85,6 +78,10 @@ pub struct Avm1Function<'gc> {
/// The base movie clip that the function was defined on.
/// This is the movie clip that contains the bytecode.
base_clip: DisplayObject<'gc>,
/// The flags that define the preloaded registers of the function.
#[collect(require_static)]
flags: FunctionFlags,
}
impl<'gc> Avm1Function<'gc> {
@ -112,15 +109,6 @@ impl<'gc> Avm1Function<'gc> {
data: actions,
name,
register_count: 0,
preload_parent: false,
preload_root: false,
suppress_super: false,
preload_super: false,
suppress_arguments: false,
preload_arguments: false,
suppress_this: false,
preload_this: false,
preload_global: false,
params: params
.iter()
.map(|&s| {
@ -133,6 +121,7 @@ impl<'gc> Avm1Function<'gc> {
scope,
constant_pool,
base_clip,
flags: FunctionFlags::empty(),
}
}
@ -172,19 +161,11 @@ impl<'gc> Avm1Function<'gc> {
data: actions,
name,
register_count: swf_function.register_count,
preload_parent: swf_function.preload_parent,
preload_root: swf_function.preload_root,
suppress_super: swf_function.suppress_super,
preload_super: swf_function.preload_super,
suppress_arguments: swf_function.suppress_arguments,
preload_arguments: swf_function.preload_arguments,
suppress_this: swf_function.suppress_this,
preload_this: swf_function.preload_this,
preload_global: swf_function.preload_global,
params: owned_params,
scope,
constant_pool,
base_clip,
flags: swf_function.flags,
}
}
@ -281,7 +262,7 @@ impl<'gc> Executable<'gc> {
Attribute::DONT_ENUM,
);
if !af.suppress_arguments {
if !af.flags.contains(FunctionFlags::SUPPRESS_ARGUMENTS) {
for i in 0..args.len() {
arguments.set_array_element(
i,
@ -292,18 +273,19 @@ impl<'gc> Executable<'gc> {
}
let argcell = arguments.into();
let super_object: Option<Object<'gc>> = if !af.suppress_super {
Some(
SuperObject::from_this_and_base_proto(
this,
base_proto.unwrap_or(this),
activation,
)?
.into(),
)
} else {
None
};
let super_object: Option<Object<'gc>> =
if !af.flags.contains(FunctionFlags::SUPPRESS_SUPER) {
Some(
SuperObject::from_this_and_base_proto(
this,
base_proto.unwrap_or(this),
activation,
)?
.into(),
)
} else {
None
};
let effective_ver = if activation.swf_version() > 5 {
af.swf_version()
@ -356,14 +338,14 @@ impl<'gc> Executable<'gc> {
let mut preload_r = 1;
if af.preload_this {
if af.flags.contains(FunctionFlags::PRELOAD_THIS) {
//TODO: What happens if you specify both suppress and
//preload for this?
frame.set_local_register(preload_r, this);
preload_r += 1;
}
if af.preload_arguments {
if af.flags.contains(FunctionFlags::PRELOAD_ARGUMENTS) {
//TODO: What happens if you specify both suppress and
//preload for arguments?
frame.set_local_register(preload_r, argcell);
@ -371,7 +353,7 @@ impl<'gc> Executable<'gc> {
}
if let Some(super_object) = super_object {
if af.preload_super {
if af.flags.contains(FunctionFlags::PRELOAD_SUPER) {
frame.set_local_register(preload_r, super_object);
//TODO: What happens if you specify both suppress and
//preload for super?
@ -381,7 +363,7 @@ impl<'gc> Executable<'gc> {
}
}
if af.preload_root {
if af.flags.contains(FunctionFlags::PRELOAD_ROOT) {
frame.set_local_register(
preload_r,
af.base_clip.avm1_root(&frame.context)?.object(),
@ -389,7 +371,7 @@ impl<'gc> Executable<'gc> {
preload_r += 1;
}
if af.preload_parent {
if af.flags.contains(FunctionFlags::PRELOAD_PARENT) {
// If _parent is undefined (because this is a root timeline), it actually does not get pushed,
// and _global ends up incorrectly taking _parent's register.
// See test for more info.
@ -399,7 +381,7 @@ impl<'gc> Executable<'gc> {
}
}
if af.preload_global {
if af.flags.contains(FunctionFlags::PRELOAD_GLOBAL) {
let global = frame.context.avm1.global_object();
frame.set_local_register(preload_r, global);
}

View File

@ -302,8 +302,8 @@ impl<'a> Reader<'a> {
fn read_define_function_2(&mut self, action_length: &mut usize) -> Result<Action<'a>> {
let name = self.read_str()?;
let num_params = self.read_u16()?;
let register_count = self.read_u8()?; // Number of registers
let flags = self.read_u16()?;
let register_count = self.read_u8()?;
let flags = FunctionFlags::from_bits_truncate(self.read_u16()?);
let mut params = Vec::with_capacity(num_params as usize);
for _ in 0..num_params {
let register = self.read_u8()?;
@ -319,15 +319,7 @@ impl<'a> Reader<'a> {
name,
params,
register_count,
preload_global: flags & 0b1_00000000 != 0,
preload_parent: flags & 0b10000000 != 0,
preload_root: flags & 0b1000000 != 0,
suppress_super: flags & 0b100000 != 0,
preload_super: flags & 0b10000 != 0,
suppress_arguments: flags & 0b1000 != 0,
preload_arguments: flags & 0b100 != 0,
suppress_this: flags & 0b10 != 0,
preload_this: flags & 0b1 != 0,
flags,
actions: self.read_slice(code_length)?,
}))
}

View File

@ -1,4 +1,5 @@
use crate::string::SwfStr;
use bitflags::bitflags;
#[derive(Clone, Debug, PartialEq)]
pub enum Action<'a> {
@ -157,15 +158,7 @@ pub struct Function<'a> {
pub name: &'a SwfStr,
pub register_count: u8,
pub params: Vec<FunctionParam<'a>>,
pub preload_parent: bool,
pub preload_root: bool,
pub suppress_super: bool,
pub preload_super: bool,
pub suppress_arguments: bool,
pub preload_arguments: bool,
pub suppress_this: bool,
pub preload_this: bool,
pub preload_global: bool,
pub flags: FunctionFlags,
pub actions: &'a [u8],
}
@ -175,6 +168,20 @@ pub struct FunctionParam<'a> {
pub register_index: Option<u8>,
}
bitflags! {
pub struct FunctionFlags: u16 {
const PRELOAD_THIS = 1 << 0;
const SUPPRESS_THIS = 1 << 1;
const PRELOAD_ARGUMENTS = 1 << 2;
const SUPPRESS_ARGUMENTS = 1 << 3;
const PRELOAD_SUPER = 1 << 4;
const SUPPRESS_SUPER = 1 << 5;
const PRELOAD_ROOT = 1 << 6;
const PRELOAD_PARENT = 1 << 7;
const PRELOAD_GLOBAL = 1 << 8;
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct TryBlock<'a> {
pub try_actions: &'a [u8],

View File

@ -144,26 +144,7 @@ impl<W: Write> Writer<W> {
self.write_string(function.name)?;
self.write_u16(function.params.len() as u16)?;
self.write_u8(function.register_count)?;
let flags = if function.preload_global {
0b1_00000000
} else {
0
} | if function.preload_parent {
0b10000000
} else {
0
} | if function.preload_root { 0b1000000 } else { 0 }
| if function.suppress_super { 0b100000 } else { 0 }
| if function.preload_super { 0b10000 } else { 0 }
| if function.suppress_arguments {
0b1000
} else {
0
}
| if function.preload_arguments { 0b100 } else { 0 }
| if function.suppress_this { 0b10 } else { 0 }
| if function.preload_this { 0b1 } else { 0 };
self.write_u16(flags)?;
self.write_u16(function.flags.bits())?;
for param in &function.params {
self.write_u8(if let Some(n) = param.register_index {
n