44from rpython .jit .metainterp .history import (Const , ConstInt , ConstPtr ,
55 ConstFloat , CONST_NULL , getkind , AbstractDescr )
66from rpython .jit .metainterp import support
7+ from rpython .jit .metainterp .resoperation import rop
78from rpython .flowspace .model import Constant
89from rpython .jit .codewriter .flatten import (
910 Register , TLabel , Label , ListOfKind , IndirectCallTargets )
@@ -131,7 +132,7 @@ def generate(self):
131132 full_code = _apply_peephole_optimizations (full_code )
132133 self .jitcode ._genext_source = full_code
133134 d = {"ConstInt" : ConstInt , "ConstPtr" : ConstPtr , "ConstFloat" : ConstFloat , "JitCode" : JitCode , "ChangeFrame" : ChangeFrame ,
134- "lltype" : lltype , "rstr" : rstr , 'llmemory' : llmemory , 'OBJECTPTR' : OBJECTPTR , 'support' : support }
135+ "lltype" : lltype , "rstr" : rstr , 'llmemory' : llmemory , 'OBJECTPTR' : OBJECTPTR , 'support' : support , 'rop' : rop }
135136 d .update (self .globals )
136137 source = py .code .Source (self .jitcode ._genext_source )
137138 exec source .compile () in d
@@ -2818,6 +2819,52 @@ def _emit_unspecialized_binary(self):
28182819 self ._emit_jump (lines )
28192820 return lines
28202821
2822+ # Mapping from operation name to rop constant for pure binary int ops
2823+ _PURE_BINARY_ROP = {
2824+ 'int_add' : 'rop.INT_ADD' ,
2825+ 'int_sub' : 'rop.INT_SUB' ,
2826+ 'int_mul' : 'rop.INT_MUL' ,
2827+ 'int_and' : 'rop.INT_AND' ,
2828+ 'int_or' : 'rop.INT_OR' ,
2829+ 'int_xor' : 'rop.INT_XOR' ,
2830+ 'int_lshift' : 'rop.INT_LSHIFT' ,
2831+ 'int_rshift' : 'rop.INT_RSHIFT' ,
2832+ 'int_lt' : 'rop.INT_LT' ,
2833+ 'int_le' : 'rop.INT_LE' ,
2834+ 'int_gt' : 'rop.INT_GT' ,
2835+ 'int_ge' : 'rop.INT_GE' ,
2836+ 'int_eq' : 'rop.INT_EQ' ,
2837+ 'int_ne' : 'rop.INT_NE' ,
2838+ }
2839+
2840+ def _emit_unspecialized_pure_binary_i (self ):
2841+ """Fast path for pure integer binary operations.
2842+
2843+ Uses MetaInterp.execute_and_record_pure_i() which bypasses:
2844+ - Method lookup chain (opimpl_* -> execute -> execute_and_record)
2845+ - Unnecessary constant-fold checks (we already know args aren't const)
2846+ - Heapcache invalidation (pure ops can't affect it)
2847+ """
2848+ lines = []
2849+ arg0 , arg1 , result = self ._get_args_and_res ()
2850+ self ._emit_n_ary_if ([arg0 , arg1 ], lines )
2851+ self ._emit_jump (lines , constant_registers = self .constant_registers .union ({arg0 , arg1 }),
2852+ indent = ' ' , target_pc = self .orig_pc )
2853+ lines .append ("else:" )
2854+ # Use fast path: direct execute_and_record_pure_i
2855+ rop_const = self ._PURE_BINARY_ROP .get (self .name )
2856+ if rop_const is not None :
2857+ lines .append (" self.registers_i[%d] = self.metainterp.execute_and_record_pure_i(%s, %s, %s)" % (
2858+ result .index , rop_const ,
2859+ self ._get_as_box (arg0 ), self ._get_as_box (arg1 )))
2860+ else :
2861+ # Fallback to opimpl for operations not in fast-path list
2862+ lines .append (" self.registers_i[%d] = self.%s(%s, %s)" % (
2863+ result .index , self .methodname ,
2864+ self ._get_as_box (arg0 ), self ._get_as_box (arg1 )))
2865+ self ._emit_jump (lines )
2866+ return lines
2867+
28212868 def _emit_unspecialized_float_binary (self ):
28222869 lines = []
28232870 arg0 , arg1 , result = self ._get_args_and_res ()
@@ -2831,20 +2878,22 @@ def _emit_unspecialized_float_binary(self):
28312878 self ._emit_jump (lines )
28322879 return lines
28332880
2834- emit_unspecialized_int_add = _emit_unspecialized_binary
2835- emit_unspecialized_int_sub = _emit_unspecialized_binary
2836- emit_unspecialized_int_mul = _emit_unspecialized_binary
2837- emit_unspecialized_int_or = _emit_unspecialized_binary
2838- emit_unspecialized_int_and = _emit_unspecialized_binary
2839- emit_unspecialized_int_rshift = _emit_unspecialized_binary
2840- emit_unspecialized_int_lshift = _emit_unspecialized_binary
2841- emit_unspecialized_int_le = _emit_unspecialized_binary
2842- emit_unspecialized_int_lt = _emit_unspecialized_binary
2843- emit_unspecialized_int_ge = _emit_unspecialized_binary
2844- emit_unspecialized_int_gt = _emit_unspecialized_binary
2845- emit_unspecialized_int_eq = _emit_unspecialized_binary
2846- emit_unspecialized_int_ne = _emit_unspecialized_binary
2847- emit_unspecialized_int_xor = _emit_unspecialized_binary
2881+ # Pure integer binary ops use fast path (skip method chain overhead)
2882+ emit_unspecialized_int_add = _emit_unspecialized_pure_binary_i
2883+ emit_unspecialized_int_sub = _emit_unspecialized_pure_binary_i
2884+ emit_unspecialized_int_mul = _emit_unspecialized_pure_binary_i
2885+ emit_unspecialized_int_or = _emit_unspecialized_pure_binary_i
2886+ emit_unspecialized_int_and = _emit_unspecialized_pure_binary_i
2887+ emit_unspecialized_int_rshift = _emit_unspecialized_pure_binary_i
2888+ emit_unspecialized_int_lshift = _emit_unspecialized_pure_binary_i
2889+ emit_unspecialized_int_le = _emit_unspecialized_pure_binary_i
2890+ emit_unspecialized_int_lt = _emit_unspecialized_pure_binary_i
2891+ emit_unspecialized_int_ge = _emit_unspecialized_pure_binary_i
2892+ emit_unspecialized_int_gt = _emit_unspecialized_pure_binary_i
2893+ emit_unspecialized_int_eq = _emit_unspecialized_pure_binary_i
2894+ emit_unspecialized_int_ne = _emit_unspecialized_pure_binary_i
2895+ emit_unspecialized_int_xor = _emit_unspecialized_pure_binary_i
2896+ # int_mod and int_floordiv use old path (can raise ZeroDivisionError)
28482897 emit_unspecialized_int_mod = _emit_unspecialized_binary
28492898 emit_unspecialized_int_floordiv = _emit_unspecialized_binary
28502899
0 commit comments