Author: rgrjr
Date: Sat Mar 4 18:57:24 2006
New Revision: 11793
Modified:
trunk/src/ops/core.ops
trunk/src/sub.c
trunk/t/op/calling.t
Log:
* src/ops/core.ops:
+ (op get_params): Parrot_free_context gently. This allows tailcall
to work from subs that create closures.
* src/sub.c:
+ (Parrot_find_pad): Try to avoid unbounded loop.
* t/op/calling.t:
+ Try to test same. May not catch the error if it regresses, but is
probably better than no test at all.
Modified: trunk/src/ops/core.ops
==============================================================================
--- trunk/src/ops/core.ops (original)
+++ trunk/src/ops/core.ops Sat Mar 4 18:57:24 2006
@@ -528,7 +528,9 @@
PObj_get_FLAGS(ccont) &= ~SUB_FLAG_TAILCALL;
--ctx->recursion_depth;
ctx->caller_ctx = caller_ctx->caller_ctx;
- Parrot_free_context(interpreter, caller_ctx, 1);
+ /* ordinarily, this will free the context immediately, but not if the
+ sub created a closure (or continuation, or . . .). */
+ Parrot_free_context(interpreter, caller_ctx, 0);
interpreter->current_args = NULL;
}
goto ADDRESS(pc);
Modified: trunk/src/sub.c
==============================================================================
--- trunk/src/sub.c (original)
+++ trunk/src/sub.c Sat Mar 4 18:57:24 2006
@@ -411,6 +411,18 @@
if (VTABLE_exists_keyed_str(interpreter, lex_pad, lex_name))
return lex_pad;
}
+#if CTX_LEAK_DEBUG
+ if (outer == ctx) {
+ /* This is a bug; a context can never be its own :outer context.
+ * Detecting it avoids an unbounded loop, which is difficult to
+ * debug, though we'd rather not pay the cost of detection in a
+ * production release.
+ */
+ real_exception(interpreter, NULL, INVALID_OPERATION,
+ "Bug: Context %p :outer points back to itself.",
+ ctx);
+ }
+#endif
ctx = outer;
}
return NULL;
Modified: trunk/t/op/calling.t
==============================================================================
--- trunk/t/op/calling.t (original)
+++ trunk/t/op/calling.t Sat Mar 4 18:57:24 2006
@@ -1640,6 +1640,72 @@
ok 2
OUTPUT
+pir_output_is(<<'CODE', <<'OUTPUT', "newclosure followed by tailcall");
+## regression test for newclosure followed by tailcall, which used to recycle
+## the context too soon. it looks awful because (a) the original version was
+## produced by a compiler, and (b) in order to detect regression, we must force
+## parrot to reuse the context, which seems to requires having other calls that
+## use particular numbers of registers (and probably a fair amount of luck).
+.sub _main :main
+ ## debug 0x80
+ .lex "MAIN-CONT", $P41
+ $I42 = 10
+ $P41 = new .Continuation
+ set_addr $P41, L2
+ goto L3
+L2:
+ get_results '(0)', $P45
+ print "got "
+ print $P45
+ print ".\n"
+ .return ()
+L3:
+ .const .Sub $P49 = "___internal_main_test_"
+ newclosure $P48, $P49
+ .return _try_it($I42, $P48)
+.end
+
+.sub ___internal_main_test_ :outer('_main')
+ .param pmc arg1
+ print "[in test]\n"
+ find_lex $P41, "MAIN-CONT"
+ $P55 = new "Undef"
+ if arg1 != 3 goto L3
+ $P58 = arg1
+ $P59 = arg1
+ $P57 = n_mul $P58, $P59
+ set_args '(0)', $P57
+ tailcall $P41
+L3:
+ print "not "
+ print arg1
+ print "\n"
+.end
+
+
+.sub _try_it
+ .param int n
+ .param pmc closure
+ $P42 = new "Undef"
+ $P42 = 0
+ goto L4
+L2:
+ closure($P42)
+ $P42 = $P42 + 1
+L4:
+ if $P42 < n goto L2
+.end
+CODE
+[in test]
+not 0
+[in test]
+not 1
+[in test]
+not 2
+[in test]
+got 9.
+OUTPUT
+
pir_output_is(<<'CODE', <<'OUTPUT', "call evaled vtable code");
.sub main :main
.local string s
@@ -2214,6 +2280,7 @@
CODE
/duplicate name/
OUTPUT
+
## remember to change the number of tests :-)
-BEGIN { plan tests => 87 }
+BEGIN { plan tests => 88 }