Author: leo
Date: Fri Sep 23 02:44:07 2005
New Revision: 9233

Modified:
   branches/leo-ctx5/languages/tcl/lib/expression.pir
   branches/leo-ctx5/src/inter_call.c
   branches/leo-ctx5/t/op/calling.t
Log:
Fix tailcalls to NCI methods

* if the tailcalled method is a NCI method pass return results
  immediately to the caller
* add comments to NCI call and return setup
* enable tailcall inside TCL's expression parser
* unTODO test

All tcl tests are still passing with the tailcallmethod enabled


Modified: branches/leo-ctx5/languages/tcl/lib/expression.pir
==============================================================================
--- branches/leo-ctx5/languages/tcl/lib/expression.pir  (original)
+++ branches/leo-ctx5/languages/tcl/lib/expression.pir  Fri Sep 23 02:44:07 2005
@@ -19,7 +19,7 @@ invoke the items on the stack.
 
 .sub __expression_parse
   .param string expr
- 
+
   .local pmc retval
 
   .local pmc undef
@@ -45,7 +45,7 @@ operand:
 
 no_operand:
   .throw ("no operand!")
- 
+
 operator:
   (chunk, pos) = get_operator(expr, pos)
   if_null chunk, chunks_done
@@ -57,7 +57,7 @@ operator:
 
 chunks_done:
 # convert the chunks into a stack.
- 
+
   # to do this, we scan for our Operators in precedence order.
   # as we find each one, put it on the program_stack with the appropriate
   # args. Leave a "NOOP" placeholder when pulling things. If our target
@@ -66,19 +66,19 @@ chunks_done:
 
   # XXX cheat for now , assume no precedence. means we can just
   # walk through, grabbing ops. (hope nothing is orphaned?)
- 
-  .local int stack_index 
+
+  .local int stack_index
   .local int input_len
 
   stack_index = 0
 
  # we're looping over this once - to handle precedence, I suggest
  # looping multiple times, leaving the NOOPS when we remove something
- # to faciliate processing on further runs. If we try to pull a 
+ # to faciliate processing on further runs. If we try to pull a
  # left or right arg and see a NO-OP, we know it's safe to skip because
  # walking the stack will convert it to a number by the time we get to it.
 
-  .local pmc our_op 
+  .local pmc our_op
   input_len  = chunks
   if input_len == 0 goto die_horribly
 
@@ -103,10 +103,10 @@ converter_loop:
   if $I2 == OP   goto is_opfunc
 
   # Should never be reached (XXX then shouldn't we die horribly?)
-  goto converter_next 
+  goto converter_next
 
 is_opfunc:
-  $I3 = our_op[2] 
+  $I3 = our_op[2]
   if $I3 != precedence_level goto converter_next
 
 right_arg:
@@ -117,7 +117,7 @@ right_arg:
   chunks[$I2] = undef
   inc $I4
   program_stack = unshift retval
-  
+
   # If we're a function, (XXX) assume a single arg (which
   # we've now pulled - so, go to the, skip the left arg.
   if precedence_level == -1 goto shift_op
@@ -167,13 +167,13 @@ converter_done:
 eat_space:
   inc pos
   if pos >= len goto fail
-  
+
   $I0 = is_whitespace expr, pos
   if $I0 == 1 goto eat_space
-  
+
   $I0 = is_digit expr, pos
   if $I0 == 1 goto number
-  
+
   $I0 = ord expr, pos
   if $I0 == 91 goto subcommand  # [
   if $I0 == 40 goto subexpr     # (
@@ -184,7 +184,7 @@ eat_space:
   if $I0 == 43 goto unary       # +
   if $I0 == 47 goto unary       # ~
   if $I0 == 33 goto unary       # !
-  
+
   $I0 = is_wordchar expr, pos
   if $I0 == 1 goto function
 
@@ -194,7 +194,7 @@ fail:
 
 subexpr:
   .return get_subexpr(expr, pos)
- 
+
 variable:
   .return get_variable(expr, pos)
 
@@ -205,7 +205,7 @@ function:
   .return get_function(expr, pos)
 
 number:
-  .return get_number(expr, pos) 
+  .return get_number(expr, pos)
 
 quote:
   .return get_quote(expr, pos)
@@ -218,16 +218,16 @@ unary:
 .sub get_operator
   .param string expr
   .param int pos
