Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c6b6842
fix jit
youknowone Mar 4, 2026
b379239
vm: complete specialized opcode dispatch paths
youknowone Mar 4, 2026
bdeca2b
vm: cache LOAD_GLOBAL with dict entry hints
youknowone Mar 4, 2026
ca3814a
vm: align adaptive specialization counters with CPython backoff
youknowone Mar 4, 2026
f04bf22
vm: apply cooldown counter on specialization success paths
youknowone Mar 4, 2026
02a1495
vm: retain LOAD_GLOBAL specializations on misses
youknowone Mar 4, 2026
13125d8
vm: keep attr and call specializations on guard misses
youknowone Mar 4, 2026
c7007b5
vm: retain store-attr and store-subscr specializations on misses
youknowone Mar 4, 2026
453294d
vm: retain specialization opcodes on generic fallback paths
youknowone Mar 4, 2026
b8f6cc2
vm: align jump-backward specialization defaults with CPython
youknowone Mar 4, 2026
7bfa961
vm: retain exact-args call specializations on misses
youknowone Mar 4, 2026
c852994
vm: retain SEND_GEN specialization on non-coroutine sends
youknowone Mar 4, 2026
1a1bbf5
vm: specialize list.append calls like CPython CALL_LIST_APPEND
youknowone Mar 4, 2026
bdd87f4
vm: set cooldown on LOAD_ATTR_CLASS specialization
youknowone Mar 4, 2026
696e57a
vm: specialize bound method object CALL paths
youknowone Mar 4, 2026
3dc64cc
vm: specialize CALL_KW for bound method objects
youknowone Mar 4, 2026
f220a24
vm: use current-state function version for CALL_KW specialization
youknowone Mar 4, 2026
a66c706
vm: align CALL/CALL_KW pyfunction specialization with CPython
youknowone Mar 4, 2026
59545f5
vm: drop call-site identity caches in generic CALL specializations
youknowone Mar 4, 2026
f8eebec
vm: align builtin type call specializations with CPython guards
youknowone Mar 4, 2026
58bb1ea
vm: align builtin CALL guards with CPython self_or_null semantics
youknowone Mar 4, 2026
157a2c3
vm: require exact list in CALL_LIST_APPEND fast path
youknowone Mar 4, 2026
cae26d4
vm: align CALL builtin/class specialization flow with CPython
youknowone Mar 4, 2026
0d01f7e
vm: tighten len/isinstance CALL specializations to builtin guards
youknowone Mar 4, 2026
22cccae
vm: gate CALL_BUILTIN_CLASS on type vectorcall like CPython
youknowone Mar 4, 2026
30e8a75
vm: run non-py CALL specializations via direct vectorcall
youknowone Mar 4, 2026
da36859
vm: align class-call specialization branching with CPython
youknowone Mar 4, 2026
42d81ff
Fix CI: disable ForIterGen, tighten CALL guards
youknowone Mar 4, 2026
d464119
vm: restore FOR_ITER_GEN specialization and tuple index parity
youknowone Mar 4, 2026
0f044d6
Add datastack-backed FastLocals for non-generator frames
youknowone Mar 4, 2026
cc3fd09
Drop read lock before key_eq in dict get_hint
youknowone Mar 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix CI: disable ForIterGen, tighten CALL guards
- Disable ForIterGen specialization (falls through to generic
  path) because inline generator frame resumption is needed
  for correct debugger StopIteration visibility (test_bdb)
- Use downcast_ref_if_exact for PyNativeFunction in CALL
  specialization guards
- Add can_specialize_call guard for class __init__ specialization
- Remove expectedFailure for test_bad_newobj_args (now passing)
  • Loading branch information
