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

Reply via email to