diff --git a/core/src/avm2.rs b/core/src/avm2.rs index 1ecb6bdc1..19bec075a 100644 --- a/core/src/avm2.rs +++ b/core/src/avm2.rs @@ -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>, flags: DoAbc2Flag, domain: Domain<'gc>, + movie: Arc, ) -> 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)?; } diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index 9564c3d6c..e610f6d5b 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -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>, + /// 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>, + /// 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>, outer: ScopeChain<'gc>, caller_domain: Option>, + caller_movie: Option>, ) -> Result> { 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> { + self.caller_movie.clone() + } + /// Returns the global scope of this activation. /// /// The global scope refers to scope at the bottom of the diff --git a/core/src/avm2/function.rs b/core/src/avm2/function.rs index 48b09a19c..126c7776c 100644 --- a/core/src/avm2/function.rs +++ b/core/src/avm2/function.rs @@ -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 { diff --git a/core/src/avm2/globals.rs b/core/src/avm2/globals.rs index a1a629334..aefc7f1ed 100644 --- a/core/src/avm2/globals.rs +++ b/core/src/avm2/globals.rs @@ -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 { diff --git a/core/src/avm2/method.rs b/core/src/avm2/method.rs index 360952565..e674b9307 100644 --- a/core/src/avm2/method.rs +++ b/core/src/avm2/method.rs @@ -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 { + 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. diff --git a/core/src/avm2/script.rs b/core/src/avm2/script.rs index ba8ee9fbc..c0eaffd2a 100644 --- a/core/src/avm2/script.rs +++ b/core/src/avm2/script.rs @@ -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>>>, + + /// The movie that this TranslationUnit was loaded from. + movie: Arc, } impl<'gc> TranslationUnit<'gc> { @@ -81,6 +86,7 @@ impl<'gc> TranslationUnit<'gc> { abc: AbcFile, domain: Domain<'gc>, name: Option>, + movie: Arc, 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 { + self.0.read().movie.clone() + } + /// Load a method from the ABC file and return its method definition. pub fn load_method( self, diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index 9a1577d65..f6167a563 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -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:?}"); } }