Stefan Behnel wrote:
> Hi,
> 
> to fix ticket 124, I tried migrating the for-in loop to new-style temps.
> The problem I ran into is that the current support for temp (de-)allocation
> in NewTempExprNode during code generation is not enough to get this to
> work. Some temps are used longer, some are used shorter than the current
> automatic granularity at a node boundary.
> 
> Example:
> 
>     for a,b in some_list:
>         pass
> 
> needs a temp for retrieving the next item, unpacks it into two target
> temps, frees the item temp and then assigns them to a and b. The problem is
> that we a) pass temps across multiple nodes here, and b) currently generate
> separate code paths for the tuple unpacking, so that the item temp disposal
> code is also generated twice. That prevents the rhs from just releasing the
> temp on a call to generate_disposal_code().

I must admit I need a little help here. At what point is it the new 
temps differ from the old temps? I'd prefer, if possible, to stay as 
close as possible to the old scheme when it comes to flow, so that one 
doesn't have to break everything and build it up again. I.e. try to make 
NewTempExprNode emulate "whatever it is" pure ExprNode with 
is_temp==True does.

> I think it would be best to keep temp allocation in the code where it needs
> to happen, but to make the deallocation explicit and callable from outside.
> This means that all nodes would need to call a "free_temps()" method on
> their subexpressions when they are done generating code for them.

If one decides to change the temp allocation flow altogether, I have 
another proposal:

Get rid of the idea of a "temporary expression node" altogether. The 
fact that an expression node must itself free its temp (which it cannot 
possibly itself know how long should be held on to) always struck me as 
messy.

So:
- Each node still flags whether it needs a result variable (i.e. the 
is_temp of today, or rather needs_target as I'll call it from here on).

- Before the parent calls subexpr.generate_result_code, it has to check 
subexpr.needs_target. If True, the parent must call 
subexpr.set_target(some_cname)

- If the parent doesn't have a variable handy to put the result in, it 
needs to allocate a temp, hand it to the child for it to store its 
result in, and finally release the temp when the result is no longer needed.

If I'm not totally mistaken, this will both be clearer and might have 
the potential to remove some unecesarry INCREFs/DECREFs that's there today.

Example code:

a = g(f(), a)

would then have this flow:

- The NameNode is a lhs, so generate_assignment_code is changed so that 
its target cname is returned to the SimpleAssignmentNode.

- The SimpleAssignmentNode notes that self.rhs.needs_target==True, and 
so it calls "self.rhs.set_target(lhs_cname)", and recurses into rhs. 
(where lhs_cname is the variable name of a in C source).

- "g", in turn, notices that the call to f() as needs_target. As g's 
purposes for f() isn't to store it in a variable, but just use the 
result, g needs to allocate a temporary and call set_target on f. 
However, for "a" (a NameNode) the needs_target is set to False, so g 
simply uses the result_code directly.

-- 
Dag Sverre
_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev

Reply via email to