MCPcopy Index your code
hub / github.com/RustPython/RustPython / default_dealloc

Function default_dealloc

crates/vm/src/object/core.rs:158–221  ·  view source on GitHub ↗

Default dealloc: handles __del__, weakref clearing, tp_clear, and memory free. Equivalent to subtype_dealloc.

(obj: *mut PyObject)

Source from the content-addressed store, hash-verified

156/// Default dealloc: handles __del__, weakref clearing, tp_clear, and memory free.
157/// Equivalent to subtype_dealloc.
158pub(super) unsafe fn default_dealloc<T: PyPayload>(obj: *mut PyObject) {
159 let obj_ref = unsafe { &*(obj as *const PyObject) };
160 if let Err(()) = obj_ref.drop_slow_inner() {
161 return; // resurrected by __del__
162 }
163
164 // Trashcan: limit recursive deallocation depth to prevent stack overflow
165 if !unsafe { trashcan::begin(obj, default_dealloc::<T>) } {
166 return; // deferred to queue
167 }
168
169 let vtable = obj_ref.0.vtable;
170
171 // Untrack from GC BEFORE deallocation.
172 // Must happen before memory is freed because intrusive list removal
173 // reads the object's gc_pointers (prev/next).
174 if obj_ref.is_gc_tracked() {
175 let ptr = unsafe { NonNull::new_unchecked(obj) };
176 unsafe {
177 crate::gc_state::gc_state().untrack_object(ptr);
178 }
179 // Verify untrack cleared the tracked flag and generation
180 debug_assert!(
181 !obj_ref.is_gc_tracked(),
182 "object still tracked after untrack_object"
183 );
184 debug_assert_eq!(
185 obj_ref.gc_generation(),
186 crate::object::GC_UNTRACKED,
187 "gc_generation not reset after untrack_object"
188 );
189 }
190
191 // Try to store in freelist for reuse BEFORE tp_clear, so that
192 // size-based freelists (e.g. PyTuple) can read the payload directly.
193 // Only exact base types (not heaptype or structseq subtypes) go into the freelist.
194 let typ = obj_ref.class();
195 let pushed = if T::HAS_FREELIST
196 && typ.heaptype_ext.is_none()
197 && core::ptr::eq(typ, T::class(crate::vm::Context::genesis()))
198 {
199 unsafe { T::freelist_push(obj) }
200 } else {
201 false
202 };
203
204 // Extract child references to break circular refs (tp_clear).
205 // This runs regardless of freelist push — the object's children must be released.
206 let mut edges = Vec::new();
207 if let Some(clear_fn) = vtable.clear {
208 unsafe { clear_fn(obj, &mut edges) };
209 }
210
211 if !pushed {
212 // Deallocate the object memory (handles ObjExt prefix if present)
213 unsafe { PyInner::dealloc(obj as *mut PyInner<T>) };
214 }
215

Callers

nothing calls this directly

Calls 10

beginFunction · 0.85
gc_stateFunction · 0.85
newFunction · 0.85
drop_slow_innerMethod · 0.80
is_gc_trackedMethod · 0.80
untrack_objectMethod · 0.80
endFunction · 0.70
eqFunction · 0.50
classMethod · 0.45
is_noneMethod · 0.45

Tested by

no test coverage detected