-  
+
   .local pmc chunk
   null chunk
- 
+
   .local pmc ops, precedences
   # Global list of available ops.
   ops = find_global "_Tcl", "operators"
   # Global list of operator precedence
   precedences = find_global "_Tcl", "precedence"
-  
+
   .local int len
   len = length expr
   dec pos
@@ -274,7 +274,7 @@ op_done:
 
   pos += op_len
 
-done:  
+done:
   .return(chunk, pos)
 .end
 
@@ -289,7 +289,7 @@ stack_evaluator:
  .local int size
  size = program_stack
  if size == 0 goto stack_done
- 
+
  .local int type
  .local pmc chunk
  chunk = pop program_stack
@@ -344,89 +344,89 @@ op_mul:
   .__pop_value_from_expr_stack(result_stack,l_arg)
   .__pop_value_from_expr_stack(result_stack,r_arg)
   op_result = mul l_arg, r_arg
-  goto done_op 
+  goto done_op
 op_div:
   .__pop_value_from_expr_stack(result_stack,l_arg)
   .__pop_value_from_expr_stack(result_stack,r_arg)
   op_result = div l_arg, r_arg
-  goto done_op 
+  goto done_op
 op_mod:
   .__pop_value_from_expr_stack(result_stack,l_arg)
   .__pop_value_from_expr_stack(result_stack,r_arg)
   op_result = mod l_arg, r_arg
-  goto done_op 
+  goto done_op
 op_plus:
   .__pop_value_from_expr_stack(result_stack,l_arg)
   .__pop_value_from_expr_stack(result_stack,r_arg)
   op_result = l_arg + r_arg
-  goto done_op 
+  goto done_op
 op_minus:
   .__pop_value_from_expr_stack(result_stack,l_arg)
   .__pop_value_from_expr_stack(result_stack,r_arg)
   op_result = l_arg - r_arg
-  goto done_op 
+  goto done_op
 op_shl:
   .__pop_value_from_expr_stack(result_stack,l_arg)
   .__pop_value_from_expr_stack(result_stack,r_arg)
   op_result = shl l_arg, r_arg
-  goto done_op 
+  goto done_op
 op_shr:
   .__pop_value_from_expr_stack(result_stack,l_arg)
   .__pop_value_from_expr_stack(result_stack,r_arg)
   op_result = shr l_arg, r_arg
-  goto done_op 
+  goto done_op
 op_lt:
   .__pop_value_from_expr_stack(result_stack,l_arg)
   .__pop_value_from_expr_stack(result_stack,r_arg)
   op_result = 1
   if l_arg < r_arg goto done_op
   op_result = 0
-  goto done_op 
+  goto done_op
 op_gt:
   .__pop_value_from_expr_stack(result_stack,l_arg)
   .__pop_value_from_expr_stack(result_stack,r_arg)
   op_result = 1
   if l_arg > r_arg goto done_op
   op_result = 0
-  goto done_op 
+  goto done_op
 op_lte:
   .__pop_value_from_expr_stack(result_stack,l_arg)
   .__pop_value_from_expr_stack(result_stack,r_arg)
   op_result = 1
   if l_arg <= r_arg goto done_op
   op_result = 0
-  goto done_op 
+  goto done_op
 op_gte:
   .__pop_value_from_expr_stack(result_stack,l_arg)
   .__pop_value_from_expr_stack(result_stack,r_arg)
   op_result = 1
   if l_arg >= r_arg goto done_op
   op_result = 0
-  goto done_op 
+  goto done_op
 op_equal:
   .__pop_value_from_expr_stack(result_stack,l_arg)
   .__pop_value_from_expr_stack(result_stack,r_arg)
   op_result = 1
   if l_arg == r_arg goto done_op
   op_result = 0
-  goto done_op 
+  goto done_op
 op_unequal:
   .__pop_value_from_expr_stack(result_stack,l_arg)
   .__pop_value_from_expr_stack(result_stack,r_arg)
   op_result = 1
   if l_arg != r_arg goto done_op
   op_result = 0
-  goto done_op 
+  goto done_op
 op_bitand:
   .__pop_value_from_expr_stack(result_stack,l_arg)
   .__pop_value_from_expr_stack(result_stack,r_arg)
   op_result = band l_arg, r_arg
