From f169070106bcdadd70057fe4dad050c91afd0027 Mon Sep 17 00:00:00 2001 From: Adrian Wielgosik Date: Thu, 26 May 2022 13:56:29 +0200 Subject: [PATCH] avm2: Pull methods' scopes from vtable, not class --- core/src/avm2/object.rs | 7 +++--- core/src/avm2/object/class_object.rs | 23 ++++++++---------- core/src/avm2/script.rs | 2 +- core/src/avm2/vtable.rs | 35 ++++++++++++++-------------- 4 files changed, 32 insertions(+), 35 deletions(-) diff --git a/core/src/avm2/object.rs b/core/src/avm2/object.rs index 6ea17f6a1..a769d8a07 100644 --- a/core/src/avm2/object.rs +++ b/core/src/avm2/object.rs @@ -303,14 +303,13 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy } Some(Property::Method { disp_id }) => { let vtable = self.vtable().unwrap(); - if let Some((superclass, method)) = vtable.get_full_method(disp_id) { + if let Some((superclass, scope, method)) = vtable.get_full_method(disp_id) { if !method.needs_arguments_object() { - let scope = superclass.unwrap().instance_scope(); - Executable::from_method(method, scope, None, superclass).exec( + Executable::from_method(method, scope, None, Some(superclass)).exec( Some(self.into()), arguments, activation, - superclass.unwrap().into(), //Deliberately invalid. + superclass.into(), //Deliberately invalid. ) } else { if let Some(bound_method) = self.get_bound_method(disp_id) { diff --git a/core/src/avm2/object/class_object.rs b/core/src/avm2/object/class_object.rs index dfcb68460..7e0c1acf2 100644 --- a/core/src/avm2/object/class_object.rs +++ b/core/src/avm2/object/class_object.rs @@ -245,7 +245,7 @@ impl<'gc> ClassObject<'gc> { class.read().validate_class(self.superclass_object())?; self.instance_vtable().init_vtable( - Some(self), + self, class.read().instance_traits(), self.instance_scope(), self.superclass_object().map(|cls| cls.instance_vtable()), @@ -254,7 +254,7 @@ impl<'gc> ClassObject<'gc> { // class vtable == class traits + Class instance traits self.class_vtable().init_vtable( - Some(self), + self, class.read().class_traits(), self.class_scope(), Some(self.instance_of().unwrap().instance_vtable()), @@ -542,15 +542,14 @@ impl<'gc> ClassObject<'gc> { } if let Some(Property::Method { disp_id, .. }) = property { // todo: handle errors - let (superclass_object, method) = + let (superclass_object, scope, method) = self.instance_vtable().get_full_method(disp_id).unwrap(); - let scope = superclass_object.unwrap().instance_scope(); let callee = FunctionObject::from_method( activation, method.clone(), scope, Some(reciever), - superclass_object, + Some(superclass_object), ); callee.call(Some(reciever), arguments, activation) @@ -602,15 +601,14 @@ impl<'gc> ClassObject<'gc> { }) = property { // todo: handle errors - let (superclass_object, method) = + let (superclass_object, scope, method) = self.instance_vtable().get_full_method(disp_id).unwrap(); - let scope = superclass_object.unwrap().class_scope(); let callee = FunctionObject::from_method( activation, method.clone(), scope, Some(reciever), - superclass_object, + Some(superclass_object), ); callee.call(Some(reciever), &[], activation) @@ -664,15 +662,14 @@ impl<'gc> ClassObject<'gc> { }) = property { // todo: handle errors - let (superclass_object, method) = + let (superclass_object, scope, method) = self.instance_vtable().get_full_method(disp_id).unwrap(); - let scope = superclass_object.unwrap().class_scope(); let callee = FunctionObject::from_method( activation, method.clone(), scope, Some(reciever), - superclass_object, + Some(superclass_object), ); callee.call(Some(reciever), &[value], activation)?; @@ -904,7 +901,7 @@ impl<'gc> TObject<'gc> for ClassObject<'gc> { .validate_class(class_object.superclass_object())?; class_object.instance_vtable().init_vtable( - Some(class_object), + class_object, parameterized_class.read().instance_traits(), class_object.instance_scope(), class_object @@ -915,7 +912,7 @@ impl<'gc> TObject<'gc> for ClassObject<'gc> { // class vtable == class traits + Class instance traits class_object.class_vtable().init_vtable( - Some(class_object), + class_object, parameterized_class.read().class_traits(), class_object.class_scope(), Some(class_object.instance_of().unwrap().instance_vtable()), diff --git a/core/src/avm2/script.rs b/core/src/avm2/script.rs index 031f8248a..1cb621f4e 100644 --- a/core/src/avm2/script.rs +++ b/core/src/avm2/script.rs @@ -379,7 +379,7 @@ impl<'gc> Script<'gc> { let scope = ScopeChain::new(domain); globals.vtable().unwrap().init_vtable( - None, + globals.instance_of().unwrap(), &self.traits()?, scope, None, diff --git a/core/src/avm2/vtable.rs b/core/src/avm2/vtable.rs index 3c4126a47..a15d1cdd1 100644 --- a/core/src/avm2/vtable.rs +++ b/core/src/avm2/vtable.rs @@ -19,6 +19,7 @@ pub struct VTable<'gc>(GcCell<'gc, VTableData<'gc>>); #[derive(Collect, Debug, Clone)] #[collect(no_drop)] pub struct VTableData<'gc> { + /// should always be Some post-initialization defining_class: Option>, /// should always be Some post-initialization @@ -28,7 +29,7 @@ pub struct VTableData<'gc> { resolved_traits: PropertyMap<'gc, Property>, - method_table: Vec<(Option>, Method<'gc>)>, + method_table: Vec<(ClassObject<'gc>, ScopeChain<'gc>, Method<'gc>)>, default_slots: Vec>>, } @@ -73,10 +74,13 @@ impl<'gc> VTable<'gc> { .method_table .get(disp_id as usize) .cloned() - .map(|x| x.1) + .map(|x| x.2) } - pub fn get_full_method(self, disp_id: u32) -> Option<(Option>, Method<'gc>)> { + pub fn get_full_method( + self, + disp_id: u32, + ) -> Option<(ClassObject<'gc>, ScopeChain<'gc>, Method<'gc>)> { self.0.read().method_table.get(disp_id as usize).cloned() } @@ -92,7 +96,7 @@ impl<'gc> VTable<'gc> { #[allow(clippy::if_same_then_else)] pub fn init_vtable( self, - defining_class: Option>, + defining_class: ClassObject<'gc>, traits: &[Trait<'gc>], scope: ScopeChain<'gc>, superclass_vtable: Option, @@ -152,15 +156,13 @@ impl<'gc> VTable<'gc> { let mut write = self.0.write(activation.context.gc_context); let write = write.deref_mut(); - write.defining_class = defining_class; + write.defining_class = Some(defining_class); write.scope = Some(scope); - if let Some(defining_class) = defining_class { - write.protected_namespace = defining_class - .inner_class_definition() - .read() - .protected_namespace(); - } + write.protected_namespace = defining_class + .inner_class_definition() + .read() + .protected_namespace(); if let Some(superclass_vtable) = superclass_vtable { write.resolved_traits = superclass_vtable.0.read().resolved_traits.clone(); @@ -193,7 +195,7 @@ impl<'gc> VTable<'gc> { for trait_data in traits { match trait_data.kind() { TraitKind::Method { method, .. } => { - let entry = (defining_class, method.clone()); + let entry = (defining_class, scope, method.clone()); match resolved_traits.get(trait_data.name()) { Some(Property::Method { disp_id, .. }) => { let disp_id = *disp_id as usize; @@ -210,7 +212,7 @@ impl<'gc> VTable<'gc> { } } TraitKind::Getter { method, .. } => { - let entry = (defining_class, method.clone()); + let entry = (defining_class, scope, method.clone()); match resolved_traits.get_mut(trait_data.name()) { Some(Property::Virtual { get: Some(disp_id), .. @@ -232,7 +234,7 @@ impl<'gc> VTable<'gc> { } } TraitKind::Setter { method, .. } => { - let entry = (defining_class, method.clone()); + let entry = (defining_class, scope, method.clone()); match resolved_traits.get_mut(trait_data.name()) { Some(Property::Virtual { set: Some(disp_id), .. @@ -310,14 +312,13 @@ impl<'gc> VTable<'gc> { receiver: Object<'gc>, disp_id: u32, ) -> Option> { - if let Some((superclass, method)) = self.get_full_method(disp_id) { - let scope = self.0.read().scope.unwrap(); + if let Some((superclass, scope, method)) = self.get_full_method(disp_id) { Some(FunctionObject::from_method( activation, method, scope, Some(receiver), - superclass, + Some(superclass), )) } else { None