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> {
if let Some(this) = this {
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 {
LoaderStream::Stage => {
return Ok(DomainObject::from_domain(
activation.context.gc_context,
appdomain_constr,
Some(appdomain_proto),
activation,
activation.context.avm2.global_domain(),
)
)?
.into());
}
LoaderStream::Swf(movie, _) => {
let library = activation
let domain = activation
.context
.library
.library_for_movie_mut(movie.clone());
return Ok(DomainObject::from_domain(
activation.context.gc_context,
appdomain_constr,
Some(appdomain_proto),
library.avm2_domain(),
)
.into());
.library_for_movie_mut(movie.clone())
.avm2_domain();
return Ok(DomainObject::from_domain(activation, domain)?.into());
}
}
}

View File

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

View File

@ -28,8 +28,13 @@ pub fn appdomain_deriver<'gc>(
.globals()
.as_application_domain()
.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)]
@ -58,28 +63,53 @@ impl<'gc> DomainObject<'gc> {
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(
mc: MutationContext<'gc, '_>,
constr: Object<'gc>,
base_proto: Option<Object<'gc>>,
activation: &mut Activation<'_, 'gc, '_>,
domain: Domain<'gc>,
) -> Object<'gc> {
let base = ScriptObjectData::base_new(base_proto, ScriptObjectClass::ClassInstance(constr));
) -> Result<Object<'gc>, Error> {
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.
pub fn derive(
constr: Object<'gc>,
base_proto: Object<'gc>,
/// Create a new object for a given script's global scope.
///
/// The `domain` object will serve as the scope of last resort should the
/// 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>,
mc: MutationContext<'gc, '_>,
) -> Result<Object<'gc>, Error> {
let constr = activation.avm2().constructors().global;
let proto = activation.avm2().prototypes().global;
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)?;
Ok(DomainObject::from_domain(
activation.context.gc_context,
constr,
Some(this),
activation.context.avm2.global_domain(),
))
appdomain_deriver(constr, this, activation)
}
}

View File

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