avm2: Make `NamespaceObject`'s sole associated method build and construct a `Namespace` instance.
This commit is contained in:
parent
b30c7509ba
commit
261cb40a22
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
},
|
||||
|
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue