Skip to content

Commit e8e230c

Browse files
committed
Expose _testinternalcapi recursion and rare events
get_recursion_depth feeds test.support.infinite_recursion. SPECIALIZATION_* and SHARED_KEYS_MAX_SIZE match the adaptive counters. Rare-event hooks increment on __class__/__bases__/function/builtins writes. Assisted-by: Grok:grok-4.6
1 parent 3459756 commit e8e230c

9 files changed

Lines changed: 113 additions & 5 deletions

File tree

‎Lib/test/test_gc.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,7 @@ def test_something(self):
12051205
assert_python_ok("-c", source)
12061206

12071207

1208+
@unittest.expectedFailure # TODO: RUSTPYTHON; get_long_lived_total is not implemented
12081209
@unittest.skipUnless(Py_GIL_DISABLED, "requires free-threaded GC")
12091210
@unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi")
12101211
def test_tuple_untrack_counts(self):
@@ -1222,6 +1223,7 @@ def test_tuple_untrack_counts(self):
12221223
# Use n // 2 just in case some other objects were collected.
12231224
self.assertTrue(new_count - count > (n // 2))
12241225

1226+
@unittest.expectedFailure # TODO: RUSTPYTHON; get_tracked_heap_size is not implemented
12251227
@requires_gil_enabled('need generational GC')
12261228
@unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi")
12271229
def test_heap_size(self):

‎Lib/test/test_inspect/test_inspect.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4308,7 +4308,6 @@ def __init__(self, a):
43084308
self.assertEqual(self.signature(C.__new__, follow_wrapped=False),
43094309
varargs_signature)
43104310

4311-
@unittest.expectedFailure # TODO: RUSTPYTHON
43124311
def test_signature_on_class_with_wrapped_new(self):
43134312
with self.subTest('FunctionType'):
43144313
class C:

‎Lib/test/test_super.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,6 @@ def method(self):
445445

446446
self.assertEqual(C().method(), super)
447447

448-
@unittest.expectedFailure # TODO: RUSTPYTHON; TypeError: type 'super' is not an acceptable base type
449448
def test_super_subclass___class__(self):
450449
class mysuper(super):
451450
pass

‎crates/vm/src/builtins/dict.rs‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -927,7 +927,11 @@ impl Py<PyDict> {
927927
vm: &VirtualMachine,
928928
) -> PyResult<()> {
929929
if self.exact_dict(vm) {
930-
self.inner_setitem(key, value, vm)
930+
self.inner_setitem(key, value, vm)?;
931+
if self.as_object().is(vm.builtins.dict().as_object()) {
932+
crate::stdlib::_testinternalcapi::note_builtin_dict();
933+
}
934+
Ok(())
931935
} else {
932936
self.as_object().set_item(key, value, vm)
933937
}

‎crates/vm/src/builtins/function.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,7 @@ impl PyFunction {
951951
*jit_guard = None;
952952
}
953953
self.func_version.store(0, Relaxed);
954+
crate::stdlib::_testinternalcapi::note_func_modification();
954955
Ok(())
955956
}
956957

@@ -965,6 +966,7 @@ impl PyFunction {
965966
PySetterValue::Delete => None,
966967
};
967968
self.func_version.store(0, Relaxed);
969+
crate::stdlib::_testinternalcapi::note_func_modification();
968970
}
969971

970972
#[pygetset]
@@ -978,6 +980,7 @@ impl PyFunction {
978980
PySetterValue::Delete => None,
979981
};
980982
self.func_version.store(0, Relaxed);
983+
crate::stdlib::_testinternalcapi::note_func_modification();
981984
}
982985

983986
// {"__closure__", T_OBJECT, OFF(func_closure), READONLY},

