CPython 3.2
                  eval
                  Shinya Kawanaka (@mayahjp)

Sunday, March 27, 2011
•           :          (Shinya Kawanaka)

             •               : mayah (or MAYAH)

             • twitter: @mayahjp
             • Python:                            (     )




Sunday, March 27, 2011
• CPython   eval

                  •




Sunday, March 27, 2011
eval

                                   Γ⊦e→f
                         Γ ⊦ e1 → v1, ..., Γ ⊦ en → vn
                              Γ ⊦ f(v1, ..., vn) → v
                                Γ ⊦ e(e1, ..., en) → v


                            (            )




Sunday, March 27, 2011
AST



             •                       AST
                         eval



             • ……           Python




Sunday, March 27, 2011
Python
                  → ALMOST YES
             • ceval.c
                                     PyEval_EvalCode              co     code (AST)
                  globals        locals

                     PyObject *
                     PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals)
                     {
                       return PyEval_EvalCodeEx(co,
                                  globals, locals,
                                  (PyObject **)NULL, 0,
                                  (PyObject **)NULL, 0,
                                  (PyObject **)NULL, 0,
                                  NULL, NULL);
                     }


Sunday, March 27, 2011
AST

             • AST
                  • PyEvalCode                              PyCodeObject
                         AST

             •

                  • PyObject

                  •            PyObject

             •

                  • PyEvalCode        PyObject*   globals   locals
                                                  map




Sunday, March 27, 2011
AST / PyCodeObject (code.h)
             • PyCodeObject             code.h

                  • opcode
                          ...                     PyObject
                typedef struct {
                   PyObject_HEAD
                   ... <snip /> ...
                   PyObject *co_code;	 	      /* instruction opcodes */
                   PyObject *co_consts;	 	    /* list (constants used) */
                   PyObject *co_names;	 	     /* list of strings (names used) */
                   PyObject *co_varnames;	    /* tuple of strings (local variable names) */
                   PyObject *co_freevars;		   /* tuple of strings (free variable names) */
                   PyObject *co_cellvars; 	   /* tuple of strings (cell variable names) */
                   ... <snip /> ...
                } PyCodeObject;
Sunday, March 27, 2011
opcode (opcode.h)
             • opcode.h        opcode

                  •        define


             #define MAKE_CLOSURE 134 /* same as MAKE_FUNCTION */
             #define LOAD_CLOSURE 135 /* Load free variable from closure */
             #define LOAD_DEREF   136 /* Load and dereference from closure cell */
             #define STORE_DEREF 137 /* Store into cell */
             #define DELETE_DEREF 138 /* Delete closure cell */




Sunday, March 27, 2011
opcode
                                   grep
             •

                  •          →

             •           ceval.c          eval   switch
                  case



             •                      AST



Sunday, March 27, 2011
AST
             • PyCodeObject
                  • co_code     opcode

                  • co_consts            AST



             • AST




Sunday, March 27, 2011
PyObject (object.h)
             • GC

             • ob_type          PyObject

             typedef struct _object {
                ... <snip /> ...
                Py_ssize_t ob_refcnt;
                struct _typeobject *ob_type;
             } PyObject;

             typedef struct {
                PyObject ob_base;
                Py_ssize_t ob_size; /* Number of items in variable part */
             } PyVarObject;