youknowone committed Mar 4, 2026
commit 42d81ffe6cb63eb2c055941c0eb2a986afee273a
4 changes: 0 additions & 4 deletions Lib/test/test_pickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,6 @@ def dumps(self, arg, proto=None, **kwargs):
f.seek(0)
return bytes(f.read())

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_bad_newobj_args(self):
return super().test_bad_newobj_args()

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_buffer_callback_error(self):
return super().test_buffer_callback_error()
Expand Down
46 changes: 22 additions & 24 deletions crates/vm/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3508,7 +3508,7 @@ impl ExecutingFrame<'_> {
let callable = self.pop_value();
let callable_tag = &*callable as *const PyObject as u32;
let is_len_callable = callable
.downcast_ref::<PyNativeFunction>()
.downcast_ref_if_exact::<PyNativeFunction>(vm)
.is_some_and(|native| native.zelf.is_none() && native.value.name == "len");
if null.is_none() && cached_tag == callable_tag && is_len_callable {
let len = obj.length(vm)?;
Expand Down Expand Up @@ -3536,7 +3536,7 @@ impl ExecutingFrame<'_> {
let callable = self.nth_value(nargs + 1);
let callable_tag = callable as *const PyObject as u32;
let is_isinstance_callable = callable
.downcast_ref::<PyNativeFunction>()
.downcast_ref_if_exact::<PyNativeFunction>(vm)
.is_some_and(|native| {
native.zelf.is_none() && native.value.name == "isinstance"
});
Expand Down Expand Up @@ -3626,7 +3626,11 @@ impl ExecutingFrame<'_> {
let self_or_null_is_some = stack[stack_len - nargs as usize - 1].is_some();
let effective_nargs = nargs + u32::from(self_or_null_is_some);
let callable = self.nth_value(nargs + 1);
if callable.downcast_ref::<PyNativeFunction>().is_some() && effective_nargs == 1 {
if callable
.downcast_ref_if_exact::<PyNativeFunction>(vm)
.is_some()
&& effective_nargs == 1
{
let nargs_usize = nargs as usize;
let pos_args: Vec<PyObjectRef> = self.pop_multiple(nargs_usize).collect();
let self_or_null = self.pop_value_opt();
Expand All @@ -3651,7 +3655,10 @@ impl ExecutingFrame<'_> {
let self_or_null_is_some = stack[stack_len - nargs as usize - 1].is_some();
let effective_nargs = nargs + u32::from(self_or_null_is_some);
let callable = self.nth_value(nargs + 1);
if callable.downcast_ref::<PyNativeFunction>().is_some() {
if callable
.downcast_ref_if_exact::<PyNativeFunction>(vm)
.is_some()
{
let nargs_usize = nargs as usize;
let pos_args: Vec<PyObjectRef> = self.pop_multiple(nargs_usize).collect();
let self_or_null = self.pop_value_opt();
Expand Down Expand Up @@ -3921,6 +3928,7 @@ impl ExecutingFrame<'_> {
// Look up __init__ (guarded by type_version)
if let Some(init) = cls.get_attr(identifier!(vm, __init__))
&& let Some(init_func) = init.downcast_ref::<PyFunction>()
&& init_func.can_specialize_call(nargs + 1)
{
// Allocate object directly (tp_new == object.__new__)
let dict = if cls
Expand Down Expand Up @@ -4003,7 +4011,10 @@ impl ExecutingFrame<'_> {
let self_or_null_is_some = stack[stack_len - nargs as usize - 1].is_some();
let effective_nargs = nargs + u32::from(self_or_null_is_some);
let callable = self.nth_value(nargs + 1);
if callable.downcast_ref::<PyNativeFunction>().is_some() {
if callable
.downcast_ref_if_exact::<PyNativeFunction>(vm)
.is_some()
{
let nargs_usize = nargs as usize;
let pos_args: Vec<PyObjectRef> = self.pop_multiple(nargs_usize).collect();
let self_or_null = self.pop_value_opt();
Expand Down Expand Up @@ -4601,23 +4612,12 @@ impl ExecutingFrame<'_> {
}
}
Instruction::ForIterGen => {
// ForIterGen is not faithfully implementable without inline
// generator frame resumption (as CPython does). Fall through
// to the generic path so the debugger sees StopIteration.
let target = bytecode::Label(self.lasti() + 1 + u32::from(arg));
let iter = self.top_value();
if let Some(generator) = iter.downcast_ref_if_exact::<PyGenerator>(vm) {
match generator.as_coro().send(iter, vm.ctx.none(), vm) {
Ok(PyIterReturn::Return(value)) => {
self.push_value(value);
}
Ok(PyIterReturn::StopIteration(_)) => {
self.for_iter_jump_on_exhausted(target);
}
Err(e) => return Err(e),
}
Ok(None)
} else {
self.execute_for_iter(vm, target)?;
Ok(None)
}
self.execute_for_iter(vm, target)?;
Ok(None)
}
Instruction::LoadGlobalModule => {
let oparg = u32::from(arg);
Expand Down Expand Up @@ -6964,7 +6964,7 @@ impl ExecutingFrame<'_> {
}

// Try to specialize builtin calls
if let Some(native) = callable.downcast_ref::<PyNativeFunction>() {
if let Some(native) = callable.downcast_ref_if_exact::<PyNativeFunction>(vm) {
let effective_nargs = nargs + u32::from(self_or_null_is_some);
let callable_tag = callable as *const PyObject as u32;
let new_op = if native.zelf.is_none()
Expand Down Expand Up @@ -7299,8 +7299,6 @@ impl ExecutingFrame<'_> {
Some(Instruction::ForIterList)
} else if iter.downcast_ref_if_exact::<PyTupleIterator>(vm).is_some() {
Some(Instruction::ForIterTuple)
} else if iter.downcast_ref_if_exact::<PyGenerator>(vm).is_some() {
Some(Instruction::ForIterGen)
} else {
None
};
Expand Down