-  goto done_op 
+  goto done_op
 op_bitxor:
   .__pop_value_from_expr_stack(result_stack,l_arg)
   .__pop_value_from_expr_stack(result_stack,r_arg)
   op_result = bxor l_arg, r_arg
-  goto done_op 
+  goto done_op
 op_bitor:
   .__pop_value_from_expr_stack(result_stack,l_arg)
   .__pop_value_from_expr_stack(result_stack,r_arg)
@@ -496,18 +496,16 @@ evaluation_done:
   .return (retval)
 
 done_interp:
-  # XXX Oddly, we can't combine this into a tailcall.
-  retval = retval."interpret"()
-  .return (retval)
+  .return retval."interpret"()
 
 .end
 
 .sub get_subexpr
   .param string expr
   .param int pos
-  
+
   .local pmc chunk, retval
-  
+
   .local int len, depth, start
   len   = length expr
   depth = 1
@@ -535,11 +533,11 @@ paren_done:
   $I0 = pos - start
   inc pos
   $S1 = substr expr, start, $I0
-  
+
   # XXX this is now officially braindead. Fissit.
   retval = __expression_parse($S1)
   retval = __expression_interpret(retval)
-  
+
   .return(retval, pos)
 
 die_horribly:
@@ -574,11 +572,11 @@ integer:
   if char > 57 goto integer_done # > "9"
   if char < 48 goto integer_done # < "0"
   inc pos
-  goto integer 
+  goto integer
 integer_done:
   if char == 46 goto floating    # "."
   if pos == 0 goto done # failure
-  
+
   $S0 = substr expr, start, pos
   $I0 = $S0
   value = new TclInt
@@ -595,7 +593,7 @@ float_loop:
   inc pos
   goto float_loop
 float_done:
-  
+
   $S0 = substr expr, start, pos
   # XXX Can't we just assign this string directly to the the TclFloat - WJC
   $N0 = $S0
@@ -614,10 +612,10 @@ done:
   .local int len, start
   len   = length expr
   start = pos
-   
+
   .local pmc func,operand
 
-  # functions *must* have ()s 
+  # functions *must* have ()s
   pos = index expr, "(", start
   if pos == -1 goto fail
 
@@ -648,10 +646,10 @@ loop_done:
   $I0 = paren_pos - start
   $S0 = substr expr, start, $I0
   $P1 = find_global "_Tcl", "functions"
-  
+
   func = $P1[$S0]
   if_null func, unknown_func
-  
+
   $I0 = find_type "TclFunc"
   func = new $I0
   $P0 = new String
@@ -663,12 +661,12 @@ loop_done:
   # XXX - If there are commas in the op, then split the operand
   #   and parse each one as an operand. needed for:
   #   atan2,pow,fmod,hypot
-  
+
   inc paren_pos
   $I0 = pos - paren_pos
   $S1 = substr expr, paren_pos, $I0
 
-  operand = __expression_parse($S1) 
+  operand = __expression_parse($S1)
   setattribute func, "TclFunc\x00argument", operand
 
 done:
@@ -694,22 +692,22 @@ unknown_func:
 .sub get_unary
   .param string expr
   .param int pos
-  
+
   .local pmc name, operand
-  
+
   $S0 = substr expr, pos, 1
   name = new String
   name = $S0
-  
+
   inc pos
   (operand, pos) = get_operand(expr, pos)
-  
+
   .local pmc unary
   $I0   = find_type "TclUnaryOp"
   unary = new $I0
   setattribute unary, "TclUnaryOp\x00name", name
   setattribute unary, "TclUnaryOp\x00operand", operand
-  
+
   .return(unary, pos)
 .end
 

Modified: branches/leo-ctx5/src/inter_call.c
==============================================================================
--- branches/leo-ctx5/src/inter_call.c  (original)
+++ branches/leo-ctx5/src/inter_call.c  Fri Sep 23 02:44:07 2005
@@ -26,34 +26,23 @@ subroutines.
 #include "inter_call.str"
 
 
