Add separate scope object for each script.

This commit is contained in:
David Wendt 2020-09-21 20:37:22 -04:00 committed by Mike Welsh
parent 89c1378569
commit 02e05e3d7f
4 changed files with 70 additions and 2 deletions

View File

@ -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());

View File

@ -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,

View File

@ -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<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Ok(Value::Undefined)
}
/// Implements `global`'s class constructor.
pub fn class_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, 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,
)
}

View File

@ -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<GcCell<'gc, Self>, 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