avm2: Slot lookups don't need the whole trait list, just the first one we find.
This commit is contained in:
parent
fd08a6ebf6
commit
041003f256
|
@ -111,16 +111,10 @@ fn do_trait_lookup<'gc>(
|
|||
}
|
||||
|
||||
/// Find traits in a list of traits matching a slot ID.
|
||||
///
|
||||
/// This function also enforces final/override bits on the traits, and will
|
||||
/// raise `VerifyError`s as needed.
|
||||
///
|
||||
/// TODO: This is an O(n^2) algorithm, it sucks.
|
||||
fn do_trait_lookup_by_slot<'gc>(
|
||||
id: u32,
|
||||
known_traits: &mut Vec<Trait<'gc>>,
|
||||
all_traits: &[Trait<'gc>],
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<Option<Trait<'gc>>, Error> {
|
||||
for trait_entry in all_traits {
|
||||
let trait_id = match trait_entry.kind() {
|
||||
TraitKind::Slot { slot_id, .. } => slot_id,
|
||||
|
@ -131,21 +125,11 @@ fn do_trait_lookup_by_slot<'gc>(
|
|||
};
|
||||
|
||||
if id == *trait_id {
|
||||
for known_trait in known_traits.iter() {
|
||||
if known_trait.is_final() {
|
||||
return Err("Attempting to override a final definition".into());
|
||||
}
|
||||
|
||||
if !trait_entry.is_override() {
|
||||
return Err("Definition override is not marked as override".into());
|
||||
}
|
||||
}
|
||||
|
||||
known_traits.push(trait_entry.clone());
|
||||
return Ok(Some(trait_entry.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
impl<'gc> Class<'gc> {
|
||||
|
@ -394,12 +378,8 @@ impl<'gc> Class<'gc> {
|
|||
/// If a given trait has an invalid name, attempts to override a final trait,
|
||||
/// or overlaps an existing trait without being an override, then this function
|
||||
/// returns an error.
|
||||
pub fn lookup_class_traits_by_slot(
|
||||
&self,
|
||||
id: u32,
|
||||
known_traits: &mut Vec<Trait<'gc>>,
|
||||
) -> Result<(), Error> {
|
||||
do_trait_lookup_by_slot(id, known_traits, &self.class_traits)
|
||||
pub fn lookup_class_traits_by_slot(&self, id: u32) -> Result<Option<Trait<'gc>>, Error> {
|
||||
do_trait_lookup_by_slot(id, &self.class_traits)
|
||||
}
|
||||
|
||||
/// Determines if this class provides a given trait on itself.
|
||||
|
@ -465,12 +445,8 @@ impl<'gc> Class<'gc> {
|
|||
/// If a given trait has an invalid name, attempts to override a final trait,
|
||||
/// or overlaps an existing trait without being an override, then this function
|
||||
/// returns an error.
|
||||
pub fn lookup_instance_traits_by_slot(
|
||||
&self,
|
||||
id: u32,
|
||||
known_traits: &mut Vec<Trait<'gc>>,
|
||||
) -> Result<(), Error> {
|
||||
do_trait_lookup_by_slot(id, known_traits, &self.instance_traits)
|
||||
pub fn lookup_instance_traits_by_slot(&self, id: u32) -> Result<Option<Trait<'gc>>, Error> {
|
||||
do_trait_lookup_by_slot(id, &self.instance_traits)
|
||||
}
|
||||
|
||||
/// Determines if this class provides a given trait on its instances.
|
||||
|
|
|
@ -317,11 +317,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
/// not instances. For resolving traits for normal `TObject` methods, use
|
||||
/// `get_trait` and `has_trait` as it will tell you if the current object
|
||||
/// has a given trait.
|
||||
fn get_provided_trait_slot(
|
||||
&self,
|
||||
id: u32,
|
||||
known_traits: &mut Vec<Trait<'gc>>,
|
||||
) -> Result<(), Error>;
|
||||
fn get_provided_trait_slot(&self, id: u32) -> Result<Option<Trait<'gc>>, Error>;
|
||||
|
||||
/// Retrieves the scope chain of the object at time of its creation.
|
||||
///
|
||||
|
|
|
@ -140,15 +140,8 @@ macro_rules! impl_avm2_custom_object {
|
|||
self.0.read().$field.get_provided_trait(name, known_traits)
|
||||
}
|
||||
|
||||
fn get_provided_trait_slot(
|
||||
&self,
|
||||
id: u32,
|
||||
known_traits: &mut Vec<Trait<'gc>>,
|
||||
) -> Result<(), Error> {
|
||||
self.0
|
||||
.read()
|
||||
.$field
|
||||
.get_provided_trait_slot(id, known_traits)
|
||||
fn get_provided_trait_slot(&self, id: u32) -> Result<Option<Trait<'gc>>, Error> {
|
||||
self.0.read().$field.get_provided_trait_slot(id)
|
||||
}
|
||||
|
||||
fn get_scope(self) -> Option<GcCell<'gc, Scope<'gc>>> {
|
||||
|
|
|
@ -180,12 +180,8 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
|
|||
self.0.read().get_provided_trait(name, known_traits)
|
||||
}
|
||||
|
||||
fn get_provided_trait_slot(
|
||||
&self,
|
||||
id: u32,
|
||||
known_traits: &mut Vec<Trait<'gc>>,
|
||||
) -> Result<(), Error> {
|
||||
self.0.read().get_provided_trait_slot(id, known_traits)
|
||||
fn get_provided_trait_slot(&self, id: u32) -> Result<Option<Trait<'gc>>, Error> {
|
||||
self.0.read().get_provided_trait_slot(id)
|
||||
}
|
||||
|
||||
fn get_scope(self) -> Option<GcCell<'gc, Scope<'gc>>> {
|
||||
|
@ -623,12 +619,7 @@ impl<'gc> ScriptObjectData<'gc> {
|
|||
pub fn get_trait_slot(&self, id: u32) -> Result<Option<Trait<'gc>>, Error> {
|
||||
match &self.class {
|
||||
//Class constructors have local slot traits only.
|
||||
ScriptObjectClass::ClassConstructor(..) => {
|
||||
let mut known_traits = Vec::new();
|
||||
self.get_provided_trait_slot(id, &mut known_traits)?;
|
||||
|
||||
Ok(known_traits.first().cloned())
|
||||
}
|
||||
ScriptObjectClass::ClassConstructor(..) => self.get_provided_trait_slot(id),
|
||||
|
||||
//Prototypes do not have traits available locally, but they provide
|
||||
//traits instead.
|
||||
|
@ -637,20 +628,17 @@ impl<'gc> ScriptObjectData<'gc> {
|
|||
//Instances walk the prototype chain to build a list of known
|
||||
//traits provided by the classes attached to those prototypes.
|
||||
ScriptObjectClass::NoClass => {
|
||||
let mut known_traits = Vec::new();
|
||||
let mut chain = Vec::new();
|
||||
let mut proto = self.proto();
|
||||
|
||||
while let Some(p) = proto {
|
||||
chain.push(p);
|
||||
if let Some(trait_val) = p.get_provided_trait_slot(id)? {
|
||||
return Ok(Some(trait_val));
|
||||
}
|
||||
|
||||
proto = p.proto();
|
||||
}
|
||||
|
||||
for proto in chain.iter().rev() {
|
||||
proto.get_provided_trait_slot(id, &mut known_traits)?;
|
||||
}
|
||||
|
||||
Ok(known_traits.first().cloned())
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -671,19 +659,15 @@ impl<'gc> ScriptObjectData<'gc> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_provided_trait_slot(
|
||||
&self,
|
||||
id: u32,
|
||||
known_traits: &mut Vec<Trait<'gc>>,
|
||||
) -> Result<(), Error> {
|
||||
pub fn get_provided_trait_slot(&self, id: u32) -> Result<Option<Trait<'gc>>, Error> {
|
||||
match &self.class {
|
||||
ScriptObjectClass::ClassConstructor(class, ..) => {
|
||||
class.read().lookup_class_traits_by_slot(id, known_traits)
|
||||
class.read().lookup_class_traits_by_slot(id)
|
||||
}
|
||||
ScriptObjectClass::InstancePrototype(class, ..) => class
|
||||
.read()
|
||||
.lookup_instance_traits_by_slot(id, known_traits),
|
||||
ScriptObjectClass::NoClass => Ok(()),
|
||||
ScriptObjectClass::InstancePrototype(class, ..) => {
|
||||
class.read().lookup_instance_traits_by_slot(id)
|
||||
}
|
||||
ScriptObjectClass::NoClass => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -181,12 +181,8 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
|
|||
self.0.read().base.get_provided_trait(name, known_traits)
|
||||
}
|
||||
|
||||
fn get_provided_trait_slot(
|
||||
&self,
|
||||
id: u32,
|
||||
known_traits: &mut Vec<Trait<'gc>>,
|
||||
) -> Result<(), Error> {
|
||||
self.0.read().base.get_provided_trait_slot(id, known_traits)
|
||||
fn get_provided_trait_slot(&self, id: u32) -> Result<Option<Trait<'gc>>, Error> {
|
||||
self.0.read().base.get_provided_trait_slot(id)
|
||||
}
|
||||
|
||||
fn get_scope(self) -> Option<GcCell<'gc, Scope<'gc>>> {
|
||||
|
|
Loading…
Reference in New Issue