avm2: Store caller movie in Activation
This commit is contained in:
parent
cf9171cb78
commit
69cdb93d53
|
@ -10,9 +10,11 @@ use crate::avm2::script::{Script, TranslationUnit};
|
|||
use crate::context::{GcContext, UpdateContext};
|
||||
use crate::display_object::{DisplayObject, DisplayObjectWeak, TDisplayObject};
|
||||
use crate::string::AvmString;
|
||||
use crate::tag_utils::SwfMovie;
|
||||
|
||||
use fnv::FnvHashMap;
|
||||
use gc_arena::{Collect, GcCell, Mutation};
|
||||
use std::sync::Arc;
|
||||
use swf::avm2::read::Reader;
|
||||
use swf::DoAbc2Flag;
|
||||
|
||||
|
@ -479,6 +481,7 @@ impl<'gc> Avm2<'gc> {
|
|||
name: Option<AvmString<'gc>>,
|
||||
flags: DoAbc2Flag,
|
||||
domain: Domain<'gc>,
|
||||
movie: Arc<SwfMovie>,
|
||||
) -> Result<(), Error<'gc>> {
|
||||
let mut reader = Reader::new(data);
|
||||
let abc = match reader.read() {
|
||||
|
@ -494,7 +497,7 @@ impl<'gc> Avm2<'gc> {
|
|||
};
|
||||
|
||||
let num_scripts = abc.scripts.len();
|
||||
let tunit = TranslationUnit::from_abc(abc, domain, name, context.gc_context);
|
||||
let tunit = TranslationUnit::from_abc(abc, domain, name, movie, context.gc_context);
|
||||
for i in 0..num_scripts {
|
||||
tunit.load_script(i as u32, context)?;
|
||||
}
|
||||
|
|
|
@ -24,10 +24,12 @@ use crate::avm2::{value, Avm2, Error};
|
|||
use crate::context::{GcContext, UpdateContext};
|
||||
use crate::string::{AvmAtom, AvmString};
|
||||
use crate::swf::extensions::ReadSwfExt;
|
||||
use crate::tag_utils::SwfMovie;
|
||||
use gc_arena::{Gc, GcCell};
|
||||
use smallvec::SmallVec;
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::{min, Ordering};
|
||||
use std::sync::Arc;
|
||||
use swf::avm2::read::Reader;
|
||||
use swf::avm2::types::{
|
||||
Class as AbcClass, Exception, Index, Method as AbcMethod, MethodFlags as AbcMethodFlags,
|
||||
|
@ -100,6 +102,11 @@ pub struct Activation<'a, 'gc: 'a> {
|
|||
/// current domain instead.
|
||||
caller_domain: Option<Domain<'gc>>,
|
||||
|
||||
/// The movie that called this builtin method.
|
||||
/// This is intended to be used only for builtin methods- if this activation's method
|
||||
/// is a bytecode method, the movie will instead be the movie that the bytecode method came from.
|
||||
caller_movie: Option<Arc<SwfMovie>>,
|
||||
|
||||
/// The class that yielded the currently executing method.
|
||||
///
|
||||
/// This is used to maintain continuity when multiple methods supercall
|
||||
|
@ -161,6 +168,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
|||
local_registers,
|
||||
outer: ScopeChain::new(context.avm2.stage_domain),
|
||||
caller_domain: None,
|
||||
caller_movie: None,
|
||||
subclass_object: None,
|
||||
activation_class: None,
|
||||
stack_depth: context.avm2.stack.len(),
|
||||
|
@ -188,6 +196,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
|||
local_registers,
|
||||
outer: ScopeChain::new(context.avm2.stage_domain),
|
||||
caller_domain: Some(domain),
|
||||
caller_movie: None,
|
||||
subclass_object: None,
|
||||
activation_class: None,
|
||||
stack_depth: context.avm2.stack.len(),
|
||||
|
@ -228,6 +237,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
|||
local_registers,
|
||||
outer: ScopeChain::new(domain),
|
||||
caller_domain: Some(domain),
|
||||
caller_movie: None,
|
||||
subclass_object: None,
|
||||
activation_class: None,
|
||||
stack_depth: context.avm2.stack.len(),
|
||||
|
@ -421,6 +431,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
|||
local_registers,
|
||||
outer,
|
||||
caller_domain: Some(outer.domain()),
|
||||
caller_movie: Some(method.owner_movie()),
|
||||
subclass_object,
|
||||
activation_class,
|
||||
stack_depth: context.avm2.stack.len(),
|
||||
|
@ -496,6 +507,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
|||
subclass_object: Option<ClassObject<'gc>>,
|
||||
outer: ScopeChain<'gc>,
|
||||
caller_domain: Option<Domain<'gc>>,
|
||||
caller_movie: Option<Arc<SwfMovie>>,
|
||||
) -> Result<Self, Error<'gc>> {
|
||||
let local_registers = RegisterSet::new(0);
|
||||
|
||||
|
@ -504,6 +516,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
|||
local_registers,
|
||||
outer,
|
||||
caller_domain,
|
||||
caller_movie,
|
||||
subclass_object,
|
||||
activation_class: None,
|
||||
stack_depth: context.avm2.stack.len(),
|
||||
|
@ -574,6 +587,12 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
|||
self.caller_domain
|
||||
}
|
||||
|
||||
/// Returns the movie of the original AS3 caller. This will be `None`
|
||||
/// if this activation was constructed with `from_nothing`
|
||||
pub fn caller_movie(&self) -> Option<Arc<SwfMovie>> {
|
||||
self.caller_movie.clone()
|
||||
}
|
||||
|
||||
/// Returns the global scope of this activation.
|
||||
///
|
||||
/// The global scope refers to scope at the bottom of the
|
||||
|
|
|
@ -125,12 +125,14 @@ impl<'gc> Executable<'gc> {
|
|||
};
|
||||
|
||||
let caller_domain = activation.caller_domain();
|
||||
let caller_movie = activation.caller_movie();
|
||||
let subclass_object = bm.bound_superclass;
|
||||
let mut activation = Activation::from_builtin(
|
||||
activation.context.reborrow(),
|
||||
subclass_object,
|
||||
bm.scope,
|
||||
caller_domain,
|
||||
caller_movie,
|
||||
)?;
|
||||
|
||||
if arguments.len() > bm.method.signature.len() && !bm.method.is_variadic {
|
||||
|
|
|
@ -684,10 +684,12 @@ fn load_playerglobal<'gc>(
|
|||
activation.avm2().native_instance_init_table = native::NATIVE_INSTANCE_INIT_TABLE;
|
||||
activation.avm2().native_call_handler_table = native::NATIVE_CALL_HANDLER_TABLE;
|
||||
|
||||
let movie = SwfMovie::from_data(PLAYERGLOBAL, "file:///".into(), None)
|
||||
.expect("playerglobal.swf should be valid");
|
||||
let movie = Arc::new(
|
||||
SwfMovie::from_data(PLAYERGLOBAL, "file:///".into(), None)
|
||||
.expect("playerglobal.swf should be valid"),
|
||||
);
|
||||
|
||||
let slice = SwfSlice::from(Arc::new(movie));
|
||||
let slice = SwfSlice::from(movie.clone());
|
||||
|
||||
let mut reader = slice.read_from(0);
|
||||
|
||||
|
@ -702,6 +704,7 @@ fn load_playerglobal<'gc>(
|
|||
None,
|
||||
do_abc.flags,
|
||||
domain,
|
||||
movie.clone(),
|
||||
)
|
||||
.expect("playerglobal.swf should be valid");
|
||||
} else if tag_code != TagCode::End {
|
||||
|
|
|
@ -7,12 +7,14 @@ use crate::avm2::value::{abc_default_value, Value};
|
|||
use crate::avm2::Error;
|
||||
use crate::avm2::Multiname;
|
||||
use crate::string::AvmString;
|
||||
use crate::tag_utils::SwfMovie;
|
||||
use gc_arena::barrier::unlock;
|
||||
use gc_arena::lock::Lock;
|
||||
use gc_arena::{Collect, Gc, Mutation};
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use swf::avm2::types::{
|
||||
AbcFile, Index, Method as AbcMethod, MethodBody as AbcMethodBody,
|
||||
MethodFlags as AbcMethodFlags, MethodParam as AbcMethodParam,
|
||||
|
@ -198,6 +200,11 @@ impl<'gc> BytecodeMethod<'gc> {
|
|||
self.abc.methods.get(self.abc_method as usize).unwrap()
|
||||
}
|
||||
|
||||
/// Get a reference to the SwfMovie this method came from.
|
||||
pub fn owner_movie(&self) -> Arc<SwfMovie> {
|
||||
self.txunit.movie()
|
||||
}
|
||||
|
||||
/// Get a reference to the ABC method body entry this refers to.
|
||||
///
|
||||
/// Some methods do not have bodies; this returns `None` in that case.
|
||||
|
|
|
@ -14,10 +14,12 @@ use crate::avm2::Namespace;
|
|||
use crate::avm2::{Avm2, Error};
|
||||
use crate::context::{GcContext, UpdateContext};
|
||||
use crate::string::{AvmAtom, AvmString};
|
||||
use crate::tag_utils::SwfMovie;
|
||||
use gc_arena::{Collect, Gc, GcCell, Mutation};
|
||||
use std::cell::Ref;
|
||||
use std::mem::drop;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use swf::avm2::types::{
|
||||
AbcFile, Index, Method as AbcMethod, Multiname as AbcMultiname, Namespace as AbcNamespace,
|
||||
Script as AbcScript,
|
||||
|
@ -72,6 +74,9 @@ struct TranslationUnitData<'gc> {
|
|||
/// Note that some of these may have a runtime (lazy) component.
|
||||
/// Make sure to check for that before using them.
|
||||
multinames: Vec<Option<Gc<'gc, Multiname<'gc>>>>,
|
||||
|
||||
/// The movie that this TranslationUnit was loaded from.
|
||||
movie: Arc<SwfMovie>,
|
||||
}
|
||||
|
||||
impl<'gc> TranslationUnit<'gc> {
|
||||
|
@ -81,6 +86,7 @@ impl<'gc> TranslationUnit<'gc> {
|
|||
abc: AbcFile,
|
||||
domain: Domain<'gc>,
|
||||
name: Option<AvmString<'gc>>,
|
||||
movie: Arc<SwfMovie>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> Self {
|
||||
let classes = vec![None; abc.classes.len()];
|
||||
|
@ -102,6 +108,7 @@ impl<'gc> TranslationUnit<'gc> {
|
|||
strings,
|
||||
namespaces,
|
||||
multinames,
|
||||
movie,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
@ -120,6 +127,10 @@ impl<'gc> TranslationUnit<'gc> {
|
|||
self.0.read().abc.clone()
|
||||
}
|
||||
|
||||
pub fn movie(self) -> Arc<SwfMovie> {
|
||||
self.0.read().movie.clone()
|
||||
}
|
||||
|
||||
/// Load a method from the ABC file and return its method definition.
|
||||
pub fn load_method(
|
||||
self,
|
||||
|
|
|
@ -802,6 +802,7 @@ impl<'gc> MovieClip<'gc> {
|
|||
None,
|
||||
swf::DoAbc2Flag::LAZY_INITIALIZE,
|
||||
domain,
|
||||
self.movie(),
|
||||
) {
|
||||
tracing::warn!("Error loading ABC file: {e:?}");
|
||||
}
|
||||
|
@ -827,7 +828,14 @@ impl<'gc> MovieClip<'gc> {
|
|||
let domain = context.library.library_for_movie_mut(movie).avm2_domain();
|
||||
let name = AvmString::new(context.gc_context, do_abc.name.decode(reader.encoding()));
|
||||
|
||||
if let Err(e) = Avm2::do_abc(context, do_abc.data, Some(name), do_abc.flags, domain) {
|
||||
if let Err(e) = Avm2::do_abc(
|
||||
context,
|
||||
do_abc.data,
|
||||
Some(name),
|
||||
do_abc.flags,
|
||||
domain,
|
||||
self.movie(),
|
||||
) {
|
||||
tracing::warn!("Error loading ABC file: {e:?}");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue