Use of Lua corotines in games

classic Classic list List threaded Threaded
32 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Use of Lua corotines in games

jose marin2
Hi.


I'm studying Lua corotines, and looks very interesting.

Is there any sample of use of Lua corotines in games?

__________________________________________________
Fale com seus amigos  de graça com o novo Yahoo! Messenger 
http://br.messenger.yahoo.com/ 


Reply | Threaded
Open this post in threaded view
|

RE: Use of Lua corotines in games

Brian Hassink
I use them in a text multi-user dungeon (MUD) game that I develop as a hobby.

My scripts are attached to objects in the game, primarily creatures, and are used to make them more life like in terms of their behavior and interaction with real users.

I use co-routines to enable the scripts run in a continuous loop and block on in-game events such as specific user actions.


-----Original Message-----
From: [hidden email] [[hidden email]] On Behalf Of Jose Marin
Sent: Monday, March 19, 2007 7:27 AM
To: [hidden email]
Subject: Use of Lua corotines in games

Hi.


I'm studying Lua corotines, and looks very interesting.

Is there any sample of use of Lua corotines in games?

__________________________________________________
Fale com seus amigos  de graça com o novo Yahoo! Messenger 
http://br.messenger.yahoo.com/ 


Reply | Threaded
Open this post in threaded view
|

Re: Use of Lua corotines in games

Wesley Smith
Are the scripts published on the World Wide Internets somewhere?  I've
been looking a coroutines
recently as well.  The more examples the better.

best,
wes

On 3/19/07, Brian Hassink <[hidden email]> wrote:
I use them in a text multi-user dungeon (MUD) game that I develop as a hobby.

My scripts are attached to objects in the game, primarily creatures, and are used to make them more life like in terms of their behavior and interaction with real users.

I use co-routines to enable the scripts run in a continuous loop and block on in-game events such as specific user actions.


-----Original Message-----
From: [hidden email] [[hidden email]] On Behalf Of Jose Marin
Sent: Monday, March 19, 2007 7:27 AM
To: [hidden email]
Subject: Use of Lua corotines in games

Hi.


I'm studying Lua corotines, and looks very interesting.

Is there any sample of use of Lua corotines in games?

__________________________________________________
Fale com seus amigos  de graça com o novo Yahoo! Messenger
http://br.messenger.yahoo.com/



Reply | Threaded
Open this post in threaded view
|

Re: Use of Lua corotines in games

Eike Decker-2
In reply to this post by jose marin2
Hi
There are lots of samples... any agent or even scripted animation can use
coroutines. Loading stuff and yielding from time to time to let other tasks
being done (unless you don't thread those loading tasks anyway). Coroutines are
much easier to handle than real threads but offer many of their benefits. 
Only problem is, that lua coroutines can't yield across C calls - which can be
fixed using Coco, a package that allows yielding C calls. However, the lua
coroutines are quite inexpensive compared to OS coroutines that must be used
then. Creating 10000-100000 coroutines is no problem. However there's a much
lower limit for OS dependent coroutines / threads than that. 


> Hi.
> 
> 
> I'm studying Lua corotines, and looks very interesting.
> 
> Is there any sample of use of Lua corotines in games?
> 
> __________________________________________________
> Fale com seus amigos  de graça com o novo Yahoo! Messenger 
> http://br.messenger.yahoo.com/
> 




Reply | Threaded
Open this post in threaded view
|

Re: Use of Lua corotines in games

Graham Wakefield
I keep hearing this phrase, but what exactly does it mean? Thanks!

On Mar 19, 2007, at 6:46 AM, Eike Decker wrote:

Only problem is, that lua coroutines can't yield across C calls


Reply | Threaded
Open this post in threaded view
|

Re: Use of Lua corotines in games

D Burgess-4
lua_resume()->lua code->resume()->C function->pcall()->yield()

I think I have this right. So when the coroutine starts running it might
call a C function which might pcall some Lua code that yields. THis
means that the yield() needs to cross a C/Lua boundary.
The same problem occurs when starting with lua_resume() and then
executing Lua pcall() which in turn may call lua_yield().

db

On 3/20/07, Graham Wakefield <[hidden email]> wrote:
I keep hearing this phrase, but what exactly does it mean? Thanks!

On Mar 19, 2007, at 6:46 AM, Eike Decker wrote:

> Only problem is, that lua coroutines can't yield across C calls



Reply | Threaded
Open this post in threaded view
|

Re: Use of Lua corotines in games

Graham Wakefield
>From the manual:

"coroutine.yield (···)

Suspends the execution of the calling coroutine. The coroutine cannot be running a C function, a metamethod, or an iterator. Any arguments to yield are passed as extra results to resume."

The bit I don't understand is how a coroutine in Lua can call yield() while it is running a C function? A code example would help here.

The manual entry for lua_resume() doesn't mention anything about yielding across C calls.

"lua_yield
int lua_yield  (lua_State *L, int nresults);
Yields a coroutine.

This function should only be called as the return expression of a C function, as follows:

     return lua_yield (L, nresults);
When a C function calls lua_yield in that way, the running coroutine suspends its execution, and the call to lua_resume that started this coroutine returns. The parameter nresults is the number of values from the stack that are passed as results to lua_resume."

What's not clear here is whether the 'running coroutine' is one created in Lua, that called a C function ending in lua_yield, or whether the running coroutine was a thread created in C via lua_newthread, or whether either case is valid.

Perhaps 'not yielding across C calls' simply means that lua_yield should not be called inside a C function, but only at the end as a return value?


On Mar 19, 2007, at 5:36 PM, David Burgess wrote:

lua_resume()->lua code->resume()->C function->pcall()->yield()

I think I have this right. So when the coroutine starts running it might
call a C function which might pcall some Lua code that yields. THis
means that the yield() needs to cross a C/Lua boundary.
The same problem occurs when starting with lua_resume() and then
executing Lua pcall() which in turn may call lua_yield().

db

On 3/20/07, Graham Wakefield <[hidden email]> wrote:
I keep hearing this phrase, but what exactly does it mean? Thanks!

On Mar 19, 2007, at 6:46 AM, Eike Decker wrote:

> Only problem is, that lua coroutines can't yield across C calls





Reply | Threaded
Open this post in threaded view
|

Re: Use of Lua corotines in games

D Burgess-4
A concise summary of the limitations (and the solution) can be found
at

http://luajit.luaforge.net/coco.html

On 3/20/07, Graham Wakefield <[hidden email]> wrote:
 From the manual:

"coroutine.yield (···)

Suspends the execution of the calling coroutine. The coroutine cannot
be running a C function, a metamethod, or an iterator. Any arguments
to yield are passed as extra results to resume."

The bit I don't understand is how a coroutine in Lua can call yield()
while it is running a C function?  A code example would help here.

The manual entry for lua_resume() doesn't mention anything about
yielding across C calls.

"lua_yield
int lua_yield  (lua_State *L, int nresults);
Yields a coroutine.

This function should only be called as the return expression of a C
function, as follows:

      return lua_yield (L, nresults);
When a C function calls lua_yield in that way, the running coroutine
suspends its execution, and the call to lua_resume that started this
coroutine returns. The parameter nresults is the number of values
from the stack that are passed as results to lua_resume."

What's not clear here is whether the 'running coroutine' is one
created in Lua, that called a C function ending in lua_yield, or
whether the running coroutine was a thread created in C via
lua_newthread, or whether either case is valid.

Perhaps 'not yielding across C calls' simply means that lua_yield
should not be called inside a C function, but only at the end as a
return value?


On Mar 19, 2007, at 5:36 PM, David Burgess wrote:

> lua_resume()->lua code->resume()->C function->pcall()->yield()
>
> I think I have this right. So when the coroutine starts running it
> might
> call a C function which might pcall some Lua code that yields. THis
> means that the yield() needs to cross a C/Lua boundary.
> The same problem occurs when starting with lua_resume() and then
> executing Lua pcall() which in turn may call lua_yield().
>
> db
>
> On 3/20/07, Graham Wakefield <[hidden email]> wrote:
>> I keep hearing this phrase, but what exactly does it mean? Thanks!
>>
>> On Mar 19, 2007, at 6:46 AM, Eike Decker wrote:
>>
>> > Only problem is, that lua coroutines can't yield across C calls
>>
>>




Reply | Threaded
Open this post in threaded view
|

Re: Use of Lua corotines in games

Steven Johnson-3
In reply to this post by jose marin2
On Mon, 19 Mar 2007 05:26:38 -0600, Jose Marin <[hidden email]> wrote:
 
> Hi.
 
 
> I'm studying Lua corotines, and looks very interesting.
 
> Is there any sample of use of Lua corotines in games?
 
Hi.
 
I use something like the following in my own projects. It was originally just supposed to be for cut scenes, but
has since spared me from lots of really messy state machines when scripting stuff like game mode logic and AI.
 
The update parameter in each operation (Wait, WaitForSignals, WaitUntil) is optional, but lets you do stuff while
the operation is in progress. You can return true from it for an early out, in which case the operation returns
nothing; otherwise the operation returns true when it finishes. The data parameter is just meant for passing
input to a predefined update function, where you can't trap needed upvalues.
 
Also, in the Wait operation, the "Pump" and "Timeline" instances are a message pump and Flash-ish timelines
that I use to set up and run optional events during the wait. They're a secondary thing here, though, so I won't
clutter this up with their implementations. Everything else should be fairly straightforward and at least make
sense with the examples.
 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
local error = error
local GetLapse = GetLapse -- Returns the time lapse since the last frame
local IsCallable = IsCallable -- Argument is a function or has a __call metamethod
local ipairs = ipairs
local new = class.new         -- Instantiates a class of the type in argument #1; constructor takes arguments #2-N
local yield = coroutine.yield
 
local function Call (func, ...)
     if func then
        return func(...)
    end
end
 
local function Body (update, body, done, finish)
    while not done() do
        -- Update any user-defined logic. On a true result, do an early out.
        if Call(update) then
            Call(finish)
            return
        end
 
        -- Update any body logic.
        Call(body)
 
        -- Pause the operation until the next turn.
        yield()
    end
 
    -- Do any cleanup and report success.
    Call(finish, params)
    return true
end
 
function Wait (duration, builders, update, data)
    local pump, time, timelines = new("Pump"), 0, {}
 
    -- Build and install each timeline, providing the pump as a helper.
    for _, func in ipairs(builders or {}) do
        timelines[#timelines + 1] = new("Timeline")
        func(timelines[#timelines], pump, data)
    end
 
    -- Wait for the duration to pass.
    return Body(update and function()
        return update(time, duration, pump, data)
    end or nil, function()
        for _, timeline in ipairs(timelines) do
            timeline:Update(time - timeline:GetTime())
        end
        time = time + GetLapse()
    end, function()
        return time > duration
    end)
end
 
function WaitForSignals (signals, count, how, update, data)
    local func, test
 
    -- If the signals are not callable, build an indexing function. Build a table if
    -- nothing is provided.
    func, signals = IsCallable(signals) and signals or function(index)
        return signals[index]
    end, signals or {}
 
    -- Build the test function.
    if how == "any" then
        test = function()
            for index = 1, count do
                if func(index) then
                    return true
                end
            end
        end
    elseif how == "every" then
        test = function()
            for index = 1, count do
                if not func(index) then
                    return
                end
            end
            return true
        end
    else
        error("Unsupported test behavior")
    end
 
    -- Wait for the operation to succeed.
    return Body(update and function()
        return update(signals, count, data)
    end or nil, nil, test)
end
 
function WaitUntil (test, update, data)
    return Body(update and function()
        return update(data)
    end or nil, nil, function()
        return test(data)
    end)
end
 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
A bunch of toy examples to show how it works. The caps/underscores were just used in the documentation to
distinguish from functions that actually exist. And of course, these must all be called within the body of a function
passed to coroutine.create/wrap.
 
-- Wait two seconds.
Wait(2)
 
-- Run the game for five minutes, but quit if everybody leaves the game.
if Wait(300, nil, function(time)
    if EVERYBODY_LEFT() then
        return true
    end
    UPDATE_GAME(time)
end) then
    SHOW_WINNERS()
end
GO_BACK_TO_LOBBY()
 
-- Wait five seconds; update objects during the second half.
Wait(5, {
    function(timeline, pump)
        timeline:Add(2.5, function()
            pump:Add(function()
                UPDATE_OBJECTS()
                return true
            end)
        end)
    end
}, function(_, _, pump)
    pump:Run()
end)
 
-- Wait for any opponent to show and then attack.
WaitForSignals(function(index)
    return me ~= players[index] and IS_IN_THE_OPEN(players[index])
end, #players, "any")
CHOOSE_AND_ATTACK(me, players)
 
-- Wait until every lever is turned, then open the door.
WaitForSignals(nil, #levers, "every", function(signals)
    for index, lever in ipairs(levers) do
        signals[index] = signals[index] or IS_BEING_TURNED(lever)
    end
end)
OPEN_DOOR()
 
-- Run until all 50 tiles are flipped. The creatures will be flipping tiles the whole time. Since
-- they also do this before the WaitForSignals call, the tiles set is passed as input, instead of
-- letting WaitForSignals create a temporary table.
local tiles = {}
local function UpdateCreatures ()
    for creature in GET_CREATURES() do
        local index = GET_TILE(creature)
        tiles[index] = not tiles[index]
    end
end
Wait(10, nil, UpdateCreatures ) -- Mill around for 10 seconds
WaitForSignals(tiles, 50, "every", function(signals, count)
    local index = math.random(count)
    signals[index] = not signals[index]
 
    -- Creatures wander over nearby tiles, flipping them.
    UpdateCreatures()
end)
 
-- Wait for the light, then go.
WaitUntil(SEMAPHORE_IS_GREEN)
GO()
 
-- Wait for the hunter to reach its prey, then attack. Look for another target if it gets away.
WaitUntil(PREY_IS_IN_RANGE, function()
    if PREY_GOT_AWAY() then
        return true
    end
    MOVE_HUNTER_CLOSER()
end) and ATTACK() or GO_HUNTING()
 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
Similar:

http://lua-users.org/lists/lua-l/2005-03/msg00109.html

The last few Game Programming Gems books are probably worth a look, too.


 
____________________________________________________________________________________
Food fight? Enjoy some healthy debate 
in the Yahoo! Answers Food & Drink Q&A.
http://answers.yahoo.com/dir/?link=list&sid=396545367


Reply | Threaded
Open this post in threaded view
|

What's wrong here?

Thomas Lauer-3
Either I am doing something so stupid that I can't see it or something
fishy is going on. Consider this:

	function x(l)
		z=0
		l=nil
		return l
	end

	print(x("test"))

... which prints "nil". Fine.

Now simply comment out the first line of x() (ie "z=0") and try again...
this time it prints "test".

It seems that the first line of x() can be any valid Lua statement other
than "l=nil" and all works fine. However, if this assignment is the
first line it just doesn't work. I am puzzled.

(In case you wonder why anyone would set a function parameter to nil:
the above is stripped down to the smallest code snippet that shows this
behaviour. The original stuff comes from a more complex wrapper around a
bunch of functions in the Lua runtime library.)

That's Lua 5.1.1 on a Win2k SP4 rollup box. I checked with both the
latest precompiled binaries and a locally compiled version.

-- 
cheers  thomasl

web : http://thomaslauer.com/start


Reply | Threaded
Open this post in threaded view
|

Re: What's wrong here?

gary ng
confirmed on linux 5.1.1
5.0.3 doesn't have this behaviour.

and turning "l=nil" into "local l=nil" also doesn't
show this behaviour.

--- Thomas Lauer <[hidden email]> wrote:

> Either I am doing something so stupid that I can't
> see it or something
> fishy is going on. Consider this:
> 
> 	function x(l)
> 		z=0
> 		l=nil
> 		return l
> 	end
> 
> 	print(x("test"))
> 
> ... which prints "nil". Fine.
> 
> Now simply comment out the first line of x() (ie
> "z=0") and try again...
> this time it prints "test".
> 
> It seems that the first line of x() can be any valid
> Lua statement other
> than "l=nil" and all works fine. However, if this
> assignment is the
> first line it just doesn't work. I am puzzled.
> 
> (In case you wonder why anyone would set a function
> parameter to nil:
> the above is stripped down to the smallest code
> snippet that shows this
> behaviour. The original stuff comes from a more
> complex wrapper around a
> bunch of functions in the Lua runtime library.)
> 
> That's Lua 5.1.1 on a Win2k SP4 rollup box. I
> checked with both the
> latest precompiled binaries and a locally compiled
> version.
> 
> -- 
> cheers  thomasl
> 
> web : http://thomaslauer.com/start
> 



 
____________________________________________________________________________________
Finding fabulous fares is fun.  
Let Yahoo! FareChase search your favorite travel sites to find flight and hotel bargains.
http://farechase.yahoo.com/promo-generic-14795097

Reply | Threaded
Open this post in threaded view
|

Re: What's wrong here?

Kristofer Karlsson
In reply to this post by Thomas Lauer-3
2007/3/21, Thomas Lauer <[hidden email]>:
Either I am doing something so stupid that I can't see it or something
fishy is going on. Consider this:

        function x(l)
                z=0
                l=nil
                return l
        end

        print(x("test"))

... which prints "nil". Fine.

Now simply comment out the first line of x() (ie "z=0") and try again...
this time it prints "test".

It seems that the first line of x() can be any valid Lua statement other
than "l=nil" and all works fine. However, if this assignment is the
first line it just doesn't work. I am puzzled.

(In case you wonder why anyone would set a function parameter to nil:
the above is stripped down to the smallest code snippet that shows this
behaviour. The original stuff comes from a more complex wrapper around a
bunch of functions in the Lua runtime library.)

That's Lua 5.1.1 on a Win2k SP4 rollup box. I checked with both the
latest precompiled binaries and a locally compiled version.

--
cheers  thomasl

web : http://thomaslauer.com/start

Strange indeed! Compiling "function(x) x = nil return x end" on lua 5.1.1 (from ubuntu lua package) gives a chunk that directly returns x.
So, it's a compiler bug and not a virtual machine bug.
My best guess (but it's nothing more than a guess) is that the compiler sees "assign nil to register 0" but doesn't see any previous assigment to register 0, thus falsely assuming that the operation can be optimized away.


Reply | Threaded
Open this post in threaded view
|

Re: What's wrong here?

Julien Hamaide-2
Kristofer Karlsson wrote:
> 2007/3/21, Thomas Lauer <[hidden email]
> <[hidden email]>>:
> 
>     Either I am doing something so stupid that I can't see it or something
>     fishy is going on. Consider this:
> 
>             function x(l)
>                     z=0
>                     l=nil
>                     return l
>             end
> 
>             print(x("test"))
> 
>     ... which prints "nil". Fine.
> 
>     Now simply comment out the first line of x() (ie "z=0") and try again...
>     this time it prints "test".
> 
>     It seems that the first line of x() can be any valid Lua statement other
>     than "l=nil" and all works fine. However, if this assignment is the
>     first line it just doesn't work. I am puzzled.
> 
>     (In case you wonder why anyone would set a function parameter to nil:
>     the above is stripped down to the smallest code snippet that shows this
>     behaviour. The original stuff comes from a more complex wrapper around a
>     bunch of functions in the Lua runtime library.)
> 
>     That's Lua 5.1.1 on a Win2k SP4 rollup box. I checked with both the
>     latest precompiled binaries and a locally compiled version.
> 
>     --
>     cheers  thomasl
> 
>     web : http://thomaslauer.com/start <http://thomaslauer.com/start>
> 
> 
> Strange indeed! Compiling "function(x) x = nil return x end" on lua
> 5.1.1 (from ubuntu lua package) gives a chunk that directly returns x.
> So, it's a compiler bug and not a virtual machine bug.
> My best guess (but it's nothing more than a guess) is that the compiler
> sees "assign nil to register 0" but doesn't see any previous assigment
> to register 0, thus falsely assuming that the operation can be optimized
> away.
> 
> 

You're right.

When the parser detects an assignment from a local variable to nil, it
calls luaK_nil() which checks if pc == 0 and skip assignment

if (fs->pc == 0)  /* function start? */
      return;  /* positions are already clean */

is the guilty code

To get rid of the bug, apply the attached patch to lcode.c

-- 
--
Julien Hamaide
Engineering Coach
10Tacle Studios Belgium / Elsewhere Entertainment
37,39c37,39
<   if (fs->pc > fs->lasttarget   /* no jumps to current position? */
<         && fs->pc != 0)  /* not function start? */
<   {
---
>   if (fs->pc > fs->lasttarget) {  /* no jumps to current position? */
>     if (fs->pc == 0)  /* function start? */
>       return;  /* positions are already clean */
Reply | Threaded
Open this post in threaded view
|

RE: What's wrong here?

Grellier, Thierry
Couldn't it be time to release a lua5.1.2, including this patch if
acknowledged?

-----Original Message-----
From: [hidden email]
[[hidden email]] On Behalf Of Julien Hamaide
Sent: Wednesday, March 21, 2007 11:54 AM
To: Lua list
Subject: Re: What's wrong here?

Kristofer Karlsson wrote:
> 2007/3/21, Thomas Lauer <[hidden email]
> <[hidden email]>>:
> 
>     Either I am doing something so stupid that I can't see it or
something
>     fishy is going on. Consider this:
> 
>             function x(l)
>                     z=0
>                     l=nil
>                     return l
>             end
> 
>             print(x("test"))
> 
>     ... which prints "nil". Fine.
> 
>     Now simply comment out the first line of x() (ie "z=0") and try
again...
>     this time it prints "test".
> 
>     It seems that the first line of x() can be any valid Lua statement
other
>     than "l=nil" and all works fine. However, if this assignment is
the
>     first line it just doesn't work. I am puzzled.
> 
>     (In case you wonder why anyone would set a function parameter to
nil:
>     the above is stripped down to the smallest code snippet that shows
this
>     behaviour. The original stuff comes from a more complex wrapper
around a
>     bunch of functions in the Lua runtime library.)
> 
>     That's Lua 5.1.1 on a Win2k SP4 rollup box. I checked with both
the
>     latest precompiled binaries and a locally compiled version.
> 
>     --
>     cheers  thomasl
> 
>     web : http://thomaslauer.com/start <http://thomaslauer.com/start>
> 
> 
> Strange indeed! Compiling "function(x) x = nil return x end" on lua
> 5.1.1 (from ubuntu lua package) gives a chunk that directly returns x.
> So, it's a compiler bug and not a virtual machine bug.
> My best guess (but it's nothing more than a guess) is that the
compiler
> sees "assign nil to register 0" but doesn't see any previous assigment
> to register 0, thus falsely assuming that the operation can be
optimized
> away.
> 
> 

You're right.

When the parser detects an assignment from a local variable to nil, it
calls luaK_nil() which checks if pc == 0 and skip assignment

if (fs->pc == 0)  /* function start? */
      return;  /* positions are already clean */

is the guilty code

To get rid of the bug, apply the attached patch to lcode.c

-- 
--
Julien Hamaide
Engineering Coach
10Tacle Studios Belgium / Elsewhere Entertainment


Reply | Threaded
Open this post in threaded view
|

Lua 5.1.1 LOADNIL optimization bug (was: What's wrong here?)

Mike Pall-71
In reply to this post by Julien Hamaide-2
Hi,

Julien Hamaide wrote:
> When the parser detects an assignment from a local variable to nil, it
> calls luaK_nil() which checks if pc == 0 and skip assignment
> 
> if (fs->pc == 0)  /* function start? */
>       return;  /* positions are already clean */
> 
> is the guilty code
> 
> To get rid of the bug, apply the attached patch to lcode.c

IMHO the patch is wrong. One needs to check that the assigned
variable is a new one and not a parameter. Only then can the
first LOADNILs be omitted. But this requires restructuring ...

The other option is to scrap this micro-optimization entirely.
IMHO it's not going to make any notable difference in speed.

BTW: When this was added during the Lua 5.1 development phase, it
gave me immense trouble with LuaJIT. Because one can no longer
assume that all variables are explicitly initialized. This makes
reasoning about the bytecode more difficult. And some of the
required special cases in the function prologue actually slow
down _all_ functions. :-(

I've commented on this previously:
  http://lua-users.org/lists/lua-l/2005-11/msg00132.html

Alas, removing the (now redundant) branch (*) in luaD_precall would
make the bytecode incompatible between Lua 5.1.1 and Lua 5.1.2.

Time for 5.2? But wait, then I have a few more suggestions ..

[*] This is redundant when the LOADNIL optimization is omitted:
    if (L->top > base + p->numparams)
      L->top = base + p->numparams;

Bye,
     Mike

Reply | Threaded
Open this post in threaded view
|

Re: Lua 5.1.1 LOADNIL optimization bug

Julien Hamaide-2

Mike Pall wrote:
> Hi,
> 
> Julien Hamaide wrote:
>> When the parser detects an assignment from a local variable to nil, it
>> calls luaK_nil() which checks if pc == 0 and skip assignment
>>
>> if (fs->pc == 0)  /* function start? */
>>       return;  /* positions are already clean */
>>
>> is the guilty code
>>
>> To get rid of the bug, apply the attached patch to lcode.c
> 
> IMHO the patch is wrong. One needs to check that the assigned
> variable is a new one and not a parameter. Only then can the
> first LOADNILs be omitted. But this requires restructuring ...
> 
> The other option is to scrap this micro-optimization entirely.
> IMHO it's not going to make any notable difference in speed.

In some ways, I've scrapped this micro-optimization when LOADNIL is
first instruction with the patch, while keeping it for other case. I
don't understand what's the difference with your solution.

Sorry



> 
> BTW: When this was added during the Lua 5.1 development phase, it
> gave me immense trouble with LuaJIT. Because one can no longer
> assume that all variables are explicitly initialized. This makes
> reasoning about the bytecode more difficult. And some of the
> required special cases in the function prologue actually slow
> down _all_ functions. :-(
> 
> I've commented on this previously:
>   http://lua-users.org/lists/lua-l/2005-11/msg00132.html
> 
> Alas, removing the (now redundant) branch (*) in luaD_precall would
> make the bytecode incompatible between Lua 5.1.1 and Lua 5.1.2.
> 
> Time for 5.2? But wait, then I have a few more suggestions ..
> 
> [*] This is redundant when the LOADNIL optimization is omitted:
>     if (L->top > base + p->numparams)
>       L->top = base + p->numparams;
> 
> Bye,
>      Mike
> 
> 


-- 
--
Julien Hamaide
Engineering Coach
10Tacle Studios Belgium / Elsewhere Entertainment

Reply | Threaded
Open this post in threaded view
|

Re: Lua 5.1.1 LOADNIL optimization bug

Mike Pall-71
Hi,

Julien Hamaide wrote:
> > IMHO the patch is wrong. One needs to check that the assigned
> > variable is a new one and not a parameter. Only then can the
> > first LOADNILs be omitted. But this requires restructuring ...
> > 
> > The other option is to scrap this micro-optimization entirely.
> > IMHO it's not going to make any notable difference in speed.
> 
> In some ways, I've scrapped this micro-optimization when LOADNIL is
> first instruction with the patch, while keeping it for other case. I
> don't understand what's the difference with your solution.

Oops. On closer look, you're right. Sorry.

I've assumed a reverse diff of luaK_nil between Lua-5.1-alpha and
beta would do. But the initialization of fs->lasttarget changed.
So, the optimal fix is to set fs->lasttarget to 0 in open_func()
and just remove the check for l->pc == 0 in luaK_nil. Your patch
is functionally identical.

Bye,
     Mike

Reply | Threaded
Open this post in threaded view
|

Environments

Eva Schmidt
Hello,

I've got a question about the environment mechanism in Lua.

I want to execute a little script from another script using loadfile(). Because of the fact that I cannot make sure that this script doesn't contain code I don't want to be executed (like os.exit() or something) I tried to just allow certain functions using an environment like that:


   -- create local environment for loadstring()
   local fenv = {}
   fenv.print = _G.print

   setfenv (loadstring, fenv)

   result, error = loadstring (s)

With this environment it should be possible to just call the printing function within the chunk to be loaded. Maybe this approach is too naive - Lua forbits changing the environment for the function loadstring() ;-(

Does anybody have some idea how I can force Lua to allow the executing of some special functions and to prohibit other functions at the same time?

thanks for help!

Eva



Reply | Threaded
Open this post in threaded view
|

Re: Environments

Alex Queiroz
Hallo,

On 3/21/07, Eva Schmidt <[hidden email]> wrote:

I want to execute a little script from another script using loadfile(). Because
of the fact that I cannot make sure that this script doesn't contain code I
don't want to be executed (like os.exit() or something) I tried to just allow
certain functions using an environment like that:


    -- create local environment for loadstring()
    local fenv = {}
    fenv.print = _G.print

    setfenv (loadstring, fenv)

    result, error = loadstring (s)

With this environment it should be possible to just call the printing function
within the chunk to be loaded. Maybe this approach is too naive -  Lua forbits
changing the environment for the function loadstring() ;-(


    You are changing the environment of the loadstring function. You
should change the environment of the loaded function:

result = setfenv(result, fenv)

Cheers,
--
-alex
http://www.ventonegro.org/

Reply | Threaded
Open this post in threaded view
|

Re: Environments

Tomás Guisasola-2
In reply to this post by Eva Schmidt
	Hi Eva

> I want to execute a little script from another script using loadfile(). Because 
> of the fact that I cannot make sure that this script doesn't contain code I 
> don't want to be executed (like os.exit() or something) I tried to just allow 
> certain functions using an environment like that:
> 
> 
>     -- create local environment for loadstring()
>     local fenv = {}
>     fenv.print = _G.print
> 
>     setfenv (loadstring, fenv)
> 
>     result, error = loadstring (s)
> 
> With this environment it should be possible to just call the printing function 
> within the chunk to be loaded. Maybe this approach is too naive -  Lua forbits 
> changing the environment for the function loadstring() ;-(
	From the Reference Manual:

"setfenv (f, table)

Sets the environment to be used by the given function. f can be a Lua function or a number that specifies the function at that stack level: Level 1 is the function calling setfenv. setfenv returns the given function.

As a special case, when f is 0 setfenv changes the environment of the running thread. In this case, setfenv returns no values."

	You can add "setfenv(0, {print=print}\n" to your string.  This
will change the environment on-the-fly!
	Or you could also change the environment of the resulting function:

-- untested!
local f = assert (loadstring (s))
setfenv (f, fenv)

> Does anybody have some idea how I can force Lua to allow the executing of some 
> special functions and to prohibit other functions at the same time?
> 
> thanks for help!
	Have you checked VEnv (http://www.keplerproject.org/venv) ?
		Tomás


12