diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index ba18667c8..a383f0389 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -259,6 +259,32 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { Ok(activation) } + /// Construct an activation for the execution of a builtin method. + /// + /// It is a logic error to attempt to execute builtins within the same + /// activation as the method or script that called them. You must use this + /// function to construct a new activation for the builtin so that it can + /// properly supercall. + pub fn from_builtin( + context: UpdateContext<'a, 'gc, 'gc_context>, + this: Option>, + base_proto: Option>, + ) -> Result { + let local_registers = GcCell::allocate(context.gc_context, RegisterSet::new(0)); + + Ok(Self { + this, + arguments: None, + is_executing: false, + local_registers, + return_value: None, + local_scope: ScriptObject::bare_object(context.gc_context), + scope: None, + base_proto, + context, + }) + } + /// Execute a script initializer. pub fn run_stack_frame_for_script(&mut self, script: Script<'gc>) -> Result<(), Error> { let init = script.init().0.into_bytecode()?; @@ -268,6 +294,28 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { Ok(()) } + /// Call the superclass's instance initializer. + pub fn super_init( + &mut self, + receiver: Object<'gc>, + args: &[Value<'gc>], + ) -> Result, Error> { + let name = QName::new(Namespace::public_namespace(), "constructor"); + let base_proto: Result, Error> = + self.base_proto().and_then(|p| p.proto()).ok_or_else(|| { + "Attempted to call super constructor without a superclass." + .to_string() + .into() + }); + let mut base_proto = base_proto?; + + let function = base_proto + .get_property(receiver, &name, self)? + .coerce_to_object(self)?; + + function.call(Some(receiver), &args, self, Some(base_proto)) + } + /// Attempts to lock the activation frame for execution. /// /// If this frame is already executing, that is an error condition. @@ -1348,20 +1396,8 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { fn op_construct_super(&mut self, arg_count: u32) -> Result, Error> { let args = self.context.avm2.pop_args(arg_count); let receiver = self.context.avm2.pop().coerce_to_object(self)?; - let name = QName::new(Namespace::public_namespace(), "constructor"); - let base_proto: Result, Error> = - self.base_proto().and_then(|p| p.proto()).ok_or_else(|| { - "Attempted to call super constructor without a superclass." - .to_string() - .into() - }); - let mut base_proto = base_proto?; - let function = base_proto - .get_property(receiver, &name, self)? - .coerce_to_object(self)?; - - function.call(Some(receiver), &args, self, Some(base_proto))?; + self.super_init(receiver, &args)?; Ok(FrameControl::Continue) } diff --git a/core/src/avm2/function.rs b/core/src/avm2/function.rs index 853d06725..2a9753299 100644 --- a/core/src/avm2/function.rs +++ b/core/src/avm2/function.rs @@ -87,7 +87,11 @@ impl<'gc> Executable<'gc> { ) -> Result, Error> { match self { Executable::Native(nf, receiver) => { - nf(activation, receiver.or(unbound_reciever), arguments) + let receiver = receiver.or(unbound_reciever); + let mut activation = + Activation::from_builtin(activation.context.reborrow(), receiver, base_proto)?; + + nf(&mut activation, receiver, arguments) } Executable::Action(bm) => { let receiver = bm.receiver.or(unbound_reciever); diff --git a/core/src/avm2/globals/array.rs b/core/src/avm2/globals/array.rs index 6f368926a..c7398c81a 100644 --- a/core/src/avm2/globals/array.rs +++ b/core/src/avm2/globals/array.rs @@ -22,6 +22,8 @@ pub fn instance_init<'gc>( args: &[Value<'gc>], ) -> Result, Error> { if let Some(this) = this { + activation.super_init(this, &[])?; + if let Some(mut array) = this.as_array_storage_mut(activation.context.gc_context) { if args.len() == 1 { if let Some(expected_len) = args diff --git a/core/src/avm2/globals/flash/display/displayobject.rs b/core/src/avm2/globals/flash/display/displayobject.rs index a226b1a16..5a568b342 100644 --- a/core/src/avm2/globals/flash/display/displayobject.rs +++ b/core/src/avm2/globals/flash/display/displayobject.rs @@ -16,10 +16,14 @@ use swf::Twips; /// Implements `flash.display.DisplayObject`'s instance constructor. pub fn instance_init<'gc>( - _activation: &mut Activation<'_, 'gc, '_>, - _this: Option>, + activation: &mut Activation<'_, 'gc, '_>, + this: Option>, _args: &[Value<'gc>], ) -> Result, Error> { + if let Some(this) = this { + activation.super_init(this, &[])?; + } + Ok(Value::Undefined) } diff --git a/core/src/avm2/globals/flash/display/displayobjectcontainer.rs b/core/src/avm2/globals/flash/display/displayobjectcontainer.rs index 1df883b6d..23746e769 100644 --- a/core/src/avm2/globals/flash/display/displayobjectcontainer.rs +++ b/core/src/avm2/globals/flash/display/displayobjectcontainer.rs @@ -16,10 +16,14 @@ use std::cmp::min; /// Implements `flash.display.DisplayObjectContainer`'s instance constructor. pub fn instance_init<'gc>( - _activation: &mut Activation<'_, 'gc, '_>, - _this: Option>, + activation: &mut Activation<'_, 'gc, '_>, + this: Option>, _args: &[Value<'gc>], ) -> Result, Error> { + if let Some(this) = this { + activation.super_init(this, &[])?; + } + Ok(Value::Undefined) } diff --git a/core/src/avm2/globals/flash/display/framelabel.rs b/core/src/avm2/globals/flash/display/framelabel.rs index d11c62486..08e647fa6 100644 --- a/core/src/avm2/globals/flash/display/framelabel.rs +++ b/core/src/avm2/globals/flash/display/framelabel.rs @@ -28,6 +28,8 @@ pub fn instance_init<'gc>( .coerce_to_i32(activation)?; if let Some(mut this) = this { + activation.super_init(this, &[])?; + this.set_property( this, &QName::new(Namespace::Private("ruffle".into()), "name"), diff --git a/core/src/avm2/globals/flash/display/interactiveobject.rs b/core/src/avm2/globals/flash/display/interactiveobject.rs index 15cc8ae94..c7af85298 100644 --- a/core/src/avm2/globals/flash/display/interactiveobject.rs +++ b/core/src/avm2/globals/flash/display/interactiveobject.rs @@ -11,10 +11,14 @@ use gc_arena::{GcCell, MutationContext}; /// Implements `flash.display.InteractiveObject`'s instance constructor. pub fn instance_init<'gc>( - _activation: &mut Activation<'_, 'gc, '_>, - _this: Option>, + activation: &mut Activation<'_, 'gc, '_>, + this: Option>, _args: &[Value<'gc>], ) -> Result, Error> { + if let Some(this) = this { + activation.super_init(this, &[])?; + } + Ok(Value::Undefined) } diff --git a/core/src/avm2/globals/flash/display/movieclip.rs b/core/src/avm2/globals/flash/display/movieclip.rs index d2b4a4a28..9dac2fb37 100644 --- a/core/src/avm2/globals/flash/display/movieclip.rs +++ b/core/src/avm2/globals/flash/display/movieclip.rs @@ -23,6 +23,8 @@ pub fn instance_init<'gc>( _args: &[Value<'gc>], ) -> Result, Error> { if let Some(this) = this { + activation.super_init(this, &[])?; + if this.as_display_object().is_none() { let movie = Arc::new(SwfMovie::empty(activation.context.swf.version())); let new_do = MovieClip::new(SwfSlice::empty(movie), activation.context.gc_context); diff --git a/core/src/avm2/globals/flash/display/scene.rs b/core/src/avm2/globals/flash/display/scene.rs index 275a08508..97ea5ba2c 100644 --- a/core/src/avm2/globals/flash/display/scene.rs +++ b/core/src/avm2/globals/flash/display/scene.rs @@ -17,6 +17,8 @@ pub fn instance_init<'gc>( args: &[Value<'gc>], ) -> Result, Error> { if let Some(mut this) = this { + activation.super_init(this, &[])?; + let name = args .get(0) .cloned() diff --git a/core/src/avm2/globals/flash/display/sprite.rs b/core/src/avm2/globals/flash/display/sprite.rs index ae7ee3a9f..e9c930515 100644 --- a/core/src/avm2/globals/flash/display/sprite.rs +++ b/core/src/avm2/globals/flash/display/sprite.rs @@ -11,10 +11,14 @@ use gc_arena::{GcCell, MutationContext}; /// Implements `flash.display.Sprite`'s instance constructor. pub fn instance_init<'gc>( - _activation: &mut Activation<'_, 'gc, '_>, - _this: Option>, + activation: &mut Activation<'_, 'gc, '_>, + this: Option>, _args: &[Value<'gc>], ) -> Result, Error> { + if let Some(this) = this { + activation.super_init(this, &[])?; + } + Ok(Value::Undefined) } diff --git a/core/src/avm2/globals/flash/events/event.rs b/core/src/avm2/globals/flash/events/event.rs index faf10c72c..ddfc41905 100644 --- a/core/src/avm2/globals/flash/events/event.rs +++ b/core/src/avm2/globals/flash/events/event.rs @@ -18,25 +18,29 @@ pub fn instance_init<'gc>( this: Option>, args: &[Value<'gc>], ) -> Result, Error> { - if let Some(mut evt) = this.unwrap().as_event_mut(activation.context.gc_context) { - evt.set_event_type( - args.get(0) - .cloned() - .unwrap_or(Value::Undefined) - .coerce_to_string(activation)?, - ); - evt.set_bubbles( - args.get(1) - .cloned() - .unwrap_or(Value::Bool(false)) - .coerce_to_boolean(), - ); - evt.set_cancelable( - args.get(2) - .cloned() - .unwrap_or(Value::Bool(false)) - .coerce_to_boolean(), - ); + if let Some(this) = this { + activation.super_init(this, &[])?; + + if let Some(mut evt) = this.as_event_mut(activation.context.gc_context) { + evt.set_event_type( + args.get(0) + .cloned() + .unwrap_or(Value::Undefined) + .coerce_to_string(activation)?, + ); + evt.set_bubbles( + args.get(1) + .cloned() + .unwrap_or(Value::Bool(false)) + .coerce_to_boolean(), + ); + evt.set_cancelable( + args.get(2) + .cloned() + .unwrap_or(Value::Bool(false)) + .coerce_to_boolean(), + ); + } } Ok(Value::Undefined) diff --git a/core/src/avm2/globals/flash/system/application_domain.rs b/core/src/avm2/globals/flash/system/application_domain.rs index d36e3bd7f..730912922 100644 --- a/core/src/avm2/globals/flash/system/application_domain.rs +++ b/core/src/avm2/globals/flash/system/application_domain.rs @@ -12,10 +12,14 @@ use gc_arena::{GcCell, MutationContext}; /// Implements `flash.system.ApplicationDomain`'s instance constructor. pub fn instance_init<'gc>( - _activation: &mut Activation<'_, 'gc, '_>, - _this: Option>, + activation: &mut Activation<'_, 'gc, '_>, + this: Option>, _args: &[Value<'gc>], ) -> Result, Error> { + if let Some(this) = this { + activation.super_init(this, &[])?; + } + Ok(Value::Undefined) } diff --git a/core/src/avm2/globals/function.rs b/core/src/avm2/globals/function.rs index 51f74373a..42fe9ba6f 100644 --- a/core/src/avm2/globals/function.rs +++ b/core/src/avm2/globals/function.rs @@ -13,10 +13,14 @@ use gc_arena::GcCell; /// Implements `Function`'s instance initializer. pub fn instance_init<'gc>( - _activation: &mut Activation<'_, 'gc, '_>, - _this: Option>, + activation: &mut Activation<'_, 'gc, '_>, + this: Option>, _args: &[Value<'gc>], ) -> Result, Error> { + if let Some(this) = this { + activation.super_init(this, &[])?; + } + Ok(Value::Undefined) }