From ad733f2f211d80329b76153118c0b051798207ab Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Mon, 13 Jul 2020 00:16:48 +0200 Subject: [PATCH] avm1: Add Avm1String which wraps Gc --- core/src/avm1.rs | 2 + core/src/avm1/activation.rs | 30 +++++----- core/src/avm1/debug.rs | 16 +++--- core/src/avm1/function.rs | 6 +- core/src/avm1/globals.rs | 4 +- core/src/avm1/globals/array.rs | 6 +- core/src/avm1/globals/boolean.rs | 6 +- core/src/avm1/globals/color_transform.rs | 9 ++- core/src/avm1/globals/context_menu_item.rs | 8 +-- core/src/avm1/globals/error.rs | 10 ++-- core/src/avm1/globals/function.rs | 6 +- core/src/avm1/globals/matrix.rs | 6 +- core/src/avm1/globals/movie_clip.rs | 8 +-- core/src/avm1/globals/number.rs | 12 ++-- core/src/avm1/globals/object.rs | 6 +- core/src/avm1/globals/point.rs | 6 +- core/src/avm1/globals/rectangle.rs | 6 +- core/src/avm1/globals/shared_object.rs | 8 +-- core/src/avm1/globals/stage.rs | 10 ++-- core/src/avm1/globals/string.rs | 40 ++++++------- core/src/avm1/globals/system_capabilities.rs | 22 ++++---- core/src/avm1/globals/system_ime.rs | 20 +++---- core/src/avm1/globals/system_security.rs | 6 +- core/src/avm1/globals/text_field.rs | 26 +++++---- core/src/avm1/globals/text_format.rs | 6 +- core/src/avm1/globals/xml.rs | 28 +++++----- core/src/avm1/object/script_object.rs | 56 +++++++++---------- core/src/avm1/object/stage_object.rs | 14 ++--- core/src/avm1/object/xml_attributes_object.rs | 6 +- core/src/avm1/string.rs | 56 +++++++++++++++++++ core/src/avm1/tests.rs | 5 +- core/src/avm1/value.rs | 20 +++---- core/src/display_object/edit_text.rs | 6 +- core/src/html/text_format.rs | 12 ++-- core/src/loader.rs | 26 +++++---- core/src/player.rs | 6 +- 36 files changed, 294 insertions(+), 226 deletions(-) create mode 100644 core/src/avm1/string.rs diff --git a/core/src/avm1.rs b/core/src/avm1.rs index 88093ccb8..bb1820080 100644 --- a/core/src/avm1.rs +++ b/core/src/avm1.rs @@ -25,6 +25,7 @@ pub mod globals; pub mod object; mod property; mod scope; +mod string; mod timer; mod value; @@ -41,6 +42,7 @@ pub use object::stage_object::StageObject; pub use object::{Object, ObjectPtr, TObject}; use scope::Scope; use smallvec::alloc::borrow::Cow; +pub use string::Avm1String; pub use timer::Timers; pub use value::Value; diff --git a/core/src/avm1/activation.rs b/core/src/avm1/activation.rs index b5f7eb961..948c9c11f 100644 --- a/core/src/avm1/activation.rs +++ b/core/src/avm1/activation.rs @@ -4,7 +4,9 @@ use crate::avm1::object::{value_object, Object, TObject}; use crate::avm1::property::Attribute; use crate::avm1::scope::Scope; use crate::avm1::value::f64_to_wrapping_u32; -use crate::avm1::{fscommand, globals, scope, skip_actions, start_drag, Avm1, ScriptObject, Value}; +use crate::avm1::{ + fscommand, globals, scope, skip_actions, start_drag, Avm1, Avm1String, ScriptObject, Value, +}; use crate::backend::navigator::{NavigationMethod, RequestOptions}; use crate::context::UpdateContext; use crate::display_object::{DisplayObject, MovieClip, TDisplayObject}; @@ -587,11 +589,11 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> { if let Value::String(a) = a { let mut s = b.coerce_to_string(self, context)?.to_string(); s.push_str(&a); - self.avm.push(Gc::allocate(context.gc_context, s)); + self.avm.push(Avm1String::new(context.gc_context, s)); } else if let Value::String(b) = b { let mut b = b.to_string(); b.push_str(&a.coerce_to_string(self, context)?); - self.avm.push(Gc::allocate(context.gc_context, b)); + self.avm.push(Avm1String::new(context.gc_context, b)); } else { let result = b.coerce_to_f64(self, context)? + a.coerce_to_f64(self, context)?; self.avm.push(result); @@ -620,7 +622,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> { // TODO(Herschel): Results on incorrect operands? let val = (self.avm.pop().coerce_to_f64(self, context)? as u8) as char; self.avm - .push(Gc::allocate(context.gc_context, val.to_string())); + .push(Avm1String::new(context.gc_context, val.to_string())); Ok(FrameControl::Continue) } @@ -1059,7 +1061,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> { match object { Value::Object(ob) => { for k in ob.get_keys(self).into_iter().rev() { - self.avm.push(Gc::allocate(context.gc_context, k)); + self.avm.push(Avm1String::new(context.gc_context, k)); } } _ => log::error!("Cannot enumerate properties of {}", name), @@ -1078,7 +1080,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> { if let Value::Object(object) = value { for k in object.get_keys(self).into_iter().rev() { - self.avm.push(Gc::allocate(context.gc_context, k)); + self.avm.push(Avm1String::new(context.gc_context, k)); } } else { log::warn!("Cannot enumerate {:?}", value); @@ -1572,7 +1574,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> { match result { Ok(val) => self .avm - .push(Gc::allocate(context.gc_context, val.to_string())), + .push(Avm1String::new(context.gc_context, val.to_string())), Err(e) => log::warn!("Couldn't parse char for action_mb_ascii_to_char: {}", e), } Ok(FrameControl::Continue) @@ -1600,7 +1602,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> { let val = self.avm.pop(); let s = val.coerce_to_string(self, context)?; let result = s[len..len + start].to_string(); // TODO(Herschel): Flash uses UTF-16 internally. - self.avm.push(Gc::allocate(context.gc_context, result)); + self.avm.push(Avm1String::new(context.gc_context, result)); Ok(FrameControl::Continue) } @@ -1826,11 +1828,11 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> { SwfValue::Int(v) => f64::from(*v).into(), SwfValue::Float(v) => f64::from(*v).into(), SwfValue::Double(v) => (*v).into(), - SwfValue::Str(v) => Gc::allocate(context.gc_context, (*v).to_string()).into(), + SwfValue::Str(v) => Avm1String::new(context.gc_context, (*v).to_string()).into(), SwfValue::Register(v) => self.current_register(*v), SwfValue::ConstantPool(i) => { if let Some(value) = self.constant_pool().read().get(*i as usize) { - Gc::allocate(context.gc_context, value.to_string()).into() + Avm1String::new(context.gc_context, value.to_string()).into() } else { log::warn!( "ActionPush: Constant pool index {} out of range (len = {})", @@ -2123,7 +2125,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> { let a = self.avm.pop(); let mut b = self.avm.pop().coerce_to_string(self, context)?.to_string(); b.push_str(&a.coerce_to_string(self, context)?); - self.avm.push(Gc::allocate(context.gc_context, b)); + self.avm.push(Avm1String::new(context.gc_context, b)); Ok(FrameControl::Continue) } @@ -2158,7 +2160,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> { .take(len) .map(|c| c as char) .collect::(); - self.avm.push(Gc::allocate(context.gc_context, result)); + self.avm.push(Avm1String::new(context.gc_context, result)); Ok(FrameControl::Continue) } @@ -2263,7 +2265,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> { let val = self.avm.pop(); let string = val.coerce_to_string(self, context)?; self.avm - .push(Gc::allocate(context.gc_context, string.to_string())); + .push(Avm1String::new(context.gc_context, string.to_string())); Ok(FrameControl::Continue) } @@ -2289,7 +2291,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> { ) -> Result, Error<'gc>> { let type_of = self.avm.pop().type_of(); self.avm - .push(Gc::allocate(context.gc_context, type_of.to_string())); + .push(Avm1String::new(context.gc_context, type_of.to_string())); Ok(FrameControl::Continue) } diff --git a/core/src/avm1/debug.rs b/core/src/avm1/debug.rs index ac725cd47..d80c63542 100644 --- a/core/src/avm1/debug.rs +++ b/core/src/avm1/debug.rs @@ -198,8 +198,7 @@ mod tests { use super::*; use crate::avm1::error::Error; use crate::avm1::test_utils::with_avm; - use crate::avm1::ScriptObject; - use gc_arena::Gc; + use crate::avm1::{Avm1String, ScriptObject}; #[test] fn dump_undefined() { @@ -258,7 +257,7 @@ mod tests { with_avm(19, |activation, context, _root| -> Result<(), Error> { assert_eq!( VariableDumper::dump( - &Value::String(Gc::allocate(context.gc_context, "".to_string())), + &Value::String(Avm1String::new(context.gc_context, "".to_string())), " ", activation, context @@ -267,7 +266,10 @@ mod tests { ); assert_eq!( VariableDumper::dump( - &Value::String(Gc::allocate(context.gc_context, "HELLO WORLD".to_string())), + &Value::String(Avm1String::new( + context.gc_context, + "HELLO WORLD".to_string() + )), " ", activation, context @@ -276,7 +278,7 @@ mod tests { ); assert_eq!( VariableDumper::dump( - &Value::String(Gc::allocate( + &Value::String(Avm1String::new( context.gc_context, "Escape \"this\" string\nplease! \u{0008}\u{000C}\n\r\t\"\\".to_string() )), @@ -310,7 +312,7 @@ mod tests { object.set("self", object.into(), activation, context)?; object.set( "test", - Value::String(Gc::allocate(context.gc_context, "value".to_string())), + Value::String(Avm1String::new(context.gc_context, "value".to_string())), activation, context, )?; @@ -333,7 +335,7 @@ mod tests { object.set("self", object.into(), activation, context)?; object.set( "test", - Value::String(Gc::allocate(context.gc_context, "value".to_string())), + Value::String(Avm1String::new(context.gc_context, "value".to_string())), activation, context, )?; diff --git a/core/src/avm1/function.rs b/core/src/avm1/function.rs index 85811e7bb..3f45088c4 100644 --- a/core/src/avm1/function.rs +++ b/core/src/avm1/function.rs @@ -6,7 +6,7 @@ use crate::avm1::object::super_object::SuperObject; use crate::avm1::property::{Attribute, Attribute::*}; use crate::avm1::scope::Scope; use crate::avm1::value::Value; -use crate::avm1::{Object, ObjectPtr, ScriptObject, TObject, UpdateContext}; +use crate::avm1::{Avm1String, Object, ObjectPtr, ScriptObject, TObject, UpdateContext}; use crate::display_object::{DisplayObject, TDisplayObject}; use crate::tag_utils::SwfSlice; use enumset::EnumSet; @@ -448,7 +448,7 @@ impl<'gc> FunctionObject<'gc> { gc_context, FunctionObjectData { function: Some(function.into()), - primitive: Gc::allocate(gc_context, "[type Function]".to_string()).into(), + primitive: Avm1String::new(gc_context, "[type Function]".to_string()).into(), }, ), } @@ -553,7 +553,7 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> { context.gc_context, FunctionObjectData { function: None, - primitive: Gc::allocate(context.gc_context, "[type Function]".to_string()) + primitive: Avm1String::new(context.gc_context, "[type Function]".to_string()) .into(), }, ), diff --git a/core/src/avm1/globals.rs b/core/src/avm1/globals.rs index ba5e7a238..3e0ec3a41 100644 --- a/core/src/avm1/globals.rs +++ b/core/src/avm1/globals.rs @@ -63,8 +63,8 @@ pub fn getURL<'a, 'gc>( None }; let method = match args.get(2) { - Some(Value::String(s)) if **s == "GET" => Some(NavigationMethod::GET), - Some(Value::String(s)) if **s == "POST" => Some(NavigationMethod::POST), + Some(Value::String(s)) if *s == "GET" => Some(NavigationMethod::GET), + Some(Value::String(s)) if *s == "POST" => Some(NavigationMethod::POST), _ => None, }; let vars_method = method.map(|m| (m, activation.locals_into_form_values(context))); diff --git a/core/src/avm1/globals/array.rs b/core/src/avm1/globals/array.rs index 1054211e8..9b697ff07 100644 --- a/core/src/avm1/globals/array.rs +++ b/core/src/avm1/globals/array.rs @@ -5,9 +5,9 @@ use crate::avm1::error::Error; use crate::avm1::function::{Executable, FunctionObject}; use crate::avm1::object::value_object; use crate::avm1::property::Attribute; -use crate::avm1::{Object, ScriptObject, TObject, UpdateContext, Value}; +use crate::avm1::{Avm1String, Object, ScriptObject, TObject, UpdateContext, Value}; use enumset::EnumSet; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; use smallvec::alloc::borrow::Cow; use std::cmp::Ordering; @@ -247,7 +247,7 @@ pub fn join<'gc>( .unwrap_or_else(|| Cow::Borrowed(",")); let values: Vec> = this.array(); - Ok(Gc::allocate( + Ok(Avm1String::new( context.gc_context, values .iter() diff --git a/core/src/avm1/globals/boolean.rs b/core/src/avm1/globals/boolean.rs index 5464504a8..bf09ecdd4 100644 --- a/core/src/avm1/globals/boolean.rs +++ b/core/src/avm1/globals/boolean.rs @@ -4,10 +4,10 @@ use crate::avm1::activation::Activation; use crate::avm1::error::Error; use crate::avm1::function::{Executable, FunctionObject}; use crate::avm1::object::value_object::ValueObject; -use crate::avm1::{Object, TObject, Value}; +use crate::avm1::{Avm1String, Object, TObject, Value}; use crate::context::UpdateContext; use enumset::EnumSet; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; /// `Boolean` constructor/function pub fn boolean<'gc>( @@ -83,7 +83,7 @@ pub fn to_string<'gc>( // Must be a bool. // Boolean.prototype.toString.call(x) returns undefined for non-bools. if let Value::Bool(b) = vbox.unbox() { - return Ok(Gc::allocate(context.gc_context, b.to_string()).into()); + return Ok(Avm1String::new(context.gc_context, b.to_string()).into()); } } diff --git a/core/src/avm1/globals/color_transform.rs b/core/src/avm1/globals/color_transform.rs index dbcb9283c..a800e15da 100644 --- a/core/src/avm1/globals/color_transform.rs +++ b/core/src/avm1/globals/color_transform.rs @@ -3,10 +3,10 @@ use crate::avm1::activation::Activation; use crate::avm1::error::Error; use crate::avm1::function::Executable; -use crate::avm1::{Object, TObject, Value}; +use crate::avm1::{Avm1String, Object, TObject, Value}; use crate::context::UpdateContext; use enumset::EnumSet; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; use crate::avm1::object::color_transform_object::ColorTransformObject; use crate::color_transform::ColorTransform; @@ -264,7 +264,10 @@ fn to_string<'gc>( this.get("alphaOffset", activation, context)?.coerce_to_string(activation, context)? ); - Ok(Value::String(Gc::allocate(context.gc_context, formatted))) + Ok(Value::String(Avm1String::new( + context.gc_context, + formatted, + ))) } fn concat<'gc>( diff --git a/core/src/avm1/globals/context_menu_item.rs b/core/src/avm1/globals/context_menu_item.rs index ac31d2c93..b45302c82 100644 --- a/core/src/avm1/globals/context_menu_item.rs +++ b/core/src/avm1/globals/context_menu_item.rs @@ -2,10 +2,10 @@ use crate::avm1::activation::Activation; use crate::avm1::error::Error; use crate::avm1::object::TObject; use crate::avm1::property::Attribute; -use crate::avm1::Object; +use crate::avm1::{Avm1String, Object}; use crate::avm1::{ScriptObject, Value}; use crate::context::UpdateContext; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; pub fn constructor<'gc>( activation: &mut Activation<'_, 'gc>, @@ -40,7 +40,7 @@ pub fn constructor<'gc>( this.set( "caption", - Gc::allocate(context.gc_context, caption).into(), + Avm1String::new(context.gc_context, caption).into(), activation, context, )?; @@ -92,7 +92,7 @@ pub fn copy<'gc>( context, copy, &[ - Gc::allocate(context.gc_context, caption).into(), + Avm1String::new(context.gc_context, caption).into(), callback.into(), separator_before.into(), enabled.into(), diff --git a/core/src/avm1/globals/error.rs b/core/src/avm1/globals/error.rs index 92376dfda..dbfbf76cd 100644 --- a/core/src/avm1/globals/error.rs +++ b/core/src/avm1/globals/error.rs @@ -3,9 +3,9 @@ use crate::avm1::activation::Activation; use crate::avm1::error::Error; use crate::avm1::property::Attribute::*; -use crate::avm1::{Object, ScriptObject, TObject, UpdateContext, Value}; +use crate::avm1::{Avm1String, Object, ScriptObject, TObject, UpdateContext, Value}; use enumset::EnumSet; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; pub fn constructor<'gc>( activation: &mut Activation<'_, 'gc>, @@ -32,13 +32,13 @@ pub fn create_proto<'gc>( object.define_value( gc_context, "message", - Gc::allocate(gc_context, "Error".to_string()).into(), + Avm1String::new(gc_context, "Error".to_string()).into(), EnumSet::empty(), ); object.define_value( gc_context, "name", - Gc::allocate(gc_context, "Error".to_string()).into(), + Avm1String::new(gc_context, "Error".to_string()).into(), EnumSet::empty(), ); @@ -60,7 +60,7 @@ fn to_string<'gc>( _args: &[Value<'gc>], ) -> Result, Error<'gc>> { let message = this.get("message", activation, context)?; - Ok(Gc::allocate( + Ok(Avm1String::new( context.gc_context, message.coerce_to_string(activation, context)?.to_string(), ) diff --git a/core/src/avm1/globals/function.rs b/core/src/avm1/globals/function.rs index c75170d6a..3fa7198ec 100644 --- a/core/src/avm1/globals/function.rs +++ b/core/src/avm1/globals/function.rs @@ -3,9 +3,9 @@ use crate::avm1::activation::Activation; use crate::avm1::error::Error; use crate::avm1::function::ExecutionReason; -use crate::avm1::{Object, ScriptObject, TObject, UpdateContext, Value}; +use crate::avm1::{Avm1String, Object, ScriptObject, TObject, UpdateContext, Value}; use enumset::EnumSet; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; /// Implements `Function` pub fn constructor<'gc>( @@ -97,7 +97,7 @@ fn to_string<'gc>( _: Object<'gc>, _: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(Gc::allocate(context.gc_context, "[type Function]".to_string()).into()) + Ok(Avm1String::new(context.gc_context, "[type Function]".to_string()).into()) } /// Partially construct `Function.prototype`. diff --git a/core/src/avm1/globals/matrix.rs b/core/src/avm1/globals/matrix.rs index e980f1656..5aea5aaeb 100644 --- a/core/src/avm1/globals/matrix.rs +++ b/core/src/avm1/globals/matrix.rs @@ -3,10 +3,10 @@ use crate::avm1::activation::Activation; use crate::avm1::error::Error; use crate::avm1::function::{Executable, FunctionObject}; -use crate::avm1::{Object, ScriptObject, TObject, Value}; +use crate::avm1::{Avm1String, Object, ScriptObject, TObject, Value}; use crate::context::UpdateContext; use enumset::EnumSet; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; use swf::{Matrix, Twips}; pub fn value_to_matrix<'gc>( @@ -403,7 +403,7 @@ fn to_string<'gc>( let tx = this.get("tx", activation, context)?; let ty = this.get("ty", activation, context)?; - Ok(Gc::allocate( + Ok(Avm1String::new( context.gc_context, format!( "(a={}, b={}, c={}, d={}, tx={}, ty={})", diff --git a/core/src/avm1/globals/movie_clip.rs b/core/src/avm1/globals/movie_clip.rs index ad7ccb03c..0a141bc4f 100644 --- a/core/src/avm1/globals/movie_clip.rs +++ b/core/src/avm1/globals/movie_clip.rs @@ -5,13 +5,13 @@ use crate::avm1::error::Error; use crate::avm1::globals::display_object::{self, AVM_DEPTH_BIAS, AVM_MAX_DEPTH}; use crate::avm1::globals::matrix::gradient_object_to_matrix; use crate::avm1::property::Attribute::*; -use crate::avm1::{Object, ScriptObject, TObject, UpdateContext, Value}; +use crate::avm1::{Avm1String, Object, ScriptObject, TObject, UpdateContext, Value}; use crate::backend::navigator::NavigationMethod; use crate::display_object::{DisplayObject, EditText, MovieClip, TDisplayObject}; use crate::prelude::*; use crate::shape_utils::DrawCommand; use crate::tag_utils::SwfSlice; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; use swf::{ FillStyle, Gradient, GradientInterpolation, GradientRecord, GradientSpread, LineCapStyle, LineJoinStyle, LineStyle, Twips, @@ -900,7 +900,7 @@ fn to_string<'gc>( context: &mut UpdateContext<'_, 'gc, '_>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(Gc::allocate(context.gc_context, movie_clip.path()).into()) + Ok(Avm1String::new(context.gc_context, movie_clip.path()).into()) } fn local_to_global<'gc>( @@ -945,7 +945,7 @@ fn get_bounds<'gc>( activation.resolve_target_display_object( context, movie_clip.into(), - Gc::allocate(context.gc_context, path.to_string()).into(), + Avm1String::new(context.gc_context, path.to_string()).into(), )? } None => Some(movie_clip.into()), diff --git a/core/src/avm1/globals/number.rs b/core/src/avm1/globals/number.rs index 2de51ec16..03d96ca9a 100644 --- a/core/src/avm1/globals/number.rs +++ b/core/src/avm1/globals/number.rs @@ -5,10 +5,10 @@ use crate::avm1::error::Error; use crate::avm1::function::{Executable, FunctionObject}; use crate::avm1::object::value_object::ValueObject; use crate::avm1::property::Attribute::*; -use crate::avm1::{Object, TObject, Value}; +use crate::avm1::{Avm1String, Object, TObject, Value}; use crate::context::UpdateContext; use enumset::EnumSet; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; /// `Number` constructor/function pub fn number<'gc>( @@ -143,7 +143,7 @@ fn to_string<'gc>( if radix == 10 { // Output number as floating-point decimal. - Ok(Gc::allocate( + Ok(Avm1String::new( context.gc_context, Value::from(this) .coerce_to_string(activation, context)? @@ -159,7 +159,7 @@ fn to_string<'gc>( Ordering::Greater => (n as u32, false), Ordering::Equal => { // Bail out immediately if we're 0. - return Ok(Gc::allocate(context.gc_context, "0".to_string()).into()); + return Ok(Avm1String::new(context.gc_context, "0".to_string()).into()); } }; @@ -177,7 +177,7 @@ fn to_string<'gc>( i += 1; } let out: String = digits[..i].iter().rev().collect(); - Ok(Gc::allocate(context.gc_context, out).into()) + Ok(Avm1String::new(context.gc_context, out).into()) } else { // NaN or large numbers. // Player version specific behavior: @@ -185,7 +185,7 @@ fn to_string<'gc>( // for example, NaN.toString(3) gives "-/.//./..././/0.0./0.". // Flash Player 6 will print a much more sane value of 0, so let's go with that. // TODO: Allow configuration of player version. - Ok(Gc::allocate(context.gc_context, "0".to_string()).into()) + Ok(Avm1String::new(context.gc_context, "0".to_string()).into()) } } diff --git a/core/src/avm1/globals/object.rs b/core/src/avm1/globals/object.rs index 94ee8d281..f60a576fd 100644 --- a/core/src/avm1/globals/object.rs +++ b/core/src/avm1/globals/object.rs @@ -3,10 +3,10 @@ use crate::avm1::activation::Activation; use crate::avm1::error::Error; use crate::avm1::function::{Executable, FunctionObject}; use crate::avm1::property::Attribute::{self, *}; -use crate::avm1::{Object, TObject, UpdateContext, Value}; +use crate::avm1::{Avm1String, Object, TObject, UpdateContext, Value}; use crate::character::Character; use enumset::EnumSet; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; use std::borrow::Cow; /// Implements `Object` @@ -93,7 +93,7 @@ fn to_string<'gc>( _: Object<'gc>, _: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(Gc::allocate(context.gc_context, "[object Object]".to_string()).into()) + Ok(Avm1String::new(context.gc_context, "[object Object]".to_string()).into()) } /// Implements `Object.prototype.isPropertyEnumerable` diff --git a/core/src/avm1/globals/point.rs b/core/src/avm1/globals/point.rs index 1af546f4d..c4a376f35 100644 --- a/core/src/avm1/globals/point.rs +++ b/core/src/avm1/globals/point.rs @@ -4,10 +4,10 @@ use crate::avm1::activation::Activation; use crate::avm1::error::Error; use crate::avm1::function::{Executable, FunctionObject}; use crate::avm1::property::Attribute; -use crate::avm1::{Object, ScriptObject, TObject, Value}; +use crate::avm1::{Avm1String, Object, ScriptObject, TObject, Value}; use crate::context::UpdateContext; use enumset::EnumSet; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; use std::f64::NAN; pub fn point_to_object<'gc>( @@ -233,7 +233,7 @@ fn to_string<'gc>( let x = this.get("x", activation, context)?; let y = this.get("y", activation, context)?; - Ok(Gc::allocate( + Ok(Avm1String::new( context.gc_context, format!( "(x={}, y={})", diff --git a/core/src/avm1/globals/rectangle.rs b/core/src/avm1/globals/rectangle.rs index 10f7677c5..f832a63aa 100644 --- a/core/src/avm1/globals/rectangle.rs +++ b/core/src/avm1/globals/rectangle.rs @@ -5,10 +5,10 @@ use crate::avm1::error::Error; use crate::avm1::function::{Executable, FunctionObject}; use crate::avm1::globals::point::{construct_new_point, point_to_object, value_to_point}; use crate::avm1::property::Attribute; -use crate::avm1::{Object, ScriptObject, TObject, Value}; +use crate::avm1::{Avm1String, Object, ScriptObject, TObject, Value}; use crate::context::UpdateContext; use enumset::EnumSet; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; use std::f64::NAN; fn constructor<'gc>( @@ -63,7 +63,7 @@ fn to_string<'gc>( let width = this.get("width", activation, context)?; let height = this.get("height", activation, context)?; - Ok(Gc::allocate( + Ok(Avm1String::new( context.gc_context, format!( "(x={}, y={}, w={}, h={})", diff --git a/core/src/avm1/globals/shared_object.rs b/core/src/avm1/globals/shared_object.rs index ff27d791c..bad7df43c 100644 --- a/core/src/avm1/globals/shared_object.rs +++ b/core/src/avm1/globals/shared_object.rs @@ -1,10 +1,10 @@ use crate::avm1::activation::Activation; use crate::avm1::error::Error; use crate::avm1::function::{Executable, FunctionObject}; -use crate::avm1::{Object, TObject, Value}; +use crate::avm1::{Avm1String, Object, TObject, Value}; use crate::context::UpdateContext; use enumset::EnumSet; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; use crate::avm1::object::shared_object::SharedObject; @@ -83,7 +83,7 @@ fn recursive_deserialize<'gc>( object.define_value( context.gc_context, entry.0, - Value::String(Gc::allocate(context.gc_context, val)), + Value::String(Avm1String::new(context.gc_context, val)), EnumSet::empty(), ); } @@ -91,7 +91,7 @@ fn recursive_deserialize<'gc>( object.define_value( context.gc_context, entry.0, - Value::String(Gc::allocate(context.gc_context, s.clone())), + Value::String(Avm1String::new(context.gc_context, s.clone())), EnumSet::empty(), ); } diff --git a/core/src/avm1/globals/stage.rs b/core/src/avm1/globals/stage.rs index af8c155f4..f7e25109f 100644 --- a/core/src/avm1/globals/stage.rs +++ b/core/src/avm1/globals/stage.rs @@ -5,8 +5,8 @@ use crate::avm1::activation::Activation; use crate::avm1::error::Error; use crate::avm1::function::Executable; use crate::avm1::property::Attribute; -use crate::avm1::{Object, ScriptObject, TObject, UpdateContext, Value}; -use gc_arena::{Gc, MutationContext}; +use crate::avm1::{Avm1String, Object, ScriptObject, TObject, UpdateContext, Value}; +use gc_arena::MutationContext; pub fn create_stage_object<'gc>( gc_context: MutationContext<'gc, '_>, @@ -92,7 +92,7 @@ fn align<'gc>( _args: &[Value<'gc>], ) -> Result, Error<'gc>> { log::warn!("Stage.align: unimplemented"); - Ok(Gc::allocate(context.gc_context, "".to_string()).into()) + Ok(Avm1String::new(context.gc_context, "".to_string()).into()) } fn set_align<'gc>( @@ -121,7 +121,7 @@ fn remove_listener<'gc>( _args: &[Value<'gc>], ) -> Result, Error<'gc>> { log::warn!("Stage.removeListener: unimplemented"); - Ok(Gc::allocate(context.gc_context, "".to_string()).into()) + Ok(Avm1String::new(context.gc_context, "".to_string()).into()) } fn scale_mode<'gc>( @@ -131,7 +131,7 @@ fn scale_mode<'gc>( _args: &[Value<'gc>], ) -> Result, Error<'gc>> { log::warn!("Stage.scaleMode: unimplemented"); - Ok(Gc::allocate(context.gc_context, "noScale".to_string()).into()) + Ok(Avm1String::new(context.gc_context, "noScale".to_string()).into()) } fn set_scale_mode<'gc>( diff --git a/core/src/avm1/globals/string.rs b/core/src/avm1/globals/string.rs index e66cc04bc..bb7ea09c9 100644 --- a/core/src/avm1/globals/string.rs +++ b/core/src/avm1/globals/string.rs @@ -5,11 +5,11 @@ use crate::avm1::error::Error; use crate::avm1::function::{Executable, FunctionObject}; use crate::avm1::object::value_object::ValueObject; use crate::avm1::property::Attribute::*; -use crate::avm1::{Object, ScriptObject, TObject, Value}; +use crate::avm1::{Avm1String, Object, ScriptObject, TObject, Value}; use crate::context::UpdateContext; use crate::string_utils; use enumset::EnumSet; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; /// `String` constructor pub fn string<'gc>( @@ -20,17 +20,17 @@ pub fn string<'gc>( ) -> Result, Error<'gc>> { let value = match args.get(0).cloned() { Some(Value::String(s)) => s, - Some(v) => Gc::allocate( + Some(v) => Avm1String::new( ac.gc_context, v.coerce_to_string(activation, ac)?.to_string(), ), - _ => Gc::allocate(ac.gc_context, String::new()), + _ => Avm1String::new(ac.gc_context, String::new()), }; if let Some(mut vbox) = this.as_value_object() { let len = value.encode_utf16().count(); vbox.set_length(ac.gc_context, len); - vbox.replace_value(ac.gc_context, value.into()); + vbox.replace_value(ac.gc_context, value.clone().into()); } Ok(value.into()) @@ -184,7 +184,7 @@ fn char_at<'gc>( let this_val = Value::from(this); let string = match this_val { Value::String(string) => string, - other => Gc::allocate( + other => Avm1String::new( context.gc_context, other.coerce_to_string(activation, context)?.to_string(), ), @@ -202,7 +202,7 @@ fn char_at<'gc>( } else { "".into() }; - Ok(Gc::allocate(context.gc_context, ret).into()) + Ok(Avm1String::new(context.gc_context, ret).into()) } fn char_code_at<'gc>( @@ -241,7 +241,7 @@ fn concat<'gc>( let s = arg.coerce_to_string(activation, context)?; ret.push_str(&s) } - Ok(Gc::allocate(context.gc_context, ret).into()) + Ok(Avm1String::new(context.gc_context, ret).into()) } fn from_char_code<'gc>( @@ -260,7 +260,7 @@ fn from_char_code<'gc>( } out.push(utf16_code_unit_to_char(i)); } - Ok(Gc::allocate(context.gc_context, out).into()) + Ok(Avm1String::new(context.gc_context, out).into()) } fn index_of<'gc>( @@ -393,9 +393,9 @@ fn slice<'gc>( .skip(start_index) .take(end_index - start_index), ); - Ok(Gc::allocate(context.gc_context, ret).into()) + Ok(Avm1String::new(context.gc_context, ret).into()) } else { - Ok(Gc::allocate(context.gc_context, "".to_string()).into()) + Ok(Avm1String::new(context.gc_context, "".to_string()).into()) } } @@ -408,7 +408,7 @@ fn split<'gc>( let this_val = Value::from(this); let this = match this_val { Value::String(string) => string, - other => Gc::allocate( + other => Avm1String::new( context.gc_context, other.coerce_to_string(activation, context)?.to_string(), ), @@ -424,7 +424,7 @@ fn split<'gc>( for (i, token) in this.split(delimiter.as_ref()).take(limit).enumerate() { array.set_array_element( i, - Gc::allocate(context.gc_context, token.to_string()).into(), + Avm1String::new(context.gc_context, token.to_string()).into(), context.gc_context, ); } @@ -435,7 +435,7 @@ fn split<'gc>( for (i, token) in this.chars().take(limit).enumerate() { array.set_array_element( i, - Gc::allocate(context.gc_context, token.to_string()).into(), + Avm1String::new(context.gc_context, token.to_string()).into(), context.gc_context, ); } @@ -456,7 +456,7 @@ fn substr<'gc>( let this_val = Value::from(this); let this = match this_val { Value::String(string) => string, - other => Gc::allocate( + other => Avm1String::new( context.gc_context, other.coerce_to_string(activation, context)?.to_string(), ), @@ -473,7 +473,7 @@ fn substr<'gc>( }; let ret = utf16_iter_to_string(this.encode_utf16().skip(start_index).take(len)); - Ok(Gc::allocate(context.gc_context, ret).into()) + Ok(Avm1String::new(context.gc_context, ret).into()) } fn substring<'gc>( @@ -489,7 +489,7 @@ fn substring<'gc>( let this_val = Value::from(this); let this = match this_val { Value::String(string) => string, - other => Gc::allocate( + other => Avm1String::new( context.gc_context, other.coerce_to_string(activation, context)?.to_string(), ), @@ -514,7 +514,7 @@ fn substring<'gc>( .skip(start_index) .take(end_index - start_index), ); - Ok(Gc::allocate(context.gc_context, ret).into()) + Ok(Avm1String::new(context.gc_context, ret).into()) } fn to_lower_case<'gc>( @@ -525,7 +525,7 @@ fn to_lower_case<'gc>( ) -> Result, Error<'gc>> { let this_val = Value::from(this); let this = this_val.coerce_to_string(activation, context)?; - Ok(Gc::allocate( + Ok(Avm1String::new( context.gc_context, this.chars() .map(string_utils::swf_char_to_lowercase) @@ -561,7 +561,7 @@ fn to_upper_case<'gc>( ) -> Result, Error<'gc>> { let this_val = Value::from(this); let this = this_val.coerce_to_string(activation, context)?; - Ok(Gc::allocate( + Ok(Avm1String::new( context.gc_context, this.chars() .map(string_utils::swf_char_to_uppercase) diff --git a/core/src/avm1/globals/system_capabilities.rs b/core/src/avm1/globals/system_capabilities.rs index 73d5e2205..4b0a55825 100644 --- a/core/src/avm1/globals/system_capabilities.rs +++ b/core/src/avm1/globals/system_capabilities.rs @@ -3,10 +3,10 @@ use crate::avm1::error::Error; use crate::avm1::function::Executable; use crate::avm1::globals::system::SystemCapabilities; use crate::avm1::object::Object; -use crate::avm1::{ScriptObject, TObject, Value}; +use crate::avm1::{Avm1String, ScriptObject, TObject, Value}; use crate::context::UpdateContext; use enumset::EnumSet; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; macro_rules! capabilities_func { ($func_name: ident, $capability: expr) => { @@ -82,7 +82,7 @@ pub fn get_player_type<'gc>( _this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(Gc::allocate(context.gc_context, context.system.player_type.to_string()).into()) + Ok(Avm1String::new(context.gc_context, context.system.player_type.to_string()).into()) } pub fn get_screen_color<'gc>( @@ -91,7 +91,7 @@ pub fn get_screen_color<'gc>( _this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(Gc::allocate(context.gc_context, context.system.screen_color.to_string()).into()) + Ok(Avm1String::new(context.gc_context, context.system.screen_color.to_string()).into()) } pub fn get_language<'gc>( @@ -100,7 +100,7 @@ pub fn get_language<'gc>( _this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(Gc::allocate( + Ok(Avm1String::new( context.gc_context, context .system @@ -153,7 +153,7 @@ pub fn get_manufacturer<'gc>( _this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(Gc::allocate( + Ok(Avm1String::new( context.gc_context, context .system @@ -169,7 +169,7 @@ pub fn get_os_name<'gc>( _this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(Gc::allocate(context.gc_context, context.system.os.to_string()).into()) + Ok(Avm1String::new(context.gc_context, context.system.os.to_string()).into()) } pub fn get_version<'gc>( @@ -178,7 +178,7 @@ pub fn get_version<'gc>( _this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(Gc::allocate( + Ok(Avm1String::new( context.gc_context, context.system.get_version_string(activation), ) @@ -191,7 +191,7 @@ pub fn get_server_string<'gc>( _this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(Gc::allocate( + Ok(Avm1String::new( context.gc_context, context.system.get_server_string(activation), ) @@ -204,7 +204,7 @@ pub fn get_cpu_architecture<'gc>( _this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(Gc::allocate( + Ok(Avm1String::new( context.gc_context, context.system.cpu_architecture.to_string(), ) @@ -217,7 +217,7 @@ pub fn get_max_idc_level<'gc>( _this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(Gc::allocate(context.gc_context, context.system.idc_level.clone()).into()) + Ok(Avm1String::new(context.gc_context, context.system.idc_level.clone()).into()) } pub fn create<'gc>( diff --git a/core/src/avm1/globals/system_ime.rs b/core/src/avm1/globals/system_ime.rs index 3375b3bca..c3ce3544f 100644 --- a/core/src/avm1/globals/system_ime.rs +++ b/core/src/avm1/globals/system_ime.rs @@ -4,9 +4,9 @@ use crate::avm1::listeners::Listeners; use crate::avm1::object::Object; use crate::avm1::property::Attribute; use crate::avm1::property::Attribute::{DontDelete, DontEnum, ReadOnly}; -use crate::avm1::{ScriptObject, TObject, Value}; +use crate::avm1::{Avm1String, ScriptObject, TObject, Value}; use crate::context::UpdateContext; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; use std::convert::Into; fn on_ime_composition<'gc>( @@ -33,7 +33,7 @@ fn get_conversion_mode<'gc>( _this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(Gc::allocate(context.gc_context, "KOREAN".to_string()).into()) + Ok(Avm1String::new(context.gc_context, "KOREAN".to_string()).into()) } fn get_enabled<'gc>( @@ -85,49 +85,49 @@ pub fn create<'gc>( ime.define_value( gc_context, "ALPHANUMERIC_FULL", - Gc::allocate(gc_context, "ALPHANUMERIC_FULL".to_string()).into(), + Avm1String::new(gc_context, "ALPHANUMERIC_FULL".to_string()).into(), Attribute::DontDelete | ReadOnly | DontEnum, ); ime.define_value( gc_context, "ALPHANUMERIC_HALF", - Gc::allocate(gc_context, "ALPHANUMERIC_HALF".to_string()).into(), + Avm1String::new(gc_context, "ALPHANUMERIC_HALF".to_string()).into(), DontDelete | ReadOnly | DontEnum, ); ime.define_value( gc_context, "CHINESE", - Gc::allocate(gc_context, "CHINESE".to_string()).into(), + Avm1String::new(gc_context, "CHINESE".to_string()).into(), DontDelete | ReadOnly | DontEnum, ); ime.define_value( gc_context, "JAPANESE_HIRAGANA", - Gc::allocate(gc_context, "JAPANESE_HIRAGANA".to_string()).into(), + Avm1String::new(gc_context, "JAPANESE_HIRAGANA".to_string()).into(), DontDelete | ReadOnly | DontEnum, ); ime.define_value( gc_context, "JAPANESE_KATAKANA_FULL", - Gc::allocate(gc_context, "JAPANESE_KATAKANA_FULL".to_string()).into(), + Avm1String::new(gc_context, "JAPANESE_KATAKANA_FULL".to_string()).into(), DontDelete | ReadOnly | DontEnum, ); ime.define_value( gc_context, "KOREAN", - Gc::allocate(gc_context, "KOREAN".to_string()).into(), + Avm1String::new(gc_context, "KOREAN".to_string()).into(), DontDelete | ReadOnly | DontEnum, ); ime.define_value( gc_context, "UNKNOWN", - Gc::allocate(gc_context, "UNKNOWN".to_string()).into(), + Avm1String::new(gc_context, "UNKNOWN".to_string()).into(), DontDelete | ReadOnly | DontEnum, ); diff --git a/core/src/avm1/globals/system_security.rs b/core/src/avm1/globals/system_security.rs index 6b4429f0d..bbf7a0da7 100644 --- a/core/src/avm1/globals/system_security.rs +++ b/core/src/avm1/globals/system_security.rs @@ -2,10 +2,10 @@ use crate::avm1::activation::Activation; use crate::avm1::error::Error; use crate::avm1::function::Executable; use crate::avm1::object::Object; -use crate::avm1::{ScriptObject, TObject, Value}; +use crate::avm1::{Avm1String, ScriptObject, TObject, Value}; use crate::context::UpdateContext; use enumset::EnumSet; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; use std::convert::Into; fn allow_domain<'gc>( @@ -54,7 +54,7 @@ fn get_sandbox_type<'gc>( _this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(Gc::allocate(context.gc_context, context.system.sandbox_type.to_string()).into()) + Ok(Avm1String::new(context.gc_context, context.system.sandbox_type.to_string()).into()) } fn get_choose_local_swf_path<'gc>( diff --git a/core/src/avm1/globals/text_field.rs b/core/src/avm1/globals/text_field.rs index b68d36cdf..aa88e3a62 100644 --- a/core/src/avm1/globals/text_field.rs +++ b/core/src/avm1/globals/text_field.rs @@ -3,10 +3,10 @@ use crate::avm1::error::Error; use crate::avm1::function::Executable; use crate::avm1::globals::display_object; use crate::avm1::property::Attribute::*; -use crate::avm1::{Object, ScriptObject, TObject, UpdateContext, Value}; +use crate::avm1::{Avm1String, Object, ScriptObject, TObject, UpdateContext, Value}; use crate::display_object::{AutoSizeMode, EditText, TDisplayObject}; use crate::html::TextFormat; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; /// Implements `TextField` pub fn constructor<'gc>( @@ -26,7 +26,7 @@ pub fn get_text<'gc>( ) -> Result, Error<'gc>> { if let Some(display_object) = this.as_display_object() { if let Some(text_field) = display_object.as_edit_text() { - return Ok(Gc::allocate(context.gc_context, text_field.text()).into()); + return Ok(Avm1String::new(context.gc_context, text_field.text()).into()); } } Ok(Value::Undefined) @@ -93,7 +93,7 @@ pub fn get_html_text<'gc>( if let Some(display_object) = this.as_display_object() { if let Some(text_field) = display_object.as_edit_text() { if let Ok(text) = text_field.html_text(context) { - return Ok(Gc::allocate(context.gc_context, text).into()); + return Ok(Avm1String::new(context.gc_context, text).into()); } } } @@ -303,7 +303,7 @@ fn variable<'gc>( .and_then(|dobj| dobj.as_edit_text()) { if let Some(variable) = etext.variable() { - return Ok(Gc::allocate(context.gc_context, variable.to_string()).into()); + return Ok(Avm1String::new(context.gc_context, variable.to_string()).into()); } } @@ -381,10 +381,12 @@ pub fn auto_size<'gc>( .and_then(|dobj| dobj.as_edit_text()) { return Ok(match etext.autosize() { - AutoSizeMode::None => Gc::allocate(context.gc_context, "none".to_string()).into(), - AutoSizeMode::Left => Gc::allocate(context.gc_context, "left".to_string()).into(), - AutoSizeMode::Center => Gc::allocate(context.gc_context, "center".to_string()).into(), - AutoSizeMode::Right => Gc::allocate(context.gc_context, "right".to_string()).into(), + AutoSizeMode::None => Avm1String::new(context.gc_context, "none".to_string()).into(), + AutoSizeMode::Left => Avm1String::new(context.gc_context, "left".to_string()).into(), + AutoSizeMode::Center => { + Avm1String::new(context.gc_context, "center".to_string()).into() + } + AutoSizeMode::Right => Avm1String::new(context.gc_context, "right".to_string()).into(), }); } @@ -403,9 +405,9 @@ pub fn set_auto_size<'gc>( { etext.set_autosize( match args.get(0).cloned().unwrap_or(Value::Undefined) { - Value::String(s) if *s == "left" => AutoSizeMode::Left, - Value::String(s) if *s == "center" => AutoSizeMode::Center, - Value::String(s) if *s == "right" => AutoSizeMode::Right, + Value::String(s) if s == "left" => AutoSizeMode::Left, + Value::String(s) if s == "center" => AutoSizeMode::Center, + Value::String(s) if s == "right" => AutoSizeMode::Right, Value::Bool(true) => AutoSizeMode::Left, _ => AutoSizeMode::None, }, diff --git a/core/src/avm1/globals/text_format.rs b/core/src/avm1/globals/text_format.rs index 706a9c70d..4b95aad6e 100644 --- a/core/src/avm1/globals/text_format.rs +++ b/core/src/avm1/globals/text_format.rs @@ -2,8 +2,8 @@ use crate::avm1::activation::Activation; use crate::avm1::error::Error; -use crate::avm1::{Object, ScriptObject, TObject, UpdateContext, Value}; -use gc_arena::{Gc, MutationContext}; +use crate::avm1::{Avm1String, Object, ScriptObject, TObject, UpdateContext, Value}; +use gc_arena::MutationContext; fn map_defined_to_string<'gc>( name: &str, @@ -16,7 +16,7 @@ fn map_defined_to_string<'gc>( Some(Value::Undefined) => Value::Null, Some(Value::Null) => Value::Null, None => Value::Null, - Some(v) => Gc::allocate( + Some(v) => Avm1String::new( ac.gc_context, v.coerce_to_string(activation, ac)?.to_string(), ) diff --git a/core/src/avm1/globals/xml.rs b/core/src/avm1/globals/xml.rs index aba5557a5..d1187b1f5 100644 --- a/core/src/avm1/globals/xml.rs +++ b/core/src/avm1/globals/xml.rs @@ -6,12 +6,12 @@ use crate::avm1::function::Executable; use crate::avm1::object::script_object::ScriptObject; use crate::avm1::object::xml_object::XMLObject; use crate::avm1::property::Attribute::*; -use crate::avm1::{Object, TObject, UpdateContext, Value}; +use crate::avm1::{Avm1String, Object, TObject, UpdateContext, Value}; use crate::backend::navigator::RequestOptions; use crate::xml; use crate::xml::{XMLDocument, XMLNode}; use enumset::EnumSet; -use gc_arena::{Gc, MutationContext}; +use gc_arena::MutationContext; use quick_xml::Error as ParseError; use std::borrow::Cow; @@ -156,7 +156,7 @@ pub fn xmlnode_get_namespace_for_prefix<'gc>( args.get(0).map(|v| v.coerce_to_string(activation, ac)), ) { if let Some(uri) = xmlnode.lookup_uri_for_namespace(&prefix_string?) { - Ok(Gc::allocate(ac.gc_context, uri).into()) + Ok(Avm1String::new(ac.gc_context, uri).into()) } else { Ok(Value::Null) } @@ -176,7 +176,7 @@ pub fn xmlnode_get_prefix_for_namespace<'gc>( args.get(0).map(|v| v.coerce_to_string(activation, ac)), ) { if let Some(prefix) = xmlnode.lookup_namespace_for_uri(&uri_string?) { - Ok(Gc::allocate(ac.gc_context, prefix).into()) + Ok(Avm1String::new(ac.gc_context, prefix).into()) } else { Ok(Value::Null) } @@ -224,7 +224,7 @@ pub fn xmlnode_to_string<'gc>( if let Some(node) = this.as_xml_node() { let result = node.into_string(&mut is_as2_compatible); - return Ok(Gc::allocate( + return Ok(Avm1String::new( ac.gc_context, result.unwrap_or_else(|e| { log::warn!("XMLNode toString failed: {}", e); @@ -234,7 +234,7 @@ pub fn xmlnode_to_string<'gc>( .into()); } - Ok(Gc::allocate(ac.gc_context, "".to_string()).into()) + Ok(Avm1String::new(ac.gc_context, "".to_string()).into()) } pub fn xmlnode_local_name<'gc>( @@ -246,7 +246,7 @@ pub fn xmlnode_local_name<'gc>( Ok(this .as_xml_node() .and_then(|n| n.tag_name()) - .map(|n| Gc::allocate(ac.gc_context, n.local_name().to_string()).into()) + .map(|n| Avm1String::new(ac.gc_context, n.local_name().to_string()).into()) .unwrap_or_else(|| Value::Null)) } @@ -259,7 +259,7 @@ pub fn xmlnode_node_name<'gc>( Ok(this .as_xml_node() .and_then(|n| n.tag_name()) - .map(|n| Gc::allocate(ac.gc_context, n.node_name().to_string()).into()) + .map(|n| Avm1String::new(ac.gc_context, n.node_name().to_string()).into()) .unwrap_or_else(|| Value::Null)) } @@ -292,7 +292,7 @@ pub fn xmlnode_node_value<'gc>( Ok(this .as_xml_node() .and_then(|n| n.node_value()) - .map(|n| Gc::allocate(ac.gc_context, n).into()) + .map(|n| Avm1String::new(ac.gc_context, n).into()) .unwrap_or_else(|| Value::Null)) } @@ -306,7 +306,7 @@ pub fn xmlnode_prefix<'gc>( .as_xml_node() .and_then(|n| n.tag_name()) .map(|n| { - Gc::allocate( + Avm1String::new( ac.gc_context, n.prefix() .map(|n| n.to_string()) @@ -493,7 +493,7 @@ pub fn xmlnode_namespace_uri<'gc>( ) -> Result, Error<'gc>> { if let Some(node) = this.as_xml_node() { if let Some(name) = node.tag_name() { - return Ok(Gc::allocate( + return Ok(Avm1String::new( ac.gc_context, node.lookup_uri_for_namespace(name.prefix().unwrap_or("")) .unwrap_or_else(|| "".to_string()), @@ -861,7 +861,7 @@ pub fn xml_on_data<'gc>( let src = src.coerce_to_string(activation, ac)?; this.call_method( "parseXML", - &[Gc::allocate(ac.gc_context, src.to_string()).into()], + &[Avm1String::new(ac.gc_context, src.to_string()).into()], activation, ac, )?; @@ -884,7 +884,7 @@ pub fn xml_doc_type_decl<'gc>( if let Some(doctype) = node.document().doctype() { let result = doctype.into_string(&mut |_| true); - return Ok(Gc::allocate( + return Ok(Avm1String::new( ac.gc_context, result.unwrap_or_else(|e| { log::warn!("Error occured when serializing DOCTYPE: {}", e); @@ -910,7 +910,7 @@ pub fn xml_xml_decl<'gc>( if let Err(e) = result { log::warn!("Could not generate XML declaration for document: {}", e); } else if let Ok(Some(result_str)) = result { - return Ok(Gc::allocate(ac.gc_context, result_str).into()); + return Ok(Avm1String::new(ac.gc_context, result_str).into()); } } diff --git a/core/src/avm1/object/script_object.rs b/core/src/avm1/object/script_object.rs index 828b1d6fb..5f0992ca2 100644 --- a/core/src/avm1/object/script_object.rs +++ b/core/src/avm1/object/script_object.rs @@ -2,11 +2,11 @@ use crate::avm1::activation::Activation; use crate::avm1::error::Error; use crate::avm1::function::{Executable, ExecutionReason, FunctionObject, NativeFunction}; use crate::avm1::property::{Attribute, Property}; -use crate::avm1::{Object, ObjectPtr, TObject, UpdateContext, Value}; +use crate::avm1::{Avm1String, Object, ObjectPtr, TObject, UpdateContext, Value}; use crate::property_map::{Entry, PropertyMap}; use core::fmt; use enumset::EnumSet; -use gc_arena::{Collect, Gc, GcCell, MutationContext}; +use gc_arena::{Collect, GcCell, MutationContext}; use std::borrow::Cow; pub const TYPE_OF_OBJECT: &str = "object"; @@ -45,7 +45,7 @@ impl<'gc> Watcher<'gc> { base_proto: Option>, ) -> Result, crate::avm1::error::Error<'gc>> { let args = [ - Value::String(Gc::allocate(context.gc_context, name.to_string())), + Value::String(Avm1String::new(context.gc_context, name.to_string())), old_value, new_value, self.user_data.clone(), @@ -853,7 +853,7 @@ mod tests { use crate::avm1::activation::ActivationIdentifier; use crate::avm1::globals::system::SystemProperties; use crate::avm1::property::Attribute::*; - use crate::avm1::{Avm1, Timers}; + use crate::avm1::{Avm1, Avm1String, Timers}; use crate::backend::audio::NullAudioBackend; use crate::backend::input::NullInputBackend; use crate::backend::navigator::NullNavigatorBackend; @@ -864,7 +864,7 @@ mod tests { use crate::loader::LoadManager; use crate::prelude::*; use crate::tag_utils::{SwfMovie, SwfSlice}; - use gc_arena::{rootless_arena, Gc}; + use gc_arena::rootless_arena; use rand::{rngs::SmallRng, SeedableRng}; use std::collections::{BTreeMap, HashMap}; use std::sync::Arc; @@ -955,13 +955,13 @@ mod tests { object.as_script_object().unwrap().define_value( context.gc_context, "forced", - Gc::allocate(context.gc_context, "forced".to_string()).into(), + Avm1String::new(context.gc_context, "forced".to_string()).into(), EnumSet::empty(), ); object .set( "natural", - Gc::allocate(context.gc_context, "natural".to_string()).into(), + Avm1String::new(context.gc_context, "natural".to_string()).into(), activation, context, ) @@ -969,11 +969,11 @@ mod tests { assert_eq!( object.get("forced", activation, context).unwrap(), - Gc::allocate(context.gc_context, "forced".to_string()).into() + Avm1String::new(context.gc_context, "forced".to_string()).into() ); assert_eq!( object.get("natural", activation, context).unwrap(), - Gc::allocate(context.gc_context, "natural".to_string()).into() + Avm1String::new(context.gc_context, "natural".to_string()).into() ); }) } @@ -984,20 +984,20 @@ mod tests { object.as_script_object().unwrap().define_value( context.gc_context, "normal", - Gc::allocate(context.gc_context, "initial".to_string()).into(), + Avm1String::new(context.gc_context, "initial".to_string()).into(), EnumSet::empty(), ); object.as_script_object().unwrap().define_value( context.gc_context, "readonly", - Gc::allocate(context.gc_context, "initial".to_string()).into(), + Avm1String::new(context.gc_context, "initial".to_string()).into(), ReadOnly.into(), ); object .set( "normal", - Gc::allocate(context.gc_context, "replaced".to_string()).into(), + Avm1String::new(context.gc_context, "replaced".to_string()).into(), activation, context, ) @@ -1005,7 +1005,7 @@ mod tests { object .set( "readonly", - Gc::allocate(context.gc_context, "replaced".to_string()).into(), + Avm1String::new(context.gc_context, "replaced".to_string()).into(), activation, context, ) @@ -1013,11 +1013,11 @@ mod tests { assert_eq!( object.get("normal", activation, context).unwrap(), - Gc::allocate(context.gc_context, "replaced".to_string()).into() + Avm1String::new(context.gc_context, "replaced".to_string()).into() ); assert_eq!( object.get("readonly", activation, context).unwrap(), - Gc::allocate(context.gc_context, "initial".to_string()).into() + Avm1String::new(context.gc_context, "initial".to_string()).into() ); }) } @@ -1028,14 +1028,14 @@ mod tests { object.as_script_object().unwrap().define_value( context.gc_context, "test", - Gc::allocate(context.gc_context, "initial".to_string()).into(), + Avm1String::new(context.gc_context, "initial".to_string()).into(), DontDelete.into(), ); assert_eq!(object.delete(activation, context.gc_context, "test"), false); assert_eq!( object.get("test", activation, context).unwrap(), - Gc::allocate(context.gc_context, "initial".to_string()).into() + Avm1String::new(context.gc_context, "initial".to_string()).into() ); object @@ -1043,7 +1043,7 @@ mod tests { .unwrap() .set( "test", - Gc::allocate(context.gc_context, "replaced".to_string()).into(), + Avm1String::new(context.gc_context, "replaced".to_string()).into(), activation, context, ) @@ -1052,7 +1052,7 @@ mod tests { assert_eq!(object.delete(activation, context.gc_context, "test"), false); assert_eq!( object.get("test", activation, context).unwrap(), - Gc::allocate(context.gc_context, "replaced".to_string()).into() + Avm1String::new(context.gc_context, "replaced".to_string()).into() ); }) } @@ -1061,7 +1061,7 @@ mod tests { fn test_virtual_get() { with_object(0, |activation, context, object| { let getter = Executable::Native(|_avm, context, _this, _args| { - Ok(Gc::allocate(context.gc_context, "Virtual!".to_string()).into()) + Ok(Avm1String::new(context.gc_context, "Virtual!".to_string()).into()) }); object.as_script_object().unwrap().add_property( @@ -1074,21 +1074,21 @@ mod tests { assert_eq!( object.get("test", activation, context).unwrap(), - Gc::allocate(context.gc_context, "Virtual!".to_string()).into() + Avm1String::new(context.gc_context, "Virtual!".to_string()).into() ); // This set should do nothing object .set( "test", - Gc::allocate(context.gc_context, "Ignored!".to_string()).into(), + Avm1String::new(context.gc_context, "Ignored!".to_string()).into(), activation, context, ) .unwrap(); assert_eq!( object.get("test", activation, context).unwrap(), - Gc::allocate(context.gc_context, "Virtual!".to_string()).into() + Avm1String::new(context.gc_context, "Virtual!".to_string()).into() ); }) } @@ -1097,7 +1097,7 @@ mod tests { fn test_delete() { with_object(0, |activation, context, object| { let getter = Executable::Native(|_avm, context, _this, _args| { - Ok(Gc::allocate(context.gc_context, "Virtual!".to_string()).into()) + Ok(Avm1String::new(context.gc_context, "Virtual!".to_string()).into()) }); object.as_script_object().unwrap().add_property( @@ -1117,13 +1117,13 @@ mod tests { object.as_script_object().unwrap().define_value( context.gc_context, "stored", - Gc::allocate(context.gc_context, "Stored!".to_string()).into(), + Avm1String::new(context.gc_context, "Stored!".to_string()).into(), EnumSet::empty(), ); object.as_script_object().unwrap().define_value( context.gc_context, "stored_un", - Gc::allocate(context.gc_context, "Stored!".to_string()).into(), + Avm1String::new(context.gc_context, "Stored!".to_string()).into(), DontDelete.into(), ); @@ -1154,7 +1154,7 @@ mod tests { ); assert_eq!( object.get("virtual_un", activation, context).unwrap(), - Gc::allocate(context.gc_context, "Virtual!".to_string()).into() + Avm1String::new(context.gc_context, "Virtual!".to_string()).into() ); assert_eq!( object.get("stored", activation, context).unwrap(), @@ -1162,7 +1162,7 @@ mod tests { ); assert_eq!( object.get("stored_un", activation, context).unwrap(), - Gc::allocate(context.gc_context, "Stored!".to_string()).into() + Avm1String::new(context.gc_context, "Stored!".to_string()).into() ); }) } diff --git a/core/src/avm1/object/stage_object.rs b/core/src/avm1/object/stage_object.rs index 3d9b62b4f..4ddfa7cad 100644 --- a/core/src/avm1/object/stage_object.rs +++ b/core/src/avm1/object/stage_object.rs @@ -5,12 +5,12 @@ use crate::avm1::error::Error; use crate::avm1::function::Executable; use crate::avm1::object::search_prototype; use crate::avm1::property::Attribute; -use crate::avm1::{Object, ObjectPtr, ScriptObject, TDisplayObject, TObject, Value}; +use crate::avm1::{Avm1String, Object, ObjectPtr, ScriptObject, TDisplayObject, TObject, Value}; use crate::context::UpdateContext; use crate::display_object::{DisplayObject, EditText, MovieClip}; use crate::property_map::PropertyMap; use enumset::EnumSet; -use gc_arena::{Collect, Gc, GcCell, MutationContext}; +use gc_arena::{Collect, GcCell, MutationContext}; use std::borrow::Cow; use std::fmt; @@ -853,7 +853,7 @@ fn target<'gc>( context: &mut UpdateContext<'_, 'gc, '_>, this: DisplayObject<'gc>, ) -> Result, Error<'gc>> { - Ok(Gc::allocate(context.gc_context, this.slash_path()).into()) + Ok(Avm1String::new(context.gc_context, this.slash_path()).into()) } fn frames_loaded<'gc>( @@ -873,7 +873,7 @@ fn name<'gc>( context: &mut UpdateContext<'_, 'gc, '_>, this: DisplayObject<'gc>, ) -> Result, Error<'gc>> { - Ok(Gc::allocate(context.gc_context, this.name().to_string()).into()) + Ok(Avm1String::new(context.gc_context, this.name().to_string()).into()) } fn set_name<'gc>( @@ -893,7 +893,7 @@ fn drop_target<'gc>( _this: DisplayObject<'gc>, ) -> Result, Error<'gc>> { log::warn!("Unimplemented property _droptarget"); - Ok(Gc::allocate(context.gc_context, "".to_string()).into()) + Ok(Avm1String::new(context.gc_context, "".to_string()).into()) } fn url<'gc>( @@ -902,7 +902,7 @@ fn url<'gc>( _this: DisplayObject<'gc>, ) -> Result, Error<'gc>> { log::warn!("Unimplemented property _url"); - Ok(Gc::allocate(context.gc_context, "".to_string()).into()) + Ok(Avm1String::new(context.gc_context, "".to_string()).into()) } fn high_quality<'gc>( @@ -968,7 +968,7 @@ fn quality<'gc>( _this: DisplayObject<'gc>, ) -> Result, Error<'gc>> { log::warn!("Unimplemented property _quality"); - Ok(Gc::allocate(context.gc_context, "HIGH".to_string()).into()) + Ok(Avm1String::new(context.gc_context, "HIGH".to_string()).into()) } fn set_quality<'gc>( diff --git a/core/src/avm1/object/xml_attributes_object.rs b/core/src/avm1/object/xml_attributes_object.rs index d5c8e311a..d94dcd6f2 100644 --- a/core/src/avm1/object/xml_attributes_object.rs +++ b/core/src/avm1/object/xml_attributes_object.rs @@ -5,10 +5,10 @@ use crate::avm1::error::Error; use crate::avm1::function::Executable; use crate::avm1::object::{ObjectPtr, TObject}; use crate::avm1::property::Attribute; -use crate::avm1::{Object, ScriptObject, UpdateContext, Value}; +use crate::avm1::{Avm1String, Object, ScriptObject, UpdateContext, Value}; use crate::xml::{XMLName, XMLNode}; use enumset::EnumSet; -use gc_arena::{Collect, Gc, MutationContext}; +use gc_arena::{Collect, MutationContext}; use std::borrow::Cow; use std::fmt; @@ -67,7 +67,7 @@ impl<'gc> TObject<'gc> for XMLAttributesObject<'gc> { Ok(self .node() .attribute_value(&XMLName::from_str(name)) - .map(|s| Gc::allocate(context.gc_context, s).into()) + .map(|s| Avm1String::new(context.gc_context, s).into()) .unwrap_or_else(|| Value::Undefined)) } diff --git a/core/src/avm1/string.rs b/core/src/avm1/string.rs new file mode 100644 index 000000000..f13947fa5 --- /dev/null +++ b/core/src/avm1/string.rs @@ -0,0 +1,56 @@ +use gc_arena::{Collect, Gc, MutationContext}; +use std::ops::Deref; + +#[derive(Debug, Clone, Collect)] +#[collect(no_drop)] +pub struct Avm1String<'gc>(Gc<'gc, String>); + +impl<'gc> Avm1String<'gc> { + pub fn new>(gc_context: MutationContext<'gc, '_>, string: S) -> Self { + Self(Gc::allocate(gc_context, string.into())) + } + + pub fn as_str(&self) -> &str { + self + } +} + +impl Deref for Avm1String<'_> { + type Target = str; + + #[inline] + fn deref(&self) -> &str { + self.0.deref() + } +} + +impl AsRef for Avm1String<'_> { + #[inline] + fn as_ref(&self) -> &str { + self + } +} + +macro_rules! impl_eq { + ($lhs:ty, $rhs: ty) => { + #[allow(unused_lifetimes)] + impl<'a, 'b> PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + PartialEq::eq(&self[..], &other[..]) + } + } + + #[allow(unused_lifetimes)] + impl<'a, 'b> PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { + PartialEq::eq(&self[..], &other[..]) + } + } + }; +} + +impl_eq! { Avm1String<'_>, str } +impl_eq! { Avm1String<'_>, &'a str } +impl_eq! { Avm1String<'_>, String } diff --git a/core/src/avm1/tests.rs b/core/src/avm1/tests.rs index 91cbd51a7..8ac8e3f2e 100644 --- a/core/src/avm1/tests.rs +++ b/core/src/avm1/tests.rs @@ -1,7 +1,6 @@ use crate::avm1::error::Error; use crate::avm1::test_utils::with_avm; -use crate::avm1::TObject; -use gc_arena::Gc; +use crate::avm1::{Avm1String, TObject}; #[test] fn locals_into_form_values() { @@ -10,7 +9,7 @@ fn locals_into_form_values() { my_locals .set( "value1", - Gc::allocate(context.gc_context, "string".to_string()).into(), + Avm1String::new(context.gc_context, "string".to_string()).into(), activation, context, ) diff --git a/core/src/avm1/value.rs b/core/src/avm1/value.rs index c84246abd..61562180c 100644 --- a/core/src/avm1/value.rs +++ b/core/src/avm1/value.rs @@ -1,8 +1,7 @@ use crate::avm1::activation::Activation; use crate::avm1::error::Error; use crate::avm1::object::value_object::ValueObject; -use crate::avm1::{Object, TObject, UpdateContext}; -use gc_arena::Gc; +use crate::avm1::{Avm1String, Object, TObject, UpdateContext}; use std::borrow::Cow; use std::f64::NAN; @@ -13,12 +12,12 @@ pub enum Value<'gc> { Null, Bool(bool), Number(f64), - String(Gc<'gc, String>), + String(Avm1String<'gc>), Object(Object<'gc>), } -impl<'gc> From> for Value<'gc> { - fn from(string: Gc<'gc, String>) -> Self { +impl<'gc> From> for Value<'gc> { + fn from(string: Avm1String<'gc>) -> Self { Value::String(string) } } @@ -596,10 +595,9 @@ mod test { use crate::avm1::object::script_object::ScriptObject; use crate::avm1::object::{Object, TObject}; use crate::avm1::test_utils::with_avm; - use crate::avm1::Value; + use crate::avm1::{Avm1String, Value}; use crate::context::UpdateContext; use enumset::EnumSet; - use gc_arena::Gc; use std::f64::{INFINITY, NAN, NEG_INFINITY}; #[test] @@ -792,8 +790,8 @@ mod test { #[test] fn abstract_lt_str() { with_avm(8, |activation, context, _this| -> Result<(), Error> { - let a = Value::String(Gc::allocate(context.gc_context, "a".to_owned())); - let b = Value::String(Gc::allocate(context.gc_context, "b".to_owned())); + let a = Value::String(Avm1String::new(context.gc_context, "a".to_owned())); + let b = Value::String(Avm1String::new(context.gc_context, "b".to_owned())); assert_eq!( a.abstract_lt(b, activation, context).unwrap(), @@ -807,8 +805,8 @@ mod test { #[test] fn abstract_gt_str() { with_avm(8, |activation, context, _this| -> Result<(), Error> { - let a = Value::String(Gc::allocate(context.gc_context, "a".to_owned())); - let b = Value::String(Gc::allocate(context.gc_context, "b".to_owned())); + let a = Value::String(Avm1String::new(context.gc_context, "a".to_owned())); + let b = Value::String(Avm1String::new(context.gc_context, "b".to_owned())); assert_eq!( b.abstract_lt(a, activation, context).unwrap(), diff --git a/core/src/display_object/edit_text.rs b/core/src/display_object/edit_text.rs index e217304c3..1796238c0 100644 --- a/core/src/display_object/edit_text.rs +++ b/core/src/display_object/edit_text.rs @@ -1,7 +1,7 @@ //! `EditText` display object and support code. use crate::avm1::activation::Activation; use crate::avm1::globals::text_field::attach_virtual_properties; -use crate::avm1::{Avm1, Object, StageObject, TObject, Value}; +use crate::avm1::{Avm1, Avm1String, Object, StageObject, TObject, Value}; use crate::context::{RenderContext, UpdateContext}; use crate::display_object::{DisplayObjectBase, TDisplayObject}; use crate::drawing::Drawing; @@ -743,7 +743,7 @@ impl<'gc> EditText<'gc> { if !text.is_empty() { let _ = object.set( property, - Gc::allocate(context.gc_context, self.text()).into(), + Avm1String::new(context.gc_context, self.text()).into(), activation, context, ); @@ -814,7 +814,7 @@ impl<'gc> EditText<'gc> { |activation, context| { let _ = object.set( property, - Gc::allocate(context.gc_context, text).into(), + Avm1String::new(context.gc_context, text).into(), activation, context, ); diff --git a/core/src/html/text_format.rs b/core/src/html/text_format.rs index 62e983af5..267290e17 100644 --- a/core/src/html/text_format.rs +++ b/core/src/html/text_format.rs @@ -1,11 +1,11 @@ //! Classes that store formatting options use crate::avm1::activation::Activation; -use crate::avm1::{Object, ScriptObject, TObject, Value}; +use crate::avm1::{Avm1String, Object, ScriptObject, TObject, Value}; use crate::context::UpdateContext; use crate::html::iterators::TextSpanIter; use crate::tag_utils::SwfMovie; use crate::xml::{Step, XMLDocument, XMLName, XMLNode}; -use gc_arena::{Collect, Gc, MutationContext}; +use gc_arena::{Collect, MutationContext}; use std::borrow::Cow; use std::cmp::{min, Ordering}; use std::sync::Arc; @@ -362,7 +362,7 @@ impl TextFormat { "font", self.font .clone() - .map(|v| Gc::allocate(uc.gc_context, v).into()) + .map(|v| Avm1String::new(uc.gc_context, v).into()) .unwrap_or(Value::Null), activation, uc, @@ -386,7 +386,7 @@ impl TextFormat { "align", self.align .map(|v| { - Gc::allocate( + Avm1String::new( uc.gc_context, match v { swf::TextAlign::Left => "left", @@ -472,7 +472,7 @@ impl TextFormat { "url", self.url .clone() - .map(|v| Gc::allocate(uc.gc_context, v).into()) + .map(|v| Avm1String::new(uc.gc_context, v).into()) .unwrap_or(Value::Null), activation, uc, @@ -481,7 +481,7 @@ impl TextFormat { "target", self.target .clone() - .map(|v| Gc::allocate(uc.gc_context, v).into()) + .map(|v| Avm1String::new(uc.gc_context, v).into()) .unwrap_or(Value::Null), activation, uc, diff --git a/core/src/loader.rs b/core/src/loader.rs index c04302c7a..c46a80c32 100644 --- a/core/src/loader.rs +++ b/core/src/loader.rs @@ -1,14 +1,14 @@ //! Management of async loaders use crate::avm1::activation::{Activation, ActivationIdentifier}; -use crate::avm1::{Object, TObject, Value}; +use crate::avm1::{Avm1String, Object, TObject, Value}; use crate::backend::navigator::OwnedFuture; use crate::context::{ActionQueue, ActionType}; use crate::display_object::{DisplayObject, MorphShape, TDisplayObject}; use crate::player::{Player, NEWEST_PLAYER_VERSION}; use crate::tag_utils::SwfMovie; use crate::xml::XMLNode; -use gc_arena::{Collect, CollectionContext, Gc, MutationContext}; +use gc_arena::{Collect, CollectionContext, MutationContext}; use generational_arena::{Arena, Index}; use std::string::FromUtf8Error; use std::sync::{Arc, Mutex, Weak}; @@ -323,7 +323,7 @@ impl<'gc> Loader<'gc> { uc, "broadcastMessage", &[ - Gc::allocate(uc.gc_context, "onLoadStart".to_string()).into(), + Avm1String::new(uc.gc_context, "onLoadStart".to_string()).into(), Value::Object(broadcaster), ], ); @@ -359,7 +359,7 @@ impl<'gc> Loader<'gc> { uc, "broadcastMessage", &[ - Gc::allocate(uc.gc_context, "onLoadProgress".to_string()) + Avm1String::new(uc.gc_context, "onLoadProgress".to_string()) .into(), Value::Object(broadcaster), length.into(), @@ -397,7 +397,7 @@ impl<'gc> Loader<'gc> { uc, "broadcastMessage", &[ - Gc::allocate(uc.gc_context, "onLoadComplete".to_string()) + Avm1String::new(uc.gc_context, "onLoadComplete".to_string()) .into(), Value::Object(broadcaster), ], @@ -438,10 +438,14 @@ impl<'gc> Loader<'gc> { uc, "broadcastMessage", &[ - Gc::allocate(uc.gc_context, "onLoadError".to_string()).into(), - Value::Object(broadcaster), - Gc::allocate(uc.gc_context, "LoadNeverCompleted".to_string()) + Avm1String::new(uc.gc_context, "onLoadError".to_string()) .into(), + Value::Object(broadcaster), + Avm1String::new( + uc.gc_context, + "LoadNeverCompleted".to_string(), + ) + .into(), ], ); } @@ -495,7 +499,7 @@ impl<'gc> Loader<'gc> { for (k, v) in form_urlencoded::parse(&data) { that.set( &k, - Gc::allocate(uc.gc_context, v.into_owned()).into(), + Avm1String::new(uc.gc_context, v.into_owned()).into(), &mut activation, uc, )?; @@ -536,7 +540,7 @@ impl<'gc> Loader<'gc> { object: broadcaster, name: "broadcastMessage", args: vec![ - Gc::allocate(gc_context, "onLoadInit".to_string()).into(), + Avm1String::new(gc_context, "onLoadInit".to_string()).into(), clip_object.map(|co| co.into()).unwrap_or(Value::Undefined), ], }, @@ -598,7 +602,7 @@ impl<'gc> Loader<'gc> { NEWEST_PLAYER_VERSION, uc, "onData", - &[Gc::allocate(uc.gc_context, xmlstring).into()], + &[Avm1String::new(uc.gc_context, xmlstring).into()], ); Ok(()) diff --git a/core/src/player.rs b/core/src/player.rs index f4d7bdf45..49633195d 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -3,7 +3,7 @@ use crate::avm1::debug::VariableDumper; use crate::avm1::globals::system::SystemProperties; use crate::avm1::listeners::SystemListener; use crate::avm1::object::Object; -use crate::avm1::{Avm1, TObject, Timers, Value}; +use crate::avm1::{Avm1, Avm1String, TObject, Timers, Value}; use crate::backend::input::{InputBackend, MouseCursor}; use crate::backend::storage::StorageBackend; use crate::backend::{ @@ -18,7 +18,7 @@ use crate::prelude::*; use crate::tag_utils::SwfMovie; use crate::transform::TransformStack; use enumset::EnumSet; -use gc_arena::{make_arena, ArenaParameters, Collect, Gc, GcCell}; +use gc_arena::{make_arena, ArenaParameters, Collect, GcCell}; use log::info; use rand::{rngs::SmallRng, SeedableRng}; use std::collections::{BTreeMap, HashMap}; @@ -292,7 +292,7 @@ impl Player { object.define_value( context.gc_context, "$version", - Gc::allocate( + Avm1String::new( context.gc_context, context.system.get_version_string(&mut activation), )