Index: Python/ceval.c =================================================================== --- Python/ceval.c (revision 72660) +++ Python/ceval.c (working copy) @@ -798,10 +798,12 @@ co_stacksize are ints. */ #define STACK_LEVEL() ((int)(stack_pointer - f->f_valuestack)) #define EMPTY() (STACK_LEVEL() == 0) +#define PEEK(offset) (stack_pointer[-((offset) + 1)]) #define TOP() (stack_pointer[-1]) #define SECOND() (stack_pointer[-2]) #define THIRD() (stack_pointer[-3]) #define FOURTH() (stack_pointer[-4]) +#define SET(offset, v) (stack_pointer[-((offset) + 1)] = (v)) #define SET_TOP(v) (stack_pointer[-1] = (v)) #define SET_SECOND(v) (stack_pointer[-2] = (v)) #define SET_THIRD(v) (stack_pointer[-3] = (v)) @@ -2188,6 +2190,27 @@ if (x != NULL) continue; break; + case LOAD_METHOD: + w = GETITEM(names, oparg); + v = TOP(); + if (Py_TYPE(v)->tp_getattro == PyObject_GenericGetAttr) { + x = _PyType_Lookup(Py_TYPE(v), w); + if (x != NULL && (PyFunction_Check(x) + || PyCFunction_Check(x))) { + Py_INCREF(x); + SET_TOP(x); + PUSH(v); + continue; + } + } + x = PyObject_GetAttr(v, w); + Py_DECREF(v); + SET_TOP(x); + if (x == NULL) + break; + PUSH(NULL); + continue; + case COMPARE_OP: w = POP(); v = TOP(); @@ -2555,6 +2578,37 @@ break; } + case CALL_METHOD: + { + PyObject **sp; + int nargs = oparg; + w = PEEK(oparg); + v = PEEK(oparg + 1); + if (w == NULL) { + SET(oparg, v); + SET(oparg + 1, NULL); + } + else { + nargs += 1; + } + PCALL(PCALL_ALL); + sp = stack_pointer; +#ifdef WITH_TSC + x = call_function(&sp, nargs, &intr0, &intr1); +#else + x = call_function(&sp, nargs); +#endif + stack_pointer = sp; + if (w == NULL) { + assert(TOP() == NULL); + POP(); + } + PUSH(x); + if (x != NULL) + continue; + break; + } + case CALL_FUNCTION: { PyObject **sp; Index: Python/compile.c =================================================================== --- Python/compile.c (revision 72660) +++ Python/compile.c (working copy) @@ -828,6 +828,8 @@ return 1; case LOAD_ATTR: return 0; + case LOAD_METHOD: + return 2; case COMPARE_OP: return -1; case IMPORT_NAME: @@ -868,6 +870,7 @@ #define NARGS(o) (((o) % 256) + 2*((o) / 256)) case CALL_FUNCTION: return -NARGS(oparg); + case CALL_METHOD: case CALL_FUNCTION_VAR: case CALL_FUNCTION_KW: return -NARGS(oparg)-1; @@ -2560,10 +2563,29 @@ } static int +maybe_optimize_method_call(struct compiler *c, expr_ty e) +{ + expr_ty meth = e->v.Call.func; + if (meth->kind != Attribute_kind || meth->v.Attribute.ctx != Load || + e->v.Call.starargs || e->v.Call.kwargs || + asdl_seq_LEN(e->v.Call.keywords)) + return -1; + VISIT(c, expr, meth->v.Attribute.value); + ADDOP_NAME(c, LOAD_METHOD, meth->v.Attribute.attr, names); + VISIT_SEQ(c, expr, e->v.Call.args); + ADDOP_I(c, CALL_METHOD, asdl_seq_LEN(e->v.Call.args)); + return 1; +} + +static int compiler_call(struct compiler *c, expr_ty e) { - int n, code = 0; + int n, err, code = 0; + err = maybe_optimize_method_call(c, e); + if (err >= 0) + return err; + VISIT(c, expr, e->v.Call.func); n = asdl_seq_LEN(e->v.Call.args); VISIT_SEQ(c, expr, e->v.Call.args); Index: Include/opcode.h =================================================================== --- Include/opcode.h (revision 72660) +++ Include/opcode.h (working copy) @@ -134,6 +134,8 @@ #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 LOAD_METHOD 138 +#define CALL_METHOD 139 /* The next 3 opcodes must be contiguous and satisfy (CALL_FUNCTION_VAR - CALL_FUNCTION) & 3 == 1 */ Index: Lib/opcode.py =================================================================== --- Lib/opcode.py (revision 72660) +++ Lib/opcode.py (working copy) @@ -177,7 +177,10 @@ hasfree.append(136) def_op('STORE_DEREF', 137) hasfree.append(137) +name_op('LOAD_METHOD', 138) +def_op('CALL_METHOD', 139) + def_op('CALL_FUNCTION_VAR', 140) # #args + (#kwargs << 8) def_op('CALL_FUNCTION_KW', 141) # #args + (#kwargs << 8) def_op('CALL_FUNCTION_VAR_KW', 142) # #args + (#kwargs << 8)