@@ -3620,17 +3620,13 @@ impl ExecutingFrame<'_> {
36203620 self . execute_call ( args, vm)
36213621 }
36223622 Instruction :: CallBuiltinO => {
3623- let instr_idx = self . lasti ( ) as usize - 1 ;
3624- let cache_base = instr_idx + 1 ;
3625- let cached_tag = self . code . instructions . read_cache_u32 ( cache_base + 1 ) ;
36263623 let nargs: u32 = arg. into ( ) ;
36273624 if nargs == 1 {
36283625 let obj = self . pop_value ( ) ;
36293626 let _null = self . pop_value_opt ( ) ;
36303627 let callable = self . pop_value ( ) ;
3631- let callable_tag = & * callable as * const PyObject as u32 ;
3632- if cached_tag == callable_tag
3633- && let Some ( native) = callable. downcast_ref :: < PyNativeFunction > ( )
3628+ if let Some ( native) = callable. downcast_ref :: < PyNativeFunction > ( )
3629+ && native. zelf . is_none ( )
36343630 {
36353631 let args = FuncArgs {
36363632 args : vec ! [ obj] ,
@@ -3648,18 +3644,13 @@ impl ExecutingFrame<'_> {
36483644 self . execute_call ( args, vm)
36493645 }
36503646 Instruction :: CallBuiltinFast => {
3651- let instr_idx = self . lasti ( ) as usize - 1 ;
3652- let cache_base = instr_idx + 1 ;
3653- let cached_tag = self . code . instructions . read_cache_u32 ( cache_base + 1 ) ;
36543647 let nargs: u32 = arg. into ( ) ;
36553648 let callable = self . nth_value ( nargs + 1 ) ;
3656- let callable_tag = callable as * const PyObject as u32 ;
3657- let func = if cached_tag == callable_tag {
3649+ let func = {
36583650 callable
36593651 . downcast_ref :: < PyNativeFunction > ( )
3652+ . filter ( |n| n. zelf . is_none ( ) )
36603653 . map ( |n| n. value . func )
3661- } else {
3662- None
36633654 } ;
36643655 if let Some ( func) = func {
36653656 let positional_args: Vec < PyObjectRef > =
@@ -3751,21 +3742,24 @@ impl ExecutingFrame<'_> {
37513742 }
37523743 }
37533744 Instruction :: CallListAppend => {
3754- let instr_idx = self . lasti ( ) as usize - 1 ;
3755- let cache_base = instr_idx + 1 ;
3756- let cached_tag = self . code . instructions . read_cache_u32 ( cache_base + 1 ) ;
37573745 let nargs: u32 = arg. into ( ) ;
37583746 if nargs == 1 {
37593747 // Stack: [callable, self_or_null, item]
37603748 let stack = & self . state . stack ;
37613749 let stack_len = stack. len ( ) ;
37623750 let self_or_null_is_some = stack[ stack_len - 2 ] . is_some ( ) ;
37633751 let callable = self . nth_value ( 2 ) ;
3764- let callable_tag = callable as * const PyObject as u32 ;
37653752 let self_is_list = stack[ stack_len - 2 ]
37663753 . as_ref ( )
37673754 . is_some_and ( |obj| obj. downcast_ref :: < PyList > ( ) . is_some ( ) ) ;
3768- if cached_tag == callable_tag && self_or_null_is_some && self_is_list {
3755+ let is_list_append =
3756+ callable
3757+ . downcast_ref :: < PyMethodDescriptor > ( )
3758+ . is_some_and ( |descr| {
3759+ descr. method . name == "append"
3760+ && descr. objclass . is ( vm. ctx . types . list_type )
3761+ } ) ;
3762+ if is_list_append && self_or_null_is_some && self_is_list {
37693763 let item = self . pop_value ( ) ;
37703764 let self_or_null = self . pop_value_opt ( ) ;
37713765 let callable = self . pop_value ( ) ;
@@ -3789,18 +3783,14 @@ impl ExecutingFrame<'_> {
37893783 self . execute_call ( args, vm)
37903784 }
37913785 Instruction :: CallMethodDescriptorNoargs => {
3792- let instr_idx = self . lasti ( ) as usize - 1 ;
3793- let cache_base = instr_idx + 1 ;
3794- let cached_tag = self . code . instructions . read_cache_u32 ( cache_base + 1 ) ;
37953786 let nargs: u32 = arg. into ( ) ;
37963787 if nargs == 0 {
37973788 // Stack: [callable, self_or_null] — peek to get func ptr
37983789 let stack = & self . state . stack ;
37993790 let stack_len = stack. len ( ) ;
38003791 let self_or_null_is_some = stack[ stack_len - 1 ] . is_some ( ) ;
38013792 let callable = self . nth_value ( 1 ) ;
3802- let callable_tag = callable as * const PyObject as u32 ;
3803- let func = if cached_tag == callable_tag && self_or_null_is_some {
3793+ let func = if self_or_null_is_some {
38043794 callable
38053795 . downcast_ref :: < PyMethodDescriptor > ( )
38063796 . map ( |d| d. method . func )
@@ -3823,18 +3813,14 @@ impl ExecutingFrame<'_> {
38233813 self . execute_call ( args, vm)
38243814 }
38253815 Instruction :: CallMethodDescriptorO => {
3826- let instr_idx = self . lasti ( ) as usize - 1 ;
3827- let cache_base = instr_idx + 1 ;
3828- let cached_tag = self . code . instructions . read_cache_u32 ( cache_base + 1 ) ;
38293816 let nargs: u32 = arg. into ( ) ;
38303817 if nargs == 1 {
38313818 // Stack: [callable, self_or_null, arg1]
38323819 let stack = & self . state . stack ;
38333820 let stack_len = stack. len ( ) ;
38343821 let self_or_null_is_some = stack[ stack_len - 2 ] . is_some ( ) ;
38353822 let callable = self . nth_value ( 2 ) ;
3836- let callable_tag = callable as * const PyObject as u32 ;
3837- let func = if cached_tag == callable_tag && self_or_null_is_some {
3823+ let func = if self_or_null_is_some {
38383824 callable
38393825 . downcast_ref :: < PyMethodDescriptor > ( )
38403826 . map ( |d| d. method . func )
@@ -3858,16 +3844,12 @@ impl ExecutingFrame<'_> {
38583844 self . execute_call ( args, vm)
38593845 }
38603846 Instruction :: CallMethodDescriptorFast => {
3861- let instr_idx = self . lasti ( ) as usize - 1 ;
3862- let cache_base = instr_idx + 1 ;
3863- let cached_tag = self . code . instructions . read_cache_u32 ( cache_base + 1 ) ;
38643847 let nargs: u32 = arg. into ( ) ;
38653848 let callable = self . nth_value ( nargs + 1 ) ;
3866- let callable_tag = callable as * const PyObject as u32 ;
38673849 let stack = & self . state . stack ;
38683850 let stack_len = stack. len ( ) ;
38693851 let self_or_null_is_some = stack[ stack_len - nargs as usize - 1 ] . is_some ( ) ;
3870- let func = if cached_tag == callable_tag && self_or_null_is_some {
3852+ let func = if self_or_null_is_some {
38713853 callable
38723854 . downcast_ref :: < PyMethodDescriptor > ( )
38733855 . map ( |d| d. method . func )
@@ -3894,13 +3876,9 @@ impl ExecutingFrame<'_> {
38943876 self . execute_call ( args, vm)
38953877 }
38963878 Instruction :: CallBuiltinClass => {
3897- let instr_idx = self . lasti ( ) as usize - 1 ;
3898- let cache_base = instr_idx + 1 ;
3899- let cached_tag = self . code . instructions . read_cache_u32 ( cache_base + 1 ) ;
39003879 let nargs: u32 = arg. into ( ) ;
39013880 let callable = self . nth_value ( nargs + 1 ) ;
3902- let callable_tag = callable as * const PyObject as u32 ;
3903- if cached_tag == callable_tag && callable. downcast_ref :: < PyType > ( ) . is_some ( ) {
3881+ if callable. downcast_ref :: < PyType > ( ) . is_some ( ) {
39043882 let args = self . collect_positional_args ( nargs) ;
39053883 let self_or_null = self . pop_value_opt ( ) ;
39063884 let callable = self . pop_value ( ) ;
@@ -3978,16 +3956,12 @@ impl ExecutingFrame<'_> {
39783956 }
39793957 Instruction :: CallMethodDescriptorFastWithKeywords => {
39803958 // Native function interface is uniform regardless of keyword support
3981- let instr_idx = self . lasti ( ) as usize - 1 ;
3982- let cache_base = instr_idx + 1 ;
3983- let cached_tag = self . code . instructions . read_cache_u32 ( cache_base + 1 ) ;
39843959 let nargs: u32 = arg. into ( ) ;
39853960 let callable = self . nth_value ( nargs + 1 ) ;
3986- let callable_tag = callable as * const PyObject as u32 ;
39873961 let stack = & self . state . stack ;
39883962 let stack_len = stack. len ( ) ;
39893963 let self_or_null_is_some = stack[ stack_len - nargs as usize - 1 ] . is_some ( ) ;
3990- let func = if cached_tag == callable_tag && self_or_null_is_some {
3964+ let func = if self_or_null_is_some {
39913965 callable
39923966 . downcast_ref :: < PyMethodDescriptor > ( )
39933967 . map ( |d| d. method . func )
@@ -4015,18 +3989,13 @@ impl ExecutingFrame<'_> {
40153989 }
40163990 Instruction :: CallBuiltinFastWithKeywords => {
40173991 // Native function interface is uniform regardless of keyword support
4018- let instr_idx = self . lasti ( ) as usize - 1 ;
4019- let cache_base = instr_idx + 1 ;
4020- let cached_tag = self . code . instructions . read_cache_u32 ( cache_base + 1 ) ;
40213992 let nargs: u32 = arg. into ( ) ;
40223993 let callable = self . nth_value ( nargs + 1 ) ;
4023- let callable_tag = callable as * const PyObject as u32 ;
4024- let func = if cached_tag == callable_tag {
3994+ let func = {
40253995 callable
40263996 . downcast_ref :: < PyNativeFunction > ( )
3997+ . filter ( |n| n. zelf . is_none ( ) )
40273998 . map ( |n| n. value . func )
4028- } else {
4029- None
40303999 } ;
40314000 if let Some ( func) = func {
40324001 let positional_args: Vec < PyObjectRef > =
@@ -4045,13 +4014,11 @@ impl ExecutingFrame<'_> {
40454014 self . execute_call ( args, vm)
40464015 }
40474016 Instruction :: CallNonPyGeneral => {
4048- let instr_idx = self . lasti ( ) as usize - 1 ;
4049- let cache_base = instr_idx + 1 ;
4050- let cached_tag = self . code . instructions . read_cache_u32 ( cache_base + 1 ) ;
40514017 let nargs: u32 = arg. into ( ) ;
40524018 let callable = self . nth_value ( nargs + 1 ) ;
4053- let callable_tag = callable as * const PyObject as u32 ;
4054- if cached_tag == callable_tag {
4019+ if callable. downcast_ref :: < PyFunction > ( ) . is_some ( )
4020+ || callable. downcast_ref :: < PyBoundMethod > ( ) . is_some ( )
4021+ {
40554022 let args = self . collect_positional_args ( nargs) ;
40564023 return self . execute_call ( args, vm) ;
40574024 }
@@ -4149,13 +4116,11 @@ impl ExecutingFrame<'_> {
41494116 self . execute_call ( args, vm)
41504117 }
41514118 Instruction :: CallKwNonPy => {
4152- let instr_idx = self . lasti ( ) as usize - 1 ;
4153- let cache_base = instr_idx + 1 ;
4154- let cached_tag = self . code . instructions . read_cache_u32 ( cache_base + 1 ) ;
41554119 let nargs: u32 = arg. into ( ) ;
41564120 let callable = self . nth_value ( nargs + 2 ) ;
4157- let callable_tag = callable as * const PyObject as u32 ;
4158- if cached_tag == callable_tag {
4121+ if callable. downcast_ref :: < PyFunction > ( ) . is_some ( )
4122+ || callable. downcast_ref :: < PyBoundMethod > ( ) . is_some ( )
4123+ {
41594124 let args = self . collect_keyword_args ( nargs) ;
41604125 return self . execute_call ( args, vm) ;
41614126 }
@@ -6920,7 +6885,6 @@ impl ExecutingFrame<'_> {
69206885
69216886 // Try to specialize method descriptor calls
69226887 if self_or_null_is_some && let Some ( descr) = callable. downcast_ref :: < PyMethodDescriptor > ( ) {
6923- let callable_tag = callable as * const PyObject as u32 ;
69246888 let call_cache_entries = Instruction :: CallListAppend . cache_entries ( ) ;
69256889 let next_idx = cache_base + call_cache_entries;
69266890 let next_is_pop_top = if next_idx < self . code . instructions . len ( ) {
@@ -6943,11 +6907,6 @@ impl ExecutingFrame<'_> {
69436907 _ => Instruction :: CallMethodDescriptorFast ,
69446908 }
69456909 } ;
6946- unsafe {
6947- self . code
6948- . instructions
6949- . write_cache_u32 ( cache_base + 1 , callable_tag) ;
6950- }
69516910 self . specialize_at ( instr_idx, cache_base, new_op) ;
69526911 return ;
69536912 }
@@ -6966,10 +6925,12 @@ impl ExecutingFrame<'_> {
69666925 } ;
69676926 let new_op = Some ( new_op) ;
69686927 if let Some ( new_op) = new_op {
6969- unsafe {
6970- self . code
6971- . instructions
6972- . write_cache_u32 ( cache_base + 1 , callable_tag) ;
6928+ if matches ! ( new_op, Instruction :: CallLen | Instruction :: CallIsinstance ) {
6929+ unsafe {
6930+ self . code
6931+ . instructions
6932+ . write_cache_u32 ( cache_base + 1 , callable_tag) ;
6933+ }
69736934 }
69746935 self . specialize_at ( instr_idx, cache_base, new_op) ;
69756936 return ;
@@ -7027,24 +6988,12 @@ impl ExecutingFrame<'_> {
70276988 }
70286989 }
70296990 // General builtin class call (any type with Callable)
7030- let callable_tag = callable as * const PyObject as u32 ;
7031- unsafe {
7032- self . code
7033- . instructions
7034- . write_cache_u32 ( cache_base + 1 , callable_tag) ;
7035- }
70366991 self . specialize_at ( instr_idx, cache_base, Instruction :: CallBuiltinClass ) ;
70376992 return ;
70386993 }
70396994 }
70406995
7041- // General fallback: cache callable identity to skip re-specialization
7042- let callable_tag = callable as * const PyObject as u32 ;
7043- unsafe {
7044- self . code
7045- . instructions
7046- . write_cache_u32 ( cache_base + 1 , callable_tag) ;
7047- }
6996+ // General fallback: specialized non-Python callable path
70486997 self . specialize_at ( instr_idx, cache_base, Instruction :: CallNonPyGeneral ) ;
70496998 }
70506999
@@ -7116,13 +7065,7 @@ impl ExecutingFrame<'_> {
71167065 return ;
71177066 }
71187067
7119- // General fallback
7120- let callable_tag = callable as * const PyObject as u32 ;
7121- unsafe {
7122- self . code
7123- . instructions
7124- . write_cache_u32 ( cache_base + 1 , callable_tag) ;
7125- }
7068+ // General fallback: specialized non-Python callable path
71267069 self . specialize_at ( instr_idx, cache_base, Instruction :: CallKwNonPy ) ;
71277070 }
71287071
0 commit comments