avm2: Make `NamespaceObject`'s sole associated method build and construct a `Namespace` instance.

This commit is contained in:
David Wendt 2021-05-31 21:02:12 -04:00
parent b30c7509ba
commit 261cb40a22
7 changed files with 92 additions and 95 deletions

View File

@ -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<AbcClass>,
) -> Result<GcCell<'gc, Class<'gc>>, 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<AbcNamespace>,
) -> Result<FrameControl<'gc>, 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)
}

View File

@ -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<GcCell<'gc, Self>, 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,

View File

@ -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<Object<'gc>>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, 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
}

View File

@ -20,7 +20,16 @@ pub fn namespace_deriver<'gc>(
proto: Object<'gc>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Object<'gc>, 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<Object<'gc>, 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<Object<'gc>, 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)
}
}

View File

@ -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<GcCell<'gc, Class<'gc>>, 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);
}

View File

@ -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<Self, Error> {
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
},

View File

@ -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<f64>) -> R
pub fn abc_default_value<'gc>(
translation_unit: TranslationUnit<'gc>,
default: &AbcDefaultValue,
uc: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Value<'gc>, 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()),
}
}