On Nov 29, 2008, at 6:19 AM, Dag Sverre Seljebotn wrote: > Dag Sverre Seljebotn wrote: >> Stefan Behnel wrote: >>> Dag Sverre Seljebotn wrote: >>>> A way to get around this would be to split generate_result_code. So >>>> mainly my proposal, but with this modification: >>>> >>>> self.subexpr.preparation_code(code) >>>> tmp = code.funcstate.allocate_temp(...) >>>> self.subexpr.store_result_code(tmp, code) >>> That's something I thought about, too. Most of the time, within an >>> expression, all you really want is to say "do whatever it takes to >>> calculate the result, and then put it *here*", where 'here' may >>> be a temp >>> or a name. >>> >>> How would the DECREF handling work for the target in that case? >>> If it's a >>> temp, I'd expect it to be empty in any case, but if it's a >>> variable name, >>> it needs a DECREF-after-INCREF. Or would the parent always hand >>> in a temp >>> and always handle variables itself? >>> >>> If we call this directly, we could also pass keyword arguments like >>> "target_needs_decref" and "make_owned_reference". >> >> I don't like those keywords as such, responsibility should be in >> parent. >> I think a can_raise_exception flag on the node gets us a long way. > > Sorry!, I didn't fully realize what you were asking. Partly because I > couldn't think of situations where the subexpr would not want to > incref, > but of course there are plenty of examples of that (like "print x"). > > So yes, you'd need the "needs_target" variable, and if that is set to > False, there would be another protocol. > > Finally if something both needs a target, but is able to return a > non-incref-ed value (cannot think of any examples -- perhaps some > buffer > code),
Here's an example: "print (<ExtClass?>foo[i]).c_level_attribute." > then I'd prefer for store_result_code to return some status about > whether it returns an incref-ed result or non-incref-ed one. So that > you'd do something like this for "print x": > > if self.operand.needs_target: > # allocate tmp etc > needs_decref = self.operand.store_result_code(tmp, code) > # output code to print tmp > if needs_decref: > # decref tmp > # release tmp > else: > # code to print self.operand.result() directly > > Perhaps this calls for a wiki page with these examples etc. before any > implementation work is done. I think simply moving everything over to the code generation phase will be the most beneficial. This will make things much more natural-- when one needs a temp one can request it right there, use it, and dispose of it when done. The "generate_disposal_code" paradigm makes sense to me, but perhaps that's because it's what I'm used to. If it's just used for temps, I agree the name should change. I like the idea of passing in a target (or None) when asking for the result code, but don't like requiring the parent to do so. It seems to make more sense to me to have the Node handle (e.g. decref/cleanup) its own code. All one should need to handle exceptions/function exit correctly is for the code object (from which one requests temps) to know which temps are in use in a given block (which are started/ended by an explicit call in the try node). Basically, the same framework should work, just transferring from the symbol table to the code object. One thing that we need to keep in mind is what optimizations the C compiler can do, and what it can't. For example, gcc can re-use the same space on the stack for multiple (independent) temp variables, but can't optimize away Py_DECREFs, so the latter are more important for us to handle. They also allow us do more things without the GIL. I realize that this is all generalities (rather than getting into the actual details) but figured I'd throw in my 2 cents now and then comment again when I actually have time to thing about this more. - Robert _______________________________________________ Cython-dev mailing list [email protected] http://codespeak.net/mailman/listinfo/cython-dev
