avm2: Make all domain object construction (save for the global domain) pull the constructor and call it in `from_domain`.

This also adds `DomainObject::script_global`, which does the same thing but picks the `global` class instead of `ApplicationDomain`.
This commit is contained in:
David Wendt 2021-05-31 17:32:27 -04:00
parent 6fe44c3862
commit 22fedf4dca
4 changed files with 56 additions and 60 deletions

View File

@ -79,31 +79,21 @@ pub fn application_domain<'gc>(
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
if let Some(this) = this { if let Some(this) = this {
if let Some(loader_stream) = this.as_loader_stream() { if let Some(loader_stream) = this.as_loader_stream() {
let appdomain_proto = activation.avm2().prototypes().application_domain;
let appdomain_constr = activation.avm2().constructors().application_domain;
match &*loader_stream { match &*loader_stream {
LoaderStream::Stage => { LoaderStream::Stage => {
return Ok(DomainObject::from_domain( return Ok(DomainObject::from_domain(
activation.context.gc_context, activation,
appdomain_constr,
Some(appdomain_proto),
activation.context.avm2.global_domain(), activation.context.avm2.global_domain(),
) )?
.into()); .into());
} }
LoaderStream::Swf(movie, _) => { LoaderStream::Swf(movie, _) => {
let library = activation let domain = activation
.context .context
.library .library
.library_for_movie_mut(movie.clone()); .library_for_movie_mut(movie.clone())
return Ok(DomainObject::from_domain( .avm2_domain();
activation.context.gc_context, return Ok(DomainObject::from_domain(activation, domain)?.into());
appdomain_constr,
Some(appdomain_proto),
library.avm2_domain(),
)
.into());
} }
} }
} }

View File

@ -39,17 +39,9 @@ pub fn current_domain<'gc>(
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
let globals = activation.scope().map(|s| s.read().globals()); let globals = activation.scope().map(|s| s.read().globals());
let appdomain = globals.and_then(|g| g.as_application_domain()); let appdomain = globals.and_then(|g| g.as_application_domain());
let appdomain_proto = activation.avm2().prototypes().application_domain;
let appdomain_constr = activation.avm2().constructors().application_domain;
if let Some(appdomain) = appdomain { if let Some(appdomain) = appdomain {
return Ok(DomainObject::from_domain( return Ok(DomainObject::from_domain(activation, appdomain)?.into());
activation.context.gc_context,
appdomain_constr,
Some(appdomain_proto),
appdomain,
)
.into());
} }
Ok(Value::Undefined) Ok(Value::Undefined)
@ -63,16 +55,7 @@ pub fn parent_domain<'gc>(
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
if let Some(appdomain) = this.and_then(|this| this.as_application_domain()) { if let Some(appdomain) = this.and_then(|this| this.as_application_domain()) {
if let Some(parent_domain) = appdomain.parent_domain() { if let Some(parent_domain) = appdomain.parent_domain() {
let appdomain_proto = activation.avm2().prototypes().application_domain; return Ok(DomainObject::from_domain(activation, parent_domain)?.into());
let appdomain_constr = activation.avm2().constructors().application_domain;
return Ok(DomainObject::from_domain(
activation.context.gc_context,
appdomain_constr,
Some(appdomain_proto),
parent_domain,
)
.into());
} }
} }

View File

@ -28,8 +28,13 @@ pub fn appdomain_deriver<'gc>(
.globals() .globals()
.as_application_domain() .as_application_domain()
.ok_or("Constructor scope must have an appdomain at the bottom of it's scope stack")?; .ok_or("Constructor scope must have an appdomain at the bottom of it's scope stack")?;
let base = ScriptObjectData::base_new(Some(proto), ScriptObjectClass::ClassInstance(constr));
DomainObject::derive(constr, proto, domain, activation.context.gc_context) Ok(DomainObject(GcCell::allocate(
activation.context.gc_context,
DomainObjectData { base, domain },
))
.into())
} }
#[derive(Clone, Collect, Debug, Copy)] #[derive(Clone, Collect, Debug, Copy)]
@ -58,28 +63,53 @@ impl<'gc> DomainObject<'gc> {
DomainObject(GcCell::allocate(mc, DomainObjectData { base, domain })).into() DomainObject(GcCell::allocate(mc, DomainObjectData { base, domain })).into()
} }
/// Create a new object for a given domain.
///
/// This function will call instance initializers. You do not need to do so
/// yourself.
pub fn from_domain( pub fn from_domain(
mc: MutationContext<'gc, '_>, activation: &mut Activation<'_, 'gc, '_>,
constr: Object<'gc>,
base_proto: Option<Object<'gc>>,
domain: Domain<'gc>, domain: Domain<'gc>,
) -> Object<'gc> { ) -> Result<Object<'gc>, Error> {
let base = ScriptObjectData::base_new(base_proto, ScriptObjectClass::ClassInstance(constr)); let constr = activation.avm2().constructors().application_domain;
let proto = activation.avm2().prototypes().application_domain;
let base =
ScriptObjectData::base_new(Some(proto), ScriptObjectClass::ClassInstance(constr));
let this = DomainObject(GcCell::allocate(
activation.context.gc_context,
DomainObjectData { base, domain },
))
.into();
DomainObject(GcCell::allocate(mc, DomainObjectData { base, domain })).into() constr.call_initializer(Some(this), &[], activation, Some(constr))?;
Ok(this)
} }
/// Construct a primitive subclass. /// Create a new object for a given script's global scope.
pub fn derive( ///
constr: Object<'gc>, /// The `domain` object will serve as the scope of last resort should the
base_proto: Object<'gc>, /// global scope not have a particular name defined.
///
/// This function will call instance initializers. You do not need to do so
/// yourself.
pub fn script_global(
activation: &mut Activation<'_, 'gc, '_>,
domain: Domain<'gc>, domain: Domain<'gc>,
mc: MutationContext<'gc, '_>,
) -> Result<Object<'gc>, Error> { ) -> Result<Object<'gc>, Error> {
let constr = activation.avm2().constructors().global;
let proto = activation.avm2().prototypes().global;
let base = let base =
ScriptObjectData::base_new(Some(base_proto), ScriptObjectClass::ClassInstance(constr)); ScriptObjectData::base_new(Some(proto), ScriptObjectClass::ClassInstance(constr));
let this = DomainObject(GcCell::allocate(
activation.context.gc_context,
DomainObjectData { base, domain },
))
.into();
Ok(DomainObject(GcCell::allocate(mc, DomainObjectData { base, domain })).into()) constr.call_initializer(Some(this), &[], activation, Some(constr))?;
Ok(this)
} }
} }
@ -107,11 +137,6 @@ impl<'gc> TObject<'gc> for DomainObject<'gc> {
)? )?
.coerce_to_object(activation)?; .coerce_to_object(activation)?;
Ok(DomainObject::from_domain( appdomain_deriver(constr, this, activation)
activation.context.gc_context,
constr,
Some(this),
activation.context.avm2.global_domain(),
))
} }
} }

View File

@ -146,11 +146,9 @@ impl<'gc> TranslationUnit<'gc> {
drop(read); drop(read);
let global_proto = uc.avm2.prototypes().global; let mut activation = Activation::from_nothing(uc.reborrow());
let global_constr = uc.avm2.constructors().global; let global = DomainObject::script_global(&mut activation, domain)?;
drop(activation);
let global =
DomainObject::from_domain(uc.gc_context, global_constr, Some(global_proto), domain);
let mut script = Script::from_abc_index(self, script_index, global, uc.gc_context)?; let mut script = Script::from_abc_index(self, script_index, global, uc.gc_context)?;
self.0 self.0