Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core/avm1/avm2: Remove some static AvmStrings #19272

Merged
merged 7 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/src/avm1/globals/bevel_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ fn method<'gc>(
}
GET_TYPE => {
let type_: &WStr = this.type_().into();
AvmString::from(type_).into()
AvmString::from_static_wstr(activation.gc(), type_).into()
}
SET_TYPE => {
this.set_type(activation, args.get(0))?;
Expand Down
2 changes: 1 addition & 1 deletion core/src/avm1/globals/displacement_map_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ fn method<'gc>(
}
GET_MODE => {
let mode: &WStr = this.mode().into();
AvmString::from(mode).into()
AvmString::from_static_wstr(activation.gc(), mode).into()
}
SET_MODE => {
this.set_mode(activation, args.get(0))?;
Expand Down
2 changes: 1 addition & 1 deletion core/src/avm1/globals/gradient_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ fn method<'gc>(
}
GET_TYPE => {
let type_: &WStr = this.type_().into();
AvmString::from(type_).into()
AvmString::from_static_wstr(activation.gc(), type_).into()
}
SET_TYPE => {
this.set_type(activation, args.get(0))?;
Expand Down
2 changes: 1 addition & 1 deletion core/src/avm1/globals/selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub fn get_focus<'gc>(
.as_displayobject()
.object()
.coerce_to_string(activation)
.unwrap_or_default()
.unwrap_or_else(|_| activation.strings().empty())
.into(),
None => Value::Null,
})
Expand Down
8 changes: 5 additions & 3 deletions core/src/avm1/object/stage_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
// Button/MovieClip children are included in key list.
for child in ctr.iter_render_list().rev() {
if child.as_interactive().is_some() {
keys.push(child.name());
keys.push(child.name().expect("Interactive DisplayObjects have names"));
}
}
}
Expand Down Expand Up @@ -657,8 +657,10 @@ fn frames_loaded<'gc>(
.map_or(Value::Undefined, Value::from)
}

fn name<'gc>(_activation: &mut Activation<'_, 'gc>, this: DisplayObject<'gc>) -> Value<'gc> {
this.name().into()
fn name<'gc>(activation: &mut Activation<'_, 'gc>, this: DisplayObject<'gc>) -> Value<'gc> {
this.name()
.unwrap_or_else(|| activation.strings().empty())
.into()
}

fn set_name<'gc>(
Expand Down
13 changes: 4 additions & 9 deletions core/src/avm2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ use self::api_version::ApiVersion;
use self::object::WeakObject;
use self::scope::Scope;

const BROADCAST_WHITELIST: [&str; 4] = ["enterFrame", "exitFrame", "frameConstructed", "render"];
const BROADCAST_WHITELIST: [&[u8]; 4] =
[b"enterFrame", b"exitFrame", b"frameConstructed", b"render"];

const PREALLOCATED_STACK_SIZE: usize = 120000;

