Author: leo
Date: Mon Nov 14 04:42:14 2005
New Revision: 9968

Modified:
   trunk/classes/closure.pmc
   trunk/classes/sub.pmc
   trunk/imcc/pbc.c
   trunk/include/parrot/sub.h
   trunk/ops/experimental.ops
   trunk/src/sub.c
   trunk/t/op/lexicals.t
Log:
lexicals 20 - closures but now really

* fix closure handling
* newclosure clones an existing sub and remembers outer_ctx
* mark the outer_ctx for closure in mark_context
* create lex_info too, if sub has just :outer but no .lex
* test

I hope it's now really correct ;-)


Modified: trunk/classes/closure.pmc
==============================================================================
--- trunk/classes/closure.pmc   (original)
+++ trunk/classes/closure.pmc   Mon Nov 14 04:42:14 2005
@@ -58,7 +58,10 @@ Marks the closure as live.
     void mark () {
         struct Parrot_sub * sub = PMC_sub(SELF);
         SUPER();
-        mark_stack(INTERP, sub->pad_stack);
+        if (sub->pad_stack)
+            mark_stack(INTERP, sub->pad_stack);
+        if (sub->outer_ctx)
+            mark_context(INTERP, sub->outer_ctx);
     }
 
 

Modified: trunk/classes/sub.pmc
==============================================================================
--- trunk/classes/sub.pmc       (original)
+++ trunk/classes/sub.pmc       Mon Nov 14 04:42:14 2005
@@ -365,6 +365,8 @@ create_ctx:
                         enum_class_LexPad),
                     sub->lex_info);
             VTABLE_set_pointer(INTERP, context->lex_pad, context);
+            if (!sub->outer_ctx)
+                 sub->outer_ctx = caller_ctx;
         }
         /* switch code segment if needed */
         if (INTERP->code != sub->seg) {

Modified: trunk/imcc/pbc.c
==============================================================================
--- trunk/imcc/pbc.c    (original)
+++ trunk/imcc/pbc.c    Mon Nov 14 04:42:14 2005
@@ -693,10 +693,14 @@ create_lexinfo(Interp *interpreter, IMC_
                 lex_name = constants[k]->u.string;
                 assert(PObj_is_string_TEST(lex_name));
                 (decl_func)(interpreter,
-                        lex_info, lex_name, r->color);
+                            lex_info, lex_name, r->color);
             }
         }
     }
+    if (!lex_info && unit->outer) {
+        lex_info = pmc_new_noinit(interpreter, lex_info_id);
+        VTABLE_init_pmc(interpreter, lex_info, sub);
+    }
     return lex_info;
 }
 

