Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,26 @@ bool v8__Isolate__GetHeapSpaceStatistics(
return isolate->GetHeapSpaceStatistics(space_statistics, index);
}

struct v8__HeapCodeStatistics {
size_t code_and_metadata_size_;
size_t bytecode_and_metadata_size_;
size_t external_script_source_size_;
size_t cpu_profiler_metadata_size_;
};

bool v8__Isolate__GetHeapCodeAndMetadataStatistics(v8::Isolate* isolate,
v8__HeapCodeStatistics* s) {
v8::HeapCodeStatistics stats;
bool ok = isolate->GetHeapCodeAndMetadataStatistics(&stats);
if (ok) {
s->code_and_metadata_size_ = stats.code_and_metadata_size();
s->bytecode_and_metadata_size_ = stats.bytecode_and_metadata_size();
s->external_script_source_size_ = stats.external_script_source_size();
s->cpu_profiler_metadata_size_ = stats.cpu_profiler_metadata_size();
}
return ok;
}

void v8__Isolate__RemoveNearHeapLimitCallback(
v8::Isolate* isolate, v8::NearHeapLimitCallback callback,
size_t heap_limit) {
Expand Down
49 changes: 49 additions & 0 deletions src/isolate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,10 @@ unsafe extern "C" {
space_statistics: *mut v8__HeapSpaceStatistics,
index: size_t,
) -> bool;
fn v8__Isolate__GetHeapCodeAndMetadataStatistics(
isolate: *mut RealIsolate,
code_statistics: *mut HeapCodeStatistics,
) -> bool;
fn v8__Isolate__AddNearHeapLimitCallback(
isolate: *mut RealIsolate,
callback: NearHeapLimitCallback,
Expand Down Expand Up @@ -1269,6 +1273,25 @@ impl Isolate {
Some(HeapSpaceStatistics(inner))
}

/// Get code and metadata statistics for the heap.
///
/// \returns true on success.
#[inline(always)]
pub fn get_heap_code_and_metadata_statistics(
&mut self,
) -> Option<HeapCodeStatistics> {
unsafe {
let mut s = MaybeUninit::zeroed();
if !v8__Isolate__GetHeapCodeAndMetadataStatistics(
self.as_real_ptr(),
s.as_mut_ptr(),
) {
return None;
}
Some(s.assume_init())
}
}

/// Tells V8 to capture current stack trace when uncaught exception occurs
/// and report it to the message listeners. The option is off by default.
#[inline(always)]
Expand Down Expand Up @@ -2234,6 +2257,32 @@ impl HeapSpaceStatistics {
}
}

#[repr(C)]
pub struct HeapCodeStatistics {
code_and_metadata_size_: usize,
bytecode_and_metadata_size_: usize,
external_script_source_size_: usize,
cpu_profiler_metadata_size_: usize,
}

impl HeapCodeStatistics {
pub fn code_and_metadata_size(&self) -> usize {
self.code_and_metadata_size_
}

pub fn bytecode_and_metadata_size(&self) -> usize {
self.bytecode_and_metadata_size_
}

pub fn external_script_source_size(&self) -> usize {
self.external_script_source_size_
}

pub fn cpu_profiler_metadata_size(&self) -> usize {
self.cpu_profiler_metadata_size_
}
}

impl<'s, F> MapFnFrom<F> for PrepareStackTraceCallback<'s>
where
F: UnitType
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ pub use handle::SealedLocal;
pub use handle::TracedReference;
pub use handle::Weak;
pub use isolate::GarbageCollectionType;
pub use isolate::HeapCodeStatistics;
pub use isolate::HeapSpaceStatistics;
pub use isolate::HeapStatistics;
pub use isolate::HostCreateShadowRealmContextCallback;
Expand Down
36 changes: 36 additions & 0 deletions tests/test_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7792,6 +7792,42 @@ fn heap_statistics() {
assert_ne!(s.number_of_native_contexts(), 0);
}

#[test]
fn heap_code_statistics() {
let _setup_guard = setup::parallel_test();

let isolate = &mut v8::Isolate::new(Default::default());

// Before running any code, statistics should still be available.
let s = isolate
.get_heap_code_and_metadata_statistics()
.expect("get_heap_code_and_metadata_statistics should succeed");

// Before running any code, code_and_metadata_size may or may not be > 0
// depending on the platform and V8 version.
// external_script_source_size and cpu_profiler_metadata_size start at 0.
assert_eq!(s.external_script_source_size(), 0);
assert_eq!(s.cpu_profiler_metadata_size(), 0);

// Run some JS to generate bytecode.
{
v8::scope!(let scope, isolate);
let context = v8::Context::new(scope, Default::default());
let scope = &mut v8::ContextScope::new(scope, context);
eval(scope, "function foo() { return 1 + 2; } foo();").unwrap();
}

let s2 = isolate
.get_heap_code_and_metadata_statistics()
.expect("get_heap_code_and_metadata_statistics should succeed");

// After compiling code, bytecode_and_metadata_size should increase.
assert!(s2.bytecode_and_metadata_size() > 0);
// code_and_metadata_size tracks JIT-compiled code, which may be 0 if V8
// only uses the interpreter for simple scripts.
assert!(s2.code_and_metadata_size() >= s.code_and_metadata_size());
}

#[test]
fn low_memory_notification() {
let _setup_guard = setup::parallel_test();
Expand Down