Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
5ed1c34
avm2: Make `ByteArrayObject::from_storage` take an `UpdateContext`
Lord-McSweeney Nov 9, 2025
6504490
avm2: Make `ScriptObject::new_object` take an `UpdateContext`
Lord-McSweeney Nov 9, 2025
e937ca4
avm2: Make a lot of functions take UpdateContext instead of Activation
Lord-McSweeney Nov 9, 2025
2252fef
avm2: Make `globals::load_playerglobal` take an `UpdateContext`
Lord-McSweeney Nov 9, 2025
fe37124
avm2: Make `Domain::movie_domain` take an `UpdateContext`
Lord-McSweeney Nov 9, 2025
5209c7f
avm2: Make `FunctionObject::from_method` take an `UpdateContext`
Lord-McSweeney Nov 9, 2025
5d3b122
avm2: Make `ArrayObject` constructor methods take an `UpdateContext`
Lord-McSweeney Nov 9, 2025
14b343f
avm2: Make `DateObject` constructor methods take an `UpdateContext`
Lord-McSweeney Nov 9, 2025
26715c9
avm2: Make `PixelBenderTypeExt::as_avm2_value` take UpdateContext
Lord-McSweeney Nov 9, 2025
1a5979b
avm2: Make `FlvValueAvm2Ext::to_avm2_value` take UpdateContext
Lord-McSweeney Nov 9, 2025
dc2d5d9
avm2: Make `external::Value::into_avm2` take UpdateContext
Lord-McSweeney Nov 9, 2025
1c6f577
avm2: Make `Metadata::as_json_object` take `UpdateContext`
Lord-McSweeney Nov 9, 2025
4395ce5
avm2: Make `describe_internal_body` take `UpdateContext`
Lord-McSweeney Nov 9, 2025
604af5e
avm2: Make `Regex::split` take `UpdateContext`
Lord-McSweeney Nov 9, 2025
c61125f
core: Remove some unnecessary Activation creations
Lord-McSweeney Nov 9, 2025
a04ee6c
core/avm2: Clean up some SharedObject code
Lord-McSweeney Nov 9, 2025
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
15 changes: 7 additions & 8 deletions core/src/avm2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub use crate::avm2::multiname::Multiname;
pub use crate::avm2::namespace::{CommonNamespaces, Namespace};
pub use crate::avm2::object::{
ArrayObject, BitmapDataObject, ClassObject, EventObject, LoaderInfoObject, Object,
SoundChannelObject, StageObject, TObject,
SharedObjectObject, SoundChannelObject, StageObject, TObject,
};
pub use crate::avm2::qname::QName;
pub use crate::avm2::value::Value;
Expand Down Expand Up @@ -243,8 +243,7 @@ impl<'gc> Avm2<'gc> {

pub fn load_player_globals(context: &mut UpdateContext<'gc>) {
let globals = context.avm2.playerglobals_domain;
let mut activation = Activation::from_domain(context, globals);
globals::load_playerglobal(&mut activation, globals);
globals::load_playerglobal(context, globals);
}

pub fn playerglobals_domain(&self) -> Domain<'gc> {
Expand Down Expand Up @@ -289,19 +288,16 @@ impl<'gc> Avm2<'gc> {
script: Script<'gc>,
context: &mut UpdateContext<'gc>,
) -> Result<(), Error<'gc>> {
// TODO can we skip creating this temporary Activation?
let mut activation = Activation::from_nothing(context);

let (method, global_object, domain) = script.init();

let scope = ScopeChain::new(domain);
// Script `global` classes extend Object
let bound_superclass = Some(activation.avm2().classes().object);
let bound_superclass = Some(context.avm2.classes().object);

// Provide a callee object if necessary
let callee = if method.needs_arguments_object() {
Some(FunctionObject::from_method(
&mut activation,
context,
method,
scope,
Some(global_object.into()),
Expand All @@ -311,6 +307,9 @@ impl<'gc> Avm2<'gc> {
None
};

// TODO can we skip creating this temporary Activation?
let mut activation = Activation::from_nothing(context);

exec(
method,
scope,
Expand Down
12 changes: 6 additions & 6 deletions core/src/avm2/activation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
unreachable!();
};

let args_object = ArrayObject::from_storage(self, args_array);
let args_object = ArrayObject::from_storage(self.context, args_array);

if method
.method()
Expand Down Expand Up @@ -1124,7 +1124,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
// TODO: What scope should the function be executed with?
let scope = self.create_scopechain();

let function = FunctionObject::from_method(self, method, scope, None, None);
let function = FunctionObject::from_method(self.context, method, scope, None, None);
let value = function.call(self, receiver, args)?;

self.push_stack(value);
Expand Down Expand Up @@ -1505,7 +1505,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
ScriptObject::custom_object(self.gc(), *catch_class, None, catch_class.vtable())
} else {
// for `finally` scopes, FP just creates a normal object.
ScriptObject::new_object(self)
ScriptObject::new_object(self.context)
};

self.push_stack(so);
Expand Down Expand Up @@ -1754,7 +1754,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
}

fn op_new_object(&mut self, num_args: u32) -> Result<(), Error<'gc>> {
let object = ScriptObject::new_object(self);
let object = ScriptObject::new_object(self.context);

for _ in 0..num_args {
let value = self.pop_stack();
Expand All @@ -1771,7 +1771,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
fn op_new_function(&mut self, method: Method<'gc>) -> Result<(), Error<'gc>> {
let scope = self.create_scopechain();

let new_fn = FunctionObject::from_method(self, method, scope, None, None);
let new_fn = FunctionObject::from_method(self.context, method, scope, None, None);

self.push_stack(new_fn);

Expand Down Expand Up @@ -1846,7 +1846,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
fn op_new_array(&mut self, num_args: u32) -> Result<(), Error<'gc>> {
let args = self.pop_stack_args(num_args);
let array = ArrayStorage::from_args(&args[..]);
let array_obj = ArrayObject::from_storage(self, array);
let array_obj = ArrayObject::from_storage(self.context, array);

self.push_stack(array_obj);

Expand Down
8 changes: 4 additions & 4 deletions core/src/avm2/amf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,12 +333,12 @@ pub fn deserialize_value_impl<'gc>(
AmfValue::Bool(b) => (*b).into(),
AmfValue::ByteArray(bytes) => {
let storage = ByteArrayStorage::from_vec(activation.context, bytes.clone());
let bytearray = ByteArrayObject::from_storage(activation, storage);
let bytearray = ByteArrayObject::from_storage(activation.context, storage);
bytearray.into()
}
AmfValue::ECMAArray(id, values, elements, _) => {
let empty_storage = ArrayStorage::new(0);
let array = ArrayObject::from_storage(activation, empty_storage);
let array = ArrayObject::from_storage(activation.context, empty_storage);
object_map.insert(*id, array.into());

// First let's create an array out of `values` (dense portion), then we add the elements onto it.
Expand Down Expand Up @@ -371,7 +371,7 @@ pub fn deserialize_value_impl<'gc>(
}
AmfValue::StrictArray(id, values) => {
let empty_storage = ArrayStorage::new(0);
let array = ArrayObject::from_storage(activation, empty_storage);
let array = ArrayObject::from_storage(activation.context, empty_storage);
object_map.insert(*id, array.into());

let mut arr: Vec<Option<Value<'gc>>> = Vec::with_capacity(values.len());
Expand Down Expand Up @@ -538,7 +538,7 @@ pub fn deserialize_lso<'gc>(
activation: &mut Activation<'_, 'gc>,
lso: &Lso,
) -> Result<Object<'gc>, Error<'gc>> {
let obj = ScriptObject::new_object(activation);
let obj = ScriptObject::new_object(activation.context);

for child in &lso.body {
obj.set_dynamic_property(
Expand Down
20 changes: 10 additions & 10 deletions core/src/avm2/domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,10 @@ impl<'gc> Domain<'gc> {
///
/// This function must not be called before the player globals have been
/// fully allocated.
pub fn movie_domain(activation: &mut Activation<'_, 'gc>, parent: Domain<'gc>) -> Domain<'gc> {
let domain_memory = Self::create_default_domain_memory(activation);
pub fn movie_domain(context: &mut UpdateContext<'gc>, parent: Domain<'gc>) -> Domain<'gc> {
let domain_memory = Self::create_default_domain_memory(context);
let this = Self(Gc::new(
activation.gc(),
context.gc(),
DomainData {
cell: RefLock::new(DomainDataMut {
defs: PropertyMap::new(),
Expand All @@ -159,7 +159,7 @@ impl<'gc> Domain<'gc> {
#[cfg(feature = "egui")]
{
parent
.cell_mut(activation.gc())
.cell_mut(context.gc())
.children
.push(DomainWeak(Gc::downgrade(this.0)));
}
Expand Down Expand Up @@ -400,21 +400,21 @@ impl<'gc> Domain<'gc> {
Ok(())
}

fn create_default_domain_memory(activation: &mut Activation<'_, 'gc>) -> ByteArrayObject<'gc> {
fn create_default_domain_memory(context: &mut UpdateContext<'gc>) -> ByteArrayObject<'gc> {
let initial_data = vec![0; MIN_DOMAIN_MEMORY_LENGTH];
let storage = ByteArrayStorage::from_vec(activation.context, initial_data);
ByteArrayObject::from_storage(activation, storage)
let storage = ByteArrayStorage::from_vec(context, initial_data);
ByteArrayObject::from_storage(context, storage)
}

/// Allocate the default domain memory for this domain, if it does not
/// already exist.
///
/// This function is only necessary to be called for domains created via
/// `global_domain`. It will panic on already fully-initialized domains.
pub fn init_default_domain_memory(self, activation: &mut Activation<'_, 'gc>) {
let memory = Self::create_default_domain_memory(activation);
pub fn init_default_domain_memory(self, context: &mut UpdateContext<'gc>) {
let memory = Self::create_default_domain_memory(context);

let write = Gc::write(activation.gc(), self.0);
let write = Gc::write(context.gc(), self.0);
match unlock!(write, DomainData, default_domain_memory).set(memory) {
Ok(_) => unlock!(write, DomainData, domain_memory).set(Some(memory)),
Err(_) => panic!("Already initialized domain memory!"),
Expand Down
10 changes: 5 additions & 5 deletions core/src/avm2/filters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ fn color_matrix_filter_to_avm2<'gc>(
filter: &ColorMatrixFilter,
) -> Result<Value<'gc>, Error<'gc>> {
let matrix = ArrayObject::from_storage(
activation,
activation.context,
filter.matrix.iter().map(|v| Value::from(*v)).collect(),
);
activation
Expand Down Expand Up @@ -423,7 +423,7 @@ fn convolution_filter_to_avm2<'gc>(
filter: &ConvolutionFilter,
) -> Result<Value<'gc>, Error<'gc>> {
let matrix = ArrayObject::from_storage(
activation,
activation.context,
filter
.matrix
.iter()
Expand Down Expand Up @@ -755,23 +755,23 @@ fn gradient_filter_to_avm2<'gc>(
class: ClassObject<'gc>,
) -> Result<Value<'gc>, Error<'gc>> {
let colors = ArrayObject::from_storage(
activation,
activation.context,
filter
.colors
.iter()
.map(|v| Value::from(v.color.to_rgb()))
.collect(),
);
let alphas = ArrayObject::from_storage(
activation,
activation.context,
filter
.colors
.iter()
.map(|v| Value::from(f64::from(v.color.a) / 255.0))
.collect(),
);
let ratios = ArrayObject::from_storage(
activation,
activation.context,
filter.colors.iter().map(|v| Value::from(v.ratio)).collect(),
);
class.construct(
Expand Down
35 changes: 18 additions & 17 deletions core/src/avm2/flv.rs
Original file line number Diff line number Diff line change
@@ -1,72 +1,73 @@
use crate::avm2::array::ArrayStorage;
use crate::avm2::object::{ArrayObject, DateObject, ScriptObject, TObject as _};
use crate::avm2::{Activation, Value as Avm2Value};
use crate::avm2::Value as Avm2Value;
use crate::context::UpdateContext;
use crate::string::AvmString;

use chrono::DateTime;
use flv_rs::{Value as FlvValue, Variable as FlvVariable};

fn avm2_object_from_flv_variables<'gc>(
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'gc>,
variables: Vec<FlvVariable>,
) -> Avm2Value<'gc> {
let info_object = ScriptObject::new_object(activation);
let info_object = ScriptObject::new_object(context);

for value in variables {
let property_name = value.name;

info_object.set_dynamic_property(
AvmString::new_utf8_bytes(activation.gc(), property_name),
value.data.to_avm2_value(activation),
activation.gc(),
AvmString::new_utf8_bytes(context.gc(), property_name),
value.data.to_avm2_value(context),
context.gc(),
);
}

info_object.into()
}

fn avm2_array_from_flv_values<'gc>(
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'gc>,

Check warning on line 30 in core/src/avm2/flv.rs

View workflow job for this annotation

GitHub Actions / Coverage Report

Coverage

Uncovered line (30)
values: Vec<FlvValue>,
) -> Avm2Value<'gc> {
let storage = ArrayStorage::from_storage(
values
.iter()
.map(|v| Some(v.clone().to_avm2_value(activation)))
.map(|v| Some(v.clone().to_avm2_value(context)))

Check warning on line 36 in core/src/avm2/flv.rs

View workflow job for this annotation

GitHub Actions / Coverage Report

Coverage

Uncovered line (36)
.collect::<Vec<Option<Avm2Value<'gc>>>>(),
);

ArrayObject::from_storage(activation, storage).into()
ArrayObject::from_storage(context, storage).into()

Check warning on line 40 in core/src/avm2/flv.rs

View workflow job for this annotation

GitHub Actions / Coverage Report

Coverage

Uncovered line (40)
}

fn avm2_date_from_flv_date<'gc>(
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'gc>,
unix_time: f64,
_local_offset: i16,
) -> Avm2Value<'gc> {
let date_time = DateTime::from_timestamp(unix_time as i64, 0).expect("invalid timestamp");

DateObject::from_date_time(activation, date_time).into()
DateObject::from_date_time(context, date_time).into()
}

pub trait FlvValueAvm2Ext<'gc> {
fn to_avm2_value(self, activation: &mut Activation<'_, 'gc>) -> Avm2Value<'gc>;
fn to_avm2_value(self, context: &mut UpdateContext<'gc>) -> Avm2Value<'gc>;
}

impl<'gc> FlvValueAvm2Ext<'gc> for FlvValue<'_> {
fn to_avm2_value(self, activation: &mut Activation<'_, 'gc>) -> Avm2Value<'gc> {
fn to_avm2_value(self, context: &mut UpdateContext<'gc>) -> Avm2Value<'gc> {
match self {
FlvValue::Object(variables) | FlvValue::EcmaArray(variables) => {
avm2_object_from_flv_variables(activation, variables)
avm2_object_from_flv_variables(context, variables)
}
FlvValue::StrictArray(values) => avm2_array_from_flv_values(activation, values),
FlvValue::StrictArray(values) => avm2_array_from_flv_values(context, values),

Check warning on line 63 in core/src/avm2/flv.rs

View workflow job for this annotation

GitHub Actions / Coverage Report

Coverage

Uncovered line (63)
FlvValue::String(string_data) | FlvValue::LongString(string_data) => {
AvmString::new_utf8_bytes(activation.gc(), string_data).into()
AvmString::new_utf8_bytes(context.gc(), string_data).into()
}
FlvValue::Date {
unix_time,
local_offset,
} => avm2_date_from_flv_date(activation, unix_time, local_offset),
} => avm2_date_from_flv_date(context, unix_time, local_offset),
FlvValue::Number(value) => value.into(),
FlvValue::Boolean(value) => value.into(),
FlvValue::Null => Avm2Value::Null,
Expand Down
27 changes: 14 additions & 13 deletions core/src/avm2/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::avm2::object::{ClassObject, ScriptObject};
use crate::avm2::scope::{Scope, ScopeChain};
use crate::avm2::script::TranslationUnit;
use crate::avm2::{Avm2, Error, Multiname, Namespace, QName};
use crate::context::UpdateContext;
use crate::string::WStr;
use crate::tag_utils::{self, ControlFlow, SwfMovie, SwfSlice, SwfStream};
use gc_arena::Collect;
Expand Down Expand Up @@ -510,10 +511,10 @@ pub fn init_early_classes<'gc>(
);

// Now to weave the Gordian knot...
object_class.link_prototype(activation, object_proto);
object_class.link_prototype(activation.context, object_proto);
object_class.link_type(mc, class_proto);

class_class.link_prototype(activation, class_proto);
class_class.link_prototype(activation.context, class_proto);
class_class.link_type(mc, class_proto);

// At this point, we need both early classes to be available in `SystemClasses`
Expand Down Expand Up @@ -815,12 +816,12 @@ pub fn init_native_system_classes(activation: &mut Activation<'_, '_>) {

/// Loads classes from our custom 'playerglobal' (which are written in ActionScript)
/// into the environment. See 'core/src/avm2/globals/README.md' for more information
pub fn load_playerglobal<'gc>(activation: &mut Activation<'_, 'gc>, domain: Domain<'gc>) {
activation.avm2().native_method_table = native::NATIVE_METHOD_TABLE;
activation.avm2().native_instance_allocator_table = native::NATIVE_INSTANCE_ALLOCATOR_TABLE;
activation.avm2().native_call_handler_table = native::NATIVE_CALL_HANDLER_TABLE;
activation.avm2().native_custom_constructor_table = native::NATIVE_CUSTOM_CONSTRUCTOR_TABLE;
activation.avm2().native_fast_call_list = native::NATIVE_FAST_CALL_LIST;
pub fn load_playerglobal<'gc>(context: &mut UpdateContext<'gc>, domain: Domain<'gc>) {
context.avm2.native_method_table = native::NATIVE_METHOD_TABLE;
context.avm2.native_instance_allocator_table = native::NATIVE_INSTANCE_ALLOCATOR_TABLE;
context.avm2.native_call_handler_table = native::NATIVE_CALL_HANDLER_TABLE;
context.avm2.native_custom_constructor_table = native::NATIVE_CUSTOM_CONSTRUCTOR_TABLE;
context.avm2.native_fast_call_list = native::NATIVE_FAST_CALL_LIST;

let movie = Arc::new(
SwfMovie::from_data(PLAYERGLOBAL, "file:///".into(), None)
Expand All @@ -836,7 +837,7 @@ pub fn load_playerglobal<'gc>(activation: &mut Activation<'_, 'gc>, domain: Doma
let do_abc = reader
.read_do_abc_2()
.expect("playerglobal.swf should be valid");
Avm2::load_builtin_abc(activation.context, do_abc.data, domain, movie.clone());
Avm2::load_builtin_abc(context, do_abc.data, domain, movie.clone());
} else if tag_code != TagCode::End {
panic!("playerglobal should only contain `DoAbc2` tag - found tag {tag_code:?}")
}
Expand All @@ -846,9 +847,9 @@ pub fn load_playerglobal<'gc>(activation: &mut Activation<'_, 'gc>, domain: Doma
let _ = tag_utils::decode_tags(&mut reader, tag_callback);

// Domain memory must be initialized after playerglobals is loaded because it relies on ByteArray.
domain.init_default_domain_memory(activation);
activation
.avm2()
domain.init_default_domain_memory(context);
context
.avm2
.stage_domain()
.init_default_domain_memory(activation);
.init_default_domain_memory(context);
}
Loading
Loading