From: Bob Rogers <[EMAIL PROTECTED]>
   Date: Sun, 6 Aug 2006 11:20:08 -0400

   Notes on the POC:

   . . . It doesn't quite work, apparently because set_retval gives up
   too soon, and so set_s_p always sets the result to a null string.

I figured this out in the process of implementing print_p.  It still
gets plenty of errors, though, some of which are pretty strange.  (The
one that unexpected succeeded is Matt's test case for bug #39988.)

                                        -- Bob

------------------------------------------------------------------------
Failed 11/239 test scripts, 95.40% okay. 124/5359 subtests failed, 97.69% okay.
Failed Test                        Stat Wstat Total Fail  Failed  List of Failed
--------------------------------------------------------------------------------
t/compilers/pge/03-optable.t         31  7936    35   31  88.57%  1-23 27 29-35
t/compilers/pge/p6regex/01-regex.t   80 20480   494   80  16.19%  287-301 305-
                                                                  327 330 355-
                                                                  357 359-390
                                                                  393-396 486-
                                                                  487
t/compilers/pge/p6regex/closure.t     3   768     6    3  50.00%  1 4-5
t/compilers/pge/p6regex/context.t     1   256    20    1   5.00%  8
t/compilers/pge/pge_examples.t        1   256     2    1  50.00%  2
t/op/calling.t                        1   256    93    1   1.08%  39
t/op/gc.t                             1   256    22    1   4.55%  11
t/pmc/delegate.t                      1   256     9    1  11.11%  9
t/pmc/mmd.t                           1   256    39    1   2.56%  30
t/pmc/object-meths.t                  2   512    34    2   5.88%  11 25
t/pmc/objects.t                       2   512    78    2   2.56%  33 59
 (1 subtest UNEXPECTEDLY SUCCEEDED), 10 tests and 459 subtests skipped.
make: *** [test] Error 255

Diffs between last version checked in and current workfile(s):

Index: include/parrot/sub.h
===================================================================
--- include/parrot/sub.h        (revision 13852)
+++ include/parrot/sub.h        (working copy)
@@ -118,6 +118,11 @@
     struct Parrot_Context *from_ctx;  /* sub, this cont is returning from */
     opcode_t *current_results;    /* ptr into code with get_results opcode
                                     full continuation only */
+    cont_C_continuation_t C_continuation;
+                                     /* if not NULL, a C function to call
+                                        instead of normal return value
+                                        processing. */
+    PMC *C_continuation_state;       /* state passed to C_continuation */
     int runloop_id;                  /* id of the creating runloop. */
 } * parrot_cont_t;
 
@@ -152,6 +157,16 @@
 PMC* Parrot_find_pad(Interp*, STRING *lex_name, parrot_context_t *);
 PMC* parrot_new_closure(Interp*, PMC*);
 
+opcode_t* Parrot_op_set_reg_from_vtable(Interp *, Call_bits_enum_t, INTVAL,
+                                        opcode_t *, get_string_method_t,
+                                        char *, PMC *);
+opcode_t * Parrot_op_tailcall_with_vtable_string(Interp *, opcode_t *, PMC *,
+                                                 get_string_method_t, char *,
+                                                 void string_fn(Interp*, 
STRING*),
+                                                 cont_C_continuation_t, PMC*);
+void parrot_op_print_string_internal(Interp*, STRING*);
+void Parrot_op_print_string_tail(Interp *, parrot_context_t *, PMC*, PMC*);
+
 #endif /* PARROT_SUB_H_GUARD */
 
 /*
Index: include/parrot/interpreter.h
===================================================================
--- include/parrot/interpreter.h        (revision 13852)
+++ include/parrot/interpreter.h        (working copy)
@@ -436,6 +436,12 @@
 
 /* &end_gen */
 
+/* This is for a C "tailcall" function used instead of normal subroutine return
+   processing. */
+typedef void (*cont_C_continuation_t)(Interp* interpreter,
+                                      parrot_context_t *caller_ctx,
+                                      PMC* continuation, PMC* c_closure_state);
+
 PARROT_API Interp *make_interpreter(Interp * parent, Interp_flags);
 PARROT_API void Parrot_init(Interp *);
 PARROT_API void Parrot_destroy(Interp *);
