Author: leo
Date: Wed Nov 9 06:08:36 2005
New Revision: 9853
Modified:
trunk/classes/sub.pmc
trunk/include/parrot/inter_call.h
trunk/include/parrot/interpreter.h
trunk/include/parrot/register.h
trunk/src/inter_call.c
trunk/src/register.c
trunk/t/pmc/object-meths.t
Log:
Variable-sized reg frames again - redo tailcall argument passing
* reallocating the whole context for tailcalls is wrong, as
continuations can point to the context structure
* follow Plan C: allocate a new register area only and use normal
argument passsing code (almost)
+ no problem with overlapping memory area
- additional allocation
* can be heavily optimized for recursive tailcalls
This should make tcl/t/cmd_array.t more happy, albeit there is still some
bogus mark_context() reported by valgrind.
Modified: trunk/classes/sub.pmc
==============================================================================
--- trunk/classes/sub.pmc (original)
+++ trunk/classes/sub.pmc Wed Nov 9 06:08:36 2005
@@ -161,7 +161,7 @@ Sets the name of the subroutine.
=item C<void set_pointer(void *value)>
-Sets the pointer to the actual subroutine.
+Sets the pointer to the actual subroutine.
*** Don't use that - use .Sub constants instead ***
Modified: trunk/include/parrot/inter_call.h
==============================================================================
--- trunk/include/parrot/inter_call.h (original)
+++ trunk/include/parrot/inter_call.h Wed Nov 9 06:08:36 2005
@@ -17,8 +17,7 @@
enum call_state_mode {
CALL_STATE_SIG = 0x001, /* runops, nci */
CALL_STATE_OP = 0x002, /* get_, set_ ops */
- CALL_STATE_TC = 0x004, /* taicall, fetch from tc_args */
- CALL_STATE_MASK = 0x007,
+ CALL_STATE_MASK = 0x003,
CALL_STATE_FLATTEN = 0x010,
@@ -36,7 +35,6 @@ struct call_state_1 {
opcode_t *pc;
PMC *signature;
} op;
- HashEntry *tc_args; /* tailcall arg store - a typed union */
} u;
struct PackFile_Constant **constants;
parrot_context_t *ctx;
Modified: trunk/include/parrot/interpreter.h
==============================================================================
--- trunk/include/parrot/interpreter.h (original)
+++ trunk/include/parrot/interpreter.h Wed Nov 9 06:08:36 2005
@@ -172,6 +172,7 @@ typedef struct Parrot_Context {
Regs_ni bp; /* pointers to FLOATVAL & INTVAL */
Regs_ps bp_ps; /* pointers to PMC & STR */
/* end common header */
+ void *malloced_mem; /* used during resize */
INTVAL n_regs_used[4]; /* INSP in PBC */
size_t regs_mem_size; /* memory occupied by registers */
INTVAL ref_count; /* how often refered to */
Modified: trunk/include/parrot/register.h
==============================================================================
--- trunk/include/parrot/register.h (original)
+++ trunk/include/parrot/register.h Wed Nov 9 06:08:36 2005
@@ -75,7 +75,7 @@ void Parrot_clear_n(Interp *);
struct Parrot_Context; /* parrot/interpreter.h */
void Parrot_alloc_context(Interp *, INTVAL *n_regs_used);
-void Parrot_realloc_context(Interp *, INTVAL *n_regs_used);
+void * Parrot_realloc_context(Interp *, INTVAL *n_regs_used);
void Parrot_free_context(Interp *, struct Parrot_Context *, int re_use);
void Parrot_set_context_threshold(Interp *, struct Parrot_Context *);
void parrot_gc_context(Interp *);
Modified: trunk/src/inter_call.c
==============================================================================
--- trunk/src/inter_call.c (original)
+++ trunk/src/inter_call.c Wed Nov 9 06:08:36 2005
@@ -315,9 +315,6 @@ next_arg(Interp *interpreter, struct cal
st->sig = PARROT_ARG_PMC; break;
}
break;
- case CALL_STATE_TC:
- st->sig = st->u.tc_args[st->i].type;
- break;
}
return 1;
}
@@ -350,14 +347,6 @@ fetch_arg(Interp *interpreter, struct ca
return fetch_arg_pmc_sig(interpreter, st);
}
break;
- case CALL_STATE_TC:
- {
- HashEntry *e = st->src.u.tc_args + st->src.i;
- st->val = e->val;
- st->src.sig = e->type;
- st->src.mode |= CALL_STATE_NEXT_ARG;
- }
- break;
}
return 0;
}
@@ -682,59 +671,34 @@ parrot_pass_args_tail_call(Interp* inter
{
struct call_state st;
int todo, i, n;
+ struct Interp_Context src_ctx;
+ void *old_mem;
if (*pc != PARROT_OP_get_params_pc)
return pc;
- todo = Parrot_init_arg_op(interpreter, interpreter->code,
+ Parrot_init_arg_op(interpreter, interpreter->code,
CONTEXT(interpreter->ctx),
interpreter->current_args, &st.src);
- if (!todo)
- return pc;
- todo = Parrot_init_arg_op(interpreter, dest_sub->seg,
- CONTEXT(interpreter->ctx),
- pc, &st.dest);
- if (!todo)
- return pc;
- /* allocate helper storage
- * due to flatten, we need max(src, dest)
+ /* remember old register base ptrs */
+ memcpy(&src_ctx, &interpreter->ctx, sizeof(struct Interp_Context));
+ /*
+ * TODO optimize recursive tail calls
*/
- n = st.src.n;
- if (st.dest.n > n)
- n = st.dest.n;
- st.dest.u.tc_args = mem_sys_allocate(n * sizeof(HashEntry));
- /* fetch args */
-
- st.dest.mode = CALL_STATE_TC;
- for (i = 0; ; ++i) {
- if (!Parrot_fetch_arg(interpreter, &st))
- break;
- assert(i < n);
- st.dest.u.tc_args[i].val = st.val;
- st.dest.u.tc_args[i].type = st.src.sig;
- }
- /* now set new register structure, realloc if needed */
- Parrot_realloc_context(interpreter, dest_sub->n_regs_used);
- /* ctx might have moved */
- st.dest.ctx = CONTEXT(interpreter->ctx);
- /* and store args */
-
- st.src.i = 0;
- st.src.n = i;
- st.opt_so_far = 0;
- st.src.mode = CALL_STATE_TC;
- st.src.u.tc_args = st.dest.u.tc_args;
- /* reinit dest */
- Parrot_init_arg_op(interpreter, dest_sub->seg,
+ old_mem = Parrot_realloc_context(interpreter, dest_sub->n_regs_used);
+ todo = Parrot_init_arg_op(interpreter, dest_sub->seg,
CONTEXT(interpreter->ctx),
pc, &st.dest);
- for (;;) {
+ /* reset st.src.ctx pointing to old regs */
+ st.src.ctx = (parrot_context_t *) &src_ctx;
+ st.opt_so_far = 0; /* XXX */
+ while (todo) {
Parrot_fetch_arg(interpreter, &st);
Parrot_convert_arg(interpreter, &st);
- if (!Parrot_store_arg(interpreter, &st))
- break;
+ todo = Parrot_store_arg(interpreter, &st);
}
- /* free helper */
- mem_sys_free(st.src.u.tc_args);
+ if (old_mem)
+ mem_sys_free(old_mem);
+
/* done. return position past get_params opcode */
return pc + st.dest.n + 2;
}
Modified: trunk/src/register.c
==============================================================================
--- trunk/src/register.c (original)
+++ trunk/src/register.c Wed Nov 9 06:08:36 2005
@@ -214,14 +214,10 @@ parrot_gc_context(Interp *interpreter)
}
static void
-init_context(Interp *interpreter, parrot_context_t *ctx)
+clear_regs(Interp *interpreter, parrot_context_t *ctx)
{
int i;
- ctx->ref_count = 0;
- ctx->current_results = NULL;
- ctx->current_args = NULL;
-
/* NULL out registers
*
* if the architecture has 0x := NULL and 0.0 we could memset too
@@ -259,6 +255,16 @@ init_context(Interp *interpreter, parrot
#endif
}
+static void
+init_context(Interp *interpreter, parrot_context_t *ctx)
+{
+ ctx->ref_count = 0;
+ ctx->current_results = NULL;
+ ctx->current_args = NULL;
+ ctx->malloced_mem = NULL;
+ clear_regs(interpreter, ctx);
+}
+
#if CHUNKED_CTX_MEM
void
Parrot_alloc_context(Interp *interpreter, INTVAL *n_regs_used)
@@ -422,13 +428,13 @@ Parrot_alloc_context(Interp *interpreter
init_context(interpreter, ctx);
}
-void
+void *
Parrot_realloc_context(Interp *interpreter, INTVAL *n_regs_used)
{
struct Parrot_Context *ctx;
size_t to_alloc, reg_alloc, size_n, size_nip;
- void *p;
- int i, slot;
+ void *p, *old_mem;
+ int i;
size_n = sizeof(FLOATVAL) * n_regs_used[REGNO_NUM];
size_nip = size_n +
@@ -437,32 +443,30 @@ Parrot_realloc_context(Interp *interpret
reg_alloc = size_nip +
sizeof(STRING*) * n_regs_used[REGNO_STR];
- slot = (reg_alloc + 7) >> 3;
- reg_alloc = slot << 3;
ctx = CONTEXT(interpreter->ctx);
- /* need a bigger one? */
- if (reg_alloc > ctx->regs_mem_size) {
- CONTEXT(interpreter->ctx) =
- ctx = mem_sys_realloc(ctx, reg_alloc + ALIGNED_CTX_SIZE);
- ctx->regs_mem_size = reg_alloc;
- /* if we realloced beyond the free_list, resize that too */
- if (slot >= interpreter->ctx_mem.n_free_slots) {
- int n = slot + 1;
- interpreter->ctx_mem.free_list = mem_sys_realloc(
- interpreter->ctx_mem.free_list, n * sizeof(void*));
- for (i = interpreter->ctx_mem.n_free_slots; i < n; ++i)
- interpreter->ctx_mem.free_list[i] = NULL;
- interpreter->ctx_mem.n_free_slots = n;
- }
- }
+ /* Need a distinct reg memory area, but we can't reallocate the
+ * context as a whole, because continuations might point to it.
+ * Therefore we just allocate the register memory and remember
+ * this in the malloced_mem pointer
+ *
+ * TODO investigate if we should preserve the original slot
+ * so that we can reuse the context memory in _free
+ *
+ * If this is a recursive tailcall, we need the old memory
+ * which is freed after argument passing. See also
+ * src/inter_call.c
+ */
+ old_mem = ctx->malloced_mem;
+ ctx->malloced_mem = p = mem_sys_allocate(reg_alloc);
+ ctx->regs_mem_size = reg_alloc;
for (i = 0; i < 4; ++i)
ctx->n_regs_used[i] = n_regs_used[i];
- p = (void *) ((char *)ctx + ALIGNED_CTX_SIZE);
/* ctx.bp points to I0, which has Nx at left */
interpreter->ctx.bp.regs_i = (INTVAL*)((char*)p + size_n);
/* this points to S0 */
interpreter->ctx.bp_ps.regs_s = (STRING**)((char*)p + size_nip);
- init_context(interpreter, ctx);
+ clear_regs(interpreter, ctx);
+ return old_mem;
}
void
@@ -481,12 +485,20 @@ Parrot_free_context(Interp *interpreter,
*
*/
if (re_use || --ctxp->ref_count == 0) {
- ptr = ctxp;
- slot = ctxp->regs_mem_size >> 3;
+ if (ctxp->malloced_mem) {
+ /* we don't have the orig size anymore, just free all
+ */
+ mem_sys_free(ctxp->malloced_mem);
+ mem_sys_free(ctxp);
+ }
+ else {
+ ptr = ctxp;
+ slot = ctxp->regs_mem_size >> 3;
- assert(slot < interpreter->ctx_mem.n_free_slots);
- *(void **)ptr = interpreter->ctx_mem.free_list[slot];
- interpreter->ctx_mem.free_list[slot] = ptr;
+ assert(slot < interpreter->ctx_mem.n_free_slots);
+ *(void **)ptr = interpreter->ctx_mem.free_list[slot];
+ interpreter->ctx_mem.free_list[slot] = ptr;
+ }
#if CTX_LEAK_DEBUG
fprintf(stderr, "free %p\n", ctxp);
#endif
Modified: trunk/t/pmc/object-meths.t
==============================================================================
--- trunk/t/pmc/object-meths.t (original)
+++ trunk/t/pmc/object-meths.t Wed Nov 9 06:08:36 2005
@@ -912,7 +912,7 @@ pir_output_is(<<'CODE', <<'OUTPUT', "tai
n = getattribute self, "Foo\0n"
dec n
unless n goto done
- tailcallmethod self, "go"
+ .return self."go"()
done:
.end
CODE