[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: modifying current execution line/opcode
- From: Rici Lake <lua@...>
- Date: Fri, 15 Dec 2006 09:24:15 -0500
On 15-Dec-06, at 5:53 AM, Fabien wrote:
By "local to a function", I really mean "in the very same function,
not in a nested one". You can't jump out of a function even if it's an
anonymous, local one, so you can't jump through a closure boundary,
unless I missed something.
You have to be careful with branch instructions in the Lua VM. The VM
needs explicit notification about when a closed variable needs to be
promoted to the heap.
Consider the "satisfaction" expressions which are part of the modified
Lua in Aranha: (See note at bottom for notation)
<binding> ::= { <name> // ',' } '=' { <expr> // ',' }
<test> ::= [ <binding> 'satisfies' ] <expr>
<if> ::= 'if' { <test> 'then' <block> // 'elseif' }
[ 'else' <block> ]
'end'
<while> ::= 'while' <test> 'do' <block> 'end
example:
if capture = s:match(pat1) satisfies #cap1 > 4 then
...
elseif capture = s:match(pat2) satisfies capture then
...
else
print "no match"
end
The scope of <binding> (at least in my original implementation) is the
<expr> and <block>. (Some might prefer it to extend to the 'end', but
that's irrelevant to this discussion.)
On the face of it, that requires very little modification of the
existing code generation, but it's not quite that simple, because a
local might need to be heapified in the evaluation of the test
expression. I haven't found a readable piece of code which exhibits
this situation, but it is syntactically possible; consider the
following <test>:
if a = f(x) satisifies seq1:any(function(y) return y < a end)
and seq2:any(function(y) return y > a end)
then ...
end
Now, it's unlikely that either of the inner functions will escape, but
it's conceivable; the implementation of the 'any' method might choose
to save its parameter for whatever reason. Unless we can prove that
that cannot happen, 'a' needs to be heapified. Consequently, for
example, the branch opcode emitted in the 'and' operator must pass
through an OP_CLOSE.
This can be implemented with BREAK pseudo-ops (which is how I did it,
in fact):
'BREAKcond level, target'
expands to:
'JUMP~cond .+3; CLOSE level; JMP target'
Of course, that could also be implemented directly in the VM, but it's
probably too rare a situation to bother.
Note: Pseudo BNF:
<foo> non-terminal
'foo' terminal
[ A ] optional A
{ A // B } A ( B A )*