avm1: Fix double-borrow when calling a getter that calls another method

This commit is contained in:
Nathan Adams 2020-07-01 18:53:16 +02:00
parent 987375299b
commit 9b66b496d0
2 changed files with 12 additions and 22 deletions

View File

@ -1,10 +1,8 @@
//! User-defined properties //! User-defined properties
use self::Attribute::*; use self::Attribute::*;
use crate::avm1::error::Error;
use crate::avm1::function::Executable; use crate::avm1::function::Executable;
use crate::avm1::stack_frame::StackFrame; use crate::avm1::Value;
use crate::avm1::{Object, UpdateContext, Value};
use core::fmt; use core::fmt;
use enumset::{EnumSet, EnumSetType}; use enumset::{EnumSet, EnumSetType};
@ -32,23 +30,6 @@ pub enum Property<'gc> {
} }
impl<'gc> Property<'gc> { impl<'gc> Property<'gc> {
/// Get the value of a property slot.
///
/// This function yields `ReturnValue` because some properties may be
/// user-defined.
pub fn get(
&self,
activation: &mut StackFrame<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
this: Object<'gc>,
base_proto: Option<Object<'gc>>,
) -> Result<Value<'gc>, Error<'gc>> {
match self {
Property::Virtual { get, .. } => get.exec(activation, context, this, base_proto, &[]),
Property::Stored { value, .. } => Ok(value.to_owned()),
}
}
/// Set a property slot. /// Set a property slot.
/// ///
/// This function may return an `Executable` of the property's virtual /// This function may return an `Executable` of the property's virtual

View File

@ -309,16 +309,25 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
return Ok(self.proto().map_or(Value::Undefined, Value::Object)); return Ok(self.proto().map_or(Value::Undefined, Value::Object));
} }
let mut exec = None;
if let Some(value) = self if let Some(value) = self
.0 .0
.read() .read()
.values .values
.get(name, activation.is_case_sensitive()) .get(name, activation.is_case_sensitive())
{ {
return value.get(activation, context, this, Some((*self).into())); match value {
Property::Virtual { get, .. } => exec = Some(get.to_owned()),
Property::Stored { value, .. } => return Ok(value.to_owned()),
}
} }
Ok(Value::Undefined) if let Some(get) = exec {
get.exec(activation, context, this, Some((*self).into()), &[])
} else {
Ok(Value::Undefined)
}
} }
/// Set a named property on the object. /// Set a named property on the object.