From 02e05e3d7fddc988ef38dee90f5f75092840d4af Mon Sep 17 00:00:00 2001 From: David Wendt Date: Mon, 21 Sep 2020 20:37:22 -0400 Subject: [PATCH] Add separate scope object for each script. --- core/src/avm2.rs | 2 +- core/src/avm2/globals.rs | 9 ++++++ core/src/avm2/globals/global_scope.rs | 43 +++++++++++++++++++++++++++ core/src/avm2/script.rs | 18 ++++++++++- 4 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 core/src/avm2/globals/global_scope.rs diff --git a/core/src/avm2.rs b/core/src/avm2.rs index ff42b0f41..b5d6543aa 100644 --- a/core/src/avm2.rs +++ b/core/src/avm2.rs @@ -137,7 +137,7 @@ impl<'gc> Avm2<'gc> { for i in (0..abc_file.scripts.len()).rev() { let script = tunit.load_script(i as u32, context.avm2, context.gc_context)?; - let mut globals = context.avm2.globals(); + let mut globals = script.read().globals(); let scope = Scope::push_scope(None, globals, context.gc_context); let mut null_activation = Activation::from_nothing(context.reborrow()); diff --git a/core/src/avm2/globals.rs b/core/src/avm2/globals.rs index fa84a2c31..2cf056209 100644 --- a/core/src/avm2/globals.rs +++ b/core/src/avm2/globals.rs @@ -20,6 +20,7 @@ mod boolean; mod class; mod flash; mod function; +mod global_scope; mod int; mod namespace; mod number; @@ -47,6 +48,7 @@ pub struct SystemPrototypes<'gc> { pub object: Object<'gc>, pub function: Object<'gc>, pub class: Object<'gc>, + pub global: Object<'gc>, pub string: Object<'gc>, pub boolean: Object<'gc>, pub number: Object<'gc>, @@ -77,6 +79,7 @@ impl<'gc> SystemPrototypes<'gc> { object, function, class, + global: empty, string: empty, boolean: empty, number: empty, @@ -277,6 +280,12 @@ pub fn load_player_globals<'gc>(activation: &mut Activation<'_, 'gc, '_>) -> Res // other from the activation they're handed. let mut sp = activation.context.avm2.system_prototypes.clone().unwrap(); + sp.global = class( + activation, + gs, + global_scope::create_class(activation.context.gc_context), + implicit_deriver, + )?; sp.string = class( activation, gs, diff --git a/core/src/avm2/globals/global_scope.rs b/core/src/avm2/globals/global_scope.rs new file mode 100644 index 000000000..f6e6917a9 --- /dev/null +++ b/core/src/avm2/globals/global_scope.rs @@ -0,0 +1,43 @@ +//! `global` constructor +//! +//! Globals are an undocumented Flash class that don't appear to have any +//! public methods, but are the class that the script global scope is an +//! instance of. + +use crate::avm2::activation::Activation; +use crate::avm2::class::Class; +use crate::avm2::method::Method; +use crate::avm2::names::{Namespace, QName}; +use crate::avm2::object::Object; +use crate::avm2::value::Value; +use crate::avm2::Error; +use gc_arena::{GcCell, MutationContext}; + +/// Implements `global`'s instance constructor. +pub fn instance_init<'gc>( + _activation: &mut Activation<'_, 'gc, '_>, + _this: Option>, + _args: &[Value<'gc>], +) -> Result, Error> { + Ok(Value::Undefined) +} + +/// Implements `global`'s class constructor. +pub fn class_init<'gc>( + _activation: &mut Activation<'_, 'gc, '_>, + _this: Option>, + _args: &[Value<'gc>], +) -> Result, Error> { + Ok(Value::Undefined) +} + +/// Construct `global`'s class. +pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> { + Class::new( + QName::new(Namespace::package(""), "global"), + Some(QName::new(Namespace::package(""), "Object").into()), + Method::from_builtin(instance_init), + Method::from_builtin(class_init), + mc, + ) +} diff --git a/core/src/avm2/script.rs b/core/src/avm2/script.rs index 0b5d76e84..7745540ea 100644 --- a/core/src/avm2/script.rs +++ b/core/src/avm2/script.rs @@ -2,6 +2,7 @@ use crate::avm2::class::Class; use crate::avm2::method::{BytecodeMethod, Method}; +use crate::avm2::object::{Object, ScriptObject}; use crate::avm2::string::AvmString; use crate::avm2::traits::Trait; use crate::avm2::{Avm2, Error}; @@ -128,7 +129,9 @@ impl<'gc> TranslationUnit<'gc> { drop(read); - let script = Script::from_abc_index(self, script_index, mc)?; + let global = ScriptObject::object(mc, avm2.prototypes().global); + + let script = Script::from_abc_index(self, script_index, global, mc)?; self.0.write(mc).scripts.insert(script_index, script); script.write(mc).load_traits(self, script_index, avm2, mc)?; @@ -192,6 +195,9 @@ impl<'gc> TranslationUnit<'gc> { #[derive(Clone, Debug, Collect)] #[collect(no_drop)] pub struct Script<'gc> { + /// The global scope for the script. + globals: Object<'gc>, + /// The initializer method to run for the script. init: Method<'gc>, @@ -209,9 +215,13 @@ impl<'gc> Script<'gc> { /// The caller is responsible for storing the class in the /// `TranslationUnit` and calling `load_traits` to complete the /// trait-loading process. + /// + /// The given `globals` should be an empty object of the `global` hidden + /// type. The initializer script will create and store traits on it. pub fn from_abc_index( unit: TranslationUnit<'gc>, script_index: u32, + globals: Object<'gc>, mc: MutationContext<'gc, '_>, ) -> Result, Error> { let abc = unit.abc(); @@ -226,6 +236,7 @@ impl<'gc> Script<'gc> { Ok(GcCell::allocate( mc, Self { + globals, init, traits: Vec::new(), traits_loaded: false, @@ -272,6 +283,11 @@ impl<'gc> Script<'gc> { self.init.clone() } + /// Return the global scope for the script. + pub fn globals(&self) -> Object<'gc> { + self.globals + } + /// Return traits for this script. /// /// This function will return an error if it is incorrectly called before