# 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;
}