Skip to content

Commit

Permalink
avm1: Don't use a static AvmString for AVM1 array's length property
Browse files Browse the repository at this point in the history
`ArrayObject` construction now requires an activation, so add
`ArrayObjectBuilder` to simplify the process: it allows grabbing what we need
from the activation (the interned `length` property name, and the array
prototype) without running afoul of the borrow checker.
  • Loading branch information
moulins committed Feb 12, 2025
1 parent bd71926 commit 14a13f6
Show file tree
Hide file tree
Showing 24 changed files with 156 additions and 204 deletions.
9 changes: 3 additions & 6 deletions core/src/avm1/activation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1470,12 +1470,9 @@ impl<'a, 'gc> Activation<'a, 'gc> {
// InitArray pops no args and pushes undefined if num_elements is out of range.
Value::Undefined
} else {
ArrayObject::new(
self.gc(),
self.context.avm1.prototypes().array,
(0..num_elements as i32).map(|_| self.context.avm1.pop()),
)
.into()
ArrayObject::builder(self)
.with((0..num_elements as i32).map(|_| self.context.avm1.pop()))
.into()
};

self.context.avm1.push(result);
Expand Down
9 changes: 3 additions & 6 deletions core/src/avm1/flv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,9 @@ fn avm1_array_from_flv_values<'gc>(
activation: &mut Activation<'_, 'gc>,
values: Vec<FlvValue>,
) -> Avm1Value<'gc> {
ArrayObject::new(
activation.gc(),
activation.context.avm1.prototypes().array,
values.iter().map(|v| v.clone().to_avm1_value(activation)),
)
.into()
ArrayObject::builder(activation)
.with(values.iter().map(|v| v.clone().to_avm1_value(activation)))
.into()
}

pub trait FlvValueAvm1Ext<'gc> {
Expand Down
6 changes: 1 addition & 5 deletions core/src/avm1/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,7 @@ impl<'gc> Avm1Function<'gc> {
return;
}

let arguments = ArrayObject::new(
frame.gc(),
frame.context.avm1.prototypes().array,
args.iter().cloned(),
);
let arguments = ArrayObject::builder(frame).with(args.iter().cloned());

arguments.define_value(
frame.gc(),
Expand Down
45 changes: 14 additions & 31 deletions core/src/avm1/globals/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,9 @@ pub fn constructor<'gc>(
array.set_length(activation, length.clamp_to_i32())?;
Ok(array.into())
} else {
Ok(ArrayObject::new(
activation.gc(),
activation.context.avm1.prototypes().array,
args.iter().cloned(),
)
.into())
Ok(ArrayObject::builder(activation)
.with(args.iter().cloned())
.into())
}
}

Expand Down Expand Up @@ -302,12 +299,9 @@ pub fn slice<'gc>(
make_index_absolute(end.coerce_to_i32(activation)?, length)
};

Ok(ArrayObject::new(
activation.gc(),
activation.context.avm1.prototypes().array,
(start..end).map(|i| this.get_element(activation, i)),
)
.into())
Ok(ArrayObject::builder(activation)
.with((start..end).map(|i| this.get_element(activation, i)))
.into())
}

pub fn splice<'gc>(
Expand Down Expand Up @@ -367,12 +361,9 @@ pub fn splice<'gc>(
}
this.set_length(activation, length - delete_count + items.len() as i32)?;

Ok(ArrayObject::new(
activation.gc(),
activation.context.avm1.prototypes().array,
result_elements,
)
.into())
Ok(ArrayObject::builder(activation)
.with(result_elements)
.into())
}

pub fn concat<'gc>(
Expand Down Expand Up @@ -402,12 +393,7 @@ pub fn concat<'gc>(
elements.push(value);
}
}
Ok(ArrayObject::new(
activation.gc(),
activation.context.avm1.prototypes().array,
elements,
)
.into())
Ok(ArrayObject::builder(activation).with(elements).into())
}

