Garbage collection durint pcall.

classic Classic list List threaded Threaded
67 messages Options
1234
Reply | Threaded
Open this post in threaded view
|

Garbage collection durint pcall.

Francisco Olarte
Hello everybody.

I'm trying (unsuccessfully) to see in the docs if a function argument
can be collected during a pcall. What I mean is:

0.- I push a function.
1.- I push a userdata object as argument.
2.- I do lua_pcall(L,1,1,0) ( Or lua_call or other similar stuff ).

Can my object be garbage collected before returning from pcall (i.e.,
if the function sets its argument to nil and then calls collectgarbage
).?

I need to know this because the object I push has a __gc method which
destroys it, and I need to access some data inside it just after
return.

( I know I can keep it alive by storing it in the registry or dupping
it or anything similar ).

Francisco Olarte.

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Roberto Ierusalimschy
> I'm trying (unsuccessfully) to see in the docs if a function argument
> can be collected during a pcall. What I mean is:
>
> 0.- I push a function.
> 1.- I push a userdata object as argument.
> 2.- I do lua_pcall(L,1,1,0) ( Or lua_call or other similar stuff ).
>
> Can my object be garbage collected before returning from pcall (i.e.,
> if the function sets its argument to nil and then calls collectgarbage
> ).?

I am not sure what you are trying to find in the docs. If an object is
garbage (it cannot be accessed from Lua), it can be collected. 'pcall'
has nothing to do with that.


> I need to know this because the object I push has a __gc method which
> destroys it, and I need to access some data inside it just after
> return.

How are going to access that data inside the object without a reference
to it?

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Francisco Olarte
Roberto:

On Mon, May 27, 2019 at 5:39 PM Roberto Ierusalimschy
<[hidden email]> wrote:

> I am not sure what you are trying to find in the docs. If an object is
> garbage (it cannot be accessed from Lua), it can be collected. 'pcall'
> has nothing to do with that.

I did not express myself too correctly. I receive a callback in C,
build a userdata with several pointers and do a pcall() with the
userdata as a parameter. The __gc method I set in the userdata frees
some C data ( as this kind of userdatas are sometimes built the other
way, lua code ask for the creation ). I need to avoid calling the __gc
method inside the pcall, to do some cleanup in C which depended on the
__gc method for the UD not being run.

At first I thought the lua code would keep it alive, as it is in the
arguments of the called function. Then I realized the function could
be "function(ud); ud=nil; collectgarbage(); end". Then I entered a
death spiral of documentation reading trying to find some thing.

After that i pulled out and decided to do it right, build the
userdata, push a copy to call the function, do my things, pop the
copy, let lua gc do its things however it wants.

> > I need to know this because the object I push has a __gc method which
> > destroys it, and I need to access some data inside it just after
> > return.
> How are going to access that data inside the object without a reference
> to it?

Just for illustration, it's a stupid thing I did, I've fixed it. The
UD HAS, among other things,  a pointer to a message. The UD destructor
frees it. I start the C callback with a pointer to a message, build
the userdata, do the pcall to the lua callback, read a field from the
message using the original ptr, return from the C callback. Now I just
dup the userdata before the callback and pop the copy after reading
the field. I did the old one in a hurry and it probably worked due to
low memory pressure. Then I began cleaning and thought "they cannot
collect it as it must be live in the parameters till the end of the
lua callback, and the return is not going to collect garbage", then I
though "but wait, someone may set the local parameter to nil and
collect"...., brain fart, death spiral. So do it in what seems to be a
guaranteed way, and use the usual pattern I try to do to avoid this
kind of a problem, "do not keep copies of pointers inside userdatas
across lua calls".

Francisco Olarte.

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Egor Skriptunoff-2
On Mon, May 27, 2019 at 8:26 PM Francisco Olarte wrote:

At first I thought the lua code would keep it alive, as it is in the
arguments of the called function. Then I realized the function could
be "function(ud); ud=nil; collectgarbage(); end". Then I entered a
death spiral of documentation reading trying to find some thing.


Lua doesn't anchor function arguments, and this fact may indeed be not obvious from the Lua manual.
I believe that many programmers stumble upon this while learning Lua.
From the (incorrect but) intuitive point of view, a function invocation "f(x,y)" looks like some sort of instance that holds all its elements (function value and argument values) until the function returns.

But actually the following happens:
   the function value is anchored by Lua VM until the function returns;
   the argument values are not anchored, they are just passed to the function's body, so they may be garbage collected before the function returns.

I suggest to add the following phrase to Lua manual:
"For example, function's arguments may be collected before the function returns."

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Sean Conner
It was thus said that the Great Egor Skriptunoff once stated:

> On Mon, May 27, 2019 at 8:26 PM Francisco Olarte wrote:
>
> > At first I thought the lua code would keep it alive, as it is in the
> > arguments of the called function. Then I realized the function could
> > be "function(ud); ud=nil; collectgarbage(); end". Then I entered a
> > death spiral of documentation reading trying to find some thing.
>
> Lua doesn't anchor function arguments, and this fact may indeed be not
> obvious from the Lua manual.
>
> I believe that many programmers stumble upon this while learning Lua.
> >From the (incorrect but) intuitive point of view, a function invocation
> "f(x,y)" looks like some sort of instance that holds all its elements
> (function value and argument values) until the function returns.
>
> But actually the following happens:
>    the function value is anchored by Lua VM until the function returns;
>    the argument values are not anchored, they are just passed to the
> function's body, so they may be garbage collected before the function
> returns.
>
> I suggest to add the following phrase to Lua manual:
> "For example, function's arguments may be collected before the function
> returns."

  I can't seem to produce this behavior, but I must admit, I can't fathom
how to trigger it.  I tried the following:

        (function(...)
          for _ = 1 , 100 do
            collectgarbage('collect')
          end
          print(...)
        end)(io.open(arg[0]))

  I run this, and 'nil' is NEVER printed.  The open file value is never
closed before the function returns.  This code works in Lua 5.1, 5.2, 5.3
and 5.4 (latest work version).

  -spc (So how does one see this behavior?)

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Francisco Olarte
In reply to this post by Egor Skriptunoff-2
Egor:

On Thu, May 30, 2019 at 7:39 AM Egor Skriptunoff
<[hidden email]> wrote:
> On Mon, May 27, 2019 at 8:26 PM Francisco Olarte wrote:
>> At first I thought the lua code would keep it alive, as it is in the
>> arguments of the called function. Then I realized the function could
>> be "function(ud); ud=nil; collectgarbage(); end". Then I entered a
>> death spiral of documentation reading trying to find some thing.

> Lua doesn't anchor function arguments, and this fact may indeed be not obvious from the Lua manual.

I took the middle road, could not find an explicit afirmation of it
anchoring them, so I assumed they would not, and coded for that.

> I believe that many programmers stumble upon this while learning Lua.

Well, it is a very strange thing to hit, you need to do some weird
things, starting by clearing the "local" which holds it inside the
function. I just got to it because I was being defensive.

> From the (incorrect but) intuitive point of view, a function invocation "f(x,y)" looks like some sort of instance that holds all its elements (function value and argument values) until the function returns.

I assume you mean "f" by "function value".

> But actually the following happens:
>    the function value is anchored by Lua VM until the function returns;
>    the argument values are not anchored, they are just passed to the function's body, so they may be garbage collected before the function returns.

You should add "they are assigned to the arguments, so if these
references are cleared..."

> I suggest to add the following phrase to Lua manual:
> "For example, function's arguments may be collected before the function returns."

This may lead to confussion, unless decorated with some example like
mine above. And, in my opinion, in does not matter too much in pure
lua code ( unless you have some __gc with lua observable side effects
).

Francisco Olarte.

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Francisco Olarte
In reply to this post by Sean Conner
Sean:

On Thu, May 30, 2019 at 8:16 AM Sean Conner <[hidden email]> wrote:
> It was thus said that the Great Egor Skriptunoff once stated:
...
> > Lua doesn't anchor function arguments, and this fact may indeed be not
> > obvious from the Lua manual.
...

>   I can't seem to produce this behavior, but I must admit, I can't fathom
> how to trigger it.  I tried the following:
>
>         (function(...)
>           for _ = 1 , 100 do
>             collectgarbage('collect')
>           end
>           print(...)
>         end)(io.open(arg[0]))
>   I run this, and 'nil' is NEVER printed.  The open file value is never
> closed before the function returns.  This code works in Lua 5.1, 5.2, 5.3
> and 5.4 (latest work version).

What Egor and I were talking is about the args not being anchored
EXCEPT by the "locals" defined by the parameters. I'm not sure of the
actual implementation but "..." keeps all the args inside accesible,
so you can get at the file at any time.

