From 1b62ead08293f7049cb8c4e23224c952ea76ab76 Mon Sep 17 00:00:00 2001 From: David Wendt Date: Mon, 7 Oct 2019 22:08:35 -0400 Subject: [PATCH] Construct the closure scope chain in one pass, which lets us skip the vec allocation. --- core/src/avm1/scope.rs | 46 +++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/core/src/avm1/scope.rs b/core/src/avm1/scope.rs index fa948326d..9680c23c5 100644 --- a/core/src/avm1/scope.rs +++ b/core/src/avm1/scope.rs @@ -61,15 +61,37 @@ impl<'gc> Scope<'gc> { /// Construct a closure scope to be used as the parent of all local scopes /// when invoking a function. + /// + /// This function filters With scopes from the scope chain. If all scopes + /// are filtered (somehow), this function constructs and returns a new, + /// single global scope with a bare object. pub fn new_closure_scope( mut parent: GcCell<'gc, Self>, mc: MutationContext<'gc, '_>, ) -> GcCell<'gc, Self> { - let mut closure_scope_list = Vec::new(); + let mut bottom_scope = None; + let mut top_scope: Option> = None; loop { if parent.read().class != ScopeClass::With { - closure_scope_list.push(parent); + let next_scope = GcCell::allocate( + mc, + Self { + parent: None, + class: parent.read().class, + values: parent.read().values, + }, + ); + + if let None = bottom_scope { + bottom_scope = Some(next_scope); + } + + if let Some(ref scope) = top_scope { + scope.write(mc).parent = Some(next_scope); + } + + top_scope = Some(next_scope); } let grandparent = parent.read().parent; @@ -80,30 +102,16 @@ impl<'gc> Scope<'gc> { } } - let mut parent_scope = None; - for scope in closure_scope_list.iter().rev() { - parent_scope = Some(GcCell::allocate( - mc, - Scope { - parent: parent_scope, - class: scope.read().class, - values: scope.read().values, - }, - )); - } - - if let Some(parent_scope) = parent_scope { - parent_scope - } else { + bottom_scope.unwrap_or_else(|| { GcCell::allocate( mc, - Scope { + Self { parent: None, class: ScopeClass::Global, values: GcCell::allocate(mc, Object::bare_object()), }, ) - } + }) } /// Construct a scope for use with `tellTarget` code where the timeline