pub fn to_string<'gc>(
Expand Down Expand Up @@ -647,12 +633,9 @@ fn sort_internal<'gc>(
if options.contains(SortOptions::RETURN_INDEXED_ARRAY) {
// Array.RETURNINDEXEDARRAY returns an array containing the sorted indices, and does not modify
// the original array.
Ok(ArrayObject::new(
activation.gc(),
activation.context.avm1.prototypes().array,
elements.into_iter().map(|(index, _)| index.into()),
)
.into())
Ok(ArrayObject::builder(activation)
.with(elements.into_iter().map(|(index, _)| index.into()))
.into())
} else {
// Standard sort modifies the original array, and returns it.
// AS2 reference incorrectly states this returns nothing, but it returns the original array, sorted.
Expand Down Expand Up @@ -738,7 +721,7 @@ pub fn create_proto<'gc>(
proto: Object<'gc>,
fn_proto: Object<'gc>,
) -> Object<'gc> {
let array = ArrayObject::empty_with_proto(context.gc(), proto);
let array = ArrayObject::builder_with_proto(context, proto).with([]);
let object = array.raw_script_object();
define_properties_on(PROTO_DECLS, context, object, fn_proto);
object.into()
Expand Down
22 changes: 12 additions & 10 deletions core/src/avm1/globals/as_broadcaster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::avm1::property::Attribute;
use crate::avm1::property_decl::Declaration;
use crate::avm1::{Activation, ArrayObject, Object, ScriptObject, Value};
use crate::string::{AvmString, StringContext};
use gc_arena::{Collect, Mutation};
use gc_arena::Collect;

