avm2: Pull methods' scopes from vtable, not class

This commit is contained in:
Adrian Wielgosik 2022-05-26 13:56:29 +02:00
parent 15cb9a9ce6
commit f169070106
4 changed files with 32 additions and 35 deletions

View File

@ -303,14 +303,13 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
} }
Some(Property::Method { disp_id }) => { Some(Property::Method { disp_id }) => {
let vtable = self.vtable().unwrap(); 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() { if !method.needs_arguments_object() {
let scope = superclass.unwrap().instance_scope(); Executable::from_method(method, scope, None, Some(superclass)).exec(
Executable::from_method(method, scope, None, superclass).exec(
Some(self.into()), Some(self.into()),
arguments, arguments,
activation, activation,
superclass.unwrap().into(), //Deliberately invalid. superclass.into(), //Deliberately invalid.
) )
} else { } else {
if let Some(bound_method) = self.get_bound_method(disp_id) { if let Some(bound_method) = self.get_bound_method(disp_id) {

View File

@ -245,7 +245,7 @@ impl<'gc> ClassObject<'gc> {
class.read().validate_class(self.superclass_object())?; class.read().validate_class(self.superclass_object())?;
self.instance_vtable().init_vtable( self.instance_vtable().init_vtable(
Some(self), self,
class.read().instance_traits(), class.read().instance_traits(),
self.instance_scope(), self.instance_scope(),
self.superclass_object().map(|cls| cls.instance_vtable()), self.superclass_object().map(|cls| cls.instance_vtable()),
@ -254,7 +254,7 @@ impl<'gc> ClassObject<'gc> {
// class vtable == class traits + Class instance traits // class vtable == class traits + Class instance traits
self.class_vtable().init_vtable( self.class_vtable().init_vtable(
Some(self), self,
class.read().class_traits(), class.read().class_traits(),
self.class_scope(), self.class_scope(),
Some(self.instance_of().unwrap().instance_vtable()), Some(self.instance_of().unwrap().instance_vtable()),
@ -542,15 +542,14 @@ impl<'gc> ClassObject<'gc> {
} }
if let Some(Property::Method { disp_id, .. }) = property { if let Some(Property::Method { disp_id, .. }) = property {
// todo: handle errors // todo: handle errors
let (superclass_object, method) = let (superclass_object, scope, method) =
self.instance_vtable().get_full_method(disp_id).unwrap(); self.instance_vtable().get_full_method(disp_id).unwrap();
let scope = superclass_object.unwrap().instance_scope();
let callee = FunctionObject::from_method( let callee = FunctionObject::from_method(
activation, activation,
method.clone(), method.clone(),
scope, scope,
Some(reciever), Some(reciever),
superclass_object, Some(superclass_object),
); );
callee.call(Some(reciever), arguments, activation) callee.call(Some(reciever), arguments, activation)
@ -602,15 +601,14 @@ impl<'gc> ClassObject<'gc> {
}) = property }) = property
{ {
// todo: handle errors // todo: handle errors
let (superclass_object, method) = let (superclass_object, scope, method) =
self.instance_vtable().get_full_method(disp_id).unwrap(); self.instance_vtable().get_full_method(disp_id).unwrap();
let scope = superclass_object.unwrap().class_scope();
let callee = FunctionObject::from_method( let callee = FunctionObject::from_method(
activation, activation,
method.clone(), method.clone(),
scope, scope,
Some(reciever), Some(reciever),
superclass_object, Some(superclass_object),
); );
callee.call(Some(reciever), &[], activation) callee.call(Some(reciever), &[], activation)
@ -664,15 +662,14 @@ impl<'gc> ClassObject<'gc> {
}) = property }) = property
{ {
// todo: handle errors // todo: handle errors
let (superclass_object, method) = let (superclass_object, scope, method) =
self.instance_vtable().get_full_method(disp_id).unwrap(); self.instance_vtable().get_full_method(disp_id).unwrap();
let scope = superclass_object.unwrap().class_scope();
let callee = FunctionObject::from_method( let callee = FunctionObject::from_method(
activation, activation,
method.clone(), method.clone(),
scope, scope,
Some(reciever), Some(reciever),
superclass_object, Some(superclass_object),
); );
callee.call(Some(reciever), &[value], activation)?; callee.call(Some(reciever), &[value], activation)?;
@ -904,7 +901,7 @@ impl<'gc> TObject<'gc> for ClassObject<'gc> {
.validate_class(class_object.superclass_object())?; .validate_class(class_object.superclass_object())?;
class_object.instance_vtable().init_vtable( class_object.instance_vtable().init_vtable(
Some(class_object), class_object,
parameterized_class.read().instance_traits(), parameterized_class.read().instance_traits(),
class_object.instance_scope(), class_object.instance_scope(),
class_object class_object
@ -915,7 +912,7 @@ impl<'gc> TObject<'gc> for ClassObject<'gc> {
// class vtable == class traits + Class instance traits // class vtable == class traits + Class instance traits
class_object.class_vtable().init_vtable( class_object.class_vtable().init_vtable(
Some(class_object), class_object,
parameterized_class.read().class_traits(), parameterized_class.read().class_traits(),
class_object.class_scope(), class_object.class_scope(),
Some(class_object.instance_of().unwrap().instance_vtable()), Some(class_object.instance_of().unwrap().instance_vtable()),

View File

@ -379,7 +379,7 @@ impl<'gc> Script<'gc> {
let scope = ScopeChain::new(domain); let scope = ScopeChain::new(domain);
globals.vtable().unwrap().init_vtable( globals.vtable().unwrap().init_vtable(
None, globals.instance_of().unwrap(),
&self.traits()?, &self.traits()?,
scope, scope,
None, None,

View File

@ -19,6 +19,7 @@ pub struct VTable<'gc>(GcCell<'gc, VTableData<'gc>>);
#[derive(Collect, Debug, Clone)] #[derive(Collect, Debug, Clone)]
#[collect(no_drop)] #[collect(no_drop)]
pub struct VTableData<'gc> { pub struct VTableData<'gc> {
/// should always be Some post-initialization
defining_class: Option<ClassObject<'gc>>, defining_class: Option<ClassObject<'gc>>,
/// should always be Some post-initialization /// should always be Some post-initialization
@ -28,7 +29,7 @@ pub struct VTableData<'gc> {
resolved_traits: PropertyMap<'gc, Property>, resolved_traits: PropertyMap<'gc, Property>,
method_table: Vec<(Option<ClassObject<'gc>>, Method<'gc>)>, method_table: Vec<(ClassObject<'gc>, ScopeChain<'gc>, Method<'gc>)>,
default_slots: Vec<Option<Value<'gc>>>, default_slots: Vec<Option<Value<'gc>>>,
} }
@ -73,10 +74,13 @@ impl<'gc> VTable<'gc> {
.method_table .method_table
.get(disp_id as usize) .get(disp_id as usize)
.cloned() .cloned()
.map(|x| x.1) .map(|x| x.2)
} }
pub fn get_full_method(self, disp_id: u32) -> Option<(Option<ClassObject<'gc>>, 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() 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)] #[allow(clippy::if_same_then_else)]
pub fn init_vtable( pub fn init_vtable(
self, self,
defining_class: Option<ClassObject<'gc>>, defining_class: ClassObject<'gc>,
traits: &[Trait<'gc>], traits: &[Trait<'gc>],
scope: ScopeChain<'gc>, scope: ScopeChain<'gc>,
superclass_vtable: Option<Self>, superclass_vtable: Option<Self>,
@ -152,15 +156,13 @@ impl<'gc> VTable<'gc> {
let mut write = self.0.write(activation.context.gc_context); let mut write = self.0.write(activation.context.gc_context);
let write = write.deref_mut(); let write = write.deref_mut();
write.defining_class = defining_class; write.defining_class = Some(defining_class);
write.scope = Some(scope); write.scope = Some(scope);
if let Some(defining_class) = defining_class {
write.protected_namespace = defining_class write.protected_namespace = defining_class
.inner_class_definition() .inner_class_definition()
.read() .read()
.protected_namespace(); .protected_namespace();
}
if let Some(superclass_vtable) = superclass_vtable { if let Some(superclass_vtable) = superclass_vtable {
write.resolved_traits = superclass_vtable.0.read().resolved_traits.clone(); write.resolved_traits = superclass_vtable.0.read().resolved_traits.clone();
@ -193,7 +195,7 @@ impl<'gc> VTable<'gc> {
for trait_data in traits { for trait_data in traits {
match trait_data.kind() { match trait_data.kind() {
TraitKind::Method { method, .. } => { TraitKind::Method { method, .. } => {
let entry = (defining_class, method.clone()); let entry = (defining_class, scope, method.clone());
match resolved_traits.get(trait_data.name()) { match resolved_traits.get(trait_data.name()) {
Some(Property::Method { disp_id, .. }) => { Some(Property::Method { disp_id, .. }) => {
let disp_id = *disp_id as usize; let disp_id = *disp_id as usize;
@ -210,7 +212,7 @@ impl<'gc> VTable<'gc> {
} }
} }
TraitKind::Getter { method, .. } => { TraitKind::Getter { method, .. } => {
let entry = (defining_class, method.clone()); let entry = (defining_class, scope, method.clone());
match resolved_traits.get_mut(trait_data.name()) { match resolved_traits.get_mut(trait_data.name()) {
Some(Property::Virtual { Some(Property::Virtual {
get: Some(disp_id), .. get: Some(disp_id), ..
@ -232,7 +234,7 @@ impl<'gc> VTable<'gc> {
} }
} }
TraitKind::Setter { method, .. } => { TraitKind::Setter { method, .. } => {
let entry = (defining_class, method.clone()); let entry = (defining_class, scope, method.clone());
match resolved_traits.get_mut(trait_data.name()) { match resolved_traits.get_mut(trait_data.name()) {
Some(Property::Virtual { Some(Property::Virtual {
set: Some(disp_id), .. set: Some(disp_id), ..
@ -310,14 +312,13 @@ impl<'gc> VTable<'gc> {
receiver: Object<'gc>, receiver: Object<'gc>,
disp_id: u32, disp_id: u32,
) -> Option<FunctionObject<'gc>> { ) -> Option<FunctionObject<'gc>> {
if let Some((superclass, method)) = self.get_full_method(disp_id) { if let Some((superclass, scope, method)) = self.get_full_method(disp_id) {
let scope = self.0.read().scope.unwrap();
Some(FunctionObject::from_method( Some(FunctionObject::from_method(
activation, activation,
method, method,
scope, scope,
Some(receiver), Some(receiver),
superclass, Some(superclass),
)) ))
} else { } else {
None None