From 78a1c9a7e3ab807023267afa02401d5fa2c2a6da Mon Sep 17 00:00:00 2001 From: David Wendt Date: Tue, 11 Feb 2020 14:46:47 -0500 Subject: [PATCH] Implement `pushscope`, `popscope`, and `pushwith`. --- core/src/avm2.rs | 39 +++++++++++++++++++++++++++++++++++++ core/src/avm2/activation.rs | 6 ++++++ core/src/avm2/scope.rs | 4 ++++ 3 files changed, 49 insertions(+) diff --git a/core/src/avm2.rs b/core/src/avm2.rs index fd5f01b10..0dee2ee44 100644 --- a/core/src/avm2.rs +++ b/core/src/avm2.rs @@ -4,6 +4,7 @@ use crate::avm2::activation::Activation; use crate::avm2::names::{Multiname, Namespace, QName}; use crate::avm2::object::{Object, TObject}; use crate::avm2::return_value::ReturnValue; +use crate::avm2::scope::Scope; use crate::avm2::value::Value; use crate::context::UpdateContext; use crate::tag_utils::SwfSlice; @@ -339,6 +340,9 @@ impl<'gc> Avm2<'gc> { Op::ReturnVoid => self.op_return_void(context), Op::GetProperty { index } => self.op_get_property(context, index), Op::SetProperty { index } => self.op_set_property(context, index), + Op::PushScope => self.op_push_scope(context), + Op::PushWith => self.op_push_with(context), + Op::PopScope => self.op_pop_scope(context), 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), @@ -499,6 +503,41 @@ impl<'gc> Avm2<'gc> { } } + fn op_push_scope(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) -> Result<(), Error> { + let object = self.pop().as_object()?; + let activation = self.current_stack_frame().unwrap(); + let mut write = activation.write(context.gc_context); + let scope_stack = write.scope(); + let new_scope = Scope::push_scope(scope_stack, object, context.gc_context); + + write.set_scope(Some(new_scope)); + + Ok(()) + } + + fn op_push_with(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) -> Result<(), Error> { + let object = self.pop().as_object()?; + let activation = self.current_stack_frame().unwrap(); + let mut write = activation.write(context.gc_context); + let scope_stack = write.scope(); + let new_scope = Scope::push_with(scope_stack, object, context.gc_context); + + write.set_scope(Some(new_scope)); + + Ok(()) + } + + fn op_pop_scope(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) -> Result<(), Error> { + let activation = self.current_stack_frame().unwrap(); + let mut write = activation.write(context.gc_context); + let scope_stack = write.scope(); + let new_scope = scope_stack.and_then(|s| s.read().pop_scope()); + + write.set_scope(new_scope); + + Ok(()) + } + fn op_find_property( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index 620ab677e..965f0d4ea 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -158,10 +158,16 @@ impl<'gc> Activation<'gc> { self.local_registers.read().get(id).cloned() } + /// Get the current scope stack. pub fn scope(&self) -> Option>> { self.scope } + /// Set a new scope stack. + pub fn set_scope(&mut self, new_scope: Option>>) { + self.scope = new_scope; + } + /// Set a local register. /// /// Returns `true` if the set was successful; `false` otherwise diff --git a/core/src/avm2/scope.rs b/core/src/avm2/scope.rs index e304de3ae..ad9cf07e5 100644 --- a/core/src/avm2/scope.rs +++ b/core/src/avm2/scope.rs @@ -69,6 +69,10 @@ impl<'gc> Scope<'gc> { ) } + pub fn pop_scope(&self) -> Option>> { + self.parent + } + /// Construct a closure scope to be used as the scope stack when invoking a /// function. ///