# New Ticket Created by Leopold Toetsch # Please include the string: [perl #22745] # in the subject line of all future correspondence about this issue. # <URL: http://rt.perl.org/rt2/Ticket/Display.html?id=22745 >
Attached is a first try to unify the various sub types, structures and classes. - sub, continuation and coroutine have the same structure now - Contination and Coroutine are subclasses of Sub - stack_destroy() is new The major change in the functionality of subroutine calls now is: - on creating a Sub it gets its own pad_stack with the current lex_pad pushed on it (if any) - on invoke, this pad_stack is placed as the interpreter's pad_stack This is the same behavior as a coroutined did and does. I'm not totally sure, if we should create a new pad_stack. OTOH, on very deeply nested subroutine calls, the return continuation would have COW copies of this stack. When there is a new_pad opcode, the stack of the subroutine would be copied then, which would be more expensive for deeper sub call depths. We might also reduce the STACK_CHUNK_DEPTH, which currently is 256. Still remaining questions are: - do we want a Sub class that supports the old invoke/ret scheme? (and how should the class be named?) - do we want a new Sublite class (as proposed by Jonathan), that doesn't have its own pad_stack for non closures (and how should the class be named?) - can we toss CSub and related functions in method_utils? Comments welcome, leo -- attachment 1 ------------------------------------------------------ url: http://rt.perl.org/rt2/attach/59625/44168/975abe/parrot-subs.patch
--- parrot/classes/continuation.pmc Fri Jun 6 17:15:39 2003 +++ parrot-leo/classes/continuation.pmc Fri Jun 20 10:55:12 2003 @@ -14,7 +14,7 @@ #include "parrot/parrot.h" #include "parrot/method_util.h" -pmclass Continuation { +pmclass Continuation extends Sub { void init () { struct Parrot_Continuation * cc; @@ -27,10 +27,6 @@ mem_sys_free(PMC_data(SELF)); } - void set_integer_native (INTVAL value) { - ((struct Parrot_Continuation *)PMC_data(SELF))->continuation - = (opcode_t *)value; - } void mark () { mark_stack( @@ -63,32 +59,10 @@ stack_mark_cow(retc->ctx.control_stack); } - PMC* get_pmc () { - return SELF; - } - - INTVAL is_same (PMC* value) { - return SELF == value; - } - - void set_same (PMC* value) { - PMC_data(SELF) = PMC_data(value); - } - - INTVAL is_equal (PMC* value) { - return (SELF->vtable == value->vtable - && memcmp(PMC_data(value), PMC_data(SELF), - sizeof(struct Parrot_Continuation)) == 0); - } - - INTVAL defined () { - return ((struct Parrot_Continuation *)PMC_data(SELF))->continuation != NULL; - } - void* invoke (void* next) { struct Parrot_Continuation * cc = (struct Parrot_Continuation*)PMC_data(SELF); restore_context(interpreter, &cc->ctx); - return cc->continuation; /* interp will jump to this address */ + return cc->address; /* interp will jump to this address */ } } --- parrot/classes/coroutine.pmc Fri Jun 6 17:15:39 2003 +++ parrot-leo/classes/coroutine.pmc Fri Jun 20 11:51:15 2003 @@ -14,11 +14,7 @@ #include "parrot/parrot.h" #include "parrot/method_util.h" -pmclass Coroutine { - - INTVAL type () { - return enum_class_Coroutine; - } +pmclass Coroutine extends Sub { STRING* name () { return whoami; @@ -30,68 +26,29 @@ } void destroy () { - /* XXX stack_destroy for deeper stacks */ - mem_sys_free(((struct Parrot_Coroutine *)PMC_data(SELF))->ctx.user_stack); - mem_sys_free(((struct Parrot_Coroutine *)PMC_data(SELF))->ctx.control_stack); + struct Parrot_Coroutine * co = + (struct Parrot_Coroutine *)PMC_data(SELF); + stack_destroy(co->ctx.pad_stack); + stack_destroy(co->ctx.control_stack); + stack_destroy(co->ctx.user_stack); mem_sys_free(PMC_data(SELF)); } void mark () { - struct Parrot_Coroutine * co = (struct Parrot_Coroutine *)PMC_data(SELF); + struct Parrot_Coroutine * co = + (struct Parrot_Coroutine *)PMC_data(SELF); mark_stack(INTERP, co->ctx.user_stack); mark_stack(INTERP, co->ctx.control_stack); mark_stack(INTERP, co->ctx.pad_stack); } - void set_integer (PMC * value) { - ((struct Parrot_Coroutine*)PMC_data(SELF))->resume - = (opcode_t*)VTABLE_get_integer(INTERP, value); - } - - void set_integer_native (INTVAL value) { - ((struct Parrot_Coroutine*)PMC_data(SELF))->resume = (opcode_t*)value; - } - - PMC* get_pmc () { - return SELF; - } - - INTVAL is_same (PMC* value) { - return SELF == value; - } - INTVAL is_equal (PMC* value) { - return (SELF->vtable == value->vtable - && memcmp(PMC_data(value), PMC_data(SELF), - sizeof(struct Parrot_Coroutine)) == 0); - } - - INTVAL defined () { - return ((struct Parrot_Coroutine*)PMC_data(SELF))->resume != NULL; - } void* invoke (void* next) { struct Parrot_Coroutine* co = (struct Parrot_Coroutine*)PMC_data(SELF); - struct Stack_Chunk * tmp_stack = NULL; - void * dest = co->resume; - co->resume = (opcode_t *)next; - - /* - * Swap control, user and pad stacks. Data in other parts of the - * context are not preserved between calls to the coroutine. - */ - - tmp_stack = INTERP->ctx.user_stack; - INTERP->ctx.user_stack = co->ctx.user_stack; - co->ctx.user_stack = tmp_stack; - - tmp_stack = INTERP->ctx.control_stack; - INTERP->ctx.control_stack = co->ctx.control_stack; - co->ctx.control_stack = tmp_stack; - - tmp_stack = INTERP->ctx.pad_stack; - INTERP->ctx.pad_stack = co->ctx.pad_stack; - co->ctx.pad_stack = tmp_stack; + void * dest = co->address; + co->address = (opcode_t *)next; + swap_context(interpreter, &co->ctx); return dest; } --- parrot/classes/eval.pmc Fri Jun 6 17:15:39 2003 +++ parrot-leo/classes/eval.pmc Fri Jun 20 11:00:08 2003 @@ -23,17 +23,9 @@ } void* invoke (void* next) { - PMC * pad = ((struct Parrot_Sub *)PMC_data(SELF))->lex_pad; struct PackFile_ByteCode *old_cs; struct PackFile_ByteCode *eval_cs = (struct PackFile_ByteCode *) - ((struct Parrot_Sub *)PMC_data(SELF))->init; - - if (pad) { - /* put the correct pad in place - * XXX leo: do we need this? */ - stack_push(INTERP, &INTERP->ctx.pad_stack, pad, - STACK_ENTRY_PMC, STACK_CLEANUP_NULL); - } + SUPER(next); /* invoke on Sub returns the address */ /* return address that the interpreter should jump to */ stack_push(INTERP, &(INTERP->ctx.control_stack), next, @@ -49,9 +41,9 @@ PIO_eprintf(interpreter, "*** back from %s\n", eval_cs->base.name); } - if (pad) - stack_pop(interpreter, &interpreter->ctx.pad_stack, - NULL, STACK_ENTRY_PMC); + /* restore ctx */ + interpreter->ctx.pad_stack = + ((struct Parrot_Sub*) PMC_data(SELF))->ctx.pad_stack; /* if code jumped to different code segment, go out of runloop * which then actually will switch segments */ if (interpreter->resume_flag & 2) --- parrot/classes/sub.pmc Wed Jun 18 16:47:55 2003 +++ parrot-leo/classes/sub.pmc Fri Jun 20 11:47:24 2003 @@ -12,6 +12,7 @@ */ #include "parrot/parrot.h" +#include "parrot/method_util.h" pmclass Sub { @@ -20,48 +21,57 @@ } void init () { - INTVAL address = 0; /* XXX this was originally passed as a - * parameter, but that's not valid. So - * this is totally broken now. */ - PMC_data(SELF) = new_sub(INTERP, (opcode_t*)address); + PMC_data(SELF) = new_sub(INTERP, (opcode_t*)0); PObj_custom_mark_destroy_SETALL(SELF); } void mark () { - PMC * pad = ((struct Parrot_Sub *)PMC_data(SELF))->lex_pad; - if (pad) { - pobject_lives(INTERP, (PObj *)pad); - } + struct Parrot_Sub * sub = (struct Parrot_Sub *)PMC_data(SELF); + mark_stack(INTERP, sub->ctx.pad_stack); } void destroy () { - mem_sys_free(PMC_data(SELF)); + struct Parrot_Sub * sub = (struct Parrot_Sub *)PMC_data(SELF); + stack_destroy(sub->ctx.pad_stack); + mem_sys_free(sub); } void set_integer (PMC * value) { - ((struct Parrot_Sub*)PMC_data(SELF))->init = (opcode_t*)VTABLE_get_integer(INTERP, value); + ((struct Parrot_Sub*)PMC_data(SELF))->address = + (opcode_t*)VTABLE_get_integer(INTERP, value); } void set_integer_native (INTVAL value) { - ((struct Parrot_Sub*)PMC_data(SELF))->init = (opcode_t*)value; + ((struct Parrot_Sub*)PMC_data(SELF))->address = (opcode_t*)value; } - void* invoke (void* next) { - PMC * pad = ((struct Parrot_Sub *)PMC_data(SELF))->lex_pad; - - if (pad) { - /* put the correct pad in place */ - stack_push(INTERP, &INTERP->ctx.pad_stack, pad, - STACK_ENTRY_PMC, STACK_CLEANUP_NULL); + INTVAL defined () { + return ((struct Parrot_Sub*)PMC_data(SELF))->address != NULL; } - return ((struct Parrot_Sub*)PMC_data(SELF))->init; + void* invoke (void* next) { + struct Parrot_Sub * sub = (struct Parrot_Sub *)PMC_data(SELF); + INTERP->ctx.pad_stack = sub->ctx.pad_stack; + + return sub->address; } void clone (PMC *ret) { + struct Parrot_Sub * sub; PObj_custom_mark_destroy_SETALL(ret); - PMC_data(ret) = mem_sys_allocate(sizeof(struct Parrot_Sub)); - memcpy(PMC_data(ret), PMC_data(SELF), sizeof(struct Parrot_Sub)); + sub = PMC_data(ret) = mem_sys_allocate(sizeof(struct Parrot_Sub)); + memcpy(sub, PMC_data(SELF), sizeof(struct Parrot_Sub)); + stack_mark_cow(sub->ctx.pad_stack); + } + + void set_same (PMC* value) { + PMC_data(SELF) = PMC_data(value); + } + + INTVAL is_equal (PMC* value) { + return (SELF->vtable == value->vtable + && memcmp(PMC_data(value), PMC_data(SELF), + sizeof(struct Parrot_Sub)) == 0); } } --- parrot/include/parrot/stacks.h Fri Jun 13 23:15:48 2003 +++ parrot-leo/include/parrot/stacks.h Fri Jun 20 11:34:51 2003 @@ -48,6 +48,7 @@ #define STACK_CLEANUP_NULL ((Stack_cleanup_method)NULLfunc) Stack_Chunk_t * new_stack(Interp *interpreter); +void stack_destroy(Stack_Chunk_t * top); Stack_Chunk_t * stack_copy(Interp *interpreter, Stack_Chunk_t *old_stack); --- parrot/include/parrot/sub.h Wed Jun 18 16:47:55 2003 +++ parrot-leo/include/parrot/sub.h Fri Jun 20 10:19:40 2003 @@ -22,22 +22,24 @@ List * values; /* lexicals go here */ List * names; /* names of lexicals go here */ } * parrot_lexicals_t; - +/* + * we currently use the same structure for all 3 sub types + * so tath we can unify the Sub classes + * if one structure needs more data, pleas append them at the end + */ typedef struct Parrot_Sub { - INTVAL flags; - PMC *lex_pad; - opcode_t *init; + struct Parrot_Context ctx; + opcode_t *address; } * parrot_sub_t; typedef struct Parrot_Coroutine { - INTVAL flags; struct Parrot_Context ctx; - opcode_t *resume; + opcode_t *address; } * parrot_coroutine_t; typedef struct Parrot_Continuation { struct Parrot_Context ctx; - opcode_t *continuation; + opcode_t *address; } * parrot_continuation_t; struct Parrot_Sub * new_sub(struct Parrot_Interp * interp, @@ -52,9 +54,8 @@ PMC * new_continuation_pmc(struct Parrot_Interp * interp, opcode_t * address); -void save_context(struct Parrot_Interp * interp, - struct Parrot_Context * ctx); - +void save_context(struct Parrot_Interp * interp, struct Parrot_Context * ctx); +void swap_context(struct Parrot_Interp * interp, struct Parrot_Context * ctx); void restore_context(struct Parrot_Interp * interp, struct Parrot_Context * ctx); --- parrot/interpreter.c Thu Jun 19 01:44:11 2003 +++ parrot-leo/interpreter.c Fri Jun 20 11:36:18 2003 @@ -669,23 +669,9 @@ } } - /* XXX move this to stacks.c */ - { - Stack_Chunk_t *chunks[3]; - chunks[0] = interpreter->ctx.pad_stack; - chunks[1] = interpreter->ctx.user_stack; - chunks[2] = interpreter->ctx.control_stack; - for (i = 0; i< 3; i++) { - Stack_Chunk_t *top = chunks[i]; - while (top->next) - top = top->next; - while(top) { - Stack_Chunk_t *next = top->prev; - mem_sys_free(top); - top = next; - } - } - } + stack_destroy(interpreter->ctx.pad_stack); + stack_destroy(interpreter->ctx.user_stack); + stack_destroy(interpreter->ctx.control_stack); /* intstack */ intstack_free(interpreter, interpreter->ctx.intstack); --- parrot/stacks.c Fri Jun 13 23:15:48 2003 +++ parrot-leo/stacks.c Fri Jun 20 11:34:58 2003 @@ -47,6 +47,18 @@ } void +stack_destroy(Stack_Chunk_t * top) +{ + while (top->next) + top = top->next; + while(top) { + Stack_Chunk_t *next = top->prev; + mem_sys_free(top); + top = next; + } +} + +void stack_mark_cow(Stack_Chunk_t *stack) { Stack_Chunk_t *chunk = stack; --- parrot/sub.c Wed Jun 18 16:47:54 2003 +++ parrot-leo/sub.c Fri Jun 20 11:21:25 2003 @@ -24,6 +24,29 @@ } void +swap_context(struct Parrot_Interp *interp, struct Parrot_Context *ctx) +{ + struct Stack_Chunk * tmp_stack = NULL; + /* + * Swap control, user and pad stacks. Data in other parts of the + * context are not preserved between calls to the coroutine. + */ + + tmp_stack = interp->ctx.user_stack; + interp->ctx.user_stack = ctx->user_stack; + ctx->user_stack = tmp_stack; + + tmp_stack = interp->ctx.control_stack; + interp->ctx.control_stack = ctx->control_stack; + ctx->control_stack = tmp_stack; + + tmp_stack = interp->ctx.pad_stack; + interp->ctx.pad_stack = ctx->pad_stack; + ctx->pad_stack = tmp_stack; + +} + +void restore_context(struct Parrot_Interp *interp, struct Parrot_Context *ctx) { memcpy(&interp->ctx, ctx, sizeof(*ctx)); @@ -34,8 +57,14 @@ { /* Using system memory until I figure out GC issues */ struct Parrot_Sub *newsub = mem_sys_allocate(sizeof(struct Parrot_Sub)); - newsub->init = address; - newsub->lex_pad = scratchpad_get_current(interp); + PMC * pad = scratchpad_get_current(interp); + newsub->address = address; + newsub->ctx.pad_stack = new_stack(interp); + if (pad) { + /* put the correct pad in place */ + stack_push(interp, &newsub->ctx.pad_stack, pad, + STACK_ENTRY_PMC, STACK_CLEANUP_NULL); + } return newsub; } @@ -46,7 +75,7 @@ PMC * pad = NULL; struct Parrot_Coroutine *newco = mem_sys_allocate(sizeof(struct Parrot_Coroutine)); - newco->resume = NULL; + newco->address = NULL; newco->ctx.user_stack = new_stack(interp); newco->ctx.control_stack = new_stack(interp); newco->ctx.pad_stack = new_stack(interp); @@ -65,7 +94,7 @@ { struct Parrot_Continuation *cc = mem_sys_allocate(sizeof(struct Parrot_Continuation)); - cc->continuation = address; + cc->address = address; save_context(interp, &cc->ctx); return cc; } @@ -75,7 +104,7 @@ new_continuation_pmc(struct Parrot_Interp * interp, opcode_t * address) { PMC* continuation = pmc_new(interp, enum_class_Continuation); - ((struct Parrot_Continuation*)PMC_data(continuation))->continuation = address; + ((struct Parrot_Continuation*)PMC_data(continuation))->address = address; return continuation; }