Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
28 changes: 18 additions & 10 deletions crates/core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,12 @@ pub struct V8HeapPolicyConfig {
pub heap_gc_trigger_fraction: f64,
#[serde(default = "def_retire", deserialize_with = "de_fraction")]
pub heap_retire_fraction: f64,
#[serde(default, rename = "heap-limit-mb", deserialize_with = "de_limit_mb")]
pub heap_limit_bytes: Option<usize>,
#[serde(
default = "def_heap_limit",
rename = "heap-limit-mb",
deserialize_with = "de_limit_mb"
)]
pub heap_limit_bytes: usize,
}

impl Default for V8HeapPolicyConfig {
Expand All @@ -196,7 +200,7 @@ impl Default for V8HeapPolicyConfig {
heap_check_time_interval: def_time_interval(),
heap_gc_trigger_fraction: def_gc_trigger(),
heap_retire_fraction: def_retire(),
heap_limit_bytes: None,
heap_limit_bytes: def_heap_limit(),
}
}
}
Expand Down Expand Up @@ -237,6 +241,12 @@ fn def_retire() -> f64 {
0.75
}

/// Default heap limit, in bytes
fn def_heap_limit() -> usize {
// 1 GiB
1024 * 1024 * 1024
}

fn de_nz_u64<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
where
D: serde::Deserializer<'de>,
Expand Down Expand Up @@ -289,22 +299,20 @@ where
}
}

fn de_limit_mb<'de, D>(deserializer: D) -> Result<Option<usize>, D::Error>
fn de_limit_mb<'de, D>(deserializer: D) -> Result<usize, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = u64::deserialize(deserializer)?;
if value == 0 {
return Ok(None);
return Ok(def_heap_limit());
}

let bytes = value
.checked_mul(1024 * 1024)
.ok_or_else(|| serde::de::Error::custom("heap-limit-mb is too large"))?;

usize::try_from(bytes)
.map(Some)
.map_err(|_| serde::de::Error::custom("heap-limit-mb does not fit in usize"))
usize::try_from(bytes).map_err(|_| serde::de::Error::custom("heap-limit-mb does not fit in usize"))
}

#[cfg(test)]
Expand Down Expand Up @@ -420,7 +428,7 @@ mod tests {
);
assert_eq!(config.v8_heap_policy.heap_gc_trigger_fraction, 0.67);
assert_eq!(config.v8_heap_policy.heap_retire_fraction, 0.75);
assert_eq!(config.v8_heap_policy.heap_limit_bytes, None);
assert_eq!(config.v8_heap_policy.heap_limit_bytes, 1024 * 1024 * 1024);
}

#[test]
Expand All @@ -443,6 +451,6 @@ mod tests {
);
assert_eq!(config.v8_heap_policy.heap_gc_trigger_fraction, 0.6);
assert_eq!(config.v8_heap_policy.heap_retire_fraction, 0.8);
assert_eq!(config.v8_heap_policy.heap_limit_bytes, Some(256 * 1024 * 1024));
assert_eq!(config.v8_heap_policy.heap_limit_bytes, 256 * 1024 * 1024);
}
}
67 changes: 47 additions & 20 deletions crates/core/src/host/v8/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ pub(crate) struct ExceptionThrown {

impl ExceptionThrown {
/// Turns a caught JS exception in `scope` into a [`JSError`].
pub(crate) fn into_error(self, scope: &mut PinTryCatch) -> JsError {
pub(crate) fn into_error(self, scope: &mut PinTryCatch) -> Result<JsError, UnknownJsError> {
JsError::from_caught(scope)
}
}
Expand Down Expand Up @@ -254,12 +254,15 @@ pub(super) enum ErrorOrException<Exc> {
Exception(Exc),
}

impl<Exc> ErrorOrException<Exc> {
pub(super) fn map_exception<Exc2>(self, f: impl FnOnce(Exc) -> Exc2) -> ErrorOrException<Exc2> {
match self {
impl ErrorOrException<ExceptionThrown> {
pub(super) fn exc_into_error(
self,
scope: &mut PinTryCatch<'_, '_, '_, '_>,
) -> Result<ErrorOrException<JsError>, UnknownJsError> {
Ok(match self {
ErrorOrException::Err(e) => ErrorOrException::Err(e),
ErrorOrException::Exception(exc) => ErrorOrException::Exception(f(exc)),
}
ErrorOrException::Exception(exc) => ErrorOrException::Exception(exc.into_error(scope)?),
})
}
}

Expand All @@ -275,6 +278,12 @@ impl From<ExceptionThrown> for ErrorOrException<ExceptionThrown> {
}
}

impl From<JsError> for ErrorOrException<JsError> {
fn from(e: JsError) -> Self {
Self::Exception(e)
}
}

impl From<ErrorOrException<JsError>> for anyhow::Error {
fn from(err: ErrorOrException<JsError>) -> Self {
match err {
Expand Down Expand Up @@ -528,23 +537,41 @@ fn get_or_insert_slot<T: 'static>(isolate: &mut v8::Isolate, default: impl FnOnc

impl JsError {
/// Turns a caught JS exception in `scope` into a [`JSError`].
fn from_caught(scope: &mut PinTryCatch<'_, '_, '_, '_>) -> Self {
match scope.message() {
Some(message) => Self {
trace: message
.get_stack_trace(scope)
.map(|trace| JsStackTrace::from_trace(scope, trace))
.unwrap_or_default(),
msg: message.get(scope).to_rust_string_lossy(scope),
},
None => Self {
trace: JsStackTrace::default(),
msg: "unknown error".to_owned(),
},
fn from_caught(scope: &mut PinTryCatch<'_, '_, '_, '_>) -> Result<Self, UnknownJsError> {
let message = scope.message().ok_or(UnknownJsError)?;
Ok(Self {
trace: message
.get_stack_trace(scope)
.map(|trace| JsStackTrace::from_trace(scope, trace))
.unwrap_or_default(),
msg: message.get(scope).to_rust_string_lossy(scope),
})
}
}

pub(super) struct UnknownJsError;

impl From<UnknownJsError> for JsError {
fn from(_: UnknownJsError) -> Self {
Self {
trace: JsStackTrace::default(),
msg: "unknown error".to_owned(),
}
}
}

impl From<UnknownJsError> for ErrorOrException<JsError> {
fn from(e: UnknownJsError) -> Self {
Self::Exception(e.into())
}
}

impl From<UnknownJsError> for anyhow::Error {
fn from(e: UnknownJsError) -> Self {
JsError::from(e).into()
}
}

pub(super) fn log_traceback(replica_ctx: &ReplicaContext, func_type: &str, func: &str, e: &anyhow::Error) {
log::info!("{func_type} \"{func}\" runtime error: {e:}");
if let Some(js_err) = e.downcast_ref::<JsError>() {
Expand Down Expand Up @@ -573,7 +600,7 @@ pub(super) fn catch_exception<'scope, T>(
body: impl FnOnce(&mut PinTryCatch<'scope, '_, '_, '_>) -> Result<T, ErrorOrException<ExceptionThrown>>,
) -> Result<T, ErrorOrException<JsError>> {
tc_scope!(scope, scope);
body(scope).map_err(|e| e.map_exception(|exc| exc.into_error(scope)))
body(scope).map_err(|e| e.exc_into_error(scope).unwrap_or_else(Into::into))
}

pub(super) type PinTryCatch<'scope, 'iso, 'x, 's> = PinnedRef<'x, TryCatch<'s, 'scope, HandleScope<'iso>>>;
Loading
Loading