core: simplify callstack handling in Player
Grab the AVM2 callstack handle before constructing the GC root, so that we can set it directly instead of modify the GC root once constructed. This means we can remove an extra GcCell. Also switch the callstack object from GcCell to GcRefLock.
This commit is contained in:
parent
0097aea381
commit
0b3395d21f
|
@ -15,7 +15,8 @@ use crate::tag_utils::SwfMovie;
|
||||||
use crate::PlayerRuntime;
|
use crate::PlayerRuntime;
|
||||||
|
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use gc_arena::{Collect, GcCell, Mutation};
|
use gc_arena::lock::GcRefLock;
|
||||||
|
use gc_arena::{Collect, Mutation};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use swf::avm2::read::Reader;
|
use swf::avm2::read::Reader;
|
||||||
use swf::DoAbc2Flag;
|
use swf::DoAbc2Flag;
|
||||||
|
@ -112,7 +113,7 @@ pub struct Avm2<'gc> {
|
||||||
scope_stack: Vec<Scope<'gc>>,
|
scope_stack: Vec<Scope<'gc>>,
|
||||||
|
|
||||||
/// The current call stack of the player.
|
/// The current call stack of the player.
|
||||||
call_stack: GcCell<'gc, CallStack<'gc>>,
|
call_stack: GcRefLock<'gc, CallStack<'gc>>,
|
||||||
|
|
||||||
/// This domain is used exclusively for classes from playerglobals
|
/// This domain is used exclusively for classes from playerglobals
|
||||||
playerglobals_domain: Domain<'gc>,
|
playerglobals_domain: Domain<'gc>,
|
||||||
|
@ -216,7 +217,7 @@ impl<'gc> Avm2<'gc> {
|
||||||
player_runtime,
|
player_runtime,
|
||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
scope_stack: Vec::new(),
|
scope_stack: Vec::new(),
|
||||||
call_stack: GcCell::new(context.gc_context, CallStack::new()),
|
call_stack: GcRefLock::new(context.gc_context, CallStack::new().into()),
|
||||||
playerglobals_domain,
|
playerglobals_domain,
|
||||||
stage_domain,
|
stage_domain,
|
||||||
system_classes: None,
|
system_classes: None,
|
||||||
|
@ -650,20 +651,20 @@ impl<'gc> Avm2<'gc> {
|
||||||
method: Method<'gc>,
|
method: Method<'gc>,
|
||||||
superclass: Option<ClassObject<'gc>>,
|
superclass: Option<ClassObject<'gc>>,
|
||||||
) {
|
) {
|
||||||
self.call_stack.write(mc).push(method, superclass)
|
self.call_stack.borrow_mut(mc).push(method, superclass)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pushes script initializer (global init) on the call stack
|
/// Pushes script initializer (global init) on the call stack
|
||||||
pub fn push_global_init(&self, mc: &Mutation<'gc>, script: Script<'gc>) {
|
pub fn push_global_init(&self, mc: &Mutation<'gc>, script: Script<'gc>) {
|
||||||
self.call_stack.write(mc).push_global_init(script)
|
self.call_stack.borrow_mut(mc).push_global_init(script)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pops an executable off the call stack
|
/// Pops an executable off the call stack
|
||||||
pub fn pop_call(&self, mc: &Mutation<'gc>) -> Option<CallNode<'gc>> {
|
pub fn pop_call(&self, mc: &Mutation<'gc>) -> Option<CallNode<'gc>> {
|
||||||
self.call_stack.write(mc).pop()
|
self.call_stack.borrow_mut(mc).pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call_stack(&self) -> GcCell<'gc, CallStack<'gc>> {
|
pub fn call_stack(&self) -> GcRefLock<'gc, CallStack<'gc>> {
|
||||||
self.call_stack
|
self.call_stack
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub fn error_allocator<'gc>(
|
||||||
let base = ScriptObjectData::new(class);
|
let base = ScriptObjectData::new(class);
|
||||||
|
|
||||||
let call_stack = (enabled!(Level::INFO) || cfg!(feature = "avm_debug"))
|
let call_stack = (enabled!(Level::INFO) || cfg!(feature = "avm_debug"))
|
||||||
.then(|| activation.avm2().call_stack().read().clone())
|
.then(|| activation.avm2().call_stack().borrow().clone())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
Ok(ErrorObject(Gc::new(
|
Ok(ErrorObject(Gc::new(
|
||||||
|
|
|
@ -50,7 +50,8 @@ use crate::tag_utils::SwfMovie;
|
||||||
use crate::timer::Timers;
|
use crate::timer::Timers;
|
||||||
use crate::vminterface::Instantiator;
|
use crate::vminterface::Instantiator;
|
||||||
use crate::DefaultFont;
|
use crate::DefaultFont;
|
||||||
use gc_arena::{Collect, DynamicRootSet, GcCell, Rootable};
|
use gc_arena::lock::GcRefLock;
|
||||||
|
use gc_arena::{Collect, DynamicRootSet, Rootable};
|
||||||
use rand::{rngs::SmallRng, SeedableRng};
|
use rand::{rngs::SmallRng, SeedableRng};
|
||||||
use ruffle_render::backend::{null::NullRenderer, RenderBackend, ViewportDimensions};
|
use ruffle_render::backend::{null::NullRenderer, RenderBackend, ViewportDimensions};
|
||||||
use ruffle_render::commands::CommandList;
|
use ruffle_render::commands::CommandList;
|
||||||
|
@ -77,14 +78,8 @@ pub const FALLBACK_DEVICE_FONT_TAG: &[u8] = include_bytes!("../assets/noto-sans-
|
||||||
#[derive(Collect)]
|
#[derive(Collect)]
|
||||||
#[collect(no_drop)]
|
#[collect(no_drop)]
|
||||||
struct GcRoot<'gc> {
|
struct GcRoot<'gc> {
|
||||||
callstack: GcCell<'gc, GcCallstack<'gc>>,
|
avm2_callstack: GcRefLock<'gc, CallStack<'gc>>,
|
||||||
data: GcCell<'gc, GcRootData<'gc>>,
|
data: GcRefLock<'gc, GcRootData<'gc>>,
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Collect, Default)]
|
|
||||||
#[collect(no_drop)]
|
|
||||||
struct GcCallstack<'gc> {
|
|
||||||
avm2: Option<GcCell<'gc, CallStack<'gc>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -97,12 +92,9 @@ impl StaticCallstack {
|
||||||
if let Some(arena) = self.arena.upgrade() {
|
if let Some(arena) = self.arena.upgrade() {
|
||||||
if let Ok(arena) = arena.try_borrow() {
|
if let Ok(arena) = arena.try_borrow() {
|
||||||
arena.mutate(|_, root| {
|
arena.mutate(|_, root| {
|
||||||
let callstack = root.callstack.read();
|
let callstack = root.avm2_callstack.borrow();
|
||||||
if let Some(callstack) = callstack.avm2 {
|
if !callstack.is_empty() {
|
||||||
let stack = callstack.read();
|
f(&callstack);
|
||||||
if !stack.is_empty() {
|
|
||||||
f(&stack)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -635,7 +627,7 @@ impl Player {
|
||||||
|
|
||||||
pub fn clear_custom_menu_items(&mut self) {
|
pub fn clear_custom_menu_items(&mut self) {
|
||||||
self.gc_arena.borrow().mutate(|gc_context, gc_root| {
|
self.gc_arena.borrow().mutate(|gc_context, gc_root| {
|
||||||
let mut root_data = gc_root.data.write(gc_context);
|
let mut root_data = gc_root.data.borrow_mut(gc_context);
|
||||||
root_data.current_context_menu = None;
|
root_data.current_context_menu = None;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1924,7 +1916,7 @@ impl Player {
|
||||||
let invalidated = self
|
let invalidated = self
|
||||||
.gc_arena
|
.gc_arena
|
||||||
.borrow()
|
.borrow()
|
||||||
.mutate(|_, gc_root| gc_root.data.read().stage.invalidated());
|
.mutate(|_, gc_root| gc_root.data.borrow().stage.invalidated());
|
||||||
if invalidated {
|
if invalidated {
|
||||||
self.update(|context| {
|
self.update(|context| {
|
||||||
let stage = context.stage;
|
let stage = context.stage;
|
||||||
|
@ -1935,7 +1927,7 @@ impl Player {
|
||||||
let mut background_color = Color::WHITE;
|
let mut background_color = Color::WHITE;
|
||||||
|
|
||||||
let (cache_draws, commands) = self.gc_arena.borrow().mutate(|gc_context, gc_root| {
|
let (cache_draws, commands) = self.gc_arena.borrow().mutate(|gc_context, gc_root| {
|
||||||
let root_data = gc_root.data.read();
|
let root_data = gc_root.data.borrow();
|
||||||
let stage = root_data.stage;
|
let stage = root_data.stage;
|
||||||
|
|
||||||
let mut cache_draws = vec![];
|
let mut cache_draws = vec![];
|
||||||
|
@ -2135,7 +2127,7 @@ impl Player {
|
||||||
F: for<'a, 'gc> FnOnce(&mut UpdateContext<'a, 'gc>) -> R,
|
F: for<'a, 'gc> FnOnce(&mut UpdateContext<'a, 'gc>) -> R,
|
||||||
{
|
{
|
||||||
self.gc_arena.borrow().mutate(|gc_context, gc_root| {
|
self.gc_arena.borrow().mutate(|gc_context, gc_root| {
|
||||||
let mut root_data = gc_root.data.write(gc_context);
|
let mut root_data = gc_root.data.borrow_mut(gc_context);
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
let (
|
let (
|
||||||
|
@ -2726,45 +2718,43 @@ impl PlayerBuilder {
|
||||||
gc_context,
|
gc_context,
|
||||||
interner: &mut interner,
|
interner: &mut interner,
|
||||||
};
|
};
|
||||||
let dynamic_root = DynamicRootSet::new(gc_context);
|
|
||||||
|
let data = GcRootData {
|
||||||
|
audio_manager: AudioManager::new(),
|
||||||
|
action_queue: ActionQueue::new(),
|
||||||
|
avm1: Avm1::new(&mut init, player_version),
|
||||||
|
avm2: Avm2::new(&mut init, player_version, player_runtime),
|
||||||
|
interner,
|
||||||
|
current_context_menu: None,
|
||||||
|
drag_object: None,
|
||||||
|
external_interface: ExternalInterface::new(
|
||||||
|
external_interface_providers,
|
||||||
|
fs_command_provider,
|
||||||
|
),
|
||||||
|
library: Library::empty(),
|
||||||
|
load_manager: LoadManager::new(),
|
||||||
|
mouse_data: MouseData {
|
||||||
|
hovered: None,
|
||||||
|
pressed: None,
|
||||||
|
right_pressed: None,
|
||||||
|
middle_pressed: None,
|
||||||
|
},
|
||||||
|
avm1_shared_objects: HashMap::new(),
|
||||||
|
avm2_shared_objects: HashMap::new(),
|
||||||
|
stage: Stage::empty(gc_context, fullscreen, fake_movie),
|
||||||
|
timers: Timers::new(),
|
||||||
|
unbound_text_fields: Vec::new(),
|
||||||
|
stream_manager: StreamManager::new(),
|
||||||
|
sockets: Sockets::empty(),
|
||||||
|
net_connections: NetConnections::default(),
|
||||||
|
local_connections: LocalConnections::empty(),
|
||||||
|
dynamic_root: DynamicRootSet::new(gc_context),
|
||||||
|
post_frame_callbacks: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
GcRoot {
|
GcRoot {
|
||||||
callstack: GcCell::new(gc_context, GcCallstack::default()),
|
avm2_callstack: data.avm2.call_stack(),
|
||||||
data: GcCell::new(
|
data: GcRefLock::new(gc_context, data.into()),
|
||||||
gc_context,
|
|
||||||
GcRootData {
|
|
||||||
audio_manager: AudioManager::new(),
|
|
||||||
action_queue: ActionQueue::new(),
|
|
||||||
avm1: Avm1::new(&mut init, player_version),
|
|
||||||
avm2: Avm2::new(&mut init, player_version, player_runtime),
|
|
||||||
interner,
|
|
||||||
current_context_menu: None,
|
|
||||||
drag_object: None,
|
|
||||||
external_interface: ExternalInterface::new(
|
|
||||||
external_interface_providers,
|
|
||||||
fs_command_provider,
|
|
||||||
),
|
|
||||||
library: Library::empty(),
|
|
||||||
load_manager: LoadManager::new(),
|
|
||||||
mouse_data: MouseData {
|
|
||||||
hovered: None,
|
|
||||||
pressed: None,
|
|
||||||
right_pressed: None,
|
|
||||||
middle_pressed: None,
|
|
||||||
},
|
|
||||||
avm1_shared_objects: HashMap::new(),
|
|
||||||
avm2_shared_objects: HashMap::new(),
|
|
||||||
stage: Stage::empty(gc_context, fullscreen, fake_movie),
|
|
||||||
timers: Timers::new(),
|
|
||||||
unbound_text_fields: Vec::new(),
|
|
||||||
stream_manager: StreamManager::new(),
|
|
||||||
sockets: Sockets::empty(),
|
|
||||||
net_connections: NetConnections::default(),
|
|
||||||
local_connections: LocalConnections::empty(),
|
|
||||||
dynamic_root,
|
|
||||||
post_frame_callbacks: Vec::new(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2915,10 +2905,6 @@ impl PlayerBuilder {
|
||||||
crate::avm2::specification::capture_specification(context, &stub_path);
|
crate::avm2::specification::capture_specification(context, &stub_path);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
player_lock.gc_arena.borrow().mutate(|context, root| {
|
|
||||||
let call_stack = root.data.read().avm2.call_stack();
|
|
||||||
root.callstack.write(context).avm2 = Some(call_stack);
|
|
||||||
});
|
|
||||||
player_lock.audio.set_frame_rate(frame_rate);
|
player_lock.audio.set_frame_rate(frame_rate);
|
||||||
player_lock.set_letterbox(self.letterbox);
|
player_lock.set_letterbox(self.letterbox);
|
||||||
player_lock.set_quality(self.quality);
|
player_lock.set_quality(self.quality);
|
||||||
|
|
Loading…
Reference in New Issue