Implement slots and related opcodes.
This commit is contained in:
parent
88957b2b3d
commit
1ab4091050
|
@ -393,6 +393,10 @@ impl<'gc> Avm2<'gc> {
|
|||
Op::FindProperty { index } => self.op_find_property(context, index),
|
||||
Op::FindPropStrict { index } => self.op_find_prop_strict(context, index),
|
||||
Op::GetLex { index } => self.op_get_lex(context, index),
|
||||
Op::GetSlot { index } => self.op_get_slot(index),
|
||||
Op::SetSlot { index } => self.op_set_slot(context, index),
|
||||
Op::GetGlobalSlot { index } => self.op_get_global_slot(index),
|
||||
Op::SetGlobalSlot { index } => self.op_set_global_slot(context, index),
|
||||
_ => self.unknown_op(op),
|
||||
};
|
||||
|
||||
|
@ -641,4 +645,42 @@ impl<'gc> Avm2<'gc> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn op_get_slot(&mut self, index: u32) -> Result<(), Error> {
|
||||
let object = self.pop().as_object()?;
|
||||
let value = object.get_slot(index)?;
|
||||
|
||||
self.push(value);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn op_set_slot(
|
||||
&mut self,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
index: u32,
|
||||
) -> Result<(), Error> {
|
||||
let object = self.pop().as_object()?;
|
||||
let value = self.pop();
|
||||
|
||||
object.set_slot(index, value, context.gc_context)
|
||||
}
|
||||
|
||||
fn op_get_global_slot(&mut self, index: u32) -> Result<(), Error> {
|
||||
let value = self.globals.get_slot(index)?;
|
||||
|
||||
self.push(value);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn op_set_global_slot(
|
||||
&mut self,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
index: u32,
|
||||
) -> Result<(), Error> {
|
||||
let value = self.pop();
|
||||
|
||||
self.globals.set_slot(index, value, context.gc_context)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -339,6 +339,19 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
|
|||
.set_property(name, value, avm, context, self.into())
|
||||
}
|
||||
|
||||
fn get_slot(self, id: u32) -> Result<Value<'gc>, Error> {
|
||||
self.0.read().base.get_slot(id)
|
||||
}
|
||||
|
||||
fn set_slot(
|
||||
self,
|
||||
id: u32,
|
||||
value: Value<'gc>,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
) -> Result<(), Error> {
|
||||
self.0.write(mc).base.set_slot(id, value, mc)
|
||||
}
|
||||
|
||||
fn has_property(self, name: &QName) -> bool {
|
||||
self.0.read().base.has_property(name)
|
||||
}
|
||||
|
|
|
@ -44,6 +44,17 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
) -> Result<(), Error>;
|
||||
|
||||
/// Retrieve a slot by it's index.
|
||||
fn get_slot(self, id: u32) -> Result<Value<'gc>, Error>;
|
||||
|
||||
/// Set a slot by it's index.
|
||||
fn set_slot(
|
||||
self,
|
||||
id: u32,
|
||||
value: Value<'gc>,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
) -> Result<(), Error>;
|
||||
|
||||
/// Resolve a multiname into a single QName, if any of the namespaces
|
||||
/// match.
|
||||
fn resolve_multiname(self, multiname: &Multiname) -> Option<QName> {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use self::Attribute::*;
|
||||
use crate::avm2::function::Executable;
|
||||
use crate::avm2::object::Object;
|
||||
use crate::avm2::object::{Object, TObject};
|
||||
use crate::avm2::return_value::ReturnValue;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::{Avm2, Error};
|
||||
|
@ -33,6 +33,10 @@ pub enum Property<'gc> {
|
|||
value: Value<'gc>,
|
||||
attributes: EnumSet<Attribute>,
|
||||
},
|
||||
Slot {
|
||||
slot_id: u32,
|
||||
attributes: EnumSet<Attribute>,
|
||||
},
|
||||
}
|
||||
|
||||
unsafe impl<'gc> Collect for Property<'gc> {
|
||||
|
@ -43,6 +47,7 @@ unsafe impl<'gc> Collect for Property<'gc> {
|
|||
set.trace(cc);
|
||||
}
|
||||
Property::Stored { value, .. } => value.trace(cc),
|
||||
Property::Slot { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +88,7 @@ impl<'gc> Property<'gc> {
|
|||
match self {
|
||||
Property::Virtual { get, .. } => *get = Some(getter_impl),
|
||||
Property::Stored { .. } => return Err("Not a virtual property".into()),
|
||||
Property::Slot { .. } => return Err("Not a virtual property".into()),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
@ -96,6 +102,7 @@ impl<'gc> Property<'gc> {
|
|||
match self {
|
||||
Property::Virtual { set, .. } => *set = Some(setter_impl),
|
||||
Property::Stored { .. } => return Err("Not a virtual property".into()),
|
||||
Property::Slot { .. } => return Err("Not a virtual property".into()),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
@ -115,6 +122,7 @@ impl<'gc> Property<'gc> {
|
|||
Property::Virtual { get: Some(get), .. } => get.exec(avm, context, this, &[]),
|
||||
Property::Virtual { get: None, .. } => Ok(Value::Undefined.into()),
|
||||
Property::Stored { value, .. } => Ok(value.to_owned().into()),
|
||||
Property::Slot { slot_id, .. } => this.get_slot(*slot_id).map(|v| v.into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,6 +157,9 @@ impl<'gc> Property<'gc> {
|
|||
|
||||
Ok(true)
|
||||
}
|
||||
Property::Slot { slot_id, .. } => this
|
||||
.set_slot(*slot_id, new_value.into(), context.gc_context)
|
||||
.map(|v| true),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,6 +168,7 @@ impl<'gc> Property<'gc> {
|
|||
match self {
|
||||
Property::Virtual { attributes, .. } => *attributes,
|
||||
Property::Stored { attributes, .. } => *attributes,
|
||||
Property::Slot { attributes, .. } => *attributes,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,6 +181,9 @@ impl<'gc> Property<'gc> {
|
|||
Property::Stored {
|
||||
ref mut attributes, ..
|
||||
} => *attributes = new_attributes,
|
||||
Property::Slot {
|
||||
ref mut attributes, ..
|
||||
} => *attributes = new_attributes,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,6 +191,7 @@ impl<'gc> Property<'gc> {
|
|||
match self {
|
||||
Property::Virtual { attributes, .. } => !attributes.contains(DontDelete),
|
||||
Property::Stored { attributes, .. } => !attributes.contains(DontDelete),
|
||||
Property::Slot { attributes, .. } => !attributes.contains(DontDelete),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,6 +199,7 @@ impl<'gc> Property<'gc> {
|
|||
match self {
|
||||
Property::Virtual { attributes, .. } => !attributes.contains(DontEnum),
|
||||
Property::Stored { attributes, .. } => !attributes.contains(DontEnum),
|
||||
Property::Slot { attributes, .. } => !attributes.contains(DontEnum),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,6 +209,7 @@ impl<'gc> Property<'gc> {
|
|||
attributes, set, ..
|
||||
} => !attributes.contains(ReadOnly) && !set.is_none(),
|
||||
Property::Stored { attributes, .. } => !attributes.contains(ReadOnly),
|
||||
Property::Slot { attributes, .. } => !attributes.contains(ReadOnly),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,9 @@ pub struct ScriptObjectData<'gc> {
|
|||
/// Properties stored on this object.
|
||||
values: HashMap<QName, Property<'gc>>,
|
||||
|
||||
/// Slots stored on this object.
|
||||
slots: Vec<Value<'gc>>,
|
||||
|
||||
/// Implicit prototype (or declared base class) of this script object.
|
||||
proto: Option<Object<'gc>>,
|
||||
}
|
||||
|
@ -54,6 +57,19 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
|
|||
.set_property(name, value, avm, context, self.into())
|
||||
}
|
||||
|
||||
fn get_slot(self, id: u32) -> Result<Value<'gc>, Error> {
|
||||
self.0.read().get_slot(id)
|
||||
}
|
||||
|
||||
fn set_slot(
|
||||
self,
|
||||
id: u32,
|
||||
value: Value<'gc>,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
) -> Result<(), Error> {
|
||||
self.0.write(mc).set_slot(id, value, mc)
|
||||
}
|
||||
|
||||
fn has_property(self, name: &QName) -> bool {
|
||||
self.0.read().has_property(name)
|
||||
}
|
||||
|
@ -133,6 +149,7 @@ impl<'gc> ScriptObjectData<'gc> {
|
|||
pub fn base_new(proto: Option<Object<'gc>>) -> Self {
|
||||
ScriptObjectData {
|
||||
values: HashMap::new(),
|
||||
slots: Vec::new(),
|
||||
proto,
|
||||
}
|
||||
}
|
||||
|
@ -172,6 +189,29 @@ impl<'gc> ScriptObjectData<'gc> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_slot(&self, id: u32) -> Result<Value<'gc>, Error> {
|
||||
self.slots
|
||||
.get(id as usize)
|
||||
.cloned()
|
||||
.ok_or_else(|| format!("Slot index {} out of bounds!", id).into())
|
||||
}
|
||||
|
||||
/// Set a slot by it's index.
|
||||
pub fn set_slot(
|
||||
&mut self,
|
||||
id: u32,
|
||||
value: Value<'gc>,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
) -> Result<(), Error> {
|
||||
if let Some(slot) = self.slots.get_mut(id as usize) {
|
||||
*slot = value;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("Slot index {} out of bounds!", id).into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_property(&self, name: &QName) -> bool {
|
||||
self.values.get(name).is_some()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue