mirror of
https://github.com/denoland/rusty_v8.git
synced 2025-03-09 13:38:51 -04:00
feat: Add v8::Isolate::request_garbage_collection_for_testing (#1148)
This commit is contained in:
parent
0f43fc0b58
commit
3e8a572ceb
4 changed files with 75 additions and 38 deletions
|
@ -317,6 +317,11 @@ bool v8__Isolate__HasPendingBackgroundTasks(v8::Isolate* isolate) {
|
||||||
return isolate->HasPendingBackgroundTasks();
|
return isolate->HasPendingBackgroundTasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void v8__Isolate__RequestGarbageCollectionForTesting(
|
||||||
|
v8::Isolate* isolate, v8::Isolate::GarbageCollectionType type) {
|
||||||
|
isolate->RequestGarbageCollectionForTesting(type);
|
||||||
|
}
|
||||||
|
|
||||||
void v8__Isolate__CreateParams__CONSTRUCT(
|
void v8__Isolate__CreateParams__CONSTRUCT(
|
||||||
uninit_t<v8::Isolate::CreateParams>* buf) {
|
uninit_t<v8::Isolate::CreateParams>* buf) {
|
||||||
construct_in_place<v8::Isolate::CreateParams>(buf);
|
construct_in_place<v8::Isolate::CreateParams>(buf);
|
||||||
|
|
|
@ -107,6 +107,15 @@ pub enum PromiseHookType {
|
||||||
After,
|
After,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Types of garbage collections that can be requested via
|
||||||
|
/// [`Isolate::request_garbage_collection_for_testing`].
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum GarbageCollectionType {
|
||||||
|
Full,
|
||||||
|
Minor,
|
||||||
|
}
|
||||||
|
|
||||||
pub type MessageCallback = extern "C" fn(Local<Message>, Local<Value>);
|
pub type MessageCallback = extern "C" fn(Local<Message>, Local<Value>);
|
||||||
|
|
||||||
pub type PromiseHook =
|
pub type PromiseHook =
|
||||||
|
@ -471,6 +480,10 @@ extern "C" {
|
||||||
callback: extern "C" fn(*const FunctionCallbackInfo),
|
callback: extern "C" fn(*const FunctionCallbackInfo),
|
||||||
);
|
);
|
||||||
fn v8__Isolate__HasPendingBackgroundTasks(isolate: *const Isolate) -> bool;
|
fn v8__Isolate__HasPendingBackgroundTasks(isolate: *const Isolate) -> bool;
|
||||||
|
fn v8__Isolate__RequestGarbageCollectionForTesting(
|
||||||
|
isolate: *mut Isolate,
|
||||||
|
r#type: usize,
|
||||||
|
);
|
||||||
|
|
||||||
fn v8__HeapProfiler__TakeHeapSnapshot(
|
fn v8__HeapProfiler__TakeHeapSnapshot(
|
||||||
isolate: *mut Isolate,
|
isolate: *mut Isolate,
|
||||||
|
@ -1140,6 +1153,31 @@ impl Isolate {
|
||||||
unsafe { v8__Isolate__HasPendingBackgroundTasks(self) }
|
unsafe { v8__Isolate__HasPendingBackgroundTasks(self) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request garbage collection with a specific embedderstack state in this
|
||||||
|
/// Isolate. It is only valid to call this function if --expose_gc was
|
||||||
|
/// specified.
|
||||||
|
///
|
||||||
|
/// This should only be used for testing purposes and not to enforce a garbage
|
||||||
|
/// collection schedule. It has strong negative impact on the garbage
|
||||||
|
/// collection performance. Use IdleNotificationDeadline() or
|
||||||
|
/// LowMemoryNotification() instead to influence the garbage collection
|
||||||
|
/// schedule.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn request_garbage_collection_for_testing(
|
||||||
|
&mut self,
|
||||||
|
r#type: GarbageCollectionType,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
v8__Isolate__RequestGarbageCollectionForTesting(
|
||||||
|
self,
|
||||||
|
match r#type {
|
||||||
|
GarbageCollectionType::Full => 0,
|
||||||
|
GarbageCollectionType::Minor => 1,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn clear_scope_and_annex(&mut self) {
|
unsafe fn clear_scope_and_annex(&mut self) {
|
||||||
// Drop the scope stack.
|
// Drop the scope stack.
|
||||||
ScopeData::drop_root(self);
|
ScopeData::drop_root(self);
|
||||||
|
|
|
@ -97,6 +97,7 @@ pub use handle::Global;
|
||||||
pub use handle::Handle;
|
pub use handle::Handle;
|
||||||
pub use handle::Local;
|
pub use handle::Local;
|
||||||
pub use handle::Weak;
|
pub use handle::Weak;
|
||||||
|
pub use isolate::GarbageCollectionType;
|
||||||
pub use isolate::HeapStatistics;
|
pub use isolate::HeapStatistics;
|
||||||
pub use isolate::HostCreateShadowRealmContextCallback;
|
pub use isolate::HostCreateShadowRealmContextCallback;
|
||||||
pub use isolate::HostImportModuleDynamicallyCallback;
|
pub use isolate::HostImportModuleDynamicallyCallback;
|
||||||
|
|
|
@ -161,8 +161,7 @@ fn global_from_into_raw() {
|
||||||
(raw, weak)
|
(raw, weak)
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
scope.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
eval(scope, "gc()").unwrap();
|
|
||||||
assert!(!weak.is_empty());
|
assert!(!weak.is_empty());
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -172,8 +171,7 @@ fn global_from_into_raw() {
|
||||||
assert_eq!(global_from_weak, reconstructed);
|
assert_eq!(global_from_weak, reconstructed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
scope.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
eval(scope, "gc()").unwrap();
|
|
||||||
assert!(weak.is_empty());
|
assert!(weak.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6379,23 +6377,24 @@ fn clear_kept_objects() {
|
||||||
let context = v8::Context::new(scope);
|
let context = v8::Context::new(scope);
|
||||||
let scope = &mut v8::ContextScope::new(scope, context);
|
let scope = &mut v8::ContextScope::new(scope, context);
|
||||||
|
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
|
||||||
let step1 = r#"
|
let step1 = r#"
|
||||||
var weakrefs = [];
|
var weakrefs = [];
|
||||||
for (let i = 0; i < 424242; i++) weakrefs.push(new WeakRef({ i }));
|
for (let i = 0; i < 424242; i++) weakrefs.push(new WeakRef({ i }));
|
||||||
gc();
|
"#;
|
||||||
|
let step2 = r#"
|
||||||
if (weakrefs.some(w => !w.deref())) throw "fail";
|
if (weakrefs.some(w => !w.deref())) throw "fail";
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
let step3 = r#"
|
||||||
let step2 = r#"
|
|
||||||
gc();
|
|
||||||
if (weakrefs.every(w => w.deref())) throw "fail";
|
if (weakrefs.every(w => w.deref())) throw "fail";
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
eval(scope, step1).unwrap();
|
eval(scope, step1).unwrap();
|
||||||
scope.clear_kept_objects();
|
scope.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
eval(scope, step2).unwrap();
|
eval(scope, step2).unwrap();
|
||||||
|
scope.clear_kept_objects();
|
||||||
|
scope.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
|
eval(scope, step3).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -7420,8 +7419,7 @@ fn weak_handle() {
|
||||||
|
|
||||||
let scope = &mut v8::HandleScope::new(scope);
|
let scope = &mut v8::HandleScope::new(scope);
|
||||||
|
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
scope.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
eval(scope, "gc()").unwrap();
|
|
||||||
|
|
||||||
assert!(weak.is_empty());
|
assert!(weak.is_empty());
|
||||||
assert_eq!(weak.to_local(scope), None);
|
assert_eq!(weak.to_local(scope), None);
|
||||||
|
@ -7450,8 +7448,8 @@ fn finalizers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let scope = &mut v8::HandleScope::new(scope);
|
let scope = &mut v8::HandleScope::new(scope);
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
scope
|
||||||
eval(scope, "gc()").unwrap();
|
.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
}
|
}
|
||||||
|
|
||||||
let finalizer_called = Rc::new(Cell::new(false));
|
let finalizer_called = Rc::new(Cell::new(false));
|
||||||
|
@ -7486,8 +7484,7 @@ fn finalizers() {
|
||||||
};
|
};
|
||||||
|
|
||||||
let scope = &mut v8::HandleScope::new(scope);
|
let scope = &mut v8::HandleScope::new(scope);
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
scope.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
eval(scope, "gc()").unwrap();
|
|
||||||
assert!(weak.is_empty());
|
assert!(weak.is_empty());
|
||||||
assert!(finalizer_called.get());
|
assert!(finalizer_called.get());
|
||||||
}
|
}
|
||||||
|
@ -7521,8 +7518,8 @@ fn guaranteed_finalizers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let scope = &mut v8::HandleScope::new(scope);
|
let scope = &mut v8::HandleScope::new(scope);
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
scope
|
||||||
eval(scope, "gc()").unwrap();
|
.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
}
|
}
|
||||||
|
|
||||||
let finalizer_called = Rc::new(Cell::new(false));
|
let finalizer_called = Rc::new(Cell::new(false));
|
||||||
|
@ -7557,8 +7554,7 @@ fn guaranteed_finalizers() {
|
||||||
};
|
};
|
||||||
|
|
||||||
let scope = &mut v8::HandleScope::new(scope);
|
let scope = &mut v8::HandleScope::new(scope);
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
scope.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
eval(scope, "gc()").unwrap();
|
|
||||||
assert!(weak.is_empty());
|
assert!(weak.is_empty());
|
||||||
assert!(finalizer_called.get());
|
assert!(finalizer_called.get());
|
||||||
}
|
}
|
||||||
|
@ -7583,8 +7579,7 @@ fn weak_from_global() {
|
||||||
assert_eq!(weak.to_global(scope).unwrap(), global);
|
assert_eq!(weak.to_global(scope).unwrap(), global);
|
||||||
|
|
||||||
drop(global);
|
drop(global);
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
scope.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
eval(scope, "gc()").unwrap();
|
|
||||||
assert!(weak.is_empty());
|
assert!(weak.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7633,8 +7628,8 @@ fn weak_from_into_raw() {
|
||||||
assert!(!finalizer_called.get());
|
assert!(!finalizer_called.get());
|
||||||
(weak1, weak2)
|
(weak1, weak2)
|
||||||
};
|
};
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
scope
|
||||||
eval(scope, "gc()").unwrap();
|
.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
assert!(weak1.is_empty());
|
assert!(weak1.is_empty());
|
||||||
assert!(weak2.is_empty());
|
assert!(weak2.is_empty());
|
||||||
assert!(finalizer_called.get());
|
assert!(finalizer_called.get());
|
||||||
|
@ -7648,8 +7643,8 @@ fn weak_from_into_raw() {
|
||||||
v8::Weak::new(scope, local)
|
v8::Weak::new(scope, local)
|
||||||
};
|
};
|
||||||
assert!(!weak.is_empty());
|
assert!(!weak.is_empty());
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
scope
|
||||||
eval(scope, "gc()").unwrap();
|
.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
assert!(weak.is_empty());
|
assert!(weak.is_empty());
|
||||||
assert_eq!(weak.into_raw(), None);
|
assert_eq!(weak.into_raw(), None);
|
||||||
}
|
}
|
||||||
|
@ -7680,8 +7675,8 @@ fn weak_from_into_raw() {
|
||||||
let raw2 = weak_with_finalizer.into_raw();
|
let raw2 = weak_with_finalizer.into_raw();
|
||||||
assert!(raw1.is_some());
|
assert!(raw1.is_some());
|
||||||
assert!(raw2.is_some());
|
assert!(raw2.is_some());
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
scope
|
||||||
eval(scope, "gc()").unwrap();
|
.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
assert!(finalizer_called.get());
|
assert!(finalizer_called.get());
|
||||||
let weak1 = unsafe { v8::Weak::from_raw(scope, raw1) };
|
let weak1 = unsafe { v8::Weak::from_raw(scope, raw1) };
|
||||||
let weak2 = unsafe { v8::Weak::from_raw(scope, raw2) };
|
let weak2 = unsafe { v8::Weak::from_raw(scope, raw2) };
|
||||||
|
@ -7695,11 +7690,10 @@ fn weak_from_into_raw() {
|
||||||
let local = v8::Object::new(scope);
|
let local = v8::Object::new(scope);
|
||||||
v8::Weak::new(scope, local).into_raw();
|
v8::Weak::new(scope, local).into_raw();
|
||||||
v8::Weak::with_finalizer(scope, local, Box::new(|_| {})).into_raw();
|
v8::Weak::with_finalizer(scope, local, Box::new(|_| {})).into_raw();
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
scope
|
||||||
eval(scope, "gc()").unwrap();
|
.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
}
|
}
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
scope.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
eval(scope, "gc()").unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -7739,8 +7733,7 @@ fn drop_weak_from_raw_in_finalizer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(!finalized.get());
|
assert!(!finalized.get());
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
scope.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
eval(scope, "gc()").unwrap();
|
|
||||||
assert!(finalized.get());
|
assert!(finalized.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8747,8 +8740,8 @@ fn gc_callbacks() {
|
||||||
let context = v8::Context::new(scope);
|
let context = v8::Context::new(scope);
|
||||||
let scope = &mut v8::ContextScope::new(scope, context);
|
let scope = &mut v8::ContextScope::new(scope, context);
|
||||||
|
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
scope
|
||||||
eval(scope, "gc()").unwrap();
|
.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
assert_eq!(state.mark_sweep_calls, 1);
|
assert_eq!(state.mark_sweep_calls, 1);
|
||||||
assert_eq!(state.incremental_marking_calls, 0);
|
assert_eq!(state.incremental_marking_calls, 0);
|
||||||
}
|
}
|
||||||
|
@ -8760,8 +8753,8 @@ fn gc_callbacks() {
|
||||||
let context = v8::Context::new(scope);
|
let context = v8::Context::new(scope);
|
||||||
let scope = &mut v8::ContextScope::new(scope, context);
|
let scope = &mut v8::ContextScope::new(scope, context);
|
||||||
|
|
||||||
// TODO use binding to Isolate::RequestGarbageCollectionForTesting instead of gc()
|
scope
|
||||||
eval(scope, "gc()").unwrap();
|
.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full);
|
||||||
// Assert callback was removed and not called again.
|
// Assert callback was removed and not called again.
|
||||||
assert_eq!(state.mark_sweep_calls, 1);
|
assert_eq!(state.mark_sweep_calls, 1);
|
||||||
assert_eq!(state.incremental_marking_calls, 0);
|
assert_eq!(state.incremental_marking_calls, 0);
|
||||||
|
|
Loading…
Add table
Reference in a new issue