avm1: Store depth in `SuperObject`

This is a temporary hack to calculate depth from `base_proto` and
`this`, so that changing `this.__proto__` will affect `super`.

In the future, `depth` should be passed instead of `base_proto`.
This commit is contained in:
relrelb 2021-10-15 10:26:43 +03:00 committed by Mike Welsh
parent 7816938e9b
commit e9efc2841b
1 changed files with 25 additions and 7 deletions

View File

@ -25,8 +25,8 @@ pub struct SuperObjectData<'gc> {
/// The object present as `this` throughout the superchain.
this: Object<'gc>,
/// The `proto` that the currently-executing method was pulled from.
base_proto: Object<'gc>,
/// The prototype depth of the currently-executing method.
depth: u8,
}
impl<'gc> SuperObject<'gc> {
@ -38,11 +38,31 @@ impl<'gc> SuperObject<'gc> {
this: Object<'gc>,
base_proto: Object<'gc>,
) -> Self {
// This is a temporary hack to calculate `depth` from `this` and `base_proto`.
// TODO: Pass `depth` alone (preferably in `Activation`),
// and remove all `base_proto` parameters.
let mut object = this;
let mut depth = 0;
while !Object::ptr_eq(object, base_proto) {
object = object.proto(activation).coerce_to_object(activation);
depth += 1;
}
Self(GcCell::allocate(
activation.context.gc_context,
SuperObjectData { this, base_proto },
SuperObjectData { this, depth },
))
}
fn base_proto(&self, activation: &mut Activation<'_, 'gc, '_>) -> Object<'gc> {
let read = self.0.read();
let depth = read.depth;
let mut proto = read.this;
for _ in 0..depth {
proto = proto.proto(activation).coerce_to_object(activation);
}
proto
}
}
impl<'gc> TObject<'gc> for SuperObject<'gc> {
@ -75,9 +95,7 @@ impl<'gc> TObject<'gc> for SuperObject<'gc> {
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let constructor = self
.0
.read()
.base_proto
.base_proto(activation)
.get("__constructor__", activation)?
.coerce_to_object(activation);
let this = self.0.read().this;
@ -138,7 +156,7 @@ impl<'gc> TObject<'gc> for SuperObject<'gc> {
}
fn proto(&self, activation: &mut Activation<'_, 'gc, '_>) -> Value<'gc> {
self.0.read().base_proto.proto(activation)
self.base_proto(activation).proto(activation)
}
fn define_value(