-/*
-
-=item C<int Parrot_init_arg_sig(Interp *, struct PackFile_ByteCode *seg,
-        struct parrot_regs_t *regs,
-        const char *sig, void *ap, struct call_state_1 *st)>
+static int next_arg(Interp *, struct call_state_1 *st);
 
-Initialize argument transfer with given code segment (holding the
-const_table), registers, function signature, and arguments.
+/*
 
-=item C<int Parrot_init_arg_op(Interp *, struct PackFile_ByteCode *seg,
-        struct parrot_regs_t *regs,
-        opcode_t *pc, struct call_state_1 *st)>
+=item C<int Parrot_init_arg_nci(Interp *, struct call_state *st, const char 
*sig)>
 
-Initialize argument transfer with given code segment (holding the
-const_table), registers, and opcode location of a get_ or set_ argument
-opcode.
+Initialize the argument passing state C<call_state> for the given NCI 
signature.
 
-Both functions can be used for either source or destination, by passing
-either C<&st.src> or C<&st.dest> of a C<call_state> structure.
+=item C<int Parrot_init_ret_nci(Interp *, struct call_state *st, const char 
*sig)>
 
-These functions return 0, if no arguments are present, or 1 on success.
+Initialize the return value passing state C<call_state> for the given
+NCI signature.
 
 =cut
 
 */
 
-static int next_arg(Interp *, struct call_state_1 *st);
-
 int
 Parrot_init_arg_nci(Interp *interpreter, struct call_state *st,
         const char *sig)
@@ -69,15 +58,59 @@ int
 Parrot_init_ret_nci(Interp *interpreter, struct call_state *st,
         const char *sig)
 {
+    PMC *current_cont;
+    parrot_context_t ctx;
+    struct PackFile_ByteCode *seg;
+    /*
+     * if this NCI call was a taicall, return results to caller's get_results
+     * this also means that we pass the caller's register base pointer
+     * and code segment
+     */
+    current_cont = CONTEXT(interpreter->ctx)->current_cont;
+    if ((PObj_get_FLAGS(current_cont) & SUB_FLAG_TAILCALL)) {
+        ctx = PMC_cont(current_cont)->to_ctx;
+        seg = PMC_cont(current_cont)->seg;
+    }
+    else {
+        ctx = interpreter->ctx;
+        seg = interpreter->code;
+    }
     /* TODO simplify all */
     Parrot_init_arg_sig(interpreter, interpreter->code, interpreter->ctx.bp,
             sig, NULL, &st->src);
-    Parrot_init_arg_op(interpreter, interpreter->code, interpreter->ctx.bp,
-            CONTEXT(interpreter->ctx)->current_results, &st->dest);
+    Parrot_init_arg_op(interpreter, seg, ctx.bp,
+            CONTEXT(ctx)->current_results, &st->dest);
     next_arg(interpreter, &st->src);
     next_arg(interpreter, &st->dest);
     return 1;
 }
+
+/*
+
+=item C<int Parrot_init_arg_sig(Interp *, struct PackFile_ByteCode *seg,
+        struct parrot_regs_t *regs,
+        const char *sig, void *ap, struct call_state_1 *st)>
+
+Initialize argument transfer with given code segment (holding the
+const_table), registers, function signature, and arguments.
+
+=item C<int Parrot_init_arg_op(Interp *, struct PackFile_ByteCode *seg,
+        struct parrot_regs_t *regs,
+        opcode_t *pc, struct call_state_1 *st)>
+
+Initialize argument transfer with given code segment (holding the
+const_table), registers, and opcode location of a get_ or set_ argument
+opcode.
+
+Both functions can be used for either source or destination, by passing
+either C<&st.src> or C<&st.dest> of a C<call_state> structure.
+
+These functions return 0, if no arguments are present, or 1 on success.
+
+=cut
+
+*/
+
 int
 Parrot_init_arg_op(Interp *interpreter, struct PackFile_ByteCode *seg,
         struct parrot_regs_t *regs,

Modified: branches/leo-ctx5/t/op/calling.t
==============================================================================
--- branches/leo-ctx5/t/op/calling.t    (original)
+++ branches/leo-ctx5/t/op/calling.t    Fri Sep 23 02:44:07 2005
@@ -1019,9 +1019,6 @@ ok 1
 ok 2
 OUTPUT
 
-# tailcall to NCI doesn't work
-TODO:
-{ local $TODO = "tailcall to NCI doesn't work";
 pir_output_is(<<'CODE', <<'OUTPUT', "taicall to NCI");
 .sub main @MAIN
     .local pmc s
@@ -1041,4 +1038,4 @@ CODE
 ok 1
 ok 2
 OUTPUT
-}
+

Reply via email to