Remove uses of `as_string` in various places.

These include:

 * Name resolution in `newobject`
 * All runtime & late-bound multinames
 * `Object.hasOwnProperty`
 * `Object.propertyIsEnumerable`
 * `Object.setPropertyIsEnumerable`
This commit is contained in:
David Wendt 2020-07-28 21:31:58 -04:00 committed by Mike Welsh
parent c040997be2
commit 4906c5a3f1
4 changed files with 46 additions and 47 deletions

View File

@ -343,9 +343,8 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
&mut self, &mut self,
method: Gc<'gc, BytecodeMethod<'gc>>, method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<AbcMultiname>, index: Index<AbcMultiname>,
mc: MutationContext<'gc, '_>,
) -> Result<Multiname<'gc>, Error> { ) -> Result<Multiname<'gc>, Error> {
Multiname::from_abc_multiname(method.translation_unit(), index, self.context.avm2, mc) Multiname::from_abc_multiname(method.translation_unit(), index, self)
} }
/// Retrieve a static, or non-runtime, multiname from the current constant /// Retrieve a static, or non-runtime, multiname from the current constant
@ -706,7 +705,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
arg_count: u32, arg_count: u32,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let args = self.context.avm2.pop_args(arg_count); let args = self.context.avm2.pop_args(arg_count);
let multiname = self.pool_multiname(method, index, self.context.gc_context)?; let multiname = self.pool_multiname(method, index)?;
let mut receiver = self.context.avm2.pop().coerce_to_object(self)?; let mut receiver = self.context.avm2.pop().coerce_to_object(self)?;
let name: Result<QName, Error> = receiver let name: Result<QName, Error> = receiver
.resolve_multiname(&multiname)? .resolve_multiname(&multiname)?
@ -730,7 +729,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
arg_count: u32, arg_count: u32,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let args = self.context.avm2.pop_args(arg_count); let args = self.context.avm2.pop_args(arg_count);
let multiname = self.pool_multiname(method, index, self.context.gc_context)?; let multiname = self.pool_multiname(method, index)?;
let mut receiver = self.context.avm2.pop().coerce_to_object(self)?; let mut receiver = self.context.avm2.pop().coerce_to_object(self)?;
let name: Result<QName, Error> = receiver let name: Result<QName, Error> = receiver
.resolve_multiname(&multiname)? .resolve_multiname(&multiname)?
@ -752,7 +751,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
arg_count: u32, arg_count: u32,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let args = self.context.avm2.pop_args(arg_count); let args = self.context.avm2.pop_args(arg_count);
let multiname = self.pool_multiname(method, index, self.context.gc_context)?; let multiname = self.pool_multiname(method, index)?;
let mut receiver = self.context.avm2.pop().coerce_to_object(self)?; let mut receiver = self.context.avm2.pop().coerce_to_object(self)?;
let name: Result<QName, Error> = receiver let name: Result<QName, Error> = receiver
.resolve_multiname(&multiname)? .resolve_multiname(&multiname)?
@ -799,7 +798,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
arg_count: u32, arg_count: u32,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let args = self.context.avm2.pop_args(arg_count); let args = self.context.avm2.pop_args(arg_count);
let multiname = self.pool_multiname(method, index, self.context.gc_context)?; let multiname = self.pool_multiname(method, index)?;
let receiver = self.context.avm2.pop().coerce_to_object(self)?; let receiver = self.context.avm2.pop().coerce_to_object(self)?;
let name: Result<QName, Error> = receiver let name: Result<QName, Error> = receiver
.resolve_multiname(&multiname)? .resolve_multiname(&multiname)?
@ -831,7 +830,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
arg_count: u32, arg_count: u32,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let args = self.context.avm2.pop_args(arg_count); let args = self.context.avm2.pop_args(arg_count);
let multiname = self.pool_multiname(method, index, self.context.gc_context)?; let multiname = self.pool_multiname(method, index)?;
let receiver = self.context.avm2.pop().coerce_to_object(self)?; let receiver = self.context.avm2.pop().coerce_to_object(self)?;
let name: Result<QName, Error> = receiver let name: Result<QName, Error> = receiver
.resolve_multiname(&multiname)? .resolve_multiname(&multiname)?
@ -869,7 +868,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
method: Gc<'gc, BytecodeMethod<'gc>>, method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<AbcMultiname>, index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let multiname = self.pool_multiname(method, index, self.context.gc_context)?; let multiname = self.pool_multiname(method, index)?;
let mut object = self.context.avm2.pop().coerce_to_object(self)?; let mut object = self.context.avm2.pop().coerce_to_object(self)?;
let name: Result<QName, Error> = object.resolve_multiname(&multiname)?.ok_or_else(|| { let name: Result<QName, Error> = object.resolve_multiname(&multiname)?.ok_or_else(|| {
@ -888,7 +887,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
index: Index<AbcMultiname>, index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value = self.context.avm2.pop(); let value = self.context.avm2.pop();
let multiname = self.pool_multiname(method, index, self.context.gc_context)?; let multiname = self.pool_multiname(method, index)?;
let mut object = self.context.avm2.pop().coerce_to_object(self)?; let mut object = self.context.avm2.pop().coerce_to_object(self)?;
if let Some(name) = object.resolve_multiname(&multiname)? { if let Some(name) = object.resolve_multiname(&multiname)? {
@ -912,7 +911,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
index: Index<AbcMultiname>, index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value = self.context.avm2.pop(); let value = self.context.avm2.pop();
let multiname = self.pool_multiname(method, index, self.context.gc_context)?; let multiname = self.pool_multiname(method, index)?;
let mut object = self.context.avm2.pop().coerce_to_object(self)?; let mut object = self.context.avm2.pop().coerce_to_object(self)?;
if let Some(name) = object.resolve_multiname(&multiname)? { if let Some(name) = object.resolve_multiname(&multiname)? {
@ -935,7 +934,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
method: Gc<'gc, BytecodeMethod<'gc>>, method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<AbcMultiname>, index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let multiname = self.pool_multiname(method, index, self.context.gc_context)?; let multiname = self.pool_multiname(method, index)?;
let object = self.context.avm2.pop().coerce_to_object(self)?; let object = self.context.avm2.pop().coerce_to_object(self)?;
if let Some(name) = object.resolve_multiname(&multiname)? { if let Some(name) = object.resolve_multiname(&multiname)? {
@ -954,7 +953,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
method: Gc<'gc, BytecodeMethod<'gc>>, method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<AbcMultiname>, index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let multiname = self.pool_multiname(method, index, self.context.gc_context)?; let multiname = self.pool_multiname(method, index)?;
let object = self.context.avm2.pop().coerce_to_object(self)?; let object = self.context.avm2.pop().coerce_to_object(self)?;
let base_proto: Result<Object<'gc>, Error> = self let base_proto: Result<Object<'gc>, Error> = self
.base_proto() .base_proto()
@ -984,7 +983,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
index: Index<AbcMultiname>, index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let value = self.context.avm2.pop(); let value = self.context.avm2.pop();
let multiname = self.pool_multiname(method, index, self.context.gc_context)?; let multiname = self.pool_multiname(method, index)?;
let object = self.context.avm2.pop().coerce_to_object(self)?; let object = self.context.avm2.pop().coerce_to_object(self)?;
let base_proto: Result<Object<'gc>, Error> = self let base_proto: Result<Object<'gc>, Error> = self
.base_proto() .base_proto()
@ -1081,8 +1080,8 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
method: Gc<'gc, BytecodeMethod<'gc>>, method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<AbcMultiname>, index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let multiname = self.pool_multiname(method, index, self.context.gc_context)?; let multiname = self.pool_multiname(method, index)?;
avm_debug!(self.avm2(), "Resolving {:?}", multiname); avm_debug!(self.context.avm2, "Resolving {:?}", multiname);
let result = if let Some(scope) = self.scope() { let result = if let Some(scope) = self.scope() {
scope.read().find(&multiname, self)? scope.read().find(&multiname, self)?
} else { } else {
@ -1101,8 +1100,8 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
method: Gc<'gc, BytecodeMethod<'gc>>, method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<AbcMultiname>, index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let multiname = self.pool_multiname(method, index, self.context.gc_context)?; let multiname = self.pool_multiname(method, index)?;
avm_debug!(self.avm2(), "Resolving {:?}", multiname); avm_debug!(self.context.avm2, "Resolving {:?}", multiname);
let found: Result<Object<'gc>, Error> = if let Some(scope) = self.scope() { let found: Result<Object<'gc>, Error> = if let Some(scope) = self.scope() {
scope.read().find(&multiname, self)? scope.read().find(&multiname, self)?
} else { } else {
@ -1202,7 +1201,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
arg_count: u32, arg_count: u32,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let args = self.context.avm2.pop_args(arg_count); let args = self.context.avm2.pop_args(arg_count);
let multiname = self.pool_multiname(method, index, self.context.gc_context)?; let multiname = self.pool_multiname(method, index)?;
let mut source = self.context.avm2.pop().coerce_to_object(self)?; let mut source = self.context.avm2.pop().coerce_to_object(self)?;
let ctor_name: Result<QName, Error> = let ctor_name: Result<QName, Error> =
@ -1269,7 +1268,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
object.set_property( object.set_property(
object, object,
&QName::new(Namespace::public_namespace(), name.as_string()?), &QName::new(Namespace::public_namespace(), name.coerce_to_string(self)?),
value, value,
self, self,
)?; )?;

View File

@ -52,14 +52,14 @@ fn value_of<'gc>(
/// `Object.prototype.hasOwnProperty` /// `Object.prototype.hasOwnProperty`
pub fn has_own_property<'gc>( pub fn has_own_property<'gc>(
_activation: &mut Activation<'_, 'gc, '_>, activation: &mut Activation<'_, 'gc, '_>,
this: Option<Object<'gc>>, this: Option<Object<'gc>>,
args: &[Value<'gc>], args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
let this: Result<Object<'gc>, Error> = this.ok_or_else(|| "No valid this parameter".into()); let this: Result<Object<'gc>, Error> = this.ok_or_else(|| "No valid this parameter".into());
let this = this?; let this = this?;
let name: Result<&Value<'gc>, Error> = args.get(0).ok_or_else(|| "No name specified".into()); let name: Result<&Value<'gc>, Error> = args.get(0).ok_or_else(|| "No name specified".into());
let name = name?.as_string()?; let name = name?.coerce_to_string(activation)?;
if let Some(ns) = this.resolve_any(name)? { if let Some(ns) = this.resolve_any(name)? {
if !ns.is_private() { if !ns.is_private() {
@ -95,14 +95,14 @@ pub fn is_prototype_of<'gc>(
/// `Object.prototype.propertyIsEnumerable` /// `Object.prototype.propertyIsEnumerable`
pub fn property_is_enumerable<'gc>( pub fn property_is_enumerable<'gc>(
_activation: &mut Activation<'_, 'gc, '_>, activation: &mut Activation<'_, 'gc, '_>,
this: Option<Object<'gc>>, this: Option<Object<'gc>>,
args: &[Value<'gc>], args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
let this: Result<Object<'gc>, Error> = this.ok_or_else(|| "No valid this parameter".into()); let this: Result<Object<'gc>, Error> = this.ok_or_else(|| "No valid this parameter".into());
let this = this?; let this = this?;
let name: Result<&Value<'gc>, Error> = args.get(0).ok_or_else(|| "No name specified".into()); let name: Result<&Value<'gc>, Error> = args.get(0).ok_or_else(|| "No name specified".into());
let name = name?.as_string()?; let name = name?.coerce_to_string(activation)?;
if let Some(ns) = this.resolve_any(name)? { if let Some(ns) = this.resolve_any(name)? {
if !ns.is_private() { if !ns.is_private() {
@ -123,7 +123,7 @@ pub fn set_property_is_enumerable<'gc>(
let this: Result<Object<'gc>, Error> = this.ok_or_else(|| "No valid this parameter".into()); let this: Result<Object<'gc>, Error> = this.ok_or_else(|| "No valid this parameter".into());
let this = this?; let this = this?;
let name: Result<&Value<'gc>, Error> = args.get(0).ok_or_else(|| "No name specified".into()); let name: Result<&Value<'gc>, Error> = args.get(0).ok_or_else(|| "No name specified".into());
let name = name?.as_string()?; let name = name?.coerce_to_string(activation)?;
if let Some(Value::Bool(is_enum)) = args.get(1) { if let Some(Value::Bool(is_enum)) = args.get(1) {
if let Some(ns) = this.resolve_any(name)? { if let Some(ns) = this.resolve_any(name)? {

View File

@ -1,8 +1,9 @@
//! AVM2 names & namespacing //! AVM2 names & namespacing
use crate::avm2::activation::Activation;
use crate::avm2::script::TranslationUnit; use crate::avm2::script::TranslationUnit;
use crate::avm2::string::AvmString; use crate::avm2::string::AvmString;
use crate::avm2::{Avm2, Error}; use crate::avm2::Error;
use gc_arena::{Collect, MutationContext}; use gc_arena::{Collect, MutationContext};
use swf::avm2::types::{ use swf::avm2::types::{
Index, Multiname as AbcMultiname, Namespace as AbcNamespace, NamespaceSet as AbcNamespaceSet, Index, Multiname as AbcMultiname, Namespace as AbcNamespace, NamespaceSet as AbcNamespaceSet,
@ -222,8 +223,7 @@ impl<'gc> Multiname<'gc> {
pub fn from_abc_multiname( pub fn from_abc_multiname(
translation_unit: TranslationUnit<'gc>, translation_unit: TranslationUnit<'gc>,
multiname_index: Index<AbcMultiname>, multiname_index: Index<AbcMultiname>,
avm: &mut Avm2<'gc>, activation: &mut Activation<'_, 'gc, '_>,
mc: MutationContext<'gc, '_>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let actual_index: Result<usize, Error> = (multiname_index.0 as usize) let actual_index: Result<usize, Error> = (multiname_index.0 as usize)
.checked_sub(1) .checked_sub(1)
@ -242,21 +242,23 @@ impl<'gc> Multiname<'gc> {
ns: vec![Namespace::from_abc_namespace( ns: vec![Namespace::from_abc_namespace(
translation_unit, translation_unit,
namespace.clone(), namespace.clone(),
mc, activation.context.gc_context,
)?], )?],
name: translation_unit.pool_string_option(name.0, mc)?, name: translation_unit
.pool_string_option(name.0, activation.context.gc_context)?,
} }
} }
AbcMultiname::RTQName { name } | AbcMultiname::RTQNameA { name } => { AbcMultiname::RTQName { name } | AbcMultiname::RTQNameA { name } => {
let ns = avm.pop().as_namespace()?.clone(); let ns = activation.avm2().pop().as_namespace()?.clone();
Self { Self {
ns: vec![ns], ns: vec![ns],
name: translation_unit.pool_string_option(name.0, mc)?, name: translation_unit
.pool_string_option(name.0, activation.context.gc_context)?,
} }
} }
AbcMultiname::RTQNameL | AbcMultiname::RTQNameLA => { AbcMultiname::RTQNameL | AbcMultiname::RTQNameLA => {
let ns = avm.pop().as_namespace()?.clone(); let ns = activation.avm2().pop().as_namespace()?.clone();
let name = avm.pop().as_string()?; let name = activation.avm2().pop().coerce_to_string(activation)?;
Self { Self {
ns: vec![ns], ns: vec![ns],
name: Some(name), name: Some(name),
@ -270,14 +272,22 @@ impl<'gc> Multiname<'gc> {
namespace_set, namespace_set,
name, name,
} => Self { } => Self {
ns: Self::abc_namespace_set(translation_unit, namespace_set.clone(), mc)?, ns: Self::abc_namespace_set(
name: translation_unit.pool_string_option(name.0, mc)?, translation_unit,
namespace_set.clone(),
activation.context.gc_context,
)?,
name: translation_unit.pool_string_option(name.0, activation.context.gc_context)?,
}, },
AbcMultiname::MultinameL { namespace_set } AbcMultiname::MultinameL { namespace_set }
| AbcMultiname::MultinameLA { namespace_set } => { | AbcMultiname::MultinameLA { namespace_set } => {
let name = avm.pop().as_string()?; let name = activation.avm2().pop().coerce_to_string(activation)?;
Self { Self {
ns: Self::abc_namespace_set(translation_unit, namespace_set.clone(), mc)?, ns: Self::abc_namespace_set(
translation_unit,
namespace_set.clone(),
activation.context.gc_context,
)?,
name: Some(name), name: Some(name),
} }
} }

View File

@ -206,16 +206,6 @@ pub fn abc_default_value<'gc>(
} }
impl<'gc> Value<'gc> { impl<'gc> Value<'gc> {
/// Demand a string value, erroring out if one is not found.
///
/// TODO: This should be replaced with `coerce_string` where possible.
pub fn as_string(&self) -> Result<AvmString<'gc>, Error> {
match self {
Value::String(s) => Ok(*s),
_ => Err(format!("Expected String, found {:?}", self).into()),
}
}
pub fn as_number(&self) -> Result<f64, Error> { pub fn as_number(&self) -> Result<f64, Error> {
match self { match self {
Value::Number(f) => Ok(*f), Value::Number(f) => Ok(*f),