Skip to content

Commit

Permalink
Allow configuring of v8 isolate heap size.
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonforal committed Jan 15, 2025
1 parent 21d5918 commit 53dc26a
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ const validSyntax = 123;
/// the runtime's v8 isolate.
#[test]
fn create_base_runtime_mutate_ctx() {
let mut runtime = inner_make_deno_core_runtime(vec![], None);
let mut runtime = inner_make_deno_core_runtime(vec![], None, None);
// We use the ES6 `Map` constructor because it will always be present
let code = "Map;";

Expand All @@ -390,6 +390,7 @@ const validSyntax = 123;
let global_proxy = default_ctx.global(scope);
global_proxy.delete(scope, key.into());
})),
None,
);
let value = try_execute(&mut runtime.handle_scope(), code).unwrap_err();
assert_eq!(value, "ReferenceError: Map is not defined".to_string());
Expand Down
26 changes: 25 additions & 1 deletion crates/static-analysis-kernel/src/analysis/ddsa_lib/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,12 +402,13 @@ for (const queryMatch of globalThis.__RUST_BRIDGE__query_match) {{
}
}

/// Creates a [`deno_core::JsRuntime`] with the provided `extensions`.
/// Creates a [`deno_core::JsRuntime`] with the provided `extensions` and heap size limit.
///
/// # Warning
/// This will leak memory for each `deno_core::JsRuntime` created. Thus, this runtime should be reused where possible.
pub(crate) fn make_base_deno_core_runtime(
extensions: Vec<deno_core::Extension>,
max_heap_size_bytes: Option<usize>,
) -> deno_core::JsRuntime {
/// Global properties that are removed from the global proxy object of the default `v8::Context` for the `JsRuntime`.
const DEFAULT_REMOVED_GLOBAL_PROPS: &[&str] = &[
Expand All @@ -423,6 +424,7 @@ pub(crate) fn make_base_deno_core_runtime(
global_proxy.delete(scope, key.into());
}
})),
max_heap_size_bytes,
)
}

Expand All @@ -434,12 +436,19 @@ pub type V8DefaultContextMutateFn = dyn Fn(&mut HandleScope, v8::Local<v8::Conte
/// that will be used as the base for all newly-created `v8::Context`s within the
/// runtime's `v8::Isolate`.
///
/// If provided, `max_heap_size_bytes` will configure a hard limit for the heap.
///
/// # Warning
/// This will leak memory for each `deno_core::JsRuntime` created. Thus, this runtime should be reused where possible.
pub(crate) fn inner_make_deno_core_runtime(
extensions: Vec<deno_core::Extension>,
config_default_v8_context: Option<Box<V8DefaultContextMutateFn>>,
max_heap_size_bytes: Option<usize>,
) -> deno_core::JsRuntime {
let mut create_params = v8::CreateParams::default();
if let Some(max) = max_heap_size_bytes {
create_params = create_params.heap_limits(0, max);
}
// [11-22-24]: There _may_ be an issue on Linux systems with PKU support where multiple
// deno_core::JsRuntime will attempt to use the same memory map, leading to segfaults.
// If this is the case, creating and using snapshots for each JsRuntime should fix this.
Expand All @@ -452,6 +461,7 @@ pub(crate) fn inner_make_deno_core_runtime(
let snapshot = snapshot_runtime.snapshot();
let leaked = Box::leak(snapshot);
deno_core::JsRuntime::new(deno_core::RuntimeOptions {
create_params: Some(create_params),
extensions,
startup_snapshot: Some(leaked),
..Default::default()
Expand Down Expand Up @@ -507,6 +517,7 @@ mod tests {
use crate::analysis::ddsa_lib::common::{
compile_script, v8_interned, v8_uint, DDSAJsRuntimeError, Instance,
};
use crate::analysis::ddsa_lib::runtime::make_base_deno_core_runtime;
use crate::analysis::ddsa_lib::test_utils::{cfg_test_v8, try_execute};
use crate::analysis::ddsa_lib::{js, JsRuntime};
use crate::analysis::tree_sitter::{get_tree, get_tree_sitter_language, TSQuery};
Expand Down Expand Up @@ -1302,4 +1313,17 @@ function visit(captures) {
let expected = r#"{"cstType":"identifier","start":{"line":1,"col":15},"end":{"line":1,"col":16},"text":"a"}"#;
assert_eq!(console_lines[0], expected);
}

/// [`make_base_deno_core_runtime`] can create a v8 isolate with a max heap size.
#[test]
fn make_base_deno_core_runtime_set_heap_limit() {
const MAX_BYTES: usize = 16 * 1024 * 1024;
let mut heap_stats = v8::HeapStatistics::default();
let _v8 = cfg_test_v8();
for size in [MAX_BYTES, MAX_BYTES * 2] {
let mut rt = make_base_deno_core_runtime(vec![], Some(size));
rt.v8_isolate().get_heap_statistics(&mut heap_stats);
assert_eq!(heap_stats.heap_size_limit(), size);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,22 @@ impl V8Platform<CfgTest> {
JsRuntime::try_new(test_deno_core_runtime).unwrap()
}

pub fn new_runtime_with_heap_limit(&self, max_heap_size_bytes: usize) -> JsRuntime {
let test_deno_core_runtime = self.deno_core_rt_with_heap_limit(max_heap_size_bytes);
JsRuntime::try_new(test_deno_core_runtime).unwrap()
}

/// Constructs a `deno_core::JsRuntime` with no v8 isolate heap limit.
pub fn deno_core_rt(&self) -> deno_core::JsRuntime {
make_base_deno_core_runtime(vec![cfg_test_deno_ext()])
make_base_deno_core_runtime(Self::extensions(), None)
}

/// Constructs a `deno_core::JsRuntime` with no v8 isolate heap limit.
pub fn deno_core_rt_with_heap_limit(&self, max_heap_size_bytes: usize) -> deno_core::JsRuntime {
make_base_deno_core_runtime(Self::extensions(), Some(max_heap_size_bytes))
}

fn extensions() -> Vec<deno_core::Extension> {
vec![cfg_test_deno_ext()]
}
}
21 changes: 18 additions & 3 deletions crates/static-analysis-kernel/src/analysis/ddsa_lib/v8_platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,25 @@ impl V8Platform<Uninitialized> {
}

impl V8Platform<Initialized> {
/// Creates and returns a new [`JsRuntime`] that utilizes this v8 platform.
/// Creates and returns a new [`JsRuntime`]. The v8 isolate's heap limit is set according to
/// the flags used to initialize this v8 platform.
pub fn try_new_runtime(&self) -> Result<JsRuntime, DDSAJsRuntimeError> {
let deno_runtime = make_base_deno_core_runtime(vec![ddsa_lib::init_ops_and_esm()]);
JsRuntime::try_new(deno_runtime)
JsRuntime::try_new(make_base_deno_core_runtime(Self::extensions(), None))
}

/// Creates and returns a new [`JsRuntime`] with the provided v8 isolate heap size limit.
pub fn try_new_runtime_with_heap_limit(
&self,
max_heap_size_bytes: usize,
) -> Result<JsRuntime, DDSAJsRuntimeError> {
JsRuntime::try_new(make_base_deno_core_runtime(
Self::extensions(),
Some(max_heap_size_bytes),
))
}

fn extensions() -> Vec<deno_core::Extension> {
vec![ddsa_lib::init_ops_and_esm()]
}
}

Expand Down

0 comments on commit 53dc26a

Please sign in to comment.