Functions close over the constant pool they were defined with.

This commit is contained in:
David Wendt 2019-11-03 17:43:28 -05:00 committed by Mike Welsh
parent 71d9655f6d
commit 681b4adfa4
3 changed files with 77 additions and 11 deletions

View File

@ -51,8 +51,9 @@ pub struct Avm1<'gc> {
/// The Flash Player version we're emulating.
player_version: u8,
/// The currently installed constant pool.
constant_pool: Vec<String>,
/// The constant pool to use for new activations from code sources that
/// don't close over the constant pool they were defined with.
constant_pool: GcCell<'gc, Vec<String>>,
/// The global object.
globals: Object<'gc>,
@ -78,6 +79,7 @@ unsafe impl<'gc> gc_arena::Collect for Avm1<'gc> {
#[inline]
fn trace(&self, cc: gc_arena::CollectionContext) {
self.globals.trace(cc);
self.constant_pool.trace(cc);
self.prototypes.trace(cc);
self.display_properties.trace(cc);
self.stack_frames.trace(cc);
@ -97,7 +99,7 @@ impl<'gc> Avm1<'gc> {
Self {
player_version,
constant_pool: vec![],
constant_pool: GcCell::allocate(gc_context, vec![]),
globals,
prototypes,
display_properties: stage_object::DisplayPropertyMap::new(gc_context),
@ -170,7 +172,14 @@ impl<'gc> Avm1<'gc> {
);
self.stack_frames.push(GcCell::allocate(
action_context.gc_context,
Activation::from_action(swf_version, code, child_scope, clip_obj, None),
Activation::from_action(
swf_version,
code,
child_scope,
self.constant_pool,
clip_obj,
None,
),
));
}
@ -197,7 +206,14 @@ impl<'gc> Avm1<'gc> {
self.push(Value::Undefined);
self.stack_frames.push(GcCell::allocate(
action_context.gc_context,
Activation::from_action(swf_version, code, child_scope, clip_obj, None),
Activation::from_action(
swf_version,
code,
child_scope,
self.constant_pool,
clip_obj,
None,
),
));
}
@ -831,10 +847,18 @@ impl<'gc> Avm1<'gc> {
fn action_constant_pool(
&mut self,
_context: &mut UpdateContext,
context: &mut UpdateContext<'_, 'gc, '_>,
constant_pool: &[&str],
) -> Result<(), Error> {
self.constant_pool = constant_pool.iter().map(|s| s.to_string()).collect();
self.constant_pool = GcCell::allocate(
context.gc_context,
constant_pool.iter().map(|s| s.to_string()).collect(),
);
self.current_stack_frame()
.unwrap()
.write(context.gc_context)
.set_constant_pool(self.constant_pool);
Ok(())
}
@ -863,7 +887,9 @@ impl<'gc> Avm1<'gc> {
self.current_stack_frame().unwrap().read().scope_cell(),
context.gc_context,
);
let func = Avm1Function::from_df1(swf_version, func_data, name, params, scope);
let constant_pool = self.current_stack_frame().unwrap().read().constant_pool();
let func =
Avm1Function::from_df1(swf_version, func_data, name, params, scope, constant_pool);
let prototype =
ScriptObject::object(context.gc_context, Some(self.prototypes.object)).into();
let func_obj = ScriptObject::function(
@ -901,7 +927,9 @@ impl<'gc> Avm1<'gc> {
self.current_stack_frame().unwrap().read().scope_cell(),
context.gc_context,
);
let func = Avm1Function::from_df2(swf_version, func_data, action_func, scope);
let constant_pool = self.current_stack_frame().unwrap().read().constant_pool();
let func =
Avm1Function::from_df2(swf_version, func_data, action_func, scope, constant_pool);
let prototype =
ScriptObject::object(context.gc_context, Some(self.prototypes.object)).into();
let func_obj = ScriptObject::function(
@ -1634,13 +1662,25 @@ impl<'gc> Avm1<'gc> {
SwfValue::Str(v) => v.to_string().into(),
SwfValue::Register(v) => self.current_register(*v),
SwfValue::ConstantPool(i) => {
if let Some(value) = self.constant_pool.get(*i as usize) {
if let Some(value) = self
.current_stack_frame()
.unwrap()
.read()
.constant_pool()
.read()
.get(*i as usize)
{
value.to_string().into()
} else {
log::warn!(
"ActionPush: Constant pool index {} out of range (len = {})",
i,
self.constant_pool.len()
self.current_stack_frame()
.unwrap()
.read()
.constant_pool()
.read()
.len()
);
Value::Undefined
}

View File

@ -66,6 +66,9 @@ pub struct Activation<'gc> {
/// All defined local variables in this stack frame.
scope: GcCell<'gc, Scope<'gc>>,
/// The currently in use constant pool.
constant_pool: GcCell<'gc, Vec<String>>,
/// The immutable value of `this`.
this: Object<'gc>,
@ -114,6 +117,7 @@ impl<'gc> Activation<'gc> {
swf_version: u8,
code: SwfSlice,
scope: GcCell<'gc, Scope<'gc>>,
constant_pool: GcCell<'gc, Vec<String>>,
this: Object<'gc>,
arguments: Option<Object<'gc>>,
) -> Activation<'gc> {
@ -122,6 +126,7 @@ impl<'gc> Activation<'gc> {
data: code,
pc: 0,
scope,
constant_pool,
this,
arguments,
return_value: None,
@ -135,6 +140,7 @@ impl<'gc> Activation<'gc> {
swf_version: u8,
code: SwfSlice,
scope: GcCell<'gc, Scope<'gc>>,
constant_pool: GcCell<'gc, Vec<String>>,
this: Object<'gc>,
arguments: Option<Object<'gc>>,
) -> Activation<'gc> {
@ -143,6 +149,7 @@ impl<'gc> Activation<'gc> {
data: code,
pc: 0,
scope,
constant_pool,
this,
arguments,
return_value: None,
@ -166,6 +173,7 @@ impl<'gc> Activation<'gc> {
) -> Activation<'gc> {
let global_scope = GcCell::allocate(mc, Scope::from_global_object(globals));
let child_scope = GcCell::allocate(mc, Scope::new_local_scope(global_scope, mc));
let empty_constant_pool = GcCell::allocate(mc, Vec::new());
Activation {
swf_version,
@ -176,6 +184,7 @@ impl<'gc> Activation<'gc> {
},
pc: 0,
scope: child_scope,
constant_pool: empty_constant_pool,
this: globals,
arguments: None,
return_value: None,
@ -192,6 +201,7 @@ impl<'gc> Activation<'gc> {
data: code,
pc: 0,
scope,
constant_pool: self.constant_pool,
this: self.this,
arguments: self.arguments,
return_value: None,
@ -342,6 +352,14 @@ impl<'gc> Activation<'gc> {
}
}
pub fn constant_pool(&self) -> GcCell<'gc, Vec<String>> {
self.constant_pool
}
pub fn set_constant_pool(&mut self, constant_pool: GcCell<'gc, Vec<String>>) {
self.constant_pool = constant_pool;
}
/// Attempts to lock the activation frame for execution.
///
/// If this frame is already executing, that is an error condition.

View File

@ -66,6 +66,9 @@ pub struct Avm1Function<'gc> {
/// The scope the function was born into.
scope: GcCell<'gc, Scope<'gc>>,
/// The constant pool the function executes with.
constant_pool: GcCell<'gc, Vec<String>>,
}
impl<'gc> Avm1Function<'gc> {
@ -79,6 +82,7 @@ impl<'gc> Avm1Function<'gc> {
name: &str,
params: &[&str],
scope: GcCell<'gc, Scope<'gc>>,
constant_pool: GcCell<'gc, Vec<String>>,
) -> Self {
let name = match name {
"" => None,
@ -101,6 +105,7 @@ impl<'gc> Avm1Function<'gc> {
preload_global: false,
params: params.iter().map(|s| (None, s.to_string())).collect(),
scope,
constant_pool,
}
}
@ -110,6 +115,7 @@ impl<'gc> Avm1Function<'gc> {
actions: SwfSlice,
swf_function: &swf::avm1::types::Function,
scope: GcCell<'gc, Scope<'gc>>,
constant_pool: GcCell<'gc, Vec<String>>,
) -> Self {
let name = match swf_function.name {
"" => None,
@ -141,6 +147,7 @@ impl<'gc> Avm1Function<'gc> {
preload_global: swf_function.preload_global,
params: owned_params,
scope,
constant_pool,
}
}
@ -237,6 +244,7 @@ impl<'gc> Executable<'gc> {
effective_ver,
af.data(),
child_scope,
af.constant_pool,
this,
Some(argcell),
),