avm2: Remove unnecessary manual accesses of the `constructor` property on prototypes.

All native object allocation in the project now pulls prototypes or constructors as necessary from the following sources:

 * System prototype or constructor lists
 * Instance `constr`s

This also resulted in the removal of a few unnecessary prototype accesses.
This commit is contained in:
David Wendt 2021-05-28 19:11:44 -04:00
parent afd5a65a1e
commit 4bc1d37029
22 changed files with 105 additions and 348 deletions

View File

@ -156,16 +156,8 @@ impl<'gc> Avm2<'gc> {
) -> Result<bool, Error> {
use crate::avm2::events::dispatch_event;
let mut activation = Activation::from_nothing(context.reborrow());
let mut event_proto = activation.avm2().prototypes().event;
let event_constr = event_proto
.get_property(
event_proto,
&QName::new(Namespace::public(), "constructor"),
&mut activation,
)?
.coerce_to_object(&mut activation)?;
drop(activation);
let event_proto = context.avm2.prototypes().event;
let event_constr = context.avm2.constructors().event;
let event_object =
EventObject::from_event(context.gc_context, event_constr, Some(event_proto), event);

View File

@ -270,14 +270,8 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
unreachable!();
};
let mut array_proto = activation.avm2().prototypes().array;
let array_constr = array_proto
.get_property(
array_proto,
&QName::new(Namespace::public(), "constructor"),
&mut activation,
)?
.coerce_to_object(&mut activation)?;
let array_proto = activation.avm2().prototypes().array;
let array_constr = activation.avm2().constructors().array;
let mut args_object = ArrayObject::from_array(
args_array,
array_constr,
@ -813,14 +807,8 @@ 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 mut ns_proto = self.context.avm2.prototypes().namespace;
let ns_constr = ns_proto
.get_property(
ns_proto,
&QName::new(Namespace::public(), "constructor"),
self,
)?
.coerce_to_object(self)?;
let ns_proto = self.context.avm2.prototypes().namespace;
let ns_constr = self.context.avm2.constructors().namespace;
self.context.avm2.push(NamespaceObject::from_namespace(
ns,
@ -1587,14 +1575,8 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
fn op_new_array(&mut self, num_args: u32) -> Result<FrameControl<'gc>, Error> {
let args = self.context.avm2.pop_args(num_args);
let array = ArrayStorage::from_args(&args[..]);
let mut array_proto = self.context.avm2.prototypes().array;
let array_constr = array_proto
.get_property(
array_proto,
&QName::new(Namespace::public(), "constructor"),
self,
)?
.coerce_to_object(self)?;
let array_proto = self.context.avm2.prototypes().array;
let array_constr = self.context.avm2.constructors().array;
let array_obj =
ArrayObject::from_array(array, array_constr, array_proto, self.context.gc_context);

View File

@ -1,7 +1,7 @@
//! Application Domains
use crate::avm2::activation::Activation;
use crate::avm2::names::{Multiname, Namespace, QName};
use crate::avm2::names::{Multiname, QName};
use crate::avm2::object::{ByteArrayObject, TObject};
use crate::avm2::script::Script;
use crate::avm2::value::Value;
@ -196,14 +196,8 @@ impl<'gc> Domain<'gc> {
self,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
let mut bytearray_proto = activation.avm2().prototypes().bytearray;
let bytearray_constr = bytearray_proto
.get_property(
bytearray_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
let bytearray_proto = activation.avm2().prototypes().bytearray;
let bytearray_constr = activation.avm2().constructors().bytearray;
let domain_memory = ByteArrayObject::new(
activation.context.gc_context,

View File

@ -96,14 +96,8 @@ pub fn build_array<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
array: ArrayStorage<'gc>,
) -> Result<Value<'gc>, Error> {
let mut array_proto = activation.avm2().prototypes().array;
let array_constr = array_proto
.get_property(
array_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
let array_proto = activation.avm2().prototypes().array;
let array_constr = activation.avm2().constructors().array;
Ok(ArrayObject::from_array(
array,

View File

@ -20,17 +20,13 @@ pub fn instance_init<'gc>(
this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
if let Some(mut this) = this {
if let Some(this) = this {
activation.super_init(this, &[])?;
if this.as_display_object().is_none() {
let constructor = this
.get_property(
this,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
.as_constr()
.ok_or("Attempted to construct non-instance DisplayObject.")?;
if let Some((movie, symbol)) = activation
.context
@ -560,14 +556,8 @@ pub fn loader_info<'gc>(
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
if let Some(dobj) = this.and_then(|this| this.as_display_object()) {
let mut loaderinfo_proto = activation.avm2().prototypes().loaderinfo;
let loaderinfo_constr = loaderinfo_proto
.get_property(
loaderinfo_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
let loaderinfo_proto = activation.avm2().prototypes().loaderinfo;
let loaderinfo_constr = activation.avm2().constructors().loaderinfo;
if let Some(root) = dobj.avm2_root(&mut activation.context) {
if DisplayObject::ptr_eq(root, dobj) {

View File

@ -66,14 +66,8 @@ pub fn application_domain<'gc>(
) -> Result<Value<'gc>, Error> {
if let Some(this) = this {
if let Some(loader_stream) = this.as_loader_stream() {
let mut appdomain_proto = activation.avm2().prototypes().application_domain;
let appdomain_constr = appdomain_proto
.get_property(
appdomain_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
let appdomain_proto = activation.avm2().prototypes().application_domain;
let appdomain_constr = activation.avm2().constructors().application_domain;
match &*loader_stream {
LoaderStream::Stage => {
@ -301,14 +295,8 @@ pub fn bytes<'gc>(
return Err("Error: The stage's loader info does not have a bytestream".into())
}
LoaderStream::Swf(root, _) => {
let mut ba_proto = activation.context.avm2.prototypes().bytearray;
let ba_constr = ba_proto
.get_property(
ba_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
let ba_proto = activation.context.avm2.prototypes().bytearray;
let ba_constr = activation.context.avm2.constructors().bytearray;
let ba = ByteArrayObject::construct(
activation.context.gc_context,

View File

@ -24,12 +24,9 @@ pub fn instance_init<'gc>(
activation.super_init(this, &[])?;
if this.as_display_object().is_none() {
let mut proto = this
.proto()
.ok_or("Attempted to construct bare-object MovieClip")?;
let constr = proto
.get_property(proto, &QName::dynamic_name("constructor"), activation)?
.coerce_to_object(activation)?;
let constr = this
.as_constr()
.ok_or("Attempted to construct non-instance MovieClip")?;
let movie = Arc::new(SwfMovie::empty(activation.context.swf.version()));
let new_do = MovieClip::new_with_avm2(
SwfSlice::empty(movie),
@ -162,16 +159,9 @@ fn labels_for_scene<'gc>(
start: scene_start,
length: scene_length,
} = scene;
let mut frame_label_proto = activation.context.avm2.prototypes().framelabel;
let frame_label_constr = activation.context.avm2.constructors().framelabel;
let labels = mc.labels_in_range(*scene_start, scene_start + scene_length);
let mut frame_labels = Vec::with_capacity(labels.len());
let frame_label_constr = frame_label_proto
.get_property(
frame_label_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
for (name, frame) in labels {
let name: Value<'gc> = AvmString::new(activation.context.gc_context, name).into();
@ -182,14 +172,8 @@ fn labels_for_scene<'gc>(
frame_labels.push(Some(frame_label.into()));
}
let mut array_proto = activation.avm2().prototypes().array;
let array_constr = array_proto
.get_property(
array_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
let array_proto = activation.avm2().prototypes().array;
let array_constr = activation.avm2().constructors().array;
Ok((
scene_name.to_string(),
@ -240,14 +224,7 @@ pub fn current_scene<'gc>(
length: mc.total_frames(),
});
let (scene_name, scene_length, scene_labels) = labels_for_scene(activation, mc, &scene)?;
let mut scene_proto = activation.context.avm2.prototypes().scene;
let scene_constr = scene_proto
.get_property(
scene_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
let scene_constr = activation.context.avm2.constructors().scene;
let args = [
AvmString::new(activation.context.gc_context, scene_name).into(),
scene_labels.into(),
@ -285,14 +262,7 @@ pub fn scenes<'gc>(
for scene in mc_scenes {
let (scene_name, scene_length, scene_labels) =
labels_for_scene(activation, mc, &scene)?;
let mut scene_proto = activation.context.avm2.prototypes().scene;
let scene_constr = scene_proto
.get_property(
scene_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
let scene_constr = activation.context.avm2.constructors().scene;
let args = [
AvmString::new(activation.context.gc_context, scene_name).into(),
scene_labels.into(),
@ -304,14 +274,8 @@ pub fn scenes<'gc>(
scene_objects.push(Some(scene.into()));
}
let mut array_proto = activation.avm2().prototypes().array;
let array_constr = array_proto
.get_property(
array_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
let array_proto = activation.context.avm2.prototypes().array;
let array_constr = activation.context.avm2.constructors().array;
return Ok(ArrayObject::from_array(
ArrayStorage::from_storage(scene_objects),

View File

@ -62,15 +62,8 @@ pub fn graphics<'gc>(
activation,
)? {
Value::Undefined | Value::Null => {
let mut graphics_proto = activation.context.avm2.prototypes().graphics;
let graphics_constr = graphics_proto
.get_property(
graphics_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)
.and_then(|v| v.coerce_to_object(activation))
.expect("Video proto needs constr");
let graphics_proto = activation.context.avm2.prototypes().graphics;
let graphics_constr = activation.context.avm2.constructors().graphics;
let graphics = Value::from(StageObject::for_display_object(
activation.context.gc_context,

View File

@ -48,15 +48,8 @@ pub fn graphics<'gc>(
activation,
)? {
Value::Undefined | Value::Null => {
let mut graphics_proto = activation.context.avm2.prototypes().graphics;
let graphics_constr = graphics_proto
.get_property(
graphics_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)
.and_then(|v| v.coerce_to_object(activation))
.expect("Video proto needs constr");
let graphics_proto = activation.context.avm2.prototypes().graphics;
let graphics_constr = activation.context.avm2.constructors().graphics;
let graphics = Value::from(StageObject::for_display_object(
activation.context.gc_context,

View File

@ -142,14 +142,8 @@ pub fn clone<'gc>(
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
if let Some(evt) = this.unwrap().as_event() {
let mut evt_proto = activation.avm2().prototypes().event;
let evt_constr = evt_proto
.get_property(
evt_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
let evt_proto = activation.avm2().prototypes().event;
let evt_constr = activation.avm2().constructors().event;
return Ok(EventObject::from_event(
activation.context.gc_context,

View File

@ -10,14 +10,7 @@ fn create_point<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
coords: (f64, f64),
) -> Result<Value<'gc>, Error> {
let mut point_proto = activation.context.avm2.prototypes().point;
let point_constr = point_proto
.get_property(
point_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
let point_constr = activation.context.avm2.constructors().point;
let args = [Value::Number(coords.0), Value::Number(coords.1)];
let new_point = point_constr.construct(activation, &args)?;

View File

@ -39,14 +39,8 @@ 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 mut appdomain_proto = activation.avm2().prototypes().application_domain;
let appdomain_constr = appdomain_proto
.get_property(
appdomain_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
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(
@ -69,14 +63,8 @@ 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 mut appdomain_proto = activation.avm2().prototypes().application_domain;
let appdomain_constr = appdomain_proto
.get_property(
appdomain_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
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,

View File

@ -209,19 +209,13 @@ pub fn exec<'gc>(
None => return Ok(Value::Null),
};
let mut regexp_proto = activation.avm2().prototypes().array;
let regexp_constr = regexp_proto
.get_property(
regexp_proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
let array_proto = activation.avm2().prototypes().array;
let array_constr = activation.avm2().constructors().array;
let object = ArrayObject::from_array(
storage,
regexp_constr,
regexp_proto,
array_constr,
array_proto,
activation.context.gc_context,
);

View File

@ -4,7 +4,6 @@ use crate::avm2::activation::Activation;
use crate::avm2::class::Class;
use crate::avm2::domain::Domain;
use crate::avm2::method::{BytecodeMethod, Method};
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::{DomainObject, Object, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::string::AvmString;
@ -147,18 +146,8 @@ impl<'gc> TranslationUnit<'gc> {
drop(read);
let mut activation = Activation::from_nothing(uc.reborrow());
let mut global_proto = activation.context.avm2.prototypes().global;
let global_constr = global_proto
.get_property(
global_proto,
&QName::new(Namespace::public(), "constructor"),
&mut activation,
)?
.coerce_to_object(&mut activation)?;
drop(activation);
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);

View File

@ -205,18 +205,8 @@ pub fn abc_default_value<'gc>(
| AbcDefaultValue::Explicit(ns)
| AbcDefaultValue::StaticProtected(ns)
| AbcDefaultValue::Private(ns) => {
let mut activation = Activation::from_nothing(uc.reborrow());
let mut ns_proto = activation.avm2().prototypes().namespace;
let ns_constr = ns_proto
.get_property(
ns_proto,
&QName::new(Namespace::public(), "constructor"),
&mut activation,
)?
.coerce_to_object(&mut activation)?;
drop(activation);
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)?,
@ -579,7 +569,7 @@ impl<'gc> Value<'gc> {
_ => {}
};
let mut proto = match self {
let proto = match self {
Value::Bool(_) => activation.avm2().prototypes().boolean,
Value::Number(_) => activation.avm2().prototypes().number,
Value::Unsigned(_) => activation.avm2().prototypes().uint,
@ -587,13 +577,14 @@ impl<'gc> Value<'gc> {
Value::String(_) => activation.avm2().prototypes().string,
_ => unreachable!(),
};
let constr = proto
.get_property(
proto,
&QName::new(Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
let constr = match self {
Value::Bool(_) => activation.avm2().constructors().boolean,
Value::Number(_) => activation.avm2().constructors().number,
Value::Unsigned(_) => activation.avm2().constructors().uint,
Value::Integer(_) => activation.avm2().constructors().int,
Value::String(_) => activation.avm2().constructors().string,
_ => unreachable!(),
};
PrimitiveObject::from_primitive(self.clone(), constr, proto, activation.context.gc_context)
}

View File

@ -1,8 +1,5 @@
use crate::avm1::Object as Avm1Object;
use crate::avm2::{
Activation as Avm2Activation, Namespace as Avm2Namespace, Object as Avm2Object,
QName as Avm2QName, StageObject as Avm2StageObject, TObject as Avm2TObject, Value as Avm2Value,
};
use crate::avm2::{Object as Avm2Object, StageObject as Avm2StageObject, Value as Avm2Value};
use crate::backend::ui::MouseCursor;
use crate::context::{RenderContext, UpdateContext};
use crate::display_object::container::{dispatch_added_event, dispatch_removed_event};
@ -178,19 +175,7 @@ impl<'gc> Avm2Button<'gc> {
.movie()
.expect("All SWF-defined buttons should have movies");
let empty_slice = SwfSlice::empty(movie.clone());
let mut sprite_proto = context.avm2.prototypes().sprite;
let mut activation = Avm2Activation::from_nothing(context.reborrow());
let sprite_constr = sprite_proto
.get_property(
sprite_proto,
&Avm2QName::new(Avm2Namespace::public(), "constructor"),
&mut activation,
)
.unwrap()
.coerce_to_object(&mut activation)
.unwrap();
drop(activation);
let sprite_constr = context.avm2.constructors().sprite;
let mut children = Vec::new();
let static_data = self.0.read().static_data;
@ -441,17 +426,8 @@ impl<'gc> TDisplayObject<'gc> for Avm2Button<'gc> {
}
if self.0.read().object.is_none() {
let mut activation = Avm2Activation::from_nothing(context.reborrow());
let mut simplebutton_proto = activation.avm2().prototypes().simplebutton;
let simplebutton_constr = simplebutton_proto
.get_property(
simplebutton_proto,
&Avm2QName::new(Avm2Namespace::public(), "constructor"),
&mut activation,
)
.unwrap()
.coerce_to_object(&mut activation)
.unwrap();
let simplebutton_proto = context.avm2.prototypes().simplebutton;
let simplebutton_constr = context.avm2.constructors().simplebutton;
let object = Avm2StageObject::for_display_object(
context.gc_context,
(*self).into(),

View File

@ -6,8 +6,8 @@ use crate::avm1::{
Value as Avm1Value,
};
use crate::avm2::{
Activation as Avm2Activation, Namespace as Avm2Namespace, Object as Avm2Object,
QName as Avm2QName, StageObject as Avm2StageObject, TObject as Avm2TObject,
Activation as Avm2Activation, Object as Avm2Object, StageObject as Avm2StageObject,
TObject as Avm2TObject,
};
use crate::backend::ui::MouseCursor;
use crate::context::{RenderContext, UpdateContext};
@ -1509,25 +1509,19 @@ impl<'gc> EditText<'gc> {
context: &mut UpdateContext<'_, 'gc, '_>,
display_object: DisplayObject<'gc>,
) {
let mut textfield_proto = context.avm2.prototypes().textfield;
let mut activation = Avm2Activation::from_nothing(context.reborrow());
let textfield_constr = textfield_proto
.get_property(
textfield_proto,
&Avm2QName::new(Avm2Namespace::public(), "constructor"),
&mut activation,
)
.and_then(|v| v.coerce_to_object(&mut activation))
.expect("Textfield proto needs constr");
let textfield_proto = context.avm2.prototypes().textfield;
let textfield_constr = context.avm2.constructors().textfield;
let object: Avm2Object<'gc> = Avm2StageObject::for_display_object(
activation.context.gc_context,
context.gc_context,
display_object,
textfield_constr,
textfield_proto,
)
.into();
let mut activation = Avm2Activation::from_nothing(context.reborrow());
if let Err(e) =
textfield_constr.call(Some(object), &[], &mut activation, Some(textfield_constr))
{

View File

@ -1,8 +1,7 @@
use crate::avm1::Object as Avm1Object;
use crate::avm2::{
Activation as Avm2Activation, Error as Avm2Error, Namespace as Avm2Namespace,
Object as Avm2Object, QName as Avm2QName, StageObject as Avm2StageObject,
TObject as Avm2TObject,
Activation as Avm2Activation, Error as Avm2Error, Object as Avm2Object,
StageObject as Avm2StageObject, TObject as Avm2TObject,
};
use crate::backend::render::ShapeHandle;
use crate::context::{RenderContext, UpdateContext};
@ -117,23 +116,18 @@ impl<'gc> TDisplayObject<'gc> for Graphic<'gc> {
fn construct_frame(&self, context: &mut UpdateContext<'_, 'gc, '_>) {
if self.avm_type() == AvmType::Avm2 && matches!(self.object2(), Avm2Value::Undefined) {
let mut allocator = || {
let mut activation = Avm2Activation::from_nothing(context.reborrow());
let mut shape_proto = activation.context.avm2.prototypes().shape;
let shape_constr = shape_proto
.get_property(
shape_proto,
&Avm2QName::new(Avm2Namespace::public(), "constructor"),
&mut activation,
)?
.coerce_to_object(&mut activation)?;
let shape_proto = context.avm2.prototypes().shape;
let shape_constr = context.avm2.constructors().shape;
let object = Avm2StageObject::for_display_object(
activation.context.gc_context,
context.gc_context,
(*self).into(),
shape_constr,
shape_proto,
)
.into();
let mut activation = Avm2Activation::from_nothing(context.reborrow());
shape_constr.call(Some(object), &[], &mut activation, Some(shape_constr))?;
Ok(object)

View File

@ -1513,19 +1513,11 @@ impl<'gc> MovieClip<'gc> {
context: &mut UpdateContext<'_, 'gc, '_>,
display_object: DisplayObject<'gc>,
) {
let mut constructor = self.0.read().avm2_constructor.unwrap_or_else(|| {
let mut activation = Avm2Activation::from_nothing(context.reborrow());
let mut mc_proto = activation.context.avm2.prototypes().movieclip;
mc_proto
.get_property(
mc_proto,
&Avm2QName::new(Avm2Namespace::public(), "constructor"),
&mut activation,
)
.unwrap()
.coerce_to_object(&mut activation)
.unwrap()
});
let mut constructor = self
.0
.read()
.avm2_constructor
.unwrap_or_else(|| context.avm2.constructors().movieclip);
let mut constr_thing = || {
let mut activation = Avm2Activation::from_nothing(context.reborrow());
@ -1561,19 +1553,11 @@ impl<'gc> MovieClip<'gc> {
/// will allocate the object first before doing so. This function is
/// intended to be called from `post_instantiate`.
fn construct_as_avm2_object(self, context: &mut UpdateContext<'_, 'gc, '_>) {
let constructor = self.0.read().avm2_constructor.unwrap_or_else(|| {
let mut activation = Avm2Activation::from_nothing(context.reborrow());
let mut mc_proto = activation.context.avm2.prototypes().movieclip;
mc_proto
.get_property(
mc_proto,
&Avm2QName::new(Avm2Namespace::public(), "constructor"),
&mut activation,
)
.unwrap()
.coerce_to_object(&mut activation)
.unwrap()
});
let constructor = self
.0
.read()
.avm2_constructor
.unwrap_or_else(|| context.avm2.constructors().movieclip);
if let Avm2Value::Object(object) = self.object2() {
let mut constr_thing = || {

View File

@ -2,9 +2,9 @@
use crate::avm1::Object as Avm1Object;
use crate::avm2::{
Activation as Avm2Activation, Event as Avm2Event, Namespace as Avm2Namespace,
Object as Avm2Object, QName as Avm2QName, ScriptObject as Avm2ScriptObject,
StageObject as Avm2StageObject, TObject as Avm2TObject, Value as Avm2Value,
Activation as Avm2Activation, Event as Avm2Event, Object as Avm2Object,
ScriptObject as Avm2ScriptObject, StageObject as Avm2StageObject, TObject as Avm2TObject,
Value as Avm2Value,
};
use crate::backend::ui::UiBackend;
use crate::config::Letterbox;
@ -518,18 +518,10 @@ impl<'gc> TDisplayObject<'gc> for Stage<'gc> {
_instantiated_by: Instantiator,
_run_frame: bool,
) {
let mut stage_proto = context.avm2.prototypes().stage;
let mut activation = Avm2Activation::from_nothing(context.reborrow());
let stage_constr = stage_proto
.get_property(
stage_proto,
&Avm2QName::new(Avm2Namespace::public(), "constructor"),
&mut activation,
)
.and_then(|v| v.coerce_to_object(&mut activation))
.expect("Stage proto needs constr");
let stage_proto = context.avm2.prototypes().stage;
let stage_constr = context.avm2.constructors().stage;
let avm2_stage = Avm2StageObject::for_display_object(
activation.context.gc_context,
context.gc_context,
(*self).into(),
stage_constr,
stage_proto,
@ -538,6 +530,7 @@ impl<'gc> TDisplayObject<'gc> for Stage<'gc> {
// TODO: Replace this when we have a convenience method for constructing AVM2 native objects.
// TODO: We should only do this if the movie is actually an AVM2 movie.
// This is necessary for EventDispatcher super-constructor to run.
let mut activation = Avm2Activation::from_nothing(context.reborrow());
if let Err(e) = stage_constr.call(
Some(avm2_stage.into()),
&[],
@ -547,7 +540,7 @@ impl<'gc> TDisplayObject<'gc> for Stage<'gc> {
log::error!("Unable to construct AVM2 Stage: {}", e);
}
self.0.write(context.gc_context).avm2_object = avm2_stage.into();
self.0.write(activation.context.gc_context).avm2_object = avm2_stage.into();
}
fn id(&self) -> CharacterId {

View File

@ -1,10 +1,7 @@
//! Video player display object
use crate::avm1::{Object as Avm1Object, StageObject as Avm1StageObject};
use crate::avm2::{
Activation as Avm2Activation, Namespace as Avm2Namespace, Object as Avm2Object,
QName as Avm2QName, StageObject as Avm2StageObject, TObject as Avm2TObject,
};
use crate::avm2::{Object as Avm2Object, StageObject as Avm2StageObject};
use crate::backend::render::BitmapInfo;
use crate::backend::video::{EncodedFrame, VideoStreamHandle};
use crate::bounding_box::BoundingBox;
@ -384,25 +381,17 @@ impl<'gc> TDisplayObject<'gc> for Video<'gc> {
fn construct_frame(&self, context: &mut UpdateContext<'_, 'gc, '_>) {
let vm_type = self.avm_type();
if vm_type == AvmType::Avm2 && matches!(self.object2(), Avm2Value::Undefined) {
let mut video_proto = context.avm2.prototypes().video;
let mut activation = Avm2Activation::from_nothing(context.reborrow());
let video_constr = video_proto
.get_property(
video_proto,
&Avm2QName::new(Avm2Namespace::public(), "constructor"),
&mut activation,
)
.and_then(|v| v.coerce_to_object(&mut activation))
.expect("Video proto needs constr");
let video_proto = context.avm2.prototypes().video;
let video_constr = context.avm2.constructors().video;
let object: Avm2Object<'_> = Avm2StageObject::for_display_object(
activation.context.gc_context,
context.gc_context,
(*self).into(),
video_constr,
video_proto,
)
.into();
self.0.write(activation.context.gc_context).object = Some(object.into());
self.0.write(context.gc_context).object = Some(object.into());
}
}

View File

@ -698,14 +698,8 @@ impl TextFormat {
&self,
activation: &mut Avm2Activation<'_, 'gc, '_>,
) -> Result<Avm2Object<'gc>, Avm2Error> {
let mut proto = activation.context.avm2.prototypes().textformat;
let constr = proto
.get_property(
proto,
&Avm2QName::new(Avm2Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
let proto = activation.context.avm2.prototypes().textformat;
let constr = activation.context.avm2.constructors().textformat;
let mut object = Avm2ScriptObject::object(activation.context.gc_context, proto);
constr.call(Some(object), &[], activation, Some(constr))?;
@ -850,14 +844,8 @@ impl TextFormat {
if let Some(ts) = &self.tab_stops {
let tab_stop_storage = ts.iter().copied().collect();
let mut array_proto = activation.avm2().prototypes().array;
let array_constr = array_proto
.get_property(
array_proto,
&Avm2QName::new(Avm2Namespace::public(), "constructor"),
activation,
)?
.coerce_to_object(activation)?;
let array_proto = activation.avm2().prototypes().array;
let array_constr = activation.avm2().constructors().array;
let tab_stops = Avm2ArrayObject::from_array(
tab_stop_storage,