Skip to content
Merged
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
317 changes: 253 additions & 64 deletions crates/perry-runtime/src/array/iterator.rs

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions crates/perry-runtime/src/closure/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,10 @@ pub(crate) fn test_captured_singleton_closure_cache_entries(
/// covers the per-batch fan-out shape (50 promises) found in
/// `benchmarks/app-patterns/kernels/promise_all_chains.ts`.
const MAX_CAPTURED_CLOSURE_SLOTS: usize = 64;
const _: () = assert!(
MAX_CAPTURED_CLOSURE_SLOTS <= u8::MAX as usize,
"hint_indices_plus_one stores an entry index plus one in a u8"
);

/// Per-`func_ptr` cache miss-streak counter for the adaptive bypass.
/// Closures whose captures change every call (per-call boxes for
Expand Down Expand Up @@ -581,9 +585,8 @@ pub extern "C" fn js_closure_alloc_with_captures_singleton(
}
crate::promise::bump(&CLOSURE_CAP_SINGLETON_MISS);

// Slow path: allocate, populate captures, insert into cache as
// the most-recent entry. If the slot list is full, drop the
// least-recent (back of the Vec).
// Slow path: allocate, populate captures, and insert with a fresh usage
// timestamp. If the entry list is full, replace its oldest timestamp.
let capture_scope = crate::gc::RuntimeHandleScope::new();
let capture_handles: Vec<_> = captures_slice
.iter()
Expand Down
4 changes: 2 additions & 2 deletions crates/perry-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,8 @@ pub use object::{
};
pub use promise::{js_is_promise, js_promise_run_microtasks, js_promise_state, js_promise_value};
pub use promise::{
js_promise_mark_internally_handled, js_promise_new, js_promise_reject, js_promise_rejected,
js_promise_resolve, js_promise_resolved,
js_promise_mark_internally_handled, js_promise_new, js_promise_new_cross_thread,
js_promise_reject, js_promise_rejected, js_promise_resolve, js_promise_resolved,
};
pub use string::js_string_from_bytes;
pub use value::{
Expand Down
6 changes: 3 additions & 3 deletions crates/perry-stdlib/src/argon2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ use argon2::{
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Argon2,
};
use perry_runtime::{js_promise_new, js_string_from_bytes, Promise, StringHeader};
use perry_runtime::{js_promise_new_cross_thread, js_string_from_bytes, Promise, StringHeader};

/// argon2.hash(password) -> Promise<string>
///
/// Hash a password using Argon2id with default parameters.
#[no_mangle]
pub unsafe extern "C" fn js_argon2_hash(password_ptr: *const StringHeader) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();

let password = match string_from_header(password_ptr) {
Some(p) => p,
Expand Down Expand Up @@ -77,7 +77,7 @@ pub unsafe extern "C" fn js_argon2_verify(
hash_ptr: *const StringHeader,
password_ptr: *const StringHeader,
) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();

let hash_str = match string_from_header(hash_ptr) {
Some(h) => h,
Expand Down
12 changes: 6 additions & 6 deletions crates/perry-stdlib/src/axios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::common::{
get_handle, register_handle, spawn_for_promise, string_from_header_lossy as string_from_header,
Handle,
};
use perry_runtime::{js_promise_new, js_string_from_bytes, Promise, StringHeader};
use perry_runtime::{js_promise_new_cross_thread, js_string_from_bytes, Promise, StringHeader};

/// #598: read the body argument as a JSON string. Strings pass
/// through as-is; everything else is JSON.stringify'd via the
Expand Down Expand Up @@ -49,7 +49,7 @@ unsafe fn request_without_body(
url_ptr: *const StringHeader,
method: reqwest::Method,
) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();

let url = match string_from_header(url_ptr) {
Some(u) => u,
Expand Down Expand Up @@ -119,7 +119,7 @@ pub unsafe extern "C" fn js_axios_options(url_ptr: *const StringHeader) -> *mut
/// axios.post(url, data) -> Promise<AxiosResponse>
#[no_mangle]
pub unsafe extern "C" fn js_axios_post(url_ptr: *const StringHeader, data: f64) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();

let url = match string_from_header(url_ptr) {
Some(u) => u,
Expand Down Expand Up @@ -186,7 +186,7 @@ pub unsafe extern "C" fn js_axios_post(url_ptr: *const StringHeader, data: f64)
/// axios.put(url, data) -> Promise<AxiosResponse>
#[no_mangle]
pub unsafe extern "C" fn js_axios_put(url_ptr: *const StringHeader, data: f64) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();

let url = match string_from_header(url_ptr) {
Some(u) => u,
Expand Down Expand Up @@ -250,7 +250,7 @@ pub unsafe extern "C" fn js_axios_put(url_ptr: *const StringHeader, data: f64) -
/// axios.delete(url) -> Promise<AxiosResponse>
#[no_mangle]
pub unsafe extern "C" fn js_axios_delete(url_ptr: *const StringHeader) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();

let url = match string_from_header(url_ptr) {
Some(u) => u,
Expand Down Expand Up @@ -305,7 +305,7 @@ pub unsafe extern "C" fn js_axios_delete(url_ptr: *const StringHeader) -> *mut P
/// axios.patch(url, data) -> Promise<AxiosResponse>
#[no_mangle]
pub unsafe extern "C" fn js_axios_patch(url_ptr: *const StringHeader, data: f64) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();

let url = match string_from_header(url_ptr) {
Some(u) => u,
Expand Down
6 changes: 3 additions & 3 deletions crates/perry-stdlib/src/bcrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub unsafe extern "C" fn js_bcrypt_hash(
password_ptr: *const StringHeader,
salt_rounds: f64,
) -> *mut perry_runtime::Promise {
let promise = perry_runtime::js_promise_new();
let promise = perry_runtime::js_promise_new_cross_thread();
let promise_ptr = promise as usize;

let password = match string_from_header(password_ptr) {
Expand Down Expand Up @@ -79,7 +79,7 @@ pub unsafe extern "C" fn js_bcrypt_compare(
password_ptr: *const StringHeader,
hash_ptr: *const StringHeader,
) -> *mut perry_runtime::Promise {
let promise = perry_runtime::js_promise_new();
let promise = perry_runtime::js_promise_new_cross_thread();
let promise_ptr = promise as usize;

let password = match string_from_header(password_ptr) {
Expand Down Expand Up @@ -142,7 +142,7 @@ pub unsafe extern "C" fn js_bcrypt_compare(
/// bcrypt.genSalt(rounds) -> Promise<string>
#[no_mangle]
pub unsafe extern "C" fn js_bcrypt_gen_salt(rounds: f64) -> *mut perry_runtime::Promise {
let promise = perry_runtime::js_promise_new();
let promise = perry_runtime::js_promise_new_cross_thread();
let promise_ptr = promise as usize;
let cost = rounds as u32;

Expand Down
13 changes: 12 additions & 1 deletion crates/perry-stdlib/src/common/async_bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,18 @@ unsafe fn unpin_promise_after_native_resolution(promise_ptr: usize) {
#[inline]
pub unsafe fn js_promise_new_for_native_resolution() -> *mut perry_runtime::Promise {
ensure_gc_scanner_registered();
let p = perry_runtime::js_promise_new();
// #8770: allocate in MALLOC space (non-moving), not the nursery arena. A
// native-resolution promise is handed to a tokio worker as a raw `usize` and,
// until its resolution is queued into PENDING_RESOLUTIONS (which the root
// scanner visits), it is reachable only through that worker-thread capture —
// invisible to the main-thread copying minor. A nursery resident in that
// window is wiped by the from-space flip REGARDLESS of its PIN flag (the flip
// resets eden/survivor blocks wholesale; only root-reachable pins force the
// fallback — see `js_promise_new_cross_thread`). Then `js_stdlib_process_
// pending` unpins/resolves through the stale pointer and faults on the
// reclaimed header. Malloc space is non-moving and both sweep paths honor
// GC_FLAG_PINNED, so the pin actually protects it there.
let p = perry_runtime::js_promise_new_cross_thread();
pin_promise_for_native_resolution(p as usize);
p
}
Expand Down
10 changes: 5 additions & 5 deletions crates/perry-stdlib/src/container/backend_ctl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub use types::{
};

pub use backend::{detect_backend, ContainerBackend};
use perry_runtime::{js_promise_new, Promise, StringHeader};
use perry_runtime::{js_promise_new_cross_thread, Promise, StringHeader};
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::OnceLock;
Expand Down Expand Up @@ -77,7 +77,7 @@ pub unsafe extern "C" fn js_container_getBackend() -> *const StringHeader {
/// FFI: js_container_detectBackend() -> *mut Promise
#[no_mangle]
pub unsafe extern "C" fn js_container_detectBackend() -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();
crate::common::spawn_for_promise_deferred(
promise as *mut u8,
async move {
Expand Down Expand Up @@ -199,7 +199,7 @@ pub unsafe extern "C" fn js_container_selectBackendFor(
/// await setBackends(ready.map(b => b.name));
#[no_mangle]
pub unsafe extern "C" fn js_container_getAvailableBackends() -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();
crate::common::spawn_for_promise_deferred(
promise as *mut u8,
async move {
Expand Down Expand Up @@ -249,7 +249,7 @@ pub unsafe extern "C" fn js_container_getBackendPriority() -> *const StringHeade
/// - `"backend probe failed: <reason>"`
#[no_mangle]
pub unsafe extern "C" fn js_container_setBackend(name_ptr: *const StringHeader) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();
let name = match string_from_header(name_ptr) {
Some(s) => s,
None => {
Expand Down Expand Up @@ -328,7 +328,7 @@ pub unsafe extern "C" fn js_container_setBackend(name_ptr: *const StringHeader)
pub unsafe extern "C" fn js_container_setBackends(
names_json_ptr: *const StringHeader,
) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();
let names_json = match string_from_header(names_json_ptr) {
Some(s) => s,
None => {
Expand Down
20 changes: 10 additions & 10 deletions crates/perry-stdlib/src/container/compose_ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub use types::{
};

pub use backend::{detect_backend, ContainerBackend};
use perry_runtime::{js_promise_new, Promise, StringHeader};
use perry_runtime::{js_promise_new_cross_thread, Promise, StringHeader};
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::OnceLock;
Expand All @@ -19,7 +19,7 @@ pub unsafe extern "C" fn js_container_compose_start(
handle: f64,
services_json_ptr: *const StringHeader,
) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();
let handle_id = handle_id_from_f64(handle);

let engine = match types::get_compose_handle(handle_id as u64) {
Expand Down Expand Up @@ -57,7 +57,7 @@ pub unsafe extern "C" fn js_container_compose_stop(
handle: f64,
services_json_ptr: *const StringHeader,
) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();
let handle_id = handle_id_from_f64(handle);

let engine = match types::get_compose_handle(handle_id as u64) {
Expand Down Expand Up @@ -95,7 +95,7 @@ pub unsafe extern "C" fn js_container_compose_restart(
handle: f64,
services_json_ptr: *const StringHeader,
) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();
let handle_id = handle_id_from_f64(handle);

let engine = match types::get_compose_handle(handle_id as u64) {
Expand Down Expand Up @@ -131,7 +131,7 @@ pub unsafe extern "C" fn js_container_compose_restart(
/// FFI: `js_container_compose_config(handle: f64) -> *mut Promise`
#[no_mangle]
pub unsafe extern "C" fn js_container_compose_config(handle: f64) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();
let handle_id = handle_id_from_f64(handle);

let engine = match types::get_compose_handle(handle_id as u64) {
Expand Down Expand Up @@ -164,7 +164,7 @@ pub unsafe extern "C" fn js_container_compose_config(handle: f64) -> *mut Promis
pub unsafe extern "C" fn js_container_composeUp(
spec_ptr: *const perry_runtime::StringHeader,
) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();

let spec = match types::parse_compose_spec(spec_ptr) {
Ok(s) => s,
Expand Down Expand Up @@ -283,7 +283,7 @@ pub unsafe extern "C" fn js_container_compose_down(
handle: f64,
opts_ptr: *const StringHeader,
) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();
let handle_id = handle_id_from_f64(handle);

let opts_json = unsafe { string_from_header(opts_ptr) };
Expand Down Expand Up @@ -330,7 +330,7 @@ pub unsafe extern "C" fn js_container_compose_down(
/// FFI: `js_container_compose_ps(handle: f64) -> *mut Promise`
#[no_mangle]
pub unsafe extern "C" fn js_container_compose_ps(handle: f64) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();
let handle_id = handle_id_from_f64(handle);

let engine = match types::get_compose_handle(handle_id as u64) {
Expand Down Expand Up @@ -376,7 +376,7 @@ pub unsafe extern "C" fn js_container_compose_logs(
service_ptr: *const StringHeader,
tail: f64,
) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();
let handle_id = handle_id_from_f64(handle);

let engine = match types::get_compose_handle(handle_id as u64) {
Expand Down Expand Up @@ -427,7 +427,7 @@ pub unsafe extern "C" fn js_container_compose_exec(
service_ptr: *const StringHeader,
cmd_json_ptr: *const StringHeader,
) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();
let handle_id = handle_id_from_f64(handle);

let engine = match types::get_compose_handle(handle_id as u64) {
Expand Down
10 changes: 5 additions & 5 deletions crates/perry-stdlib/src/container/images.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub use types::{
};

pub use backend::{detect_backend, ContainerBackend};
use perry_runtime::{js_promise_new, Promise, StringHeader};
use perry_runtime::{js_promise_new_cross_thread, Promise, StringHeader};
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::OnceLock;
Expand All @@ -19,7 +19,7 @@ use std::sync::OnceLock;
pub unsafe extern "C" fn js_container_pullImage(
reference_ptr: *const StringHeader,
) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();

let reference = match string_from_header(reference_ptr) {
Some(s) => s,
Expand Down Expand Up @@ -52,7 +52,7 @@ pub unsafe extern "C" fn js_container_pullImage(
/// FFI: js_container_listImages() -> *mut Promise
#[no_mangle]
pub unsafe extern "C" fn js_container_listImages() -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();

// Resolves with a JSON-encoded `ImageInfo[]` string.
crate::common::spawn_for_promise_deferred(
Expand All @@ -78,7 +78,7 @@ pub unsafe extern "C" fn js_container_build(
spec_ptr: *const StringHeader,
image_name_ptr: *const StringHeader,
) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();

let spec_json = string_from_header(spec_ptr).unwrap_or_else(|| "{}".to_string());
let image_name = string_from_header(image_name_ptr).unwrap_or_default();
Expand Down Expand Up @@ -108,7 +108,7 @@ pub unsafe extern "C" fn js_container_removeImage(
reference_ptr: *const StringHeader,
force: i32,
) -> *mut Promise {
let promise = js_promise_new();
let promise = js_promise_new_cross_thread();

let reference = match string_from_header(reference_ptr) {
Some(s) => s,
Expand Down
Loading
Loading