avm2: Remove SystemPrototypes.
This commit is contained in:
parent
1c5312d6c8
commit
f31d4c2498
|
@ -1,6 +1,6 @@
|
|||
//! ActionScript Virtual Machine 2 (AS3) support
|
||||
|
||||
use crate::avm2::globals::{SystemClasses, SystemPrototypes};
|
||||
use crate::avm2::globals::SystemClasses;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::object::EventObject;
|
||||
use crate::avm2::script::{Script, TranslationUnit};
|
||||
|
@ -72,9 +72,6 @@ pub struct Avm2<'gc> {
|
|||
/// Global scope object.
|
||||
globals: Domain<'gc>,
|
||||
|
||||
/// System prototypes.
|
||||
system_prototypes: Option<SystemPrototypes<'gc>>,
|
||||
|
||||
/// System classes.
|
||||
system_classes: Option<SystemClasses<'gc>>,
|
||||
|
||||
|
@ -100,7 +97,6 @@ impl<'gc> Avm2<'gc> {
|
|||
Self {
|
||||
stack: Vec::new(),
|
||||
globals,
|
||||
system_prototypes: None,
|
||||
system_classes: None,
|
||||
broadcast_list: Default::default(),
|
||||
|
||||
|
@ -115,13 +111,6 @@ impl<'gc> Avm2<'gc> {
|
|||
globals::load_player_globals(&mut activation, globals)
|
||||
}
|
||||
|
||||
/// Return the current set of system prototypes.
|
||||
///
|
||||
/// This function panics if the interpreter has not yet been initialized.
|
||||
pub fn prototypes(&self) -> &SystemPrototypes<'gc> {
|
||||
self.system_prototypes.as_ref().unwrap()
|
||||
}
|
||||
|
||||
/// Return the current set of system classes.
|
||||
///
|
||||
/// This function panics if the interpreter has not yet been initialized.
|
||||
|
|
|
@ -44,124 +44,6 @@ const NS_VECTOR: &str = "__AS3__.vec";
|
|||
|
||||
pub use flash::utils::NS_FLASH_PROXY;
|
||||
|
||||
/// This structure represents all system builtins' prototypes.
|
||||
#[derive(Clone, Collect)]
|
||||
#[collect(no_drop)]
|
||||
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>,
|
||||
pub int: Object<'gc>,
|
||||
pub uint: Object<'gc>,
|
||||
pub namespace: Object<'gc>,
|
||||
pub array: Object<'gc>,
|
||||
pub movieclip: Object<'gc>,
|
||||
pub framelabel: Object<'gc>,
|
||||
pub scene: Object<'gc>,
|
||||
pub application_domain: Object<'gc>,
|
||||
pub event: Object<'gc>,
|
||||
pub fullscreenevent: Object<'gc>,
|
||||
pub video: Object<'gc>,
|
||||
pub xml: Object<'gc>,
|
||||
pub xml_list: Object<'gc>,
|
||||
pub display_object: Object<'gc>,
|
||||
pub shape: Object<'gc>,
|
||||
pub textfield: Object<'gc>,
|
||||
pub textformat: Object<'gc>,
|
||||
pub graphics: Object<'gc>,
|
||||
pub loaderinfo: Object<'gc>,
|
||||
pub bytearray: Object<'gc>,
|
||||
pub stage: Object<'gc>,
|
||||
pub sprite: Object<'gc>,
|
||||
pub simplebutton: Object<'gc>,
|
||||
pub regexp: Object<'gc>,
|
||||
pub vector: Object<'gc>,
|
||||
pub soundtransform: Object<'gc>,
|
||||
pub soundchannel: Object<'gc>,
|
||||
pub bitmap: Object<'gc>,
|
||||
pub bitmapdata: Object<'gc>,
|
||||
pub date: Object<'gc>,
|
||||
pub qname: Object<'gc>,
|
||||
pub sharedobject: Object<'gc>,
|
||||
pub nativemenu: Object<'gc>,
|
||||
pub contextmenu: Object<'gc>,
|
||||
pub mouseevent: Object<'gc>,
|
||||
pub textevent: Object<'gc>,
|
||||
pub errorevent: Object<'gc>,
|
||||
pub ioerrorevent: Object<'gc>,
|
||||
pub securityerrorevent: Object<'gc>,
|
||||
}
|
||||
|
||||
impl<'gc> SystemPrototypes<'gc> {
|
||||
/// Construct a minimal set of system prototypes necessary for
|
||||
/// bootstrapping player globals.
|
||||
///
|
||||
/// All other system prototypes aside from the three given here will be set
|
||||
/// to the empty object also handed to this function. It is the caller's
|
||||
/// responsibility to instantiate each class and replace the empty object
|
||||
/// with that.
|
||||
fn new(
|
||||
object: Object<'gc>,
|
||||
function: Object<'gc>,
|
||||
class: Object<'gc>,
|
||||
global: Object<'gc>,
|
||||
empty: Object<'gc>,
|
||||
) -> Self {
|
||||
SystemPrototypes {
|
||||
object,
|
||||
function,
|
||||
class,
|
||||
global,
|
||||
string: empty,
|
||||
boolean: empty,
|
||||
number: empty,
|
||||
int: empty,
|
||||
uint: empty,
|
||||
namespace: empty,
|
||||
array: empty,
|
||||
movieclip: empty,
|
||||
framelabel: empty,
|
||||
scene: empty,
|
||||
application_domain: empty,
|
||||
event: empty,
|
||||
fullscreenevent: empty,
|
||||
video: empty,
|
||||
xml: empty,
|
||||
xml_list: empty,
|
||||
display_object: empty,
|
||||
shape: empty,
|
||||
textfield: empty,
|
||||
textformat: empty,
|
||||
graphics: empty,
|
||||
loaderinfo: empty,
|
||||
bytearray: empty,
|
||||
stage: empty,
|
||||
sprite: empty,
|
||||
simplebutton: empty,
|
||||
regexp: empty,
|
||||
vector: empty,
|
||||
soundtransform: empty,
|
||||
soundchannel: empty,
|
||||
bitmap: empty,
|
||||
bitmapdata: empty,
|
||||
date: empty,
|
||||
qname: empty,
|
||||
sharedobject: empty,
|
||||
nativemenu: empty,
|
||||
contextmenu: empty,
|
||||
mouseevent: empty,
|
||||
textevent: empty,
|
||||
errorevent: empty,
|
||||
ioerrorevent: empty,
|
||||
securityerrorevent: empty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This structure represents all system builtin classes.
|
||||
#[derive(Clone, Collect)]
|
||||
#[collect(no_drop)]
|
||||
|
@ -319,13 +201,13 @@ fn dynamic_class<'gc>(
|
|||
|
||||
/// Add a class builtin to the global scope.
|
||||
///
|
||||
/// This function returns the class object and class prototype as a pair, which
|
||||
/// may be stored in `SystemClasses` and `SystemPrototypes`, respectively.
|
||||
/// This function returns the class object and class prototype as a class, which
|
||||
/// may be stored in `SystemClasses`
|
||||
fn class<'gc>(
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
class_def: GcCell<'gc, Class<'gc>>,
|
||||
script: Script<'gc>,
|
||||
) -> Result<(ClassObject<'gc>, Object<'gc>), Error> {
|
||||
) -> Result<ClassObject<'gc>, Error> {
|
||||
let (_, mut global, mut domain) = script.init();
|
||||
|
||||
let class_read = class_def.read();
|
||||
|
@ -364,7 +246,7 @@ fn class<'gc>(
|
|||
);
|
||||
domain.export_definition(class_name, script, activation.context.gc_context)?;
|
||||
|
||||
Ok((class_object, class_object.prototype()))
|
||||
Ok(class_object)
|
||||
}
|
||||
|
||||
/// Add a builtin constant to the global scope.
|
||||
|
@ -402,13 +284,10 @@ fn namespace<'gc>(
|
|||
|
||||
macro_rules! avm2_system_class {
|
||||
($field:ident, $activation:ident, $class:expr, $script:expr) => {
|
||||
let (class_object, proto) = class($activation, $class, $script)?;
|
||||
let class_object = class($activation, $class, $script)?;
|
||||
|
||||
let sc = $activation.avm2().system_classes.as_mut().unwrap();
|
||||
sc.$field = class_object;
|
||||
|
||||
let sp = $activation.avm2().system_prototypes.as_mut().unwrap();
|
||||
sp.$field = proto;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -478,16 +357,9 @@ pub fn load_player_globals<'gc>(
|
|||
global_class.link_prototype(activation, global_proto)?;
|
||||
global_class.link_type(activation, class_proto, class_class);
|
||||
|
||||
// At this point, we need at least a partial set of system prototypes in
|
||||
// order to continue initializing the player. The rest of the prototypes
|
||||
// are set to a bare object until we have a chance to initialize them.
|
||||
activation.context.avm2.system_prototypes = Some(SystemPrototypes::new(
|
||||
object_proto,
|
||||
fn_proto,
|
||||
class_proto,
|
||||
global_proto,
|
||||
ScriptObject::bare_object(mc),
|
||||
));
|
||||
// At this point, we need at least a partial set of system classes in
|
||||
// order to continue initializing the player. The rest of the classes
|
||||
// are set to a temporary class until we have a chance to initialize them.
|
||||
|
||||
activation.context.avm2.system_classes = Some(SystemClasses::new(
|
||||
object_class,
|
||||
|
@ -505,8 +377,8 @@ pub fn load_player_globals<'gc>(
|
|||
let object_class = object_class.into_finished_class(activation)?;
|
||||
let _global_class = global_class.into_finished_class(activation)?;
|
||||
|
||||
globals.set_proto(mc, activation.avm2().prototypes().global);
|
||||
globals.set_instance_of(mc, activation.avm2().classes().global);
|
||||
globals.set_proto(mc, global_proto);
|
||||
globals.set_instance_of(mc, global_class);
|
||||
globals.fork_vtable(activation.context.gc_context);
|
||||
|
||||
// From this point, `globals` is safe to be modified
|
||||
|
@ -951,16 +823,13 @@ fn load_playerglobal<'gc>(
|
|||
let class_object = activation.resolve_class(&qname.into())?;
|
||||
let sc = $activation.avm2().system_classes.as_mut().unwrap();
|
||||
sc.$field = class_object;
|
||||
|
||||
let sp = $activation.avm2().system_prototypes.as_mut().unwrap();
|
||||
sp.$field = class_object.prototype();
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
// This acts the same way as 'avm2_system_class', but for classes
|
||||
// declared in 'playerglobal'. Classes are declared as ("package", "class", field_name),
|
||||
// and are stored in 'avm2().system_classes' and 'avm2().system_prototypes'
|
||||
// and are stored in 'avm2().system_classes'
|
||||
avm2_system_classes_playerglobal!(activation, script, [("flash.display", "Scene", scene)]);
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -235,7 +235,7 @@ pub fn to_string<'gc>(
|
|||
this: Option<Object<'gc>>,
|
||||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
let object_proto = activation.avm2().prototypes().object;
|
||||
let object_proto = activation.avm2().classes().object.prototype();
|
||||
let name = QName::dynamic_name("toString").into();
|
||||
object_proto
|
||||
.get_property(&name, activation)?
|
||||
|
|
|
@ -58,8 +58,7 @@ impl<'gc> ArrayObject<'gc> {
|
|||
array: ArrayStorage<'gc>,
|
||||
) -> Result<Object<'gc>, Error> {
|
||||
let class = activation.avm2().classes().array;
|
||||
let proto = activation.avm2().prototypes().array;
|
||||
let base = ScriptObjectData::base_new(Some(proto), Some(class));
|
||||
let base = ScriptObjectData::new(class);
|
||||
|
||||
let mut instance: Object<'gc> = ArrayObject(GcCell::allocate(
|
||||
activation.context.gc_context,
|
||||
|
|
|
@ -45,8 +45,7 @@ impl<'gc> ByteArrayObject<'gc> {
|
|||
bytes: ByteArrayStorage,
|
||||
) -> Result<Object<'gc>, Error> {
|
||||
let class = activation.avm2().classes().bytearray;
|
||||
let proto = activation.avm2().prototypes().bytearray;
|
||||
let base = ScriptObjectData::base_new(Some(proto), Some(class));
|
||||
let base = ScriptObjectData::new(class);
|
||||
|
||||
let mut instance: Object<'gc> = ByteArrayObject(GcCell::allocate(
|
||||
activation.context.gc_context,
|
||||
|
|
|
@ -134,7 +134,7 @@ impl<'gc> ClassObject<'gc> {
|
|||
class_object.link_prototype(activation, class_proto)?;
|
||||
|
||||
let class_class = activation.avm2().classes().class;
|
||||
let class_class_proto = activation.avm2().prototypes().class;
|
||||
let class_class_proto = class_class.prototype();
|
||||
|
||||
class_object.link_type(activation, class_class_proto, class_class);
|
||||
class_object.into_finished_class(activation)
|
||||
|
@ -877,7 +877,6 @@ impl<'gc> TObject<'gc> for ClassObject<'gc> {
|
|||
let class_proto = self.allocate_prototype(activation, superclass_object)?;
|
||||
|
||||
let class_class = activation.avm2().classes().class;
|
||||
let class_class_proto = activation.avm2().prototypes().class;
|
||||
|
||||
let constructor = self.0.read().constructor.clone();
|
||||
let native_constructor = self.0.read().native_constructor.clone();
|
||||
|
@ -886,7 +885,7 @@ impl<'gc> TObject<'gc> for ClassObject<'gc> {
|
|||
let mut class_object = ClassObject(GcCell::allocate(
|
||||
activation.context.gc_context,
|
||||
ClassObjectData {
|
||||
base: ScriptObjectData::base_new(Some(class_class_proto), Some(class_class)),
|
||||
base: ScriptObjectData::new(class_class),
|
||||
class: parameterized_class,
|
||||
prototype: None,
|
||||
class_scope,
|
||||
|
|
|
@ -49,8 +49,7 @@ impl<'gc> DomainObject<'gc> {
|
|||
domain: Domain<'gc>,
|
||||
) -> Result<Object<'gc>, Error> {
|
||||
let class = activation.avm2().classes().application_domain;
|
||||
let proto = activation.avm2().prototypes().application_domain;
|
||||
let base = ScriptObjectData::base_new(Some(proto), Some(class));
|
||||
let base = ScriptObjectData::new(class);
|
||||
let mut this: Object<'gc> = DomainObject(GcCell::allocate(
|
||||
activation.context.gc_context,
|
||||
DomainObjectData { base, domain },
|
||||
|
|
|
@ -42,7 +42,7 @@ impl<'gc> FunctionObject<'gc> {
|
|||
let this = Self::from_method(activation, method, scope, None, None);
|
||||
let es3_proto = ScriptObject::object(
|
||||
activation.context.gc_context,
|
||||
activation.avm2().prototypes().object,
|
||||
activation.avm2().classes().object.prototype(),
|
||||
);
|
||||
|
||||
this.0.write(activation.context.gc_context).prototype = Some(es3_proto);
|
||||
|
@ -61,14 +61,13 @@ impl<'gc> FunctionObject<'gc> {
|
|||
receiver: Option<Object<'gc>>,
|
||||
subclass_object: Option<ClassObject<'gc>>,
|
||||
) -> FunctionObject<'gc> {
|
||||
let fn_proto = activation.avm2().prototypes().function;
|
||||
let fn_class = activation.avm2().classes().function;
|
||||
let exec = Executable::from_method(method, scope, receiver, subclass_object);
|
||||
|
||||
FunctionObject(GcCell::allocate(
|
||||
activation.context.gc_context,
|
||||
FunctionObjectData {
|
||||
base: ScriptObjectData::base_new(Some(fn_proto), Some(fn_class)),
|
||||
base: ScriptObjectData::new(fn_class),
|
||||
exec,
|
||||
prototype: None,
|
||||
},
|
||||
|
|
|
@ -71,8 +71,7 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
root: DisplayObject<'gc>,
|
||||
) -> Result<Object<'gc>, Error> {
|
||||
let class = activation.avm2().classes().loaderinfo;
|
||||
let proto = activation.avm2().prototypes().loaderinfo;
|
||||
let base = ScriptObjectData::base_new(Some(proto), Some(class));
|
||||
let base = ScriptObjectData::new(class);
|
||||
let loaded_stream = Some(LoaderStream::Swf(movie, root));
|
||||
|
||||
let mut this: Object<'gc> = LoaderInfoObject(GcCell::allocate(
|
||||
|
@ -93,8 +92,7 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
/// Create a loader info object for the stage.
|
||||
pub fn from_stage(activation: &mut Activation<'_, 'gc, '_>) -> Result<Object<'gc>, Error> {
|
||||
let class = activation.avm2().classes().loaderinfo;
|
||||
let proto = activation.avm2().prototypes().loaderinfo;
|
||||
let base = ScriptObjectData::base_new(Some(proto), Some(class));
|
||||
let base = ScriptObjectData::new(class);
|
||||
|
||||
let mut this: Object<'gc> = LoaderInfoObject(GcCell::allocate(
|
||||
activation.context.gc_context,
|
||||
|
|
|
@ -49,8 +49,7 @@ impl<'gc> NamespaceObject<'gc> {
|
|||
namespace: Namespace<'gc>,
|
||||
) -> Result<Object<'gc>, Error> {
|
||||
let class = activation.avm2().classes().namespace;
|
||||
let proto = activation.avm2().prototypes().namespace;
|
||||
let base = ScriptObjectData::base_new(Some(proto), Some(class));
|
||||
let base = ScriptObjectData::new(class);
|
||||
|
||||
let mut this: Object<'gc> = NamespaceObject(GcCell::allocate(
|
||||
activation.context.gc_context,
|
||||
|
|
|
@ -65,14 +65,6 @@ impl<'gc> PrimitiveObject<'gc> {
|
|||
return Err("Cannot box a null value".into());
|
||||
}
|
||||
|
||||
let proto = match primitive {
|
||||
Value::Bool(_) => activation.avm2().prototypes().boolean,
|
||||
Value::Number(_) => activation.avm2().prototypes().number,
|
||||
Value::Unsigned(_) => activation.avm2().prototypes().uint,
|
||||
Value::Integer(_) => activation.avm2().prototypes().int,
|
||||
Value::String(_) => activation.avm2().prototypes().string,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let class = match primitive {
|
||||
Value::Bool(_) => activation.avm2().classes().boolean,
|
||||
Value::Number(_) => activation.avm2().classes().number,
|
||||
|
@ -82,7 +74,7 @@ impl<'gc> PrimitiveObject<'gc> {
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let base = ScriptObjectData::base_new(Some(proto), Some(class));
|
||||
let base = ScriptObjectData::new(class);
|
||||
let mut this: Object<'gc> = PrimitiveObject(GcCell::allocate(
|
||||
activation.context.gc_context,
|
||||
PrimitiveObjectData { base, primitive },
|
||||
|
|
|
@ -46,8 +46,7 @@ impl<'gc> QNameObject<'gc> {
|
|||
qname: QName<'gc>,
|
||||
) -> Result<Object<'gc>, Error> {
|
||||
let class = activation.avm2().classes().qname;
|
||||
let proto = activation.avm2().prototypes().qname;
|
||||
let base = ScriptObjectData::base_new(Some(proto), Some(class));
|
||||
let base = ScriptObjectData::new(class);
|
||||
|
||||
let mut this: Object<'gc> = QNameObject(GcCell::allocate(
|
||||
activation.context.gc_context,
|
||||
|
|
|
@ -47,8 +47,7 @@ impl<'gc> RegExpObject<'gc> {
|
|||
regexp: RegExp<'gc>,
|
||||
) -> Result<Object<'gc>, Error> {
|
||||
let class = activation.avm2().classes().regexp;
|
||||
let proto = activation.avm2().prototypes().regexp;
|
||||
let base = ScriptObjectData::base_new(Some(proto), Some(class));
|
||||
let base = ScriptObjectData::new(class);
|
||||
|
||||
let mut this: Object<'gc> = RegExpObject(GcCell::allocate(
|
||||
activation.context.gc_context,
|
||||
|
|
|
@ -132,6 +132,18 @@ impl<'gc> ScriptObjectData<'gc> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new(instance_of: ClassObject<'gc>) -> Self {
|
||||
ScriptObjectData {
|
||||
values: Default::default(),
|
||||
slots: Vec::new(),
|
||||
bound_methods: Vec::new(),
|
||||
proto: Some(instance_of.prototype()),
|
||||
instance_of: Some(instance_of),
|
||||
vtable: Some(instance_of.instance_vtable()),
|
||||
enumerants: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_property_local(
|
||||
&self,
|
||||
multiname: &Multiname<'gc>,
|
||||
|
|
|
@ -94,11 +94,10 @@ impl<'gc> StageObject<'gc> {
|
|||
display_object: DisplayObject<'gc>,
|
||||
) -> Result<Self, Error> {
|
||||
let class = activation.avm2().classes().graphics;
|
||||
let proto = activation.avm2().prototypes().graphics;
|
||||
let mut this = Self(GcCell::allocate(
|
||||
activation.context.gc_context,
|
||||
StageObjectData {
|
||||
base: ScriptObjectData::base_new(Some(proto), Some(class)),
|
||||
base: ScriptObjectData::new(class),
|
||||
display_object: Some(display_object),
|
||||
},
|
||||
));
|
||||
|
|
|
@ -46,8 +46,7 @@ impl<'gc> TextFormatObject<'gc> {
|
|||
text_format: TextFormat,
|
||||
) -> Result<Object<'gc>, Error> {
|
||||
let class = activation.avm2().classes().textformat;
|
||||
let proto = activation.avm2().prototypes().textformat;
|
||||
let base = ScriptObjectData::base_new(Some(proto), Some(class));
|
||||
let base = ScriptObjectData::new(class);
|
||||
|
||||
let mut this: Object<'gc> = Self(GcCell::allocate(
|
||||
activation.context.gc_context,
|
||||
|
|
Loading…
Reference in New Issue