const OBJECT_DECLS: &[Declaration] = declare_properties! {
"initialize" => method(initialize; DONT_ENUM | DONT_DELETE);
Expand Down Expand Up @@ -62,11 +62,11 @@ pub struct BroadcasterFunctions<'gc> {
impl<'gc> BroadcasterFunctions<'gc> {
pub fn initialize(
self,
gc_context: &Mutation<'gc>,
context: &StringContext<'gc>,
broadcaster: Object<'gc>,
array_proto: Object<'gc>,
) {
initialize_internal(gc_context, broadcaster, self, array_proto);
initialize_internal(context, broadcaster, self, array_proto);
}
}

Expand Down Expand Up @@ -187,7 +187,7 @@ fn initialize<'gc>(
if let Some(val) = args.get(0) {
let broadcaster = val.coerce_to_object(activation);
initialize_internal(
activation.gc(),
&activation.context.strings,
broadcaster,
activation.context.avm1.broadcaster_functions(),
activation.context.avm1.prototypes().array,
Expand All @@ -197,31 +197,33 @@ fn initialize<'gc>(
}

fn initialize_internal<'gc>(
gc_context: &Mutation<'gc>,
context: &StringContext<'gc>,
broadcaster: Object<'gc>,
functions: BroadcasterFunctions<'gc>,
array_proto: Object<'gc>,
) {
broadcaster.define_value(
gc_context,
context.gc(),
"_listeners",
ArrayObject::empty_with_proto(gc_context, array_proto).into(),
ArrayObject::builder_with_proto(context, array_proto)
.with([])
.into(),
Attribute::DONT_ENUM,
);
broadcaster.define_value(
gc_context,
context.gc(),
"addListener",
functions.add_listener.into(),
Attribute::DONT_DELETE | Attribute::DONT_ENUM,
);
broadcaster.define_value(
gc_context,
context.gc(),
"removeListener",
functions.remove_listener.into(),
Attribute::DONT_DELETE | Attribute::DONT_ENUM,
);
broadcaster.define_value(
gc_context,
context.gc(),
"broadcastMessage",
functions.broadcast_message.into(),
Attribute::DONT_DELETE | Attribute::DONT_ENUM,
Expand Down
15 changes: 7 additions & 8 deletions core/src/avm1/globals/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,13 @@ fn filters<'gc>(
this: Avm1Button<'gc>,
activation: &mut Activation<'_, 'gc>,
) -> Result<Value<'gc>, Error<'gc>> {
Ok(ArrayObject::new(
activation.gc(),
activation.context.avm1.prototypes().array,
this.filters()
.into_iter()
.map(|filter| bitmap_filter::filter_to_avm1(activation, filter)),
)
.into())
Ok(ArrayObject::builder(activation)
.with(
this.filters()
.into_iter()
.map(|filter| bitmap_filter::filter_to_avm1(activation, filter)),
)
.into())
}

fn set_filters<'gc>(
Expand Down
9 changes: 3 additions & 6 deletions core/src/avm1/globals/color_matrix_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,9 @@ impl<'gc> ColorMatrixFilter<'gc> {
}

fn matrix(&self, activation: &mut Activation<'_, 'gc>) -> Value<'gc> {
ArrayObject::new(
activation.gc(),
activation.context.avm1.prototypes().array,
self.0.read().matrix.iter().map(|&v| v.into()),
)
.into()
ArrayObject::builder(activation)
.with(self.0.read().matrix.iter().map(|&v| v.into()))
.into()
}

fn set_matrix(
Expand Down
11 changes: 3 additions & 8 deletions core/src/avm1/globals/convolution_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use crate::avm1::function::{Executable, FunctionObject};
use crate::avm1::object::NativeObject;
use crate::avm1::property_decl::{define_properties_on, Declaration};
use crate::avm1::{Activation, ArrayObject, Error, Object, ScriptObject, TObject, Value};
use crate::context::UpdateContext;
use crate::string::StringContext;
use gc_arena::{Collect, GcCell, Mutation};
use std::ops::Deref;
Expand Down Expand Up @@ -167,12 +166,8 @@ impl<'gc> ConvolutionFilter<'gc> {
Ok(())
}

fn matrix(&self, context: &mut UpdateContext<'gc>) -> ArrayObject<'gc> {
ArrayObject::new(
context.gc(),
context.avm1.prototypes().array,
self.0.read().matrix.iter().map(|&x| x.into()),
)
fn matrix(&self, activation: &Activation<'_, 'gc>) -> ArrayObject<'gc> {
ArrayObject::builder(activation).with(self.0.read().matrix.iter().map(|&x| x.into()))
}

fn set_matrix(
Expand Down Expand Up @@ -366,7 +361,7 @@ fn method<'gc>(
this.set_matrix_y(activation, args.get(0))?;
Value::Undefined
}
GET_MATRIX => this.matrix(activation.context).into(),
GET_MATRIX => this.matrix(activation).into(),
SET_MATRIX => {
this.set_matrix(activation, args.get(0))?;
Value::Undefined
Expand Down
2 changes: 1 addition & 1 deletion core/src/avm1/globals/file_reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ pub fn create_constructor<'gc>(
) -> Object<'gc> {
let file_reference_proto = ScriptObject::new(context.gc(), Some(proto));
define_properties_on(PROTO_DECLS, context, file_reference_proto, fn_proto);
broadcaster_functions.initialize(context.gc(), file_reference_proto.into(), array_proto);
broadcaster_functions.initialize(context, file_reference_proto.into(), array_proto);
let constructor = FunctionObject::constructor(
context.gc(),
Executable::Native(constructor),
Expand Down
25 changes: 9 additions & 16 deletions core/src/avm1/globals/gradient_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::avm1::globals::bevel_filter::BevelFilterType;
use crate::avm1::object::NativeObject;
use crate::avm1::property_decl::{define_properties_on, Declaration};
use crate::avm1::{Activation, ArrayObject, Error, Object, ScriptObject, TObject, Value};
use crate::context::UpdateContext;
use crate::string::StringContext;
use gc_arena::{Collect, GcCell, Mutation};
use ruffle_macros::istr;
Expand Down Expand Up @@ -165,11 +164,9 @@ impl<'gc> GradientFilter<'gc> {
Ok(())
}

fn colors(&self, context: &mut UpdateContext<'gc>) -> ArrayObject<'gc> {
fn colors(&self, activation: &Activation<'_, 'gc>) -> ArrayObject<'gc> {
let read = self.0.read();
ArrayObject::new(
context.gc(),
context.avm1.prototypes().array,
ArrayObject::builder(activation).with(
read.colors[..read.num_colors]
.iter()
.map(|r| r.color.to_rgb().into()),
Expand Down Expand Up @@ -203,11 +200,9 @@ impl<'gc> GradientFilter<'gc> {
Ok(())
}

fn alphas(&self, context: &mut UpdateContext<'gc>) -> ArrayObject<'gc> {
fn alphas(&self, activation: &Activation<'_, 'gc>) -> ArrayObject<'gc> {
let read = self.0.read();
ArrayObject::new(
context.gc(),
context.avm1.prototypes().array,
ArrayObject::builder(activation).with(
read.colors[..read.num_colors]
.iter()
.map(|r| (f64::from(r.color.a) / 255.0).into()),
Expand Down Expand Up @@ -243,11 +238,9 @@ impl<'gc> GradientFilter<'gc> {
Ok(())
}

fn ratios(&self, context: &mut UpdateContext<'gc>) -> ArrayObject<'gc> {
fn ratios(&self, activation: &Activation<'_, 'gc>) -> ArrayObject<'gc> {
let read = self.0.read();
ArrayObject::new(
context.gc(),
context.avm1.prototypes().array,
ArrayObject::builder(activation).with(
read.colors[..read.num_colors]
.iter()
.map(|r| r.ratio.into()),
Expand Down Expand Up @@ -474,17 +467,17 @@ fn method<'gc>(
this.set_angle(activation, args.get(0))?;
Value::Undefined
}
GET_COLORS => this.colors(activation.context).into(),
GET_COLORS => this.colors(activation).into(),
SET_COLORS => {
this.set_colors(activation, args.get(0))?;
Value::Undefined
}
GET_ALPHAS => this.alphas(activation.context).into(),
GET_ALPHAS => this.alphas(activation).into(),
SET_ALPHAS => {
this.set_alphas(activation, args.get(0))?;
Value::Undefined
}
GET_RATIOS => this.ratios(activation.context).into(),
GET_RATIOS => this.ratios(activation).into(),
SET_RATIOS => {
this.set_ratios(activation, args.get(0))?;
Value::Undefined
Expand Down
2 changes: 1 addition & 1 deletion core/src/avm1/globals/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ pub fn create_key_object<'gc>(
array_proto: Object<'gc>,
) -> Object<'gc> {
let key = ScriptObject::new(context.gc(), Some(proto));
broadcaster_functions.initialize(context.gc(), key.into(), array_proto);
broadcaster_functions.initialize(context, key.into(), array_proto);
define_properties_on(OBJECT_DECLS, context, key, fn_proto);
key.into()
}
2 changes: 1 addition & 1 deletion core/src/avm1/globals/mouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub fn create_mouse_object<'gc>(
array_proto: Object<'gc>,
) -> Object<'gc> {
let mouse = ScriptObject::new(context.gc(), Some(proto));
broadcaster_functions.initialize(context.gc(), mouse.into(), array_proto);
broadcaster_functions.initialize(context, mouse.into(), array_proto);
define_properties_on(OBJECT_DECLS, context, mouse, fn_proto);
mouse.into()
}
15 changes: 7 additions & 8 deletions core/src/avm1/globals/movie_clip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1784,14 +1784,13 @@ fn filters<'gc>(
this: MovieClip<'gc>,
activation: &mut Activation<'_, 'gc>,
) -> Result<Value<'gc>, Error<'gc>> {
Ok(ArrayObject::new(
activation.gc(),
activation.context.avm1.prototypes().array,
this.filters()
.into_iter()
.map(|filter| bitmap_filter::filter_to_avm1(activation, filter)),
)
.into())
Ok(ArrayObject::builder(activation)
.with(
this.filters()
.into_iter()
.map(|filter| bitmap_filter::filter_to_avm1(activation, filter)),
)
.into())
}

fn set_filters<'gc>(
Expand Down
Loading

0 comments on commit 14a13f6

Please sign in to comment.