At 10:15 AM 4/6/01 +0200, Roeland Rengelink wrote: >Carlos Alberto Reis Ribeiro wrote: > >[extensively about a proposal to add a new magic method __onassign__ to >solve a problem in arithmetic expressions] > >Hi, > >I've looked at another approach to solve the problem under >consideration. This approach seems to work and does not require a magic >__onassign__ method. It does require some refcount magic, which makes >this procedure somewhat unobvious. Yes, I agree with you that __onassign__ is not necessary. I also agree that an object's reference count is the key to the solution. I do not agree that any "magic" needs to be done to any object, either by copying it or setting some flag. I sent a possible solution to Carlos, but did not post it to the list. I thought that the list's interest in our topic had waned, and that the discussion should be taken offline. The ensuing responses from you and others convince me that, hey, maybe it does belong on this list. Here's the message in question (appended, not quoted or attached)... --------- I've been thinking about your in-place operator optimizations. Two main approaches I have considered: 1) Doing it at the bytecode level. Bytecodes that would produce "new" objects mark that position on the stack (not the object on the stack itself) as a candidate for in-place operator optimization. If, later in the bytecode, a BINARY_* would execute with the marked position being second from the top (the left operand of the binary op), the BINARY_* opcode is replaced with the corresponding INPLACE_* opcode. 2) Exploiting the fact that, in the CPython virtual machine, the stack must own its own reference to each object on the stack, one reference for each stack position. When the VM executes an opcode, it pops the objects off the stack, them does some stuff, and only as the final act decrements the reference counts of the objects it popped. Thus, when the VM POP()s an object from the stack, it still owns a reference to it. And if the object's reference count is 1, then only the stack can reach the object. This is tantamount to having the object marked 'temp'. No stacks in other frames refer to the object, nor does any other Python object, if ob_refcnt == 1. Then, we can have the code for BINARY_OP check the left operand object. If ob_refcnt == 1, it's a "temp" object, and we can do the inplace operation instead. No change to the compilation phase is needed. Here's a test implementation, a patch against 2.1b1 Python/ceval.c. Looks like it works. *** Python/ceval.old Thu Apr 5 19:59:56 2001 --- Python/ceval.c Thu Apr 5 20:05:05 2001 *************** *** 410,415 **** --- 410,418 ---- #define SETLOCAL(i, value) do { Py_XDECREF(GETLOCAL(i)); \ GETLOCAL(i) = value; } while (0) + /* Inplace operator optimization macro */ + #define CAN_IOP(x) (x->ob_refcnt == 1) + /* Start of code */ #ifdef USE_STACKCHECK *************** *** 883,889 **** case BINARY_POWER: w = POP(); v = POP(); ! x = PyNumber_Power(v, w, Py_None); Py_DECREF(v); Py_DECREF(w); PUSH(x); --- 886,895 ---- case BINARY_POWER: w = POP(); v = POP(); ! if (CAN_IOP(v)) ! x = PyNumber_InPlacePower(v, w, Py_None); ! else ! x = PyNumber_Power(v, w, Py_None); Py_DECREF(v); Py_DECREF(w); PUSH(x); *************** *** 893,899 **** case BINARY_MULTIPLY: w = POP(); v = POP(); ! x = PyNumber_Multiply(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); --- 899,908 ---- case BINARY_MULTIPLY: w = POP(); v = POP(); ! if (CAN_IOP(v)) ! x = PyNumber_InPlaceMultiply(v, w); ! else ! x = PyNumber_Multiply(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); *************** *** 903,909 **** case BINARY_DIVIDE: w = POP(); v = POP(); ! x = PyNumber_Divide(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); --- 912,921 ---- case BINARY_DIVIDE: w = POP(); v = POP(); ! if (CAN_IOP(v)) ! x = PyNumber_InPlaceDivide(v, w); ! else ! x = PyNumber_Divide(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); *************** *** 913,919 **** case BINARY_MODULO: w = POP(); v = POP(); ! x = PyNumber_Remainder(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); --- 925,934 ---- case BINARY_MODULO: w = POP(); v = POP(); ! if (CAN_IOP(v)) ! x = PyNumber_InPlaceRemainder(v, w); ! else ! x = PyNumber_Remainder(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); *************** *** 937,944 **** else x = PyInt_FromLong(i); } else ! x = PyNumber_Add(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); --- 952,961 ---- else x = PyInt_FromLong(i); } + else if (CAN_IOP(v)) + x = PyNumber_InPlaceAdd(v, w); else ! x = PyNumber_Add(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); *************** *** 962,969 **** else x = PyInt_FromLong(i); } else ! x = PyNumber_Subtract(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); --- 979,988 ---- else x = PyInt_FromLong(i); } + else if (CAN_IOP(v)) + x = PyNumber_InPlaceSubtract(v, w); else ! x = PyNumber_Subtract(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); *************** *** 1000,1006 **** case BINARY_LSHIFT: w = POP(); v = POP(); ! x = PyNumber_Lshift(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); --- 1019,1028 ---- case BINARY_LSHIFT: w = POP(); v = POP(); ! if (CAN_IOP(v)) ! x = PyNumber_InPlaceLshift(v, w); ! else ! x = PyNumber_Lshift(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); *************** *** 1010,1016 **** case BINARY_RSHIFT: w = POP(); v = POP(); ! x = PyNumber_Rshift(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); --- 1032,1041 ---- case BINARY_RSHIFT: w = POP(); v = POP(); ! if (CAN_IOP(v)) ! x = PyNumber_InPlaceRshift(v, w); ! else ! x = PyNumber_Rshift(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); *************** *** 1020,1026 **** case BINARY_AND: w = POP(); v = POP(); ! x = PyNumber_And(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); --- 1045,1054 ---- case BINARY_AND: w = POP(); v = POP(); ! if (CAN_IOP(v)) ! x = PyNumber_InPlaceAnd(v, w); ! else ! x = PyNumber_And(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); *************** *** 1030,1036 **** case BINARY_XOR: w = POP(); v = POP(); ! x = PyNumber_Xor(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); --- 1058,1067 ---- case BINARY_XOR: w = POP(); v = POP(); ! if (CAN_IOP(v)) ! x = PyNumber_InPlaceXor(v, w); ! else ! x = PyNumber_Xor(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); *************** *** 1040,1046 **** case BINARY_OR: w = POP(); v = POP(); ! x = PyNumber_Or(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); --- 1071,1080 ---- case BINARY_OR: w = POP(); v = POP(); ! if (CAN_IOP(v)) ! x = PyNumber_InPlaceOr(v, w); ! else ! x = PyNumber_Or(v, w); Py_DECREF(v); Py_DECREF(w); PUSH(x); -- robin900 at yahoo.com _________________________________________________________ Do You Yahoo!? Get your free @yahoo.com address at http://mail.yahoo.com
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4