I was thinking on something along the line of "function(x) x=nil;
collectgarbage('collect') end". X is the only thing alive, so when I
do something similar to your example from C ( lua_pushfunction,
lua_pushuserdata_with_gc, lua_pcall )  the gc for the userdata may
have been called just after return. I was doing a silly thing,
accessing things which I had put into the ( now inaccessible )
userdata via C-data I had stashed in the Cfunction ( the same C-data
used to build the userdata, AAMOF ), and it hit me that as no
reference was kept anywhere it may have been GCed even if hadn't call
_gc on the CC side ( I accessed it immediately after pcall return, on
the C side ) as someone may have cleared the references in the lua
arguments and called collectgarbage ( I did it erroneously thinking
that some sort of "call frame" would have kept them alive, and as I
did not call collectgarbage before accessing them they may be
collectable, but not collected ).

>   -spc (So how does one see this behavior?)

( Do not use ..., you cannot set ...=nil so the arguments are
referenced by whatever implements ... )

( I should have done this first thing, still not sure if it proves my
point or C api keeps something, but better code around)
[ tmp]$ cat tstgc.lua
-- Is lua keeping arguments alive?
collected=false
mt = {__gc=function() print("Collecting"); collected=true; end}

function bmf(x)
   print("BMF start");
   x=nil
   collectgarbage('collect');
   print("BMF end");
end

print("Starting")
bmf(setmetatable({},mt));
print("Ending")

[ tmp]$ lua tstgc.lua
Starting
BMF start
Collecting
BMF end
Ending
[ tmp]$ lua -v
Lua 5.3.4  Copyright (C) 1994-2017 Lua.org, PUC-Rio

Francisco Olarte.

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

szbnwer@gmail.com
hi all! :)

just a hint for ur game:
use a global weak table to observe stuffs, so it can hold
Schrödinger's lua value. :D pass its value to the function, and u can
also play with it via _G, and then u can stop and trigger the gc
manually...

all the bests to u and have fun! :)

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

szbnwer@gmail.com
and also try some tailcall recursion to make the experiment cool! :)

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Roberto Ierusalimschy
In reply to this post by Francisco Olarte
> > I believe that many programmers stumble upon this while learning Lua.
>
> Well, it is a very strange thing to hit, you need to do some weird
> things, starting by clearing the "local" which holds it inside the
> function. I just got to it because I was being defensive.

It is weirded than that. You also need some alternative way to access
the value that is being collected. (In your case, you didn't have
access to the value itself, but to some C structure being closed by
__gc. Another option, as already pointed out, is through a weak table.)
That doesn't seem common for someone learning Lua.

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Francisco Olarte
Roberto:

On Thu, May 30, 2019 at 5:57 PM Roberto Ierusalimschy
<[hidden email]> wrote:
>
> > > I believe that many programmers stumble upon this while learning Lua.
> > Well, it is a very strange thing to hit, you need to do some weird
> > things, starting by clearing the "local" which holds it inside the
> > function. I just got to it because I was being defensive.
> It is weirded than that. You also need some alternative way to access
> the value that is being collected.

My example ( lua, not  the original C question ) did not access the
vars, but had observable side effects (prints + setting a global var
), that's how I know parameters can be collected. The example did an
unusual but not that weird thing, setting the parameter to nil ( I
sometimes do this in real code, there are cases where logic is clearer
when treating parameters as modifiable locas ) and a
collectgarbage('collect'), to simulate memory pressure.

This thing would normally be harmless in pure lua. My C code did a
stupid thing ( pcalling and keeping pointer without keeping the object
alive ), which I solved by doing the ( imho ) right thing, "If the
manual does not say it is not collected, assume it can be".

The rest was just trying to demonstrate it can happen.

> ... (In your case, you didn't have> access to the value itself, but to some C structure being closed by
> __gc.

I admit it again. I did it a stupid thing, I corrected it, I do not do
that now, but I wanted to know if the parameter lifetimes were somehow
extended to the return ( now I've proven they are not , so my
intelectual itch is fully satisfied )

> Another option, as already pointed out, is through a weak table.)
> That doesn't seem common for someone learning Lua.

It has __gc, observable finalizers, not that simple, but I'm still a
beginner (in Lua, specially the api ) and hit this things. May be
because it allows me to solve some complex interaction problems, so I
tend to go to the dark corners.