@@ -459,6 +465,8 @@
         va_list);
 
 PARROT_API void* Parrot_run_meth_fromc(Interp *, PMC *sub, PMC* obj, STRING 
*meth);
+PARROT_API opcode_t * Parrot_tailcall_meth_fromc(Interp *,
+        PMC *, PMC *, opcode_t *, cont_C_continuation_t, PMC *);
 PARROT_API void* Parrot_run_meth_fromc_args(Interp *, PMC *sub,
         PMC* obj, STRING *meth, const char *signature, ...);
 PARROT_API INTVAL Parrot_run_meth_fromc_args_reti(Interp *, PMC *sub,
Index: src/pmc/retcontinuation.pmc
===================================================================
--- src/pmc/retcontinuation.pmc (revision 13852)
+++ src/pmc/retcontinuation.pmc (working copy)
@@ -123,6 +123,11 @@
         INTERP->ctx.bp = caller_ctx->bp;
         INTERP->ctx.bp_ps = caller_ctx->bp_ps;
         next = cc->address;
+        if (cc->C_continuation) {
+            /* The C continuation replaces results handling. */
+            cc->C_continuation(INTERP, cc->from_ctx,
+                               SELF, cc->C_continuation_state);
+        }
         Parrot_free_context(INTERP, cc->from_ctx, 1);
         seg = cc->seg;
 #ifdef NDEBUG
Index: src/pmc/continuation.pmc
===================================================================
--- src/pmc/continuation.pmc    (revision 13852)
+++ src/pmc/continuation.pmc    (working copy)
@@ -87,6 +87,8 @@
         struct Parrot_cont * cc = PMC_cont(SELF);
         if (cc->to_ctx)
             mark_context(INTERP, cc->to_ctx);
+        if (cc->C_continuation_state)
+            pobject_lives(INTERP, (PObj *)cc->C_continuation_state);
     }
 
 /*
@@ -269,6 +271,11 @@
             ctx->current_results = cc->current_results;
         }
         pc = cc->address;
+        if (cc->C_continuation) {
+            /* The C continuation replaces results handling. */
+            cc->C_continuation(INTERP, caller_ctx,
+                               SELF, cc->C_continuation_state);
+        }
         if (ctx->current_results && INTERP->current_args) {
             /*
              * the register pointer is already switched back
Index: src/inter_run.c
===================================================================
--- src/inter_run.c     (revision 13852)
+++ src/inter_run.c     (working copy)
@@ -276,6 +276,31 @@
     return set_retval(interpreter, 0, ctx);
 }
 
+opcode_t *
+Parrot_tailcall_meth_fromc(Interp *interpreter,
+                           PMC *sub, PMC *obj, opcode_t *return_addr,
+                           cont_C_continuation_t C_cont,
+                           PMC *C_cont_state)
+/* This is magic for avoiding subordinate runloops. */
+{
+    parrot_context_t *old_ctx = CONTEXT(interpreter->ctx);
+    opcode_t offset, *dest;
+    struct Parrot_cont * cc;
+
+    interpreter->current_cont
+        = new_ret_continuation_pmc(interpreter, return_addr);
+    interpreter->current_object = obj;
+    cc = PMC_cont(interpreter->current_cont);
+    cc->C_continuation = C_cont;
+    cc->C_continuation_state = C_cont_state;
+    dest = VTABLE_invoke(interpreter, sub, (void*)1);
+    if (!dest)
+        internal_exception(1, "Subroutine returned a NULL address");
+    dest = parrot_pass_args_fromc(interpreter, "O", dest,
+                                  old_ctx, obj);
+    return dest;
+}
+
 void *
 Parrot_runops_fromc_args(Parrot_Interp interpreter, PMC *sub,
         const char *sig, ...)
Index: src/sub.c
===================================================================
--- src/sub.c   (revision 13852)
+++ src/sub.c   (working copy)
@@ -137,10 +137,13 @@
 new_continuation(Interp *interp, struct Parrot_cont *to)
 {
     struct Parrot_cont * const cc = mem_sys_allocate(sizeof(struct 
Parrot_cont));
-    struct Parrot_Context * const to_ctx = to ? to->to_ctx : 
CONTEXT(interp->ctx);
+    struct Parrot_Context * const to_ctx
+        = to ? to->to_ctx : CONTEXT(interp->ctx);
 
     cc->to_ctx = to_ctx;
     cc->from_ctx = CONTEXT(interp->ctx);
+    cc->C_continuation = NULL;
+    cc->C_continuation_state = NULL;
     cc->runloop_id = 0;
     CONTEXT(interp->ctx)->ref_count++;
     if (to) {
@@ -172,6 +175,8 @@
     struct Parrot_cont * const cc = mem_sys_allocate(sizeof(struct 
Parrot_cont));
     cc->to_ctx = CONTEXT(interp->ctx);
     cc->from_ctx = NULL;    /* filled in during a call */
+    cc->C_continuation = NULL;
+    cc->C_continuation_state = NULL;
     cc->runloop_id = 0;
     cc->seg = interp->code;
     cc->current_results = NULL;
@@ -483,6 +488,177 @@
 #endif
     return clos_pmc;
 }
+
+/* [stolen from delegate.pmc.  -- rgr, 5-Aug-06.] */
+static PMC *
+find_method_internal(Interp* interpreter, PMC *pmc, STRING *meth) {
+    PMC *class = pmc;
+
+    if (PObj_is_object_TEST(pmc)) {
+        class = GET_CLASS((Buffer *)PMC_data(pmc), pmc);
+    }
+    return Parrot_find_method_with_cache(interpreter, class, meth);
+}
+
+/* [stolen from delegate.pmc.  -- rgr, 5-Aug-06.] */
+static PMC *
+find_method_sub_or_die(Interp* interpreter, PMC *pmc, STRING *meth) {
+    PMC *returnPMC = find_method_internal(interpreter, pmc, meth);
+    if (PMC_IS_NULL(returnPMC)) {
+        PMC *class = pmc;
+        if (PObj_is_object_TEST(pmc)) {
+            class = GET_CLASS((Buffer *)PMC_data(pmc), pmc);
+            real_exception(interpreter, NULL, E_LookupError,
+                "Can't find method '%s' for object '%s'",
+                string_to_cstring(interpreter, meth),
+                string_to_cstring(interpreter, PMC_str_val(
+                        get_attrib_num((SLOTTYPE *)PMC_data(class),
+                            PCD_CLASS_NAME)))
+                );
+        } else {
+            real_exception(interpreter, NULL, E_LookupError,
+                "Can't find method '%s' - erroneous PMC",
+                string_to_cstring(interpreter, meth)
+                );
+        }
+    }
+    return returnPMC;
+}
+
+static void
+store_tail_result_into_register(Interp* interpreter,
+                                parrot_context_t *returning_ctx,
+                                PMC* continuation, PMC* c_closure_state)
+{
+    struct Parrot_Context *ctx = CONTEXT(interpreter->ctx);
+    INTVAL arg_type
+        = VTABLE_get_integer_keyed_int(interpreter, c_closure_state, 0);
+    INTVAL arg_register
+        = VTABLE_get_integer_keyed_int(interpreter, c_closure_state, 1);
+
+    switch (arg_type) {
+        case PARROT_ARG_STRING:
+            CTX_REG_STR(ctx, arg_register)
+                = set_retval(interpreter, 'S', returning_ctx);
+            break;
+        case PARROT_ARG_PMC:
+            CTX_REG_PMC(ctx, arg_register)
+                = set_retval(interpreter, 'P', returning_ctx);
+            break;
+        case PARROT_ARG_INTVAL:
+        case PARROT_ARG_FLOATVAL:
+        default:
+            real_exception(interpreter, NULL, 1,
+                           "oops; got arg_type %d when storing tail result\n",
+                           arg_type);
+    }
+}
+
+opcode_t *
+Parrot_op_set_reg_from_vtable(Interp *interpreter,
+                             Call_bits_enum_t arg_type,
+                             INTVAL arg_register,
+                             opcode_t *next,
+                             get_string_method_t vtable_method,
+                             char *method_name,
+                             PMC *method_object)
+{
+  struct Parrot_Context *ctx = CONTEXT(interpreter->ctx);
+
+  if (vtable_method == interpreter->vtables[enum_class_delegate]->get_string) {
+      /* winner */
+      /* fprintf(stderr, "gotcha\n"); */
+      STRING *meth = const_string(interpreter, method_name);
+      PMC *sub = find_method_sub_or_die(interpreter, method_object, meth);
+      PMC *state;
+      opcode_t *next_instruction;
+
+      state = pmc_new(interpreter, enum_class_FixedIntegerArray);
+      VTABLE_set_integer_native(interpreter, state, 2);
+      VTABLE_set_integer_keyed_int(interpreter, state, 0, (INTVAL) arg_type);
+      VTABLE_set_integer_keyed_int(interpreter, state, 1, (INTVAL) 
arg_register);
+      next_instruction
+          = Parrot_tailcall_meth_fromc(interpreter, sub, method_object, next,
+                                       store_tail_result_into_register,
+                                       state);
+      return next_instruction;
+  }
+  else {
+    /* just call the method and stuff it in the register. */
+    switch (arg_type) {
+        case PARROT_ARG_INTVAL:
+           CTX_REG_INT(ctx, arg_register)
+               = (INTVAL) (*vtable_method) (interpreter, method_object);
+            break;
+        case PARROT_ARG_FLOATVAL:
+            /* CTX_REG_NUM(ctx, arg_register) = (FLOATVAL) (*vtable_method) 
(interpreter, method_object); */
+            break;
+        case PARROT_ARG_STRING:
+            CTX_REG_STR(ctx, arg_register)
+               = (struct parrot_string_t *)
+                   (*vtable_method) (interpreter, method_object);
+            break;
+        case PARROT_ARG_PMC:
+            CTX_REG_PMC(ctx, arg_register)
+               = (PMC *) (*vtable_method) (interpreter, method_object);
+            break;
+        default:
+            internal_exception(1, "oops\n");
+    }
+    return next;
+  }
+}
+
+void
+parrot_op_print_string_internal(Interp* interpreter,
+                               STRING* const s)
+/* Helper for printing the result of a vtable method call. */
+{
+  if (s) {
+    PIO_putps(interpreter, PIO_STDOUT(interpreter), s);
+  }
+}
+
+void
+Parrot_op_print_string_tail(Interp* interpreter,
+                           parrot_context_t *returning_ctx,
+                           PMC* continuation, PMC* c_closure_state)
+/* Helper for printing the result of a vtable method call. */
+{
+  STRING * const s = set_retval(interpreter, 's', returning_ctx);
+  parrot_op_print_string_internal(interpreter, s);
+}
+
+opcode_t *
+Parrot_op_tailcall_with_vtable_string(Interp* interpreter,
+                                     opcode_t *next,
+                                     PMC *method_object,
+                                     get_string_method_t vtable_method,
+                                     char *method_name,
+                                     void string_fn(Interp*, STRING*),
+                                     cont_C_continuation_t continuation_fn,
+                                     PMC* c_closure_state)
+/* [we need to supply both tailcall_fn and continuation_fn because we don't 
have
+   a mechanism for passing non-PMC data to C_continuation fns.  -- rgr,
+   8-Aug-06.] */
+{
+  struct Parrot_Context *ctx = CONTEXT(interpreter->ctx);
+
+  if (vtable_method == interpreter->vtables[enum_class_delegate]->get_string) {
+      STRING *meth = const_string(interpreter, method_name);
+      PMC *sub = find_method_sub_or_die(interpreter, method_object, meth);
+
+      return Parrot_tailcall_meth_fromc(interpreter, sub, method_object, next,
+                                       continuation_fn, c_closure_state);
+  }
+  else {
+    /* just call the method, and pass the resulting string the string_fn. */
+    STRING * const s = VTABLE_get_string(interpreter, method_object);
+    (*string_fn)(interpreter, s);
+    return next;
+  }
+}
+
 /*
 
 =back
Index: src/ops/core.ops
===================================================================
--- src/ops/core.ops    (revision 13852)
+++ src/ops/core.ops    (working copy)
@@ -544,7 +544,10 @@
     ctx = CONTEXT(interpreter->ctx);
     ccont = ctx->current_cont;
 
-    if (PMC_cont(ccont)->address) {
+    if (PMC_cont(ccont)->C_continuation) {
+      /* return values will be handled at continuation invocation time. */
+    }
+    else if (PMC_cont(ccont)->address) {
        /* else it's from runops_fromc */
        parrot_context_t * const caller_ctx = PMC_cont(ccont)->to_ctx;
        if (! caller_ctx) {
Index: src/ops/set.ops
===================================================================
--- src/ops/set.ops     (revision 13852)
+++ src/ops/set.ops     (working copy)
@@ -155,9 +155,15 @@
   goto NEXT();
 }
 
+/* ' */
+
 inline op set(out STR, invar PMC) :base_core {
-  $1 = $2->vtable->get_string(interpreter, $2);
-  goto NEXT();
+  opcode_t *next = expr NEXT();
+  next = Parrot_op_set_reg_from_vtable
+    (interpreter, PARROT_ARG_STRING, cur_opcode[1], next,
+     $2->vtable->get_string, "__get_string",
+     $2);
+  goto ADDRESS(next);
 }
 
 inline op set(out STR, invar STR) :base_core {
Index: src/ops/io.ops
===================================================================
--- src/ops/io.ops      (revision 13852)
+++ src/ops/io.ops      (working copy)
@@ -229,13 +229,15 @@
   goto NEXT();
 }
 
+/* ' */
+
 op print(invar PMC) :base_io {
   PMC * const p = $1;
-  STRING * const s = (VTABLE_get_string(interpreter, p));
-  if (s) {
-    PIO_putps(interpreter, PIO_STDOUT(interpreter), s);
-  }
-  goto NEXT();
+  opcode_t *next = expr NEXT();
+  next = Parrot_op_tailcall_with_vtable_string
+    (interpreter, next, $1, $1->vtable->get_string, "__get_string",
+     parrot_op_print_string_internal, Parrot_op_print_string_tail, NULL);
+  goto ADDRESS(next);
 }
 
 op write(invar PMC) :base_io {

End of diffs.

Reply via email to