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.