-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
(sorry for the late reply)
Leopold Toetsch wrote:
> Am Sonntag, 20. Mai 2007 21:51 schrieb Bram Geron:
>> Bram Geron wrote:
>>> The patch in <parrot.solution1.patch> fixes the problem for me.
>> I realized that contexts currently initially have a ref_count of 0, if
>> they're not used as :outer targets for other subs. So in 'normal'
>> situations, the caller's context's ref_count now drops from 0 to -1 in a
>> tail call, and since -1 != 0 the caller's context will never be freed,
>> resulting in a memory leak. Attached <parrot.solution1.updated.patch>
>> should fix that.
>
> It's likely simpler to start all context refcounts equally with 1. This would
> probably reduce the current special refcount handling. But it would need some
> changes, which is easily greppable I presume.
The patch I attached should solve that. In a freshly created context,
the refcount is zero, and this increases it by one. I think incrementing
it is slightly better than directly assigning it a refcount of 1,
because that could cause bugs if we incremented the refcount before for
some mysterious reason. (far-fetched, I admit.)
With the patch, [perl #42790] "[BUG] Tailcall with slurpy argument
passing causes a memory leak" is solved for me too.
- --
Bram Geron | GPG 0xE7B9E65E
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFGanWHvquQbee55l4RApxAAJ9TAdA5Oc6vWpfhoCqLZPnD9+4rBwCeOg0T
4vgdP53aR0FQJ0iPjsKR8v4=
=NEBz
-----END PGP SIGNATURE-----
Index: src/pmc/sub.pmc
===================================================================
--- src/pmc/sub.pmc (revision 18597)
+++ src/pmc/sub.pmc (working copy)
@@ -284,8 +284,9 @@
if (PObj_get_FLAGS(SELF) & SUB_FLAG_IS_OUTER) {
/* don't destroy context */
ccont->vtable = interp->vtables[enum_class_Continuation];
- context->ref_count++;
}
+ /* reference counting should work */
+ context->ref_count++;
if (!PMC_IS_NULL(INTERP->current_object)) {
context->current_object = INTERP->current_object;
@@ -322,7 +323,7 @@
PObj_get_FLAGS(ccont) &= ~SUB_FLAG_TAILCALL;
context->caller_ctx = caller_ctx->caller_ctx;
- Parrot_free_context(INTERP, caller_ctx, 1);
+ Parrot_free_context(INTERP, caller_ctx, 0);
}
}
Index: t/op/calling.t
===================================================================
--- t/op/calling.t (revision 18597)
+++ t/op/calling.t (working copy)
@@ -7,7 +7,7 @@
use lib qw( . lib ../lib ../../lib );
use Test::More;
-use Parrot::Test tests => 94;
+use Parrot::Test tests => 95;
=head1 NAME
@@ -2408,6 +2408,45 @@
Have bar: 2
OUTPUT
+pir_output_is( <<'CODE', <<'OUTPUT', "Tail call without arguments should not free the context when a closure depends on it" );
+.sub main :main
+ $P0 = create_closure_and_run_it()
+.end
+
+.sub create_closure_and_run_it
+ P0 = new "Integer"
+ P0 = 3
+ .lex "val", P0
+ P2 = get_global "myclosure"
+ P1 = newclosure P2
+ # There is a closure depending on our current context, so this shouldn't
+ # free it.
+ .return P1()
+.end
+
+.sub myclosure :outer(create_closure_and_run_it)
+ P1 = find_lex "val"
+ say P1
+ donothing()
+ P1 = find_lex "val"
+ say P1
+ .return ()
+.end
+
+.sub donothing
+ P0 = new "Integer"
+ P0 = 5
+ # This creates a new binding that is not accessible by the
+ # caller (myclosure)
+ .lex "val", P0
+ P2 = null
+ P1 = null
+.end
+CODE
+3
+3
+OUTPUT
+
# Local Variables:
# mode: cperl
# cperl-indent-level: 4