Skip to content
Draft
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
3 changes: 3 additions & 0 deletions changelog.d/12113-ext-test-handle-scope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The http, net, streams and ws ext-crate tests root values through
`RuntimeHandleScope`. The runtime does not export the shadow-stack entry
points on native stack-map targets, so these tests no longer compiled.
25 changes: 11 additions & 14 deletions crates/perry-ext-http/src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,29 +215,25 @@ mod tests {
static GC_TEST_LOCK: Mutex<()> = Mutex::new(());

struct GcTestGuard {
frame: u64,
previous_force_evacuation: i32,
_lock: MutexGuard<'static, ()>,
}

impl GcTestGuard {
fn new() -> Self {
Self::new_with_slots(0)
}

fn new_with_slots(slot_count: u32) -> Self {
let lock = GC_TEST_LOCK
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner());
// Unit tests skip program startup, which registers the runtime-handle
// root scanner these tests root values through.
perry_runtime::gc::gc_init();
// Rewriting is observable only when the collector moves the root.
// Keep that test policy thread-local so unrelated test threads do
// not observe a process-wide environment mutation.
let previous_force_evacuation =
perry_runtime::gc::js_gc_force_evacuation_test_override(1);
perry_runtime::gc::js_gc_write_barriers_emitted(1);
let frame = perry_runtime::gc::js_shadow_frame_push(slot_count);
Self {
frame,
previous_force_evacuation,
_lock: lock,
}
Expand All @@ -246,7 +242,6 @@ mod tests {

impl Drop for GcTestGuard {
fn drop(&mut self) {
perry_runtime::gc::js_shadow_frame_pop(self.frame);
perry_runtime::gc::js_gc_write_barriers_emitted(0);
perry_runtime::gc::js_gc_force_evacuation_test_override(self.previous_force_evacuation);
}
Expand Down Expand Up @@ -398,16 +393,17 @@ mod tests {

#[test]
fn http_server_options_store_keep_alive_timeout_buffer() {
let _guard = GcTestGuard::new_with_slots(1);
let _guard = GcTestGuard::new();
let options_json = perry_ffi::alloc_string(
r#"{"headersTimeout":111,"keepAliveTimeout":222,"keepAliveTimeoutBuffer":321,"requestTimeout":444}"#,
);
let options_ptr = options_json.as_raw() as *const perry_runtime::StringHeader;
let options = unsafe { perry_runtime::json::js_json_parse(options_ptr) };
perry_runtime::gc::js_shadow_slot_set(0, options.bits());
let scope = perry_runtime::gc::RuntimeHandleScope::new();
let options = scope.root_nanbox_u64(options.bits());

let mut server = HttpServer::with_handler(0);
crate::server::server::apply_server_options(&mut server, f64::from_bits(options.bits()));
crate::server::server::apply_server_options(&mut server, options.get_nanbox_f64());

assert_eq!(server.headers_timeout, 111.0);
assert_eq!(server.keep_alive_timeout, 222.0);
Expand Down Expand Up @@ -599,15 +595,16 @@ mod tests {
drop_handle(handle);

// Option path through `apply_server_options`.
let _guard = GcTestGuard::new_with_slots(1);
let _guard = GcTestGuard::new();
let options_json =
perry_ffi::alloc_string(r#"{"requestTimeout":1e300,"headersTimeout":222}"#);
let options_ptr = options_json.as_raw() as *const perry_runtime::StringHeader;
let options = unsafe { perry_runtime::json::js_json_parse(options_ptr) };
perry_runtime::gc::js_shadow_slot_set(0, options.bits());
let scope = perry_runtime::gc::RuntimeHandleScope::new();
let options = scope.root_nanbox_u64(options.bits());

let mut server = HttpServer::with_handler(0);
crate::server::server::apply_server_options(&mut server, f64::from_bits(options.bits()));
crate::server::server::apply_server_options(&mut server, options.get_nanbox_f64());
// Oversized `requestTimeout` clamped; unrelated knob untouched.
assert_eq!(server.request_timeout, 9_007_199_254_740_991.0);
assert_eq!(server.headers_timeout, 222.0);
Expand Down
4 changes: 0 additions & 4 deletions crates/perry-ext-http/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use std::sync::{Mutex, MutexGuard};
pub(crate) static GC_TEST_LOCK: Mutex<()> = Mutex::new(());

struct GcTestGuard {
frame: u64,
previous_force_evacuation: i32,
_lock: MutexGuard<'static, ()>,
}
Expand All @@ -21,9 +20,7 @@ impl GcTestGuard {
// observe a process-wide environment mutation.
let previous_force_evacuation = perry_runtime::gc::js_gc_force_evacuation_test_override(1);
perry_runtime::gc::js_gc_write_barriers_emitted(1);
let frame = perry_runtime::gc::js_shadow_frame_push(0);
Self {
frame,
previous_force_evacuation,
_lock: lock,
}
Expand All @@ -32,7 +29,6 @@ impl GcTestGuard {

impl Drop for GcTestGuard {
fn drop(&mut self) {
perry_runtime::gc::js_shadow_frame_pop(self.frame);
perry_runtime::gc::js_gc_write_barriers_emitted(0);
perry_runtime::gc::js_gc_force_evacuation_test_override(self.previous_force_evacuation);
}
Expand Down
19 changes: 10 additions & 9 deletions crates/perry-ext-net/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use std::sync::{Mutex, MutexGuard};
pub(crate) static GC_TEST_LOCK: Mutex<()> = Mutex::new(());

struct GcTestGuard {
frame: u64,
previous_force_evacuation: i32,
_lock: MutexGuard<'static, ()>,
}
Expand All @@ -17,14 +16,15 @@ impl GcTestGuard {
let lock = GC_TEST_LOCK
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner());
// Unit tests skip program startup, which registers the runtime-handle
// root scanner these tests root values through.
perry_runtime::gc::gc_init();
// Rewriting is observable only when the collector moves the root.
// Keep that test policy thread-local so unrelated test threads do not
// observe a process-wide environment mutation.
let previous_force_evacuation = perry_runtime::gc::js_gc_force_evacuation_test_override(1);
perry_runtime::gc::js_gc_write_barriers_emitted(1);
let frame = perry_runtime::gc::js_shadow_frame_push(1);
Self {
frame,
previous_force_evacuation,
_lock: lock,
}
Expand All @@ -33,7 +33,6 @@ impl GcTestGuard {

impl Drop for GcTestGuard {
fn drop(&mut self) {
perry_runtime::gc::js_shadow_frame_pop(self.frame);
perry_runtime::gc::js_gc_write_barriers_emitted(0);
perry_runtime::gc::js_gc_force_evacuation_test_override(self.previous_force_evacuation);
}
Expand Down Expand Up @@ -81,11 +80,12 @@ fn gc_mutable_scanner_rewrites_listener_roots() {
crate::gc_roots::scan_net_roots,
);

// Keep an ordinary shadow-stack root as the control. Its rewrite proves
// Keep an ordinary runtime-handle root as the control. Its rewrite proves
// the collection copied live objects independently of scan_net_roots, so
// a listener that stays at its old address is an actual scanner failure.
let control = young_gc_root();
perry_runtime::gc::js_shadow_slot_set(0, control as u64);
let scope = perry_runtime::gc::RuntimeHandleScope::new();
let control_root = scope.root_heap_word_u64(control as u64);

let socket_id = -9_001;
let _cleanup = NetHandleCleanup::new(vec![socket_id]);
Expand All @@ -112,7 +112,7 @@ fn gc_mutable_scanner_rewrites_listener_roots() {
perry_runtime::gc::moved_objects_total() > moved_objects_before,
"copying minor did not relocate an object, so the scanner was not exercised"
);
assert_rewritten(control, perry_runtime::gc::js_shadow_slot_get(0) as i64);
assert_rewritten(control, control_root.get_heap_word_u64() as i64);

let after = {
let listeners = statics::listeners().lock().unwrap();
Expand Down Expand Up @@ -413,7 +413,8 @@ fn stored_socket_endpoints_reach_dynamic_dispatch() {
);
// Preserve an address/family string if the dispatch getter allocates
// across a moving collection before the value comparison.
perry_runtime::gc::js_shadow_slot_set(0, expected.to_bits());
let scope = perry_runtime::gc::RuntimeHandleScope::new();
let expected = scope.root_nanbox_f64(expected);
let mut actual = dispatch::undefined();
assert_eq!(
unsafe {
Expand All @@ -427,7 +428,7 @@ fn stored_socket_endpoints_reach_dynamic_dispatch() {
1,
"{name} is claimed for a socket"
);
let expected = f64::from_bits(perry_runtime::gc::js_shadow_slot_get(0));
let expected = expected.get_nanbox_f64();
assert_ne!(
perry_runtime::value::js_jsvalue_equals(expected, actual),
0,
Expand Down
4 changes: 0 additions & 4 deletions crates/perry-ext-streams/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1449,7 +1449,6 @@ mod tests {
static GC_TEST_LOCK: Mutex<()> = Mutex::new(());

struct GcTestGuard {
frame: u64,
previous_force_evacuation: i32,
_lock: MutexGuard<'static, ()>,
}
Expand All @@ -1462,9 +1461,7 @@ mod tests {
let previous_force_evacuation =
perry_runtime::gc::js_gc_force_evacuation_test_override(1);
perry_runtime::gc::js_gc_write_barriers_emitted(1);
let frame = perry_runtime::gc::js_shadow_frame_push(0);
Self {
frame,
previous_force_evacuation,
_lock: lock,
}
Expand All @@ -1473,7 +1470,6 @@ mod tests {

impl Drop for GcTestGuard {
fn drop(&mut self) {
perry_runtime::gc::js_shadow_frame_pop(self.frame);
perry_runtime::gc::js_gc_write_barriers_emitted(0);
perry_runtime::gc::js_gc_force_evacuation_test_override(self.previous_force_evacuation);
}
Expand Down
4 changes: 0 additions & 4 deletions crates/perry-ext-ws/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use std::sync::{Mutex, MutexGuard};
static GC_TEST_LOCK: Mutex<()> = Mutex::new(());

struct GcTestGuard {
frame: u64,
previous_force_evacuation: i32,
_lock: MutexGuard<'static, ()>,
}
Expand All @@ -17,9 +16,7 @@ impl GcTestGuard {
.unwrap_or_else(|poisoned| poisoned.into_inner());
let previous_force_evacuation = perry_runtime::gc::js_gc_force_evacuation_test_override(1);
perry_runtime::gc::js_gc_write_barriers_emitted(1);
let frame = perry_runtime::gc::js_shadow_frame_push(0);
Self {
frame,
previous_force_evacuation,
_lock: lock,
}
Expand All @@ -28,7 +25,6 @@ impl GcTestGuard {

impl Drop for GcTestGuard {
fn drop(&mut self) {
perry_runtime::gc::js_shadow_frame_pop(self.frame);
perry_runtime::gc::js_gc_write_barriers_emitted(0);
perry_runtime::gc::js_gc_force_evacuation_test_override(self.previous_force_evacuation);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ crate-type = ["staticlib", "rlib"]

[dependencies]
perry-ffi = { workspace = true }

[dev-dependencies]
perry-ffi = { workspace = true, features = ["runtime-link"] }
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ use perry_ffi::{alloc_string, read_buffer_bytes, BufferHeader, StringHeader};
#[no_mangle]
pub unsafe extern "C" fn js_pdf_parse(buf_ptr: i64) -> *mut StringHeader {
let buf_ptr = (buf_ptr as u64 & 0x0000_FFFF_FFFF_FFFF) as *const BufferHeader;
let bytes = read_buffer_bytes(buf_ptr).unwrap_or(&[]);
let summary = format!("stub: {} bytes", bytes.len());
let len =
perry_ffi::bytes::no_gc(|scope| read_buffer_bytes(buf_ptr, scope).map_or(0, <[u8]>::len));
let summary = format!("stub: {len} bytes");
alloc_string(&summary).as_raw()
}

Expand Down
Loading