core: Remove LoaderHandle when load is done

In almost all cases, we were letting completed LoaderHandles
accumulate, leaking memory and wasting time in `preload_tick`
This commit is contained in:
Aaron Hill 2024-02-03 23:05:31 -05:00 committed by Nathan Adams
parent 0df6bafdaf
commit c8f4cb6fb2
2 changed files with 50 additions and 14 deletions

View File

@ -24,6 +24,12 @@ use super::Avm2;
#[collect(no_drop)]
pub struct Domain<'gc>(GcCell<'gc, DomainData<'gc>>);
impl std::fmt::Debug for Domain<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Domain({:p})", self.0.as_ptr())
}
}
#[derive(Copy, Clone, Collect)]
#[collect(no_drop)]
pub struct DomainWeak<'gc>(GcWeakCell<'gc, DomainData<'gc>>);

View File

@ -614,7 +614,7 @@ pub enum LoaderStatus {
Failed,
}
#[derive(Collect, Clone, Copy)]
#[derive(Collect, Clone, Copy, Debug)]
#[collect(no_drop)]
pub enum MovieLoaderVMData<'gc> {
Avm1 {
@ -632,7 +632,7 @@ pub enum MovieLoaderVMData<'gc> {
}
/// A struct that holds garbage-collected pointers for asynchronous code.
#[derive(Collect)]
#[derive(Collect, Debug)]
#[collect(no_drop)]
pub enum Loader<'gc> {
/// Loader that is loading the root movie of a player.
@ -886,7 +886,7 @@ impl<'gc> Loader<'gc> {
parameters: Vec<(String, String)>,
on_metadata: Box<dyn FnOnce(&swf::HeaderExt)>,
) -> OwnedFuture<(), Error> {
let _handle = match self {
let handle = match self {
Loader::RootMovie { self_handle, .. } => {
self_handle.expect("Loader not self-introduced")
}
@ -943,6 +943,7 @@ impl<'gc> Loader<'gc> {
movie.append_parameters(parameters);
player.lock().unwrap().mutate_with_update_context(|uc| {
uc.set_root_movie(movie);
uc.load_manager.remove_loader(handle);
});
Ok(())
})
@ -1154,6 +1155,8 @@ impl<'gc> Loader<'gc> {
}
}
activation.context.load_manager.remove_loader(handle);
Ok(())
})
})
@ -1254,6 +1257,8 @@ impl<'gc> Loader<'gc> {
}
}
activation.context.load_manager.remove_loader(handle);
Ok(())
})
})
@ -1443,6 +1448,8 @@ impl<'gc> Loader<'gc> {
}
}
uc.load_manager.remove_loader(handle);
Ok(())
})
})
@ -1507,6 +1514,8 @@ impl<'gc> Loader<'gc> {
crate::avm1::start_sound(&mut activation, sound_object.into(), &[])?;
}
activation.context.load_manager.remove_loader(handle);
Ok(())
})
})
@ -1607,6 +1616,8 @@ impl<'gc> Loader<'gc> {
}
}
uc.load_manager.remove_loader(handle);
Ok(())
})
})
@ -1674,6 +1685,10 @@ impl<'gc> Loader<'gc> {
}
}
player.lock().unwrap().update(|uc| {
uc.load_manager.remove_loader(handle);
});
Ok(())
}
Err(response) => player.lock().unwrap().update(|uc| {
@ -1685,6 +1700,7 @@ impl<'gc> Loader<'gc> {
};
stream.report_error(response.error);
uc.load_manager.remove_loader(handle);
Ok(())
}),
}
@ -2283,6 +2299,12 @@ impl<'gc> Loader<'gc> {
&["onLoadComplete".into(), target_clip.object(), status.into()],
);
}
if let Loader::Movie { loader_status, .. } =
uc.load_manager.get_loader_mut(handle).unwrap()
{
*loader_status = LoaderStatus::Succeeded;
};
}
// This is fired after we process the movie's first frame,
// in `MovieClip.on_exit_frame`
@ -2299,14 +2321,10 @@ impl<'gc> Loader<'gc> {
loader_info_obj.fire_init_and_complete_events(uc, status, redirected);
}
}
// We only remove this in the AVM2 case - in AVM1, this is handled by 'movie_clip_on_load'
uc.load_manager.remove_loader(handle);
}
}
if let Loader::Movie { loader_status, .. } = uc.load_manager.get_loader_mut(handle).unwrap()
{
*loader_status = LoaderStatus::Succeeded;
};
Ok(())
}
@ -2357,6 +2375,11 @@ impl<'gc> Loader<'gc> {
],
);
}
if let Loader::Movie { loader_status, .. } =
uc.load_manager.get_loader_mut(handle).unwrap()
{
*loader_status = LoaderStatus::Failed;
};
}
MovieLoaderVMData::Avm2 { loader_info, .. } => {
let mut activation = Avm2Activation::from_nothing(uc.reborrow());
@ -2396,14 +2419,11 @@ impl<'gc> Loader<'gc> {
.map_err(|e| Error::Avm2Error(e.to_string()))?;
Avm2::dispatch_event(uc, io_error_evt, loader_info);
// We only remove this in the AVM2 case - in AVM1, this is handled by 'movie_clip_on_load'
uc.load_manager.remove_loader(handle);
}
}
if let Loader::Movie { loader_status, .. } = uc.load_manager.get_loader_mut(handle).unwrap()
{
*loader_status = LoaderStatus::Failed;
};
Ok(())
}
@ -2584,6 +2604,8 @@ impl<'gc> Loader<'gc> {
tracing::warn!("Error on file dialog: {:?}", err);
}
}
activation.context.load_manager.remove_loader(handle);
Ok(())
}
Some(&Loader::FileDialogAvm2 { target_object, .. }) => {
@ -2622,6 +2644,8 @@ impl<'gc> Loader<'gc> {
}
}
uc.load_manager.remove_loader(handle);
Ok(())
}
None => Err(Error::Cancelled),
@ -2735,6 +2759,8 @@ impl<'gc> Loader<'gc> {
}
}
uc.load_manager.remove_loader(handle);
Ok(())
})
})
@ -2940,6 +2966,8 @@ impl<'gc> Loader<'gc> {
}
}
activation.context.load_manager.remove_loader(handle);
Ok(())
})
})
@ -3110,6 +3138,8 @@ impl<'gc> Loader<'gc> {
}
}
activation.context.load_manager.remove_loader(handle);
Ok(())
})
})