Expand Down Expand Up @@ -483,10 +484,7 @@ impl<'gc> Avm2<'gc> {
object: Object<'gc>,
event_name: AvmString<'gc>,
) {
if !BROADCAST_WHITELIST
.iter()
.any(|x| AvmString::from(*x) == event_name)
{
if !BROADCAST_WHITELIST.iter().any(|x| *x == &event_name) {
return;
}

Expand Down Expand Up @@ -521,10 +519,7 @@ impl<'gc> Avm2<'gc> {
) {
let event_name = event.event().event_type();

if !BROADCAST_WHITELIST
.iter()
.any(|x| AvmString::from(*x) == event_name)
{
if !BROADCAST_WHITELIST.iter().any(|x| *x == &event_name) {
return;
}

Expand Down
22 changes: 14 additions & 8 deletions core/src/avm2/e4x.rs
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,7 @@ impl<'gc> E4XNode<'gc> {
) -> Result<Vec<Self>, Error<'gc>> {
let string = match &value {
// The docs claim that this throws a TypeError, but it actually doesn't
Value::Null | Value::Undefined => AvmString::default(),
Value::Null | Value::Undefined => activation.strings().empty(),
// The docs claim that only String, Number or Boolean are accepted, but that's also a lie
val => {
if let Some(obj) = val.as_object() {
Expand Down Expand Up @@ -962,7 +962,7 @@ impl<'gc> E4XNode<'gc> {
} else {
(
AvmString::new_utf8_bytes(activation.gc(), text.as_bytes()),
AvmString::default(),
activation.strings().empty(),
)
};
let node = E4XNode(GcCell::new(
Expand Down Expand Up @@ -1312,16 +1312,22 @@ impl<'gc> E4XNode<'gc> {
return true;
}

let self_ns = self.namespace().map(|ns| ns.uri).unwrap_or_default();
let self_ns = self.namespace().map(|ns| ns.uri);
// FIXME: For cases where we don't have *any* explicit namespace
// we just give up and assume we should match the default public namespace.
if !name.namespace_set().iter().any(|ns| ns.is_namespace()) {
return self_ns.is_empty();
return self_ns.is_none_or(|n| n.is_empty());
}

name.namespace_set()
.iter()
.any(|ns| ns.as_uri_opt().expect("NS set cannot contain Any") == self_ns)
name.namespace_set().iter().any(|ns| {
let uri = ns.as_uri_opt().expect("NS set cannot contain Any");

if let Some(self_ns) = self_ns {
uri == self_ns
} else {
uri.is_empty()
}
})
}

pub fn descendants(&self, name: &Multiname<'gc>, out: &mut Vec<E4XOrXml<'gc>>) {
Expand Down Expand Up @@ -1412,7 +1418,7 @@ pub fn simple_content_to_string<'gc>(
children: impl Iterator<Item = E4XOrXml<'gc>>,
activation: &mut Activation<'_, 'gc>,
) -> AvmString<'gc> {
let mut out = AvmString::default();
let mut out = activation.strings().empty();
for child in children {
if matches!(
&*child.node().kind(),
Expand Down
39 changes: 15 additions & 24 deletions core/src/avm2/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,7 @@ pub struct Event<'gc> {

impl<'gc> Event<'gc> {
/// Construct a new event of a given type.
pub fn new<S>(event_type: S) -> Self
where
S: Into<AvmString<'gc>>,
{
pub fn new(event_type: AvmString<'gc>) -> Self {
Event {
bubbles: false,
cancelable: false,
Expand All @@ -88,19 +85,16 @@ impl<'gc> Event<'gc> {
current_target: None,
event_phase: EventPhase::AtTarget,
target: None,
event_type: event_type.into(),
event_type,
}
}

pub fn event_type(&self) -> AvmString<'gc> {
self.event_type
}

pub fn set_event_type<S>(&mut self, event_type: S)
where
S: Into<AvmString<'gc>>,
{
self.event_type = event_type.into();
pub fn set_event_type(&mut self, event_type: AvmString<'gc>) {
self.event_type = event_type;
}

pub fn is_bubbling(&self) -> bool {
Expand Down Expand Up @@ -185,11 +179,8 @@ impl<'gc> DispatchList<'gc> {

/// Get all of the event handlers for a given event type, if such a type
/// exists.
fn get_event(
&self,
event: impl Into<AvmString<'gc>>,
) -> Option<&BTreeMap<i32, Vec<EventHandler<'gc>>>> {
self.0.get(&event.into())
fn get_event(&self, event: AvmString<'gc>) -> Option<&BTreeMap<i32, Vec<EventHandler<'gc>>>> {
self.0.get(&event)
}

/// Get all of the event handlers for a given event type, for mutation.
Expand All @@ -198,20 +189,20 @@ impl<'gc> DispatchList<'gc> {
/// list.
fn get_event_mut(
&mut self,
event: impl Into<AvmString<'gc>>,
event: AvmString<'gc>,
) -> &mut BTreeMap<i32, Vec<EventHandler<'gc>>> {
self.0.entry(event.into()).or_default()
self.0.entry(event).or_default()
}

/// Get a single priority level of event handlers for a given event type,
/// for mutation.
fn get_event_priority_mut(
&mut self,
event: impl Into<AvmString<'gc>>,
event: AvmString<'gc>,
priority: i32,
) -> &mut Vec<EventHandler<'gc>> {
self.0
.entry(event.into())
.entry(event)
.or_default()
.entry(priority)
.or_default()
Expand All @@ -225,14 +216,14 @@ impl<'gc> DispatchList<'gc> {
/// be added again, and this function will silently fail.
pub fn add_event_listener(
&mut self,
event: impl Into<AvmString<'gc>> + Clone,
event: AvmString<'gc>,
priority: i32,
handler: Object<'gc>,
use_capture: bool,
) {
let new_handler = EventHandler::new(handler, use_capture);

if let Some(event_sheaf) = self.get_event(event.clone()) {
if let Some(event_sheaf) = self.get_event(event) {
for (_other_prio, other_set) in event_sheaf.iter() {
if other_set.contains(&new_handler) {
return;
Expand All @@ -250,7 +241,7 @@ impl<'gc> DispatchList<'gc> {
/// removed from any priority in the list.
pub fn remove_event_listener(
&mut self,
event: impl Into<AvmString<'gc>>,
event: AvmString<'gc>,
handler: Object<'gc>,
use_capture: bool,
) {
Expand All @@ -264,7 +255,7 @@ impl<'gc> DispatchList<'gc> {
}

/// Determine if there are any event listeners in this dispatch list.
pub fn has_event_listener(&self, event: impl Into<AvmString<'gc>>) -> bool {
pub fn has_event_listener(&self, event: AvmString<'gc>) -> bool {
if let Some(event_sheaf) = self.get_event(event) {
for (_prio, set) in event_sheaf.iter() {
if !set.is_empty() {
Expand All @@ -286,7 +277,7 @@ impl<'gc> DispatchList<'gc> {
/// phases.
pub fn iter_event_handlers<'a>(
&'a mut self,
event: impl Into<AvmString<'gc>>,
event: AvmString<'gc>,
use_capture: bool,
) -> impl 'a + Iterator<Item = Object<'gc>> {
self.get_event_mut(event)
Expand Down
23 changes: 19 additions & 4 deletions core/src/avm2/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::avm2::traits::Trait;
use crate::avm2::value::Value;
use crate::avm2::vtable::VTable;
use crate::avm2::{Avm2, Error, Multiname, Namespace, QName};
use crate::string::WStr;
use crate::tag_utils::{self, ControlFlow, SwfMovie, SwfSlice, SwfStream};
use gc_arena::Collect;
use std::sync::Arc;
Expand Down Expand Up @@ -812,9 +813,16 @@ macro_rules! avm2_system_classes_playerglobal {
($activation:expr, [$(($package:expr, $class_name:expr, $field:ident)),* $(,)?]) => {
let activation = $activation;
$(
// Package and class names are ASCII
let package = WStr::from_units($package.as_bytes());
let class_name = WStr::from_units($class_name.as_bytes());

let package = activation.strings().intern_static(package);
let class_name = activation.strings().intern_static(class_name);

// Lookup with the highest version, so we we see all defined classes here
let ns = Namespace::package($package, ApiVersion::VM_INTERNAL, activation.strings());
let name = QName::new(ns, $class_name);
let ns = Namespace::package(package, ApiVersion::VM_INTERNAL, activation.strings());
let name = QName::new(ns, class_name);
let class_object = activation.domain().get_defined_value(activation, name).unwrap_or_else(|e| panic!("Failed to lookup {name:?}: {e:?}"));
let class_object = class_object.as_object().unwrap().as_class_object().unwrap();
let sc = activation.avm2().system_classes.as_mut().unwrap();
Expand All @@ -827,11 +835,18 @@ macro_rules! avm2_system_class_defs_playerglobal {
($activation:expr, [$(($package:expr, $class_name:expr, $field:ident)),* $(,)?]) => {
let activation = $activation;
$(
// Package and class names are ASCII
let package = WStr::from_units($package.as_bytes());
let class_name = WStr::from_units($class_name.as_bytes());

let package = activation.strings().intern_static(package);
let class_name = activation.strings().intern_static(class_name);

let domain = activation.domain();

// Lookup with the highest version, so we we see all defined classes here
let ns = Namespace::package($package, ApiVersion::VM_INTERNAL, activation.strings());
let name = Multiname::new(ns, $class_name);
let ns = Namespace::package(package, ApiVersion::VM_INTERNAL, activation.strings());
let name = Multiname::new(ns, class_name);
let class_def = domain.get_class(activation.context, &name).unwrap_or_else(|| panic!("Failed to lookup {name:?}"));
let sc = activation.avm2().system_class_defs.as_mut().unwrap();
sc.$field = class_def;
Expand Down
8 changes: 6 additions & 2 deletions core/src/avm2/globals/flash/display/bitmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::avm2::globals::flash::display::display_object::initialize_for_allocat
use crate::avm2::object::{BitmapDataObject, ClassObject, Object, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::string::AvmString;
use ruffle_render::bitmap::PixelSnapping;
use ruffle_wstr::WStr;

Expand Down Expand Up @@ -156,15 +157,18 @@ pub fn set_bitmap_data<'gc>(

/// Stub `Bitmap.pixelSnapping`'s getter
pub fn get_pixel_snapping<'gc>(
_activation: &mut Activation<'_, 'gc>,
activation: &mut Activation<'_, 'gc>,
this: Value<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this.as_object().unwrap();

if let Some(bitmap) = this.as_display_object().and_then(|dobj| dobj.as_bitmap()) {
let value: &WStr = bitmap.pixel_snapping().into();
return Ok(Value::String(value.into()));
return Ok(Value::String(AvmString::from_static_wstr(
activation.gc(),
value,
)));
}
Ok(Value::Undefined)
}
Expand Down
7 changes: 5 additions & 2 deletions core/src/avm2/globals/flash/display/display_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -542,14 +542,17 @@ pub fn set_rotation<'gc>(

/// Implements `name`'s getter.
pub fn get_name<'gc>(
_activation: &mut Activation<'_, 'gc>,
activation: &mut Activation<'_, 'gc>,
this: Value<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this.as_object().unwrap();

if let Some(dobj) = this.as_display_object() {
return Ok(dobj.name().into());
return Ok(dobj
.name()
.unwrap_or_else(|| activation.strings().empty())
.into());
}

Ok(Value::Undefined)
Expand Down
6 changes: 3 additions & 3 deletions core/src/avm2/globals/q_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ pub fn q_name_constructor<'gc>(
};

if let Value::Object(Object::QNameObject(qname)) = local_arg {
this.set_local_name(activation.gc(), qname.local_name());
this.set_local_name(activation.gc(), qname.local_name(activation.strings()));
} else {
this.set_local_name(activation.gc(), local_arg.coerce_to_string(activation)?);
}
Expand Down Expand Up @@ -102,14 +102,14 @@ pub fn q_name_constructor<'gc>(

/// Implements `QName.localName`'s getter
pub fn get_local_name<'gc>(
_activation: &mut Activation<'_, 'gc>,
activation: &mut Activation<'_, 'gc>,
this: Value<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this.as_object().unwrap();

if let Some(this) = this.as_qname_object() {
return Ok(this.local_name().into());
return Ok(this.local_name(activation.strings()).into());
}

Ok(Value::Undefined)
Expand Down
Loading