‎crates/vm/src/builtins/object.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ impl PyBaseObject {
441441
if both_mutable || both_module {
442442
super::type_::compatible_for_assignment(current_cls, &cls, "__class__", vm)?;
443443
instance.set_class(cls, vm);
444+
crate::stdlib::_testinternalcapi::note_set_class();
444445
Ok(())
445446
} else {
446447
Err(vm.new_type_error(

‎crates/vm/src/builtins/type.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1868,6 +1868,7 @@ impl PyType {
18681868
zelf.update_all_slots(&vm.ctx);
18691869

18701870
register_subclasses(&zelf.bases.read());
1871+
crate::stdlib::_testinternalcapi::note_set_bases();
18711872
Ok(())
18721873
});
18731874
drop(retired);
Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,110 @@
11
pub(crate) use _testinternalcapi::module_def;
22

3+
use core::sync::atomic::{AtomicUsize, Ordering};
4+
5+
static RARE_SET_CLASS: AtomicUsize = AtomicUsize::new(0);
6+
static RARE_SET_BASES: AtomicUsize = AtomicUsize::new(0);
7+
static RARE_SET_EVAL_FRAME_FUNC: AtomicUsize = AtomicUsize::new(0);
8+
static RARE_BUILTIN_DICT: AtomicUsize = AtomicUsize::new(0);
9+
static RARE_FUNC_MODIFICATION: AtomicUsize = AtomicUsize::new(0);
10+
11+
pub(crate) fn note_set_class() {
12+
RARE_SET_CLASS.fetch_add(1, Ordering::Relaxed);
13+
}
14+
15+
pub(crate) fn note_set_bases() {
16+
RARE_SET_BASES.fetch_add(1, Ordering::Relaxed);
17+
}
18+
19+
pub(crate) fn note_builtin_dict() {
20+
RARE_BUILTIN_DICT.fetch_add(1, Ordering::Relaxed);
21+
}
22+
23+
pub(crate) fn note_func_modification() {
24+
RARE_FUNC_MODIFICATION.fetch_add(1, Ordering::Relaxed);
25+
}
26+
327
#[pymodule]
428
mod _testinternalcapi {
5-
use crate::{PyObjectRef, VirtualMachine};
29+
use super::*;
30+
use crate::{PyObjectRef, PyResult, VirtualMachine, builtins::PyDictRef};
31+
32+
// ADAPTIVE_WARMUP_VALUE + 1
33+
#[pyattr]
34+
const SPECIALIZATION_THRESHOLD: usize = 2;
35+
36+
// ADAPTIVE_COOLDOWN_VALUE + 1
37+
#[pyattr]
38+
const SPECIALIZATION_COOLDOWN: usize = 53;
39+
40+
#[pyattr]
41+
const SHARED_KEYS_MAX_SIZE: usize = crate::object::SHARED_KEYS_MAX_SIZE;
642

743
#[pyfunction]
844
fn has_inline_values(obj: PyObjectRef, _vm: &VirtualMachine) -> bool {
945
obj.has_inline_values()
1046
}
47+
48+
#[pyfunction]
49+
fn get_recursion_depth(vm: &VirtualMachine) -> usize {
50+
vm.current_recursion_depth()
51+
}
52+
53+
#[pyfunction]
54+
fn reset_rare_event_counters() {
55+
RARE_SET_CLASS.store(0, Ordering::Relaxed);
56+
RARE_SET_BASES.store(0, Ordering::Relaxed);
57+
RARE_SET_EVAL_FRAME_FUNC.store(0, Ordering::Relaxed);
58+
RARE_BUILTIN_DICT.store(0, Ordering::Relaxed);
59+
RARE_FUNC_MODIFICATION.store(0, Ordering::Relaxed);
60+
}
61+
62+
#[pyfunction]
63+
fn get_rare_event_counters(vm: &VirtualMachine) -> PyResult<PyDictRef> {
64+
let dict = vm.ctx.new_dict();
65+
dict.set_item(
66+
"set_class",
67+
vm.ctx
68+
.new_int(RARE_SET_CLASS.load(Ordering::Relaxed))
69+
.into(),
70+
vm,
71+
)?;
72+
dict.set_item(
73+
"set_bases",
74+
vm.ctx
75+
.new_int(RARE_SET_BASES.load(Ordering::Relaxed))
76+
.into(),
77+
vm,
78+
)?;
79+
dict.set_item(
80+
"set_eval_frame_func",
81+
vm.ctx
82+
.new_int(RARE_SET_EVAL_FRAME_FUNC.load(Ordering::Relaxed))
83+
.into(),
84+
vm,
85+
)?;
86+
dict.set_item(
87+
"builtin_dict",
88+
vm.ctx
89+
.new_int(RARE_BUILTIN_DICT.load(Ordering::Relaxed))
90+
.into(),
91+
vm,
92+
)?;
93+
dict.set_item(
94+
"func_modification",
95+
vm.ctx
96+
.new_int(RARE_FUNC_MODIFICATION.load(Ordering::Relaxed))
97+
.into(),
98+
vm,
99+
)?;
100+
Ok(dict)
101+
}
102+
103+
#[pyfunction]
104+
fn set_eval_frame_record(_recorder: PyObjectRef) {
105+
RARE_SET_EVAL_FRAME_FUNC.fetch_add(1, Ordering::Relaxed);
106+
}
107+
108+
#[pyfunction]
109+
fn set_eval_frame_default() {}
11110
}

‎crates/vm/src/stdlib/mod.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ mod _string;
1414
mod _symtable;
1515
mod _sysconfig;
1616
mod _sysconfigdata;
17-
mod _testinternalcapi;
17+
pub(crate) mod _testinternalcapi;
1818
mod _types;
1919
pub mod _typing;
2020
pub mod _warnings;

0 commit comments

Comments
 (0)