avm2: Remove all classless objects
This commit is contained in:
parent
953a02533f
commit
6cc1488f73
|
@ -81,8 +81,8 @@ pub use crate::avm2::globals::flash::ui::context_menu::make_context_menu_state;
|
|||
pub use crate::avm2::multiname::Multiname;
|
||||
pub use crate::avm2::namespace::Namespace;
|
||||
pub use crate::avm2::object::{
|
||||
ArrayObject, BitmapDataObject, ClassObject, EventObject, Object, ScriptObject,
|
||||
SoundChannelObject, StageObject, TObject,
|
||||
ArrayObject, BitmapDataObject, ClassObject, EventObject, Object, SoundChannelObject,
|
||||
StageObject, TObject,
|
||||
};
|
||||
pub use crate::avm2::qname::QName;
|
||||
pub use crate::avm2::value::Value;
|
||||
|
|
|
@ -1589,9 +1589,9 @@ impl<'a, 'gc> Activation<'a, 'gc> {
|
|||
let vname = ex.variable_name;
|
||||
|
||||
let so = if let Some(vname) = vname {
|
||||
ScriptObject::catch_scope(self.context.gc_context, &vname)
|
||||
ScriptObject::catch_scope(self, &vname)
|
||||
} else {
|
||||
// for `finally` scopes, FP just creates a bare object.
|
||||
// for `finally` scopes, FP just creates a normal object.
|
||||
self.avm2().classes().object.construct(self, &[])?
|
||||
};
|
||||
|
||||
|
|
|
@ -472,12 +472,7 @@ pub fn load_player_globals<'gc>(
|
|||
) -> Result<(), Error<'gc>> {
|
||||
let mc = activation.context.gc_context;
|
||||
|
||||
let globals = ScriptObject::custom_object(mc, None, None);
|
||||
let gs = ScopeChain::new(domain).chain(mc, &[Scope::new(globals)]);
|
||||
let script = Script::empty_script(mc, globals, domain);
|
||||
|
||||
// Set the outer scope of this activation to the global scope.
|
||||
activation.set_outer(gs);
|
||||
|
||||
// public / root package
|
||||
//
|
||||
|
@ -510,22 +505,31 @@ pub fn load_player_globals<'gc>(
|
|||
class_i_class.set_c_class(mc, class_c_class);
|
||||
class_c_class.set_i_class(mc, class_i_class);
|
||||
|
||||
domain.export_class(object_i_class.name(), object_i_class, mc);
|
||||
domain.export_class(class_i_class.name(), class_i_class, mc);
|
||||
|
||||
// Function is more of a "normal" class than the other two, so we can create it normally.
|
||||
let fn_classdef = function::create_class(activation, object_i_class, class_i_class);
|
||||
|
||||
// Register the classes in the domain, now
|
||||
domain.export_class(object_i_class.name(), object_i_class, mc);
|
||||
domain.export_class(class_i_class.name(), class_i_class, mc);
|
||||
domain.export_class(fn_classdef.name(), fn_classdef, mc);
|
||||
|
||||
// Initialize the script
|
||||
let globals = ScriptObject::custom_object(mc, object_i_class, None, None);
|
||||
let script = Script::empty_script(mc, globals, domain);
|
||||
|
||||
let gs = ScopeChain::new(domain).chain(mc, &[Scope::new(globals)]);
|
||||
activation.set_outer(gs);
|
||||
|
||||
let object_class = ClassObject::from_class_partial(activation, object_i_class, None)?;
|
||||
let object_proto = ScriptObject::custom_object(mc, Some(object_class), None);
|
||||
let object_proto = ScriptObject::custom_object(mc, object_i_class, Some(object_class), None);
|
||||
|
||||
let class_class =
|
||||
ClassObject::from_class_partial(activation, class_i_class, Some(object_class))?;
|
||||
let class_proto = ScriptObject::custom_object(mc, Some(object_class), Some(object_proto));
|
||||
let class_proto =
|
||||
ScriptObject::custom_object(mc, object_i_class, Some(object_class), Some(object_proto));
|
||||
|
||||
let fn_class = ClassObject::from_class_partial(activation, fn_classdef, Some(object_class))?;
|
||||
let fn_proto = ScriptObject::custom_object(mc, Some(fn_class), Some(object_proto));
|
||||
let fn_proto = ScriptObject::custom_object(mc, fn_classdef, Some(fn_class), Some(object_proto));
|
||||
|
||||
// Now to weave the Gordian knot...
|
||||
object_class.link_prototype(activation, object_proto)?;
|
||||
|
|
|
@ -19,7 +19,7 @@ fn dispatch_list<'gc>(
|
|||
)? {
|
||||
Value::Object(o) => Ok(o),
|
||||
_ => {
|
||||
let dispatch_list = DispatchObject::empty_list(activation.context.gc_context);
|
||||
let dispatch_list = DispatchObject::empty_list(activation);
|
||||
this.init_property(
|
||||
&Multiname::new(activation.avm2().flash_events_internal, "_dispatchList"),
|
||||
dispatch_list.into(),
|
||||
|
|
|
@ -163,7 +163,7 @@ impl<'gc> ClassObject<'gc> {
|
|||
let class_object = ClassObject(GcCell::new(
|
||||
activation.context.gc_context,
|
||||
ClassObjectData {
|
||||
base: ScriptObjectData::custom_new(None, None),
|
||||
base: ScriptObjectData::custom_new(c_class, None, None),
|
||||
class,
|
||||
prototype: None,
|
||||
class_scope: scope,
|
||||
|
@ -186,8 +186,6 @@ impl<'gc> ClassObject<'gc> {
|
|||
.instance_scope = instance_scope;
|
||||
class_object.init_instance_vtable(activation)?;
|
||||
|
||||
class_object.set_instance_class(activation.context.gc_context, c_class);
|
||||
|
||||
class.add_class_object(activation.context.gc_context, class_object);
|
||||
|
||||
Ok(class_object)
|
||||
|
|
|
@ -63,12 +63,11 @@ pub struct DispatchObjectData<'gc> {
|
|||
|
||||
impl<'gc> DispatchObject<'gc> {
|
||||
/// Construct an empty dispatch list.
|
||||
pub fn empty_list(mc: &Mutation<'gc>) -> Object<'gc> {
|
||||
// TODO: we might want this to be a proper Object instance, just in case
|
||||
let base = ScriptObjectData::custom_new(None, None);
|
||||
pub fn empty_list(activation: &mut Activation<'_, 'gc>) -> Object<'gc> {
|
||||
let base = ScriptObjectData::new(activation.avm2().classes().object);
|
||||
|
||||
DispatchObject(GcCell::new(
|
||||
mc,
|
||||
activation.context.gc_context,
|
||||
DispatchObjectData {
|
||||
base,
|
||||
dispatch: DispatchList::new(),
|
||||
|
|
|
@ -95,13 +95,11 @@ impl<'gc> FunctionObject<'gc> {
|
|||
scope: ScopeChain<'gc>,
|
||||
) -> Result<FunctionObject<'gc>, Error<'gc>> {
|
||||
let this = Self::from_method(activation, method, scope, None, None);
|
||||
let es3_proto = ScriptObject::custom_object(
|
||||
activation.context.gc_context,
|
||||
// TODO: is this really a class-less object?
|
||||
// (also: how much of "ES3 class-less object" is even true?)
|
||||
None,
|
||||
Some(activation.avm2().classes().object.prototype()),
|
||||
);
|
||||
let es3_proto = activation
|
||||
.avm2()
|
||||
.classes()
|
||||
.object
|
||||
.construct(activation, &[])?;
|
||||
|
||||
this.0.write(activation.context.gc_context).prototype = Some(es3_proto);
|
||||
|
||||
|
@ -204,6 +202,7 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
|
|||
|
||||
let instance = ScriptObject::custom_object(
|
||||
activation.context.gc_context,
|
||||
activation.avm2().classes().object.inner_class_definition(),
|
||||
Some(activation.avm2().classes().object),
|
||||
Some(prototype),
|
||||
);
|
||||
|
|
|
@ -105,23 +105,33 @@ impl<'gc> ScriptObject<'gc> {
|
|||
/// is technically also equivalent and faster, but not recommended outside lower-level Core code)
|
||||
pub fn custom_object(
|
||||
mc: &Mutation<'gc>,
|
||||
class: Option<ClassObject<'gc>>,
|
||||
class: Class<'gc>,
|
||||
class_obj: Option<ClassObject<'gc>>,
|
||||
proto: Option<Object<'gc>>,
|
||||
) -> Object<'gc> {
|
||||
ScriptObject(GcCell::new(mc, ScriptObjectData::custom_new(proto, class))).into()
|
||||
ScriptObject(GcCell::new(
|
||||
mc,
|
||||
ScriptObjectData::custom_new(class, proto, class_obj),
|
||||
))
|
||||
.into()
|
||||
}
|
||||
|
||||
/// A special case for `newcatch` implementation. Basically a variable (q)name
|
||||
/// which maps to slot 1.
|
||||
pub fn catch_scope(mc: &Mutation<'gc>, qname: &QName<'gc>) -> Object<'gc> {
|
||||
pub fn catch_scope(activation: &mut Activation<'_, 'gc>, qname: &QName<'gc>) -> Object<'gc> {
|
||||
// TODO: use a proper ClassObject here; purposefully crafted bytecode
|
||||
// can observe (the lack of) it.
|
||||
let mut base = ScriptObjectData::custom_new(None, None);
|
||||
let vt = VTable::newcatch(mc, qname);
|
||||
let mut base = ScriptObjectData::custom_new(
|
||||
activation.avm2().classes().object.inner_class_definition(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
let vt = VTable::newcatch(activation.context.gc_context, qname);
|
||||
base.set_vtable(vt);
|
||||
base.install_instance_slots();
|
||||
|
||||
ScriptObject(GcCell::new(mc, base)).into()
|
||||
ScriptObject(GcCell::new(activation.context.gc_context, base)).into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,7 +139,11 @@ impl<'gc> ScriptObjectData<'gc> {
|
|||
/// Create new object data of a given class.
|
||||
/// This is a low-level function used to implement things like object allocators.
|
||||
pub fn new(instance_of: ClassObject<'gc>) -> Self {
|
||||
Self::custom_new(Some(instance_of.prototype()), Some(instance_of))
|
||||
Self::custom_new(
|
||||
instance_of.inner_class_definition(),
|
||||
Some(instance_of.prototype()),
|
||||
Some(instance_of),
|
||||
)
|
||||
}
|
||||
|
||||
/// Create new custom object data of a given possibly-none class and prototype.
|
||||
|
@ -137,13 +151,17 @@ impl<'gc> ScriptObjectData<'gc> {
|
|||
/// This should *not* be used, unless you really need
|
||||
/// to do something weird or lazily initialize the object.
|
||||
/// You shouldn't let scripts observe this weirdness.
|
||||
pub fn custom_new(proto: Option<Object<'gc>>, instance_of: Option<ClassObject<'gc>>) -> Self {
|
||||
pub fn custom_new(
|
||||
class: Class<'gc>,
|
||||
proto: Option<Object<'gc>>,
|
||||
instance_of: Option<ClassObject<'gc>>,
|
||||
) -> Self {
|
||||
ScriptObjectData {
|
||||
values: Default::default(),
|
||||
slots: Vec::new(),
|
||||
bound_methods: Vec::new(),
|
||||
proto,
|
||||
instance_class: instance_of.map(|cls| cls.inner_class_definition()),
|
||||
instance_class: Some(class),
|
||||
vtable: instance_of.map(|cls| cls.instance_vtable()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::avm1::Object as Avm1Object;
|
|||
use crate::avm2::object::TObject;
|
||||
use crate::avm2::{
|
||||
Activation as Avm2Activation, Avm2, EventObject as Avm2EventObject, Object as Avm2Object,
|
||||
ScriptObject as Avm2ScriptObject, StageObject as Avm2StageObject, Value as Avm2Value,
|
||||
StageObject as Avm2StageObject, Value as Avm2Value,
|
||||
};
|
||||
use crate::backend::ui::MouseCursor;
|
||||
use crate::config::Letterbox;
|
||||
|
@ -130,10 +130,10 @@ pub struct StageData<'gc> {
|
|||
show_menu: bool,
|
||||
|
||||
/// The AVM2 view of this stage object.
|
||||
avm2_object: Avm2Object<'gc>,
|
||||
avm2_object: Option<Avm2Object<'gc>>,
|
||||
|
||||
/// The AVM2 'LoaderInfo' object for this stage object
|
||||
loader_info: Avm2Object<'gc>,
|
||||
loader_info: Option<Avm2Object<'gc>>,
|
||||
|
||||
/// An array of AVM2 'Stage3D' instances
|
||||
stage3ds: Vec<Avm2Object<'gc>>,
|
||||
|
@ -183,8 +183,8 @@ impl<'gc> Stage<'gc> {
|
|||
window_mode: Default::default(),
|
||||
show_menu: true,
|
||||
stage_focus_rect: true,
|
||||
avm2_object: Avm2ScriptObject::custom_object(gc_context, None, None),
|
||||
loader_info: Avm2ScriptObject::custom_object(gc_context, None, None),
|
||||
avm2_object: None,
|
||||
loader_info: None,
|
||||
stage3ds: vec![],
|
||||
movie,
|
||||
viewport_matrix: Matrix::IDENTITY,
|
||||
|
@ -242,7 +242,7 @@ impl<'gc> Stage<'gc> {
|
|||
}
|
||||
|
||||
pub fn set_loader_info(self, gc_context: &Mutation<'gc>, loader_info: Avm2Object<'gc>) {
|
||||
self.0.write(gc_context).loader_info = loader_info;
|
||||
self.0.write(gc_context).loader_info = Some(loader_info);
|
||||
}
|
||||
|
||||
// Get the invalidation state
|
||||
|
@ -787,7 +787,7 @@ impl<'gc> TDisplayObject<'gc> for Stage<'gc> {
|
|||
match avm2_stage {
|
||||
Ok(avm2_stage) => {
|
||||
let mut write = self.0.write(activation.context.gc_context);
|
||||
write.avm2_object = avm2_stage.into();
|
||||
write.avm2_object = Some(avm2_stage.into());
|
||||
write.stage3ds = vec![stage3d];
|
||||
}
|
||||
Err(e) => tracing::error!("Unable to construct AVM2 Stage: {}", e),
|
||||
|
@ -864,11 +864,15 @@ impl<'gc> TDisplayObject<'gc> for Stage<'gc> {
|
|||
}
|
||||
|
||||
fn object2(&self) -> Avm2Value<'gc> {
|
||||
self.0.read().avm2_object.into()
|
||||
self.0
|
||||
.read()
|
||||
.avm2_object
|
||||
.expect("Attempted to access Stage::object2 before initialization")
|
||||
.into()
|
||||
}
|
||||
|
||||
fn loader_info(&self) -> Option<Avm2Object<'gc>> {
|
||||
Some(self.0.read().loader_info)
|
||||
self.0.read().loader_info
|
||||
}
|
||||
|
||||
fn movie(&self) -> Arc<SwfMovie> {
|
||||
|
|
Loading…
Reference in New Issue