From 261cb40a225961c4ef916e6c88ab7fe39fc8f5fd Mon Sep 17 00:00:00 2001 From: David Wendt Date: Mon, 31 May 2021 21:02:12 -0400 Subject: [PATCH] avm2: Make `NamespaceObject`'s sole associated method build and construct a `Namespace` instance. --- core/src/avm2/activation.rs | 18 +++------- core/src/avm2/class.rs | 20 ++++++----- core/src/avm2/globals/namespace.rs | 14 ++++++++ core/src/avm2/object/namespace_object.rs | 44 ++++++++++-------------- core/src/avm2/script.rs | 32 +++++++++-------- core/src/avm2/traits.rs | 33 +++++++----------- core/src/avm2/value.rs | 26 ++++++-------- 7 files changed, 92 insertions(+), 95 deletions(-) diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index b230495eb..549a635d3 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -230,9 +230,9 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { let activation_constr = if method.method().needs_activation { let translation_unit = method.translation_unit(); let abc_method = method.method(); - let activation_class = - Class::from_method_body(&mut context, translation_unit, abc_method, body)?; let mut dummy_activation = Activation::from_nothing(context.reborrow()); + let activation_class = + Class::from_method_body(&mut dummy_activation, translation_unit, abc_method, body)?; let constr = ClassObject::from_class(&mut dummy_activation, activation_class, None, scope)?; @@ -523,9 +523,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { method: Gc<'gc, BytecodeMethod<'gc>>, index: Index, ) -> Result>, Error> { - method - .translation_unit() - .load_class(index.0, &mut self.context) + method.translation_unit().load_class(index.0, self) } pub fn run_actions( @@ -800,15 +798,9 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { value: Index, ) -> Result, Error> { let ns = self.pool_namespace(method, value, self.context.gc_context)?; - let ns_proto = self.context.avm2.prototypes().namespace; - let ns_constr = self.context.avm2.constructors().namespace; + let ns_object = NamespaceObject::from_namespace(self, ns)?; - self.context.avm2.push(NamespaceObject::from_namespace( - ns, - ns_constr, - ns_proto, - self.context.gc_context, - )?); + self.context.avm2.push(ns_object); Ok(FrameControl::Continue) } diff --git a/core/src/avm2/class.rs b/core/src/avm2/class.rs index f8363a706..b738f30d1 100644 --- a/core/src/avm2/class.rs +++ b/core/src/avm2/class.rs @@ -9,7 +9,6 @@ use crate::avm2::string::AvmString; use crate::avm2::traits::{Trait, TraitKind}; use crate::avm2::value::Value; use crate::avm2::Error; -use crate::context::UpdateContext; use bitflags::bitflags; use gc_arena::{Collect, GcCell, MutationContext}; use std::fmt; @@ -369,7 +368,7 @@ impl<'gc> Class<'gc> { &mut self, unit: TranslationUnit<'gc>, class_index: u32, - uc: &mut UpdateContext<'_, 'gc, '_>, + activation: &mut Activation<'_, 'gc, '_>, ) -> Result<(), Error> { if self.traits_loaded { return Ok(()); @@ -392,32 +391,37 @@ impl<'gc> Class<'gc> { for abc_trait in abc_instance.traits.iter() { self.instance_traits - .push(Trait::from_abc_trait(unit, abc_trait, uc)?); + .push(Trait::from_abc_trait(unit, abc_trait, activation)?); } for abc_trait in abc_class.traits.iter() { self.class_traits - .push(Trait::from_abc_trait(unit, abc_trait, uc)?); + .push(Trait::from_abc_trait(unit, abc_trait, activation)?); } Ok(()) } pub fn from_method_body( - uc: &mut UpdateContext<'_, 'gc, '_>, + activation: &mut Activation<'_, 'gc, '_>, translation_unit: TranslationUnit<'gc>, method: &AbcMethod, body: &AbcMethodBody, ) -> Result, Error> { - let name = translation_unit.pool_string(method.name.as_u30(), uc.gc_context)?; + let name = + translation_unit.pool_string(method.name.as_u30(), activation.context.gc_context)?; let mut traits = Vec::with_capacity(body.traits.len()); for trait_entry in body.traits.iter() { - traits.push(Trait::from_abc_trait(translation_unit, trait_entry, uc)?); + traits.push(Trait::from_abc_trait( + translation_unit, + trait_entry, + activation, + )?); } Ok(GcCell::allocate( - uc.gc_context, + activation.context.gc_context, Self { name: QName::dynamic_name(name), super_class: None, diff --git a/core/src/avm2/globals/namespace.rs b/core/src/avm2/globals/namespace.rs index 73d2132b4..816623908 100644 --- a/core/src/avm2/globals/namespace.rs +++ b/core/src/avm2/globals/namespace.rs @@ -18,6 +18,19 @@ pub fn instance_init<'gc>( Err("Namespace constructor is a stub.".into()) } +/// Implements `Namespace`'s native instance initializer. +pub fn native_instance_init<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Option>, + args: &[Value<'gc>], +) -> Result, Error> { + if let Some(this) = this { + activation.super_init(this, args)?; + } + + Ok(Value::Undefined) +} + /// Implements `Namespace`'s class initializer. pub fn class_init<'gc>( _activation: &mut Activation<'_, 'gc, '_>, @@ -39,6 +52,7 @@ pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc> let mut write = class.write(mc); write.set_instance_deriver(namespace_deriver); + write.set_native_instance_init(Method::from_builtin(native_instance_init)); class } diff --git a/core/src/avm2/object/namespace_object.rs b/core/src/avm2/object/namespace_object.rs index d70118673..958b14523 100644 --- a/core/src/avm2/object/namespace_object.rs +++ b/core/src/avm2/object/namespace_object.rs @@ -20,7 +20,16 @@ pub fn namespace_deriver<'gc>( proto: Object<'gc>, activation: &mut Activation<'_, 'gc, '_>, ) -> Result, Error> { - NamespaceObject::derive(constr, proto, activation.context.gc_context) + let base = ScriptObjectData::base_new(Some(proto), ScriptObjectClass::ClassInstance(constr)); + + Ok(NamespaceObject(GcCell::allocate( + activation.context.gc_context, + NamespaceObjectData { + base, + namespace: Namespace::public(), + }, + )) + .into()) } /// An Object which represents a boxed namespace name. @@ -41,38 +50,23 @@ pub struct NamespaceObjectData<'gc> { impl<'gc> NamespaceObject<'gc> { /// Box a namespace into an object. pub fn from_namespace( + activation: &mut Activation<'_, 'gc, '_>, namespace: Namespace<'gc>, - constr: Object<'gc>, - base_proto: Object<'gc>, - mc: MutationContext<'gc, '_>, ) -> Result, Error> { + let constr = activation.avm2().constructors().namespace; + let proto = activation.avm2().prototypes().namespace; let base = - ScriptObjectData::base_new(Some(base_proto), ScriptObjectClass::ClassInstance(constr)); + ScriptObjectData::base_new(Some(proto), ScriptObjectClass::ClassInstance(constr)); - Ok(NamespaceObject(GcCell::allocate( - mc, + let this = NamespaceObject(GcCell::allocate( + activation.context.gc_context, NamespaceObjectData { base, namespace }, )) - .into()) - } + .into(); - /// Construct a namespace subclass. - pub fn derive( - constr: Object<'gc>, - base_proto: Object<'gc>, - mc: MutationContext<'gc, '_>, - ) -> Result, Error> { - let base = - ScriptObjectData::base_new(Some(base_proto), ScriptObjectClass::ClassInstance(constr)); + constr.call_native_initializer(Some(this), &[], activation, Some(constr))?; - Ok(NamespaceObject(GcCell::allocate( - mc, - NamespaceObjectData { - base, - namespace: Namespace::public(), - }, - )) - .into()) + Ok(this) } } diff --git a/core/src/avm2/script.rs b/core/src/avm2/script.rs index 9525ffdea..b7feef1da 100644 --- a/core/src/avm2/script.rs +++ b/core/src/avm2/script.rs @@ -109,7 +109,7 @@ impl<'gc> TranslationUnit<'gc> { pub fn load_class( self, class_index: u32, - uc: &mut UpdateContext<'_, 'gc, '_>, + activation: &mut Activation<'_, 'gc, '_>, ) -> Result>, Error> { let read = self.0.read(); if let Some(class) = read.classes.get(&class_index) { @@ -118,15 +118,15 @@ impl<'gc> TranslationUnit<'gc> { drop(read); - let class = Class::from_abc_index(self, class_index, uc.gc_context)?; + let class = Class::from_abc_index(self, class_index, activation.context.gc_context)?; self.0 - .write(uc.gc_context) + .write(activation.context.gc_context) .classes .insert(class_index, class); class - .write(uc.gc_context) - .load_traits(self, class_index, uc)?; + .write(activation.context.gc_context) + .load_traits(self, class_index, activation)?; Ok(class) } @@ -148,18 +148,22 @@ impl<'gc> TranslationUnit<'gc> { 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)?; + let mut script = + Script::from_abc_index(self, script_index, global, activation.context.gc_context)?; self.0 - .write(uc.gc_context) + .write(activation.context.gc_context) .scripts .insert(script_index, script); - script.load_traits(self, script_index, uc)?; + script.load_traits(self, script_index, &mut activation)?; for traitdef in script.traits()?.iter() { - domain.export_definition(traitdef.name().clone(), script, uc.gc_context)?; + domain.export_definition( + traitdef.name().clone(), + script, + activation.context.gc_context, + )?; } Ok(script) @@ -310,9 +314,9 @@ impl<'gc> Script<'gc> { &mut self, unit: TranslationUnit<'gc>, script_index: u32, - uc: &mut UpdateContext<'_, 'gc, '_>, + activation: &mut Activation<'_, 'gc, '_>, ) -> Result<(), Error> { - let mut write = self.0.write(uc.gc_context); + let mut write = self.0.write(activation.context.gc_context); if write.traits_loaded { return Ok(()); @@ -330,9 +334,9 @@ impl<'gc> Script<'gc> { for abc_trait in script.traits.iter() { drop(write); - let newtrait = Trait::from_abc_trait(unit, abc_trait, uc)?; + let newtrait = Trait::from_abc_trait(unit, abc_trait, activation)?; - write = self.0.write(uc.gc_context); + write = self.0.write(activation.context.gc_context); write.traits.push(newtrait); } diff --git a/core/src/avm2/traits.rs b/core/src/avm2/traits.rs index 6b5f3f33d..b23f7658d 100644 --- a/core/src/avm2/traits.rs +++ b/core/src/avm2/traits.rs @@ -1,12 +1,12 @@ //! Active trait definitions +use crate::avm2::activation::Activation; use crate::avm2::class::Class; use crate::avm2::method::Method; use crate::avm2::names::{Multiname, QName}; use crate::avm2::script::TranslationUnit; use crate::avm2::value::{abc_default_value, Value}; use crate::avm2::Error; -use crate::context::UpdateContext; use bitflags::bitflags; use gc_arena::{Collect, GcCell}; use swf::avm2::types::{Trait as AbcTrait, TraitKind as AbcTraitKind}; @@ -180,9 +180,10 @@ impl<'gc> Trait<'gc> { pub fn from_abc_trait( unit: TranslationUnit<'gc>, abc_trait: &AbcTrait, - uc: &mut UpdateContext<'_, 'gc, '_>, + activation: &mut Activation<'_, 'gc, '_>, ) -> Result { - let name = QName::from_abc_multiname(unit, abc_trait.name.clone(), uc.gc_context)?; + let mc = activation.context.gc_context; + let name = QName::from_abc_multiname(unit, abc_trait.name.clone(), mc)?; Ok(match &abc_trait.kind { AbcTraitKind::Slot { @@ -197,14 +198,10 @@ impl<'gc> Trait<'gc> { type_name: if type_name.0 == 0 { Multiname::any() } else { - Multiname::from_abc_multiname_static( - unit, - type_name.clone(), - uc.gc_context, - )? + Multiname::from_abc_multiname_static(unit, type_name.clone(), mc)? }, default_value: if let Some(dv) = value { - Some(abc_default_value(unit, dv, uc)?) + Some(abc_default_value(unit, dv, activation)?) } else { None }, @@ -215,7 +212,7 @@ impl<'gc> Trait<'gc> { attributes: trait_attribs_from_abc_traits(abc_trait), kind: TraitKind::Method { disp_id: *disp_id, - method: unit.load_method(method.0, uc.gc_context)?, + method: unit.load_method(method.0, mc)?, }, }, AbcTraitKind::Getter { disp_id, method } => Trait { @@ -223,7 +220,7 @@ impl<'gc> Trait<'gc> { attributes: trait_attribs_from_abc_traits(abc_trait), kind: TraitKind::Getter { disp_id: *disp_id, - method: unit.load_method(method.0, uc.gc_context)?, + method: unit.load_method(method.0, mc)?, }, }, AbcTraitKind::Setter { disp_id, method } => Trait { @@ -231,7 +228,7 @@ impl<'gc> Trait<'gc> { attributes: trait_attribs_from_abc_traits(abc_trait), kind: TraitKind::Setter { disp_id: *disp_id, - method: unit.load_method(method.0, uc.gc_context)?, + method: unit.load_method(method.0, mc)?, }, }, AbcTraitKind::Class { slot_id, class } => Trait { @@ -239,7 +236,7 @@ impl<'gc> Trait<'gc> { attributes: trait_attribs_from_abc_traits(abc_trait), kind: TraitKind::Class { slot_id: *slot_id, - class: unit.load_class(class.0, uc)?, + class: unit.load_class(class.0, activation)?, }, }, AbcTraitKind::Function { slot_id, function } => Trait { @@ -247,7 +244,7 @@ impl<'gc> Trait<'gc> { attributes: trait_attribs_from_abc_traits(abc_trait), kind: TraitKind::Function { slot_id: *slot_id, - function: unit.load_method(function.0, uc.gc_context)?, + function: unit.load_method(function.0, mc)?, }, }, AbcTraitKind::Const { @@ -262,14 +259,10 @@ impl<'gc> Trait<'gc> { type_name: if type_name.0 == 0 { Multiname::any() } else { - Multiname::from_abc_multiname_static( - unit, - type_name.clone(), - uc.gc_context, - )? + Multiname::from_abc_multiname_static(unit, type_name.clone(), mc)? }, default_value: if let Some(dv) = value { - Some(abc_default_value(unit, dv, uc)?) + Some(abc_default_value(unit, dv, activation)?) } else { None }, diff --git a/core/src/avm2/value.rs b/core/src/avm2/value.rs index 4f5bb05c2..eb62c8861 100644 --- a/core/src/avm2/value.rs +++ b/core/src/avm2/value.rs @@ -7,7 +7,6 @@ use crate::avm2::object::{NamespaceObject, Object, PrimitiveObject, TObject}; use crate::avm2::script::TranslationUnit; use crate::avm2::string::AvmString; use crate::avm2::Error; -use crate::context::UpdateContext; use crate::ecma_conversions::{f64_to_wrapping_i32, f64_to_wrapping_u32}; use gc_arena::{Collect, MutationContext}; use std::cell::Ref; @@ -185,14 +184,14 @@ pub fn abc_double(translation_unit: TranslationUnit<'_>, index: Index) -> R pub fn abc_default_value<'gc>( translation_unit: TranslationUnit<'gc>, default: &AbcDefaultValue, - uc: &mut UpdateContext<'_, 'gc, '_>, + activation: &mut Activation<'_, 'gc, '_>, ) -> Result, Error> { match default { AbcDefaultValue::Int(i) => abc_int(translation_unit, *i).map(|v| v.into()), AbcDefaultValue::Uint(u) => abc_uint(translation_unit, *u).map(|v| v.into()), AbcDefaultValue::Double(d) => abc_double(translation_unit, *d).map(|v| v.into()), AbcDefaultValue::String(s) => translation_unit - .pool_string(s.0, uc.gc_context) + .pool_string(s.0, activation.context.gc_context) .map(|v| v.into()), AbcDefaultValue::True => Ok(true.into()), AbcDefaultValue::False => Ok(false.into()), @@ -204,18 +203,15 @@ pub fn abc_default_value<'gc>( | AbcDefaultValue::Protected(ns) | AbcDefaultValue::Explicit(ns) | AbcDefaultValue::StaticProtected(ns) - | AbcDefaultValue::Private(ns) => { - let ns_proto = uc.avm2.prototypes().namespace; - let ns_constr = uc.avm2.constructors().namespace; - - Ok(NamespaceObject::from_namespace( - Namespace::from_abc_namespace(translation_unit, ns.clone(), uc.gc_context)?, - ns_constr, - ns_proto, - uc.gc_context, - )? - .into()) - } + | AbcDefaultValue::Private(ns) => Ok(NamespaceObject::from_namespace( + activation, + Namespace::from_abc_namespace( + translation_unit, + ns.clone(), + activation.context.gc_context, + )?, + )? + .into()), } }