mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	GH-131798: Split CALL_LEN into several uops (GH-133180)
This commit is contained in:
		
							parent
							
								
									893034cf93
								
							
						
					
					
						commit
						9cc77aaf9d
					
				
					 11 changed files with 314 additions and 281 deletions
				
			
		|  | @ -4337,22 +4337,25 @@ dummy_func( | |||
|             _CALL_BUILTIN_FAST_WITH_KEYWORDS + | ||||
|             _CHECK_PERIODIC; | ||||
| 
 | ||||
|         inst(CALL_LEN, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { | ||||
|             /* len(o) */ | ||||
|             PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); | ||||
|         macro(CALL_LEN) = | ||||
|             unused/1 + | ||||
|             unused/2 + | ||||
|             _GUARD_NOS_NULL + | ||||
|             _GUARD_CALLABLE_LEN + | ||||
|             _CALL_LEN; | ||||
| 
 | ||||
|             int total_args = oparg; | ||||
|             if (!PyStackRef_IsNull(self_or_null)) { | ||||
|                 args--; | ||||
|                 total_args++; | ||||
|             } | ||||
|             DEOPT_IF(total_args != 1); | ||||
|         op(_GUARD_CALLABLE_LEN, (callable, unused, unused -- callable, unused, unused)){ | ||||
|             PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); | ||||
|             PyInterpreterState *interp = tstate->interp; | ||||
|             DEOPT_IF(callable_o != interp->callable_cache.len); | ||||
|         } | ||||
| 
 | ||||
|         op(_CALL_LEN, (callable, null, arg -- res)) { | ||||
|             /* len(o) */ | ||||
|             (void)null; | ||||
|             STAT_INC(CALL, hit); | ||||
|             _PyStackRef arg_stackref = args[0]; | ||||
|             PyObject *arg = PyStackRef_AsPyObjectBorrow(arg_stackref); | ||||
|             Py_ssize_t len_i = PyObject_Length(arg); | ||||
|             PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); | ||||
|             Py_ssize_t len_i = PyObject_Length(arg_o); | ||||
|             if (len_i < 0) { | ||||
|                 ERROR_NO_POP(); | ||||
|             } | ||||
|  | @ -4361,9 +4364,8 @@ dummy_func( | |||
|             if (res_o == NULL) { | ||||
|                 ERROR_NO_POP(); | ||||
|             } | ||||
|             PyStackRef_CLOSE(arg_stackref); | ||||
|             DEAD(args); | ||||
|             DEAD(self_or_null); | ||||
|             PyStackRef_CLOSE(arg); | ||||
|             DEAD(null); | ||||
|             PyStackRef_CLOSE(callable); | ||||
|             res = PyStackRef_FromPyObjectSteal(res_o); | ||||
|         } | ||||
|  |  | |||
							
								
								
									
										42
									
								
								Python/executor_cases.c.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										42
									
								
								Python/executor_cases.c.h
									
										
									
										generated
									
									
									
								
							|  | @ -5788,35 +5788,31 @@ | |||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         case _CALL_LEN: { | ||||
|             _PyStackRef *args; | ||||
|             _PyStackRef self_or_null; | ||||
|         case _GUARD_CALLABLE_LEN: { | ||||
|             _PyStackRef callable; | ||||
|             _PyStackRef res; | ||||
|             oparg = CURRENT_OPARG(); | ||||
|             args = &stack_pointer[-oparg]; | ||||
|             self_or_null = stack_pointer[-1 - oparg]; | ||||
|             callable = stack_pointer[-2 - oparg]; | ||||
|             callable = stack_pointer[-3]; | ||||
|             PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); | ||||
|             int total_args = oparg; | ||||
|             if (!PyStackRef_IsNull(self_or_null)) { | ||||
|                 args--; | ||||
|                 total_args++; | ||||
|             } | ||||
|             if (total_args != 1) { | ||||
|                 UOP_STAT_INC(uopcode, miss); | ||||
|                 JUMP_TO_JUMP_TARGET(); | ||||
|             } | ||||
|             PyInterpreterState *interp = tstate->interp; | ||||
|             if (callable_o != interp->callable_cache.len) { | ||||
|                 UOP_STAT_INC(uopcode, miss); | ||||
|                 JUMP_TO_JUMP_TARGET(); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         case _CALL_LEN: { | ||||
|             _PyStackRef arg; | ||||
|             _PyStackRef null; | ||||
|             _PyStackRef callable; | ||||
|             _PyStackRef res; | ||||
|             arg = stack_pointer[-1]; | ||||
|             null = stack_pointer[-2]; | ||||
|             callable = stack_pointer[-3]; | ||||
|             (void)null; | ||||
|             STAT_INC(CALL, hit); | ||||
|             _PyStackRef arg_stackref = args[0]; | ||||
|             PyObject *arg = PyStackRef_AsPyObjectBorrow(arg_stackref); | ||||
|             PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); | ||||
|             _PyFrame_SetStackPointer(frame, stack_pointer); | ||||
|             Py_ssize_t len_i = PyObject_Length(arg); | ||||
|             Py_ssize_t len_i = PyObject_Length(arg_o); | ||||
|             stack_pointer = _PyFrame_GetStackPointer(frame); | ||||
|             if (len_i < 0) { | ||||
|                 JUMP_TO_ERROR(); | ||||
|  | @ -5826,10 +5822,12 @@ | |||
|             if (res_o == NULL) { | ||||
|                 JUMP_TO_ERROR(); | ||||
|             } | ||||
|             stack_pointer += -1; | ||||
|             assert(WITHIN_STACK_BOUNDS()); | ||||
|             _PyFrame_SetStackPointer(frame, stack_pointer); | ||||
|             PyStackRef_CLOSE(arg_stackref); | ||||
|             PyStackRef_CLOSE(arg); | ||||
|             stack_pointer = _PyFrame_GetStackPointer(frame); | ||||
|             stack_pointer += -2 - oparg; | ||||
|             stack_pointer += -2; | ||||
|             assert(WITHIN_STACK_BOUNDS()); | ||||
|             _PyFrame_SetStackPointer(frame, stack_pointer); | ||||
|             PyStackRef_CLOSE(callable); | ||||
|  |  | |||
							
								
								
									
										90
									
								
								Python/generated_cases.c.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										90
									
								
								Python/generated_cases.c.h
									
										
									
										generated
									
									
									
								
							|  | @ -3414,55 +3414,61 @@ | |||
|             next_instr += 4; | ||||
|             INSTRUCTION_STATS(CALL_LEN); | ||||
|             static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); | ||||
|             _PyStackRef null; | ||||
|             _PyStackRef callable; | ||||
|             _PyStackRef self_or_null; | ||||
|             _PyStackRef *args; | ||||
|             _PyStackRef arg; | ||||
|             _PyStackRef res; | ||||
|             /* Skip 1 cache entry */ | ||||
|             /* Skip 2 cache entries */ | ||||
|             args = &stack_pointer[-oparg]; | ||||
|             self_or_null = stack_pointer[-1 - oparg]; | ||||
|             callable = stack_pointer[-2 - oparg]; | ||||
|             PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); | ||||
|             int total_args = oparg; | ||||
|             if (!PyStackRef_IsNull(self_or_null)) { | ||||
|                 args--; | ||||
|                 total_args++; | ||||
|             // _GUARD_NOS_NULL
 | ||||
|             { | ||||
|                 null = stack_pointer[-2]; | ||||
|                 if (!PyStackRef_IsNull(null)) { | ||||
|                     UPDATE_MISS_STATS(CALL); | ||||
|                     assert(_PyOpcode_Deopt[opcode] == (CALL)); | ||||
|                     JUMP_TO_PREDICTED(CALL); | ||||
|                 } | ||||
|             } | ||||
|             if (total_args != 1) { | ||||
|                 UPDATE_MISS_STATS(CALL); | ||||
|                 assert(_PyOpcode_Deopt[opcode] == (CALL)); | ||||
|                 JUMP_TO_PREDICTED(CALL); | ||||
|             // _GUARD_CALLABLE_LEN
 | ||||
|             { | ||||
|                 callable = stack_pointer[-3]; | ||||
|                 PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); | ||||
|                 PyInterpreterState *interp = tstate->interp; | ||||
|                 if (callable_o != interp->callable_cache.len) { | ||||
|                     UPDATE_MISS_STATS(CALL); | ||||
|                     assert(_PyOpcode_Deopt[opcode] == (CALL)); | ||||
|                     JUMP_TO_PREDICTED(CALL); | ||||
|                 } | ||||
|             } | ||||
|             PyInterpreterState *interp = tstate->interp; | ||||
|             if (callable_o != interp->callable_cache.len) { | ||||
|                 UPDATE_MISS_STATS(CALL); | ||||
|                 assert(_PyOpcode_Deopt[opcode] == (CALL)); | ||||
|                 JUMP_TO_PREDICTED(CALL); | ||||
|             // _CALL_LEN
 | ||||
|             { | ||||
|                 arg = stack_pointer[-1]; | ||||
|                 (void)null; | ||||
|                 STAT_INC(CALL, hit); | ||||
|                 PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); | ||||
|                 _PyFrame_SetStackPointer(frame, stack_pointer); | ||||
|                 Py_ssize_t len_i = PyObject_Length(arg_o); | ||||
|                 stack_pointer = _PyFrame_GetStackPointer(frame); | ||||
|                 if (len_i < 0) { | ||||
|                     JUMP_TO_LABEL(error); | ||||
|                 } | ||||
|                 PyObject *res_o = PyLong_FromSsize_t(len_i); | ||||
|                 assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); | ||||
|                 if (res_o == NULL) { | ||||
|                     JUMP_TO_LABEL(error); | ||||
|                 } | ||||
|                 stack_pointer += -1; | ||||
|                 assert(WITHIN_STACK_BOUNDS()); | ||||
|                 _PyFrame_SetStackPointer(frame, stack_pointer); | ||||
|                 PyStackRef_CLOSE(arg); | ||||
|                 stack_pointer = _PyFrame_GetStackPointer(frame); | ||||
|                 stack_pointer += -2; | ||||
|                 assert(WITHIN_STACK_BOUNDS()); | ||||
|                 _PyFrame_SetStackPointer(frame, stack_pointer); | ||||
|                 PyStackRef_CLOSE(callable); | ||||
|                 stack_pointer = _PyFrame_GetStackPointer(frame); | ||||
|                 res = PyStackRef_FromPyObjectSteal(res_o); | ||||
|             } | ||||
|             STAT_INC(CALL, hit); | ||||
|             _PyStackRef arg_stackref = args[0]; | ||||
|             PyObject *arg = PyStackRef_AsPyObjectBorrow(arg_stackref); | ||||
|             _PyFrame_SetStackPointer(frame, stack_pointer); | ||||
|             Py_ssize_t len_i = PyObject_Length(arg); | ||||
|             stack_pointer = _PyFrame_GetStackPointer(frame); | ||||
|             if (len_i < 0) { | ||||
|                 JUMP_TO_LABEL(error); | ||||
|             } | ||||
|             PyObject *res_o = PyLong_FromSsize_t(len_i); | ||||
|             assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); | ||||
|             if (res_o == NULL) { | ||||
|                 JUMP_TO_LABEL(error); | ||||
|             } | ||||
|             _PyFrame_SetStackPointer(frame, stack_pointer); | ||||
|             PyStackRef_CLOSE(arg_stackref); | ||||
|             stack_pointer = _PyFrame_GetStackPointer(frame); | ||||
|             stack_pointer += -2 - oparg; | ||||
|             assert(WITHIN_STACK_BOUNDS()); | ||||
|             _PyFrame_SetStackPointer(frame, stack_pointer); | ||||
|             PyStackRef_CLOSE(callable); | ||||
|             stack_pointer = _PyFrame_GetStackPointer(frame); | ||||
|             res = PyStackRef_FromPyObjectSteal(res_o); | ||||
|             stack_pointer[0] = res; | ||||
|             stack_pointer += 1; | ||||
|             assert(WITHIN_STACK_BOUNDS()); | ||||
|  |  | |||
|  | @ -1084,10 +1084,18 @@ dummy_func(void) { | |||
|         sym_set_const(callable, (PyObject *)&PyUnicode_Type); | ||||
|     } | ||||
| 
 | ||||
|     op(_CALL_LEN, (callable[1], self_or_null[1], args[oparg] -- res)) { | ||||
|     op(_CALL_LEN, (unused, unused, unused -- res)) { | ||||
|         res = sym_new_type(ctx, &PyLong_Type); | ||||
|     } | ||||
| 
 | ||||
|     op(_GUARD_CALLABLE_LEN, (callable, unused, unused -- callable, unused, unused)) { | ||||
|         PyObject *len = _PyInterpreterState_GET()->callable_cache.len; | ||||
|         if (sym_get_const(ctx, callable) == len) { | ||||
|             REPLACE_OP(this_instr, _NOP, 0, 0); | ||||
|         } | ||||
|         sym_set_const(callable, len); | ||||
|     } | ||||
| 
 | ||||
| // END BYTECODES //
 | ||||
| 
 | ||||
| } | ||||
|  |  | |||
							
								
								
									
										15
									
								
								Python/optimizer_cases.c.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										15
									
								
								Python/optimizer_cases.c.h
									
										
									
										generated
									
									
									
								
							|  | @ -2065,11 +2065,22 @@ | |||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         case _GUARD_CALLABLE_LEN: { | ||||
|             JitOptSymbol *callable; | ||||
|             callable = stack_pointer[-3]; | ||||
|             PyObject *len = _PyInterpreterState_GET()->callable_cache.len; | ||||
|             if (sym_get_const(ctx, callable) == len) { | ||||
|                 REPLACE_OP(this_instr, _NOP, 0, 0); | ||||
|             } | ||||
|             sym_set_const(callable, len); | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         case _CALL_LEN: { | ||||
|             JitOptSymbol *res; | ||||
|             res = sym_new_type(ctx, &PyLong_Type); | ||||
|             stack_pointer[-2 - oparg] = res; | ||||
|             stack_pointer += -1 - oparg; | ||||
|             stack_pointer[-3] = res; | ||||
|             stack_pointer += -2; | ||||
|             assert(WITHIN_STACK_BOUNDS()); | ||||
|             break; | ||||
|         } | ||||
|  |  | |||
|  | @ -2147,7 +2147,7 @@ specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs) | |||
|             } | ||||
|             /* len(o) */ | ||||
|             PyInterpreterState *interp = _PyInterpreterState_GET(); | ||||
|             if (callable == interp->callable_cache.len) { | ||||
|             if (callable == interp->callable_cache.len && instr->op.arg == 1) { | ||||
|                 specialize(instr, CALL_LEN); | ||||
|                 return 0; | ||||
|             } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Diego Russo
						Diego Russo