Francisco Olarte.

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Egor Skriptunoff-2
In reply to this post by Roberto Ierusalimschy
On Thu, May 30, 2019 at 6:57 PM Roberto Ierusalimschy wrote:
> > I believe that many programmers stumble upon this while learning Lua.
>
> Well, it is a very strange thing to hit, you need to do some weird
> things, starting by clearing the "local" which holds it inside the
> function.

It is weirded than that. You also need some alternative way to access
the value that is being collected.
That doesn't seem common for someone learning Lua.



You're correct about "the alternative way".
But nevertheless, such mistake could be made while learning Lua.
And I believe many people do this mistake (I've done it too).
A programmer must understand that Lua doesn't anchor function's arguments.
Otherwise he could write a program similar to the following:

   local ffi = require"ffi"
   ffi.cdef"int MessageBoxA(void*, const char*, const char*, int)"

   local function show_message(str, cap)
      str = ffi.cast("const char *", str)
      cap = ffi.cast("const char *", cap)

      -- add some code here which may trigger GC

      ffi.C.MessageBoxA(nil, str, cap, 0)
   end

   show_message("Hello "..os.getenv"USERNAME", "Greeting")



Here FFI library is used to create cdata (specific type of userdata) which contains references not visible by GC.
New value of local variable 'str' is actually a C pointer to Lua string passed as argument.
For this pointer to be valid, original Lua string must exist.
But in this program 'str' may become a dangling pointer before 'MessageBoxA' is invoked.

The situation is tricky enough.
The mistake is observable only when Lua string is dynamically created (such as "Hello "..username).
Strings represented as literals (such as "Greeting") are anchored by the function's prototype, so they will not be GC-ed inside this function.

Of course, this problem is not FFI-library specific.
You can make similar mistake when using usual userdatum.
FFI library just gives you wonderful possibility to create userdata-like objects without writing C code.

That's why I've suggested to add phrase to the Lua manual to emphasize the fact that Lua doesn't anchor functions' arguments.
Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Roberto Ierusalimschy
> Of course, this problem is not FFI-library specific.

I beg to differ.

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Philippe Verdy
In reply to this post by Francisco Olarte


Le jeu. 30 mai 2019 à 08:31, Francisco Olarte <[hidden email]> a écrit :
Egor:

On Thu, May 30, 2019 at 7:39 AM Egor Skriptunoff
<[hidden email]> wrote:
> On Mon, May 27, 2019 at 8:26 PM Francisco Olarte wrote:
>> At first I thought the lua code would keep it alive, as it is in the
>> arguments of the called function. Then I realized the function could
>> be "function(ud); ud=nil; collectgarbage(); end". Then I entered a
>> death spiral of documentation reading trying to find some thing.

> Lua doesn't anchor function arguments, and this fact may indeed be not obvious from the Lua manual.

I took the middle road, could not find an explicit afirmation of it
anchoring them, so I assumed they would not, and coded for that.

> I believe that many programmers stumble upon this while learning Lua.

Well, it is a very strange thing to hit, you need to do some weird
things, starting by clearing the "local" which holds it inside the
function. I just got to it because I was being defensive.

You don't need to "clear" the locals that hold the parameter values; it's enough to change their value, making the old value then inaccessible and is garbage-collectable at any time after this time, before the function returns, because it is no longer accessible at all (unless you've aliased that value by copying into another variable or data structure which is still accessible).

A typical example :

function(x)
  if type(x) = 'string'
    x = tonumber(x)
    -- x was a string whose value may be gargage collected before this function returns
    -- x is now another object, a number
  else if type(x) = 'table'
    x = average(x)
    -- x was a table whose value may be gargage collected before this function returns
    -- x is now another object, a number
   end
   collectgarbage('collect')  -- fhe former table or string value of x may be garbage-collected
   local y = dosomethingwith(x)
   return y
  end

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Francisco Olarte
In reply to this post by Egor Skriptunoff-2
On Fri, May 31, 2019 at 9:36 PM Egor Skriptunoff
<[hidden email]> wrote:
...

> A programmer must understand that Lua doesn't anchor function's arguments.
> Otherwise he could write a program similar to the following:
>
>    local ffi = require"ffi"
>    ffi.cdef"int MessageBoxA(void*, const char*, const char*, int)"
>
>    local function show_message(str, cap)
>       str = ffi.cast("const char *", str)
>       cap = ffi.cast("const char *", cap)
>
>       -- add some code here which may trigger GC
>
>       ffi.C.MessageBoxA(nil, str, cap, 0)
>    end
>
>    show_message("Hello "..os.getenv"USERNAME", "Greeting")
>
>
> Here FFI library is used to create cdata (specific type of userdata) which contains references not visible by GC.
> New value of local variable 'str' is actually a C pointer to Lua string passed as argument.
> For this pointer to be valid, original Lua string must exist.
> But in this program 'str' may become a dangling pointer before 'MessageBoxA' is invoked.
> The situation is tricky enough.
> The mistake is observable only when Lua string is dynamically created (such as "Hello "..username).
> Strings represented as literals (such as "Greeting") are anchored by the function's prototype, so they will not be GC-ed inside this function.

This "ffi.cast" stuff will bite you in much simpler constructs, even
without any function calls:

s=package.path.."x" -- Just looking for a known external strin..
s=ffi.cast("const char *", s)
-- trigger gc, use s

IMNSHO this kinds of functions have their use, but it should be
wrapped and hiden deep in the bowels of a library written with great
care to have proper anchoring around all usages. No funky pcalls
needed to core dump.

> Of course, this problem is not FFI-library specific.
> You can make similar mistake when using usual userdatum.
> FFI library just gives you wonderful possibility to create userdata-like objects without writing C code.

Yep, it's halfway between lua and C, and any programmer can dump core
there. That's why I think ffi should be treaten as the C/C++ compiler,
just leave it to the pros and wrap it in a lib. My userdata libraries
may have bugs and dump, but I treat any possibiilty of the user been
able to trigger a dump from lua as a high priority bug. I nearly
switched to luajit to make the lib using ffi, and in this case I would
have threated the "lua" code using ffi as the C code.

> That's why I've suggested to add phrase to the Lua manual to emphasize the fact that Lua doesn't anchor functions' arguments.

That would be nice. I nearly hit that ( I'll say it again, is was a
bug in my code ), but some comments around the pcall / etc..
descriptions may be nice ( I was thinking, the args are in the stack
until return, so no gc, so I can touch them a bit. I did not think the
args may be cleared from the stack before executing, or the args may
be called before pushing results and result creation may trigger a gc.
Then I thought about it and sent the email which triggered this
discussion. Then I decide to do the right thing and anchor them myself
( as I do with some other stuff, assume the worst when not finding
docs, worst it can happen then is I wasted a few cycles ) ).

Francisco Olarte.

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Francisco Olarte
In reply to this post by Philippe Verdy
Philippe:

On Sat, Jun 1, 2019 at 4:51 AM Philippe Verdy <[hidden email]> wrote:
> You don't need to "clear" the locals that hold the parameter values; it's enough to change their value, making the old value then inaccessible and is garbage-collectable at any time after this time, before the function returns, because it is no longer accessible at all (unless you've aliased that value by copying into another variable or data structure which is still accessible).

Oh, my apologies. You are right, I assumed a moderately knowledgeable
audience when I wrote that.

Francisco Olarte.

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Gé Weijers
A general observation:

An optimizing implementation of Lua could do variable liveness analysis and reuse stack slots, resulting in the following:

function f(x)
  print(x)
  local y = g() -- this overwrites x, making it collectable
  print(y)
end

I have seen this behavior in compiled languages that use a garbage collector, the compiler translates the code into static single assignment form, and 'x' is considered dead once its value is passed to 'print', so the GC no longer traces it and 'x' disappears. 

PUC's Lua interpreter does not do this but a different implementation (JIT-based?) may well. Assuming the object is reachable until the function returns is hazardous to your health 😕


Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Francisco Olarte
Hi Gé:

On Sat, Jun 1, 2019 at 6:50 PM Gé Weijers <[hidden email]> wrote:
> A general observation:
> An optimizing implementation of Lua could do variable liveness analysis and reuse stack slots, resulting in the following:
> function f(x)
>   print(x)
>   local y = g() -- this overwrites x, making it collectable
>   print(y)
> end
> I have seen this behavior in compiled languages that use a garbage collector, the compiler translates the code into static single assignment form, and 'x' is considered dead once its value is passed to 'print', so the GC no longer traces it and 'x' disappears.

I think this would be a faulty optimizer. To be exact, I think doing
this and allowing the value to be collected would be an optimizer
error. I have not tried to understand the spec in detail, but, in a
language with finalizers which can be observed, this changes the
semantics of the program.

If you do not have finalizers, and the only thing you can do with a
value is read it, that's ok to me, or if the language specifies these
kind of behaviour, but I may have coded a function which this shape,
even without the print of x, with the only purpose of insuring the
finalizer of x's value does not run until function return, and the
optimizer is changing it ( again, if the optimizer is sure that's not
the case, optimize it, but that would be real impressive optimizer ).

Again, not sure of the intention but "Lua manages memory automatically
by running a garbage collector to collect all dead objects (that is,
objects that are no longer accessible from Lua)." indicates to me I
can count of the value of x not being collected before return from the
function, otherwise the guys at Rio could have written "no longer
ACCESED", their english is quite good and given their work I am quite
sure they understand the difference.

And, the only thing I should be able to observe from an optimization
of code ( with defined behaviour, not entering into the undefined
behaviour tarpit here ) should be it running at a different speed (
not necessarily faster ). Other effects, buggy optimizer.

> PUC's Lua interpreter does not do this but a different implementation (JIT-based?) may well. Assuming the object is reachable until the function returns is hazardous to your health

I think PUC's follow their own definition in 2.5 of the manual, and
I've always assumed they would do it or modify it ( the interpreter OR
the manual ) if reported not doing it on any case.

A different implementation, as long as it documents it, is fine for me
as long as they document their behaviour ( although it may be really
difficult to justify that optimization. Fine on a language without
finalizers, but on a different one saying "when you call
f(create_observable_finalizer_object()) the object may be garbage
collected and the finalizer called at any time" is a though thing to
defend. And would prohibit a series of more "legit" optimizations (
and, IMO, useful) optimizations, like folding
"var=create_observable_finalizer_object();f(var);var=nil into the
above call.):

Francisco Olarte.

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Andrew Gierth
>>>>> "Francisco" == Francisco Olarte <[hidden email]> writes:

 >> A general observation: An optimizing implementation of Lua could do
 >> variable liveness analysis and reuse stack slots, resulting in the
 >> following:

 >> function f(x)
 >>   print(x)
 >>   local y = g() -- this overwrites x, making it collectable
 >>   print(y)
 >> end

 Francisco> I think this would be a faulty optimizer. To be exact, I
 Francisco> think doing this and allowing the value to be collected
 Francisco> would be an optimizer error. I have not tried to understand
 Francisco> the spec in detail, but, in a language with finalizers which
 Francisco> can be observed, this changes the semantics of the program.

There's a specific idiom that this kind of optimization would break,
which is when one fetches a key or value from a weak table into a local
variable purely to ensure it does not get collected during some process.
In this case the local variable might never be referenced at all after
assigning it.

--
Andrew.

Reply | Threaded
Open this post in threaded view
|

Re: Garbage collection durint pcall.

Coda Highland


On Sat, Jun 1, 2019 at 2:13 PM Andrew Gierth <[hidden email]> wrote:
>>>>> "Francisco" == Francisco Olarte <[hidden email]> writes:

 >> A general observation: An optimizing implementation of Lua could do
 >> variable liveness analysis and reuse stack slots, resulting in the
 >> following:

 >> function f(x)
 >>   print(x)
 >>   local y = g() -- this overwrites x, making it collectable
 >>   print(y)
 >> end

 Francisco> I think this would be a faulty optimizer. To be exact, I
 Francisco> think doing this and allowing the value to be collected
 Francisco> would be an optimizer error. I have not tried to understand
 Francisco> the spec in detail, but, in a language with finalizers which
 Francisco> can be observed, this changes the semantics of the program.

There's a specific idiom that this kind of optimization would break,
which is when one fetches a key or value from a weak table into a local
variable purely to ensure it does not get collected during some process.
In this case the local variable might never be referenced at all after
assigning it.

--
Andrew.

This is often called RAII ("resource acquisition is initialization" but the actual practice of it doesn't quite fit that exact description anymore).

The solution is to assert that <toclose> variables are always considered live. It is, after all, an explicit declaration that the end of the variable's lifetime is precisely the same as the end of the lexical scope. And this would also be one of the more common reasons to use a <toclose> variable in the first place, so it's a win-win.

/s/ Adam
1234