Sunday, March 27, 2011
_typeobject (object.h)
             •

                  •


             typedef struct _typeobject {
                PyObject_VAR_HEAD
                ... <snip /> ...
                destructor tp_dealloc;
                printfunc tp_print;
                getattrfunc tp_getattr;
                setattrfunc tp_setattr;
                void *tp_reserved; /* formerly known as tp_compare */
                reprfunc tp_repr;


Sunday, March 27, 2011
•

                  • _typeobject (PyTypeObject)      tp_dict

                  •                  PyObject

             •                        primitive
                         primitive       PyObject

                  •                     int



Sunday, March 27, 2011
PyLongObject (longobject.h)
             •                     Py             Object
                                               PyIntObject

                  • → grep

                  •                PyLongObject

                         • 64bit        long                 ...




Sunday, March 27, 2011
PyLongObject (contd.)
             • _longobject

                  •

                  • digit      (      ) uint32

                         • 64bit

             struct _longobject {
             	   PyObject_VAR_HEAD
             	   digit ob_digit[1];
             };



Sunday, March 27, 2011
• PyObject

                  •                          PyObject

                  •

             •                primitive
                  primitive       PyObject

                  • PyLongObject


Sunday, March 27, 2011
...
             •             map

             • PyObject                 dict



                  •              eval

                  • eval




Sunday, March 27, 2011
•           eval



             •




Sunday, March 27, 2011
PyEval_EvalCodeEx (ceval.c)
             •

                  •         +α (PyFrameObject)      (PyFrame_New())

                  •

                  • PyFrameObject        PyEval_EvalFrameEx

                         • PyEval_EvalFrameEx        AST       eval




Sunday, March 27, 2011
PyFrameObject (frameobject.h)
             •



             typedef struct _frame {
                PyObject_VAR_HEAD
                struct _frame *f_back;	 /* previous frame, or NULL */
                PyCodeObject *f_code;	       /* code segment */
                PyObject *f_builtins;	 /* builtin symbol table (PyDictObject) */
                PyObject *f_globals;	 /* global symbol table (PyDictObject) */
                PyObject *f_locals;		   /* local symbol table (any mapping) */
                PyObject **f_valuestack;	 /* points after the last local */
                ....
             }


Sunday, March 27, 2011
PyFrame_New (frameobject.c)
             •

                  •

             •

                  •                 code

                  •

                  •        malloc



Sunday, March 27, 2011
•                              (              )

                  •                   local          kw (keyword)




             • SETLOCAL                                             OK

                         for (i = 0; i < n; i++) {
                            x = args[i];
                            Py_INCREF(x);
                            SETLOCAL(i, x);
                         }

Sunday, March 27, 2011
PyEval_EvalCodeEx (contd.)
             •

                  •      PyEval_EvalFrameEx

             •                        goto fail

                  •      fail     __del__



                  •                         C stack



Sunday, March 27, 2011
PyEval_EvalCode

             • pythonrun.c            run_mod()

                  • AST                     eval

             static PyObject * run_mod(mod_ty mod, const char *filename, PyObject
             *globals, PyObject *locals, PyCompilerFlags *flags, PyArena *arena)
             {
                PyCodeObject *co;
                PyObject *v;
                co = PyAST_Compile(mod, filename, flags, arena);
                if (co == NULL) return NULL;
                v = PyEval_EvalCode((PyObject*)co, globals, locals);
                Py_DECREF(co);
                return v;
             }


Sunday, March 27, 2011
fast_function (ceval.c)
             • eval

                  •


                  • eval   call_function



             •



Sunday, March 27, 2011
PyEval_EvalFrameEx (ceval.c)
             •

             •

                 register int opcode;       /* Current opcode */
                 register int oparg;      /* Current opcode argument, if any */
                 register enum why_code why; /* Reason for block stack unwind */
                 register int err;     /* Error status -- nonzero if error */
                 register PyObject *x;       /* Result object -- NULL if error */
                 register PyObject *v;       /* Temporary objects popped off stack */
                 register PyObject *w;
                 register PyObject *u;
                 register PyObject *t;


Sunday, March 27, 2011
PyEval_EvalFrameEx (contd.)
             •                                             Main
                  switch on opcode



             •                           operation   x   NULL
                              err    0       why     WHY_NOT


                  operation




Sunday, March 27, 2011
PyEval_EvalFrameEx (contd.)
             •                           NOP (No operation)
                         TARGET(NOP)
                           FAST_DISPATCH();

             •

             #define TARGET(op) 
               case op:

             #define DISPATCH() continue

             #define FAST_DISPATCH() goto fast_next_opcode




Sunday, March 27, 2011
PyEval_EvalFrameEx (contd.)
             • NOP                  LOAD_CONST (                 )
                         x = GETITEM(consts, oparg);
                         Py_INCREF(x);
                         PUSH(x);
                         FAST_DISPATCH();


             •                           PUSH(x)             stack machine


             #define BASIC_PUSH(v) (*stack_pointer++ = (v))
             #define PUSH(v)       BASIC_PUSH(v)




Sunday, March 27, 2011
stack machine
             •               stack machine                       (BINARY_ADD)   2
                  operands                       POP → POP → PUSH

             •→
                         TARGET(BINARY_ADD)	 	        	   // only main
                           w = POP();
                           v = TOP();
                           x = PyNumber_Add(v, w);
                           Py_DECREF(v);
                           Py_DECREF(w);
                           SET_TOP(x);
                           if (x != NULL) DISPATCH();
                           break;


Sunday, March 27, 2011
• stack machine


                  • if

                         •   if         compare & branch

                  •

             • python             AST   compile




Sunday, March 27, 2011
JUMP_IF_TRUE [FALSE]
                  (_OR_POP)
             • stack machine                                                             jump



                  • JUMP_IF_TRUE [FALSE] (_OR_POP)
                         TARGET(POP_JUMP_IF_TRUE)
                           w = POP();
                           if (w == Py_False) {
                               Py_DECREF(w);
                               FAST_DISPATCH();
                           }
                           if (w == Py_True) {
                               Py_DECREF(w);
                               JUMPTO(oparg);   // this will set the next instruction!
                               FAST_DISPATCH();

Sunday, March 27, 2011
JUMPTO
             • first_instr        code

                  • offset
             #define JUMPTO(x)       (next_instr = first_instr + (x))


             • first_instr
                 first_instr = (unsigned char*) PyBytes_AS_STRING(co->co_code);


                  • co_code


Sunday, March 27, 2011
CALL_FUNCTION
             •               stack pointer                        call_function



                         TARGET(CALL_FUNCTION) {
                           PyObject **sp;
                           PCALL(PCALL_ALL); 	 	      	   // for profiling
                           sp = stack_pointer;
                           x = call_function(&sp, oparg);
                           stack_pointer = sp;
                           PUSH(x);
                           if (x != NULL) DISPATCH();
                           break;
                         }




Sunday, March 27, 2011
call_function
             • oparg

                  •      16bit
                                   (
             static PyObject *
             call_function(PyObject ***pp_stack, int oparg)
             {
                int na = oparg & 0xff;
                int nk = (oparg>>8) & 0xff;
                int n = na + 2 * nk;
                PyObject **pfunc = (*pp_stack) - n - 1;
                PyObject *func = *pfunc;
                PyObject *x, *w;



Sunday, March 27, 2011
call_function (contd.)
             •

                  • CPyFunction


                         PyObject *callargs;
                         callargs = load_args(pp_stack, na);
                         READ_TIMESTAMP(*pintr0);
                         C_TRACE(x, PyCFunction_Call(func,callargs,NULL));
                         READ_TIMESTAMP(*pintr1);
                         Py_XDECREF(callargs);




Sunday, March 27, 2011
TIME UP
             •




Sunday, March 27, 2011

CPython 3.2 SourceCodeReading

  • 1.
    CPython 3.2 eval Shinya Kawanaka (@mayahjp) Sunday, March 27, 2011
  • 2.
    : (Shinya Kawanaka) • : mayah (or MAYAH) • twitter: @mayahjp • Python: ( ) Sunday, March 27, 2011
  • 3.
    • CPython eval • Sunday, March 27, 2011
  • 4.
    eval Γ⊦e→f Γ ⊦ e1 → v1, ..., Γ ⊦ en → vn Γ ⊦ f(v1, ..., vn) → v Γ ⊦ e(e1, ..., en) → v ( ) Sunday, March 27, 2011
  • 5.
    AST • AST eval • …… Python Sunday, March 27, 2011
  • 6.
    Python → ALMOST YES • ceval.c PyEval_EvalCode co code (AST) globals locals PyObject * PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals) { return PyEval_EvalCodeEx(co, globals, locals, (PyObject **)NULL, 0, (PyObject **)NULL, 0, (PyObject **)NULL, 0, NULL, NULL); } Sunday, March 27, 2011
  • 7.
    AST • AST • PyEvalCode PyCodeObject AST • • PyObject • PyObject • • PyEvalCode PyObject* globals locals map Sunday, March 27, 2011
  • 8.
    AST / PyCodeObject(code.h) • PyCodeObject code.h • opcode ... PyObject typedef struct { PyObject_HEAD ... <snip /> ... PyObject *co_code; /* instruction opcodes */ PyObject *co_consts; /* list (constants used) */ PyObject *co_names; /* list of strings (names used) */ PyObject *co_varnames; /* tuple of strings (local variable names) */ PyObject *co_freevars; /* tuple of strings (free variable names) */ PyObject *co_cellvars; /* tuple of strings (cell variable names) */ ... <snip /> ... } PyCodeObject; Sunday, March 27, 2011
  • 9.
    opcode (opcode.h) • opcode.h opcode • define #define MAKE_CLOSURE 134 /* same as MAKE_FUNCTION */ #define LOAD_CLOSURE 135 /* Load free variable from closure */ #define LOAD_DEREF 136 /* Load and dereference from closure cell */ #define STORE_DEREF 137 /* Store into cell */ #define DELETE_DEREF 138 /* Delete closure cell */ Sunday, March 27, 2011
  • 10.
    opcode grep • • → • ceval.c eval switch case • AST Sunday, March 27, 2011
  • 11.
    AST • PyCodeObject • co_code opcode • co_consts AST • AST Sunday, March 27, 2011
  • 12.
    PyObject (object.h) • GC • ob_type PyObject typedef struct _object { ... <snip /> ... Py_ssize_t ob_refcnt; struct _typeobject *ob_type; } PyObject; typedef struct { PyObject ob_base; Py_ssize_t ob_size; /* Number of items in variable part */ } PyVarObject; Sunday, March 27, 2011
  • 13.
    _typeobject (object.h) • • typedef struct _typeobject { PyObject_VAR_HEAD ... <snip /> ... destructor tp_dealloc; printfunc tp_print; getattrfunc tp_getattr; setattrfunc tp_setattr; void *tp_reserved; /* formerly known as tp_compare */ reprfunc tp_repr; Sunday, March 27, 2011
  • 14.
    • _typeobject (PyTypeObject) tp_dict • PyObject • primitive primitive PyObject • int Sunday, March 27, 2011
  • 15.
    PyLongObject (longobject.h) • Py Object PyIntObject • → grep • PyLongObject • 64bit long ... Sunday, March 27, 2011
  • 16.
    PyLongObject (contd.) • _longobject • • digit ( ) uint32 • 64bit struct _longobject { PyObject_VAR_HEAD digit ob_digit[1]; }; Sunday, March 27, 2011
  • 17.
    • PyObject • PyObject • • primitive primitive PyObject • PyLongObject Sunday, March 27, 2011
  • 18.
    ... • map • PyObject dict • eval • eval Sunday, March 27, 2011
  • 19.
    eval • Sunday, March 27, 2011
  • 20.
    PyEval_EvalCodeEx (ceval.c) • • +α (PyFrameObject) (PyFrame_New()) • • PyFrameObject PyEval_EvalFrameEx • PyEval_EvalFrameEx AST eval Sunday, March 27, 2011
  • 21.
    PyFrameObject (frameobject.h) • typedef struct _frame { PyObject_VAR_HEAD struct _frame *f_back; /* previous frame, or NULL */ PyCodeObject *f_code; /* code segment */ PyObject *f_builtins; /* builtin symbol table (PyDictObject) */ PyObject *f_globals; /* global symbol table (PyDictObject) */ PyObject *f_locals; /* local symbol table (any mapping) */ PyObject **f_valuestack; /* points after the last local */ .... } Sunday, March 27, 2011
  • 22.
    PyFrame_New (frameobject.c) • • • • code • • malloc Sunday, March 27, 2011
  • 23.
    ( ) • local kw (keyword) • SETLOCAL OK for (i = 0; i < n; i++) { x = args[i]; Py_INCREF(x); SETLOCAL(i, x); } Sunday, March 27, 2011
  • 24.
    PyEval_EvalCodeEx (contd.) • • PyEval_EvalFrameEx • goto fail • fail __del__ • C stack Sunday, March 27, 2011
  • 25.
    PyEval_EvalCode • pythonrun.c run_mod() • AST eval static PyObject * run_mod(mod_ty mod, const char *filename, PyObject *globals, PyObject *locals, PyCompilerFlags *flags, PyArena *arena) { PyCodeObject *co; PyObject *v; co = PyAST_Compile(mod, filename, flags, arena); if (co == NULL) return NULL; v = PyEval_EvalCode((PyObject*)co, globals, locals); Py_DECREF(co); return v; } Sunday, March 27, 2011
  • 26.
    fast_function (ceval.c) • eval • • eval call_function • Sunday, March 27, 2011
  • 27.
    PyEval_EvalFrameEx (ceval.c) • • register int opcode; /* Current opcode */ register int oparg; /* Current opcode argument, if any */ register enum why_code why; /* Reason for block stack unwind */ register int err; /* Error status -- nonzero if error */ register PyObject *x; /* Result object -- NULL if error */ register PyObject *v; /* Temporary objects popped off stack */ register PyObject *w; register PyObject *u; register PyObject *t; Sunday, March 27, 2011
  • 28.
    PyEval_EvalFrameEx (contd.) • Main switch on opcode • operation x NULL err 0 why WHY_NOT operation Sunday, March 27, 2011
  • 29.
    PyEval_EvalFrameEx (contd.) • NOP (No operation) TARGET(NOP) FAST_DISPATCH(); • #define TARGET(op) case op: #define DISPATCH() continue #define FAST_DISPATCH() goto fast_next_opcode Sunday, March 27, 2011
  • 30.
    PyEval_EvalFrameEx (contd.) • NOP LOAD_CONST ( ) x = GETITEM(consts, oparg); Py_INCREF(x); PUSH(x); FAST_DISPATCH(); • PUSH(x) stack machine #define BASIC_PUSH(v) (*stack_pointer++ = (v)) #define PUSH(v) BASIC_PUSH(v) Sunday, March 27, 2011
  • 31.
    stack machine • stack machine (BINARY_ADD) 2 operands POP → POP → PUSH •→ TARGET(BINARY_ADD) // only main w = POP(); v = TOP(); x = PyNumber_Add(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); break; Sunday, March 27, 2011
  • 32.
    • stack machine • if • if compare & branch • • python AST compile Sunday, March 27, 2011
  • 33.
    JUMP_IF_TRUE [FALSE] (_OR_POP) • stack machine jump • JUMP_IF_TRUE [FALSE] (_OR_POP) TARGET(POP_JUMP_IF_TRUE) w = POP(); if (w == Py_False) { Py_DECREF(w); FAST_DISPATCH(); } if (w == Py_True) { Py_DECREF(w); JUMPTO(oparg); // this will set the next instruction! FAST_DISPATCH(); Sunday, March 27, 2011
  • 34.
    JUMPTO • first_instr code • offset #define JUMPTO(x) (next_instr = first_instr + (x)) • first_instr first_instr = (unsigned char*) PyBytes_AS_STRING(co->co_code); • co_code Sunday, March 27, 2011
  • 35.
    CALL_FUNCTION • stack pointer call_function TARGET(CALL_FUNCTION) { PyObject **sp; PCALL(PCALL_ALL); // for profiling sp = stack_pointer; x = call_function(&sp, oparg); stack_pointer = sp; PUSH(x); if (x != NULL) DISPATCH(); break; } Sunday, March 27, 2011
  • 36.
    call_function • oparg • 16bit ( static PyObject * call_function(PyObject ***pp_stack, int oparg) { int na = oparg & 0xff; int nk = (oparg>>8) & 0xff; int n = na + 2 * nk; PyObject **pfunc = (*pp_stack) - n - 1; PyObject *func = *pfunc; PyObject *x, *w; Sunday, March 27, 2011
  • 37.
    call_function (contd.) • • CPyFunction PyObject *callargs; callargs = load_args(pp_stack, na); READ_TIMESTAMP(*pintr0); C_TRACE(x, PyCFunction_Call(func,callargs,NULL)); READ_TIMESTAMP(*pintr1); Py_XDECREF(callargs); Sunday, March 27, 2011
  • 38.
    TIME UP • Sunday, March 27, 2011