avm1: Boxing a value calls the object constructor

This commit is contained in:
Mike Welsh 2020-01-19 14:10:04 -08:00
parent ccf62979a1
commit b49357e46f
3 changed files with 25 additions and 17 deletions

View File

@ -937,8 +937,8 @@ impl<'gc> Avm1<'gc> {
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let method_name = self.pop(); let method_name = self.pop();
let object = let object_val = self.pop();
value_object::ValueObject::boxed(context.gc_context, self.pop(), &self.prototypes); let object = value_object::ValueObject::boxed(self, context, object_val);
let num_args = self.pop().as_i64()?; // TODO(Herschel): max arg count? let num_args = self.pop().as_i64()?; // TODO(Herschel): max arg count?
let mut args = Vec::new(); let mut args = Vec::new();
for _ in 0..num_args { 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> { fn action_get_member(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) -> Result<(), Error> {
let name_val = self.pop(); let name_val = self.pop();
let name = name_val.coerce_to_string(self, context)?; let name = name_val.coerce_to_string(self, context)?;
let object = let object_val = self.pop();
value_object::ValueObject::boxed(context.gc_context, self.pop(), &self.prototypes); let object = value_object::ValueObject::boxed(self, context, object_val);
object.get(&name, self, context)?.push(self); object.get(&name, self, context)?.push(self);

View File

@ -19,7 +19,7 @@ pub(crate) mod movie_clip;
mod object; mod object;
mod sound; mod sound;
mod stage; mod stage;
mod string; pub(crate) mod string;
pub(crate) mod text_field; pub(crate) mod text_field;
mod xml; mod xml;

View File

@ -1,7 +1,6 @@
//! Object impl for boxed values //! Object impl for boxed values
use crate::avm1::function::Executable; use crate::avm1::function::Executable;
use crate::avm1::globals::SystemPrototypes;
use crate::avm1::object::{ObjectPtr, TObject}; use crate::avm1::object::{ObjectPtr, TObject};
use crate::avm1::property::Attribute; use crate::avm1::property::Attribute;
use crate::avm1::return_value::ReturnValue; 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 /// If a class exists for a given value type, this function automatically
/// selects the correct prototype for it from the system prototypes list. /// selects the correct prototype for it from the system prototypes list.
pub fn boxed( pub fn boxed(
gc_context: MutationContext<'gc, '_>, avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
value: Value<'gc>, value: Value<'gc>,
system_prototypes: &SystemPrototypes<'gc>,
) -> Object<'gc> { ) -> Object<'gc> {
if let Value::Object(ob) = value { if let Value::Object(ob) = value {
ob ob
} else { } else {
let proto = match value { let (constructor, proto) = match &value {
Value::String(_) => Some(system_prototypes.string), Value::String(_) => (
_ => None, Some(crate::avm1::globals::string::string),
Some(avm.prototypes.string),
),
_ => (None, None),
}; };
ValueObject(GcCell::allocate( let obj = ValueObject(GcCell::allocate(
gc_context, context.gc_context,
ValueObjectData { ValueObjectData {
base: ScriptObject::object(gc_context, proto), base: ScriptObject::object(context.gc_context, proto),
value, 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()
} }
} }