diff options
Diffstat (limited to 'Python/ceval.c')
| -rw-r--r-- | Python/ceval.c | 309 | 
1 files changed, 177 insertions, 132 deletions
| diff --git a/Python/ceval.c b/Python/ceval.c index d5172b9..5519ac7 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -30,6 +30,9 @@  #define CHECKEXC 1      /* Double-check exception checking */  #endif +/* Private API for the LOAD_METHOD opcode. */ +extern int _PyObject_GetMethod(PyObject *, PyObject *, PyObject **); +  typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *);  /* Forward declarations */ @@ -83,63 +86,6 @@ static long dxp[256];  #endif  #endif -/* Function call profile */ -#ifdef CALL_PROFILE -#define PCALL_NUM 11 -static int pcall[PCALL_NUM]; - -#define PCALL_ALL 0 -#define PCALL_FUNCTION 1 -#define PCALL_FAST_FUNCTION 2 -#define PCALL_FASTER_FUNCTION 3 -#define PCALL_METHOD 4 -#define PCALL_BOUND_METHOD 5 -#define PCALL_CFUNCTION 6 -#define PCALL_TYPE 7 -#define PCALL_GENERATOR 8 -#define PCALL_OTHER 9 -#define PCALL_POP 10 - -/* Notes about the statistics - -   PCALL_FAST stats - -   FAST_FUNCTION means no argument tuple needs to be created. -   FASTER_FUNCTION means that the fast-path frame setup code is used. - -   If there is a method call where the call can be optimized by changing -   the argument tuple and calling the function directly, it gets recorded -   twice. - -   As a result, the relationship among the statistics appears to be -   PCALL_ALL == PCALL_FUNCTION + PCALL_METHOD - PCALL_BOUND_METHOD + -                PCALL_CFUNCTION + PCALL_TYPE + PCALL_GENERATOR + PCALL_OTHER -   PCALL_FUNCTION > PCALL_FAST_FUNCTION > PCALL_FASTER_FUNCTION -   PCALL_METHOD > PCALL_BOUND_METHOD -*/ - -#define PCALL(POS) pcall[POS]++ - -PyObject * -PyEval_GetCallStats(PyObject *self) -{ -    return Py_BuildValue("iiiiiiiiiii", -                         pcall[0], pcall[1], pcall[2], pcall[3], -                         pcall[4], pcall[5], pcall[6], pcall[7], -                         pcall[8], pcall[9], pcall[10]); -} -#else -#define PCALL(O) - -PyObject * -PyEval_GetCallStats(PyObject *self) -{ -    Py_INCREF(Py_None); -    return Py_None; -} -#endif - -  #ifdef WITH_THREAD  #define GIL_REQUEST _Py_atomic_load_relaxed(&gil_drop_request)  #else @@ -718,7 +664,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)      return tstate->interp->eval_frame(f, throwflag);  } -PyObject * +PyObject* _Py_HOT_FUNCTION  _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)  {  #ifdef DXPAIRS @@ -1424,6 +1370,12 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)              PyObject *right = POP();              PyObject *left = TOP();              PyObject *sum; +            /* NOTE(haypo): Please don't try to micro-optimize int+int on +               CPython using bytecode, it is simply worthless. +               See http://bugs.python.org/issue21955 and +               http://bugs.python.org/issue10044 for the discussion. In short, +               no patch shown any impact on a realistic benchmark, only a minor +               speedup on microbenchmarks. */              if (PyUnicode_CheckExact(left) &&                       PyUnicode_CheckExact(right)) {                  sum = unicode_concatenate(left, right, f, next_instr); @@ -1538,7 +1490,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)          TARGET(SET_ADD) {              PyObject *v = POP(); -            PyObject *set = stack_pointer[-oparg]; +            PyObject *set = PEEK(oparg);              int err;              err = PySet_Add(set, v);              Py_DECREF(v); @@ -2400,8 +2352,10 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)          TARGET(DELETE_DEREF) {              PyObject *cell = freevars[oparg]; -            if (PyCell_GET(cell) != NULL) { -                PyCell_Set(cell, NULL); +            PyObject *oldobj = PyCell_GET(cell); +            if (oldobj != NULL) { +                PyCell_SET(cell, NULL); +                Py_DECREF(oldobj);                  DISPATCH();              }              format_exc_unbound(co, oparg); @@ -2798,7 +2752,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)              PyObject *map;              int err;              STACKADJ(-2); -            map = stack_pointer[-oparg];  /* dict */ +            map = PEEK(oparg);                      /* dict */              assert(PyDict_CheckExact(map));              err = PyDict_SetItem(map, key, value);  /* map[key] = value */              Py_DECREF(value); @@ -3111,7 +3065,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)              Py_DECREF(mgr);              if (enter == NULL)                  goto error; -            res = PyObject_CallFunctionObjArgs(enter, NULL); +            res = _PyObject_CallNoArg(enter);              Py_DECREF(enter);              if (res == NULL)                  goto error; @@ -3145,7 +3099,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)              }              SET_TOP(exit);              Py_DECREF(mgr); -            res = PyObject_CallFunctionObjArgs(enter, NULL); +            res = _PyObject_CallNoArg(enter);              Py_DECREF(enter);              if (res == NULL)                  goto error; @@ -3184,8 +3138,12 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)                 gotos should still be resumed.)              */ +            PyObject* stack[3];              PyObject *exit_func; -            PyObject *exc = TOP(), *val = Py_None, *tb = Py_None, *res; +            PyObject *exc, *val, *tb, *res; + +            val = tb = Py_None; +            exc = TOP();              if (exc == Py_None) {                  (void)POP();                  exit_func = TOP(); @@ -3229,8 +3187,11 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)                  assert(block->b_type == EXCEPT_HANDLER);                  block->b_level--;              } -            /* XXX Not the fastest way to call it... */ -            res = PyObject_CallFunctionObjArgs(exit_func, exc, val, tb, NULL); + +            stack[0] = exc; +            stack[1] = val; +            stack[2] = tb; +            res = _PyObject_FastCall(exit_func, stack, 3);              Py_DECREF(exit_func);              if (res == NULL)                  goto error; @@ -3267,10 +3228,103 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)              DISPATCH();          } +        TARGET(LOAD_METHOD) { +            /* Designed to work in tamdem with CALL_METHOD. */ +            PyObject *name = GETITEM(names, oparg); +            PyObject *obj = TOP(); +            PyObject *meth = NULL; + +            int meth_found = _PyObject_GetMethod(obj, name, &meth); + +            SET_TOP(meth);  /* Replace `obj` on top; OK if NULL. */ +            if (meth == NULL) { +                /* Most likely attribute wasn't found. */ +                Py_DECREF(obj); +                goto error; +            } + +            if (meth_found) { +                /* The method object is now on top of the stack. +                   Push `obj` back to the stack, so that the stack +                   layout would be: + +                       method | obj | arg1 | ... | argN +                */ +                PUSH(obj); +            } +            else { +                /* Not a method (but a regular attr, or something +                   was returned by a descriptor protocol).  Push +                   NULL to the top of the stack, to signal +                   CALL_METHOD that it's not a method call. +                */ +                Py_DECREF(obj); +                PUSH(NULL); +            } +            DISPATCH(); +        } + +        TARGET(CALL_METHOD) { +            /* Designed to work in tamdem with LOAD_METHOD. */ +            PyObject **sp, *res, *obj; + +            sp = stack_pointer; + +            obj = PEEK(oparg + 1); +            if (obj == NULL) { +                /* `obj` is NULL when LOAD_METHOD thinks that it's not +                   a method call.  Swap the NULL and callable. + +                   Stack layout: + +                       ... | callable | NULL | arg1 | ... | argN +                                                           ^- TOP() +                                              ^- (-oparg) +                                       ^- (-oparg-1) +                              ^- (-oparg-2) + +                   after the next line it will be: + +                       ... | callable | callable | arg1 | ... | argN +                                                                ^- TOP() +                                                   ^- (-oparg) +                                        ^- (-oparg-1) +                              ^- (-oparg-2) + +                   Right side `callable` will be POPed by call_funtion. +                   Left side `callable` will be POPed manually later +                   (one of "callbale" refs on the stack is borrowed.) +                */ +                SET_VALUE(oparg + 1, PEEK(oparg + 2)); +                res = call_function(&sp, oparg, NULL); +                stack_pointer = sp; +                (void)POP(); /* POP the left side callable. */ +            } +            else { +                /* This is a method call.  Stack layout: + +                     ... | method | obj | arg1 | ... | argN +                                                        ^- TOP() +                                           ^- (-oparg) +                                     ^- (-oparg-1) + +                  `obj` and `method` will be POPed by call_function. +                  We'll be passing `oparg + 1` to call_function, to +                  make it accept the `obj` as a first argument. +                */ +                res = call_function(&sp, oparg + 1, NULL); +                stack_pointer = sp; +            } + +            PUSH(res); +            if (res == NULL) +                goto error; +            DISPATCH(); +        } +          PREDICTED(CALL_FUNCTION);          TARGET(CALL_FUNCTION) {              PyObject **sp, *res; -            PCALL(PCALL_ALL);              sp = stack_pointer;              res = call_function(&sp, oparg, NULL);              stack_pointer = sp; @@ -3286,7 +3340,6 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)              names = POP();              assert(PyTuple_CheckExact(names) && PyTuple_GET_SIZE(names) <= oparg); -            PCALL(PCALL_ALL);              sp = stack_pointer;              res = call_function(&sp, oparg, names);              stack_pointer = sp; @@ -3301,7 +3354,6 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)          TARGET(CALL_FUNCTION_EX) {              PyObject *func, *callargs, *kwargs = NULL, *result; -            PCALL(PCALL_ALL);              if (oparg & 0x01) {                  kwargs = POP();                  if (!PyDict_CheckExact(kwargs)) { @@ -3879,7 +3931,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,      /* Create the frame */      tstate = PyThreadState_GET();      assert(tstate != NULL); -    f = PyFrame_New(tstate, co, globals, locals); +    f = _PyFrame_New_NoTrack(tstate, co, globals, locals);      if (f == NULL) {          return NULL;      } @@ -4048,7 +4100,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,         vars into frame. */      for (i = 0; i < PyTuple_GET_SIZE(co->co_cellvars); ++i) {          PyObject *c; -        int arg; +        Py_ssize_t arg;          /* Possibly account for the cell variable being an argument. */          if (co->co_cell2arg != NULL &&              (arg = co->co_cell2arg[i]) != CO_CELL_NOT_AN_ARG) { @@ -4091,8 +4143,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,           * when the generator is resumed. */          Py_CLEAR(f->f_back); -        PCALL(PCALL_GENERATOR); -          /* Create a new generator that owns the ready to run frame           * and return that as the value. */          if (is_coro) { @@ -4102,8 +4152,11 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,          } else {              gen = PyGen_NewWithQualName(f, name, qualname);          } -        if (gen == NULL) +        if (gen == NULL) {              return NULL; +        } + +        _PyObject_GC_TRACK(f);          if (is_coro && coro_wrapper != NULL) {              PyObject *wrapped; @@ -4126,9 +4179,15 @@ fail: /* Jump here from prelude on failure */         so recursion_depth must be boosted for the duration.      */      assert(tstate != NULL); -    ++tstate->recursion_depth; -    Py_DECREF(f); -    --tstate->recursion_depth; +    if (Py_REFCNT(f) > 1) { +        Py_DECREF(f); +        _PyObject_GC_TRACK(f); +    } +    else { +        ++tstate->recursion_depth; +        Py_DECREF(f); +        --tstate->recursion_depth; +    }      return retval;  } @@ -4245,7 +4304,7 @@ do_raise(PyObject *exc, PyObject *cause)      if (PyExceptionClass_Check(exc)) {          type = exc; -        value = PyObject_CallObject(exc, NULL); +        value = _PyObject_CallNoArg(exc);          if (value == NULL)              goto raise_error;          if (!PyExceptionInstance_Check(value)) { @@ -4270,10 +4329,13 @@ do_raise(PyObject *exc, PyObject *cause)          goto raise_error;      } +    assert(type != NULL); +    assert(value != NULL); +      if (cause) {          PyObject *fixed_cause;          if (PyExceptionClass_Check(cause)) { -            fixed_cause = PyObject_CallObject(cause, NULL); +            fixed_cause = _PyObject_CallNoArg(cause);              if (fixed_cause == NULL)                  goto raise_error;              Py_DECREF(cause); @@ -4296,8 +4358,8 @@ do_raise(PyObject *exc, PyObject *cause)      PyErr_SetObject(type, value);      /* PyErr_SetObject incref's its arguments */ -    Py_XDECREF(value); -    Py_XDECREF(type); +    Py_DECREF(value); +    Py_DECREF(type);      return 0;  raise_error: @@ -4681,7 +4743,8 @@ PyEval_MergeCompilerFlags(PyCompilerFlags *cf)     The arg must be a tuple or NULL.  The kw must be a dict or NULL. */  PyObject * -PyEval_CallObjectWithKeywords(PyObject *func, PyObject *args, PyObject *kwargs) +PyEval_CallObjectWithKeywords(PyObject *callable, +                              PyObject *args, PyObject *kwargs)  {  #ifdef Py_DEBUG      /* PyEval_CallObjectWithKeywords() must not be called with an exception @@ -4691,7 +4754,7 @@ PyEval_CallObjectWithKeywords(PyObject *func, PyObject *args, PyObject *kwargs)  #endif      if (args == NULL) { -        return _PyObject_FastCallDict(func, NULL, 0, kwargs); +        return _PyObject_FastCallDict(callable, NULL, 0, kwargs);      }      if (!PyTuple_Check(args)) { @@ -4706,7 +4769,7 @@ PyEval_CallObjectWithKeywords(PyObject *func, PyObject *args, PyObject *kwargs)          return NULL;      } -    return PyObject_Call(func, args, kwargs); +    return PyObject_Call(callable, args, kwargs);  }  const char * @@ -4766,7 +4829,7 @@ if (tstate->use_tracing && tstate->c_profilefunc) { \      x = call; \      } -static PyObject * +static PyObject* _Py_HOT_FUNCTION  call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)  {      PyObject **pfunc = (*pp_stack) - oparg - 1; @@ -4782,17 +4845,17 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)      if (PyCFunction_Check(func)) {          PyThreadState *tstate = PyThreadState_GET(); -        PCALL(PCALL_CFUNCTION); -          stack = (*pp_stack) - nargs - nkwargs;          C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));      }      else {          if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { -            /* optimize access to bound methods */ +            /* Optimize access to bound methods. Reuse the Python stack +               to pass 'self' as the first argument, replace 'func' +               with 'self'. It avoids the creation of a new temporary tuple +               for arguments (to replace func with self) when the method uses +               FASTCALL. */              PyObject *self = PyMethod_GET_SELF(func); -            PCALL(PCALL_METHOD); -            PCALL(PCALL_BOUND_METHOD);              Py_INCREF(self);              func = PyMethod_GET_FUNCTION(func);              Py_INCREF(func); @@ -4824,7 +4887,6 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)      while ((*pp_stack) > pfunc) {          w = EXT_POP(*pp_stack);          Py_DECREF(w); -        PCALL(PCALL_POP);      }      return x; @@ -4839,7 +4901,7 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)     done before evaluating the frame.  */ -static PyObject* +static PyObject* _Py_HOT_FUNCTION  _PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs,                       PyObject *globals)  { @@ -4849,14 +4911,13 @@ _PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs,      Py_ssize_t i;      PyObject *result; -    PCALL(PCALL_FASTER_FUNCTION);      assert(globals != NULL);      /* XXX Perhaps we should create a specialized -       PyFrame_New() that doesn't take locals, but does +       _PyFrame_New_NoTrack() that doesn't take locals, but does         take builtins without sanity checking them.         */      assert(tstate != NULL); -    f = PyFrame_New(tstate, co, globals, NULL); +    f = _PyFrame_New_NoTrack(tstate, co, globals, NULL);      if (f == NULL) {          return NULL;      } @@ -4869,10 +4930,15 @@ _PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs,      }      result = PyEval_EvalFrameEx(f,0); -    ++tstate->recursion_depth; -    Py_DECREF(f); -    --tstate->recursion_depth; - +    if (Py_REFCNT(f) > 1) { +        Py_DECREF(f); +        _PyObject_GC_TRACK(f); +    } +    else { +        ++tstate->recursion_depth; +        Py_DECREF(f); +        --tstate->recursion_depth; +    }      return result;  } @@ -4895,9 +4961,6 @@ fast_function(PyObject *func, PyObject **stack,      /* kwnames must only contains str strings, no subclass, and all keys must         be unique */ -    PCALL(PCALL_FUNCTION); -    PCALL(PCALL_FAST_FUNCTION); -      if (co->co_kwonlyargcount == 0 && nkwargs == 0 &&          co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))      { @@ -4960,11 +5023,8 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,      assert(nargs == 0 || args != NULL);      assert(kwargs == NULL || PyDict_Check(kwargs)); -    PCALL(PCALL_FUNCTION); -    PCALL(PCALL_FAST_FUNCTION); -      if (co->co_kwonlyargcount == 0 && -        (kwargs == NULL || PyDict_Size(kwargs) == 0) && +        (kwargs == NULL || PyDict_GET_SIZE(kwargs) == 0) &&          co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))      {          /* Fast paths */ @@ -4982,7 +5042,7 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,      if (kwargs != NULL) {          Py_ssize_t pos, i; -        nk = PyDict_Size(kwargs); +        nk = PyDict_GET_SIZE(kwargs);          kwtuple = PyTuple_New(2 * nk);          if (kwtuple == NULL) { @@ -5030,23 +5090,6 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,  static PyObject *  do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict)  { -#ifdef CALL_PROFILE -    /* At this point, we have to look at the type of func to -       update the call stats properly.  Do it here so as to avoid -       exposing the call stats machinery outside ceval.c -    */ -    if (PyFunction_Check(func)) -        PCALL(PCALL_FUNCTION); -    else if (PyMethod_Check(func)) -        PCALL(PCALL_METHOD); -    else if (PyType_Check(func)) -        PCALL(PCALL_TYPE); -    else if (PyCFunction_Check(func)) -        PCALL(PCALL_CFUNCTION); -    else -        PCALL(PCALL_OTHER); -#endif -      if (PyCFunction_Check(func)) {          PyObject *result;          PyThreadState *tstate = PyThreadState_GET(); @@ -5345,8 +5388,10 @@ unicode_concatenate(PyObject *v, PyObject *w,              PyObject **freevars = (f->f_localsplus +                                     f->f_code->co_nlocals);              PyObject *c = freevars[oparg]; -            if (PyCell_GET(c) == v) -                PyCell_Set(c, NULL); +            if (PyCell_GET(c) ==  v) { +                PyCell_SET(c, NULL); +                Py_DECREF(v); +            }              break;          }          case STORE_NAME: @@ -5430,8 +5475,8 @@ _PyEval_RequestCodeExtraIndex(freefunc free)  static void  dtrace_function_entry(PyFrameObject *f)  { -    char* filename; -    char* funcname; +    const char *filename; +    const char *funcname;      int lineno;      filename = PyUnicode_AsUTF8(f->f_code->co_filename); @@ -5444,8 +5489,8 @@ dtrace_function_entry(PyFrameObject *f)  static void  dtrace_function_return(PyFrameObject *f)  { -    char* filename; -    char* funcname; +    const char *filename; +    const char *funcname;      int lineno;      filename = PyUnicode_AsUTF8(f->f_code->co_filename); @@ -5461,7 +5506,7 @@ maybe_dtrace_line(PyFrameObject *frame,                    int *instr_lb, int *instr_ub, int *instr_prev)  {      int line = frame->f_lineno; -    char *co_filename, *co_name; +    const char *co_filename, *co_name;      /* If the last instruction executed isn't in the current         instruction window, reset the window. | 
