Construct the closure scope chain in one pass, which lets us skip the vec allocation.

This commit is contained in:
David Wendt 2019-10-07 22:08:35 -04:00
parent 2b90c61a69
commit 1b62ead082
1 changed files with 27 additions and 19 deletions

View File

@ -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<GcCell<'gc, Self>> = 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