Index: Include/classobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/classobject.h,v retrieving revision 2.43 diff -c -r2.43 classobject.h *** Include/classobject.h 8 Apr 2003 18:47:21 -0000 2.43 --- Include/classobject.h 17 Apr 2003 23:23:55 -0000 *************** *** 74,79 **** --- 74,80 ---- PyAPI_FUNC(int) PyClass_IsSubclass(PyObject *, PyObject *); + PyAPI_FUNC(PyObject *) _Py_instance_getmethod(PyInstanceObject *, PyObject *); #ifdef __cplusplus } Index: Include/object.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/object.h,v retrieving revision 2.117 diff -c -r2.117 object.h *** Include/object.h 23 Mar 2003 17:52:28 -0000 2.117 --- Include/object.h 17 Apr 2003 23:23:56 -0000 *************** *** 387,392 **** --- 387,393 ---- PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *); PyAPI_FUNC(PyObject *) PyObject_SelfIter(PyObject *); PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *); + PyAPI_FUNC(PyObject *) _PyObject_Generic_getmethod(PyObject *, PyObject *); PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *, PyObject *, PyObject *); PyAPI_FUNC(long) PyObject_Hash(PyObject *); Index: Include/opcode.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/opcode.h,v retrieving revision 2.41 diff -c -r2.41 opcode.h *** Include/opcode.h 30 Aug 2002 13:09:49 -0000 2.41 --- Include/opcode.h 17 Apr 2003 23:23:56 -0000 *************** *** 138,143 **** --- 138,144 ---- /* Support for opargs more than 16 bits long */ #define EXTENDED_ARG 143 + #define CALL_ATTR 144 enum cmp_op {PyCmp_LT=Py_LT, PyCmp_LE=Py_LE, PyCmp_EQ=Py_EQ, PyCmp_NE=Py_NE, PyCmp_GT=Py_GT, PyCmp_GE=Py_GE, Index: Lib/opcode.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/opcode.py,v retrieving revision 1.1 diff -c -r1.1 opcode.py *** Lib/opcode.py 27 Feb 2003 21:27:52 -0000 1.1 --- Lib/opcode.py 17 Apr 2003 23:23:57 -0000 *************** *** 184,188 **** --- 184,189 ---- def_op('EXTENDED_ARG', 143) EXTENDED_ARG = 143 + def_op('CALL_ATTR', 144) del def_op, name_op, jrel_op, jabs_op Index: Objects/classobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/classobject.c,v retrieving revision 2.170 diff -c -r2.170 classobject.c *** Objects/classobject.c 9 Apr 2003 19:35:08 -0000 2.170 --- Objects/classobject.c 17 Apr 2003 23:24:04 -0000 *************** *** 780,785 **** --- 780,803 ---- return v; } + PyObject * + _Py_instance_getmethod(PyInstanceObject *inst, PyObject *name) + { + PyObject *v; + PyClassObject *class; + descrgetfunc f; + + v = PyDict_GetItem(inst->in_dict, name); + if (v != NULL) + return NULL; + v = class_lookup(inst->in_class, name, &class); + if (v != NULL && PyFunction_Check(v)) { + Py_INCREF(v); + return v; + } + return NULL; + } + static int instance_setattr1(PyInstanceObject *inst, PyObject *name, PyObject *v) { Index: Objects/object.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v retrieving revision 2.207 diff -c -r2.207 object.c *** Objects/object.c 15 Apr 2003 15:10:51 -0000 2.207 --- Objects/object.c 17 Apr 2003 23:24:09 -0000 *************** *** 1352,1357 **** --- 1352,1461 ---- } PyObject * + _PyObject_Generic_getmethod(PyObject *obj, PyObject *name) + { + PyTypeObject *tp = obj->ob_type; + PyObject *descr = NULL; + PyObject *res = NULL; + long dictoffset; + PyObject **dictptr; + + if (!PyString_Check(name)){ + #ifdef Py_USING_UNICODE + /* The Unicode to string conversion is done here because the + existing tp_setattro slots expect a string object as name + and we wouldn't want to break those. */ + if (PyUnicode_Check(name)) { + name = PyUnicode_AsEncodedString(name, NULL, NULL); + if (name == NULL) + return NULL; + } + else + #endif + { + PyErr_SetString(PyExc_TypeError, + "attribute name must be string"); + return NULL; + } + } + else + Py_INCREF(name); + + if (tp->tp_dict == NULL) { + if (PyType_Ready(tp) < 0) + goto notfound; + } + + /* Inline _PyType_Lookup */ + { + int i, n; + PyObject *mro, *base, *dict; + + /* Look in tp_dict of types in MRO */ + mro = tp->tp_mro; + assert(mro != NULL); + assert(PyTuple_Check(mro)); + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + base = PyTuple_GET_ITEM(mro, i); + if (PyClass_Check(base)) + dict = ((PyClassObject *)base)->cl_dict; + else { + assert(PyType_Check(base)); + dict = ((PyTypeObject *)base)->tp_dict; + } + assert(dict && PyDict_Check(dict)); + descr = PyDict_GetItem(dict, name); + if (descr != NULL) + break; + } + } + + if (descr != NULL && + PyType_HasFeature(descr->ob_type, Py_TPFLAGS_HAVE_CLASS)) { + if (descr->ob_type->tp_descr_get != NULL && + PyDescr_IsData(descr)) + goto notfound; + } + + /* Inline _PyObject_GetDictPtr */ + dictoffset = tp->tp_dictoffset; + if (dictoffset != 0) { + PyObject *dict; + if (dictoffset < 0) { + int tsize; + size_t size; + + tsize = ((PyVarObject *)obj)->ob_size; + if (tsize < 0) + tsize = -tsize; + size = _PyObject_VAR_SIZE(tp, tsize); + + dictoffset += (long)size; + assert(dictoffset > 0); + assert(dictoffset % SIZEOF_VOID_P == 0); + } + dictptr = (PyObject **) ((char *)obj + dictoffset); + dict = *dictptr; + if (dict != NULL) { + res = PyDict_GetItem(dict, name); + if (res != NULL) + goto notfound; + } + } + + if (descr != NULL && PyFunction_Check(descr)) { + Py_INCREF(descr); + Py_DECREF(name); + return descr; + } + + notfound: + Py_DECREF(name); + return NULL; + } + + PyObject * PyObject_GenericGetAttr(PyObject *obj, PyObject *name) { PyTypeObject *tp = obj->ob_type; Index: Python/ceval.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/ceval.c,v retrieving revision 2.358 diff -c -r2.358 ceval.c *** Python/ceval.c 9 Apr 2003 19:06:17 -0000 2.358 --- Python/ceval.c 17 Apr 2003 23:24:16 -0000 *************** *** 34,39 **** --- 34,40 ---- /* Forward declarations */ static PyObject *eval_frame(PyFrameObject *); static PyObject *call_function(PyObject ***, int); + static PyObject *call_attr(PyObject ***, PyObject *, int); static PyObject *fast_function(PyObject *, PyObject ***, int, int, int); static PyObject *do_call(PyObject *, PyObject ***, int, int); static PyObject *ext_do_call(PyObject *, PyObject ***, int, int, int); *************** *** 2086,2091 **** --- 2087,2100 ---- STACK_LEVEL()); continue; + case CALL_ATTR: + PCALL(PCALL_ALL); + x = call_attr(&stack_pointer, names, oparg); + PUSH(x); + if (x != NULL) + continue; + break; + case CALL_FUNCTION: PCALL(PCALL_ALL); x = call_function(&stack_pointer, oparg); *************** *** 3378,3391 **** } 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; /* Always dispatch PyCFunction first, because these are presumed to be the most frequent callable object. --- 3387,3396 ---- } static PyObject * ! call_callable(PyObject ***pp_stack, PyObject *func, PyObject **top_obj, ! int n, int na, int nk) { ! PyObject * result, * tmpo; /* Always dispatch PyCFunction first, because these are presumed to be the most frequent callable object. *************** *** 3397,3448 **** PyCFunction meth = PyCFunction_GET_FUNCTION(func); PyObject *self = PyCFunction_GET_SELF(func); if (flags & METH_NOARGS && na == 0) ! x = (*meth)(self, NULL); else if (flags & METH_O && na == 1) { PyObject *arg = EXT_POP(*pp_stack); ! x = (*meth)(self, arg); Py_DECREF(arg); } else { err_args(func, flags, na); ! x = NULL; } } else { PyObject *callargs; callargs = load_args(pp_stack, na); ! x = PyCFunction_Call(func, callargs, NULL); Py_XDECREF(callargs); } ! } else { if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { /* optimize access to bound methods */ PyObject *self = PyMethod_GET_SELF(func); PCALL(PCALL_METHOD); PCALL(PCALL_BOUND_METHOD); Py_INCREF(self); func = PyMethod_GET_FUNCTION(func); Py_INCREF(func); ! Py_DECREF(*pfunc); ! *pfunc = self; na++; n++; ! } else ! Py_INCREF(func); if (PyFunction_Check(func)) ! x = fast_function(func, pp_stack, n, na, nk); else ! x = do_call(func, pp_stack, na, nk); ! Py_DECREF(func); } ! ! /* What does this do? */ ! while ((*pp_stack) > pfunc) { ! w = EXT_POP(*pp_stack); ! Py_DECREF(w); PCALL(PCALL_POP); } ! return x; } /* The fast_function() function optimize calls for which no argument --- 3402,3523 ---- PyCFunction meth = PyCFunction_GET_FUNCTION(func); PyObject *self = PyCFunction_GET_SELF(func); if (flags & METH_NOARGS && na == 0) ! result = (*meth)(self, NULL); else if (flags & METH_O && na == 1) { PyObject *arg = EXT_POP(*pp_stack); ! result = (*meth)(self, arg); Py_DECREF(arg); } else { err_args(func, flags, na); ! result = NULL; } } else { PyObject *callargs; callargs = load_args(pp_stack, na); ! result = PyCFunction_Call(func, callargs, NULL); Py_XDECREF(callargs); } ! } ! else { if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { /* optimize access to bound methods */ PyObject *self = PyMethod_GET_SELF(func); PCALL(PCALL_METHOD); PCALL(PCALL_BOUND_METHOD); Py_INCREF(self); + tmpo = func; func = PyMethod_GET_FUNCTION(func); Py_INCREF(func); ! Py_DECREF(tmpo); ! Py_DECREF(*top_obj); ! *top_obj = self; na++; n++; ! } if (PyFunction_Check(func)) ! result = fast_function(func, pp_stack, n, na, nk); else ! result = do_call(func, pp_stack, na, nk); } ! Py_DECREF(func); ! /* We need to pop off the stack all arguments plus the function ! * object, but the PyMethod case modifies the stack and the number ! * of arguments, so we can't just pop 'n' times. */ ! while ((*pp_stack) > top_obj) { ! tmpo = EXT_POP(*pp_stack); ! Py_DECREF(tmpo); PCALL(PCALL_POP); } ! return result; ! } ! ! static PyObject * ! call_attr(PyObject ***pp_stack, PyObject *names, int oparg) ! { ! int na = oparg & 0xFF; ! int attri = (oparg >> 8) & 0xFFFF; ! int nk = oparg >> 24; ! int n = na + 2 * nk; ! ! PyObject **inst = (*pp_stack) - n - 1; ! PyObject *funcname = GETITEM(names, attri); ! PyObject *func = NULL, *result, *w; ! ! if (PyInstance_Check(*inst)) { ! func = _Py_instance_getmethod((PyInstanceObject *) *inst, ! funcname); ! if (func) { ! na++; ! n++; ! PCALL(PCALL_METHOD); ! PCALL(PCALL_BOUND_METHOD); ! result = fast_function(func, pp_stack, n, na, nk); ! Py_DECREF(func); ! while ((*pp_stack) > inst) { ! w = EXT_POP(*pp_stack); ! Py_DECREF(w); ! PCALL(PCALL_POP); ! } ! return result; ! } ! } else if ((*inst)->ob_type->tp_getattro == PyObject_GenericGetAttr) { ! func = _PyObject_Generic_getmethod(*inst, funcname); ! if (func) { ! na++; ! n++; ! PCALL(PCALL_METHOD); ! PCALL(PCALL_BOUND_METHOD); ! result = fast_function(func, pp_stack, n, na, nk); ! Py_DECREF(func); ! while ((*pp_stack) > inst) { ! w = EXT_POP(*pp_stack); ! Py_DECREF(w); ! PCALL(PCALL_POP); ! } ! return result; ! } ! } ! ! func = PyObject_GetAttr(*inst, funcname); ! if (!func) { ! return func; ! } ! result = call_callable(pp_stack, func, inst, n, na, nk); ! return result; ! } ! ! 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; ! Py_INCREF(*pfunc); ! ! return call_callable(pp_stack, *pfunc, pfunc, n, na, nk); } /* The fast_function() function optimize calls for which no argument Index: Python/compile.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v retrieving revision 2.279 diff -c -r2.279 compile.c *** Python/compile.c 15 Apr 2003 10:35:07 -0000 2.279 --- Python/compile.c 17 Apr 2003 23:24:24 -0000 *************** *** 1850,1855 **** --- 1850,1903 ---- com_node(c, CHILD(n, 2)); } + #define STARFLAG 0x1 + #define STARSTARFLAG 0x2 + + static int + com_call_arglist(struct compiling *c, node *n, int *na, int *nk) + { + PyObject *keywords = NULL; + int i; + int lineno = n->n_lineno; + int flags = 0; + REQ(n, arglist); + for (i = 0; i < NCH(n); i += 2) { + node *ch = CHILD(n, i); + if (TYPE(ch) == STAR || + TYPE(ch) == DOUBLESTAR) + break; + if (ch->n_lineno != lineno) { + lineno = ch->n_lineno; + com_set_lineno(c, lineno); + } + com_argument(c, ch, &keywords); + if (keywords == NULL) + (*na)++; + else + (*nk)++; + } + Py_XDECREF(keywords); + while (i < NCH(n)) { + node *tok = CHILD(n, i); + node *ch = CHILD(n, i+1); + i += 3; + switch (TYPE(tok)) { + case STAR: + flags |= STARFLAG; + break; + case DOUBLESTAR: + flags |= STARSTARFLAG; + break; + } + com_node(c, ch); + } + if (*na > 255 || *nk > 255) { + com_error(c, PyExc_SyntaxError, + "more than 255 arguments"); + } + return flags; + } + static void com_call_function(struct compiling *c, node *n) { *************** *** 1857,1911 **** com_addoparg(c, CALL_FUNCTION, 0); } else { ! PyObject *keywords = NULL; ! int i, na, nk; ! int lineno = n->n_lineno; ! int star_flag = 0; ! int starstar_flag = 0; ! int opcode; ! REQ(n, arglist); ! na = 0; ! nk = 0; ! for (i = 0; i < NCH(n); i += 2) { ! node *ch = CHILD(n, i); ! if (TYPE(ch) == STAR || ! TYPE(ch) == DOUBLESTAR) ! break; ! if (ch->n_lineno != lineno) { ! lineno = ch->n_lineno; ! com_set_lineno(c, lineno); ! } ! com_argument(c, ch, &keywords); ! if (keywords == NULL) ! na++; ! else ! nk++; ! } ! Py_XDECREF(keywords); ! while (i < NCH(n)) { ! node *tok = CHILD(n, i); ! node *ch = CHILD(n, i+1); ! i += 3; ! switch (TYPE(tok)) { ! case STAR: star_flag = 1; break; ! case DOUBLESTAR: starstar_flag = 1; break; ! } ! com_node(c, ch); ! } ! if (na > 255 || nk > 255) { ! com_error(c, PyExc_SyntaxError, ! "more than 255 arguments"); ! } ! if (star_flag || starstar_flag) ! opcode = CALL_FUNCTION_VAR - 1 + ! star_flag + (starstar_flag << 1); else ! opcode = CALL_FUNCTION; com_addoparg(c, opcode, na | (nk << 8)); ! com_pop(c, na + 2*nk + star_flag + starstar_flag); } } static void com_select_member(struct compiling *c, node *n) { --- 1905,1924 ---- com_addoparg(c, CALL_FUNCTION, 0); } else { ! int na = 0, nk = 0, opcode; ! int flags = com_call_arglist(c, n, &na, &nk); ! if (flags & STARFLAG || flags & STARSTARFLAG) ! opcode = CALL_FUNCTION_VAR - 1 + flags; else ! opcode = CALL_FUNCTION; com_addoparg(c, opcode, na | (nk << 8)); ! com_pop(c, na + 2*nk + flags); } } + #undef STARSTARFLAG + #undef STARFLAG + static void com_select_member(struct compiling *c, node *n) { *************** *** 2072,2077 **** --- 2085,2145 ---- } } + static int + com_callattr_check(struct compiling *c, node *n, int child) + { + node *n1, *n2; + int na = 0, nk = 0; + int flags = 0, index; + PyObject *name; + char buffer[MANGLE_LEN]; + char * sname; + + if (child+1 >= NCH(n)) + return 0; + n1 = CHILD(n, child); + n2 = CHILD(n, child+1); + if (TYPE(n1) != trailer || TYPE(n2) != trailer) + return 0; + if (TYPE(CHILD(n1, 0)) != DOT) + return 0; + if (TYPE(CHILD(n2, 0)) != LPAR) + return 0; + if (TYPE(CHILD(n2, 1)) != RPAR) { + node *arglistnode = CHILD(n2, 1); + int i = NCH(arglistnode); + if (i > 1 && + (TYPE(CHILD(arglistnode, i - 2)) == STAR || + TYPE(CHILD(arglistnode, i - 2)) == DOUBLESTAR)) + return 0; + if (com_call_arglist(c, arglistnode, &na, &nk)) { + com_error(c, PyExc_SystemError, + "com_callattr_check failed to detect *args or **kwargs"); + return 0; + } + } + + REQ(CHILD(n1, 1), NAME); + sname = STR(CHILD(n1, 1)); + if (_Py_Mangle(c->c_private, sname, buffer, sizeof(buffer))) + sname = buffer; + if (sname == NULL || + (name = PyString_InternFromString(sname)) == NULL) { + c->c_errors++; + index = 255; + } else { + index = com_addname(c, name); + Py_DECREF(name); + } + if (index >> 16) { + com_error(c, PyExc_SystemError, "Too many constants"); + return 0; + } + flags = (nk << 24) + (index << 8) + na; + com_addoparg(c, CALL_ATTR, flags); + return 1; + } + static void com_power(struct compiling *c, node *n) { *************** *** 2085,2092 **** com_pop(c, 1); break; } ! else com_apply_trailer(c, CHILD(n, i)); } } --- 2153,2166 ---- com_pop(c, 1); break; } ! else { ! int j = com_callattr_check(c, n, i); ! if (j) { ! i += j; ! continue; ! } com_apply_trailer(c, CHILD(n, i)); + } } } Index: Python/import.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/import.c,v retrieving revision 2.220 diff -c -r2.220 import.c *** Python/import.c 23 Mar 2003 14:31:01 -0000 2.220 --- Python/import.c 17 Apr 2003 23:24:31 -0000 *************** *** 55,60 **** --- 55,63 ---- GvR, 2002-08-31: Because MWH changed the bytecode again, moved the magic number *back* to 62011. This should get the snake-farm to throw away its old .pyc files, amongst others. + + THW, 2003-03-25: Changed it back to MWH's version for the CALL_ATTR + opcode. Known values: Python 1.5: 20121 *************** *** 69,76 **** Python 2.3a0: 62011 Python 2.3a0: 62021 Python 2.3a0: 62011 (!) */ ! #define MAGIC (62011 | ((long)'\r'<<16) | ((long)'\n'<<24)) /* Magic word as global; note that _PyImport_Init() can change the value of this global to accommodate for alterations of how the --- 72,80 ---- Python 2.3a0: 62011 Python 2.3a0: 62021 Python 2.3a0: 62011 (!) + Python 2.3a0: 62021 (!) */ ! #define MAGIC (62021 | ((long)'\r'<<16) | ((long)'\n'<<24)) /* Magic word as global; note that _PyImport_Init() can change the value of this global to accommodate for alterations of how the