Index: Include/classobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/classobject.h,v retrieving revision 2.43 diff -c -c -r2.43 classobject.h *** Include/classobject.h 8 Apr 2003 18:47:21 -0000 2.43 --- Include/classobject.h 2 May 2003 12:02:30 -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.118 diff -c -c -r2.118 object.h *** Include/object.h 17 Apr 2003 19:52:27 -0000 2.118 --- Include/object.h 2 May 2003 12:02:30 -0000 *************** *** 387,392 **** --- 387,394 ---- PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *); PyAPI_FUNC(PyObject *) PyObject_SelfIter(PyObject *); PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *); + PyAPI_FUNC(int) _PyObject_GenericGetAttr_raw(PyObject *, 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.43 diff -c -c -r2.43 opcode.h *** Include/opcode.h 24 Apr 2003 05:45:16 -0000 2.43 --- Include/opcode.h 2 May 2003 12:02:30 -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.3 diff -c -c -r1.3 opcode.py *** Lib/opcode.py 24 Apr 2003 05:45:17 -0000 1.3 --- Lib/opcode.py 2 May 2003 12:02:30 -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 -c -r2.170 classobject.c *** Objects/classobject.c 9 Apr 2003 19:35:08 -0000 2.170 --- Objects/classobject.c 2 May 2003 12:02:31 -0000 *************** *** 759,764 **** --- 759,782 ---- return res; } + 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; + } + /* See classobject.h comments: this only does dict lookups, and is always * safe to call. */ Index: Objects/object.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v retrieving revision 2.209 diff -c -c -r2.209 object.c *** Objects/object.c 18 Apr 2003 00:45:58 -0000 2.209 --- Objects/object.c 2 May 2003 12:02:31 -0000 *************** *** 1351,1356 **** --- 1351,1531 ---- return obj; } + /* + * Multiple return values in C, sigh. + * The _PyObject_GenericGetAttr_raw function is the backend for both + * the PyObject_GenericGetAttr function, and the CALL_ATTR opcode + * handling in ceval.c. It needs to return two values, the found + * object and a status indicator, because in the case of descriptors, + * where the descriptor was found indicates whether we should call its + * descr_get method. + * + * *res should not contain an object; it will be initialized to NULL. + * When status was successful, *res always contains a new reference. + * The status flag means: + * + * -1 : an exception was raised (which could be an AttributeError); + * *res should not be used. + * 0 : a regular attribute was found, and put into *res. Its + * descr_get method should *not* be called even if the object is a + * descr. + * 1 : a descr was found in the right context, and put into *res. If + * desired, its descr_get method can be called. (CALL_ATTR, in + * specific, will avoid this if at all possible.) + */ + + int + _PyObject_GenericGetAttr_raw(PyObject *obj, PyObject *name, PyObject **res) + { + PyTypeObject *tp = obj->ob_type; + PyObject *descr = NULL; + long dictoffset; + PyObject **dictptr; + int status = -1; + + *res = NULL; + + 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 -1; + } + else + #endif + { + PyErr_SetString(PyExc_TypeError, + "attribute name must be string"); + return -1; + } + } + else + Py_INCREF(name); + + if (tp->tp_dict == NULL) { + if (PyType_Ready(tp) < 0) { + status = -1; + goto done; + } + } + + /* 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)) { + Py_INCREF(descr); + *res = descr; + status = 1; + goto done; + } + } + + /* 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) { + Py_INCREF(*res); + status = 0; + goto done; + } + } + } + + + if (descr != NULL) { + Py_INCREF(descr); + if (descr->ob_type->tp_descr_get != NULL) + status = 1; + else + status = 0; + *res = descr; + goto done; + } + + PyErr_Format(PyExc_AttributeError, + "'%.50s' object has no attribute '%.400s'", + tp->tp_name, PyString_AS_STRING(name)); + *res = NULL; + status = -1; + done: + Py_DECREF(name); + return status; + } + + #if CALL_ATTR_SLOW_BUT_PRETTY_PATH + + /* If not for speed, we would be using this PyObject_GenericGetAttr + * implementation + */ + PyObject * + PyObject_GenericGetAttr(PyObject *obj, PyObject *name) + { + PyObject *res = NULL; + int status; + + status = _PyObject_GenericGetAttr_raw(obj, name, &res); + if (status < 0) + return NULL; + if (status > 0) { + descrgetfunc f; + PyObject *old = res; + f = res->ob_type->tp_descr_get; + assert(f); + res = f(old, obj, (PyObject *)obj->ob_type); + Py_DECREF(old); + } + return res; + } + + #else + PyObject * PyObject_GenericGetAttr(PyObject *obj, PyObject *name) { *************** *** 1468,1473 **** --- 1643,1650 ---- Py_DECREF(name); return res; } + + #endif int PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value) Index: Python/ceval.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/ceval.c,v retrieving revision 2.362 diff -c -c -r2.362 ceval.c *** Python/ceval.c 29 Apr 2003 16:18:42 -0000 2.362 --- Python/ceval.c 2 May 2003 12:02:31 -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); *************** *** 87,95 **** #endif #endif /* Function call profile */ #ifdef CALL_PROFILE ! #define PCALL_NUM 11 static int pcall[PCALL_NUM]; #define PCALL_ALL 0 --- 88,97 ---- #endif #endif + #define CALL_PROFILE /* Function call profile */ #ifdef CALL_PROFILE ! #define PCALL_NUM 21 static int pcall[PCALL_NUM]; #define PCALL_ALL 0 *************** *** 103,108 **** --- 105,120 ---- #define PCALL_GENERATOR 8 #define PCALL_OTHER 9 #define PCALL_POP 10 + #define PCALL_ATTR 11 + #define PCALL_ATTR_INST 12 + #define PCALL_ATTR_INST_FAST 13 + #define PCALL_ATTR_INST_MISS 14 + #define PCALL_ATTR_CLS 15 + #define PCALL_ATTR_CLS_PYFUNC 16 + #define PCALL_ATTR_CLS_DESCR 17 + #define PCALL_ATTR_CLS_MISS 18 + #define PCALL_ATTR_CLS_ERR 19 + #define PCALL_ATTR_MISS 20 /* Notes about the statistics *************** *** 127,136 **** PyObject * PyEval_GetCallStats(PyObject *self) { ! return Py_BuildValue("iiiiiiiiii", ! pcall[0], pcall[1], pcall[2], pcall[3], ! pcall[4], pcall[5], pcall[6], pcall[7], ! pcall[8], pcall[9]); } #else #define PCALL(O) --- 139,168 ---- PyObject * PyEval_GetCallStats(PyObject *self) { ! return Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i," ! "s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i}", ! "PCALL_ALL", pcall[PCALL_ALL], ! "PCALL_FUNCTION", pcall[PCALL_FUNCTION], ! "PCALL_FAST_FUNCTION", pcall[PCALL_FAST_FUNCTION], ! "PCALL_FASTER_FUNCTION", pcall[PCALL_FASTER_FUNCTION], ! "PCALL_METHOD", pcall[PCALL_METHOD], ! "PCALL_BOUND_METHOD", pcall[PCALL_BOUND_METHOD], ! "PCALL_CFUNCTION", pcall[PCALL_CFUNCTION], ! "PCALL_TYPE", pcall[PCALL_TYPE], ! "PCALL_GENERATOR", pcall[PCALL_GENERATOR], ! "PCALL_OTHER", pcall[PCALL_OTHER], ! "PCALL_POP", pcall[PCALL_POP], ! "PCALL_ATTR", pcall[PCALL_ATTR], ! "PCALL_ATTR_INST", pcall[PCALL_ATTR_INST], ! "PCALL_ATTR_INST_FAST", pcall[PCALL_ATTR_INST_FAST], ! "PCALL_ATTR_INST_MISS", pcall[PCALL_ATTR_INST_MISS], ! "PCALL_ATTR_CLS", pcall[PCALL_ATTR_CLS], ! "PCALL_ATTR_CLS_PYFUNC", pcall[PCALL_ATTR_CLS_PYFUNC], ! "PCALL_ATTR_CLS_DESCR", pcall[PCALL_ATTR_CLS_DESCR], ! "PCALL_ATTR_CLS_MISS", pcall[PCALL_ATTR_CLS_MISS], ! "PCALL_ATTR_CLS_ERR", pcall[PCALL_ATTR_CLS_ERR], ! "PCALL_ATTR_MISS", pcall[PCALL_ATTR_MISS] ! ); } #else #define PCALL(O) *************** *** 2089,2094 **** --- 2121,2135 ---- STACK_LEVEL()); continue; + case CALL_ATTR: + PCALL(PCALL_ALL); + PCALL(PCALL_ATTR); + 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); *************** *** 3380,3385 **** --- 3421,3656 ---- nargs); } + #if CALL_ATTR_SLOW_BUT_PRETTY_PATH + + 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. + */ + if (PyCFunction_Check(func) && nk == 0) { + int flags = PyCFunction_GET_FLAGS(func); + PCALL(PCALL_CFUNCTION); + if (flags & (METH_NOARGS | METH_O)) { + 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; + } + + #endif + + /* Helper function for call_attr to call python functions. Eats a + * reference to func. + */ + static PyObject * + call_fast_pymeth(PyObject *func, PyObject ***pp_stack, PyObject **inst, + int n, int na, int nk) + { + PyObject *w, *result; + + n++; + na++; + 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; + } + + 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, *tmpo; + + if ((*inst)->ob_type->tp_getattro == PyObject_GenericGetAttr) { + int status = _PyObject_GenericGetAttr_raw(*inst, funcname, + &func); + PCALL(PCALL_ATTR_CLS); + if (status < 0) { + PCALL(PCALL_ATTR_CLS_ERR); + return NULL; + } + if (status == 1 && PyFunction_Check(func)) { + PCALL(PCALL_ATTR_CLS_PYFUNC); + return call_fast_pymeth(func, pp_stack, inst, + n, na, nk); + } + else if (status == 1) { + descrgetfunc f = func->ob_type->tp_descr_get; + tmpo = func; + assert(f); + PCALL(PCALL_ATTR_CLS_DESCR); + func = f(tmpo, *inst, (PyObject *)(*inst)->ob_type); + Py_DECREF(tmpo); + } else { + PCALL(PCALL_ATTR_CLS_MISS); + } + } else { + if (PyInstance_Check(*inst)) { + func = _Py_instance_getmethod( + (PyInstanceObject *)*inst, funcname); + PCALL(PCALL_ATTR_INST); + if (func != NULL) { + PCALL(PCALL_ATTR_INST_FAST); + return call_fast_pymeth(func, pp_stack, inst, + n, na, nk); + } + PCALL(PCALL_ATTR_INST_MISS); + } else + PCALL(PCALL_ATTR_MISS); + func = PyObject_GetAttr(*inst, funcname); + if (func == NULL) { + return NULL; + } + } + #if CALL_ATTR_SLOW_BUT_PRETTY_PATH + result = call_callable(pp_stack, func, inst, n, na, nk); + return result; + #else + + /* Always dispatch PyCFunction first, because these are + presumed to be the most frequent callable object. + */ + if (PyCFunction_Check(func) && nk == 0) { + int flags = PyCFunction_GET_FLAGS(func); + PCALL(PCALL_CFUNCTION); + if (flags & (METH_NOARGS | METH_O)) { + 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(*inst); + *inst = 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) > inst) { + tmpo = EXT_POP(*pp_stack); + Py_DECREF(tmpo); + PCALL(PCALL_POP); + } + return result; + #endif + } + + #if CALL_ATTR_SLOW_BUT_PRETTY_PATH + + inline 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); + } + + #else + static PyObject * call_function(PyObject ***pp_stack, int oparg) { *************** *** 3447,3452 **** --- 3718,3725 ---- } return x; } + + #endif /* The fast_function() function optimize calls for which no argument tuple is necessary; the objects are passed directly from the stack. Index: Python/compile.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v retrieving revision 2.282 diff -c -c -r2.282 compile.c *** Python/compile.c 29 Apr 2003 17:07:34 -0000 2.282 --- Python/compile.c 2 May 2003 12:02:31 -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 -c -r2.220 import.c *** Python/import.c 23 Mar 2003 14:31:01 -0000 2.220 --- Python/import.c 2 May 2003 12:02:32 -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