avm1: Cache ConstantPools for constant pools with more than 1000 entries
This commit is contained in:
parent
f5b4fbce77
commit
c66cfd4518
|
@ -12,7 +12,7 @@ use crate::display_object::{DisplayObject, MovieClip, TDisplayObject, TDisplayOb
|
|||
use crate::ecma_conversions::{f64_to_wrapping_i32, f64_to_wrapping_u32};
|
||||
use crate::loader::MovieLoaderVMData;
|
||||
use crate::string::{AvmString, SwfStrExt as _, WStr, WString};
|
||||
use crate::tag_utils::SwfSlice;
|
||||
use crate::tag_utils::{SwfPosition, SwfSlice};
|
||||
use crate::vminterface::Instantiator;
|
||||
use crate::{avm_error, avm_warn};
|
||||
use gc_arena::{Gc, GcCell, MutationContext};
|
||||
|
@ -25,6 +25,7 @@ use std::cmp::min;
|
|||
use std::fmt;
|
||||
use swf::avm1::read::Reader;
|
||||
use swf::avm1::types::*;
|
||||
use swf::extensions::ReadSwfExt;
|
||||
use url::form_urlencoded;
|
||||
|
||||
use super::object_reference::MovieClipReference;
|
||||
|
@ -480,7 +481,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
|||
Action::CastOp => self.action_cast_op(),
|
||||
Action::CharToAscii => self.action_char_to_ascii(),
|
||||
Action::CloneSprite => self.action_clone_sprite(),
|
||||
Action::ConstantPool(action) => self.action_constant_pool(action),
|
||||
Action::ConstantPool(action) => self.action_constant_pool(action, data, reader),
|
||||
Action::Decrement => self.action_decrement(),
|
||||
Action::DefineFunction(action) => self.action_define_function(action.into(), data),
|
||||
Action::DefineFunction2(action) => self.action_define_function(action, data),
|
||||
|
@ -863,21 +864,42 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
|||
fn action_constant_pool(
|
||||
&mut self,
|
||||
action: ConstantPool,
|
||||
data: &SwfSlice,
|
||||
reader: &mut Reader,
|
||||
) -> Result<FrameControl<'gc>, Error<'gc>> {
|
||||
let constants = action
|
||||
.strings
|
||||
.iter()
|
||||
.map(|s| {
|
||||
self.context
|
||||
.interner
|
||||
.intern_wstr(self.context.gc_context, s.decode(self.encoding()))
|
||||
.into()
|
||||
})
|
||||
.collect();
|
||||
let current_pos = reader.pos(data.movie.data());
|
||||
let swf_position = SwfPosition::new(data.movie.clone(), current_pos);
|
||||
|
||||
let const_pool_cache = self.context.avm1.constant_pool_cache();
|
||||
|
||||
let constants = if let Some(constants) = const_pool_cache.get(&swf_position) {
|
||||
*constants
|
||||
} else {
|
||||
let constants: Vec<_> = action
|
||||
.strings
|
||||
.iter()
|
||||
.map(|s| {
|
||||
self.context
|
||||
.interner
|
||||
.intern_wstr(self.context.gc_context, s.decode(self.encoding()))
|
||||
.into()
|
||||
})
|
||||
.collect();
|
||||
|
||||
let consts = Gc::new(self.context.gc_context, constants);
|
||||
|
||||
if consts.len() > 1000 {
|
||||
self.context
|
||||
.avm1
|
||||
.constant_pool_cache()
|
||||
.insert(swf_position, consts);
|
||||
}
|
||||
|
||||
consts
|
||||
};
|
||||
|
||||
self.context.avm1.set_constant_pool(constants);
|
||||
|
||||
self.context
|
||||
.avm1
|
||||
.set_constant_pool(Gc::new(self.context.gc_context, constants));
|
||||
self.set_constant_pool(self.context.avm1.constant_pool());
|
||||
|
||||
Ok(FrameControl::Continue)
|
||||
|
|
|
@ -10,10 +10,11 @@ use crate::context::{GcContext, UpdateContext};
|
|||
use crate::frame_lifecycle::FramePhase;
|
||||
use crate::prelude::*;
|
||||
use crate::string::AvmString;
|
||||
use crate::tag_utils::SwfSlice;
|
||||
use crate::tag_utils::{SwfPosition, SwfSlice};
|
||||
use crate::{avm1, avm_debug};
|
||||
use gc_arena::{Collect, Gc, MutationContext};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use swf::avm1::read::Reader;
|
||||
use tracing::instrument;
|
||||
|
||||
|
@ -27,6 +28,8 @@ pub struct Avm1<'gc> {
|
|||
/// don't close over the constant pool they were defined with.
|
||||
constant_pool: Gc<'gc, Vec<Value<'gc>>>,
|
||||
|
||||
constant_pool_cache: HashMap<SwfPosition, Gc<'gc, Vec<Value<'gc>>>>,
|
||||
|
||||
/// The global scope (pre-allocated so that it can be reused by fresh `Activation`s).
|
||||
global_scope: Gc<'gc, Scope<'gc>>,
|
||||
|
||||
|
@ -80,6 +83,7 @@ impl<'gc> Avm1<'gc> {
|
|||
Self {
|
||||
player_version,
|
||||
constant_pool: Gc::new(gc_context, vec![]),
|
||||
constant_pool_cache: HashMap::new(),
|
||||
global_scope: Gc::new(gc_context, Scope::from_global_object(globals)),
|
||||
prototypes,
|
||||
broadcaster_functions,
|
||||
|
@ -363,6 +367,10 @@ impl<'gc> Avm1<'gc> {
|
|||
self.constant_pool = constant_pool;
|
||||
}
|
||||
|
||||
pub fn constant_pool_cache(&mut self) -> &mut HashMap<SwfPosition, Gc<'gc, Vec<Value<'gc>>>> {
|
||||
&mut self.constant_pool_cache
|
||||
}
|
||||
|
||||
/// DisplayObject property map.
|
||||
pub fn display_properties(&self) -> &stage_object::DisplayPropertyMap<'gc> {
|
||||
&self.display_properties
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use gc_arena::Collect;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::sync::Arc;
|
||||
use swf::{CharacterId, Fixed8, HeaderExt, Rectangle, TagCode, Twips};
|
||||
use thiserror::Error;
|
||||
|
@ -409,6 +410,34 @@ impl SwfSlice {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Collect)]
|
||||
#[collect(no_drop)]
|
||||
pub struct SwfPosition {
|
||||
pub movie: Arc<SwfMovie>,
|
||||
pub pos: usize,
|
||||
}
|
||||
|
||||
impl SwfPosition {
|
||||
pub fn new(movie: Arc<SwfMovie>, pos: usize) -> Self {
|
||||
SwfPosition { movie, pos }
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for SwfPosition {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.movie, &other.movie) && self.pos == other.pos
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for SwfPosition {}
|
||||
|
||||
impl Hash for SwfPosition {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.pos.hash(state);
|
||||
Arc::as_ptr(&self.movie).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// Decode tags from a SWF stream reader.
|
||||
///
|
||||
/// The given `tag_callback` will be called for each decoded tag. It will be
|
||||
|
|
Loading…
Reference in New Issue