# New Ticket Created by Allison Randal # Please include the string: [perl #23368] # in the subject line of all future correspondence about this issue. # <URL: http://rt.perl.org/rt2/Ticket/Display.html?id=23368 >
This patch switches languages/perl6 over to using CPS. It isn't a complete and final solution, just a step in the right direction. My goal was to make the smallest number of code changes possible to get it to work. Switching to the current calling conventions fixed 4 out of 5 failing tests with calls to closures and rules (t/compiler/2.t 3-5, and t/rx/basic.t 6). The remaining test (t/compiler/1.t 15) fails because some architectures return "inf" instead of "Inf" when dividing by zero. Eventually, division by zero should probably throw an exception, so I'm ignoring this for now. Allison -- attachment 1 ------------------------------------------------------ url: http://rt.perl.org/rt2/attach/62986/46376/feb335/p6c_calling_conventions.patch
Index: languages/perl6/P6C/Builtins.pm =================================================================== RCS file: /cvs/public/parrot/languages/perl6/P6C/Builtins.pm,v retrieving revision 1.16 diff -u -r1.16 Builtins.pm --- languages/perl6/P6C/Builtins.pm 9 Sep 2002 05:11:58 -0000 1.16 +++ languages/perl6/P6C/Builtins.pm 19 Aug 2003 01:27:40 -0000 @@ -17,7 +17,8 @@ use vars '%builtin_names'; BEGIN { my @names = qw(print1 exit warn die print sleep time substr length - index map grep join reverse defined); + index map grep join reverse defined install_catch + pop_catch); @[EMAIL PROTECTED] = (1) x @names; } @@ -27,7 +28,7 @@ sub declare { my $hash = shift; - for (qw(print1 exit sleep)) { + for (qw(print1 exit sleep install_catch pop_catch)) { $hash->{$_} = new P6C::IMCC::Sub args => [['PerlUndef', 'a']], rettype => []; $P6C::Context::CONTEXT{$_} = new P6C::Context type => 'PerlUndef'; @@ -92,122 +93,123 @@ print <<'END'; -.emit - -_substr: - pushp - pushi - pushs -# get arr - restore P0 +.pcc_sub _substr non_prototyped + .param object params + $P0 = params # n paras - set I0, P0 - set S0, P0[0] - set I1, P0[1] - eq I0, 2, __substr_2 - set I2, P0[2] - gt I0, 4, __substr_die - lt I0, 2, __substr_die - length I3, S0 - set I4, I3 - ge I2, 0, __substr_34 + $I0 = params + $S0 = params[0] + $I1 = params[1] + if $I0 == 2 goto substr_2 + $I2 = params[2] + if $I0 > 4 goto substr_die + if $I0 < 2 goto substr_die + length $I3, $S0 + $I4 = $I3 + if $I2 >= 0 goto substr_34 # len negative, leave -len of string - sub I3, I3, I1 - add I3, I3, I2 - set I2, I3 -__substr_34: - set S1, "" + $I3 = $I3 - $I1 + $I3 = $I3 + $I2 + $I2 = $I3 +substr_34: + $S1 = "" # # offset >= len? - ge I1, I4, __substr_ret - eq I0, 4, __substr_4 -__substr_3: - substr S1, S0, I1, I2 -__substr_ret: - new P1, .PerlString - set P1, S1 - save P1 - pops - popi - popp - ret -__substr_4: - set S2, P0[3] - substr S1, S0, I1, I2, S2 - set P0[2], S1 - branch __substr_ret -__substr_2: - length I2, S0 - sub I2, I2, I1 - branch __substr_3 -__substr_die: - set S0, "wrong number of args for substr" - new P0, .PerlArray - set P0[0], S0 - save P0 - bsr _die - branch __substr_ret + if $I1 >= $I4 goto substr_ret + if $I0 == 4 goto substr_4 +substr_3: + substr $S1, $S0, $I1, $I2 +substr_ret: + $P1 = new PerlString + $P1 = $S1 + .pcc_begin_return + .return $P1 + .pcc_end_return +substr_4: + $S2 = params[3] + substr $S1, $S0, $I1, $I2, $S2 + params[2] = $S1 + goto substr_ret +substr_2: + length $I2, $S0 + sub $I2, $I2, $I1 + goto substr_3 +substr_die: + set $S0, "wrong number of args for substr" + $P0 = new PerlArray + $P0[0] = $S0 + find_lex $P2, "&die" + .pcc_begin non_prototyped + .arg $P0 + .pcc_call $P2 +substr_ret_label: + .pcc_end + goto substr_ret + end +.end -_length: - pushp - pushs - pushi - restore P0 - set S0, P0 - length I0, S0 - new P1, .PerlInt - set P1, I0 - save P1 - popi - pops - popp - ret +.pcc_sub _length non_prototyped + .param object s + $S0 = s + length $I0, $S0 + $P1 = new PerlInt + set $P1, $I0 + .pcc_begin_return + .return $P1 + .pcc_end_return + end +.end -_reverse: - pushp - pushi - restore P0 - set I0, P0 - dec I0 - set I1, 0 - new P1, .PerlArray -__reverse_loopstart: - set P2, P0[I0] - set P1[I1], P2 - inc I1 - dec I0 - le 0, I0, __reverse_loopstart - save P1 - popi - popp - ret +.pcc_sub _reverse non_prototyped + .param object orig_array + $I0 = orig_array + dec $I0 + $I1 = 0 + $P1 = new PerlArray +reverse_loopstart: + $P2 = orig_array[$I0] + $P1[$I1] = $P2 + inc $I1 + dec $I0 + if 0 <= $I0 goto reverse_loopstart + .pcc_begin_return + .return $P1 + .pcc_end_return + end +.end -_join: - saveall - restore P3 - set I1, P3 - gt I1, 1, __join_next +.pcc_sub _join non_prototyped + .param object params + .local int num_params + num_params = params + if num_params > 1 goto join_next # Empty args: - set S0, "" - branch __join_ret + $S0 = "" + goto join_ret # At least one arg: -__join_next: - set S1, P3[0] # separator - set S0, P3[1] # accumulated string - set I0, 2 # arg number - branch __join_test -__join_loopstart: - set S2, P3[I0] - concat S0, S1 - concat S0, S2 - inc I0 -__join_test: - ne I1, I0, __join_loopstart -__join_ret: - new P2, .PerlString - set P2, S0 - save P2 - restoreall - ret +join_next: + .local string separator + separator = params[0] # separator + $S0 = params[1] # accumulated string + .local int counter + counter = 2 # arg number + goto join_test +join_loopstart: + $S2 = params[counter] + concat $S0, separator + concat $S0, $S2 + inc counter +join_test: + if num_params != counter goto join_loopstart +join_ret: + $P2 = new PerlString + $P2 = $S0 + .pcc_begin_return + .return $P2 + .pcc_end_return + end +.end + +.emit _grep: pushp @@ -346,146 +348,153 @@ popp ret -_index: - pushp - pushs - pushi - restore P0 - set I2, P0 - lt I2, 2, __index_numarg_error - set S0, P0[0] - set S1, P0[1] - set I0, 0 - new P1, .PerlInt - set P1, I0 - lt I3, 3, __index_2_arg - index I0, S0, S1 - set P1, I0 - branch __index_end -__index_2_arg: - set I1, P0[2] - index I0, S0, S1, I1 - set P1, I0 -__index_end: - save P1 - popi - pops - popp - ret -__index_numarg_error: - set S0, "wrong number of args for index" - new P0, .PerlArray - set P0[0], S0 - save P0 - bsr _die - branch __index_end +.eom -_time: - pushn - pushp - new P1, .PerlNum - time N1 - set P1, N1 - save P1 - popp - popn - ret +.pcc_sub _index non_prototyped + .param object params + $I2 = params + if $I2 < 2 goto index_numarg_error + $S0 = params[0] + $S1 = params[1] + $I0 = 0 + $P1 = new PerlInt + $P1 = $I0 + if $I3 < 3 goto index_2_arg + index $I0, $S0, $S1 + $P1 = $I0 + goto index_end +index_2_arg: + $I1 = params[2] + index $I0, $S0, $S1, $I1 + $P1 = $I0 +index_end: + .pcc_begin_return + .return $P1 + .pcc_end_return + end +index_numarg_error: + $S0 = "wrong number of args for index" + $P0 = new PerlArray + $P0[0] = $S0 + find_lex $P2, "&die" + .pcc_begin non_prototyped + .arg $P0 + .pcc_call $P2 +pcc_ret_label: + .pcc_end + goto index_end +.end + +.pcc_sub _time non_prototyped + $P1 = new PerlNum + time $N1 + set $P1, $N1 + .pcc_begin_return + .return $P1 + .pcc_end_return + end +.end -_sleep: - pushp - pushi - restore P0 - set I0, P0 - sleep I0 - popi - popp - ret +.pcc_sub _sleep non_prototyped + .param object wait + $I0 = wait + sleep $I0 + .pcc_begin_return + .pcc_end_return + end +.end -_print1: - pushp - restore P31 - print P31 +.pcc_sub _print1 non_prototyped + .param object p + print p print "\n" - popp - ret + .pcc_begin_return + .pcc_end_return + end +.end -_print: - pushi - pushp - restore P3 - set I0, P3 - set I1, 0 -_print_loopstart: - eq I0, I1, _print_loopend - set P0, P3[I1] - print P0 - inc I1 - branch _print_loopstart -_print_loopend: - popp - popi - ret +.pcc_sub _print non_prototyped + .param object params + .local int num_elem + .local int counter + num_elem = params + counter = 0 +print_loopstart: + if counter == num_elem goto print_loopend + $P0 = params[counter] + print $P0 + inc counter + goto print_loopstart +print_loopend: + .pcc_begin_return + .pcc_end_return + end +.end -_exit: - pushp - restore P0 - print P0 +.pcc_sub _exit non_prototyped + .param object message + print message print "\n" end - ret +.end -_die: - pushp - pushi +.pcc_sub _die non_prototyped + .param object params # setup $!: #################### - new P0, .PerlString - restore P3 - set I0, P3 - eq I0, 0, _die_unknown - new P1, .PerlString - set I1, 0 -_die_loopstart: - eq I0, I1, _die_loopend - set P1, P3[I1] - concat P0, P0, P1 - inc I1 - branch _die_loopstart -_die_unknown: - set P0, "Unknown error." -_die_loopend: - store_global "_SV__BANG_", P0 + .local object dollar_bang + dollar_bang = new PerlString + .local int num_params + num_params = params + if num_params == 0 goto die_unknown + $P1 = new PerlString + .local int counter + counter = 0 +die_loopstart: + if num_params == counter goto die_loopend + $P1 = params[counter] + dollar_bang = dollar_bang . $P1 + inc counter + goto die_loopstart +die_unknown: + dollar_bang = "Unknown error." +die_loopend: + store_global "_SV__BANG_", dollar_bang # Look for a CATCH handler: ### - find_global P1, "_AV_catchers" - set I0, P1 - eq I0, 0, _die_nohandler + .local object try_stack + find_global try_stack, "_AV_catchers" + $I0 = try_stack + if $I0 == 0 goto die_nohandler # Remove top catch handler - dec I0 - set P0, P1[I0] - set P1, I0 - store_global "_AV_catchers", P1 -# Implicitly refers to continuation in P0 - invoke -_die_nohandler: - print P0 + dec $I0 + $P0 = try_stack[$I0] + try_stack = $I0 + store_global "_AV_catchers", try_stack + invoke $P0 + +die_nohandler: + print dollar_bang print "\nDied (no handler).\n" end - ret +.end -_warn: - bsr _print - ret +.pcc_sub _warn non_prototyped + .param object params + find_lex $P0, "&print" + .pcc_begin non_prototyped + .arg params + .pcc_call $P0 +warn_ret_label: + .result $P1 + .pcc_end + .pcc_begin_return + .return $P1 + .pcc_end_return +.end -__CALL_CLOSURE: - pushp - restore P0 - restore P1 - save P1 - invoke - popp - ret +.emit __setup: save P0 # == argv @@ -526,32 +535,31 @@ popp ret -__install_catch: - pushp - pushi - # gross continuation-creating sequence: - restore P0 - find_global P2, "_AV_catchers" - set I1, P2 - set P2[I1], P0 - store_global "_AV_catchers", P2 - popi - popp - ret +.eom -__pop_catch: - pushp - pushi - find_global P2, "_AV_catchers" - set I1, P2 - dec I1 - set P2, I1 - store_global "_AV_catchers", P2 - popi - popp - ret +.pcc_sub _install_catch non_prototyped + .param object continuation + .local object try_stack + find_global try_stack, "_AV_catchers" + $I1 = try_stack + try_stack[$I1] = continuation + store_global "_AV_catchers", try_stack + .pcc_begin_return + .pcc_end_return + end +.end -.eom +.pcc_sub _pop_catch non_prototyped + .local object try_stack + find_global try_stack, "_AV_catchers" + $I1 = try_stack + dec $I1 + try_stack = $I1 + store_global "_AV_catchers", try_stack + .pcc_begin_return + .pcc_end_return + end +.end END Index: languages/perl6/P6C/IMCC.pm =================================================================== RCS file: /cvs/public/parrot/languages/perl6/P6C/IMCC.pm,v retrieving revision 1.26 diff -u -r1.26 IMCC.pm --- languages/perl6/P6C/IMCC.pm 22 May 2003 10:51:21 -0000 1.26 +++ languages/perl6/P6C/IMCC.pm 19 Aug 2003 01:27:43 -0000 @@ -162,8 +162,30 @@ die "Must define main" unless $funcs{main}; print <<'END'; .sub __main + new_pad 0 call __setup - call _main +END + # XXX: This is hackish. The builtins should really be global multimethods, + # and closures shouldn't be excluded by name. This'll do until it can be + # refactored to use imcc lexicals and globals everywhere. + + foreach my $name (keys %funcs) { + next if $name =~ /closure/; + my $mangled_name = mangled_name($name); + my $local_name = $name . "_sub"; + my $lexical_name = "&" . $name; + print <<END; + .local Sub $local_name + newsub $local_name, .Sub, $mangled_name + store_lex -1, "$lexical_name", $local_name +END + } + print <<'END'; + .pcc_begin non_prototyped + .pcc_call main_sub +main_ret_label: + .pcc_end + pop_pad end .end END @@ -175,7 +197,7 @@ next; } $name = mangled_name($name); - print ".sub $name\n"; + print ".pcc_sub $name non_prototyped\n"; $sub->emit; print ".end\n"; } @@ -839,13 +861,15 @@ my ($thing, $args) = @_; my $argval = $args ? $args->val : newtmp('PerlArray'); my $func = $thing->val; + my $ret_label = genlabel 'ret_label'; my $ret = gentmp 'pmc'; code(<<END); + .pcc_begin non_prototyped .arg $argval - # .arg $func - # call __CALL_CLOSURE - invoke $func + .pcc_call $func +$ret_label: .result $ret + .pcc_end END return $ret; } @@ -985,10 +1009,6 @@ sub emit { my $x = shift; - print <<END; - saveall -# Parameters: -END foreach (@{$x->args}) { my ($t, $pname) = @$_; my $ptype = P6C::IMCC::paramtype($t); @@ -1017,8 +1037,7 @@ } print $x->{code}; print <<END; - restoreall - ret + end END } @@ -1592,7 +1611,9 @@ $ret = $x->block->val; unless ($ctx->{noreturn}) { code(<<END); + .pcc_begin_return .return $ret + .pcc_end_return END emit_label type => 'return'; } @@ -1621,7 +1642,9 @@ unless ($ctx->{noreturn}) { code(<<END); + .pcc_begin_return .return $ret + .pcc_end_return END emit_label type => 'return' unless $ctx->{noreturn}; } Index: languages/perl6/P6C/IMCC/prefix.pm =================================================================== RCS file: /cvs/public/parrot/languages/perl6/P6C/IMCC/prefix.pm,v retrieving revision 1.15 diff -u -r1.15 prefix.pm --- languages/perl6/P6C/IMCC/prefix.pm 25 Jun 2003 13:05:46 -0000 1.15 +++ languages/perl6/P6C/IMCC/prefix.pm 19 Aug 2003 01:27:44 -0000 @@ -189,6 +189,12 @@ my ($x) = @_; my $func = $P6C::IMCC::funcs{$x->name}; my $ctx = $x->{ctx}; + + my $subname = "&" . $x->name; + my $subtmp = gentmp 'pmc'; + code(<<END); + find_lex $subtmp, "$subname" +END if ($x->args) { my $args = $x->args->val; @@ -203,13 +209,24 @@ .", expected "[EMAIL PROTECTED]>args}; } - foreach (reverse @$args) { + code(<<END); + .pcc_begin non_prototyped +END + foreach (@$args) { code("\t.arg $_\n"); } + } else { + code(<<END); + .pcc_begin non_prototyped +END } - my $mname = P6C::IMCC::mangled_name($x->name); - code("\tcall $mname\n"); + + my $ret_label = genlabel 'ret_label'; + code(<<END); + .pcc_call $subtmp +$ret_label: +END # Now handle return value. @@ -225,12 +242,16 @@ .result $results[$i] END } + code(<<END); + .pcc_end +END return tuple_in_context([EMAIL PROTECTED], $ctx); } elsif ($rettype eq 'PerlArray') { my $ret = gentmp 'pmc'; code(<<END); .result $ret + .pcc_end END # XXX: this is not nice, but it's more useful than returning # array-lengths. @@ -257,6 +278,7 @@ my $ret = gentmp 'pmc'; code(<<END); .result $ret + .pcc_end END return scalar_in_context($ret, $ctx); @@ -550,6 +572,9 @@ my $try = genlabel 'try'; my $cont = newtmp 'Continuation'; my $label = $endblock; + my $subtmp = gentmp 'pmc'; + my $startcatch = genlabel 'ret_label'; + my $endcatch = genlabel 'ret_label'; my $catch; my $result; my $ret = gentmp 'pmc'; @@ -561,8 +586,12 @@ code(<<END); $addr = addr $label $cont = $addr + find_lex $subtmp, "&install_catch" + .pcc_begin non_prototyped .arg $cont - call __install_catch + .pcc_call $subtmp +$startcatch: + .pcc_end goto $try END if ($catcher) { @@ -616,7 +645,11 @@ } # Reached end of block => no exception. Pop the continuation. code(<<END); - call __pop_catch + find_lex $subtmp, "&pop_catch" + .pcc_begin non_prototyped + .pcc_call $subtmp +$endcatch: + .pcc_end $endblock: END return $ret; @@ -717,6 +750,7 @@ emit_label name => $label, type => 'break'; pop_scope; + return undef_in_context($x->{ctx}); } sub prefix_defined {