From b49357e46faff946031d18ea81dcbfa6bba50679 Mon Sep 17 00:00:00 2001 From: Mike Welsh Date: Sun, 19 Jan 2020 14:10:04 -0800 Subject: [PATCH] avm1: Boxing a value calls the object constructor --- core/src/avm1.rs | 8 ++++---- core/src/avm1/globals.rs | 2 +- core/src/avm1/value_object.rs | 32 ++++++++++++++++++++------------ 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/core/src/avm1.rs b/core/src/avm1.rs index 0c182b2a7..7bf346d97 100644 --- a/core/src/avm1.rs +++ b/core/src/avm1.rs @@ -937,8 +937,8 @@ impl<'gc> Avm1<'gc> { context: &mut UpdateContext<'_, 'gc, '_>, ) -> Result<(), Error> { let method_name = self.pop(); - let object = - value_object::ValueObject::boxed(context.gc_context, self.pop(), &self.prototypes); + let object_val = self.pop(); + let object = value_object::ValueObject::boxed(self, context, object_val); let num_args = self.pop().as_i64()?; // TODO(Herschel): max arg count? let mut args = Vec::new(); for _ in 0..num_args { @@ -1276,8 +1276,8 @@ impl<'gc> Avm1<'gc> { fn action_get_member(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) -> Result<(), Error> { let name_val = self.pop(); let name = name_val.coerce_to_string(self, context)?; - let object = - value_object::ValueObject::boxed(context.gc_context, self.pop(), &self.prototypes); + let object_val = self.pop(); + let object = value_object::ValueObject::boxed(self, context, object_val); object.get(&name, self, context)?.push(self); diff --git a/core/src/avm1/globals.rs b/core/src/avm1/globals.rs index cc9250301..851effba8 100644 --- a/core/src/avm1/globals.rs +++ b/core/src/avm1/globals.rs @@ -19,7 +19,7 @@ pub(crate) mod movie_clip; mod object; mod sound; mod stage; -mod string; +pub(crate) mod string; pub(crate) mod text_field; mod xml; diff --git a/core/src/avm1/value_object.rs b/core/src/avm1/value_object.rs index bf1198d5f..6ff3ac0c0 100644 --- a/core/src/avm1/value_object.rs +++ b/core/src/avm1/value_object.rs @@ -1,7 +1,6 @@ //! Object impl for boxed values use crate::avm1::function::Executable; -use crate::avm1::globals::SystemPrototypes; use crate::avm1::object::{ObjectPtr, TObject}; use crate::avm1::property::Attribute; use crate::avm1::return_value::ReturnValue; @@ -40,26 +39,35 @@ impl<'gc> ValueObject<'gc> { /// If a class exists for a given value type, this function automatically /// selects the correct prototype for it from the system prototypes list. pub fn boxed( - gc_context: MutationContext<'gc, '_>, + avm: &mut Avm1<'gc>, + context: &mut UpdateContext<'_, 'gc, '_>, value: Value<'gc>, - system_prototypes: &SystemPrototypes<'gc>, ) -> Object<'gc> { if let Value::Object(ob) = value { ob } else { - let proto = match value { - Value::String(_) => Some(system_prototypes.string), - _ => None, + let (constructor, proto) = match &value { + Value::String(_) => ( + Some(crate::avm1::globals::string::string), + Some(avm.prototypes.string), + ), + _ => (None, None), }; - ValueObject(GcCell::allocate( - gc_context, + let obj = ValueObject(GcCell::allocate( + context.gc_context, ValueObjectData { - base: ScriptObject::object(gc_context, proto), - value, + base: ScriptObject::object(context.gc_context, proto), + value: Value::Undefined, }, - )) - .into() + )); + + // Constructor populates the boxed object with the value. + if let Some(constructor) = constructor { + let _ = constructor(avm, context, obj.into(), &[value]); + } + + obj.into() } }