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