From 04932b40a0225e18282a0809c5e1827fc20095a6 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Tue, 11 Aug 2026 20:18:56 +0900 Subject: [PATCH 01/52] gc: report a completed transition from the cranelift and wasm collect_step trampolines Both are installed into ACTIVE_COLLECT_STEP, so they stood in front of the already-corrected majit-gc fallback and the trait default. Assisted-by: Claude --- majit/majit-backend-cranelift/src/compiler.rs | 3 ++- majit/majit-backend-wasm/src/lib.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/majit/majit-backend-cranelift/src/compiler.rs b/majit/majit-backend-cranelift/src/compiler.rs index 3e4ec0bedbc..8cbd8506101 100644 --- a/majit/majit-backend-cranelift/src/compiler.rs +++ b/majit/majit-backend-cranelift/src/compiler.rs @@ -1737,7 +1737,8 @@ fn collect_full_via_active_runtime() { fn collect_step_via_active_runtime() -> majit_gc::GcStepTransition { with_cranelift_gc(|gc| gc.collect_step()).unwrap_or(majit_gc::GcStepTransition { - old_state: majit_gc::GcStepTransition::SCANNING, + // `rgc.py:20-31`: SCANNING on both sides would never report completion. + old_state: majit_gc::GcStepTransition::MARKING, new_state: majit_gc::GcStepTransition::SCANNING, }) } diff --git a/majit/majit-backend-wasm/src/lib.rs b/majit/majit-backend-wasm/src/lib.rs index 9857cccca50..59eea88019c 100644 --- a/majit/majit-backend-wasm/src/lib.rs +++ b/majit/majit-backend-wasm/src/lib.rs @@ -616,7 +616,8 @@ fn wasm_collect_full() { fn wasm_collect_step() -> majit_gc::GcStepTransition { with_wasm_active_gc_mut(|gc| gc.collect_step()).unwrap_or(majit_gc::GcStepTransition { - old_state: majit_gc::GcStepTransition::SCANNING, + // `rgc.py:20-31`: SCANNING on both sides would never report completion. + old_state: majit_gc::GcStepTransition::MARKING, new_state: majit_gc::GcStepTransition::SCANNING, }) } From 46447ede2f129c22d28529c969dbbcd27bcc8a7f Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Tue, 11 Aug 2026 20:20:00 +0900 Subject: [PATCH 02/52] gc: answer gc_isenabled before the GC singleton is stored gc_query_reentrant reaches singleton_ref, which panics when store_singleton has not run; would_collect asks this from the interpreter allocation path. Assisted-by: Claude --- majit/majit-gc/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/majit/majit-gc/src/lib.rs b/majit/majit-gc/src/lib.rs index db46ab92804..a1af82aba8a 100644 --- a/majit/majit-gc/src/lib.rs +++ b/majit/majit-gc/src/lib.rs @@ -2889,6 +2889,11 @@ pub fn gc_set_enabled(enabled: bool) { /// major-progress path returns early while it is clear, and an explicit /// `gc.collect()` passes `force_enabled` to get past it. pub fn gc_isenabled() -> bool { + // Before `store_singleton` there is no collector to suppress, and nothing + // could have disabled automatic collection yet. + if !gc_sync::is_initialized() { + return true; + } gc_sync::gc_query_reentrant(|gc| gc.isenabled()) } From 5e2c2f2593bdcffc190941be67770c8c9a90d465 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Tue, 11 Aug 2026 20:20:08 +0900 Subject: [PATCH 03/52] gc: drop the repeated summary line from wrap_raw_nodes' doc Assisted-by: Claude --- pyre/pyre-interpreter/src/module/gc/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pyre/pyre-interpreter/src/module/gc/mod.rs b/pyre/pyre-interpreter/src/module/gc/mod.rs index 32a4fc601e2..71299ba829d 100644 --- a/pyre/pyre-interpreter/src/module/gc/mod.rs +++ b/pyre/pyre-interpreter/src/module/gc/mod.rs @@ -656,7 +656,6 @@ fn pin_referents(w_obj: PyObjectRef) { /// `referents.py:35-39 wrap`: app-level objects pass through, internal nodes /// become `W_GcRef`. Results are rooted as they are made because constructing /// a later wrapper can initialize a type and allocate. -/// Wrap the raw nodes rooted at `first..last`, leaving the wrappers pinned. /// /// Returns the first shadow-stack slot of the wrapped range, which runs to the /// stack top on return. A slot range rather than a `Vec` because From 8b9b8252fa332215a2e5f221cada006743f15ecf Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Tue, 11 Aug 2026 20:20:18 +0900 Subject: [PATCH 04/52] gc: write the heap dump through an installable host write HeapDumpWriter reached the descriptor with a raw libc::write. Under --features sandbox that descriptor is the guest's, so gc._dump_rpy_heap(1) put dump bytes on the marshalling pipe and a virtualized descriptor named an unrelated host fd. The write now goes through a process-global hook that the sandbox build fills in with host_seam::ops::write; with no hook installed the native path is unchanged. HEAP_DUMP_EIO is exported so both sides name one constant, and its comment now states pyre's own reason for a fixed code rather than attributing it to inspector.py, which raises the real errno (inspector.py:212-223). Assisted-by: Claude --- majit/majit-gc/src/collector.rs | 94 ++++++++++++---------- majit/majit-gc/src/lib.rs | 14 ++++ pyre/pyre-interpreter/src/module/gc/mod.rs | 14 ++++ 3 files changed, 80 insertions(+), 42 deletions(-) diff --git a/majit/majit-gc/src/collector.rs b/majit/majit-gc/src/collector.rs index 2bd1be84ad0..f777ef18f5f 100644 --- a/majit/majit-gc/src/collector.rs +++ b/majit/majit-gc/src/collector.rs @@ -60,9 +60,9 @@ struct HeapDumpWriter { buffer: Vec, } -// POSIX EIO. `libc`'s wasm32-unknown-unknown surface exposes no errno -// constants, but inspector.py uses EIO for a short raw write on every target. -const HEAP_DUMP_EIO: i32 = 5; +// Some targets and host-seam failures provide no OS errno. Use the POSIX EIO +// value for those cases so every heap-dump failure still carries an error code. +pub const HEAP_DUMP_EIO: i32 = 5; impl HeapDumpWriter { const BUFSIZE: usize = 8192; @@ -94,48 +94,58 @@ impl HeapDumpWriter { return Ok(()); } let byte_len = self.buffer.len() * std::mem::size_of::(); - // Neither `write` nor `_write` exists here, so no call was made and - // `errno` still names some unrelated earlier one. Report the dump's own - // failure code instead of reading a stale `errno`. - #[cfg(not(any(unix, windows)))] - { - let _ = (byte_len, self.fd); - return Err(HEAP_DUMP_EIO); - } - #[cfg(any(unix, windows))] - { - #[cfg(unix)] - let written: isize = unsafe { - libc::write( - self.fd, - self.buffer.as_ptr().cast::(), - byte_len, - ) - }; - // The CRT entry point is `_write`, but `libc` exports it under the - // POSIX name with a `#[link_name = "_write"]` alias, so the Rust - // path is `libc::write` on this target as well. It takes a - // `c_uint` count and returns `c_int`, unlike the `size_t`/`ssize_t` - // unix signature above. - #[cfg(windows)] - let written: isize = unsafe { - libc::write( - self.fd, - self.buffer.as_ptr().cast::(), - byte_len as libc::c_uint, - ) as isize - }; - if written < 0 { - return Err(std::io::Error::last_os_error() - .raw_os_error() - .unwrap_or(HEAP_DUMP_EIO)); + // SAFETY: the initialized `isize` elements occupy exactly `byte_len` + // bytes and remain borrowed for the duration of the write. + let bytes = + unsafe { std::slice::from_raw_parts(self.buffer.as_ptr().cast::(), byte_len) }; + let write_result = if let Some(result) = crate::try_heap_dump_write(self.fd, bytes) { + result + } else { + // Neither `write` nor `_write` exists here, so no call was made and + // `errno` still names some unrelated earlier one. Report the dump's own + // failure code instead of reading a stale `errno`. + #[cfg(not(any(unix, windows)))] + { + Err(HEAP_DUMP_EIO) } - if written as usize != byte_len { - return Err(HEAP_DUMP_EIO); + #[cfg(any(unix, windows))] + { + #[cfg(unix)] + let written: isize = unsafe { + libc::write( + self.fd, + self.buffer.as_ptr().cast::(), + byte_len, + ) + }; + // The CRT entry point is `_write`, but `libc` exports it under the + // POSIX name with a `#[link_name = "_write"]` alias, so the Rust + // path is `libc::write` on this target as well. It takes a + // `c_uint` count and returns `c_int`, unlike the `size_t`/`ssize_t` + // unix signature above. + #[cfg(windows)] + let written: isize = unsafe { + libc::write( + self.fd, + self.buffer.as_ptr().cast::(), + byte_len as libc::c_uint, + ) as isize + }; + if written < 0 { + Err(std::io::Error::last_os_error() + .raw_os_error() + .unwrap_or(HEAP_DUMP_EIO)) + } else { + Ok(written) + } } - self.buffer.clear(); - Ok(()) + }; + let written = write_result?; + if written as usize != byte_len { + return Err(HEAP_DUMP_EIO); } + self.buffer.clear(); + Ok(()) } } diff --git a/majit/majit-gc/src/lib.rs b/majit/majit-gc/src/lib.rs index a1af82aba8a..358450b444a 100644 --- a/majit/majit-gc/src/lib.rs +++ b/majit/majit-gc/src/lib.rs @@ -1,3 +1,4 @@ +pub use collector::HEAP_DUMP_EIO; pub use gcreftracer::{GcTable, install_gc_table_walker}; /// GC traits and interfaces for the JIT. /// @@ -2461,10 +2462,12 @@ pub fn is_app_level_object(obj: GcRef) -> bool { } pub type DumpRpyHeapFn = fn(i32) -> Result; +pub type HeapDumpWriteFn = fn(i32, &[u8]) -> Result; pub type GetTypeidsTextFn = fn() -> Option>; pub type GetTypeidsListFn = fn() -> Option>; global_hook!(static ACTIVE_DUMP_RPY_HEAP: DumpRpyHeapFn); +global_hook!(static HEAP_DUMP_WRITE: HeapDumpWriteFn); global_hook!(static ACTIVE_GET_TYPEIDS_TEXT: GetTypeidsTextFn); global_hook!(static ACTIVE_GET_TYPEIDS_LIST: GetTypeidsListFn); @@ -2472,6 +2475,17 @@ pub fn set_active_dump_rpy_heap(hook: Option) { ACTIVE_DUMP_RPY_HEAP.set(hook); } +/// Install the host write used by `inspector.py:212-223 HeapDumper.flush`. +/// Sandboxed interpreters use this to translate guest descriptors through +/// their host seam; when absent, the collector retains its native raw write. +pub fn set_heap_dump_write(hook: Option) { + HEAP_DUMP_WRITE.set(hook); +} + +pub(crate) fn try_heap_dump_write(fd: i32, bytes: &[u8]) -> Option> { + HEAP_DUMP_WRITE.get().map(|write| write(fd, bytes)) +} + pub fn set_active_get_typeids_text(hook: Option) { ACTIVE_GET_TYPEIDS_TEXT.set(hook); } diff --git a/pyre/pyre-interpreter/src/module/gc/mod.rs b/pyre/pyre-interpreter/src/module/gc/mod.rs index 71299ba829d..7b680edee39 100644 --- a/pyre/pyre-interpreter/src/module/gc/mod.rs +++ b/pyre/pyre-interpreter/src/module/gc/mod.rs @@ -981,7 +981,21 @@ fn gc_call_method( } } +#[cfg(feature = "sandbox")] +fn heap_dump_write_via_host(fd: i32, bytes: &[u8]) -> Result { + crate::host_seam::ops::write(fd, bytes) + .map(|written| written as isize) + // A non-OS seam failure still needs an errno. Use the collector's code + // for targets and failure modes that cannot supply one. + .map_err(|error| match error { + crate::host_seam::SeamError::Os(errno) => errno, + _ => majit_gc::HEAP_DUMP_EIO, + }) +} + fn dump_rpy_heap_fd(fd: i32) -> Result<(), crate::PyError> { + #[cfg(feature = "sandbox")] + majit_gc::set_heap_dump_write(Some(heap_dump_write_via_host)); match majit_gc::dump_rpy_heap(fd) { Ok(true) => Ok(()), Ok(false) => Err(crate::PyError::not_implemented( From 6eb5fddf6f288ad3ab097a12e0d16dd65675fe8d Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 02:20:28 +0900 Subject: [PATCH 05/52] gc: share space actions across execution contexts PyPy owns the action flag, user-finalizer action, and GIL release action on the object space. Pyre instead gave each execution context a separate flag, so a worker collection fired a GC hook bit that only the boot context dispatched.\n\nKeep one process-owned flag and action instance, root their managed fields once, and add a worker-thread oracle fixture that verifies the hook runs on the collecting thread. --- .../gc_hook_worker_thread.cranelift.jitstats | 15 ++ .../gc_hook_worker_thread.dynasm.jitstats | 15 ++ pyre/bench/synth/gc_hook_worker_thread.py | 33 +++ pyre/pyre-interpreter/src/eval.rs | 12 +- pyre/pyre-interpreter/src/executioncontext.rs | 189 ++++++++++++++---- pyre/pyre-interpreter/src/module/gc/hook.rs | 21 +- pyre/pyre-interpreter/src/module/gc/mod.rs | 6 +- .../src/module/signal/interp_signal.rs | 2 +- .../pyre-interpreter/src/module/thread/gil.rs | 46 ++--- .../pyre-interpreter/src/module/thread/mod.rs | 24 +-- 10 files changed, 242 insertions(+), 121 deletions(-) create mode 100644 pyre/bench/synth/gc_hook_worker_thread.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_hook_worker_thread.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_hook_worker_thread.py diff --git a/pyre/bench/synth/gc_hook_worker_thread.cranelift.jitstats b/pyre/bench/synth/gc_hook_worker_thread.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_hook_worker_thread.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_hook_worker_thread.dynasm.jitstats b/pyre/bench/synth/gc_hook_worker_thread.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_hook_worker_thread.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_hook_worker_thread.py b/pyre/bench/synth/gc_hook_worker_thread.py new file mode 100644 index 00000000000..842431dec73 --- /dev/null +++ b/pyre/bench/synth/gc_hook_worker_thread.py @@ -0,0 +1,33 @@ +# pyre-check: no-cpython +# pyre-check: skip-backends=wasm +# The wasm guest has no OS-thread implementation, while this fixture verifies +# which native mutator dispatches an object-space GC action. +import _thread +import gc + + +main_ident = _thread.get_ident() +callback_idents = [] +worker_idents = [] +done = _thread.allocate_lock() +done.acquire() + + +def on_collect(stats): + callback_idents.append(_thread.get_ident()) + + +def worker(): + worker_idents.append(_thread.get_ident()) + gc.collect() + done.release() + + +gc.hooks.on_gc_collect = on_collect +_thread.start_new_thread(worker, ()) +done.acquire() + +assert callback_idents +assert callback_idents[-1] == worker_idents[-1] +assert callback_idents[-1] != main_ident +print("gc hook ran on collecting worker") diff --git a/pyre/pyre-interpreter/src/eval.rs b/pyre/pyre-interpreter/src/eval.rs index 11401545cb9..912e6b6e4d6 100644 --- a/pyre/pyre-interpreter/src/eval.rs +++ b/pyre/pyre-interpreter/src/eval.rs @@ -953,17 +953,6 @@ pub unsafe fn walk_pyframe_roots_area( } { visitor(unsafe { &mut *(hook as *mut majit_ir::GcRef) }); } - // pending_with_disabled_del is a GC-visible list upstream - // (executioncontext.py:652); pyre's Vec lives in the boxed - // UserDelAction, so its element slots are visited here. - let action = unsafe { (*ec).user_del_action }; - if !action.is_null() - && let Some(list) = unsafe { (*action).pending_with_disabled_del.as_mut() } - { - for slot in list.iter_mut() { - visitor(unsafe { &mut *(slot as *mut PyObjectRef as *mut majit_ir::GcRef) }); - } - } }; visit_ec_slots(frame_ec); if ambient_ec != frame_ec { @@ -1177,6 +1166,7 @@ pub unsafe fn walk_pyframe_roots_area( /// faulthandler's — so it registers once for the process. fn walk_interpreter_global_roots(visitor: &mut dyn FnMut(&mut majit_ir::GcRef)) { walk_global_prebuilt_roots(visitor); + crate::executioncontext::walk_space_user_del_action_roots(visitor); crate::module::gc::hook::walk_hook_roots(visitor); crate::module::thread::walk_thread_roots(visitor); #[cfg(all(not(target_arch = "wasm32"), not(feature = "sandbox")))] diff --git a/pyre/pyre-interpreter/src/executioncontext.rs b/pyre/pyre-interpreter/src/executioncontext.rs index fe4fac2fe6f..a7391ed88d6 100644 --- a/pyre/pyre-interpreter/src/executioncontext.rs +++ b/pyre/pyre-interpreter/src/executioncontext.rs @@ -214,14 +214,52 @@ impl WRootFinalizerQueue { } fn finalizer_queue_trigger() { - let ec = crate::call::getexecutioncontext() as *mut ExecutionContext; - if ec.is_null() { + let action = space_user_del_action(); + if !action.is_null() { + unsafe { (*action).fire() }; + } +} + +// `baseobjspace.py:450` / `executioncontext.py:724`: both the action flag and +// the user-finalizer action belong to the object space, not to an individual +// execution context. Pyre does not yet expose a typed Rust `ObjSpace`, so the +// process-global runtime instance is its storage owner. ECs carry a thin +// reference to the flag, while finalizer users resolve the action here just as +// PyPy reaches `self.space.user_del_action`. +static SPACE_USER_DEL_ACTION: OnceLock = OnceLock::new(); + +fn install_space_user_del_action( + space: PyObjectRef, + actionflag: &mut (dyn ActionFlagOps + 'static), +) -> *mut UserDelAction { + *SPACE_USER_DEL_ACTION + .get_or_init(|| Box::into_raw(UserDelAction::new(space, actionflag)) as usize) + as *mut UserDelAction +} + +pub fn space_user_del_action() -> *mut UserDelAction { + SPACE_USER_DEL_ACTION.get().copied().unwrap_or(0) as *mut UserDelAction +} + +/// Trace the object-space-owned finalizer action exactly once as a non-stack +/// root. In translated PyPy this happens through the object-space graph; the +/// leaked Rust allocation is outside that graph, so its managed slots must be +/// forwarded explicitly. +pub(crate) fn walk_space_user_del_action_roots(visitor: &mut dyn FnMut(&mut majit_ir::GcRef)) { + let action = space_user_del_action(); + if action.is_null() { return; } - unsafe { - let action = (*ec).user_del_action; - if !action.is_null() { - (*action).fire(); + let action = unsafe { &mut *action }; + let mut forward = |slot: &mut PyObjectRef| { + if !slot.is_null() { + visitor(unsafe { &mut *(slot as *mut PyObjectRef as *mut majit_ir::GcRef) }); + } + }; + forward(&mut action.base.space); + if let Some(pending) = action.pending_with_disabled_del.as_mut() { + for obj in pending { + forward(obj); } } } @@ -281,10 +319,9 @@ pub struct ExecutionContext { /// `os_local.py:ExecutionContext._thread_local_objs`: weak references to /// `_thread._local` objects which own a dictionary for this EC. pub thread_local_refs: Vec, - pub actionflag: ActionFlag, - /// `space.user_del_action`, allocated after the ExecutionContext reaches - /// its stable process-lifetime address. - pub user_del_action: *mut UserDelAction, + /// Cached access to process-owned `space.actionflag`. Every EC points to + /// the same flag, matching `baseobjspace.py:450`. + pub actionflag: SpaceActionFlag, /// `pypy/objspace/std/dictmultiobject.py:60-69 /// allocate_and_init_instance(module=True)` parity — the builtins /// module's `w_dict` is a `W_ModuleDictObject` backed by @@ -307,14 +344,6 @@ pub struct ExecutionContext { /// pointer into the leaked action owned by `module::_signal` /// (`install_signal_handling`); `None` until installed. pub check_signal_action: Option<*mut dyn AsyncActionOps>, - /// `gil.py:20-23 GILThreadLocals.initialize` — the `GILReleaseAction` - /// registered on the ticker, which yields the GIL every - /// `sys.getcheckinterval()` bytecodes. There is one per execution context, - /// because the ticker it is registered on is too, so unlike the - /// process-global signal action it is owned rather than leaked: the - /// pointer is the box `module::thread::gil::shutdown` gives back. `None` - /// until installed. - pub gil_release_action: Option<*mut dyn AsyncActionOps>, /// `executioncontext.py sys_exc_operror` — the active exception for /// `sys.exc_info()` / bare `raise`, saved/restored across handler /// regions by PUSH_EXC_INFO / POP_EXCEPT. Single source of truth @@ -400,12 +429,10 @@ impl ExecutionContext { trace_all_generation: 0, profile_all_generation: 0, thread_local_refs: Vec::new(), - actionflag: ActionFlag::new(), - user_del_action: std::ptr::null_mut(), + actionflag: SpaceActionFlag::new(), builtins_module, builtin_dict_cache: std::cell::Cell::new(pyre_object::PY_NULL), check_signal_action: None, - gil_release_action: None, sys_exc_value: pyre_object::PY_NULL, coroutine_origin_tracking_depth: 0, current_gen_or_coroutine: pyre_object::PY_NULL, @@ -418,9 +445,9 @@ impl ExecutionContext { /// `OSThreadLocals.enter_thread()` / `ExecutionContext(space)` parity. /// - /// Interpreter-wide objects (the object space and builtins module) remain - /// shared, while frame, exception, tracing, profiling, generator, and - /// action state starts fresh for each OS thread. + /// Interpreter-wide objects (the object space, action flag, finalizer + /// action, and builtins module) remain shared, while frame, exception, + /// tracing, profiling, and generator state starts fresh for each OS thread. pub fn clone_for_thread(&self) -> Self { let mut ec = self.clone(); ec.topframeref = std::ptr::null_mut(); @@ -437,11 +464,7 @@ impl ExecutionContext { ec.trace_all_generation = 0; ec.profile_all_generation = 0; ec.thread_local_refs.clear(); - ec.actionflag = ActionFlag::new(); - // The periodic actions are registered on the actionflag just replaced, - // so the new thread registers its own. - ec.gil_release_action = None; - ec.user_del_action = std::ptr::null_mut(); + ec.actionflag = SpaceActionFlag::new(); // The cached Module wrapper is execution-context-owned and movable. // A new thread lazily builds its own wrapper over the shared // builtins_module, matching a fresh PyPy ExecutionContext. @@ -482,11 +505,9 @@ impl ExecutionContext { } pub fn install_user_del_action(&mut self) { - if self.user_del_action.is_null() { - let action = UserDelAction::new(self.space, &mut self.actionflag); - self.user_del_action = Box::into_raw(action); - } - crate::module::gc::hook::initialize(self.space, &mut self.actionflag); + let actionflag = self.actionflag.shared_mut(); + install_space_user_del_action(self.space, actionflag); + crate::module::gc::hook::initialize(self.space, actionflag); pyre_object::gc_hook::register_maybe_finalizer_hook(maybe_register_user_finalizer); } @@ -821,8 +842,9 @@ impl ExecutionContext { } pub fn _run_finalizers_now(&mut self) { - if !self.user_del_action.is_null() { - unsafe { (*self.user_del_action)._run_finalizers() }; + let action = space_user_del_action(); + if !action.is_null() { + unsafe { (*action)._run_finalizers() }; } } @@ -842,8 +864,9 @@ impl ExecutionContext { /// coroutine's frame. The action runs before the next opcode, after the /// attribute receiver has left the value stack. pub fn finalize_discarded_coroutine_after_frame_get(&mut self) { - if !self.user_del_action.is_null() { - unsafe { (*self.user_del_action).collect_oldgen_and_fire() }; + let action = space_user_del_action(); + if !action.is_null() { + unsafe { (*action).collect_oldgen_and_fire() }; } } @@ -1927,6 +1950,85 @@ impl ActionFlagOps for ActionFlag { } } +/// Stable reference to the process-owned `space.actionflag`. +/// +/// PyPy stores one `ActionFlag` on `ObjSpace` and every execution context +/// reaches it through `self.space.actionflag` (`executioncontext.py:163-165`). +/// Pyre's opaque `PyObjectRef` space has no typed Rust fields yet, so the +/// process runtime owns the equivalent allocation and each EC carries this +/// thin reference. The GIL serializes interpreter access just as it does for +/// PyPy's plain Python fields; the OS signal handler is the only asynchronous +/// writer and already uses the registered ticker address. +#[derive(Clone, Copy)] +pub struct SpaceActionFlag { + ptr: *mut ActionFlag, +} + +static SPACE_ACTIONFLAG: OnceLock = OnceLock::new(); + +impl Default for SpaceActionFlag { + fn default() -> Self { + Self::new() + } +} + +impl SpaceActionFlag { + pub fn new() -> Self { + let ptr = *SPACE_ACTIONFLAG + .get_or_init(|| Box::into_raw(Box::new(ActionFlag::new())) as usize) + as *mut ActionFlag; + Self { ptr } + } + + fn inner(&self) -> &ActionFlag { + // SAFETY: SPACE_ACTIONFLAG owns one leaked process-lifetime value. + // Interpreter calls are serialized by the GIL; shared signal writes + // touch only `_ticker` through its registered raw address. + unsafe { &*self.ptr } + } + + fn inner_mut(&mut self) -> &mut ActionFlag { + // SAFETY: see `inner`; callers hold the GIL while mutating the flag. + unsafe { &mut *self.ptr } + } + + /// The stable object-space allocation used when an action caches its + /// `space.actionflag` back-reference. Returning the shared allocation, + /// rather than this EC's thin wrapper, keeps the pointer valid even if an + /// embedding drops the EC that first registered the action. + pub fn shared_mut(&mut self) -> &'static mut ActionFlag { + // SAFETY: SPACE_ACTIONFLAG owns one leaked process-lifetime value. + // Registration and action dispatch are serialized by the GIL. + unsafe { &mut *self.ptr } + } + + pub fn ticker_addr(&mut self) -> *mut isize { + self.inner_mut().ticker_addr() + } +} + +impl ActionFlagOps for SpaceActionFlag { + fn abstract_flag(&self) -> &AbstractActionFlag { + self.inner().abstract_flag() + } + + fn abstract_flag_mut(&mut self) -> &mut AbstractActionFlag { + self.inner_mut().abstract_flag_mut() + } + + fn get_ticker(&self) -> isize { + self.inner().get_ticker() + } + + fn reset_ticker(&mut self, value: isize) { + self.inner_mut().reset_ticker(value); + } + + fn decrement_ticker(&mut self, by: isize) -> isize { + self.inner_mut().decrement_ticker(by) + } +} + pub struct AsyncAction { pub space: PyObjectRef, _action_index: isize, @@ -1938,12 +2040,11 @@ pub struct AsyncAction { /// uses `self.space.actionflag` — a constant lookup once the action /// is constructed because PyPy's `space.actionflag` is set once at /// `pypy/interpreter/baseobjspace.py:447` and never replaced. - /// Pyre keeps the actionflag on `ExecutionContext` rather than on - /// `space`, so we cache the back-reference at registration time - /// (`AsyncAction::new` / `UserDelAction::new` / - /// `AsyncActionOps::register_periodic_action`). The pointer is - /// stable for the process lifetime because pyrex owns the EC for - /// the entire run. `fire()` dereferences this slot directly, + /// Pyre's EC stores a thin reference to the process-owned flag, so we cache + /// the registering reference here (`AsyncAction::new` / + /// `UserDelAction::new` / `AsyncActionOps::register_periodic_action`). + /// The process-owned flag outlives every action. `fire()` dereferences + /// this slot directly, /// matching PyPy's `self.space.actionflag.fire(self)` 1:1 without /// the TLS detour. `null` means the action has not been registered /// yet — calling `fire` in that state is a programmer error diff --git a/pyre/pyre-interpreter/src/module/gc/hook.rs b/pyre/pyre-interpreter/src/module/gc/hook.rs index 2d06b126338..47a8bc6e174 100644 --- a/pyre/pyre-interpreter/src/module/gc/hook.rs +++ b/pyre/pyre-interpreter/src/module/gc/hook.rs @@ -413,22 +413,11 @@ fn app_hooks_ptr() -> Option<*mut W_AppLevelHooks> { .then_some(obj as *mut W_AppLevelHooks) } -/// Create the space-owned singleton and bind its three actions to an -/// actionflag. The main ExecutionContext calls this during bootstrap, before -/// worker ECs can import `gc`, so the flag it passes outlives every later EC. -/// -/// Reach, however, is not lifetime, and this is where pyre still departs from -/// PyPy. There `actionflag` belongs to the `space`, so every execution context -/// dispatches the same set; here it is a field on each `ExecutionContext` -/// (`executioncontext.rs` `pub actionflag: ActionFlag`), and an `AsyncAction` -/// binds to exactly one flag when `register_nonperiodic_action` hands it an -/// `_action_index` for that flag's bitmask. `get_or_init` therefore leaves the -/// hooks registered with the bootstrapping EC alone: a worker thread that runs -/// a collection fires a bit its own dispatch loop never reads, so its callback -/// waits for the bootstrapping thread to reach an opcode. Closing this means -/// moving `ActionFlag` onto the space the way upstream has it, not -/// re-registering per EC — the second flag would overwrite the index the first -/// one handed out. +/// Create the space-owned singleton and bind its three actions to the shared +/// `space.actionflag`. The main ExecutionContext calls this during bootstrap; +/// worker ECs carry [`crate::executioncontext::SpaceActionFlag`] references to +/// that same flag, so a collection performed by a worker fires and dispatches +/// the same action indexes there, matching PyPy's process-owned object space. pub fn initialize( space: PyObjectRef, actionflag: &mut (dyn ActionFlagOps + 'static), diff --git a/pyre/pyre-interpreter/src/module/gc/mod.rs b/pyre/pyre-interpreter/src/module/gc/mod.rs index 7b680edee39..1a6db9efab5 100644 --- a/pyre/pyre-interpreter/src/module/gc/mod.rs +++ b/pyre/pyre-interpreter/src/module/gc/mod.rs @@ -704,11 +704,7 @@ fn list_from_roots(first: usize) -> PyObjectRef { } fn user_del_action() -> Option<&'static mut crate::executioncontext::UserDelAction> { - let ec = crate::call::getexecutioncontext() as *mut crate::PyExecutionContext; - if ec.is_null() { - return None; - } - let action = unsafe { (*ec).user_del_action }; + let action = crate::executioncontext::space_user_del_action(); if action.is_null() { None } else { diff --git a/pyre/pyre-interpreter/src/module/signal/interp_signal.rs b/pyre/pyre-interpreter/src/module/signal/interp_signal.rs index 6e8c885d427..02832edb03f 100644 --- a/pyre/pyre-interpreter/src/module/signal/interp_signal.rs +++ b/pyre/pyre-interpreter/src/module/signal/interp_signal.rs @@ -451,7 +451,7 @@ pub fn install_signal_handling(ec: &mut ExecutionContext) { // into it for the whole run), so it is leaked deliberately. let action: &'static mut CheckSignalAction = Box::leak(CheckSignalAction::new(ec.space)); let async_ptr: *mut dyn AsyncActionOps = &mut *action; - action.register_periodic_action(&mut ec.actionflag, false); + action.register_periodic_action(ec.actionflag.shared_mut(), false); ec.check_signal_action = Some(async_ptr); // Hand the ticker cell address to the OS handler so it can force the diff --git a/pyre/pyre-interpreter/src/module/thread/gil.rs b/pyre/pyre-interpreter/src/module/thread/gil.rs index 0591b5d5c28..02c7b7fdf1b 100644 --- a/pyre/pyre-interpreter/src/module/thread/gil.rs +++ b/pyre/pyre-interpreter/src/module/thread/gil.rs @@ -7,6 +7,7 @@ //! `GILReleaseAction` is that hand-off — an action registered on the ticker //! which yields the GIL every `sys.getcheckinterval()` bytecodes. +use std::sync::OnceLock; use std::sync::atomic::{AtomicBool, Ordering}; use crate::executioncontext::{ @@ -52,41 +53,36 @@ impl AsyncActionOps for GilReleaseAction { impl PeriodicAsyncActionOps for GilReleaseAction {} +static GIL_RELEASE_ACTION: OnceLock = OnceLock::new(); + /// gil.py:20-23 `GILThreadLocals.initialize` — "add the GIL-releasing callback /// as an action on the space". /// /// `use_bytecode_counter=True` is what puts it at the end of the periodic list /// (executioncontext.py:503-504: "hack to put the release-the-GIL one at the /// end of the list"), behind the signal check. Idempotent; the actionflag -/// holds the action's heap address, so ownership stays with the execution -/// context until [`shutdown`] gives it back. +/// holds the action's heap address, so the process-owned flag retains it for +/// the runtime lifetime. pub fn initialize(ec: &mut ExecutionContext) { - if ec.gil_release_action.is_some() { - return; - } - let action: &'static mut GilReleaseAction = Box::leak(GilReleaseAction::new(ec.space)); - let async_ptr: *mut dyn AsyncActionOps = &mut *action; - action.register_periodic_action(&mut ec.actionflag, true); - ec.gil_release_action = Some(async_ptr); + GIL_RELEASE_ACTION.get_or_init(|| { + let action: &'static mut GilReleaseAction = Box::leak(GilReleaseAction::new(ec.space)); + action.register_periodic_action(ec.actionflag.shared_mut(), true); + action as *mut GilReleaseAction as usize + }); } -/// Reclaim what [`initialize`] registered. -/// -/// Upstream has nothing to reclaim: one `GILReleaseAction` is registered on -/// `space.actionflag` for the process. pyre gives each execution context its -/// own ticker, so each one also allocates its own action, and a thread which -/// leaves without giving it back leaks it. -/// -/// The caller's execution context, and with it the actionflag that still names -/// this action, is dropped immediately afterwards without running any Python -/// in between. -pub fn shutdown(ec: &mut ExecutionContext) { - let Some(action) = ec.gil_release_action.take() else { +/// Trace the process-owned periodic action's object-space reference. The +/// action is a translated object-space child in PyPy; pyre's leaked Rust box +/// needs the corresponding explicit non-stack root. +pub(super) fn walk_action_roots(visitor: &mut dyn FnMut(&mut majit_ir::GcRef)) { + let Some(&addr) = GIL_RELEASE_ACTION.get() else { return; }; - // SAFETY: the pointer is the one `initialize` leaked out of a `Box`, and - // this is the only place that takes it back. - drop(unsafe { Box::from_raw(action) }); + let action = unsafe { &mut *(addr as *mut GilReleaseAction) }; + let slot = &mut action.base.base.space; + if !slot.is_null() { + visitor(unsafe { &mut *(slot as *mut PyObjectRef as *mut majit_ir::GcRef) }); + } } /// gil.py:17-18 `GILThreadLocals.gil_ready`, quasi-immutable and "changed (to @@ -111,8 +107,6 @@ pub fn setup_threads(ec: &mut ExecutionContext) -> bool { majit_gc::rgil::allocate(); GIL_READY.store(true, Ordering::Release); } - // Registering the action is per-execution-context, unlike upstream's - // once-per-space `initialize`, because the ticker it hangs on is too. initialize(ec); first } diff --git a/pyre/pyre-interpreter/src/module/thread/mod.rs b/pyre/pyre-interpreter/src/module/thread/mod.rs index 0b662e76580..72f3a88caf8 100644 --- a/pyre/pyre-interpreter/src/module/thread/mod.rs +++ b/pyre/pyre-interpreter/src/module/thread/mod.rs @@ -197,15 +197,6 @@ pub(crate) fn walk_thread_roots(visitor: &mut dyn FnMut(&mut majit_ir::GcRef)) { forward(&mut frame); ec.topframeref = frame as *mut crate::PyFrame; } - if !ec.user_del_action.is_null() { - let action = unsafe { &mut *ec.user_del_action }; - forward(&mut action.base.space); - if let Some(pending) = action.pending_with_disabled_del.as_mut() { - for obj in pending { - forward(obj); - } - } - } // `builtins_module` / `builtin_dict_cache` / `thread_local_refs`. // `clone_for_thread` copies the builtins reference into the child // EC, so each copy is its own slot: forwarding only the parent's @@ -214,6 +205,7 @@ pub(crate) fn walk_thread_roots(visitor: &mut dyn FnMut(&mut majit_ir::GcRef)) { ec.walk_builtin_roots(visitor); } } + gil::walk_action_roots(visitor); let mut forwarded = Vec::new(); for handle in SHUTDOWN_HANDLES.lock().iter_mut() { let old = *handle; @@ -1408,9 +1400,6 @@ fn thread_is_stopping(ec: &mut crate::PyExecutionContext) { local.thread_is_stopping(ident); } } - // Last: nothing above runs bytecode, so nothing can reach the ticker this - // action is registered on after it is gone. - gil::shutdown(ec); } /// The calling thread's identity. @@ -1639,13 +1628,12 @@ fn spawn_thread( }); let ec_ptr = &*ec as *const crate::PyExecutionContext; crate::call::set_last_exec_ctx(ec_ptr); - // `install_user_del_action` can allocate. Publish the fresh EC - // first, matching OSThreadLocals.enter_thread() installing the - // ExecutionContext before thread bootstrap invokes Python code. + // Publish the fresh EC first, matching + // OSThreadLocals.enter_thread() installing the ExecutionContext + // before thread bootstrap invokes Python code. ec.install_user_del_action(); - // Each mutator owns its ticker, so the GIL-releasing action has to - // be registered on this thread's own actionflag; without it a - // worker would hold the GIL until its next external call. + // The space-owned GIL action is already registered on the shared + // actionflag; this is an idempotent bootstrap guard. gil::initialize(&mut ec); let ident = current_ident(); if has_handle { From 96f65d7be13bf90f403814664e8138a42f6d8cb1 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 02:51:11 +0900 Subject: [PATCH 06/52] gc: collect JSON encoder strings --- .../gc_json_string_collectable.cranelift.jitstats | 15 +++++++++++++++ .../gc_json_string_collectable.dynasm.jitstats | 15 +++++++++++++++ pyre/bench/synth/gc_json_string_collectable.py | 14 ++++++++++++++ .../gc_json_string_collectable.wasm.jitstats | 15 +++++++++++++++ pyre/pyre-interpreter/src/module/_json/mod.rs | 6 +++--- 5 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 pyre/bench/synth/gc_json_string_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_json_string_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_json_string_collectable.py create mode 100644 pyre/bench/synth/gc_json_string_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_json_string_collectable.cranelift.jitstats b/pyre/bench/synth/gc_json_string_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_json_string_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_json_string_collectable.dynasm.jitstats b/pyre/bench/synth/gc_json_string_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_json_string_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_json_string_collectable.py b/pyre/bench/synth/gc_json_string_collectable.py new file mode 100644 index 00000000000..9ccecf030b2 --- /dev/null +++ b/pyre/bench/synth/gc_json_string_collectable.py @@ -0,0 +1,14 @@ +# pyre-check: no-cpython + +import gc +import json + + +# PyPy's W_UnicodeObject returned by the JSON encoder is an ordinary GC +# object. The input is assembled at runtime so neither side can satisfy the +# identity check with a translated string constant. +source = "gc-json-probe-" + ("x" * 37) +encoded = json.encoder.encode_basestring(source) + +assert any(obj is encoded for obj in gc.get_objects()) +print("json encoder result is collectable") diff --git a/pyre/bench/synth/gc_json_string_collectable.wasm.jitstats b/pyre/bench/synth/gc_json_string_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_json_string_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/module/_json/mod.rs b/pyre/pyre-interpreter/src/module/_json/mod.rs index e2319ae62a1..a13fd03cc3a 100644 --- a/pyre/pyre-interpreter/src/module/_json/mod.rs +++ b/pyre/pyre-interpreter/src/module/_json/mod.rs @@ -98,9 +98,9 @@ fn json_decode_error(msg: String, doc: PyObjectRef, pos: usize) -> PyError { fn encode_basestring_impl(obj: PyObjectRef, ascii_only: bool) -> PyResult { let value = require_string(obj)?; - Ok(pyre_object::w_str_from_wtf8(machinery::encode_string( - value, ascii_only, - ))) + Ok(pyre_object::w_str_from_wtf8_managed( + machinery::encode_string(value, ascii_only), + )) } fn scanstring_impl(doc: PyObjectRef, end: i64, strict_obj: PyObjectRef) -> PyResult { From 0b0d65adcfa9e4322ee2367353cf5101ff3a90a6 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 03:12:49 +0900 Subject: [PATCH 07/52] gc: collect JSON decoder strings --- pyre/bench/synth/gc_json_string_collectable.py | 9 +++++++-- pyre/pyre-interpreter/src/module/_json/mod.rs | 15 +++++++++++---- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/pyre/bench/synth/gc_json_string_collectable.py b/pyre/bench/synth/gc_json_string_collectable.py index 9ccecf030b2..117ff6b9dc5 100644 --- a/pyre/bench/synth/gc_json_string_collectable.py +++ b/pyre/bench/synth/gc_json_string_collectable.py @@ -9,6 +9,11 @@ # identity check with a translated string constant. source = "gc-json-probe-" + ("x" * 37) encoded = json.encoder.encode_basestring(source) - assert any(obj is encoded for obj in gc.get_objects()) -print("json encoder result is collectable") + +decoded, end = json.decoder.scanstring('"' + source + '"', 1) +assert decoded == source +assert end == len(source) + 2 +assert any(obj is decoded for obj in gc.get_objects()) + +print("json codec strings are collectable") diff --git a/pyre/pyre-interpreter/src/module/_json/mod.rs b/pyre/pyre-interpreter/src/module/_json/mod.rs index a13fd03cc3a..fe940a53add 100644 --- a/pyre/pyre-interpreter/src/module/_json/mod.rs +++ b/pyre/pyre-interpreter/src/module/_json/mod.rs @@ -115,10 +115,17 @@ fn scanstring_impl(doc: PyObjectRef, end: i64, strict_obj: PyObjectRef) -> PyRes json_decode_error("Unterminated string starting at".to_owned(), doc, start) })?; match machinery::scan_string(rest, start, strict) { - Ok((decoded, next, _)) => Ok(pyre_object::w_tuple_new(vec![ - pyre_object::w_str_from_wtf8(decoded), - pyre_object::w_int_new(next as i64), - ])), + Ok((decoded, next, _)) => { + let _roots = gc_roots::push_roots(); + let decoded_slot = gc_roots::shadow_stack_len(); + gc_roots::pin_root(pyre_object::w_str_from_wtf8_managed(decoded)); + let next_slot = gc_roots::shadow_stack_len(); + gc_roots::pin_root(pyre_object::w_int_new(next as i64)); + Ok(pyre_object::w_tuple_new(vec![ + gc_roots::shadow_stack_get(decoded_slot), + gc_roots::shadow_stack_get(next_slot), + ])) + } Err(err) => Err(json_decode_error(err.msg, doc, err.pos)), } } From b67648303dd3ab774f89536c2b75fb36fe1b4fde Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 03:28:50 +0900 Subject: [PATCH 08/52] gc: collect JSON error notes --- pyre/bench/synth/gc_json_string_collectable.py | 16 +++++++++++++++- pyre/pyre-interpreter/src/module/_json/mod.rs | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pyre/bench/synth/gc_json_string_collectable.py b/pyre/bench/synth/gc_json_string_collectable.py index 117ff6b9dc5..7cd80599e4f 100644 --- a/pyre/bench/synth/gc_json_string_collectable.py +++ b/pyre/bench/synth/gc_json_string_collectable.py @@ -16,4 +16,18 @@ assert end == len(source) + 2 assert any(obj is decoded for obj in gc.get_objects()) -print("json codec strings are collectable") +try: + json.dumps([object()]) +except TypeError as exc: + notes = getattr(exc, "__notes__", None) + if not notes: + # The installed PyPy is older than json's 3.14 context-note change; + # its ordinary runtime note still provides the GC ownership oracle. + exc.add_note("gc-json-note-" + ("x" * 37)) + note = exc.__notes__[-1] +else: + raise AssertionError("json.dumps accepted an unsupported object") + +assert any(obj is note for obj in gc.get_objects()) + +print("json runtime strings are collectable") diff --git a/pyre/pyre-interpreter/src/module/_json/mod.rs b/pyre/pyre-interpreter/src/module/_json/mod.rs index fe940a53add..1c24aede5fe 100644 --- a/pyre/pyre-interpreter/src/module/_json/mod.rs +++ b/pyre/pyre-interpreter/src/module/_json/mod.rs @@ -825,7 +825,7 @@ fn add_json_note(mut err: PyError, note: impl Into) -> gc_roots::pin_root(exc); // The note quotes a key the caller supplied, which may hold a lone // surrogate, so it is carried as the WTF-8 it is. - let note = pyre_object::w_str_from_wtf8(note.into()); + let note = pyre_object::w_str_from_wtf8_managed(note.into()); let note_slot = gc_roots::shadow_stack_len(); gc_roots::pin_root(note); if let Ok(add_note) = From 7978c7c099be1d343f18b306d541916415847d59 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 03:49:52 +0900 Subject: [PATCH 09/52] gc: collect JSON encoder chunks --- pyre/bench/synth/gc_json_string_collectable.py | 10 ++++++++++ pyre/pyre-interpreter/src/module/_json/mod.rs | 7 +++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/pyre/bench/synth/gc_json_string_collectable.py b/pyre/bench/synth/gc_json_string_collectable.py index 7cd80599e4f..7fc7a41eb9e 100644 --- a/pyre/bench/synth/gc_json_string_collectable.py +++ b/pyre/bench/synth/gc_json_string_collectable.py @@ -30,4 +30,14 @@ assert any(obj is note for obj in gc.get_objects()) +chunks = list(json.JSONEncoder().iterencode({"runtime": source}, _one_shot=True)) +assert chunks +chunk = chunks[0] +if json.encoder.c_make_encoder is None: + # This PyPy build has no _json accelerator, so its one-shot call still + # yields structural pure-Python chunks. Use an ordinary runtime string as + # the ownership oracle; Pyre must keep checking the accelerator's chunk. + chunk = "gc-json-chunk-" + ("x" * 37) +assert any(obj is chunk for obj in gc.get_objects()) + print("json runtime strings are collectable") diff --git a/pyre/pyre-interpreter/src/module/_json/mod.rs b/pyre/pyre-interpreter/src/module/_json/mod.rs index 1c24aede5fe..f5da343b24f 100644 --- a/pyre/pyre-interpreter/src/module/_json/mod.rs +++ b/pyre/pyre-interpreter/src/module/_json/mod.rs @@ -1178,8 +1178,11 @@ fn encode_dict( fn encoder_call_impl(self_obj: PyObjectRef, obj: PyObjectRef, level: i64) -> PyResult { let encoded = encode_value(self_obj, obj, level.max(0))?; - Ok(pyre_object::w_list_new(vec![pyre_object::w_str_from_wtf8( - encoded, + let _roots = gc_roots::push_roots(); + let encoded_slot = gc_roots::shadow_stack_len(); + gc_roots::pin_root(pyre_object::w_str_from_wtf8_managed(encoded)); + Ok(pyre_object::w_list_new(vec![gc_roots::shadow_stack_get( + encoded_slot, )])) } From 59aeffd1d64f53a0e9c8d5be4946f4fbac346c4e Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 04:06:54 +0900 Subject: [PATCH 10/52] gc: collect JSON float keys --- .../bench/synth/gc_json_string_collectable.py | 24 +++++++++++++++++++ pyre/pyre-interpreter/src/module/_json/mod.rs | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/pyre/bench/synth/gc_json_string_collectable.py b/pyre/bench/synth/gc_json_string_collectable.py index 7fc7a41eb9e..4a72398b3ae 100644 --- a/pyre/bench/synth/gc_json_string_collectable.py +++ b/pyre/bench/synth/gc_json_string_collectable.py @@ -40,4 +40,28 @@ chunk = "gc-json-chunk-" + ("x" * 37) assert any(obj is chunk for obj in gc.get_objects()) +float_key = 1.2345678901234567e123 +float_key_managed = [] + + +def observe_key(key): + if key.startswith("1.234567890123456") and key.endswith("e+123"): + float_key_managed.append(any(obj is key for obj in gc.get_objects())) + return json.encoder.encode_basestring_ascii(key) + + +if json.encoder.c_make_encoder is None: + # Keep the ownership assertion meaningful on a PyPy without its optional + # accelerator: float.__repr__ returns the same kind of managed text that + # _pypyjson._coerce_dict_key creates with space.newtext(). + key_text = repr(float_key) + float_key_managed.append(any(obj is key_text for obj in gc.get_objects())) +else: + encoder = json.encoder.c_make_encoder( + {}, lambda obj: None, observe_key, None, ": ", ", ", False, False, True + ) + assert encoder({float_key: None}, 0) == ['{"1.2345678901234567e+123": null}'] + +assert float_key_managed == [True] + print("json runtime strings are collectable") diff --git a/pyre/pyre-interpreter/src/module/_json/mod.rs b/pyre/pyre-interpreter/src/module/_json/mod.rs index f5da343b24f..4556d2dbc04 100644 --- a/pyre/pyre-interpreter/src/module/_json/mod.rs +++ b/pyre/pyre-interpreter/src/module/_json/mod.rs @@ -1065,7 +1065,7 @@ fn coerce_key(self_obj: PyObjectRef, key: PyObjectRef) -> Result Date: Wed, 12 Aug 2026 04:22:59 +0900 Subject: [PATCH 11/52] gc: collect explicit GenericAlias reprs --- ...ic_alias_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ ...neric_alias_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ .../synth/gc_generic_alias_repr_collectable.py | 17 +++++++++++++++++ ...generic_alias_repr_collectable.wasm.jitstats | 15 +++++++++++++++ .../pyre-interpreter/src/_pypy_generic_alias.rs | 4 +++- 5 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_generic_alias_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_generic_alias_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_generic_alias_repr_collectable.py create mode 100644 pyre/bench/synth/gc_generic_alias_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_generic_alias_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_generic_alias_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_generic_alias_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_generic_alias_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_generic_alias_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_generic_alias_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_generic_alias_repr_collectable.py b/pyre/bench/synth/gc_generic_alias_repr_collectable.py new file mode 100644 index 00000000000..b51a55474f5 --- /dev/null +++ b/pyre/bench/synth/gc_generic_alias_repr_collectable.py @@ -0,0 +1,17 @@ +# pyre-check: no-cpython + +import gc +import types + + +# Exercise the explicit descriptor path. repr(alias) uses the interpreter's +# generic display helper, while GenericAlias.__repr__(alias) calls ga_repr. +name = "RuntimeAlias" + ("X" * 19) +runtime_type = type(name, (), {}) +alias = list[runtime_type] +rendered = types.GenericAlias.__repr__(alias) + +assert rendered == "list[__main__.RuntimeAliasXXXXXXXXXXXXXXXXXXX]" +assert any(obj is rendered for obj in gc.get_objects()) + +print("generic alias repr is collectable") diff --git a/pyre/bench/synth/gc_generic_alias_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_generic_alias_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_generic_alias_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/_pypy_generic_alias.rs b/pyre/pyre-interpreter/src/_pypy_generic_alias.rs index f8207656d32..055327057e1 100644 --- a/pyre/pyre-interpreter/src/_pypy_generic_alias.rs +++ b/pyre/pyre-interpreter/src/_pypy_generic_alias.rs @@ -215,7 +215,9 @@ fn self_alias(args: &[PyObjectRef]) -> Result { /// `GenericAlias.__repr__` (`_pypy_generic_alias.py:57`). fn ga_repr(args: &[PyObjectRef]) -> crate::PyResult { let self_ = self_alias(args)?; - Ok(pyre_object::w_str_from_wtf8(unsafe { repr(self_)? })) + Ok(pyre_object::w_str_from_wtf8_managed(unsafe { + repr(self_)? + })) } /// `GenericAlias.__hash__` (`_pypy_generic_alias.py:82`). From 8b9ca390817f015a7786a9461b4ac2b83815e392 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 04:39:09 +0900 Subject: [PATCH 12/52] gc: collect ContextVar reprs --- ...contextvar_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ ...gc_contextvar_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ .../bench/synth/gc_contextvar_repr_collectable.py | 14 ++++++++++++++ .../gc_contextvar_repr_collectable.wasm.jitstats | 15 +++++++++++++++ .../src/module/_contextvars/mod.rs | 6 +++--- 5 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 pyre/bench/synth/gc_contextvar_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_contextvar_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_contextvar_repr_collectable.py create mode 100644 pyre/bench/synth/gc_contextvar_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_contextvar_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_contextvar_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_contextvar_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_contextvar_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_contextvar_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_contextvar_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_contextvar_repr_collectable.py b/pyre/bench/synth/gc_contextvar_repr_collectable.py new file mode 100644 index 00000000000..95e34fae468 --- /dev/null +++ b/pyre/bench/synth/gc_contextvar_repr_collectable.py @@ -0,0 +1,14 @@ +# pyre-check: no-cpython + +import contextvars +import gc + + +name = "runtime-context-" + ("x" * 29) +variable = contextvars.ContextVar(name) +rendered = repr(variable) + +assert "runtime-context-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" in rendered +assert any(obj is rendered for obj in gc.get_objects()) + +print("ContextVar repr is collectable") diff --git a/pyre/bench/synth/gc_contextvar_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_contextvar_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_contextvar_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/module/_contextvars/mod.rs b/pyre/pyre-interpreter/src/module/_contextvars/mod.rs index ae1ea26f182..e8a75a58326 100644 --- a/pyre/pyre-interpreter/src/module/_contextvars/mod.rs +++ b/pyre/pyre-interpreter/src/module/_contextvars/mod.rs @@ -249,9 +249,9 @@ fn context_var_repr_string(obj: PyObjectRef) -> Result Result { - Ok(pyre_object::w_str_from_wtf8(context_var_repr_string( - args[0], - )?)) + Ok(pyre_object::w_str_from_wtf8_managed( + context_var_repr_string(args[0])?, + )) } fn token_type() -> PyObjectRef { From ffbccee8dcfffb6ee3b96b43fd2d4789555d9cae Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 04:54:56 +0900 Subject: [PATCH 13/52] gc: collect ContextVar token reprs --- pyre/bench/synth/gc_contextvar_repr_collectable.py | 8 +++++++- pyre/pyre-interpreter/src/module/_contextvars/mod.rs | 4 +++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/pyre/bench/synth/gc_contextvar_repr_collectable.py b/pyre/bench/synth/gc_contextvar_repr_collectable.py index 95e34fae468..4e052da719c 100644 --- a/pyre/bench/synth/gc_contextvar_repr_collectable.py +++ b/pyre/bench/synth/gc_contextvar_repr_collectable.py @@ -11,4 +11,10 @@ assert "runtime-context-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" in rendered assert any(obj is rendered for obj in gc.get_objects()) -print("ContextVar repr is collectable") +token = variable.set(object()) +token_rendered = repr(token) + +assert "runtime-context-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" in token_rendered +assert any(obj is token_rendered for obj in gc.get_objects()) + +print("contextvars reprs are collectable") diff --git a/pyre/pyre-interpreter/src/module/_contextvars/mod.rs b/pyre/pyre-interpreter/src/module/_contextvars/mod.rs index e8a75a58326..91c82b875f8 100644 --- a/pyre/pyre-interpreter/src/module/_contextvars/mod.rs +++ b/pyre/pyre-interpreter/src/module/_contextvars/mod.rs @@ -384,7 +384,9 @@ fn token_repr_string(token: PyObjectRef) -> Result Result { - Ok(pyre_object::w_str_from_wtf8(token_repr_string(args[0])?)) + Ok(pyre_object::w_str_from_wtf8_managed(token_repr_string( + args[0], + )?)) } fn token_enter(args: &[PyObjectRef]) -> Result { From b390e6eb8405d5798e4509e8fcf8137562ce27f2 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 05:14:31 +0900 Subject: [PATCH 14/52] gc: collect structseq reprs --- ..._structseq_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ .../gc_structseq_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ pyre/bench/synth/gc_structseq_repr_collectable.py | 12 ++++++++++++ .../gc_structseq_repr_collectable.wasm.jitstats | 15 +++++++++++++++ pyre/pyre-interpreter/src/_structseq.rs | 2 +- 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_structseq_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_structseq_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_structseq_repr_collectable.py create mode 100644 pyre/bench/synth/gc_structseq_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_structseq_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_structseq_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_structseq_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_structseq_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_structseq_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_structseq_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_structseq_repr_collectable.py b/pyre/bench/synth/gc_structseq_repr_collectable.py new file mode 100644 index 00000000000..cc68dad02c1 --- /dev/null +++ b/pyre/bench/synth/gc_structseq_repr_collectable.py @@ -0,0 +1,12 @@ +# pyre-check: no-cpython + +import gc +import sys + + +rendered = repr(sys.version_info) + +assert rendered.startswith("sys.version_info(major=3, minor=") +assert any(obj is rendered for obj in gc.get_objects()) + +print("structseq repr is collectable") diff --git a/pyre/bench/synth/gc_structseq_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_structseq_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_structseq_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/_structseq.rs b/pyre/pyre-interpreter/src/_structseq.rs index f82a998eaad..0e32c780707 100644 --- a/pyre/pyre-interpreter/src/_structseq.rs +++ b/pyre/pyre-interpreter/src/_structseq.rs @@ -172,7 +172,7 @@ fn structseq_repr(args: &[PyObjectRef]) -> Result { out.push_wtf8(&unsafe { crate::py_repr_wtf8(item)? }); } out.push_str(")"); - Ok(pyre_object::w_str_from_wtf8(out)) + Ok(pyre_object::w_str_from_wtf8_managed(out)) } /// `lib_pypy/_structseq.py structseq_reduce` — `return type(self), From f81d30fa475b943faf576710e5e9c26f896a7190 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 05:30:09 +0900 Subject: [PATCH 15/52] gc: collect array unicode strings --- ...array_tounicode_collectable.cranelift.jitstats | 15 +++++++++++++++ ...gc_array_tounicode_collectable.dynasm.jitstats | 15 +++++++++++++++ .../bench/synth/gc_array_tounicode_collectable.py | 12 ++++++++++++ .../gc_array_tounicode_collectable.wasm.jitstats | 15 +++++++++++++++ pyre/pyre-interpreter/src/module/array/mod.rs | 2 +- 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_array_tounicode_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_array_tounicode_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_array_tounicode_collectable.py create mode 100644 pyre/bench/synth/gc_array_tounicode_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_array_tounicode_collectable.cranelift.jitstats b/pyre/bench/synth/gc_array_tounicode_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_array_tounicode_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_array_tounicode_collectable.dynasm.jitstats b/pyre/bench/synth/gc_array_tounicode_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_array_tounicode_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_array_tounicode_collectable.py b/pyre/bench/synth/gc_array_tounicode_collectable.py new file mode 100644 index 00000000000..495ed85d216 --- /dev/null +++ b/pyre/bench/synth/gc_array_tounicode_collectable.py @@ -0,0 +1,12 @@ +# pyre-check: no-cpython + +import array +import gc + + +rendered = array.array("u", "abc").tounicode() + +assert rendered == "abc" +assert any(obj is rendered for obj in gc.get_objects()) + +print("array tounicode is collectable") diff --git a/pyre/bench/synth/gc_array_tounicode_collectable.wasm.jitstats b/pyre/bench/synth/gc_array_tounicode_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_array_tounicode_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/module/array/mod.rs b/pyre/pyre-interpreter/src/module/array/mod.rs index 0cbd212f195..a9c05a4dda3 100644 --- a/pyre/pyre-interpreter/src/module/array/mod.rs +++ b/pyre/pyre-interpreter/src/module/array/mod.rs @@ -864,7 +864,7 @@ fn array_tounicode_method(args: &[PyObjectRef]) -> PyResult { .ok_or_else(|| PyError::value_error("character out of range"))?; wb.push(point); } - Ok(pyre_object::unicodeobject::w_str_from_wtf8(wb)) + Ok(pyre_object::unicodeobject::w_str_from_wtf8_managed(wb)) } fn array_fromunicode_method(args: &[PyObjectRef]) -> PyResult { From 842a4d589e135216f1762b7b0ad06635a10e59d5 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 05:45:23 +0900 Subject: [PATCH 16/52] gc: collect explicit array reprs --- .../gc_array_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ .../gc_array_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ pyre/bench/synth/gc_array_repr_collectable.py | 15 +++++++++++++++ .../synth/gc_array_repr_collectable.wasm.jitstats | 15 +++++++++++++++ pyre/pyre-interpreter/src/module/array/mod.rs | 4 +++- 5 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_array_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_array_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_array_repr_collectable.py create mode 100644 pyre/bench/synth/gc_array_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_array_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_array_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_array_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_array_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_array_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_array_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_array_repr_collectable.py b/pyre/bench/synth/gc_array_repr_collectable.py new file mode 100644 index 00000000000..788a6556469 --- /dev/null +++ b/pyre/bench/synth/gc_array_repr_collectable.py @@ -0,0 +1,15 @@ +# pyre-check: no-cpython + +import array +import gc + + +integer_rendered = array.array.__repr__(array.array("i", [1, 2, 3])) +unicode_rendered = array.array.__repr__(array.array("u", "abc")) + +assert integer_rendered == "array('i', [1, 2, 3])" +assert unicode_rendered == "array('u', 'abc')" +assert any(obj is integer_rendered for obj in gc.get_objects()) +assert any(obj is unicode_rendered for obj in gc.get_objects()) + +print("array reprs are collectable") diff --git a/pyre/bench/synth/gc_array_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_array_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_array_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/module/array/mod.rs b/pyre/pyre-interpreter/src/module/array/mod.rs index a9c05a4dda3..9c3333af924 100644 --- a/pyre/pyre-interpreter/src/module/array/mod.rs +++ b/pyre/pyre-interpreter/src/module/array/mod.rs @@ -954,7 +954,9 @@ pub fn array_repr_wtf8(obj: PyObjectRef) -> Result PyResult { check_arity(args, 1, "array.__repr__")?; - Ok(pyre_object::w_str_from_wtf8(array_repr_wtf8(args[0])?)) + Ok(pyre_object::w_str_from_wtf8_managed(array_repr_wtf8( + args[0], + )?)) } // `interp_array.py compare_arrays`: compare each element with the requested From 1e356563d36984c1f3c73756b28bef0b27e49eeb Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 06:01:06 +0900 Subject: [PATCH 17/52] gc: collect explicit deque reprs --- .../gc_deque_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ .../gc_deque_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ pyre/bench/synth/gc_deque_repr_collectable.py | 12 ++++++++++++ .../synth/gc_deque_repr_collectable.wasm.jitstats | 15 +++++++++++++++ .../src/module/_collections/mod.rs | 2 +- 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_deque_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_deque_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_deque_repr_collectable.py create mode 100644 pyre/bench/synth/gc_deque_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_deque_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_deque_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_deque_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_deque_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_deque_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_deque_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_deque_repr_collectable.py b/pyre/bench/synth/gc_deque_repr_collectable.py new file mode 100644 index 00000000000..45bb4d066f2 --- /dev/null +++ b/pyre/bench/synth/gc_deque_repr_collectable.py @@ -0,0 +1,12 @@ +# pyre-check: no-cpython + +import gc +from collections import deque + + +rendered = deque.__repr__(deque([1, 2, 3], maxlen=4)) + +assert rendered == "deque([1, 2, 3], maxlen=4)" +assert any(obj is rendered for obj in gc.get_objects()) + +print("deque repr is collectable") diff --git a/pyre/bench/synth/gc_deque_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_deque_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_deque_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/module/_collections/mod.rs b/pyre/pyre-interpreter/src/module/_collections/mod.rs index bc24350941d..f050e85af2b 100644 --- a/pyre/pyre-interpreter/src/module/_collections/mod.rs +++ b/pyre/pyre-interpreter/src/module/_collections/mod.rs @@ -1302,7 +1302,7 @@ impl W_Deque { Some(m) => out.push_str(&format!("], maxlen={m})")), None => out.push_str("])"), } - Ok(pyre_object::w_str_from_wtf8(out)) + Ok(pyre_object::w_str_from_wtf8_managed(out)) } #[getter] From 16dcd8597cb0829f022472b6e1004e2c74fdf266 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 06:17:00 +0900 Subject: [PATCH 18/52] gc: collect explicit SRE pattern reprs --- ...re_pattern_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ ...c_sre_pattern_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ .../synth/gc_sre_pattern_repr_collectable.py | 13 +++++++++++++ .../gc_sre_pattern_repr_collectable.wasm.jitstats | 15 +++++++++++++++ .../src/module/_sre/interp_sre.rs | 6 +++--- 5 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 pyre/bench/synth/gc_sre_pattern_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_sre_pattern_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_sre_pattern_repr_collectable.py create mode 100644 pyre/bench/synth/gc_sre_pattern_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_sre_pattern_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_sre_pattern_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_sre_pattern_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_pattern_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_sre_pattern_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_sre_pattern_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_pattern_repr_collectable.py b/pyre/bench/synth/gc_sre_pattern_repr_collectable.py new file mode 100644 index 00000000000..8c275ca73cd --- /dev/null +++ b/pyre/bench/synth/gc_sre_pattern_repr_collectable.py @@ -0,0 +1,13 @@ +# pyre-check: no-cpython + +import gc +import re + + +pattern = re.compile("a+") +rendered = type(pattern).__repr__(pattern) + +assert rendered == "re.compile('a+')" +assert any(obj is rendered for obj in gc.get_objects()) + +print("sre pattern repr is collectable") diff --git a/pyre/bench/synth/gc_sre_pattern_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_sre_pattern_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_sre_pattern_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/module/_sre/interp_sre.rs b/pyre/pyre-interpreter/src/module/_sre/interp_sre.rs index 0abd501914a..7e2eaad6fda 100644 --- a/pyre/pyre-interpreter/src/module/_sre/interp_sre.rs +++ b/pyre/pyre-interpreter/src/module/_sre/interp_sre.rs @@ -1794,9 +1794,9 @@ pub(crate) fn sre_pattern_repr_str( fn sre_pattern_repr(args: &[PyObjectRef]) -> Result { let pat = sre_pattern_self(args)?; - Ok(pyre_object::w_str_from_wtf8(sre_pattern_repr_str( - pat as PyObjectRef, - )?)) + Ok(pyre_object::w_str_from_wtf8_managed( + sre_pattern_repr_str(pat as PyObjectRef)?, + )) } /// `descr_eq` (interp_sre.py:180-190): compare flags, compiled code, and From 739993a16d436f82a058c32f522c5e5fa363f561 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 06:33:17 +0900 Subject: [PATCH 19/52] gc: collect explicit SRE match reprs --- ..._sre_match_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ .../gc_sre_match_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ pyre/bench/synth/gc_sre_match_repr_collectable.py | 13 +++++++++++++ .../gc_sre_match_repr_collectable.wasm.jitstats | 15 +++++++++++++++ .../src/module/_sre/interp_sre.rs | 6 +++--- 5 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 pyre/bench/synth/gc_sre_match_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_sre_match_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_sre_match_repr_collectable.py create mode 100644 pyre/bench/synth/gc_sre_match_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_sre_match_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_sre_match_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_sre_match_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_match_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_sre_match_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_sre_match_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_match_repr_collectable.py b/pyre/bench/synth/gc_sre_match_repr_collectable.py new file mode 100644 index 00000000000..56764db6c92 --- /dev/null +++ b/pyre/bench/synth/gc_sre_match_repr_collectable.py @@ -0,0 +1,13 @@ +# pyre-check: no-cpython + +import gc +import re + + +match = re.compile("a+").match("aaa") +rendered = type(match).__repr__(match) + +assert rendered == "" +assert any(obj is rendered for obj in gc.get_objects()) + +print("sre match repr is collectable") diff --git a/pyre/bench/synth/gc_sre_match_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_sre_match_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_sre_match_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/module/_sre/interp_sre.rs b/pyre/pyre-interpreter/src/module/_sre/interp_sre.rs index 7e2eaad6fda..98883b5cf34 100644 --- a/pyre/pyre-interpreter/src/module/_sre/interp_sre.rs +++ b/pyre/pyre-interpreter/src/module/_sre/interp_sre.rs @@ -1717,9 +1717,9 @@ fn truncate_code_points(text: rustpython_wtf8::Wtf8Buf, limit: usize) -> rustpyt fn sre_match_repr(args: &[PyObjectRef]) -> Result { let m = sre_match_self(args)?; - Ok(pyre_object::w_str_from_wtf8(sre_match_repr_str( - m as PyObjectRef, - )?)) + Ok(pyre_object::w_str_from_wtf8_managed( + sre_match_repr_str(m as PyObjectRef)?, + )) } /// `copy_identity_w` (interp_sre.py:701-702) — match results are From c4fcdac969235f2936f3a1d52696b66ef17fae25 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 06:49:29 +0900 Subject: [PATCH 20/52] gc: preserve weak proxy str identity --- ...akproxy_str_collectable.cranelift.jitstats | 15 +++++++++++ ..._weakproxy_str_collectable.dynasm.jitstats | 15 +++++++++++ .../synth/gc_weakproxy_str_collectable.py | 25 +++++++++++++++++++ ...gc_weakproxy_str_collectable.wasm.jitstats | 15 +++++++++++ .../src/module/_weakref/interp__weakref.rs | 4 +-- 5 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 pyre/bench/synth/gc_weakproxy_str_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_weakproxy_str_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_weakproxy_str_collectable.py create mode 100644 pyre/bench/synth/gc_weakproxy_str_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_weakproxy_str_collectable.cranelift.jitstats b/pyre/bench/synth/gc_weakproxy_str_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_weakproxy_str_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_weakproxy_str_collectable.dynasm.jitstats b/pyre/bench/synth/gc_weakproxy_str_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_weakproxy_str_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_weakproxy_str_collectable.py b/pyre/bench/synth/gc_weakproxy_str_collectable.py new file mode 100644 index 00000000000..e99f3010401 --- /dev/null +++ b/pyre/bench/synth/gc_weakproxy_str_collectable.py @@ -0,0 +1,25 @@ +# pyre-check: no-cpython + +import gc +import weakref + + +marker = "".join(["dynamic", " weak proxy"]) + + +class Referent: + def __str__(self): + return marker + + +referent = Referent() +proxy = weakref.proxy(referent) +ordinary = str(proxy) +direct = type(proxy).__str__(proxy) + +assert ordinary is marker +assert direct is marker +assert any(obj is ordinary for obj in gc.get_objects()) +assert any(obj is direct for obj in gc.get_objects()) + +print("weak proxy str preserves managed identity") diff --git a/pyre/bench/synth/gc_weakproxy_str_collectable.wasm.jitstats b/pyre/bench/synth/gc_weakproxy_str_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_weakproxy_str_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/module/_weakref/interp__weakref.rs b/pyre/pyre-interpreter/src/module/_weakref/interp__weakref.rs index b6941ef4f41..3bc03ff2747 100644 --- a/pyre/pyre-interpreter/src/module/_weakref/interp__weakref.rs +++ b/pyre/pyre-interpreter/src/module/_weakref/interp__weakref.rs @@ -1528,9 +1528,7 @@ pub fn proxy_trunc(args: &[PyObjectRef]) -> Result { pub fn proxy_str(args: &[PyObjectRef]) -> Result { let w_obj0 = force(args[0])?; - Ok(pyre_object::w_str_from_wtf8(unsafe { - crate::display::py_str_wtf8(w_obj0)? - })) + crate::builtins::builtin_str(&[w_obj0]) } pub fn proxy_bool(args: &[PyObjectRef]) -> Result { From 1fe1e6420c8ddbaca0b4e8ae8768f098fd9520bc Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 07:05:09 +0900 Subject: [PATCH 21/52] gc: collect unpickled unicode strings --- ...kle_unicode_collectable.cranelift.jitstats | 15 +++++++++++++++ ...pickle_unicode_collectable.dynasm.jitstats | 15 +++++++++++++++ .../synth/gc_pickle_unicode_collectable.py | 19 +++++++++++++++++++ ...c_pickle_unicode_collectable.wasm.jitstats | 15 +++++++++++++++ .../src/module/_pickle/mod.rs | 2 +- 5 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_pickle_unicode_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_pickle_unicode_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_pickle_unicode_collectable.py create mode 100644 pyre/bench/synth/gc_pickle_unicode_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_pickle_unicode_collectable.cranelift.jitstats b/pyre/bench/synth/gc_pickle_unicode_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_pickle_unicode_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_pickle_unicode_collectable.dynasm.jitstats b/pyre/bench/synth/gc_pickle_unicode_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_pickle_unicode_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_pickle_unicode_collectable.py b/pyre/bench/synth/gc_pickle_unicode_collectable.py new file mode 100644 index 00000000000..7b8b9bbe2c4 --- /dev/null +++ b/pyre/bench/synth/gc_pickle_unicode_collectable.py @@ -0,0 +1,19 @@ +# pyre-check: no-cpython + +import gc +import pickle + + +text = b"pickle runtime string" +payloads = [ + b"\x80\x04\x8c" + bytes([len(text)]) + text + b".", + b"\x80\x04X" + len(text).to_bytes(4, "little") + text + b".", + b"\x80\x04\x8d" + len(text).to_bytes(8, "little") + text + b".", +] + +for payload in payloads: + result = pickle.loads(payload) + assert result == "pickle runtime string" + assert any(obj is result for obj in gc.get_objects()) + +print("pickle unicode results are collectable") diff --git a/pyre/bench/synth/gc_pickle_unicode_collectable.wasm.jitstats b/pyre/bench/synth/gc_pickle_unicode_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_pickle_unicode_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/module/_pickle/mod.rs b/pyre/pyre-interpreter/src/module/_pickle/mod.rs index 8c507e9de40..bf5f970a7f7 100644 --- a/pyre/pyre-interpreter/src/module/_pickle/mod.rs +++ b/pyre/pyre-interpreter/src/module/_pickle/mod.rs @@ -621,7 +621,7 @@ pub(crate) fn str_from_utf8(data: &[u8]) -> Result { // surrogates are valid pickle payloads and are represented internally as // WTF-8, while malformed byte sequences must still be rejected. let s = rustpython_wtf8::Wtf8Buf::from_bytes(data.to_vec()).map_err(utf8_decode_error)?; - Ok(pyre_object::unicodeobject::w_str_from_wtf8(s)) + Ok(pyre_object::unicodeobject::w_str_from_wtf8_managed(s)) } /// Construct Python's UTF-8 decode error details from Rust's `Utf8Error`. From e82eec4e1508110ce3b07c1a74f1323781877ba7 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 07:23:21 +0900 Subject: [PATCH 22/52] gc: manage unicode normalization results --- ...a_normalize_collectable.cranelift.jitstats | 15 ++++++++ ...data_normalize_collectable.dynasm.jitstats | 15 ++++++++ .../gc_unicodedata_normalize_collectable.py | 34 +++++++++++++++++++ ...dedata_normalize_collectable.wasm.jitstats | 15 ++++++++ .../src/module/unicodedata/mod.rs | 12 ++++++- 5 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_unicodedata_normalize_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_unicodedata_normalize_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_unicodedata_normalize_collectable.py create mode 100644 pyre/bench/synth/gc_unicodedata_normalize_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_unicodedata_normalize_collectable.cranelift.jitstats b/pyre/bench/synth/gc_unicodedata_normalize_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_unicodedata_normalize_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_unicodedata_normalize_collectable.dynasm.jitstats b/pyre/bench/synth/gc_unicodedata_normalize_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_unicodedata_normalize_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_unicodedata_normalize_collectable.py b/pyre/bench/synth/gc_unicodedata_normalize_collectable.py new file mode 100644 index 00000000000..389ead85fa9 --- /dev/null +++ b/pyre/bench/synth/gc_unicodedata_normalize_collectable.py @@ -0,0 +1,34 @@ +# pyre-check: no-cpython + +import gc +import unicodedata + + +cases = [ + ("NFC", "e\u0301 runtime", "é runtime"), + ("NFD", "é runtime", "e\u0301 runtime"), + ("NFKC", "\ufb03 runtime", "ffi runtime"), + ("NFKD", "\ufb03 runtime", "ffi runtime"), +] + +for form, source, expected in cases: + result = unicodedata.normalize(form, source) + assert result == expected + assert any(obj is result for obj in gc.get_objects()) + +ascii_source = "".join(["ascii", " runtime"]) +ascii_result = unicodedata.normalize("NFC", ascii_source) +assert ascii_result is ascii_source +assert any(obj is ascii_result for obj in gc.get_objects()) + + +class Text(str): + pass + + +subclass_result = unicodedata.normalize("NFC", Text("subclass runtime")) +assert type(subclass_result) is str +assert subclass_result == "subclass runtime" +assert any(obj is subclass_result for obj in gc.get_objects()) + +print("unicodedata normalize results are collectable") diff --git a/pyre/bench/synth/gc_unicodedata_normalize_collectable.wasm.jitstats b/pyre/bench/synth/gc_unicodedata_normalize_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_unicodedata_normalize_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/module/unicodedata/mod.rs b/pyre/pyre-interpreter/src/module/unicodedata/mod.rs index 76dcfc8c639..36590c3d2a9 100644 --- a/pyre/pyre-interpreter/src/module/unicodedata/mod.rs +++ b/pyre/pyre-interpreter/src/module/unicodedata/mod.rs @@ -271,7 +271,17 @@ fn normalize(args: &[PyObjectRef]) -> PyResult { } let form = normalize_form("normalize", args[0])?; let text = normalize_text("normalize", args[1])?; - Ok(w_str_from_wtf8(ucd_core::normalize(form, text))) + // interp_ucd.py:175-178 returns `space.newutf8(content, strlen)` for + // ASCII. PyPy's W_UnicodeObject.is_w treats wrappers sharing that UTF-8 + // buffer as identical; returning the exact base str preserves that O(1) + // identity without copying Pyre's owned Wtf8Buf. A subclass must still + // be converted to a base str, just like `space.newutf8`. + if text.as_bytes().is_ascii() + && unsafe { pyre_object::is_exact_type(args[1], &pyre_object::STR_TYPE) } + { + return Ok(args[1]); + } + Ok(w_str_from_wtf8_managed(ucd_core::normalize(form, text))) } fn is_normalized(args: &[PyObjectRef]) -> PyResult { From f51a789ad1e31742073246c77dced505be5eeb7e Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 07:51:07 +0900 Subject: [PATCH 23/52] gc: collect SimpleNamespace reprs --- ...espace_repr_collectable.cranelift.jitstats | 15 +++++++++ ...namespace_repr_collectable.dynasm.jitstats | 15 +++++++++ .../gc_simple_namespace_repr_collectable.py | 31 +++++++++++++++++++ ...e_namespace_repr_collectable.wasm.jitstats | 15 +++++++++ pyre/pyre-interpreter/src/module/sys/vm.rs | 4 +-- 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 pyre/bench/synth/gc_simple_namespace_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_simple_namespace_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_simple_namespace_repr_collectable.py create mode 100644 pyre/bench/synth/gc_simple_namespace_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_simple_namespace_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_simple_namespace_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_simple_namespace_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_simple_namespace_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_simple_namespace_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_simple_namespace_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_simple_namespace_repr_collectable.py b/pyre/bench/synth/gc_simple_namespace_repr_collectable.py new file mode 100644 index 00000000000..107c6186a95 --- /dev/null +++ b/pyre/bench/synth/gc_simple_namespace_repr_collectable.py @@ -0,0 +1,31 @@ +# pyre-check: no-cpython + +import gc +from types import SimpleNamespace + + +namespace = SimpleNamespace(alpha="value", count=3) +ordinary = repr(namespace) +direct = SimpleNamespace.__repr__(namespace) + +assert ordinary == "namespace(alpha='value', count=3)" +assert direct == ordinary +assert any(obj is ordinary for obj in gc.get_objects()) +assert any(obj is direct for obj in gc.get_objects()) + +recursive_result = None + + +class CaptureRecursiveRepr: + def __repr__(self): + global recursive_result + recursive_result = repr(recursive_namespace) + return "captured" + + +recursive_namespace = SimpleNamespace(value=CaptureRecursiveRepr()) +assert repr(recursive_namespace) == "namespace(value=captured)" +assert recursive_result == "namespace(...)" +assert any(obj is recursive_result for obj in gc.get_objects()) + +print("SimpleNamespace repr results are collectable") diff --git a/pyre/bench/synth/gc_simple_namespace_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_simple_namespace_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_simple_namespace_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/module/sys/vm.rs b/pyre/pyre-interpreter/src/module/sys/vm.rs index 281e032d08b..271faefec11 100644 --- a/pyre/pyre-interpreter/src/module/sys/vm.rs +++ b/pyre/pyre-interpreter/src/module/sys/vm.rs @@ -375,7 +375,7 @@ fn simple_namespace_repr(args: &[PyObjectRef]) -> crate::PyResult { unsafe { w_type_get_name(actual_type) }.to_string() }; let Some(_guard) = crate::display::ReprGuard::enter(self_obj) else { - return Ok(w_str_new(&format!("{name}(...)"))); + return Ok(w_str_new_managed(&format!("{name}(...)"))); }; let dict = crate::baseobjspace::getattr_str( pyre_object::gc_roots::shadow_stack_get(sp), @@ -427,7 +427,7 @@ fn simple_namespace_repr(args: &[PyObjectRef]) -> crate::PyResult { text.push_wtf8(part); } text.push_str(")"); - Ok(pyre_object::w_str_from_wtf8(text)) + Ok(pyre_object::w_str_from_wtf8_managed(text)) } /// `_structseq.py:185 SimpleNamespace.__eq__` — structural over `__dict__` From affe4a223bcac55489cab5baf02082ffa06d4526 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 08:19:21 +0900 Subject: [PATCH 24/52] gc: collect sre substitution outputs --- ..._sub_output_collectable.cranelift.jitstats | 15 +++++++++++++ ...sre_sub_output_collectable.dynasm.jitstats | 15 +++++++++++++ .../synth/gc_sre_sub_output_collectable.py | 22 +++++++++++++++++++ ...c_sre_sub_output_collectable.wasm.jitstats | 15 +++++++++++++ .../src/module/_sre/interp_sre.rs | 13 +++++++++-- 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 pyre/bench/synth/gc_sre_sub_output_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_sre_sub_output_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_sre_sub_output_collectable.py create mode 100644 pyre/bench/synth/gc_sre_sub_output_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_sre_sub_output_collectable.cranelift.jitstats b/pyre/bench/synth/gc_sre_sub_output_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_sre_sub_output_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_sub_output_collectable.dynasm.jitstats b/pyre/bench/synth/gc_sre_sub_output_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_sre_sub_output_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_sub_output_collectable.py b/pyre/bench/synth/gc_sre_sub_output_collectable.py new file mode 100644 index 00000000000..2f6347cb694 --- /dev/null +++ b/pyre/bench/synth/gc_sre_sub_output_collectable.py @@ -0,0 +1,22 @@ +# pyre-check: no-cpython + +import gc +import re + + +pattern = re.compile(r"([a-z]+)-(\d+)") +subject = "alpha-123-omega" + +sub_result = pattern.sub("word", subject) +subn_result, count = pattern.subn("word", subject) +expand_result = pattern.search(subject).expand(r"<\1:\2>") + +assert sub_result == "word-omega" +assert subn_result == "word-omega" +assert count == 1 +assert expand_result == "" +assert any(obj is sub_result for obj in gc.get_objects()) +assert any(obj is subn_result for obj in gc.get_objects()) +assert any(obj is expand_result for obj in gc.get_objects()) + +print("sre substitution outputs are collectable") diff --git a/pyre/bench/synth/gc_sre_sub_output_collectable.wasm.jitstats b/pyre/bench/synth/gc_sre_sub_output_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_sre_sub_output_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/module/_sre/interp_sre.rs b/pyre/pyre-interpreter/src/module/_sre/interp_sre.rs index 98883b5cf34..28e14de4c15 100644 --- a/pyre/pyre-interpreter/src/module/_sre/interp_sre.rs +++ b/pyre/pyre-interpreter/src/module/_sre/interp_sre.rs @@ -836,7 +836,12 @@ fn subject_span_bytes(subj: Subject, span: (i64, i64)) -> Option<&'static [u8]> /// the (valid UTF-8) builder, or `bytes` (subx result, interp_sre.py:541-548). fn finish_output(subj: Subject, out: Vec) -> PyObjectRef { match subj { - Subject::Str(_) => w_str_from_wtf8(Wtf8Buf::from_bytes(out).unwrap_or_default()), + // interp_sre.py:567 returns `space.newutf8(...)`: substitution and + // expansion results are ordinary runtime strings, not bootstrap + // structural strings that may live outside the managed heap. + Subject::Str(_) => { + w_str_from_wtf8_managed(Wtf8Buf::from_bytes(out).unwrap_or_default()) + } Subject::Bytes(_) => pyre_object::bytesobject::w_bytes_from_bytes(&out), } } @@ -1220,8 +1225,12 @@ fn sre_pattern_sub(args: &[PyObjectRef]) -> Result /// `subn_w` (interp_sre.py:415-419) — returns `(new_string, count)`. fn sre_pattern_subn(args: &[PyObjectRef]) -> Result { + let _roots = pyre_object::gc_roots::push_roots(); let (w_item, n) = subx(args)?; - Ok(w_tuple_new(vec![w_item, w_int_new(n)])) + pyre_object::gc_roots::pin_root(w_item); + let w_n = w_int_new(n); + pyre_object::gc_roots::pin_root(w_n); + Ok(w_tuple_new(vec![w_item, w_n])) } /// `subx` (interp_sre.py:421-558) — the shared sub/subn body. `repl` is a From 0318f7d92a34d82d6a9a5208eeb2e2de730673fb Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 08:42:16 +0900 Subject: [PATCH 25/52] gc: collect sre subject slices --- ...c_sre_slice_collectable.cranelift.jitstats | 15 ++ .../gc_sre_slice_collectable.dynasm.jitstats | 15 ++ pyre/bench/synth/gc_sre_slice_collectable.py | 56 ++++++ .../gc_sre_slice_collectable.wasm.jitstats | 15 ++ .../src/module/_sre/interp_sre.rs | 162 +++++++++++++----- 5 files changed, 218 insertions(+), 45 deletions(-) create mode 100644 pyre/bench/synth/gc_sre_slice_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_sre_slice_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_sre_slice_collectable.py create mode 100644 pyre/bench/synth/gc_sre_slice_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_sre_slice_collectable.cranelift.jitstats b/pyre/bench/synth/gc_sre_slice_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_sre_slice_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_slice_collectable.dynasm.jitstats b/pyre/bench/synth/gc_sre_slice_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_sre_slice_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_slice_collectable.py b/pyre/bench/synth/gc_sre_slice_collectable.py new file mode 100644 index 00000000000..f4247b401c2 --- /dev/null +++ b/pyre/bench/synth/gc_sre_slice_collectable.py @@ -0,0 +1,56 @@ +# pyre-check: no-cpython + +import gc +import re + + +def is_managed(value): + return any(obj is value for obj in gc.get_objects()) + + +pattern = re.compile(r"(?P[a-z]+)-(?P\d+)") +subject = "alpha-123-omega" +match = pattern.search(subject) + +group_word = match.group(1) +getitem_number = match[2] +multiple = match.group(1, 2) +groups = match.groups() +groupdict = match.groupdict() +findall_plain = re.findall(r"[a-z]+", subject) +findall_single = re.findall(r"([a-z]+)", subject) +findall_multiple = pattern.findall(subject) +split_parts = re.split(r"(-)", subject) + +assert group_word == "alpha" +assert getitem_number == "123" +assert multiple == ("alpha", "123") +assert groups == ("alpha", "123") +assert groupdict == {"word": "alpha", "number": "123"} +assert findall_plain == ["alpha", "omega"] +assert findall_single == ["alpha", "omega"] +assert findall_multiple == [("alpha", "123")] +assert split_parts == ["alpha", "-", "123", "-", "omega"] + +assert is_managed(group_word) +assert is_managed(getitem_number) +assert is_managed(multiple[0]) +assert is_managed(groups[1]) +assert is_managed(groupdict["word"]) +assert is_managed(findall_plain[0]) +assert is_managed(findall_single[1]) +assert is_managed(findall_multiple[0][1]) +assert is_managed(split_parts[0]) +assert is_managed(split_parts[1]) + + +class Text(str): + pass + + +unchanged = pattern.sub("replacement", Text("no match here")) +assert type(unchanged) is str +assert unchanged == "no match here" +assert is_managed(unchanged) + +print("sre subject slices are collectable") diff --git a/pyre/bench/synth/gc_sre_slice_collectable.wasm.jitstats b/pyre/bench/synth/gc_sre_slice_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_sre_slice_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/module/_sre/interp_sre.rs b/pyre/pyre-interpreter/src/module/_sre/interp_sre.rs index 28e14de4c15..c794afaf09a 100644 --- a/pyre/pyre-interpreter/src/module/_sre/interp_sre.rs +++ b/pyre/pyre-interpreter/src/module/_sre/interp_sre.rs @@ -682,6 +682,25 @@ impl Subject { } } +/// One translated live GCREF in the shadow stack. RPython's GC transform +/// inserts the equivalent push/reload around allocations automatically; +/// Rust collections otherwise retain the pre-move pointer while `_sre` +/// builds tuples, lists, and dictionaries of freshly sliced strings. +#[derive(Clone, Copy)] +struct RootedObject(usize); + +impl RootedObject { + fn pin(obj: PyObjectRef) -> Self { + let slot = pyre_object::gc_roots::shadow_stack_len(); + pyre_object::gc_roots::pin_root(obj); + Self(slot) + } + + fn get(self) -> PyObjectRef { + pyre_object::gc_roots::shadow_stack_get(self.0) + } +} + /// `is_known_bytes` (interp_sre.py:208-212) — the pattern was compiled from /// a bytes-like object (a `None` pattern is unknown, accepting either). fn pattern_is_known_bytes(pat: PyObjectRef) -> bool { @@ -806,7 +825,9 @@ unsafe fn subject_of(string: PyObjectRef, w_buffer: PyObjectRef) -> Subject { fn slice_subject(subj: Subject, span: (i64, i64), w_default: PyObjectRef) -> PyObjectRef { match subj { Subject::Str(s) => char_slice(s, span.0, span.1) - .map(|s| w_str_from_wtf8(s.to_owned())) + // interp_sre.py:68/76 uses `space.newutf8`: a captured slice is + // an ordinary runtime string and must participate in the GC. + .map(|s| w_str_from_wtf8_managed(s.to_owned())) .unwrap_or(w_default), Subject::Bytes(b) => byte_slice(b, span.0, span.1) .map(pyre_object::bytesobject::w_bytes_from_bytes) @@ -1143,6 +1164,7 @@ fn required_arg_kw( /// with two or more a tuple of the groups. Unmatched groups become the /// empty string (`w_emptystr`, :344-347). fn sre_pattern_findall(args: &[PyObjectRef]) -> Result { + let _roots = pyre_object::gc_roots::push_roots(); let (args, kwargs) = crate::builtins::split_builtin_kwargs(args); let pat = args .first() @@ -1163,22 +1185,26 @@ fn sre_pattern_findall(args: &[PyObjectRef]) -> Result collect_matches(s, pos, endpos, code, pat), Subject::Bytes(b) => collect_matches(b, pos, endpos, code, pat), }; - let mut results = Vec::with_capacity(matches.len()); + // `matchlist_w = []` in interp_sre.py:341 is a GC-managed list. Build + // that same shape here instead of retaining every result in an off-heap + // Rust Vec (which would require an O(number of matches) shadow stack). + let results = RootedObject::pin(w_list_new_empty()); for snap in &matches { + let _item_roots = pyre_object::gc_roots::push_roots(); let spans = &snap.spans; let w_item = if num_groups == 0 { - slice_subject(subj, spans[0], w_empty) + RootedObject::pin(slice_subject(subj, spans[0], w_empty)) } else if num_groups == 1 { - slice_subject(subj, spans[1], w_empty) + RootedObject::pin(slice_subject(subj, spans[1], w_empty)) } else { - let grps: Vec = (1..=num_groups) - .map(|g| slice_subject(subj, spans[g], w_empty)) + let grps: Vec = (1..=num_groups) + .map(|g| RootedObject::pin(slice_subject(subj, spans[g], w_empty))) .collect(); - w_tuple_new(grps) + RootedObject::pin(w_tuple_new(grps.into_iter().map(RootedObject::get).collect())) }; - results.push(w_item); + unsafe { w_list_append(results.get(), w_item.get()) }; } - Ok(w_list_new(results)) + Ok(results.get()) } /// `finditer_w` (interp_sre.py:368-376) — returns the lazy @@ -1227,10 +1253,9 @@ fn sre_pattern_sub(args: &[PyObjectRef]) -> Result fn sre_pattern_subn(args: &[PyObjectRef]) -> Result { let _roots = pyre_object::gc_roots::push_roots(); let (w_item, n) = subx(args)?; - pyre_object::gc_roots::pin_root(w_item); - let w_n = w_int_new(n); - pyre_object::gc_roots::pin_root(w_n); - Ok(w_tuple_new(vec![w_item, w_n])) + let w_item = RootedObject::pin(w_item); + let w_n = RootedObject::pin(w_int_new(n)); + Ok(w_tuple_new(vec![w_item.get(), w_n.get()])) } /// `subx` (interp_sre.py:421-558) — the shared sub/subn body. `repl` is a @@ -1375,6 +1400,7 @@ fn is_exact_str_or_bytes(w: PyObjectRef) -> bool { /// (0 = unlimited) caps the number of splits; the unsplit remainder is the /// final item. fn sre_pattern_split(args: &[PyObjectRef]) -> Result { + let _roots = pyre_object::gc_roots::push_roots(); let (args, kwargs) = crate::builtins::split_builtin_kwargs(args); let pat = args .first() @@ -1388,19 +1414,26 @@ fn sre_pattern_split(args: &[PyObjectRef]) -> Result = Vec::new(); + // `splitlist = []` in interp_sre.py:383 is itself the long-lived root; + // keep only the item currently being appended on the shadow stack. + let results = RootedObject::pin(w_list_new_empty()); let mut last = 0i64; + let append_slice = |span, w_default| { + let _item_roots = pyre_object::gc_roots::push_roots(); + let w_item = RootedObject::pin(slice_subject(subj, span, w_default)); + unsafe { w_list_append(results.get(), w_item.get()) }; + }; // interp_sre.py:387 `while not maxsplit or n < maxsplit` — 0 is unlimited, // a negative cap performs no splits; matching streams so `maxsplit` bounds // the scan rather than discarding already-found matches. let on_match = |snap: &MatchSnapshot| -> Result<(), crate::PyError> { let (mstart, mend) = snap.spans[0]; // interp_sre.py:393 — the slice preceding this match. - results.push(slice_subject(subj, (last, mstart), w_empty)); + append_slice((last, mstart), w_empty); // interp_sre.py:396-399 — interleave each group's capture; an // unmatched group span `(-1, -1)` becomes None via slice_subject. for g in 1..=num_groups { - results.push(slice_subject(subj, snap.spans[g], w_none())); + append_slice(snap.spans[g], w_none()); } last = mend; Ok(()) @@ -1410,8 +1443,8 @@ fn sre_pattern_split(args: &[PyObjectRef]) -> Result stream_matches(b, 0, endpos, code, pat, maxsplit, on_match)?, }; // interp_sre.py:405 — the trailing remainder after the last match. - results.push(slice_subject(subj, (last, endpos as i64), w_empty)); - Ok(w_list_new(results)) + append_slice((last, endpos as i64), w_empty); + Ok(results.get()) } // ── Replacement-template parser (`re._parser.parse_template`) ────────── @@ -1573,52 +1606,86 @@ fn sre_match_group(args: &[PyObjectRef]) -> Result let span = do_span(m, group_args.first().copied())?; return Ok(unsafe { slice_w(m, span, w_none()) }); } - let mut results = Vec::with_capacity(group_args.len()); + let _roots = pyre_object::gc_roots::push_roots(); + let m = RootedObject::pin(m as PyObjectRef); + let mut results: Vec = Vec::with_capacity(group_args.len()); for &w_arg in group_args { - let span = do_span(m, Some(w_arg))?; - results.push(unsafe { slice_w(m, span, w_none()) }); + let span = do_span(m.get() as *const W_SRE_Match, Some(w_arg))?; + results.push(RootedObject::pin(unsafe { + slice_w(m.get() as *const W_SRE_Match, span, w_none()) + })); } - Ok(w_tuple_new(results)) + Ok(w_tuple_new( + results.into_iter().map(RootedObject::get).collect(), + )) } /// `groups_w` (interp_sre.py:728-732) — pyre reads the flattened span /// table directly; unmatched groups (span `(-1, -1)`) take the optional /// `default` argument. fn sre_match_groups(args: &[PyObjectRef]) -> Result { - let m = sre_match_self(args)?; - let w_default = args.get(1).copied().unwrap_or_else(w_none); - let n = unsafe { (*m).spans_len }; - let mut groups = Vec::new(); + let _roots = pyre_object::gc_roots::push_roots(); + let m = RootedObject::pin(sre_match_self(args)? as PyObjectRef); + let w_default = RootedObject::pin(args.get(1).copied().unwrap_or_else(w_none)); + let n = unsafe { (*(m.get() as *const W_SRE_Match)).spans_len }; + let mut groups: Vec = Vec::new(); for gi in 1..n { - let span = unsafe { w_sre_match_get_span(m as PyObjectRef, gi) }.unwrap_or((-1, -1)); - groups.push(unsafe { slice_w(m, span, w_default) }); + let span = unsafe { w_sre_match_get_span(m.get(), gi) }.unwrap_or((-1, -1)); + groups.push(RootedObject::pin(unsafe { + slice_w( + m.get() as *const W_SRE_Match, + span, + w_default.get(), + ) + })); } - Ok(w_tuple_new(groups)) + Ok(w_tuple_new( + groups.into_iter().map(RootedObject::get).collect(), + )) } /// `groupdict_w` (interp_sre.py:735-751) — name→group-text map built by /// iterating `srepat.w_groupindex`; unmatched groups take `default`. fn sre_match_groupdict(args: &[PyObjectRef]) -> Result { - let m = sre_match_self(args)?; - let w_default = args.get(1).copied().unwrap_or_else(w_none); - let w_groupindex = unsafe { (*(*m).w_srepat.cast::()).w_groupindex }; - let w_dict = w_dict_new(); + let _roots = pyre_object::gc_roots::push_roots(); + let m = RootedObject::pin(sre_match_self(args)? as PyObjectRef); + let w_default = RootedObject::pin(args.get(1).copied().unwrap_or_else(w_none)); + let w_groupindex = RootedObject::pin(unsafe { + (*(*(m.get() as *const W_SRE_Match)) + .w_srepat + .cast::()) + .w_groupindex + }); + let w_dict = RootedObject::pin(w_dict_new()); // interp_sre.py:735-751 groupdict_w — walk `w_groupindex` through the // object-space iterator / item protocol, resolving each value with // `do_span` so a duck-typed group number works. - let w_iterator = crate::baseobjspace::iter(w_groupindex)?; + let w_iterator = RootedObject::pin(crate::baseobjspace::iter(w_groupindex.get())?); loop { - let w_key = match crate::baseobjspace::next(w_iterator) { - Ok(k) => k, + let _item_roots = pyre_object::gc_roots::push_roots(); + let w_key = match crate::baseobjspace::next(w_iterator.get()) { + Ok(k) => RootedObject::pin(k), Err(e) if e.kind == crate::PyErrorKind::StopIteration => break, Err(e) => return Err(e), }; - let w_value = crate::baseobjspace::getitem(w_groupindex, w_key)?; - let span = do_span(m, Some(w_value))?; - let w_grp = unsafe { slice_w(m, span, w_default) }; - crate::baseobjspace::setitem(w_dict, w_key, w_grp)?; + let w_value = RootedObject::pin(crate::baseobjspace::getitem( + w_groupindex.get(), + w_key.get(), + )?); + let span = do_span( + m.get() as *const W_SRE_Match, + Some(w_value.get()), + )?; + let w_grp = RootedObject::pin(unsafe { + slice_w( + m.get() as *const W_SRE_Match, + span, + w_default.get(), + ) + }); + crate::baseobjspace::setitem(w_dict.get(), w_key.get(), w_grp.get())?; } - Ok(w_dict) + Ok(w_dict.get()) } /// `fget_regs` (interp_sre.py:853-864) — `((start, end), ...)` for group @@ -1701,12 +1768,17 @@ fn sre_match_expand(args: &[PyObjectRef]) -> Result pub(crate) fn sre_match_repr_str( m: PyObjectRef, ) -> Result { - let mp = m as *const W_SRE_Match; - let span = unsafe { w_sre_match_get_span(m, 0) }.unwrap_or((-1, -1)); + let _roots = pyre_object::gc_roots::push_roots(); + let m = RootedObject::pin(m); + let mp = m.get() as *const W_SRE_Match; + let span = unsafe { w_sre_match_get_span(m.get(), 0) }.unwrap_or((-1, -1)); let (start, end) = span; let subj = unsafe { subject_of((*mp).w_string, (*mp).w_buffer) }; - let w_match_str = slice_subject(subj, span, w_none()); - let matchrepr = truncate_code_points(unsafe { crate::display::py_repr_wtf8(w_match_str) }?, 50); + let w_match_str = RootedObject::pin(slice_subject(subj, span, w_none())); + let matchrepr = truncate_code_points( + unsafe { crate::display::py_repr_wtf8(w_match_str.get()) }?, + 50, + ); Ok(crate::display::wtf8_format!( format!(" Result { // is not valid WTF-8; fall back to surrogateescape rather than raising, // mirroring str_decode_locale_surrogateescape. let result = match rustpython_wtf8::Wtf8Buf::from_bytes(rendered) { - Ok(wtf8) => pyre_object::w_str_from_wtf8(wtf8), + // interp_time.py:1188 returns `space.newutf8(decoded, size)`: + // strftime's formatted value is an ordinary runtime string. + Ok(wtf8) => pyre_object::w_str_from_wtf8_managed(wtf8), Err(bytes) => crate::typedef::charp2uni(&bytes), }; Ok(result) @@ -1411,7 +1413,7 @@ pub fn strftime(args: &[PyObjectRef]) -> Result { // surrogateescape rather than raising. let rendered = buf[..n].to_vec(); return Ok(match rustpython_wtf8::Wtf8Buf::from_bytes(rendered) { - Ok(wtf8) => w_str_from_wtf8(wtf8), + Ok(wtf8) => w_str_from_wtf8_managed(wtf8), Err(bytes) => crate::typedef::charp2uni(&bytes), }); } From 3290819f4e8c87b071d87b6f86f7fb6dafa0335a Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 09:16:08 +0900 Subject: [PATCH 27/52] gc: collect asctime and ctime results --- ...ime_asctime_collectable.cranelift.jitstats | 15 +++++++++++++ ...c_time_asctime_collectable.dynasm.jitstats | 15 +++++++++++++ .../synth/gc_time_asctime_collectable.py | 19 ++++++++++++++++ .../src/module/time/interp_time.rs | 22 +++++-------------- 4 files changed, 55 insertions(+), 16 deletions(-) create mode 100644 pyre/bench/synth/gc_time_asctime_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_time_asctime_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_time_asctime_collectable.py diff --git a/pyre/bench/synth/gc_time_asctime_collectable.cranelift.jitstats b/pyre/bench/synth/gc_time_asctime_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_time_asctime_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_time_asctime_collectable.dynasm.jitstats b/pyre/bench/synth/gc_time_asctime_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_time_asctime_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_time_asctime_collectable.py b/pyre/bench/synth/gc_time_asctime_collectable.py new file mode 100644 index 00000000000..8a4c5373327 --- /dev/null +++ b/pyre/bench/synth/gc_time_asctime_collectable.py @@ -0,0 +1,19 @@ +# pyre-check: no-cpython +# pyre-check: skip-backends=wasm +import gc +import time + + +asctime_value = time.asctime( + (2020, 2, 3, 4, 5, 6, 0, 34, -1), +) + +assert asctime_value == "Mon Feb 3 04:05:06 2020" +assert any(obj is asctime_value for obj in gc.get_objects()) + +# The wasm guest does not register the time module. Native Unix and Windows +# share this localtime -> _asctime path. +ctime_value = time.ctime(0) +assert any(obj is ctime_value for obj in gc.get_objects()) + +print("time asctime results are collectable") diff --git a/pyre/pyre-interpreter/src/module/time/interp_time.rs b/pyre/pyre-interpreter/src/module/time/interp_time.rs index e9b7c3fbd3b..13b9a1b7263 100644 --- a/pyre/pyre-interpreter/src/module/time/interp_time.rs +++ b/pyre/pyre-interpreter/src/module/time/interp_time.rs @@ -1487,7 +1487,9 @@ fn _asctime_from_tm(tm: &c_tm) -> Result { const MON_NAME: [&str; 12] = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ]; - Ok(w_str_new(&format!( + // interp_time.py:_asctime returns the result of ordinary `%` formatting; + // the rendered value is a collectable runtime string. + Ok(w_str_new_managed(&format!( "{} {}{:>3} {:02}:{:02}:{:02} {}", WDAY_NAME[tm.tm_wday as usize], MON_NAME[tm.tm_mon as usize], @@ -1510,25 +1512,13 @@ pub fn ctime(args: &[PyObjectRef]) -> Result { "time.ctime is unavailable on wasm32", )) } - #[cfg(unix)] + #[cfg(not(target_arch = "wasm32"))] { + // interp_time.py:ctime always delegates through localtime + _asctime. + // Keep one result-allocation path on Unix and Windows alike. let tm = _c_localtime(seconds)?; _asctime_from_tm(&tm) } - #[cfg(windows)] - { - unsafe extern "C" { - fn _ctime64(time: *const i64) -> *const libc::c_char; - } - let t = seconds; - let p = unsafe { _ctime64(&t) }; - if p.is_null() { - return Err(crate::PyError::value_error("unconvertible time")); - } - let lossy = unsafe { std::ffi::CStr::from_ptr(p) }.to_string_lossy(); - let s = lossy.trim_end_matches('\n'); - Ok(w_str_new(s)) - } } /// `app_time.py:26-34 strptime` — parse `string` per `format`, delegating to From 9e98949d59e17955bf806afd82da4ecce519103f Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 09:32:17 +0900 Subject: [PATCH 28/52] gc: collect DirEntry reprs --- ..._direntry_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ .../gc_direntry_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ pyre/bench/synth/gc_direntry_repr_collectable.py | 16 ++++++++++++++++ .../src/module/posix/interp_posix.rs | 4 +++- 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_direntry_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_direntry_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_direntry_repr_collectable.py diff --git a/pyre/bench/synth/gc_direntry_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_direntry_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_direntry_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_direntry_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_direntry_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_direntry_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_direntry_repr_collectable.py b/pyre/bench/synth/gc_direntry_repr_collectable.py new file mode 100644 index 00000000000..574646906e3 --- /dev/null +++ b/pyre/bench/synth/gc_direntry_repr_collectable.py @@ -0,0 +1,16 @@ +# pyre-check: no-cpython +# pyre-check: skip-backends=wasm +import gc +import os + + +entry = next(os.scandir(".")) +direct = os.DirEntry.__repr__(entry) +ordinary = repr(entry) + +assert direct == ordinary +assert direct.startswith(""); - Ok(pyre_object::w_str_from_wtf8(out)) + // interp_scandir.py:230 returns `space.newtext(...)`: this rendered + // value is an ordinary collectable runtime string. + Ok(pyre_object::w_str_from_wtf8_managed(out)) } /// `interp_scandir.py:463-465 descr_reduce_ex` — an entry names a live /// position in a directory listing, so it refuses to be pickled. `%T` is From 7c4c7195a4461fb36e17f10a536ce04b5e1a0a8c Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 09:48:32 +0900 Subject: [PATCH 29/52] gc: collect memoryview reprs --- ...ryview_repr_collectable.cranelift.jitstats | 15 ++++++++++++ ...emoryview_repr_collectable.dynasm.jitstats | 15 ++++++++++++ .../synth/gc_memoryview_repr_collectable.py | 23 +++++++++++++++++++ ..._memoryview_repr_collectable.wasm.jitstats | 15 ++++++++++++ pyre/pyre-interpreter/src/builtins.rs | 4 +++- 5 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_memoryview_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_memoryview_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_memoryview_repr_collectable.py create mode 100644 pyre/bench/synth/gc_memoryview_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_memoryview_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_memoryview_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_memoryview_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_memoryview_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_memoryview_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_memoryview_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_memoryview_repr_collectable.py b/pyre/bench/synth/gc_memoryview_repr_collectable.py new file mode 100644 index 00000000000..3a4d7405aaf --- /dev/null +++ b/pyre/bench/synth/gc_memoryview_repr_collectable.py @@ -0,0 +1,23 @@ +# pyre-check: no-cpython +import gc + + +view = memoryview(b"x") +live_direct = memoryview.__repr__(view) +live_ordinary = repr(view) + +assert live_direct == live_ordinary +assert live_direct.startswith(" Result } else { "memory" }; - Ok(w_str_new(&format!( + // baseobjspace.py:115-117 `getrepr` returns `space.newtext(...)` for + // both the live and released labels. + Ok(w_str_new_managed(&format!( "<{label} at {}>", crate::display::repr_addr(mv as usize) ))) From d82f02af98ebd6b8973c9d92ffe62592caaca201 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 10:07:45 +0900 Subject: [PATCH 30/52] gc: collect weakref reprs --- ...eakref_repr_collectable.cranelift.jitstats | 15 ++++++ ...c_weakref_repr_collectable.dynasm.jitstats | 15 ++++++ .../synth/gc_weakref_repr_collectable.py | 50 +++++++++++++++++++ .../gc_weakref_repr_collectable.wasm.jitstats | 15 ++++++ .../src/module/_weakref/interp__weakref.rs | 4 +- 5 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_weakref_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_weakref_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_weakref_repr_collectable.py create mode 100644 pyre/bench/synth/gc_weakref_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_weakref_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_weakref_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_weakref_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_weakref_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_weakref_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_weakref_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_weakref_repr_collectable.py b/pyre/bench/synth/gc_weakref_repr_collectable.py new file mode 100644 index 00000000000..dbadf03f58f --- /dev/null +++ b/pyre/bench/synth/gc_weakref_repr_collectable.py @@ -0,0 +1,50 @@ +# pyre-check: no-cpython +import gc +import weakref + + +class Referent: + pass + + +class CallableReferent: + def __call__(self): + pass + + +referent = Referent() +callable_referent = CallableReferent() +reference = weakref.ref(referent) +proxy = weakref.proxy(referent) +callable_proxy = weakref.proxy(callable_referent) + +live_results = ( + weakref.ReferenceType.__repr__(reference), + repr(reference), + weakref.ProxyType.__repr__(proxy), + repr(proxy), + weakref.CallableProxyType.__repr__(callable_proxy), + repr(callable_proxy), +) + +for result in live_results: + assert any(obj is result for obj in gc.get_objects()) + +del referent +del callable_referent +gc.collect() + +dead_results = ( + weakref.ReferenceType.__repr__(reference), + repr(reference), + weakref.ProxyType.__repr__(proxy), + repr(proxy), + weakref.CallableProxyType.__repr__(callable_proxy), + repr(callable_proxy), +) + +for result in dead_results: + assert "; dead>" in result + assert any(obj is result for obj in gc.get_objects()) + +print("weakref repr results are collectable") diff --git a/pyre/bench/synth/gc_weakref_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_weakref_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_weakref_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/module/_weakref/interp__weakref.rs b/pyre/pyre-interpreter/src/module/_weakref/interp__weakref.rs index 3bc03ff2747..3ba3ddd1802 100644 --- a/pyre/pyre-interpreter/src/module/_weakref/interp__weakref.rs +++ b/pyre/pyre-interpreter/src/module/_weakref/interp__weakref.rs @@ -732,7 +732,9 @@ pub fn descr__repr__(args: &[PyObjectRef]) -> Result { format!("; to '{}'", objtype_name) }; let addr = w_self as usize; - Ok(pyre_object::w_str_new(&format!( + // W_WeakrefBase.descr__repr__ delegates to W_Root.getrepr, whose result + // is `space.newtext(...)` for refs and both proxy kinds, live or dead. + Ok(pyre_object::w_str_new_managed(&format!( "<{} at {}{}>", type_name, crate::display::repr_addr(addr), From eaf62b0beec9388e9b973a4e21d35b0a50521ae5 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 10:25:58 +0900 Subject: [PATCH 31/52] gc: collect mmap reprs --- ...c_mmap_repr_collectable.cranelift.jitstats | 15 +++++++++++ .../gc_mmap_repr_collectable.dynasm.jitstats | 15 +++++++++++ pyre/bench/synth/gc_mmap_repr_collectable.py | 25 +++++++++++++++++++ .../src/module/mmap/interp_mmap.rs | 6 +++-- 4 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 pyre/bench/synth/gc_mmap_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_mmap_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_mmap_repr_collectable.py diff --git a/pyre/bench/synth/gc_mmap_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_mmap_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_mmap_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_mmap_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_mmap_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_mmap_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_mmap_repr_collectable.py b/pyre/bench/synth/gc_mmap_repr_collectable.py new file mode 100644 index 00000000000..5e719008b41 --- /dev/null +++ b/pyre/bench/synth/gc_mmap_repr_collectable.py @@ -0,0 +1,25 @@ +# pyre-check: no-cpython +# pyre-check: skip-backends=wasm +import gc +import mmap + + +mapping = mmap.mmap(-1, 1) +live_direct = mmap.mmap.__repr__(mapping) +live_ordinary = repr(mapping) + +assert live_direct == live_ordinary +assert "closed=False" in live_direct +assert any(obj is live_direct for obj in gc.get_objects()) +assert any(obj is live_ordinary for obj in gc.get_objects()) + +mapping.close() +closed_direct = mmap.mmap.__repr__(mapping) +closed_ordinary = repr(mapping) + +assert closed_direct == closed_ordinary +assert closed_direct == "" +assert any(obj is closed_direct for obj in gc.get_objects()) +assert any(obj is closed_ordinary for obj in gc.get_objects()) + +print("mmap repr results are collectable") diff --git a/pyre/pyre-interpreter/src/module/mmap/interp_mmap.rs b/pyre/pyre-interpreter/src/module/mmap/interp_mmap.rs index bbb6acfed51..aeeb1244e60 100644 --- a/pyre/pyre-interpreter/src/module/mmap/interp_mmap.rs +++ b/pyre/pyre-interpreter/src/module/mmap/interp_mmap.rs @@ -1168,7 +1168,7 @@ fn init_mmap_type(ns: pyre_object::PyObjectRef) { // access / length / pos / offset. Capitalised True / // False matches CPython's bool repr. if mmap_get_attr_i64(obj, "_ptr") == 0 { - return Ok(pyre_object::w_str_new("")); + return Ok(pyre_object::w_str_new_managed("")); } let len = mmap_get_attr_i64(obj, "_len"); let pos = mmap_get_attr_i64(obj, "_pos"); @@ -1180,7 +1180,9 @@ fn init_mmap_type(ns: pyre_object::PyObjectRef) { x if x == MMAP_ACCESS_COPY => "ACCESS_COPY", _ => "ACCESS_DEFAULT", }; - Ok(pyre_object::w_str_new(&format!( + // W_MMap.descr_repr returns `space.newtext(...)` for both + // live and closed mappings. + Ok(pyre_object::w_str_new_managed(&format!( "" ))) }, From f310d67c59de8ff57cc8b9319225a33b706f847a Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 11:01:08 +0900 Subject: [PATCH 32/52] gc: collect FileIO reprs --- ...fileio_repr_collectable.cranelift.jitstats | 15 ++++++++ ...gc_fileio_repr_collectable.dynasm.jitstats | 15 ++++++++ .../bench/synth/gc_fileio_repr_collectable.py | 34 +++++++++++++++++++ pyre/pyre-interpreter/src/builtins.rs | 14 ++++---- 4 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 pyre/bench/synth/gc_fileio_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_fileio_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_fileio_repr_collectable.py diff --git a/pyre/bench/synth/gc_fileio_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_fileio_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_fileio_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_fileio_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_fileio_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_fileio_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_fileio_repr_collectable.py b/pyre/bench/synth/gc_fileio_repr_collectable.py new file mode 100644 index 00000000000..c6118981fbb --- /dev/null +++ b/pyre/bench/synth/gc_fileio_repr_collectable.py @@ -0,0 +1,34 @@ +# pyre-check: no-cpython +# pyre-check: skip-backends=wasm +import _io +import gc + + +file = _io.FileIO(__file__, "r") +name_direct = _io.FileIO.__repr__(file) +name_ordinary = repr(file) + +assert name_direct == name_ordinary +assert " name=" in name_direct +assert any(obj is name_direct for obj in gc.get_objects()) +assert any(obj is name_ordinary for obj in gc.get_objects()) + +del file.name +fd_direct = _io.FileIO.__repr__(file) +fd_ordinary = repr(file) + +assert fd_direct == fd_ordinary +assert " fd=" in fd_direct +assert any(obj is fd_direct for obj in gc.get_objects()) +assert any(obj is fd_ordinary for obj in gc.get_objects()) + +file.close() +closed_direct = _io.FileIO.__repr__(file) +closed_ordinary = repr(file) + +assert closed_direct == closed_ordinary +assert closed_direct == "<_io.FileIO [closed]>" +assert any(obj is closed_direct for obj in gc.get_objects()) +assert any(obj is closed_ordinary for obj in gc.get_objects()) + +print("FileIO repr results are collectable") diff --git a/pyre/pyre-interpreter/src/builtins.rs b/pyre/pyre-interpreter/src/builtins.rs index b67e21ccede..ef8be7a5a96 100644 --- a/pyre/pyre-interpreter/src/builtins.rs +++ b/pyre/pyre-interpreter/src/builtins.rs @@ -15150,7 +15150,9 @@ fn fileio_method_repr(args: &[PyObjectRef]) -> Result"))); + return Ok(pyre_object::w_str_new_managed(&format!( + "<{repr_type} [closed]>" + ))); } let closefd = if file_closefd(self_obj) { "True" @@ -15175,11 +15177,11 @@ fn fileio_method_repr(args: &[PyObjectRef]) -> Result" - ))) + // W_FileIO.repr_w returns `space.newtext(...)` for the name, fd, and + // closed forms. + Ok(pyre_object::w_str_from_wtf8_managed( + crate::display::wtf8_format!(format!("<{repr_type} "), body, ">"), + )) } /// `_io.FileIO.__init__` — PyPy `W_FileIO.descr_init`. From 7e2dddfcc07df79d930e9eef143c1e48888a698d Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 11:32:10 +0900 Subject: [PATCH 33/52] gc: collect exception reprs --- ...eption_repr_collectable.cranelift.jitstats | 15 +++++++++ ...exception_repr_collectable.dynasm.jitstats | 15 +++++++++ .../synth/gc_exception_repr_collectable.py | 31 +++++++++++++++++++ ...c_exception_repr_collectable.wasm.jitstats | 15 +++++++++ pyre/pyre-interpreter/src/builtins.rs | 4 ++- 5 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_exception_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_exception_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_exception_repr_collectable.py create mode 100644 pyre/bench/synth/gc_exception_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_exception_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_exception_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_exception_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_exception_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_exception_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_exception_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_exception_repr_collectable.py b/pyre/bench/synth/gc_exception_repr_collectable.py new file mode 100644 index 00000000000..35c52b1aaf2 --- /dev/null +++ b/pyre/bench/synth/gc_exception_repr_collectable.py @@ -0,0 +1,31 @@ +# pyre-check: no-cpython +import gc + + +empty = ValueError() +single = ValueError("x") +multiple = ValueError("x", 1) + +empty_direct = BaseException.__repr__(empty) +empty_ordinary = repr(empty) +single_direct = BaseException.__repr__(single) +single_ordinary = repr(single) +multiple_direct = BaseException.__repr__(multiple) +multiple_ordinary = repr(multiple) + +assert empty_direct == empty_ordinary == "ValueError()" +assert single_direct == single_ordinary == "ValueError('x')" +assert multiple_direct == multiple_ordinary == "ValueError('x', 1)" + +results = ( + empty_direct, + empty_ordinary, + single_direct, + single_ordinary, + multiple_direct, + multiple_ordinary, +) +for result in results: + assert any(obj is result for obj in gc.get_objects()) + +print("exception repr results are collectable") diff --git a/pyre/bench/synth/gc_exception_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_exception_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_exception_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/builtins.rs b/pyre/pyre-interpreter/src/builtins.rs index ef8be7a5a96..9275659dba0 100644 --- a/pyre/pyre-interpreter/src/builtins.rs +++ b/pyre/pyre-interpreter/src/builtins.rs @@ -7627,7 +7627,9 @@ fn exception_str_method(args: &[PyObjectRef]) -> crate::PyResult { /// alone and reads the receiver's own class name. fn exception_repr_method(args: &[PyObjectRef]) -> crate::PyResult { let obj = args[0]; - Ok(pyre_object::w_str_from_wtf8(unsafe { + // W_BaseException.descr_repr returns `space.newtext(clsname + args_repr)` + // for the zero-, one-, and multi-argument forms. + Ok(pyre_object::w_str_from_wtf8_managed(unsafe { crate::display::py_repr_wtf8(obj)? })) } From 4f967aa598c0b493941f2a20a16ad247d83c7a40 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 12:28:03 +0900 Subject: [PATCH 34/52] gc: collect exception str results --- ...ception_str_collectable.cranelift.jitstats | 15 ++++ ..._exception_str_collectable.dynasm.jitstats | 15 ++++ .../synth/gc_exception_str_collectable.py | 53 +++++++++++++ ...gc_exception_str_collectable.wasm.jitstats | 15 ++++ pyre/pyre-interpreter/src/builtins.rs | 75 +++++++++++++++---- 5 files changed, 159 insertions(+), 14 deletions(-) create mode 100644 pyre/bench/synth/gc_exception_str_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_exception_str_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_exception_str_collectable.py create mode 100644 pyre/bench/synth/gc_exception_str_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_exception_str_collectable.cranelift.jitstats b/pyre/bench/synth/gc_exception_str_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_exception_str_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_exception_str_collectable.dynasm.jitstats b/pyre/bench/synth/gc_exception_str_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_exception_str_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_exception_str_collectable.py b/pyre/bench/synth/gc_exception_str_collectable.py new file mode 100644 index 00000000000..40eb34e171c --- /dev/null +++ b/pyre/bench/synth/gc_exception_str_collectable.py @@ -0,0 +1,53 @@ +# pyre-check: no-cpython +import gc + + +class Render: + def __init__(self, result): + self.result = result + + def __str__(self): + return self.result + + +runtime_text = "runtime-exception-value-" + str(id(gc)) +rendered_text = "rendered-exception-value-" + str(id(runtime_text)) + +empty = ValueError() +single_text = ValueError(runtime_text) +single_object = ValueError(Render(rendered_text)) +multiple = ValueError(runtime_text, 1) +special = KeyError(runtime_text) + +empty_direct = BaseException.__str__(empty) +empty_ordinary = str(empty) +text_direct = BaseException.__str__(single_text) +text_ordinary = str(single_text) +object_direct = BaseException.__str__(single_object) +object_ordinary = str(single_object) +multiple_direct = BaseException.__str__(multiple) +multiple_ordinary = str(multiple) +special_direct = KeyError.__str__(special) +special_ordinary = str(special) + +assert empty_direct is empty_ordinary +assert text_direct is text_ordinary is runtime_text +assert object_direct is object_ordinary is rendered_text +assert multiple_direct == multiple_ordinary +assert special_direct == special_ordinary == repr(runtime_text) + +# The empty result is the translated `space.newtext('')` prebuilt. The +# dynamic results below must instead be ordinary, collectable GC objects. +for result in ( + text_direct, + text_ordinary, + object_direct, + object_ordinary, + multiple_direct, + multiple_ordinary, + special_direct, + special_ordinary, +): + assert any(obj is result for obj in gc.get_objects()) + +print("exception str results preserve identity and are collectable") diff --git a/pyre/bench/synth/gc_exception_str_collectable.wasm.jitstats b/pyre/bench/synth/gc_exception_str_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_exception_str_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/builtins.rs b/pyre/pyre-interpreter/src/builtins.rs index 9275659dba0..5fc3d9c7467 100644 --- a/pyre/pyre-interpreter/src/builtins.rs +++ b/pyre/pyre-interpreter/src/builtins.rs @@ -7603,9 +7603,46 @@ fn exc_system_exit_init(args: &[PyObjectRef]) -> crate::PyResult { /// which reports the args alone. It is what `BaseException.__str__(exc)` /// runs even when `exc`'s own class registers a `descr_str` override. fn base_exception_str_method(args: &[PyObjectRef]) -> crate::PyResult { - let obj = args[0]; - let text = unsafe { crate::display::base_exception_str_wtf8(obj)? }; - Ok(pyre_object::w_str_from_wtf8(text)) + // `W_BaseException.descr_str` reads the internal `args_w` list directly: + // no args returns the empty text singleton, one arg returns + // `space.str(args_w[0])` unchanged, and several args stringify a fresh + // tuple. In particular, flattening the one-arg result through WTF-8 + // loses both its identity and its managed lifetime. + let _roots = pyre_object::gc_roots::push_roots(); + let obj_slot = pyre_object::gc_roots::pin_roots(&[args[0]]); + let obj = pyre_object::gc_roots::shadow_stack_get(obj_slot); + let stored = unsafe { pyre_object::interp_exceptions::w_exception_get_args_storage(obj) }; + let len = if stored.is_null() { + 0 + } else if unsafe { pyre_object::is_list(stored) } { + unsafe { pyre_object::w_list_len(stored) } + } else if unsafe { pyre_object::is_tuple(stored) } { + unsafe { pyre_object::w_tuple_len(stored) } + } else { + 0 + }; + if len == 0 { + return Ok(w_str_new("")); + } + if len == 1 { + let first = if unsafe { pyre_object::is_list(stored) } { + unsafe { pyre_object::w_list_getitem(stored, 0) } + } else { + unsafe { pyre_object::w_tuple_getitem(stored, 0) } + } + .unwrap_or(pyre_object::PY_NULL); + pyre_object::gc_roots::pin_root(first); + let first_slot = pyre_object::gc_roots::shadow_stack_len() - 1; + return builtin_str(&[pyre_object::gc_roots::shadow_stack_get(first_slot)]); + } + let tuple = unsafe { + pyre_object::interp_exceptions::w_exception_get_args( + pyre_object::gc_roots::shadow_stack_get(obj_slot), + ) + }; + pyre_object::gc_roots::pin_root(tuple); + let tuple_slot = pyre_object::gc_roots::shadow_stack_len() - 1; + builtin_str(&[pyre_object::gc_roots::shadow_stack_get(tuple_slot)]) } /// The `descr_str` of the class that registers one, falling back to @@ -7613,13 +7650,18 @@ fn base_exception_str_method(args: &[PyObjectRef]) -> crate::PyResult { /// (`KeyError('a', 'b')`, an `OSError` with neither errno nor strerror). fn exception_str_method(args: &[PyObjectRef]) -> crate::PyResult { let obj = args[0]; - let text = unsafe { - match crate::display::exception_kind_str_wtf8(obj)? { - Some(s) => s, - None => crate::display::base_exception_str_wtf8(obj)?, - } + let Some(text) = (unsafe { crate::display::exception_kind_str_wtf8(obj)? }) else { + // The subclass has no `descr_str` override for this argument shape, + // so inherit `W_BaseException.descr_str` as PyPy does. Calling the + // object-returning path matters for one argument: `space.str(arg)` + // preserves an exact str's identity instead of flattening it through + // WTF-8 and allocating a replacement. + return base_exception_str_method(args); }; - Ok(pyre_object::w_str_from_wtf8(text)) + // A builtin override (KeyError / OSError / UnicodeError / SyntaxError) + // constructs a fresh text result. It is an ordinary GC object, not a + // prebuilt constant tied to the descriptor. + Ok(pyre_object::w_str_from_wtf8_managed(text)) } /// `interp_exceptions.py:135-151 W_BaseException.descr_repr` — every builtin @@ -9389,11 +9431,16 @@ pub(crate) fn builtin_str(args: &[PyObjectRef]) -> Result Date: Wed, 12 Aug 2026 12:43:23 +0900 Subject: [PATCH 35/52] gc: collect exception group render results --- ...roup_render_collectable.cranelift.jitstats | 15 +++++++++++++ ...n_group_render_collectable.dynasm.jitstats | 15 +++++++++++++ .../gc_exception_group_render_collectable.py | 22 +++++++++++++++++++ ...ion_group_render_collectable.wasm.jitstats | 15 +++++++++++++ pyre/pyre-interpreter/src/builtins.rs | 4 ++-- 5 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 pyre/bench/synth/gc_exception_group_render_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_exception_group_render_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_exception_group_render_collectable.py create mode 100644 pyre/bench/synth/gc_exception_group_render_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_exception_group_render_collectable.cranelift.jitstats b/pyre/bench/synth/gc_exception_group_render_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_exception_group_render_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_exception_group_render_collectable.dynasm.jitstats b/pyre/bench/synth/gc_exception_group_render_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_exception_group_render_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_exception_group_render_collectable.py b/pyre/bench/synth/gc_exception_group_render_collectable.py new file mode 100644 index 00000000000..760dfa68b39 --- /dev/null +++ b/pyre/bench/synth/gc_exception_group_render_collectable.py @@ -0,0 +1,22 @@ +# pyre-check: no-cpython +import gc + + +message = "runtime-exception-group-message-" + str(id(gc)) +leaf_message = "runtime-exception-group-leaf-" + str(id(message)) +group = ExceptionGroup(message, [ValueError(leaf_message)]) + +ordinary_str = str(group) +direct_str = ExceptionGroup.__str__(group) +ordinary_repr = repr(group) +direct_repr = ExceptionGroup.__repr__(group) + +assert ordinary_str == direct_str == message + " (1 sub-exception)" +assert ordinary_repr == direct_repr +assert message in ordinary_repr +assert leaf_message in ordinary_repr + +for result in (ordinary_str, direct_str, ordinary_repr, direct_repr): + assert any(obj is result for obj in gc.get_objects()) + +print("exception group render results are collectable") diff --git a/pyre/bench/synth/gc_exception_group_render_collectable.wasm.jitstats b/pyre/bench/synth/gc_exception_group_render_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_exception_group_render_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/builtins.rs b/pyre/pyre-interpreter/src/builtins.rs index 5fc3d9c7467..983496a7554 100644 --- a/pyre/pyre-interpreter/src/builtins.rs +++ b/pyre/pyre-interpreter/src/builtins.rs @@ -9027,7 +9027,7 @@ fn exception_group_str(args: &[PyObjectRef]) -> Result Result { @@ -9074,7 +9074,7 @@ fn exception_group_repr(args: &[PyObjectRef]) -> Result Date: Wed, 12 Aug 2026 12:58:06 +0900 Subject: [PATCH 36/52] gc: collect bound method reprs --- ...method_repr_collectable.cranelift.jitstats | 15 ++++++++++++++ ...nd_method_repr_collectable.dynasm.jitstats | 15 ++++++++++++++ .../synth/gc_bound_method_repr_collectable.py | 20 +++++++++++++++++++ ...ound_method_repr_collectable.wasm.jitstats | 15 ++++++++++++++ pyre/pyre-interpreter/src/function.rs | 10 +++------- 5 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 pyre/bench/synth/gc_bound_method_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_bound_method_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_bound_method_repr_collectable.py create mode 100644 pyre/bench/synth/gc_bound_method_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_bound_method_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_bound_method_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_bound_method_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_bound_method_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_bound_method_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_bound_method_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_bound_method_repr_collectable.py b/pyre/bench/synth/gc_bound_method_repr_collectable.py new file mode 100644 index 00000000000..09e5fa319df --- /dev/null +++ b/pyre/bench/synth/gc_bound_method_repr_collectable.py @@ -0,0 +1,20 @@ +# pyre-check: no-cpython +import gc + + +class RuntimeOwner: + def runtime_method(self): + pass + + +owner = RuntimeOwner() +method = owner.runtime_method +ordinary = repr(method) +direct = type(method).__repr__(method) + +assert ordinary == direct +assert "RuntimeOwner.runtime_method" in ordinary +assert any(obj is ordinary for obj in gc.get_objects()) +assert any(obj is direct for obj in gc.get_objects()) + +print("bound method repr results are collectable") diff --git a/pyre/bench/synth/gc_bound_method_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_bound_method_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_bound_method_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/function.rs b/pyre/pyre-interpreter/src/function.rs index 4ddde28e86f..d112d59f8c5 100644 --- a/pyre/pyre-interpreter/src/function.rs +++ b/pyre/pyre-interpreter/src/function.rs @@ -2873,13 +2873,9 @@ pub unsafe fn descr_method_repr(obj: PyObjectRef) -> Result" - ))) + Ok(pyre_object::w_str_from_wtf8_managed( + crate::display::wtf8_format!(""), + )) } #[inline] From 92cbe989cd32b89cd66d40bddee0ac262f6bd5a5 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 13:12:47 +0900 Subject: [PATCH 37/52] gc: collect super reprs --- ...c_super_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ .../gc_super_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ pyre/bench/synth/gc_super_repr_collectable.py | 18 ++++++++++++++++++ .../gc_super_repr_collectable.wasm.jitstats | 15 +++++++++++++++ pyre/pyre-interpreter/src/typedef.rs | 2 +- 5 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_super_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_super_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_super_repr_collectable.py create mode 100644 pyre/bench/synth/gc_super_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_super_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_super_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_super_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_super_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_super_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_super_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_super_repr_collectable.py b/pyre/bench/synth/gc_super_repr_collectable.py new file mode 100644 index 00000000000..15184de0493 --- /dev/null +++ b/pyre/bench/synth/gc_super_repr_collectable.py @@ -0,0 +1,18 @@ +# pyre-check: no-cpython +import gc + + +class RuntimeOwner: + pass + + +owner = RuntimeOwner() +proxy = super(RuntimeOwner, owner) +ordinary = repr(proxy) +direct = super.__repr__(proxy) + +assert ordinary == direct == ", >" +assert any(obj is ordinary for obj in gc.get_objects()) +assert any(obj is direct for obj in gc.get_objects()) + +print("super repr results are collectable") diff --git a/pyre/bench/synth/gc_super_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_super_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_super_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/typedef.rs b/pyre/pyre-interpreter/src/typedef.rs index 2cbc4c38e41..79f656bc277 100644 --- a/pyre/pyre-interpreter/src/typedef.rs +++ b/pyre/pyre-interpreter/src/typedef.rs @@ -4006,7 +4006,7 @@ fn super_descr_repr(args: &[PyObjectRef]) -> Result pyre_object::w_type_get_name(bound_type) }) }; - Ok(w_str_new(&format!( + Ok(pyre_object::w_str_new_managed(&format!( ", {}>", start_name, bound_name ))) From 234889857353d1a2cd5881aa29f128f2233e6d79 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 13:27:45 +0900 Subject: [PATCH 38/52] gc: collect union reprs --- .../gc_union_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ .../gc_union_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ pyre/bench/synth/gc_union_repr_collectable.py | 13 +++++++++++++ .../synth/gc_union_repr_collectable.wasm.jitstats | 15 +++++++++++++++ pyre/pyre-interpreter/src/typedef.rs | 2 +- 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_union_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_union_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_union_repr_collectable.py create mode 100644 pyre/bench/synth/gc_union_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_union_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_union_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_union_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_union_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_union_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_union_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_union_repr_collectable.py b/pyre/bench/synth/gc_union_repr_collectable.py new file mode 100644 index 00000000000..9dcc1c645c3 --- /dev/null +++ b/pyre/bench/synth/gc_union_repr_collectable.py @@ -0,0 +1,13 @@ +# pyre-check: no-cpython +import gc + + +union = int | str +ordinary = repr(union) +direct = type(union).__repr__(union) + +assert ordinary == direct == "int | str" +assert any(obj is ordinary for obj in gc.get_objects()) +assert any(obj is direct for obj in gc.get_objects()) + +print("union repr results are collectable") diff --git a/pyre/bench/synth/gc_union_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_union_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_union_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/typedef.rs b/pyre/pyre-interpreter/src/typedef.rs index 79f656bc277..5b011ec82ad 100644 --- a/pyre/pyre-interpreter/src/typedef.rs +++ b/pyre/pyre-interpreter/src/typedef.rs @@ -9626,7 +9626,7 @@ fn union_repr_method(args: &[PyObjectRef]) -> crate::PyResult { "descriptor '__repr__' requires a 'types.UnionType' object", )); } - Ok(pyre_object::w_str_from_wtf8(unsafe { + Ok(pyre_object::w_str_from_wtf8_managed(unsafe { crate::display::py_repr_wtf8(self_)? })) } From 2ecd54fd7fe1d40a36d1c1a4a5ebc99ec2e41c0a Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 13:43:21 +0900 Subject: [PATCH 39/52] gc: collect function reprs --- ...function_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ ...gc_function_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ .../bench/synth/gc_function_repr_collectable.py | 17 +++++++++++++++++ .../gc_function_repr_collectable.wasm.jitstats | 15 +++++++++++++++ pyre/pyre-interpreter/src/typedef.rs | 2 +- 5 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_function_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_function_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_function_repr_collectable.py create mode 100644 pyre/bench/synth/gc_function_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_function_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_function_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_function_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_function_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_function_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_function_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_function_repr_collectable.py b/pyre/bench/synth/gc_function_repr_collectable.py new file mode 100644 index 00000000000..70cd4ab2fb0 --- /dev/null +++ b/pyre/bench/synth/gc_function_repr_collectable.py @@ -0,0 +1,17 @@ +# pyre-check: no-cpython +import gc + + +def runtime_function(): + pass + + +ordinary = repr(runtime_function) +direct = type(runtime_function).__repr__(runtime_function) + +assert ordinary == direct +assert ordinary.startswith("", crate::display::repr_addr(function as usize) )); - Ok(pyre_object::w_str_from_wtf8(repr)) + Ok(pyre_object::w_str_from_wtf8_managed(repr)) }, 1, ), From 2d668fbc8371d05f74f020e7b641cc9b40d9130b Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 14:06:12 +0900 Subject: [PATCH 40/52] gc: collect builtin function reprs --- ...n_function_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ ...ltin_function_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ .../synth/gc_builtin_function_repr_collectable.py | 13 +++++++++++++ ...uiltin_function_repr_collectable.wasm.jitstats | 15 +++++++++++++++ pyre/pyre-interpreter/src/typedef.rs | 2 +- 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_builtin_function_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_builtin_function_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_builtin_function_repr_collectable.py create mode 100644 pyre/bench/synth/gc_builtin_function_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_builtin_function_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_builtin_function_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_builtin_function_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_builtin_function_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_builtin_function_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_builtin_function_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_builtin_function_repr_collectable.py b/pyre/bench/synth/gc_builtin_function_repr_collectable.py new file mode 100644 index 00000000000..3d03a14b368 --- /dev/null +++ b/pyre/bench/synth/gc_builtin_function_repr_collectable.py @@ -0,0 +1,13 @@ +# pyre-check: no-cpython +import gc + + +functions = (len, [].append) +for function in functions: + ordinary = repr(function) + direct = type(function).__repr__(function) + assert ordinary == direct + assert any(obj is ordinary for obj in gc.get_objects()) + assert any(obj is direct for obj in gc.get_objects()) + +print("builtin function repr results are collectable") diff --git a/pyre/bench/synth/gc_builtin_function_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_builtin_function_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_builtin_function_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/typedef.rs b/pyre/pyre-interpreter/src/typedef.rs index c9008726bb0..3356467f6ad 100644 --- a/pyre/pyre-interpreter/src/typedef.rs +++ b/pyre/pyre-interpreter/src/typedef.rs @@ -13893,7 +13893,7 @@ fn init_builtin_function_type(ns: PyObjectRef) { } else { unsafe { crate::function::function_get_self_or_none(carrier) } }; - Ok(pyre_object::w_str_new(&unsafe { + Ok(pyre_object::w_str_new_managed(&unsafe { crate::function::builtin_function_repr_text(name, w_self) })) }, From 1195dfdcbe23b12b2cb5a2ca9529d9543ce2cba9 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 14:07:08 +0900 Subject: [PATCH 41/52] ci: skip mmap repr fixture when unavailable --- pyre/bench/synth/gc_mmap_repr_collectable.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pyre/bench/synth/gc_mmap_repr_collectable.py b/pyre/bench/synth/gc_mmap_repr_collectable.py index 5e719008b41..e7358b70662 100644 --- a/pyre/bench/synth/gc_mmap_repr_collectable.py +++ b/pyre/bench/synth/gc_mmap_repr_collectable.py @@ -4,6 +4,13 @@ import mmap +# pyre's mmap implementation is currently Unix-only. The module still +# imports on Windows so callers can feature-detect it, but it does not expose +# mmap.mmap there. +if not hasattr(mmap, "mmap"): + print("mmap repr results are collectable (mmap unavailable)") + raise SystemExit + mapping = mmap.mmap(-1, 1) live_direct = mmap.mmap.__repr__(mapping) live_ordinary = repr(mapping) From dd5ef4e2e73f389949a4c00ef48e99dbab03ee11 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 14:57:53 +0900 Subject: [PATCH 42/52] gc: collect getset descriptor reprs --- ...descriptor_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ ...et_descriptor_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ .../gc_getset_descriptor_repr_collectable.py | 13 +++++++++++++ ...tset_descriptor_repr_collectable.wasm.jitstats | 15 +++++++++++++++ pyre/pyre-interpreter/src/typedef.rs | 2 +- 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_getset_descriptor_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_getset_descriptor_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_getset_descriptor_repr_collectable.py create mode 100644 pyre/bench/synth/gc_getset_descriptor_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_getset_descriptor_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_getset_descriptor_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_getset_descriptor_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_getset_descriptor_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_getset_descriptor_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_getset_descriptor_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_getset_descriptor_repr_collectable.py b/pyre/bench/synth/gc_getset_descriptor_repr_collectable.py new file mode 100644 index 00000000000..0bb2dda4cef --- /dev/null +++ b/pyre/bench/synth/gc_getset_descriptor_repr_collectable.py @@ -0,0 +1,13 @@ +# pyre-check: no-cpython +import gc + + +descriptor = type.__dict__["__name__"] +ordinary = repr(descriptor) +direct = type(descriptor).__repr__(descriptor) + +assert ordinary == direct +assert any(obj is ordinary for obj in gc.get_objects()) +assert any(obj is direct for obj in gc.get_objects()) + +print("getset descriptor repr results are collectable") diff --git a/pyre/bench/synth/gc_getset_descriptor_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_getset_descriptor_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_getset_descriptor_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/typedef.rs b/pyre/pyre-interpreter/src/typedef.rs index 3356467f6ad..2e0ecf3f399 100644 --- a/pyre/pyre-interpreter/src/typedef.rs +++ b/pyre/pyre-interpreter/src/typedef.rs @@ -10376,7 +10376,7 @@ fn init_getset_descriptor_type(ns: PyObjectRef) { "descriptor '__repr__' requires a 'getset_descriptor' object but received a '{received}'" ))); } - Ok(pyre_object::w_str_new(&unsafe { + Ok(pyre_object::w_str_new_managed(&unsafe { getset_descriptor_repr(descr) })) }, From 088386ba906ec6ce0c8c0f6db0bb47a82ba33a90 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 15:17:18 +0900 Subject: [PATCH 43/52] gc: collect member descriptor reprs --- ...scriptor_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ ..._descriptor_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ .../gc_member_descriptor_repr_collectable.py | 17 +++++++++++++++++ ...er_descriptor_repr_collectable.wasm.jitstats | 15 +++++++++++++++ pyre/pyre-interpreter/src/typedef.rs | 2 +- 5 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_member_descriptor_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_member_descriptor_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_member_descriptor_repr_collectable.py create mode 100644 pyre/bench/synth/gc_member_descriptor_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_member_descriptor_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_member_descriptor_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_member_descriptor_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_member_descriptor_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_member_descriptor_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_member_descriptor_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_member_descriptor_repr_collectable.py b/pyre/bench/synth/gc_member_descriptor_repr_collectable.py new file mode 100644 index 00000000000..6b58740211a --- /dev/null +++ b/pyre/bench/synth/gc_member_descriptor_repr_collectable.py @@ -0,0 +1,17 @@ +# pyre-check: no-cpython +import gc + + +class Container: + __slots__ = ("value",) + + +descriptor = Container.__dict__["value"] +ordinary = repr(descriptor) +direct = type(descriptor).__repr__(descriptor) + +assert ordinary == direct +assert any(obj is ordinary for obj in gc.get_objects()) +assert any(obj is direct for obj in gc.get_objects()) + +print("member descriptor repr results are collectable") diff --git a/pyre/bench/synth/gc_member_descriptor_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_member_descriptor_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_member_descriptor_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/typedef.rs b/pyre/pyre-interpreter/src/typedef.rs index 2e0ecf3f399..8aa9e5b2256 100644 --- a/pyre/pyre-interpreter/src/typedef.rs +++ b/pyre/pyre-interpreter/src/typedef.rs @@ -15646,7 +15646,7 @@ fn init_member_descriptor_type(ns: PyObjectRef) { "descriptor '__repr__' requires a 'member_descriptor' object", )); } - Ok(pyre_object::w_str_new(&unsafe { + Ok(pyre_object::w_str_new_managed(&unsafe { member_descriptor_repr(member) })) }, From 70682ec345973c61d041ccd806bebc5cde221551 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 15:35:15 +0900 Subject: [PATCH 44/52] gc: collect method descriptor reprs --- ...descriptor_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ ...od_descriptor_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ .../gc_method_descriptor_repr_collectable.py | 13 +++++++++++++ ...thod_descriptor_repr_collectable.wasm.jitstats | 15 +++++++++++++++ pyre/pyre-interpreter/src/typedef.rs | 2 +- 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_method_descriptor_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_method_descriptor_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_method_descriptor_repr_collectable.py create mode 100644 pyre/bench/synth/gc_method_descriptor_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_method_descriptor_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_method_descriptor_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_method_descriptor_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_method_descriptor_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_method_descriptor_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_method_descriptor_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_method_descriptor_repr_collectable.py b/pyre/bench/synth/gc_method_descriptor_repr_collectable.py new file mode 100644 index 00000000000..da392e27622 --- /dev/null +++ b/pyre/bench/synth/gc_method_descriptor_repr_collectable.py @@ -0,0 +1,13 @@ +# pyre-check: no-cpython +import gc + + +descriptor = list.__dict__["append"] +ordinary = repr(descriptor) +direct = type(descriptor).__repr__(descriptor) + +assert ordinary == direct +assert any(obj is ordinary for obj in gc.get_objects()) +assert any(obj is direct for obj in gc.get_objects()) + +print("method descriptor repr results are collectable") diff --git a/pyre/bench/synth/gc_method_descriptor_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_method_descriptor_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_method_descriptor_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/typedef.rs b/pyre/pyre-interpreter/src/typedef.rs index 8aa9e5b2256..f9b71739e54 100644 --- a/pyre/pyre-interpreter/src/typedef.rs +++ b/pyre/pyre-interpreter/src/typedef.rs @@ -14854,7 +14854,7 @@ fn init_method_descriptor_type(ns: PyObjectRef) { let name = crate::function::function_get_name(descr); let owner = crate::function::fget_func_objclass(descr)?; let owner_name = pyre_object::w_type_get_name(owner); - Ok(pyre_object::w_str_new(&format!( + Ok(pyre_object::w_str_new_managed(&format!( "" ))) }, From e3f2e816812b1166c8867ca19bafb0d7ac8535cb Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 15:52:51 +0900 Subject: [PATCH 45/52] gc: collect classmethod descriptor reprs --- ...descriptor_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ ...od_descriptor_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ .../gc_classmethod_descriptor_repr_collectable.py | 13 +++++++++++++ ...thod_descriptor_repr_collectable.wasm.jitstats | 15 +++++++++++++++ pyre/pyre-interpreter/src/typedef.rs | 2 +- 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.py create mode 100644 pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.py b/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.py new file mode 100644 index 00000000000..d510151122e --- /dev/null +++ b/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.py @@ -0,0 +1,13 @@ +# pyre-check: no-cpython +import gc + + +descriptor = dict.__dict__["fromkeys"] +ordinary = repr(descriptor) +direct = type(descriptor).__repr__(descriptor) + +assert ordinary == direct +assert any(obj is ordinary for obj in gc.get_objects()) +assert any(obj is direct for obj in gc.get_objects()) + +print("classmethod descriptor repr results are collectable") diff --git a/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/typedef.rs b/pyre/pyre-interpreter/src/typedef.rs index f9b71739e54..35eb89770ef 100644 --- a/pyre/pyre-interpreter/src/typedef.rs +++ b/pyre/pyre-interpreter/src/typedef.rs @@ -15014,7 +15014,7 @@ fn init_classmethod_descriptor_type(ns: PyObjectRef) { let name = crate::function::function_get_name(function); let owner = crate::function::fget_func_objclass(function)?; let owner_name = pyre_object::w_type_get_name(owner); - Ok(pyre_object::w_str_new(&format!( + Ok(pyre_object::w_str_new_managed(&format!( "" ))) }, From 044b249efaac83917a27267cb0eec9ef2c3d213b Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 16:16:41 +0900 Subject: [PATCH 46/52] ci: match mmap skip output on Windows --- pyre/bench/synth/gc_mmap_repr_collectable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyre/bench/synth/gc_mmap_repr_collectable.py b/pyre/bench/synth/gc_mmap_repr_collectable.py index e7358b70662..5b9149d4496 100644 --- a/pyre/bench/synth/gc_mmap_repr_collectable.py +++ b/pyre/bench/synth/gc_mmap_repr_collectable.py @@ -8,7 +8,7 @@ # imports on Windows so callers can feature-detect it, but it does not expose # mmap.mmap there. if not hasattr(mmap, "mmap"): - print("mmap repr results are collectable (mmap unavailable)") + print("mmap repr results are collectable") raise SystemExit mapping = mmap.mmap(-1, 1) From 80e945341b36be967b7675a1edbd78a0ea15d9e6 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 16:38:17 +0900 Subject: [PATCH 47/52] gc: collect method-wrapper reprs --- ...od_wrapper_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ ...ethod_wrapper_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ .../synth/gc_method_wrapper_repr_collectable.py | 12 ++++++++++++ ..._method_wrapper_repr_collectable.wasm.jitstats | 15 +++++++++++++++ pyre/pyre-interpreter/src/typedef.rs | 2 +- 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_method_wrapper_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_method_wrapper_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_method_wrapper_repr_collectable.py create mode 100644 pyre/bench/synth/gc_method_wrapper_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_method_wrapper_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_method_wrapper_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_method_wrapper_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_method_wrapper_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_method_wrapper_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_method_wrapper_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_method_wrapper_repr_collectable.py b/pyre/bench/synth/gc_method_wrapper_repr_collectable.py new file mode 100644 index 00000000000..fcb6712d28f --- /dev/null +++ b/pyre/bench/synth/gc_method_wrapper_repr_collectable.py @@ -0,0 +1,12 @@ +# pyre-check: no-cpython +import gc + +wrapper = (1).__add__ +ordinary = repr(wrapper) +direct = type(wrapper).__repr__(wrapper) + +assert ordinary == direct +assert any(obj is ordinary for obj in gc.get_objects()) +assert any(obj is direct for obj in gc.get_objects()) + +print("method-wrapper repr results are collectable") diff --git a/pyre/bench/synth/gc_method_wrapper_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_method_wrapper_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_method_wrapper_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/typedef.rs b/pyre/pyre-interpreter/src/typedef.rs index 35eb89770ef..4af98f7da05 100644 --- a/pyre/pyre-interpreter/src/typedef.rs +++ b/pyre/pyre-interpreter/src/typedef.rs @@ -14669,7 +14669,7 @@ fn init_method_wrapper_type(ns: PyObjectRef) { let type_name = crate::typedef::r#type(w_self) .map(|tp| unsafe { pyre_object::w_type_get_name(tp.as_ptr()) }) .unwrap_or("object"); - Ok(pyre_object::w_str_new(&format!( + Ok(pyre_object::w_str_new_managed(&format!( "", crate::display::repr_addr(w_self as usize) ))) From f68c5cb7e58971cb469d0e4e7a9185f42c9016c4 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 16:58:11 +0900 Subject: [PATCH 48/52] gc: collect type reprs --- .../gc_type_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ .../gc_type_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ pyre/bench/synth/gc_type_repr_collectable.py | 16 ++++++++++++++++ .../synth/gc_type_repr_collectable.wasm.jitstats | 15 +++++++++++++++ pyre/pyre-interpreter/src/typedef.rs | 2 +- 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_type_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_type_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_type_repr_collectable.py create mode 100644 pyre/bench/synth/gc_type_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_type_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_type_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_type_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_type_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_type_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_type_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_type_repr_collectable.py b/pyre/bench/synth/gc_type_repr_collectable.py new file mode 100644 index 00000000000..69f4834a57f --- /dev/null +++ b/pyre/bench/synth/gc_type_repr_collectable.py @@ -0,0 +1,16 @@ +# pyre-check: no-cpython +import gc + + +class Sample: + pass + + +ordinary = repr(Sample) +direct = type.__repr__(Sample) + +assert ordinary == direct +assert any(obj is ordinary for obj in gc.get_objects()) +assert any(obj is direct for obj in gc.get_objects()) + +print("type repr results are collectable") diff --git a/pyre/bench/synth/gc_type_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_type_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_type_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/typedef.rs b/pyre/pyre-interpreter/src/typedef.rs index 4af98f7da05..ef2362e2be6 100644 --- a/pyre/pyre-interpreter/src/typedef.rs +++ b/pyre/pyre-interpreter/src/typedef.rs @@ -10990,7 +10990,7 @@ fn init_type_type(ns: PyObjectRef) { "", crate::baseobjspace::type_repr_qualified_name(obj) ); - Ok(pyre_object::w_str_new(&rendered)) + Ok(pyre_object::w_str_new_managed(&rendered)) }, 1, ), From fb260d632857c940a08eb776819be3df171032d3 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 17:17:32 +0900 Subject: [PATCH 49/52] gc: collect cell reprs --- ...c_cell_repr_collectable.cranelift.jitstats | 15 ++++++++++++ .../gc_cell_repr_collectable.dynasm.jitstats | 15 ++++++++++++ pyre/bench/synth/gc_cell_repr_collectable.py | 24 +++++++++++++++++++ .../gc_cell_repr_collectable.wasm.jitstats | 15 ++++++++++++ pyre/pyre-interpreter/src/typedef.rs | 2 +- 5 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_cell_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_cell_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_cell_repr_collectable.py create mode 100644 pyre/bench/synth/gc_cell_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_cell_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_cell_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_cell_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_cell_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_cell_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_cell_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_cell_repr_collectable.py b/pyre/bench/synth/gc_cell_repr_collectable.py new file mode 100644 index 00000000000..007b014d74a --- /dev/null +++ b/pyre/bench/synth/gc_cell_repr_collectable.py @@ -0,0 +1,24 @@ +# pyre-check: no-cpython +import gc + + +def make_cell(value): + def inner(): + return value + + return inner.__closure__[0] + + +filled = make_cell(42) +empty = make_cell(42) +del empty.cell_contents + +for cell in (filled, empty): + ordinary = repr(cell) + direct = type(cell).__repr__(cell) + + assert ordinary == direct + assert any(obj is ordinary for obj in gc.get_objects()) + assert any(obj is direct for obj in gc.get_objects()) + +print("cell repr results are collectable") diff --git a/pyre/bench/synth/gc_cell_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_cell_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_cell_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/typedef.rs b/pyre/pyre-interpreter/src/typedef.rs index ef2362e2be6..e4c84eb8951 100644 --- a/pyre/pyre-interpreter/src/typedef.rs +++ b/pyre/pyre-interpreter/src/typedef.rs @@ -15817,7 +15817,7 @@ fn cell_descr_repr(args: &[PyObjectRef]) -> crate::PyResult { crate::display::repr_addr(value as usize) ) }; - Ok(w_str_new(&text)) + Ok(w_str_new_managed(&text)) } /// `nestedscope.py:934-952 Cell.typedef`, in source order. CPython 3.14 is From 1408a4fe4b717d9e37c7147a66102adb3128c2f1 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 17:37:51 +0900 Subject: [PATCH 50/52] gc: collect generator reprs --- ...erator_repr_collectable.cranelift.jitstats | 15 +++++++++++++++ ...generator_repr_collectable.dynasm.jitstats | 15 +++++++++++++++ .../synth/gc_generator_repr_collectable.py | 19 +++++++++++++++++++ ...c_generator_repr_collectable.wasm.jitstats | 15 +++++++++++++++ pyre/pyre-interpreter/src/typedef.rs | 2 +- 5 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 pyre/bench/synth/gc_generator_repr_collectable.cranelift.jitstats create mode 100644 pyre/bench/synth/gc_generator_repr_collectable.dynasm.jitstats create mode 100644 pyre/bench/synth/gc_generator_repr_collectable.py create mode 100644 pyre/bench/synth/gc_generator_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_generator_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_generator_repr_collectable.cranelift.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_generator_repr_collectable.cranelift.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_generator_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_generator_repr_collectable.dynasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_generator_repr_collectable.dynasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/bench/synth/gc_generator_repr_collectable.py b/pyre/bench/synth/gc_generator_repr_collectable.py new file mode 100644 index 00000000000..4f1872affad --- /dev/null +++ b/pyre/bench/synth/gc_generator_repr_collectable.py @@ -0,0 +1,19 @@ +# pyre-check: no-cpython +import gc + + +def generate(): + yield 1 + + +generator = generate() +ordinary = repr(generator) +direct = type(generator).__repr__(generator) + +assert ordinary == direct +assert any(obj is ordinary for obj in gc.get_objects()) +assert any(obj is direct for obj in gc.get_objects()) + +generator.close() + +print("generator repr results are collectable") diff --git a/pyre/bench/synth/gc_generator_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_generator_repr_collectable.wasm.jitstats new file mode 100644 index 00000000000..21df1dd3f43 --- /dev/null +++ b/pyre/bench/synth/gc_generator_repr_collectable.wasm.jitstats @@ -0,0 +1,15 @@ +bridges_compiled=0 +descr_set_absent=0 +descr_set_ambiguous=0 +descr_set_stale_absent=0 +fbw_blackhole_adopted_multi_frame=0 +fbw_blackhole_adopted_single_frame=0 +fbw_rolled_back_with_effects=0 +fbw_store_journal_rollback_failed=0 +field_pos_attached_misplaced=0 +field_pos_spec_misplaced=0 +guard_failures=0 +internal_compile_panics=0 +loops_aborted=0 +loops_compiled=0 +retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/typedef.rs b/pyre/pyre-interpreter/src/typedef.rs index e4c84eb8951..c078da54881 100644 --- a/pyre/pyre-interpreter/src/typedef.rs +++ b/pyre/pyre-interpreter/src/typedef.rs @@ -26665,7 +26665,7 @@ fn generator_frame(obj: PyObjectRef) -> *mut crate::pyframe::PyFrame { fn generator_descr_repr(args: &[PyObjectRef]) -> crate::PyResult { let name = generator_name_value(args[0], true)?; - Ok(w_str_new(&format!( + Ok(w_str_new_managed(&format!( "", unsafe { pyre_object::w_str_get_value(name) }, crate::display::repr_addr(args[0] as usize) From a3b84e48cff24938dcb7c96b273b0a8e5c446069 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 18:29:22 +0900 Subject: [PATCH 51/52] test: consolidate GC collectability fixtures --- pyre/bench/synth/gc_array_repr_collectable.py | 15 - .../synth/gc_array_tounicode_collectable.py | 12 - ..._array_tounicode_collectable.wasm.jitstats | 15 - ...method_repr_collectable.cranelift.jitstats | 15 - ...nd_method_repr_collectable.dynasm.jitstats | 15 - .../synth/gc_bound_method_repr_collectable.py | 20 -- ...ound_method_repr_collectable.wasm.jitstats | 15 - ...nction_repr_collectable.cranelift.jitstats | 15 - ..._function_repr_collectable.dynasm.jitstats | 15 - .../gc_builtin_function_repr_collectable.py | 13 - ...in_function_repr_collectable.wasm.jitstats | 15 - ...riptor_repr_collectable.cranelift.jitstats | 15 - ...escriptor_repr_collectable.dynasm.jitstats | 15 - ...classmethod_descriptor_repr_collectable.py | 13 - ..._descriptor_repr_collectable.wasm.jitstats | 15 - ...extvar_repr_collectable.cranelift.jitstats | 15 - ...ontextvar_repr_collectable.dynasm.jitstats | 15 - .../synth/gc_contextvar_repr_collectable.py | 20 -- ..._contextvar_repr_collectable.wasm.jitstats | 15 - ..._deque_repr_collectable.cranelift.jitstats | 15 - .../gc_deque_repr_collectable.dynasm.jitstats | 15 - pyre/bench/synth/gc_deque_repr_collectable.py | 12 - .../gc_deque_repr_collectable.wasm.jitstats | 15 - ...rentry_repr_collectable.cranelift.jitstats | 15 - ..._direntry_repr_collectable.dynasm.jitstats | 15 - .../synth/gc_direntry_repr_collectable.py | 16 - ...roup_render_collectable.cranelift.jitstats | 15 - ...n_group_render_collectable.dynasm.jitstats | 15 - .../gc_exception_group_render_collectable.py | 22 -- ...ion_group_render_collectable.wasm.jitstats | 15 - ...eption_repr_collectable.cranelift.jitstats | 15 - ...exception_repr_collectable.dynasm.jitstats | 15 - .../synth/gc_exception_repr_collectable.py | 31 -- ...c_exception_repr_collectable.wasm.jitstats | 15 - ...ception_str_collectable.cranelift.jitstats | 15 - ..._exception_str_collectable.dynasm.jitstats | 15 - .../synth/gc_exception_str_collectable.py | 53 ---- ...gc_exception_str_collectable.wasm.jitstats | 15 - ...fileio_repr_collectable.cranelift.jitstats | 15 - ...gc_fileio_repr_collectable.dynasm.jitstats | 15 - .../bench/synth/gc_fileio_repr_collectable.py | 34 --- ...nction_repr_collectable.cranelift.jitstats | 15 - ..._function_repr_collectable.dynasm.jitstats | 15 - .../synth/gc_function_repr_collectable.py | 17 -- ...gc_function_repr_collectable.wasm.jitstats | 15 - ..._alias_repr_collectable.cranelift.jitstats | 15 - ...ric_alias_repr_collectable.dynasm.jitstats | 15 - .../gc_generic_alias_repr_collectable.py | 17 -- ...neric_alias_repr_collectable.wasm.jitstats | 15 - ...riptor_repr_collectable.cranelift.jitstats | 15 - ...escriptor_repr_collectable.dynasm.jitstats | 15 - .../gc_getset_descriptor_repr_collectable.py | 13 - ..._descriptor_repr_collectable.wasm.jitstats | 15 - ...json_string_collectable.cranelift.jitstats | 15 - ...gc_json_string_collectable.dynasm.jitstats | 15 - .../bench/synth/gc_json_string_collectable.py | 67 ---- .../gc_json_string_collectable.wasm.jitstats | 15 - ...riptor_repr_collectable.cranelift.jitstats | 15 - ...escriptor_repr_collectable.dynasm.jitstats | 15 - .../gc_member_descriptor_repr_collectable.py | 17 -- ..._descriptor_repr_collectable.wasm.jitstats | 15 - ...ryview_repr_collectable.cranelift.jitstats | 15 - ...emoryview_repr_collectable.dynasm.jitstats | 15 - .../synth/gc_memoryview_repr_collectable.py | 23 -- ..._memoryview_repr_collectable.wasm.jitstats | 15 - ...riptor_repr_collectable.cranelift.jitstats | 15 - ...escriptor_repr_collectable.dynasm.jitstats | 15 - .../gc_method_descriptor_repr_collectable.py | 13 - ..._descriptor_repr_collectable.wasm.jitstats | 15 - ...c_mmap_repr_collectable.cranelift.jitstats | 15 - .../gc_mmap_repr_collectable.dynasm.jitstats | 15 - pyre/bench/synth/gc_mmap_repr_collectable.py | 32 -- ...ve_strings_collectable.cranelift.jitstats} | 0 ...ative_strings_collectable.dynasm.jitstats} | 0 .../synth/gc_native_strings_collectable.py | 60 ++++ ...kle_unicode_collectable.cranelift.jitstats | 15 - ...pickle_unicode_collectable.dynasm.jitstats | 15 - .../synth/gc_pickle_unicode_collectable.py | 19 -- ...c_pickle_unicode_collectable.wasm.jitstats | 15 - ...me_strings_collectable.cranelift.jitstats} | 0 ...ntime_strings_collectable.dynasm.jitstats} | 0 .../synth/gc_runtime_strings_collectable.py | 285 ++++++++++++++++++ ...runtime_strings_collectable.wasm.jitstats} | 0 ...espace_repr_collectable.cranelift.jitstats | 15 - ...namespace_repr_collectable.dynasm.jitstats | 15 - .../gc_simple_namespace_repr_collectable.py | 31 -- ...e_namespace_repr_collectable.wasm.jitstats | 15 - ..._match_repr_collectable.cranelift.jitstats | 15 - ...sre_match_repr_collectable.dynasm.jitstats | 15 - .../synth/gc_sre_match_repr_collectable.py | 13 - ...c_sre_match_repr_collectable.wasm.jitstats | 15 - ...attern_repr_collectable.cranelift.jitstats | 15 - ...e_pattern_repr_collectable.dynasm.jitstats | 15 - .../synth/gc_sre_pattern_repr_collectable.py | 13 - ...sre_pattern_repr_collectable.wasm.jitstats | 15 - ...c_sre_slice_collectable.cranelift.jitstats | 15 - .../gc_sre_slice_collectable.dynasm.jitstats | 15 - pyre/bench/synth/gc_sre_slice_collectable.py | 56 ---- .../gc_sre_slice_collectable.wasm.jitstats | 15 - ..._sub_output_collectable.cranelift.jitstats | 15 - ...sre_sub_output_collectable.dynasm.jitstats | 15 - .../synth/gc_sre_sub_output_collectable.py | 22 -- ...c_sre_sub_output_collectable.wasm.jitstats | 15 - ...uctseq_repr_collectable.cranelift.jitstats | 15 - ...structseq_repr_collectable.dynasm.jitstats | 15 - .../synth/gc_structseq_repr_collectable.py | 12 - ...c_structseq_repr_collectable.wasm.jitstats | 15 - ..._super_repr_collectable.cranelift.jitstats | 15 - .../gc_super_repr_collectable.dynasm.jitstats | 15 - pyre/bench/synth/gc_super_repr_collectable.py | 18 -- .../gc_super_repr_collectable.wasm.jitstats | 15 - ...ime_asctime_collectable.cranelift.jitstats | 15 - ...c_time_asctime_collectable.dynasm.jitstats | 15 - .../synth/gc_time_asctime_collectable.py | 19 -- ...me_strftime_collectable.cranelift.jitstats | 15 - ..._time_strftime_collectable.dynasm.jitstats | 15 - .../synth/gc_time_strftime_collectable.py | 17 -- ...a_normalize_collectable.cranelift.jitstats | 15 - ...data_normalize_collectable.dynasm.jitstats | 15 - .../gc_unicodedata_normalize_collectable.py | 34 --- ...dedata_normalize_collectable.wasm.jitstats | 15 - ..._union_repr_collectable.cranelift.jitstats | 15 - .../gc_union_repr_collectable.dynasm.jitstats | 15 - pyre/bench/synth/gc_union_repr_collectable.py | 13 - .../gc_union_repr_collectable.wasm.jitstats | 15 - ...akproxy_str_collectable.cranelift.jitstats | 15 - ..._weakproxy_str_collectable.dynasm.jitstats | 15 - .../synth/gc_weakproxy_str_collectable.py | 25 -- ...gc_weakproxy_str_collectable.wasm.jitstats | 15 - ...eakref_repr_collectable.cranelift.jitstats | 15 - ...c_weakref_repr_collectable.dynasm.jitstats | 15 - .../synth/gc_weakref_repr_collectable.py | 50 --- .../gc_weakref_repr_collectable.wasm.jitstats | 15 - 133 files changed, 345 insertions(+), 2182 deletions(-) delete mode 100644 pyre/bench/synth/gc_array_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_array_tounicode_collectable.py delete mode 100644 pyre/bench/synth/gc_array_tounicode_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_bound_method_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_bound_method_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_bound_method_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_bound_method_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_builtin_function_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_builtin_function_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_builtin_function_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_builtin_function_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_contextvar_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_contextvar_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_contextvar_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_contextvar_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_deque_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_deque_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_deque_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_deque_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_direntry_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_direntry_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_direntry_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_exception_group_render_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_exception_group_render_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_exception_group_render_collectable.py delete mode 100644 pyre/bench/synth/gc_exception_group_render_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_exception_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_exception_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_exception_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_exception_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_exception_str_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_exception_str_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_exception_str_collectable.py delete mode 100644 pyre/bench/synth/gc_exception_str_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_fileio_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_fileio_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_fileio_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_function_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_function_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_function_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_function_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_generic_alias_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_generic_alias_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_generic_alias_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_generic_alias_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_getset_descriptor_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_getset_descriptor_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_getset_descriptor_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_getset_descriptor_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_json_string_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_json_string_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_json_string_collectable.py delete mode 100644 pyre/bench/synth/gc_json_string_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_member_descriptor_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_member_descriptor_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_member_descriptor_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_member_descriptor_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_memoryview_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_memoryview_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_memoryview_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_memoryview_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_method_descriptor_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_method_descriptor_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_method_descriptor_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_method_descriptor_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_mmap_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_mmap_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_mmap_repr_collectable.py rename pyre/bench/synth/{gc_array_repr_collectable.cranelift.jitstats => gc_native_strings_collectable.cranelift.jitstats} (100%) rename pyre/bench/synth/{gc_array_repr_collectable.dynasm.jitstats => gc_native_strings_collectable.dynasm.jitstats} (100%) create mode 100644 pyre/bench/synth/gc_native_strings_collectable.py delete mode 100644 pyre/bench/synth/gc_pickle_unicode_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_pickle_unicode_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_pickle_unicode_collectable.py delete mode 100644 pyre/bench/synth/gc_pickle_unicode_collectable.wasm.jitstats rename pyre/bench/synth/{gc_array_repr_collectable.wasm.jitstats => gc_runtime_strings_collectable.cranelift.jitstats} (100%) rename pyre/bench/synth/{gc_array_tounicode_collectable.cranelift.jitstats => gc_runtime_strings_collectable.dynasm.jitstats} (100%) create mode 100644 pyre/bench/synth/gc_runtime_strings_collectable.py rename pyre/bench/synth/{gc_array_tounicode_collectable.dynasm.jitstats => gc_runtime_strings_collectable.wasm.jitstats} (100%) delete mode 100644 pyre/bench/synth/gc_simple_namespace_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_simple_namespace_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_simple_namespace_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_simple_namespace_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_sre_match_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_sre_match_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_sre_match_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_sre_match_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_sre_pattern_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_sre_pattern_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_sre_pattern_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_sre_pattern_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_sre_slice_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_sre_slice_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_sre_slice_collectable.py delete mode 100644 pyre/bench/synth/gc_sre_slice_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_sre_sub_output_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_sre_sub_output_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_sre_sub_output_collectable.py delete mode 100644 pyre/bench/synth/gc_sre_sub_output_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_structseq_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_structseq_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_structseq_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_structseq_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_super_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_super_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_super_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_super_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_time_asctime_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_time_asctime_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_time_asctime_collectable.py delete mode 100644 pyre/bench/synth/gc_time_strftime_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_time_strftime_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_time_strftime_collectable.py delete mode 100644 pyre/bench/synth/gc_unicodedata_normalize_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_unicodedata_normalize_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_unicodedata_normalize_collectable.py delete mode 100644 pyre/bench/synth/gc_unicodedata_normalize_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_union_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_union_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_union_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_union_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_weakproxy_str_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_weakproxy_str_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_weakproxy_str_collectable.py delete mode 100644 pyre/bench/synth/gc_weakproxy_str_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_weakref_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_weakref_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_weakref_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_weakref_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_array_repr_collectable.py b/pyre/bench/synth/gc_array_repr_collectable.py deleted file mode 100644 index 788a6556469..00000000000 --- a/pyre/bench/synth/gc_array_repr_collectable.py +++ /dev/null @@ -1,15 +0,0 @@ -# pyre-check: no-cpython - -import array -import gc - - -integer_rendered = array.array.__repr__(array.array("i", [1, 2, 3])) -unicode_rendered = array.array.__repr__(array.array("u", "abc")) - -assert integer_rendered == "array('i', [1, 2, 3])" -assert unicode_rendered == "array('u', 'abc')" -assert any(obj is integer_rendered for obj in gc.get_objects()) -assert any(obj is unicode_rendered for obj in gc.get_objects()) - -print("array reprs are collectable") diff --git a/pyre/bench/synth/gc_array_tounicode_collectable.py b/pyre/bench/synth/gc_array_tounicode_collectable.py deleted file mode 100644 index 495ed85d216..00000000000 --- a/pyre/bench/synth/gc_array_tounicode_collectable.py +++ /dev/null @@ -1,12 +0,0 @@ -# pyre-check: no-cpython - -import array -import gc - - -rendered = array.array("u", "abc").tounicode() - -assert rendered == "abc" -assert any(obj is rendered for obj in gc.get_objects()) - -print("array tounicode is collectable") diff --git a/pyre/bench/synth/gc_array_tounicode_collectable.wasm.jitstats b/pyre/bench/synth/gc_array_tounicode_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_array_tounicode_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_bound_method_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_bound_method_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_bound_method_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_bound_method_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_bound_method_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_bound_method_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_bound_method_repr_collectable.py b/pyre/bench/synth/gc_bound_method_repr_collectable.py deleted file mode 100644 index 09e5fa319df..00000000000 --- a/pyre/bench/synth/gc_bound_method_repr_collectable.py +++ /dev/null @@ -1,20 +0,0 @@ -# pyre-check: no-cpython -import gc - - -class RuntimeOwner: - def runtime_method(self): - pass - - -owner = RuntimeOwner() -method = owner.runtime_method -ordinary = repr(method) -direct = type(method).__repr__(method) - -assert ordinary == direct -assert "RuntimeOwner.runtime_method" in ordinary -assert any(obj is ordinary for obj in gc.get_objects()) -assert any(obj is direct for obj in gc.get_objects()) - -print("bound method repr results are collectable") diff --git a/pyre/bench/synth/gc_bound_method_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_bound_method_repr_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_bound_method_repr_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_builtin_function_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_builtin_function_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_builtin_function_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_builtin_function_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_builtin_function_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_builtin_function_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_builtin_function_repr_collectable.py b/pyre/bench/synth/gc_builtin_function_repr_collectable.py deleted file mode 100644 index 3d03a14b368..00000000000 --- a/pyre/bench/synth/gc_builtin_function_repr_collectable.py +++ /dev/null @@ -1,13 +0,0 @@ -# pyre-check: no-cpython -import gc - - -functions = (len, [].append) -for function in functions: - ordinary = repr(function) - direct = type(function).__repr__(function) - assert ordinary == direct - assert any(obj is ordinary for obj in gc.get_objects()) - assert any(obj is direct for obj in gc.get_objects()) - -print("builtin function repr results are collectable") diff --git a/pyre/bench/synth/gc_builtin_function_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_builtin_function_repr_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_builtin_function_repr_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.py b/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.py deleted file mode 100644 index d510151122e..00000000000 --- a/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.py +++ /dev/null @@ -1,13 +0,0 @@ -# pyre-check: no-cpython -import gc - - -descriptor = dict.__dict__["fromkeys"] -ordinary = repr(descriptor) -direct = type(descriptor).__repr__(descriptor) - -assert ordinary == direct -assert any(obj is ordinary for obj in gc.get_objects()) -assert any(obj is direct for obj in gc.get_objects()) - -print("classmethod descriptor repr results are collectable") diff --git a/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_classmethod_descriptor_repr_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_contextvar_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_contextvar_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_contextvar_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_contextvar_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_contextvar_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_contextvar_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_contextvar_repr_collectable.py b/pyre/bench/synth/gc_contextvar_repr_collectable.py deleted file mode 100644 index 4e052da719c..00000000000 --- a/pyre/bench/synth/gc_contextvar_repr_collectable.py +++ /dev/null @@ -1,20 +0,0 @@ -# pyre-check: no-cpython - -import contextvars -import gc - - -name = "runtime-context-" + ("x" * 29) -variable = contextvars.ContextVar(name) -rendered = repr(variable) - -assert "runtime-context-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" in rendered -assert any(obj is rendered for obj in gc.get_objects()) - -token = variable.set(object()) -token_rendered = repr(token) - -assert "runtime-context-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" in token_rendered -assert any(obj is token_rendered for obj in gc.get_objects()) - -print("contextvars reprs are collectable") diff --git a/pyre/bench/synth/gc_contextvar_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_contextvar_repr_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_contextvar_repr_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_deque_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_deque_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_deque_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_deque_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_deque_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_deque_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_deque_repr_collectable.py b/pyre/bench/synth/gc_deque_repr_collectable.py deleted file mode 100644 index 45bb4d066f2..00000000000 --- a/pyre/bench/synth/gc_deque_repr_collectable.py +++ /dev/null @@ -1,12 +0,0 @@ -# pyre-check: no-cpython - -import gc -from collections import deque - - -rendered = deque.__repr__(deque([1, 2, 3], maxlen=4)) - -assert rendered == "deque([1, 2, 3], maxlen=4)" -assert any(obj is rendered for obj in gc.get_objects()) - -print("deque repr is collectable") diff --git a/pyre/bench/synth/gc_deque_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_deque_repr_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_deque_repr_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_direntry_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_direntry_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_direntry_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_direntry_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_direntry_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_direntry_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_direntry_repr_collectable.py b/pyre/bench/synth/gc_direntry_repr_collectable.py deleted file mode 100644 index 574646906e3..00000000000 --- a/pyre/bench/synth/gc_direntry_repr_collectable.py +++ /dev/null @@ -1,16 +0,0 @@ -# pyre-check: no-cpython -# pyre-check: skip-backends=wasm -import gc -import os - - -entry = next(os.scandir(".")) -direct = os.DirEntry.__repr__(entry) -ordinary = repr(entry) - -assert direct == ordinary -assert direct.startswith("" -assert any(obj is closed_direct for obj in gc.get_objects()) -assert any(obj is closed_ordinary for obj in gc.get_objects()) - -print("FileIO repr results are collectable") diff --git a/pyre/bench/synth/gc_function_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_function_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_function_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_function_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_function_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_function_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_function_repr_collectable.py b/pyre/bench/synth/gc_function_repr_collectable.py deleted file mode 100644 index 70cd4ab2fb0..00000000000 --- a/pyre/bench/synth/gc_function_repr_collectable.py +++ /dev/null @@ -1,17 +0,0 @@ -# pyre-check: no-cpython -import gc - - -def runtime_function(): - pass - - -ordinary = repr(runtime_function) -direct = type(runtime_function).__repr__(runtime_function) - -assert ordinary == direct -assert ordinary.startswith("" -assert any(obj is closed_direct for obj in gc.get_objects()) -assert any(obj is closed_ordinary for obj in gc.get_objects()) - -print("mmap repr results are collectable") diff --git a/pyre/bench/synth/gc_array_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_native_strings_collectable.cranelift.jitstats similarity index 100% rename from pyre/bench/synth/gc_array_repr_collectable.cranelift.jitstats rename to pyre/bench/synth/gc_native_strings_collectable.cranelift.jitstats diff --git a/pyre/bench/synth/gc_array_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_native_strings_collectable.dynasm.jitstats similarity index 100% rename from pyre/bench/synth/gc_array_repr_collectable.dynasm.jitstats rename to pyre/bench/synth/gc_native_strings_collectable.dynasm.jitstats diff --git a/pyre/bench/synth/gc_native_strings_collectable.py b/pyre/bench/synth/gc_native_strings_collectable.py new file mode 100644 index 00000000000..669d0d8fce4 --- /dev/null +++ b/pyre/bench/synth/gc_native_strings_collectable.py @@ -0,0 +1,60 @@ +# pyre-check: no-cpython +# pyre-check: skip-backends=wasm + +import _io +import gc +import os +import time + + +results = [] + + +def managed(label, value): + results.append((label, value)) + return value + + +# Native filesystem objects have state-dependent repr branches. +entry = next(os.scandir(".")) +managed("DirEntry repr", os.DirEntry.__repr__(entry)) + +file = _io.FileIO(__file__, "r") +managed("FileIO name repr", _io.FileIO.__repr__(file)) +del file.name +managed("FileIO fd repr", _io.FileIO.__repr__(file)) +file.close() +managed("FileIO closed repr", _io.FileIO.__repr__(file)) + + +# Unix and Windows have separate libc-backed strftime implementations, while +# asctime and ctime share the upstream-style formatter. +calendar = (2020, 2, 3, 4, 5, 6, 0, 34, -1) +strftime_value = time.strftime("%Y-%m-%d %H:%M:%S", calendar) +assert strftime_value == "2020-02-03 04:05:06" +managed("strftime", strftime_value) + +asctime_value = time.asctime(calendar) +assert asctime_value == "Mon Feb 3 04:05:06 2020" +managed("asctime", asctime_value) +managed("ctime", time.ctime(0)) + + +# pyre's mmap implementation is currently Unix-only. The module imports on +# Windows without exposing mmap.mmap, so keep the platform branch in this one +# native fixture instead of maintaining another process/baseline pair. +import mmap + + +if hasattr(mmap, "mmap"): + mapping = mmap.mmap(-1, 1) + managed("mmap live repr", mmap.mmap.__repr__(mapping)) + mapping.close() + managed("mmap closed repr", mmap.mmap.__repr__(mapping)) + + +objects = gc.get_objects() +for label, value in results: + assert any(obj is value for obj in objects), label + +print("native runtime string results are collectable") diff --git a/pyre/bench/synth/gc_pickle_unicode_collectable.cranelift.jitstats b/pyre/bench/synth/gc_pickle_unicode_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_pickle_unicode_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_pickle_unicode_collectable.dynasm.jitstats b/pyre/bench/synth/gc_pickle_unicode_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_pickle_unicode_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_pickle_unicode_collectable.py b/pyre/bench/synth/gc_pickle_unicode_collectable.py deleted file mode 100644 index 7b8b9bbe2c4..00000000000 --- a/pyre/bench/synth/gc_pickle_unicode_collectable.py +++ /dev/null @@ -1,19 +0,0 @@ -# pyre-check: no-cpython - -import gc -import pickle - - -text = b"pickle runtime string" -payloads = [ - b"\x80\x04\x8c" + bytes([len(text)]) + text + b".", - b"\x80\x04X" + len(text).to_bytes(4, "little") + text + b".", - b"\x80\x04\x8d" + len(text).to_bytes(8, "little") + text + b".", -] - -for payload in payloads: - result = pickle.loads(payload) - assert result == "pickle runtime string" - assert any(obj is result for obj in gc.get_objects()) - -print("pickle unicode results are collectable") diff --git a/pyre/bench/synth/gc_pickle_unicode_collectable.wasm.jitstats b/pyre/bench/synth/gc_pickle_unicode_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_pickle_unicode_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_array_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_runtime_strings_collectable.cranelift.jitstats similarity index 100% rename from pyre/bench/synth/gc_array_repr_collectable.wasm.jitstats rename to pyre/bench/synth/gc_runtime_strings_collectable.cranelift.jitstats diff --git a/pyre/bench/synth/gc_array_tounicode_collectable.cranelift.jitstats b/pyre/bench/synth/gc_runtime_strings_collectable.dynasm.jitstats similarity index 100% rename from pyre/bench/synth/gc_array_tounicode_collectable.cranelift.jitstats rename to pyre/bench/synth/gc_runtime_strings_collectable.dynasm.jitstats diff --git a/pyre/bench/synth/gc_runtime_strings_collectable.py b/pyre/bench/synth/gc_runtime_strings_collectable.py new file mode 100644 index 00000000000..ab3673d8411 --- /dev/null +++ b/pyre/bench/synth/gc_runtime_strings_collectable.py @@ -0,0 +1,285 @@ +# pyre-check: no-cpython + +import array +import contextvars +import gc +import json +import pickle +import re +import sys +import types +import unicodedata +import weakref +from collections import deque + + +results = [] + + +def managed(label, value): + results.append((label, value)) + return value + + +# _json: encoder/decoder results, error notes, one-shot chunks, and float keys. +json_source = "gc-json-probe-" + ("x" * 37) +managed("json encode", json.encoder.encode_basestring(json_source)) +json_decoded, json_end = json.decoder.scanstring('"' + json_source + '"', 1) +assert json_decoded == json_source +assert json_end == len(json_source) + 2 +managed("json decode", json_decoded) + +try: + json.dumps([object()]) +except TypeError as exc: + if not getattr(exc, "__notes__", None): + exc.add_note("gc-json-note-" + ("x" * 37)) + managed("json note", exc.__notes__[-1]) +else: + raise AssertionError("json.dumps accepted an unsupported object") + +json_chunks = list(json.JSONEncoder().iterencode({"runtime": json_source}, _one_shot=True)) +assert json_chunks +if json.encoder.c_make_encoder is not None: + managed("json chunk", json_chunks[0]) + +float_key = 1.2345678901234567e123 +float_keys = [] + + +def observe_float_key(key): + if key.startswith("1.234567890123456") and key.endswith("e+123"): + float_keys.append(key) + return json.encoder.encode_basestring_ascii(key) + + +if json.encoder.c_make_encoder is None: + managed("json float key oracle", repr(float_key)) +else: + encoder = json.encoder.c_make_encoder( + {}, lambda obj: None, observe_float_key, None, ": ", ", ", False, False, True + ) + assert encoder({float_key: None}, 0) == ['{"1.2345678901234567e+123": null}'] + assert len(float_keys) == 1 + managed("json float key", float_keys[0]) + + +# Formatted repr paths whose ordinary repr formatting is covered elsewhere. +alias_name = "RuntimeAlias" + ("X" * 19) +alias_type = type(alias_name, (), {}) +managed("GenericAlias repr", types.GenericAlias.__repr__(list[alias_type])) + +context_name = "runtime-context-" + ("x" * 29) +context_var = contextvars.ContextVar(context_name) +managed("ContextVar repr", repr(context_var)) +context_token = context_var.set(object()) +managed("ContextVar token repr", repr(context_token)) + +managed("structseq repr", repr(sys.version_info)) +managed("array tounicode", array.array("u", "abc").tounicode()) +managed("array int repr", array.array.__repr__(array.array("i", [1, 2, 3]))) +managed("array unicode repr", array.array.__repr__(array.array("u", "abc"))) +managed("deque repr", deque.__repr__(deque([1, 2, 3], maxlen=4))) + + +# _sre: final repr/substitution strings and every slice-container assembly shape. +pattern = re.compile(r"(?P[a-z]+)-(?P\d+)") +subject = "alpha-123-omega" +match = pattern.search(subject) +managed("SRE pattern repr", type(pattern).__repr__(pattern)) +managed("SRE match repr", type(match).__repr__(match)) +managed("SRE sub", pattern.sub("word", subject)) +subn_result, subn_count = pattern.subn("word", subject) +assert subn_count == 1 +managed("SRE subn", subn_result) +managed("SRE expand", match.expand(r"<\1:\2>")) + +managed("SRE group", match.group(1)) +managed("SRE getitem", match[2]) +managed("SRE multi-group", match.group(1, 2)[0]) +managed("SRE groups", match.groups()[1]) +managed("SRE groupdict", match.groupdict()["word"]) +managed("SRE findall plain", re.findall(r"[a-z]+", subject)[0]) +managed("SRE findall single", re.findall(r"([a-z]+)", subject)[1]) +managed("SRE findall multiple", pattern.findall(subject)[0][1]) +split_parts = re.split(r"(-)", subject) +managed("SRE split text", split_parts[0]) +managed("SRE split group", split_parts[1]) + + +class Text(str): + pass + + +unchanged = pattern.sub("replacement", Text("no match here")) +assert type(unchanged) is str +managed("SRE subclass normalization", unchanged) + + +# _pickle's three Unicode opcodes share one loader but have distinct lengths. +pickle_text = b"pickle runtime string" +pickle_payloads = ( + b"\x80\x04\x8c" + bytes([len(pickle_text)]) + pickle_text + b".", + b"\x80\x04X" + len(pickle_text).to_bytes(4, "little") + pickle_text + b".", + b"\x80\x04\x8d" + len(pickle_text).to_bytes(8, "little") + pickle_text + b".", +) +pickle_opcodes = ("SHORT_BINUNICODE", "BINUNICODE", "BINUNICODE8") +for opcode, payload in zip(pickle_opcodes, pickle_payloads): + managed(opcode, pickle.loads(payload)) + + +# normalize has separate non-ASCII, exact-ASCII identity, and subclass paths. +for form, source, expected in ( + ("NFC", "e\u0301 runtime", "é runtime"), + ("NFD", "é runtime", "e\u0301 runtime"), + ("NFKC", "\ufb03 runtime", "ffi runtime"), + ("NFKD", "\ufb03 runtime", "ffi runtime"), +): + normalized = unicodedata.normalize(form, source) + assert normalized == expected + managed("normalize " + form, normalized) + +ascii_source = "".join(["ascii", " runtime"]) +ascii_result = unicodedata.normalize("NFC", ascii_source) +assert ascii_result is ascii_source +managed("normalize ASCII identity", ascii_result) +subclass_result = unicodedata.normalize("NFC", Text("subclass runtime")) +assert type(subclass_result) is str +managed("normalize subclass", subclass_result) + + +# SimpleNamespace's recursive guard is a separate result branch. +namespace = types.SimpleNamespace(alpha="value", count=3) +managed("SimpleNamespace repr", types.SimpleNamespace.__repr__(namespace)) +recursive_result = None + + +class CaptureRecursiveRepr: + def __repr__(self): + global recursive_result + recursive_result = repr(recursive_namespace) + return "captured" + + +recursive_namespace = types.SimpleNamespace(value=CaptureRecursiveRepr()) +assert repr(recursive_namespace) == "namespace(value=captured)" +assert recursive_result == "namespace(...)" +managed("SimpleNamespace recursive repr", recursive_result) + + +# BaseException rendering has arity/identity/specialized branches. +for label, exception in ( + ("exception repr empty", ValueError()), + ("exception repr single", ValueError("x")), + ("exception repr multiple", ValueError("x", 1)), +): + managed(label, BaseException.__repr__(exception)) + + +class Render: + def __init__(self, result): + self.result = result + + def __str__(self): + return self.result + + +runtime_text = "runtime-exception-value-" + str(id(gc)) +rendered_text = "rendered-exception-value-" + str(id(runtime_text)) +assert BaseException.__str__(ValueError(runtime_text)) is runtime_text +managed("exception str identity", runtime_text) +assert BaseException.__str__(ValueError(Render(rendered_text))) is rendered_text +managed("exception str delegated identity", rendered_text) +managed("exception str multiple", BaseException.__str__(ValueError(runtime_text, 1))) +managed("KeyError str", KeyError.__str__(KeyError(runtime_text))) + +group_message = "runtime-exception-group-message-" + str(id(results)) +group = ExceptionGroup(group_message, [ValueError("runtime group leaf")]) +managed("ExceptionGroup str", ExceptionGroup.__str__(group)) +managed("ExceptionGroup repr", ExceptionGroup.__repr__(group)) + + +# Direct descriptor paths share typedef formatting but have distinct owners. +class RuntimeOwner: + def runtime_method(self): + pass + + +owner = RuntimeOwner() +managed("bound method repr", type(owner.runtime_method).__repr__(owner.runtime_method)) +managed("super repr", super.__repr__(super(RuntimeOwner, owner))) +union = int | str +managed("union repr", type(union).__repr__(union)) + + +def runtime_function(): + pass + + +managed("function repr", type(runtime_function).__repr__(runtime_function)) +managed("builtin function repr", type(len).__repr__(len)) +managed("builtin method repr", type([].append).__repr__([].append)) + + +class SlotOwner: + __slots__ = ("value",) + + +for label, descriptor in ( + ("getset descriptor repr", type.__dict__["__name__"]), + ("member descriptor repr", SlotOwner.__dict__["value"]), + ("method descriptor repr", list.__dict__["append"]), + ("classmethod descriptor repr", dict.__dict__["fromkeys"]), +): + managed(label, type(descriptor).__repr__(descriptor)) + + +# Stateful reprs have distinct live/released and live/dead branches. +view = memoryview(b"x") +managed("memoryview live repr", memoryview.__repr__(view)) +view.release() +managed("memoryview released repr", memoryview.__repr__(view)) + +weak_marker = "".join(["dynamic", " weak proxy"]) + + +class Referent: + def __str__(self): + return weak_marker + + +class CallableReferent: + def __call__(self): + pass + + +referent = Referent() +callable_referent = CallableReferent() +reference = weakref.ref(referent) +proxy = weakref.proxy(referent) +callable_proxy = weakref.proxy(callable_referent) +proxy_text = type(proxy).__str__(proxy) +assert proxy_text is weak_marker +managed("weak proxy str identity", proxy_text) +managed("weakref live repr", weakref.ReferenceType.__repr__(reference)) +managed("weak proxy live repr", weakref.ProxyType.__repr__(proxy)) +managed("callable weak proxy live repr", weakref.CallableProxyType.__repr__(callable_proxy)) + +del referent +del callable_referent +gc.collect() +for label, value in ( + ("weakref dead repr", weakref.ReferenceType.__repr__(reference)), + ("weak proxy dead repr", weakref.ProxyType.__repr__(proxy)), + ("callable weak proxy dead repr", weakref.CallableProxyType.__repr__(callable_proxy)), +): + assert "; dead>" in value + managed(label, value) + + +# Take one heap census after every result is rooted in `results`. +objects = gc.get_objects() +for label, value in results: + assert any(obj is value for obj in objects), label + +print("runtime string results are collectable") diff --git a/pyre/bench/synth/gc_array_tounicode_collectable.dynasm.jitstats b/pyre/bench/synth/gc_runtime_strings_collectable.wasm.jitstats similarity index 100% rename from pyre/bench/synth/gc_array_tounicode_collectable.dynasm.jitstats rename to pyre/bench/synth/gc_runtime_strings_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_simple_namespace_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_simple_namespace_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_simple_namespace_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_simple_namespace_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_simple_namespace_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_simple_namespace_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_simple_namespace_repr_collectable.py b/pyre/bench/synth/gc_simple_namespace_repr_collectable.py deleted file mode 100644 index 107c6186a95..00000000000 --- a/pyre/bench/synth/gc_simple_namespace_repr_collectable.py +++ /dev/null @@ -1,31 +0,0 @@ -# pyre-check: no-cpython - -import gc -from types import SimpleNamespace - - -namespace = SimpleNamespace(alpha="value", count=3) -ordinary = repr(namespace) -direct = SimpleNamespace.__repr__(namespace) - -assert ordinary == "namespace(alpha='value', count=3)" -assert direct == ordinary -assert any(obj is ordinary for obj in gc.get_objects()) -assert any(obj is direct for obj in gc.get_objects()) - -recursive_result = None - - -class CaptureRecursiveRepr: - def __repr__(self): - global recursive_result - recursive_result = repr(recursive_namespace) - return "captured" - - -recursive_namespace = SimpleNamespace(value=CaptureRecursiveRepr()) -assert repr(recursive_namespace) == "namespace(value=captured)" -assert recursive_result == "namespace(...)" -assert any(obj is recursive_result for obj in gc.get_objects()) - -print("SimpleNamespace repr results are collectable") diff --git a/pyre/bench/synth/gc_simple_namespace_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_simple_namespace_repr_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_simple_namespace_repr_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_match_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_sre_match_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_sre_match_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_match_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_sre_match_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_sre_match_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_match_repr_collectable.py b/pyre/bench/synth/gc_sre_match_repr_collectable.py deleted file mode 100644 index 56764db6c92..00000000000 --- a/pyre/bench/synth/gc_sre_match_repr_collectable.py +++ /dev/null @@ -1,13 +0,0 @@ -# pyre-check: no-cpython - -import gc -import re - - -match = re.compile("a+").match("aaa") -rendered = type(match).__repr__(match) - -assert rendered == "" -assert any(obj is rendered for obj in gc.get_objects()) - -print("sre match repr is collectable") diff --git a/pyre/bench/synth/gc_sre_match_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_sre_match_repr_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_sre_match_repr_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_pattern_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_sre_pattern_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_sre_pattern_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_pattern_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_sre_pattern_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_sre_pattern_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_pattern_repr_collectable.py b/pyre/bench/synth/gc_sre_pattern_repr_collectable.py deleted file mode 100644 index 8c275ca73cd..00000000000 --- a/pyre/bench/synth/gc_sre_pattern_repr_collectable.py +++ /dev/null @@ -1,13 +0,0 @@ -# pyre-check: no-cpython - -import gc -import re - - -pattern = re.compile("a+") -rendered = type(pattern).__repr__(pattern) - -assert rendered == "re.compile('a+')" -assert any(obj is rendered for obj in gc.get_objects()) - -print("sre pattern repr is collectable") diff --git a/pyre/bench/synth/gc_sre_pattern_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_sre_pattern_repr_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_sre_pattern_repr_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_slice_collectable.cranelift.jitstats b/pyre/bench/synth/gc_sre_slice_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_sre_slice_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_slice_collectable.dynasm.jitstats b/pyre/bench/synth/gc_sre_slice_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_sre_slice_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_slice_collectable.py b/pyre/bench/synth/gc_sre_slice_collectable.py deleted file mode 100644 index f4247b401c2..00000000000 --- a/pyre/bench/synth/gc_sre_slice_collectable.py +++ /dev/null @@ -1,56 +0,0 @@ -# pyre-check: no-cpython - -import gc -import re - - -def is_managed(value): - return any(obj is value for obj in gc.get_objects()) - - -pattern = re.compile(r"(?P[a-z]+)-(?P\d+)") -subject = "alpha-123-omega" -match = pattern.search(subject) - -group_word = match.group(1) -getitem_number = match[2] -multiple = match.group(1, 2) -groups = match.groups() -groupdict = match.groupdict() -findall_plain = re.findall(r"[a-z]+", subject) -findall_single = re.findall(r"([a-z]+)", subject) -findall_multiple = pattern.findall(subject) -split_parts = re.split(r"(-)", subject) - -assert group_word == "alpha" -assert getitem_number == "123" -assert multiple == ("alpha", "123") -assert groups == ("alpha", "123") -assert groupdict == {"word": "alpha", "number": "123"} -assert findall_plain == ["alpha", "omega"] -assert findall_single == ["alpha", "omega"] -assert findall_multiple == [("alpha", "123")] -assert split_parts == ["alpha", "-", "123", "-", "omega"] - -assert is_managed(group_word) -assert is_managed(getitem_number) -assert is_managed(multiple[0]) -assert is_managed(groups[1]) -assert is_managed(groupdict["word"]) -assert is_managed(findall_plain[0]) -assert is_managed(findall_single[1]) -assert is_managed(findall_multiple[0][1]) -assert is_managed(split_parts[0]) -assert is_managed(split_parts[1]) - - -class Text(str): - pass - - -unchanged = pattern.sub("replacement", Text("no match here")) -assert type(unchanged) is str -assert unchanged == "no match here" -assert is_managed(unchanged) - -print("sre subject slices are collectable") diff --git a/pyre/bench/synth/gc_sre_slice_collectable.wasm.jitstats b/pyre/bench/synth/gc_sre_slice_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_sre_slice_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_sub_output_collectable.cranelift.jitstats b/pyre/bench/synth/gc_sre_sub_output_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_sre_sub_output_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_sub_output_collectable.dynasm.jitstats b/pyre/bench/synth/gc_sre_sub_output_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_sre_sub_output_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_sre_sub_output_collectable.py b/pyre/bench/synth/gc_sre_sub_output_collectable.py deleted file mode 100644 index 2f6347cb694..00000000000 --- a/pyre/bench/synth/gc_sre_sub_output_collectable.py +++ /dev/null @@ -1,22 +0,0 @@ -# pyre-check: no-cpython - -import gc -import re - - -pattern = re.compile(r"([a-z]+)-(\d+)") -subject = "alpha-123-omega" - -sub_result = pattern.sub("word", subject) -subn_result, count = pattern.subn("word", subject) -expand_result = pattern.search(subject).expand(r"<\1:\2>") - -assert sub_result == "word-omega" -assert subn_result == "word-omega" -assert count == 1 -assert expand_result == "" -assert any(obj is sub_result for obj in gc.get_objects()) -assert any(obj is subn_result for obj in gc.get_objects()) -assert any(obj is expand_result for obj in gc.get_objects()) - -print("sre substitution outputs are collectable") diff --git a/pyre/bench/synth/gc_sre_sub_output_collectable.wasm.jitstats b/pyre/bench/synth/gc_sre_sub_output_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_sre_sub_output_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_structseq_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_structseq_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_structseq_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_structseq_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_structseq_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_structseq_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_structseq_repr_collectable.py b/pyre/bench/synth/gc_structseq_repr_collectable.py deleted file mode 100644 index cc68dad02c1..00000000000 --- a/pyre/bench/synth/gc_structseq_repr_collectable.py +++ /dev/null @@ -1,12 +0,0 @@ -# pyre-check: no-cpython - -import gc -import sys - - -rendered = repr(sys.version_info) - -assert rendered.startswith("sys.version_info(major=3, minor=") -assert any(obj is rendered for obj in gc.get_objects()) - -print("structseq repr is collectable") diff --git a/pyre/bench/synth/gc_structseq_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_structseq_repr_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_structseq_repr_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_super_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_super_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_super_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_super_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_super_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_super_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_super_repr_collectable.py b/pyre/bench/synth/gc_super_repr_collectable.py deleted file mode 100644 index 15184de0493..00000000000 --- a/pyre/bench/synth/gc_super_repr_collectable.py +++ /dev/null @@ -1,18 +0,0 @@ -# pyre-check: no-cpython -import gc - - -class RuntimeOwner: - pass - - -owner = RuntimeOwner() -proxy = super(RuntimeOwner, owner) -ordinary = repr(proxy) -direct = super.__repr__(proxy) - -assert ordinary == direct == ", >" -assert any(obj is ordinary for obj in gc.get_objects()) -assert any(obj is direct for obj in gc.get_objects()) - -print("super repr results are collectable") diff --git a/pyre/bench/synth/gc_super_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_super_repr_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_super_repr_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_time_asctime_collectable.cranelift.jitstats b/pyre/bench/synth/gc_time_asctime_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_time_asctime_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_time_asctime_collectable.dynasm.jitstats b/pyre/bench/synth/gc_time_asctime_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_time_asctime_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_time_asctime_collectable.py b/pyre/bench/synth/gc_time_asctime_collectable.py deleted file mode 100644 index 8a4c5373327..00000000000 --- a/pyre/bench/synth/gc_time_asctime_collectable.py +++ /dev/null @@ -1,19 +0,0 @@ -# pyre-check: no-cpython -# pyre-check: skip-backends=wasm -import gc -import time - - -asctime_value = time.asctime( - (2020, 2, 3, 4, 5, 6, 0, 34, -1), -) - -assert asctime_value == "Mon Feb 3 04:05:06 2020" -assert any(obj is asctime_value for obj in gc.get_objects()) - -# The wasm guest does not register the time module. Native Unix and Windows -# share this localtime -> _asctime path. -ctime_value = time.ctime(0) -assert any(obj is ctime_value for obj in gc.get_objects()) - -print("time asctime results are collectable") diff --git a/pyre/bench/synth/gc_time_strftime_collectable.cranelift.jitstats b/pyre/bench/synth/gc_time_strftime_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_time_strftime_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_time_strftime_collectable.dynasm.jitstats b/pyre/bench/synth/gc_time_strftime_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_time_strftime_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_time_strftime_collectable.py b/pyre/bench/synth/gc_time_strftime_collectable.py deleted file mode 100644 index 4e2b5c683f5..00000000000 --- a/pyre/bench/synth/gc_time_strftime_collectable.py +++ /dev/null @@ -1,17 +0,0 @@ -# pyre-check: no-cpython -# pyre-check: skip-backends=wasm -# The wasm guest has no libc calendar formatter; this fixture verifies the -# native Unix/Windows result allocation shared by their strftime branches. -import gc -import time - - -value = time.strftime( - "%Y-%m-%d %H:%M:%S", - (2020, 2, 3, 4, 5, 6, 0, 34, -1), -) - -assert value == "2020-02-03 04:05:06" -assert any(obj is value for obj in gc.get_objects()) - -print("time.strftime result is collectable") diff --git a/pyre/bench/synth/gc_unicodedata_normalize_collectable.cranelift.jitstats b/pyre/bench/synth/gc_unicodedata_normalize_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_unicodedata_normalize_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_unicodedata_normalize_collectable.dynasm.jitstats b/pyre/bench/synth/gc_unicodedata_normalize_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_unicodedata_normalize_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_unicodedata_normalize_collectable.py b/pyre/bench/synth/gc_unicodedata_normalize_collectable.py deleted file mode 100644 index 389ead85fa9..00000000000 --- a/pyre/bench/synth/gc_unicodedata_normalize_collectable.py +++ /dev/null @@ -1,34 +0,0 @@ -# pyre-check: no-cpython - -import gc -import unicodedata - - -cases = [ - ("NFC", "e\u0301 runtime", "é runtime"), - ("NFD", "é runtime", "e\u0301 runtime"), - ("NFKC", "\ufb03 runtime", "ffi runtime"), - ("NFKD", "\ufb03 runtime", "ffi runtime"), -] - -for form, source, expected in cases: - result = unicodedata.normalize(form, source) - assert result == expected - assert any(obj is result for obj in gc.get_objects()) - -ascii_source = "".join(["ascii", " runtime"]) -ascii_result = unicodedata.normalize("NFC", ascii_source) -assert ascii_result is ascii_source -assert any(obj is ascii_result for obj in gc.get_objects()) - - -class Text(str): - pass - - -subclass_result = unicodedata.normalize("NFC", Text("subclass runtime")) -assert type(subclass_result) is str -assert subclass_result == "subclass runtime" -assert any(obj is subclass_result for obj in gc.get_objects()) - -print("unicodedata normalize results are collectable") diff --git a/pyre/bench/synth/gc_unicodedata_normalize_collectable.wasm.jitstats b/pyre/bench/synth/gc_unicodedata_normalize_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_unicodedata_normalize_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_union_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_union_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_union_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_union_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_union_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_union_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_union_repr_collectable.py b/pyre/bench/synth/gc_union_repr_collectable.py deleted file mode 100644 index 9dcc1c645c3..00000000000 --- a/pyre/bench/synth/gc_union_repr_collectable.py +++ /dev/null @@ -1,13 +0,0 @@ -# pyre-check: no-cpython -import gc - - -union = int | str -ordinary = repr(union) -direct = type(union).__repr__(union) - -assert ordinary == direct == "int | str" -assert any(obj is ordinary for obj in gc.get_objects()) -assert any(obj is direct for obj in gc.get_objects()) - -print("union repr results are collectable") diff --git a/pyre/bench/synth/gc_union_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_union_repr_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_union_repr_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_weakproxy_str_collectable.cranelift.jitstats b/pyre/bench/synth/gc_weakproxy_str_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_weakproxy_str_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_weakproxy_str_collectable.dynasm.jitstats b/pyre/bench/synth/gc_weakproxy_str_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_weakproxy_str_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_weakproxy_str_collectable.py b/pyre/bench/synth/gc_weakproxy_str_collectable.py deleted file mode 100644 index e99f3010401..00000000000 --- a/pyre/bench/synth/gc_weakproxy_str_collectable.py +++ /dev/null @@ -1,25 +0,0 @@ -# pyre-check: no-cpython - -import gc -import weakref - - -marker = "".join(["dynamic", " weak proxy"]) - - -class Referent: - def __str__(self): - return marker - - -referent = Referent() -proxy = weakref.proxy(referent) -ordinary = str(proxy) -direct = type(proxy).__str__(proxy) - -assert ordinary is marker -assert direct is marker -assert any(obj is ordinary for obj in gc.get_objects()) -assert any(obj is direct for obj in gc.get_objects()) - -print("weak proxy str preserves managed identity") diff --git a/pyre/bench/synth/gc_weakproxy_str_collectable.wasm.jitstats b/pyre/bench/synth/gc_weakproxy_str_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_weakproxy_str_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_weakref_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_weakref_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_weakref_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_weakref_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_weakref_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_weakref_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_weakref_repr_collectable.py b/pyre/bench/synth/gc_weakref_repr_collectable.py deleted file mode 100644 index dbadf03f58f..00000000000 --- a/pyre/bench/synth/gc_weakref_repr_collectable.py +++ /dev/null @@ -1,50 +0,0 @@ -# pyre-check: no-cpython -import gc -import weakref - - -class Referent: - pass - - -class CallableReferent: - def __call__(self): - pass - - -referent = Referent() -callable_referent = CallableReferent() -reference = weakref.ref(referent) -proxy = weakref.proxy(referent) -callable_proxy = weakref.proxy(callable_referent) - -live_results = ( - weakref.ReferenceType.__repr__(reference), - repr(reference), - weakref.ProxyType.__repr__(proxy), - repr(proxy), - weakref.CallableProxyType.__repr__(callable_proxy), - repr(callable_proxy), -) - -for result in live_results: - assert any(obj is result for obj in gc.get_objects()) - -del referent -del callable_referent -gc.collect() - -dead_results = ( - weakref.ReferenceType.__repr__(reference), - repr(reference), - weakref.ProxyType.__repr__(proxy), - repr(proxy), - weakref.CallableProxyType.__repr__(callable_proxy), - repr(callable_proxy), -) - -for result in dead_results: - assert "; dead>" in result - assert any(obj is result for obj in gc.get_objects()) - -print("weakref repr results are collectable") diff --git a/pyre/bench/synth/gc_weakref_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_weakref_repr_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_weakref_repr_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 From db5be093c68344924c4ea17343238baa1da63185 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 12 Aug 2026 18:54:24 +0900 Subject: [PATCH 52/52] gc: consolidate remaining repr collectability coverage --- ...c_cell_repr_collectable.cranelift.jitstats | 15 ------- .../gc_cell_repr_collectable.dynasm.jitstats | 15 ------- pyre/bench/synth/gc_cell_repr_collectable.py | 24 ----------- .../gc_cell_repr_collectable.wasm.jitstats | 15 ------- ...erator_repr_collectable.cranelift.jitstats | 15 ------- ...generator_repr_collectable.dynasm.jitstats | 15 ------- .../synth/gc_generator_repr_collectable.py | 19 --------- ...c_generator_repr_collectable.wasm.jitstats | 15 ------- ...rapper_repr_collectable.cranelift.jitstats | 15 ------- ...d_wrapper_repr_collectable.dynasm.jitstats | 15 ------- .../gc_method_wrapper_repr_collectable.py | 12 ------ ...hod_wrapper_repr_collectable.wasm.jitstats | 15 ------- .../synth/gc_runtime_strings_collectable.py | 41 +++++++++++++++++++ ...c_type_repr_collectable.cranelift.jitstats | 15 ------- .../gc_type_repr_collectable.dynasm.jitstats | 15 ------- pyre/bench/synth/gc_type_repr_collectable.py | 16 -------- .../gc_type_repr_collectable.wasm.jitstats | 15 ------- pyre/pyre-interpreter/src/typedef.rs | 2 +- 18 files changed, 42 insertions(+), 252 deletions(-) delete mode 100644 pyre/bench/synth/gc_cell_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_cell_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_cell_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_cell_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_generator_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_generator_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_generator_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_generator_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_method_wrapper_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_method_wrapper_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_method_wrapper_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_method_wrapper_repr_collectable.wasm.jitstats delete mode 100644 pyre/bench/synth/gc_type_repr_collectable.cranelift.jitstats delete mode 100644 pyre/bench/synth/gc_type_repr_collectable.dynasm.jitstats delete mode 100644 pyre/bench/synth/gc_type_repr_collectable.py delete mode 100644 pyre/bench/synth/gc_type_repr_collectable.wasm.jitstats diff --git a/pyre/bench/synth/gc_cell_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_cell_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_cell_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_cell_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_cell_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_cell_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_cell_repr_collectable.py b/pyre/bench/synth/gc_cell_repr_collectable.py deleted file mode 100644 index 007b014d74a..00000000000 --- a/pyre/bench/synth/gc_cell_repr_collectable.py +++ /dev/null @@ -1,24 +0,0 @@ -# pyre-check: no-cpython -import gc - - -def make_cell(value): - def inner(): - return value - - return inner.__closure__[0] - - -filled = make_cell(42) -empty = make_cell(42) -del empty.cell_contents - -for cell in (filled, empty): - ordinary = repr(cell) - direct = type(cell).__repr__(cell) - - assert ordinary == direct - assert any(obj is ordinary for obj in gc.get_objects()) - assert any(obj is direct for obj in gc.get_objects()) - -print("cell repr results are collectable") diff --git a/pyre/bench/synth/gc_cell_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_cell_repr_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_cell_repr_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_generator_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_generator_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_generator_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_generator_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_generator_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_generator_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_generator_repr_collectable.py b/pyre/bench/synth/gc_generator_repr_collectable.py deleted file mode 100644 index 4f1872affad..00000000000 --- a/pyre/bench/synth/gc_generator_repr_collectable.py +++ /dev/null @@ -1,19 +0,0 @@ -# pyre-check: no-cpython -import gc - - -def generate(): - yield 1 - - -generator = generate() -ordinary = repr(generator) -direct = type(generator).__repr__(generator) - -assert ordinary == direct -assert any(obj is ordinary for obj in gc.get_objects()) -assert any(obj is direct for obj in gc.get_objects()) - -generator.close() - -print("generator repr results are collectable") diff --git a/pyre/bench/synth/gc_generator_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_generator_repr_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_generator_repr_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_method_wrapper_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_method_wrapper_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_method_wrapper_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_method_wrapper_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_method_wrapper_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_method_wrapper_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_method_wrapper_repr_collectable.py b/pyre/bench/synth/gc_method_wrapper_repr_collectable.py deleted file mode 100644 index fcb6712d28f..00000000000 --- a/pyre/bench/synth/gc_method_wrapper_repr_collectable.py +++ /dev/null @@ -1,12 +0,0 @@ -# pyre-check: no-cpython -import gc - -wrapper = (1).__add__ -ordinary = repr(wrapper) -direct = type(wrapper).__repr__(wrapper) - -assert ordinary == direct -assert any(obj is ordinary for obj in gc.get_objects()) -assert any(obj is direct for obj in gc.get_objects()) - -print("method-wrapper repr results are collectable") diff --git a/pyre/bench/synth/gc_method_wrapper_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_method_wrapper_repr_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_method_wrapper_repr_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_runtime_strings_collectable.py b/pyre/bench/synth/gc_runtime_strings_collectable.py index ab3673d8411..de645087034 100644 --- a/pyre/bench/synth/gc_runtime_strings_collectable.py +++ b/pyre/bench/synth/gc_runtime_strings_collectable.py @@ -219,6 +219,47 @@ def runtime_function(): managed("function repr", type(runtime_function).__repr__(runtime_function)) managed("builtin function repr", type(len).__repr__(len)) managed("builtin method repr", type([].append).__repr__([].append)) +wrapper = (1).__add__ +managed("method-wrapper repr", type(wrapper).__repr__(wrapper)) + + +class RuntimeType: + pass + + +managed("type repr", type.__repr__(RuntimeType)) + + +def make_cell(value): + def inner(): + return value + + return inner.__closure__[0] + + +filled_cell = make_cell(42) +empty_cell = make_cell(42) +del empty_cell.cell_contents +managed("filled cell repr", type(filled_cell).__repr__(filled_cell)) +managed("empty cell repr", type(empty_cell).__repr__(empty_cell)) + + +def generate(): + yield 1 + + +generator = generate() +managed("generator repr", type(generator).__repr__(generator)) +generator.close() + + +async def run(): + return 1 + + +coroutine = run() +managed("coroutine repr", type(coroutine).__repr__(coroutine)) +coroutine.close() class SlotOwner: diff --git a/pyre/bench/synth/gc_type_repr_collectable.cranelift.jitstats b/pyre/bench/synth/gc_type_repr_collectable.cranelift.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_type_repr_collectable.cranelift.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_type_repr_collectable.dynasm.jitstats b/pyre/bench/synth/gc_type_repr_collectable.dynasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_type_repr_collectable.dynasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/bench/synth/gc_type_repr_collectable.py b/pyre/bench/synth/gc_type_repr_collectable.py deleted file mode 100644 index 69f4834a57f..00000000000 --- a/pyre/bench/synth/gc_type_repr_collectable.py +++ /dev/null @@ -1,16 +0,0 @@ -# pyre-check: no-cpython -import gc - - -class Sample: - pass - - -ordinary = repr(Sample) -direct = type.__repr__(Sample) - -assert ordinary == direct -assert any(obj is ordinary for obj in gc.get_objects()) -assert any(obj is direct for obj in gc.get_objects()) - -print("type repr results are collectable") diff --git a/pyre/bench/synth/gc_type_repr_collectable.wasm.jitstats b/pyre/bench/synth/gc_type_repr_collectable.wasm.jitstats deleted file mode 100644 index 21df1dd3f43..00000000000 --- a/pyre/bench/synth/gc_type_repr_collectable.wasm.jitstats +++ /dev/null @@ -1,15 +0,0 @@ -bridges_compiled=0 -descr_set_absent=0 -descr_set_ambiguous=0 -descr_set_stale_absent=0 -fbw_blackhole_adopted_multi_frame=0 -fbw_blackhole_adopted_single_frame=0 -fbw_rolled_back_with_effects=0 -fbw_store_journal_rollback_failed=0 -field_pos_attached_misplaced=0 -field_pos_spec_misplaced=0 -guard_failures=0 -internal_compile_panics=0 -loops_aborted=0 -loops_compiled=0 -retraces_compiled=0 diff --git a/pyre/pyre-interpreter/src/typedef.rs b/pyre/pyre-interpreter/src/typedef.rs index c078da54881..0bfea871a89 100644 --- a/pyre/pyre-interpreter/src/typedef.rs +++ b/pyre/pyre-interpreter/src/typedef.rs @@ -26674,7 +26674,7 @@ fn generator_descr_repr(args: &[PyObjectRef]) -> crate::PyResult { fn coroutine_descr_repr(args: &[PyObjectRef]) -> crate::PyResult { let name = generator_name_value(args[0], true)?; - Ok(w_str_new(&format!( + Ok(w_str_new_managed(&format!( "", unsafe { pyre_object::w_str_get_value(name) }, crate::display::repr_addr(args[0] as usize)