@@ -642,9 +642,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
642642 processor's own internal branch predication has a high likelihood of
643643 success, resulting in a nearly zero-overhead transition to the
644644 next opcode. A successful prediction saves a trip through the eval-loop
645- including its two unpredictable branches, the HAS_ARG test and the
645+ including its two unpredictable branches, the HAS_ARG test and the
646646 switch-case. Combined with the processor's internal branch prediction,
647- a successful PREDICT has the effect of making the two opcodes run as if
647+ a successful PREDICT has the effect of making the two opcodes run as if
648648 they were a single new opcode with the bodies combined.
649649
650650 If collecting opcode statistics, your choices are to either keep the
@@ -796,7 +796,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
796796 an argument which depends on the situation.
797797 The global trace function is also called
798798 whenever an exception is detected. */
799- if (call_trace_protected (tstate -> c_tracefunc ,
799+ if (call_trace_protected (tstate -> c_tracefunc ,
800800 tstate -> c_traceobj ,
801801 f , PyTrace_CALL , Py_None )) {
802802 /* Trace function raised an error */
@@ -828,10 +828,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
828828 this wasn't always true before 2.3! PyFrame_New now sets
829829 f->f_lasti to -1 (i.e. the index *before* the first instruction)
830830 and YIELD_VALUE doesn't fiddle with f_lasti any more. So this
831- does work. Promise.
831+ does work. Promise.
832832
833833 When the PREDICT() macros are enabled, some opcode pairs follow in
834- direct succession without updating f->f_lasti. A successful
834+ direct succession without updating f->f_lasti. A successful
835835 prediction effectively links the two codes together as if they
836836 were a single new opcode; accordingly,f->f_lasti will point to
837837 the first code in the pair (for instance, GET_ITER followed by
@@ -1678,7 +1678,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
16781678 {
16791679 int totalargs = 1 + (oparg & 0xFF ) + (oparg >> 8 );
16801680 v = POP ();
1681-
1681+
16821682 if (unpack_iterable (v , oparg & 0xFF , oparg >> 8 ,
16831683 stack_pointer + totalargs )) {
16841684 stack_pointer += totalargs ;
@@ -2071,7 +2071,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
20712071 because it prevents detection of a control-break in tight loops like
20722072 "while 1: pass". Compile with this option turned-on when you need
20732073 the speed-up and do not need break checking inside tight loops (ones
2074- that contain only instructions ending with goto fast_next_opcode).
2074+ that contain only instructions ending with goto fast_next_opcode).
20752075 */
20762076 goto fast_next_opcode ;
20772077#else
@@ -2257,7 +2257,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
22572257 break ;
22582258 }
22592259
2260- case MAKE_CLOSURE :
2260+ case MAKE_CLOSURE :
22612261 case MAKE_FUNCTION :
22622262 {
22632263 int posdefaults = oparg & 0xff ;
@@ -2267,7 +2267,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
22672267 v = POP (); /* code object */
22682268 x = PyFunction_New (v , f -> f_globals );
22692269 Py_DECREF (v );
2270-
2270+
22712271 if (x != NULL && opcode == MAKE_CLOSURE ) {
22722272 v = POP ();
22732273 err = PyFunction_SetClosure (x , v );
@@ -2650,6 +2650,7 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
26502650 }
26512651 }
26522652 for (i = 0 ; i < kwcount ; i ++ ) {
2653+ PyObject * * co_varnames ;
26532654 PyObject * keyword = kws [2 * i ];
26542655 PyObject * value = kws [2 * i + 1 ];
26552656 int j ;
@@ -2659,16 +2660,25 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
26592660 co -> co_name );
26602661 goto fail ;
26612662 }
2662- /* XXX slow -- speed up using dictionary? */
2663+ /* Speed hack: do raw pointer compares. As names are
2664+ normally interned this should almost always hit. */
2665+ co_varnames = PySequence_Fast_ITEMS (co -> co_varnames );
2666+ for (j = 0 ;
2667+ j < co -> co_argcount + co -> co_kwonlyargcount ;
2668+ j ++ ) {
2669+ PyObject * nm = co_varnames [j ];
2670+ if (nm == keyword )
2671+ goto kw_found ;
2672+ }
2673+ /* Slow fallback, just in case */
26632674 for (j = 0 ;
26642675 j < co -> co_argcount + co -> co_kwonlyargcount ;
26652676 j ++ ) {
2666- PyObject * nm = PyTuple_GET_ITEM (
2667- co -> co_varnames , j );
2677+ PyObject * nm = co_varnames [j ];
26682678 int cmp = PyObject_RichCompareBool (
26692679 keyword , nm , Py_EQ );
26702680 if (cmp > 0 )
2671- break ;
2681+ goto kw_found ;
26722682 else if (cmp < 0 )
26732683 goto fail ;
26742684 }
@@ -2685,20 +2695,20 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
26852695 goto fail ;
26862696 }
26872697 PyDict_SetItem (kwdict , keyword , value );
2698+ continue ;
26882699 }
2689- else {
2690- if (GETLOCAL (j ) != NULL ) {
2691- PyErr_Format (PyExc_TypeError ,
2692- "%U() got multiple "
2693- "values for keyword "
2694- "argument '%S'" ,
2695- co -> co_name ,
2696- keyword );
2697- goto fail ;
2698- }
2699- Py_INCREF (value );
2700- SETLOCAL (j , value );
2700+ kw_found :
2701+ if (GETLOCAL (j ) != NULL ) {
2702+ PyErr_Format (PyExc_TypeError ,
2703+ "%U() got multiple "
2704+ "values for keyword "
2705+ "argument '%S'" ,
2706+ co -> co_name ,
2707+ keyword );
2708+ goto fail ;
27012709 }
2710+ Py_INCREF (value );
2711+ SETLOCAL (j , value );
27022712 }
27032713 if (co -> co_kwonlyargcount > 0 ) {
27042714 for (i = co -> co_argcount ;
@@ -2930,7 +2940,7 @@ do_raise(PyObject *exc, PyObject *cause)
29302940
29312941/* Iterate v argcnt times and store the results on the stack (via decreasing
29322942 sp). Return 1 for success, 0 if error.
2933-
2943+
29342944 If argcntafter == -1, do a simple unpack. If it is >= 0, do an unpack
29352945 with a variable target.
29362946*/
0 commit comments