Modified: trunk/include/parrot/sub.h
==============================================================================
--- trunk/include/parrot/sub.h  (original)
+++ trunk/include/parrot/sub.h  Mon Nov 14 04:42:14 2005
@@ -65,6 +65,7 @@ typedef struct Parrot_sub {
     PMC      *lex_info;         /* LexInfo PMC */
     PMC      *outer_sub;        /* :outer for closures */
     PMC      *eval_pmc;         /* eval container / NULL */
+    parrot_context_t *outer_ctx;       /* new style */
 
     /* - end common */
 
@@ -91,10 +92,10 @@ typedef struct Parrot_coro {
     PMC      *lex_info;         /* LexInfo PMC */
     PMC      *outer_sub;        /* :outer for closures */
     PMC      *eval_pmc;         /* eval container / NULL */
+    struct Parrot_Context  *ctx;          /* coroutine context */
 
     /* - end common */
 
-    struct Parrot_Context  *ctx;          /* coroutine context */
     struct PackFile_ByteCode *caller_seg;  /* bytecode segment */
 } * parrot_coro_t;
 
@@ -141,6 +142,7 @@ int Parrot_Context_info(Interp *interpre
 STRING* Parrot_Context_infostr(Interp *interpreter, parrot_context_t *);
 
 PMC* Parrot_find_pad(Interp*, STRING *lex_name);
+PMC* parrot_new_closure(Interp*, PMC*);
 
 #endif /* PARROT_SUB_H_GUARD */
 

Modified: trunk/ops/experimental.ops
==============================================================================
--- trunk/ops/experimental.ops  (original)
+++ trunk/ops/experimental.ops  Mon Nov 14 04:42:14 2005
@@ -231,19 +231,7 @@ Create a closure of the given subroutine
 =cut
 
 inline op newclosure(out PMC, in PMC) {
-  PMC *clos;
-  struct Parrot_sub *newsub;
-  PMC * pad = scratchpad_get_current(interpreter);
-  clos = VTABLE_clone(interpreter, $2);
-  clos->vtable = Parrot_base_vtables[enum_class_Closure];
-  newsub = PMC_sub(clos);
-  newsub->pad_stack = new_stack(interpreter, "Pad");
-  if (pad) {
-    /* put the correct pad in place */
-    stack_push(interpreter, &newsub->pad_stack, pad,
-       STACK_ENTRY_PMC, STACK_CLEANUP_NULL);
-  }
-  $1 = clos;
+  $1 = parrot_new_closure(interpreter, $2);
   goto NEXT();
 }
 ###############################################################################

Modified: trunk/src/sub.c
==============================================================================
--- trunk/src/sub.c     (original)
+++ trunk/src/sub.c     Mon Nov 14 04:42:14 2005
@@ -39,7 +39,8 @@ mark_context(Interp* interpreter, parrot
     PObj *obj;
     int i;
 
-    mark_stack(interpreter, ctx->pad_stack);
+    if (ctx->pad_stack)
+        mark_stack(interpreter, ctx->pad_stack);
     mark_stack(interpreter, ctx->user_stack);
     mark_stack(interpreter, ctx->control_stack);
     mark_register_stack(interpreter, ctx->reg_stack);
@@ -418,7 +419,7 @@ Parrot_find_pad(Interp* interpreter, STR
 {
     PMC *lex_pad;
     parrot_context_t *ctx;
-    PMC *result, *sub, *caller, *cont;
+    PMC *result, *sub;
 
     ctx = CONTEXT(interpreter->ctx);;
     lex_pad = ctx->lex_pad;
@@ -429,28 +430,53 @@ Parrot_find_pad(Interp* interpreter, STR
         result = VTABLE_get_pmc_keyed_str(interpreter, lex_pad, lex_name);
         if (result)
             return lex_pad;
-        sub = PMC_sub(sub)->outer_sub;
-        /*
-         * locate outer in call chain
-         */
-        while (1) {
-            cont = ctx->current_cont;
-            if (!cont)
-                return NULL;
-            ctx = PMC_cont(cont)->to_ctx;
-            if (!ctx)
-                return NULL;
-            caller = ctx->current_sub;
-            if (caller == sub)
-                break;
-        }
+        ctx = PMC_sub(sub)->outer_ctx;
+        if (!ctx)
+            return NULL;
         lex_pad = ctx->lex_pad;
         if (PMC_IS_NULL(lex_pad))
             return NULL;
+        sub = PMC_sub(sub)->outer_sub;
     }
     return NULL;
 }
 
+PMC*
+parrot_new_closure(Interp *interpreter, PMC *sub_pmc)
+{
+    PMC *clos_pmc;
+    struct Parrot_sub *clos, *sub;
+    PMC *pad, *cont;
+    parrot_context_t *ctx;
+
+    clos_pmc = VTABLE_clone(interpreter, sub_pmc);
+    clos_pmc->vtable = Parrot_base_vtables[enum_class_Closure];
+    sub = PMC_sub(sub_pmc);
+    clos = PMC_sub(clos_pmc);
+    if (!PMC_IS_NULL(sub->lex_info)) {
+        /* new style closures */
+        ctx = CONTEXT(interpreter->ctx);
+        cont = ctx->current_cont;
+        /* preserve this frame by converting the continuation */
+        cont->vtable = Parrot_base_vtables[enum_class_Continuation];
+        /* remember this (the :outer) ctx in the closure */
+        clos->outer_ctx = ctx;
+        /* the closure refs now this context too */
+        ctx->ref_count++;
+    }
+    else {
+        /* old scratchpad */
+
+        pad = scratchpad_get_current(interpreter);
+        clos->pad_stack = new_stack(interpreter, "Pad");
+        if (pad) {
+            /* put the correct pad in place */
+            stack_push(interpreter, &clos->pad_stack, pad,
+                    STACK_ENTRY_PMC, STACK_CLEANUP_NULL);
+        }
+    }
+    return clos_pmc;
+}
 /*
 
 =back

Modified: trunk/t/op/lexicals.t
==============================================================================
--- trunk/t/op/lexicals.t       (original)
+++ trunk/t/op/lexicals.t       Mon Nov 14 04:42:14 2005
@@ -16,7 +16,7 @@ Tests various lexical scratchpad operati
 
 =cut
 
-use Parrot::Test tests => 32;
+use Parrot::Test tests => 33;
 
 output_is(<<'CODE', <<'OUTPUT', '.lex parsing - PASM');
 .pcc_sub main:
@@ -324,6 +324,63 @@ ex_main_a
 ex_main_a
 OUTPUT
 
+pir_output_is(<<'CODE', <<'OUTPUT', 'closure 3');
+# sub foo {
+#     my ($n) = @_;
+#     sub {$n += shift}
+# }
+# my $f = foo(5);
+# print &$f(3), "\n";
+# my $g = foo(20);
+# print &$g(3), "\n";
+# print &$f(3), "\n";
+# print &$g(4), "\n";
+
+.sub foo
+    .param pmc arg
+    .local pmc n
+    .lex '$n', n
+    n = arg
+    .const .Sub anon = "anon"
+    $P0 = newclosure anon
+    .return ($P0)
+.end
+
+.sub anon :outer(foo)
+    .param pmc arg
+    $P0 = find_lex '$n'
+    # in practice we need copying the arg but as it is passed
+    # as native int, we already have a fresh pmc
+    $P0 += arg
+    .return ($P0)
+.end
+
+.sub main :main
+    .local pmc f, g
+    .lex '$f', f
+    .lex '$g', g
+    f = foo(5)
+    $P0 = f(3)
+    print $P0
+    print "\n"
+    g = foo(20)
+    $P0 = g(3)
+    print $P0
+    print "\n"
+    $P0 = f(3)
+    print $P0
+    print "\n"
+    $P0 = g(4)
+    print $P0
+    print "\n"
+.end
+CODE
+8
+23
+11
+27
+OUTPUT
+
 pir_output_like(<<'CODE', <<'OUTPUT', 'get non existing');
 .sub "main"
     .lex 'a', $P0

Reply via email to