leo's Journal http://use.perl.org/~leo/journal/ leo's use Perl Journal en-us use Perl; is Copyright 1998-2006, Chris Nandor. Stories, comments, journals, and other submissions posted on use Perl; are Copyright their respective owners. 2012-01-25T02:15:12+00:00 pudge pudge@perl.org Technology hourly 1 1970-01-01T00:00+00:00 leo's Journal http://use.perl.org/images/topics/useperl.gif http://use.perl.org/~leo/journal/ Todays Vienna.pm TechSocial http://use.perl.org/~leo/journal/35038?from=rss <p>We had another TechSocial Meeting in Vienna - taking place on 1st monday of every month. First Willy showed using Perl for emulating heavy (really tons of) hardware - very impressive. Second talk by <a href="http://use.perl.org/~domm/journal/">domm</a> was an intro to Perl 5.10.</p><p>The pub (remember Tech<b>Scocial</b>) did e.g. provide 'Perlhuhnbrust' on the menue, but we didn't ask if it were of the 5.10 persuasion.</p><p>The smart match operator lead to immediate discussion, whether there exists a 'not-smart-operator' or rather a 'smart-not-operator' or their combination:</p><blockquote><div><p> <code> $foo !~~<nobr> <wbr></nobr>/bar/; # not smart aka dumb match<br> </code></p></div> </blockquote><p>Would this maybe match every <code>chicken</code> or rather not?</p><blockquote><div><p> <code> $foo ~!~<nobr> <wbr></nobr>/bar/; # smart no match<br> $foo !~!~<nobr> <wbr></nobr>/bar/; # no dumb match<br> </code></p></div> </blockquote><p>... which immediately lead to a discussion of the orthogonality of the <code>not</code> operator, which generally was considered as very important. E.g. is this valid syntax, and what does it mean:</p><blockquote><div><p> <code> not my $var; </code></p></div> </blockquote><p>Semantically it's a promise not to use this variable in that scope. But perl has a different POV</p><blockquote><div><p> <code> $ perl -Mstrict -Mwarnings -le'not my $var'<br> Useless use of not in void context at -e line 1. </code></p></div> </blockquote><p>OTOH<nobr> <wbr></nobr>...</p><blockquote><div><p> <code> $ perl -Mstrict -Mwarnings -le'print not my $beer'<br> 1<br> <br> $ perl -Mstrict -Mwarnings -le'print ! my $beer'<br> 1 </code></p></div> </blockquote><p>... there are some 'true' items, which aren't your beer. But<nobr> <wbr></nobr>...</p><blockquote><div><p> <code> $ perl -Mstrict -Mwarnings -le'print $_-&gt;ignore for not our @beer'<br> Can't call method "ignore" without a package or object reference at -e line 1.</code></p></div> </blockquote><p>... you can't actually ignore all of them.</p> leo 2007-12-03T22:59:45+00:00 journal P3 - Parrot Presentation Program http://use.perl.org/~leo/journal/30955?from=rss <p>As outlined in the previous journal entry, I'm writing a new presentation tool using Parrot. It now has hit the parrot svn repository.</p><p>A basic presentation (written in html) about P3 itself can be found <a href="http://svn.perl.org/parrot/trunk/apps/p3/p3p.html"> here</a> (sorry - the svn server is delivering this as text/plain). </p> leo 2006-09-10T19:57:30+00:00 journal Parrot can do AJAX too! http://use.perl.org/~leo/journal/30902?from=rss <p>Above subject is shamelessy stolen from Jonathan, who has used it on IRC. Anyway, I got bored by doing my presentations with</p><blockquote><div><p> <code> $<nobr> <wbr></nobr>./parrot slpod.imc yapc.pod </code></p></div> </blockquote><p>... or some such. I wrote the predecessor of that at YAPC::EU::2003 during lunch break and the slides at dinner (no, that isn't a joke) and it caused a lot of fun at these days.</p><p>But in recent times all has to be <strong>AJAX</strong>, hasn't it? Alas, I started hacking <i>examples/io/httpd.pir</i> to support a CGI GET request, which is invoking Parrot subroutines, and put together 60 lines of JavaScript dealing mainly with keyboard requests to navigate between slide pieces and to send <strong>XMLHttpRequest</strong>s. The <i>XML</i> thingy is totally optional, don't be afraid, plain text messages or html snippets are working fine too - and that's what the next slide presentation program will use.</p><p>Given that your GET request delivers a valid HTML snippet, and you got e.g. <tt>&lt;div id="answer"&gt;&lt;/div&gt;</tt> on your html page, then all you need to fill this with contents is mainly this JavaScript two-liner:</p><blockquote><div><p> <code> var x = document.getElementById('answer');<br> x.innerHTML = req.responseText; </code></p></div> </blockquote><p>That's almost it. I'll put together a working example in the parrot repo during the next days.</p> leo 2006-09-05T22:41:06+00:00 journal YAPC::EU::2006 Parrot BOF http://use.perl.org/~leo/journal/30880?from=rss <p>About 10 (more or less) parrots flocked together in the lobby of Jury's Inn Hotel at Wednesday. The topics were:</p><ul> <li>Parrot on VMS (VAX). The <a href="http://vaxman.de/">Vaxman</a> and Martin, who has already sent a patch to p6i, are hopefully continuing this story.</li><li>JIT for the x86_64 architecture</li><li>Perl5 continuations. I discussed parrot's implemenation and some implications mainly with Nick.</li><li>Parrot interfaces. Allison and me went through a more flexible concept extending the current static vtable layout.</li></ul> leo 2006-09-04T15:50:36+00:00 journal Parrot: if vs. unless http://use.perl.org/~leo/journal/28727?from=rss <p>Parrot provides two opcodes to branch on the truthness of a register: <code>if</code> and <code>unless</code>. It looks like that it's just a matter of taste, which one to use. Is it really?</p><p>Not with modern CPUs with branch prediction rules and with JIT code inside tight inner loops. Below are two versions of the ackermann function, one written with <code>if</code> and one using <code>unless</code>. (If you are missing the loop in the code, well, that's coming from tailcall optimization, turned on with <code>-Oc</code>.)</p><p> <code> $ cat ack-if.pir<br><nobr> <wbr></nobr>.sub&nbsp;ack<br> &nbsp;&nbsp;.param&nbsp;int&nbsp;x<br> &nbsp;&nbsp;.param&nbsp;int&nbsp;y<br> &nbsp;&nbsp;if&nbsp;x&nbsp;goto&nbsp;a1<br> &nbsp;&nbsp;&nbsp;&nbsp;inc&nbsp;y<br> &nbsp;&nbsp;&nbsp;&nbsp;.return&nbsp;(y)<br> a1:<br> &nbsp;&nbsp;if&nbsp;y&nbsp;goto&nbsp;a2<br> &nbsp;&nbsp;&nbsp;&nbsp;dec&nbsp;x<br> &nbsp;&nbsp;&nbsp;&nbsp;.return&nbsp;ack(x,&nbsp;1)<br> a2:<br> &nbsp;&nbsp;dec&nbsp;y<br> &nbsp;&nbsp;y&nbsp;=&nbsp;ack(x,&nbsp;y)<br> &nbsp;&nbsp;dec&nbsp;x<br> &nbsp;&nbsp;.return&nbsp;ack(x,&nbsp;y)<br><nobr> <wbr></nobr>.end<br> </code> </p><p> <code> $ cat ack-unless.pir<br><nobr> <wbr></nobr>.sub&nbsp;ack<br> &nbsp;&nbsp;.param&nbsp;int&nbsp;x<br> &nbsp;&nbsp;.param&nbsp;int&nbsp;y<br> &nbsp;&nbsp;unless&nbsp;x&nbsp;goto&nbsp;a1<br> &nbsp;&nbsp;unless&nbsp;y&nbsp;goto&nbsp;a2<br> &nbsp;&nbsp;dec&nbsp;y<br> &nbsp;&nbsp;y&nbsp;=&nbsp;ack(x,&nbsp;y)<br> &nbsp;&nbsp;dec&nbsp;x<br> &nbsp;&nbsp;.return&nbsp;ack(x,&nbsp;y)<br> a1:<br> &nbsp;&nbsp;inc&nbsp;y<br> &nbsp;&nbsp;.return&nbsp;(y)<br> a2:<br> &nbsp;&nbsp;dec&nbsp;x<br> &nbsp;&nbsp;.return&nbsp;ack(x,&nbsp;1)<br><nobr> <wbr></nobr>.end<br> </code> </p><p>And here are the timings of both with<nobr> <wbr></nobr><code>./parrot -Oc -Cj ack-xx.pir 12</code> on an AMD X2@2000: </p><p> <code> ack-if&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.9&nbsp;s<br> ack-unless&nbsp;&nbsp;2.4&nbsp;s</code> </p><p>Branches with positive branch offsets (downwards) are considered to be likely not taken, that is the fall-through case is the default one. As there are a lot more positive numbers than the one zero, the <code>unless</code> is the better choice here (for some CPUs, YMMV). Well, that's at least my conclusion for now. But there is another issue: branch alignment. I've not yet experimented with different label alignments, but I know that alignment can cause timing differences like above too.</p> leo 2006-02-18T21:12:58+00:00 journal Parrot -Ofun http://use.perl.org/~leo/journal/28623?from=rss <p>Heureka - from the -Ofun department</p><p>Or - running the ackermann function (and possibly other recursive functions) really fast.</p><p> <code>$ time<nobr> <wbr></nobr>./parrot -Oc -C ack.pir 11<br> Ack(3, 11) = 16381<br> <br> real 0m0.567s<br> user 0m0.559s<br> sys 0m0.008s<br> </code> </p><p> <code>$ time<nobr> <wbr></nobr>./ack 11<br> Ack(3,11): 16381<br> <br> real 0m0.980s<br> user 0m0.978s<br> sys 0m0.002s<br> </code> </p><p>The latter is optimized C code. Parrot is recompiling (or will do when that's finished) statically known and simple PIR code to native machine code via it's JIT system.</p><p>See also a recent post on perl6-internals.</p> leo 2006-02-08T16:56:09+00:00 journal Parrot 0.4.1 "Foghorn Leghorn" Released! http://use.perl.org/~leo/journal/28283?from=rss <p>Numerous folks contributing more than 640 revisions were helping to create a more powerful <a href="http://en.wikipedia.org/wiki/Foghorn_Leghorn">bird</a> err <a href="http://www.parrotcode.org/">parrot</a>. </p><p>Thanks all!</p> leo 2006-01-08T16:11:26+00:00 journal Parrot 0.4.0 "Luthor" Released! http://use.perl.org/~leo/journal/27855?from=rss <p>Numerous people have contributed to another major release of <a href="http://www.parrotcode.org/">Parrot</a>: 0.4.0 'Luthor' is out - thanks to all. </p><p>The release name is of course not related to <a href="http://www.forbes.com/home/lists/2005/11/29/forbes-fictional-rich_cx_mn_de_05fict15land.html">this article</a>, but comes from our brand new <a href="http://svn.perl.org/parrot/trunk/docs/pdds/pdd20_lexical_vars.pod">lexical stuff</a>. </p> leo 2005-12-04T16:53:28+00:00 journal "The Continuation Bug" is gone http://use.perl.org/~leo/journal/27504?from=rss <p>Today I've checked in the final fix for one of the longest outstanding bugs inside Parrot.</p><p>A short recap:</p><p>Having first-class continuation objects is one of the design goals of Parrot. A lot of HLLs support continuations with some special syntax and with continuations in the core a lot of HLL control structures and features like exceptions can be implemented easily. </p><p>But there was a problem with continuations. Continuations can change the CFG (control flow graph) of a program in such a way that there are suddenly loops, where the register allocation code isn't (and can't be) aware of it.</p><p>The following code piece from a test provided by <a href="http://www.bofh.org.uk/">Piers</a> revealed the whole problem:</p><p> <code> arr1 = "[1, 3, 5]"<br> arr2 = "[1, 5, 9]"<br> x = choose(arr1)<br> y = choose(arr2)<br> if (x * y != 15)<br> fail = find_lex "fail"<br> fail()</code> </p><p>To the register allocator this looks like a linear control flow, which is just executed once (there is no loop outside of that code snippet). But actually the <code>choose</code> closures are capturing their continuations and are backtracking through the call to the <code>fail</code> function. We suddenly have a loop going from <code>fail()</code> to one of the <code>choose()</code> function call returns. The code that the register allocator should have been considering would be something like this:</p><p> <code> &nbsp;&nbsp;arr1 = "[1, 3, 5]"<br> &nbsp;&nbsp;arr2 = "[1, 5, 9]"<br> choose_again_1: # label actually in front of function return<br> &nbsp;&nbsp;x = choose(arr1)<br> choose_again_2:<br> &nbsp;&nbsp;y = choose(arr2)<br> &nbsp;&nbsp;if (x * y != 15)<br> &nbsp;&nbsp;fail = find_lex "fail"<br> &nbsp;&nbsp;fail()<br> &nbsp;&nbsp;goto choose_again_1 or _2</code> </p><p>This implies that the registers of the variables <code>x, y, arr2</code> can't be reused for example to assign a register to the <code>fail</code> variable. But exactly this has happened and the code really "fail"ed.</p><p>There were some (IMHO) impractical proposals to fix this, like refetching all variables from lexicals all the time (and don't use native integers and numbers because these aren't lexicals) but the real fix for this is now in: that is - just don't reallocate the registers used by lexicals and non-volatile variables to other variables like temporaries.</p><p>That's the reason for variable-sized register frames and, well, some lack of visible progress of Parrot development for some time.</p> leo 2005-11-07T23:24:35+00:00 journal Parrot 0.3.1 "Wart" Released! http://use.perl.org/~leo/journal/27487?from=rss <p>After more than 400 revisions within one month the next release of Parrot has arrived on <a href="http://www.cpan.org/authors/id/L/LT/LTOETSCH/parrot-0.3.1.tar.gz">CPAN</a>.</p><p>Thanks to all providing patches and help us with developing <a href="http://www.parrotcode.org/">Parrot</a>.</p> leo 2005-11-06T13:54:32+00:00 journal Parrot 0.3.0 "Alex" Released! http://use.perl.org/~leo/journal/26960?from=rss <p>With a lot of help (Robrt, clkao, svk - many thanks) the branch got merged back to trunk and is now released as Parrot 0.3.0. The official announce should make it to the front page soon.</p> leo 2005-10-01T15:48:48+00:00 journal Calling conventions - a comparison http://use.perl.org/~leo/journal/26303?from=rss <p>I've now compared old calling conventions with the new one by checking bytecode size, executed amount of opcodes, and the timings of one of the benchmarks.</p><p>I've used the suduku solver and the oo5 benchmark. The latter does 1 million attribute accesses via a method call, comprising a typical example of OO code.</p><p>The numbers were achieved by running<tt> <br>$<nobr> <wbr></nobr>./parrot -o sudoku.pbc examples/assembly/sudoku.pir<br> $<nobr> <wbr></nobr>./pdump sudoku.pbc | grep size<br> $<nobr> <wbr></nobr>./parrot -p sudoku.pbc<br> </tt> and by <tt>$<nobr> <wbr></nobr>./parrot -p examples/benchmarks/oo5.imc</tt> or <tt>-C </tt>. </p><p>Here are the results:</p><blockquote><div><p> <tt> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;old&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new<br> &nbsp;&nbsp;&nbsp;Sudoku&nbsp;codesize&nbsp;&nbsp;&nbsp;&nbsp;5764&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3442<br> &nbsp;&nbsp;&nbsp;Sudoku&nbsp;ops&nbsp;-p&nbsp;&nbsp;&nbsp;&nbsp;911973&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;793967<br> &nbsp;&nbsp;&nbsp;oo5&nbsp;&nbsp;&nbsp;&nbsp;ops&nbsp;-p&nbsp;&nbsp;22501832&nbsp;&nbsp;&nbsp;&nbsp;10503606<br> &nbsp;&nbsp;&nbsp;oo5&nbsp;time&nbsp;-C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7.5s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4.9s<br> </tt></p> </div></blockquote><p>The new calling code reduces code size and executed opocdes significantly, which goes up to a factor of two for the benchmark. There is also a non-trivial speedup albeit no attempts were done yet to optimze the new code for speed.</p> leo 2005-08-16T14:13:57+00:00 journal Slow progress http://use.perl.org/~leo/journal/25683?from=rss <p>Two GC bugs (one in my branch, one in both trunk and the branch) slowed down further progress in finishing the calling convention changes. But these bugs are fixed now, and <a href="http://use.perl.org/~coke/journal/">Coke</a> can finish hunting his own in partcl<nobr> <wbr></nobr>;-)</p><p>In return for endless debug sessions, I compared <tt>oo5.imc</tt> and <tt>oo6.imc</tt> from <tt>examples/benchmarks</tt> - these (premature) results are promising: around half of the opcodes saved and more then 20% speedup. These two benchmarks test attribute accessor functions, where the call overhead is considerable.</p> leo 2005-07-13T21:27:04+00:00 journal Continuations and return context http://use.perl.org/~leo/journal/25626?from=rss <p> <b>A correction foremost</b> </p><p>A remark WRT the paragraph mentioning type checking in my <a href="http://use.perl.org/~leo/journal/25491">first ewaa journal</a>. It was caused by me misinterpreting the type conversion specs in <a href="http://svn.perl.org/parrot/trunk/docs/pdds/pdd03_calling_conventions.pod">pdd03</a>. We are now doing full type conversion, which makes argument passing strictly positional. That's very likely the expectation of our <a href="http://svn.perl.org/parrot/trunk/docs/req/model_users.pod">users</a> anyway. In the old scheme calling a subroutine:</p><p> <code>foo(pmc b, str a) # pseudosyntax to denote argument types</code> </p><p>just worked, despite the sub was defined as:</p><p><nobr> <wbr></nobr><code>.sub foo<br><nobr> <wbr></nobr>.param str a<br><nobr> <wbr></nobr>.param pmc b</code> </p><p>Looks weird, but was really used, probably more by accident then for some good reason. Now you get the first argument converted to a string and the second as a new string PMC.</p><p> <b>Continuations and return context</b> </p><p>As Dan describes in his <a href="http://www.sidhe.org/~dan/blog/archives/000423.html">blog</a>, there is not much difference between a subroutine call and the invocation of a continuation. Both can return results to the caller. A nice example provided by <a href="http://www.bofh.org.uk/">Piers</a> from Parrot's <a href="http://svn.perl.org/parrot/trunk/t/op/gc.t">tests</a> (yeah, number 13) contains something like:</p><p> <code>x = choose([1, 3, 5])<br> y = choose([1, 5, 9])<br> if (x * y != 15)<br> fail()</code> </p><p>Above is vastly simplified, because the <i>choose</i> function calls capture their continuations and call a <i>try</i> closure that either backtracks via the saved <i>fail </i> hook or delivers the next item from the passed in choices array. Anyway the interesting thing (for a proper implementation of continuations) is, that there are mupltiple continuations that like to return either the next <i>x</i> or <i>y</i>, when invoked indirectly via the <i>fail</i> function. These continuations are not only returning to different program locations they are also returning different results.</p><p>In the source we got this line:</p><p> <code>our_cc($P3) # $P3 being one of the next choices</code> </p><p>where eventually the next result for <i>choose</i> is to be returned to the main program. It looks like a plain subroutine call, but invokes the passed in continuation and ends up, where one of the <i>choose</i> calls had left off.</p><p>This means that creating a full continuation still needs to copy the context structure (which contains also the current return results location). A return continuation can just contain a pointer to the refered context.</p><p>After having implemented this all now, the rather complicated tests (p6rules, streams), which are using continuations as well as coroutines are passing within my branch (I didn't look at other failing tests yet, but just converting explicit register usage for call setup to new conventions should fix almost all). These tests are of course passing in Parrot svn trunk true, but now (for the most common case of invoking a return continuation) no context is copied at all, it's just a matter of putting the pointer of the captured context into the interpreter.</p><p>The official way to do <i>call/cc</i> is still unchanged, it's:</p><p> <code><nobr> <wbr></nobr>.include "interpinfo.pasm"<br> cc = interpinfo<nobr> <wbr></nobr>.INTERPINFO_CURRENT_CONT</code> </p><p>This usually means that you need a helper subroutine, where you capture the continuation (and pass it along somewhere for later usage), it's OTOH a well defined usage of continuations in e.g. <i>scheme</i>. When things are settling, I'm sure that we can provide some shortcuts for capturing continuations inside the same sub (or context) too.</p><p>And implementing <i>want</i> or similar is of course simple now, as the <i>get_results</i> opcode is emitted before the subroutine invocation, and is therefore available for plain function returns as well as for continuations that return a result. Both can return what the caller <i>want</i>s, because the information is present in the context.</p> leo 2005-07-10T21:17:06+00:00 journal 360 KByte and done http://use.perl.org/~leo/journal/25552?from=rss <p>Well, the <tt>svn diff</tt> got bigger a bit and operation is now that far consolidated that I've committed it to a new branch <tt>branches/leo-ctx5</tt>, so that @all can investigate it and start helping to get it finished soon.</p> leo 2005-07-06T21:40:12+00:00 journal 160 KBytes and still counting http://use.perl.org/~leo/journal/25532?from=rss <p>Well, 160 Kbytes are my diffs now against Parrot svn HEAD. And still no chance to check it in, without blocking $others, because too much still is failing.</p><p>Done:</p><ul> <li> <code>r = foo(a, b)</code> translates now to new call scheme opcodes, as well as<nobr> <wbr></nobr><code>.param</code> and<nobr> <wbr></nobr><code>.returns()</code> stuff. Just tossed 460 lines in <i>imcc/pcc.c</i> and added 20 new. Works fine.</li><li>Converted the NCI generation code to the new scheme too.</li><li>Running Parrot Subs from C code now also uses new conventions</li></ul><p>Overall it looks like that calling PASM/PASM is by far simpler now, but PASM/C (<i>NCI</i>) and C/PASM (<i>runops_fromc_*</i>) interfaces use slightly more code lines. OTOH we get now strict type checking and conversions to and from PMCs, which wasn't in the old scheme. I can very well imagine that we don't want to call C code w/o argument verification anyway.</p> leo 2005-07-05T19:35:51+00:00 journal Context patch is getting ready http://use.perl.org/~leo/journal/25512?from=rss <p>Wrote a second context allocation strategy today. Just malloc/free backed by a free list. Works fine, except that it seems to reveal a very likely unrelated GC bug, which I'm still chasing.</p><p>Yesterday was <a href="http://xrl.us/gnie">"Somehow Olympia"</a> (German text) here in Herrnbaumgarten. We had a lot of fun for example watching "towel throwing for politicians".</p> leo 2005-07-04T20:11:05+00:00 journal Parrot Calling Conventions http://use.perl.org/~leo/journal/25491?from=rss <b>WWCPD: Calling Conventions</b> <p>The original design was not only rather <a href="http://www.sidhe.org/~dan/blog/archives/000413.html">heavyweight</a>, it was also incomplete and a bit blurry. It was lacking support for MMD argument signatures, return value context, typechecking, and so on.</p><p>I'll try do describe some reasons, why we changed calling conventions to use a <a href="http://svn.perl.org/parrot/trunk/docs/pdds/pdd03_calling_conventions.pod"> new abstract scheme</a>. The major change is that all the argument passing is now done by dedicated opcodes, which allows any later implementation and adaption under the hood without changing the ABI of the <a href="http://www.parrotcode.org/">Parrot VM</a>.</p><p> <b>MMD Signatures</b> </p><p>A function call:</p><p> <code> foo(Px, Iy)</code> </p><p>was translated to these argument-related opcodes (function lookup and call opcodes omitted for brevity):</p><p> <code> set I0, 1 # prototyped call<br> set I1, 1 # 1 INT argument<br> set I2, 0 # 0 STR arguments<br> set I3, 1 # 1 PMC argument<br> set I4, 0 # 0 NUM arguments<br> set P5, Px # get PMC argument<br> set I5, Iy # get INT argument<br> set S0, "foo" # function name</code> </p><p>A lot of opcodes to dispatch, but takes almost no time with the JIT runtime. Fine so far. Another function call:</p><p> <code> foo(Ix, Py)</code> </p><p>produced exactly the same call register setup - these two function calls can not be discerned when, it comes to multi method dispatch.</p><p>Now the first argument setup just translates to:</p><p> <code> set_args "(0b10,0)", Px, Iy</code> </p><p>and the second is:</p><p> <code> set_args "(0,0b10)", Ix, Py</code> </p><p>Thus we not only saved 7 opcode dispatches per function call, we got a clear type information of the caller's arguments including the argument order. You don't have to set these type bits yourself, the assembler does it according to the passed arguments, so just writing: </p><p> <code> set_args "(0,0)", Ix, Py</code> </p><p>works fine.</p><p> <b>Type checking</b> </p><p>In the old scheme you could happily call a function with:</p><p> <code> foo(Px, Iy)</code> </p><p>which was defined as:</p><p> <code><nobr> <wbr></nobr>.sub foo<br><nobr> <wbr></nobr>.param float n<br><nobr> <wbr></nobr>.param string s</code> </p><p>The<nobr> <wbr></nobr>.param was just translated to:</p><p> <code> foo:<br> set Nx, N5 # get 1st NUM param into n<br> set Sy, I5 # get 1st STR param into s</code> </p><p>Due to the register usage of argument passing the function would have picked up whatever happens to be in registers N5 and S5 and would run - probably not long though. A possible "solution" would have been to force all compilers and Parrot hackers to emit code to first verify the passed arguments. That's of course another bunch of opcodes, bulky and error-prone. Now the function defines precisely what it awaits:</p><p> <code><nobr> <wbr></nobr>.sub foo<br> get_params "(0b11,0b1)", Nx, Sy</code> </p><p>Again the type bits are filled in by the assembler. But during the call sequence, the argument passing code can verify the types (and counts) of arguments and parameters. Conversions to and from PMC parameters are specified and done automatically. Mismatches are reported by an exception.</p><p> <b>Implicit register usage</b> </p><p>The central mechanism of a function call in the old scheme was just the plain argumentless opcode:</p><p> <code> invoke</code> </p><p>It would pick up whatever happens to be in P1 and uses it as the continuation of the call. P2 was defined to be the invocant, if it's a method call. And so on - and it call's whatever is in P0. That's per se fine, if all code writers and compilers strictly use this convention and don't forget to NULLify registers that shouldn't be used for the call, but it's a major PITA for the assembler, which ought to track the control flow for proper register allocation: is the invoke a function call, a yield, a return from a function? Well it's not defined, it could be everything. Not a few lines inside imcc are trying to track down the usage of invoke opcodes to do the right thing. You can imagine that this does not contribute to clear code.</p><p> <b>Method invocant</b> </p><p>The old call scheme demanded that the invocant is passed out-of-band in P2. It's also only available in functions declared as methods by a special <i>interpinfo</i> call. This doesn't really match our major target languages, where the invocant just happens to be the first param of a method.</p><p>Calling a function as a method or vice versa would have needed to shift PMC arguments down or up to get everything into the registers that the callee expects.</p><p> <b>Return value context</b> </p><p>The old scheme had no provision for specifying, what and how many return results the caller expects. Now the <i>get_results</i> opcode is emitted before the actual function call, so that a function return has a chance to return what the caller <i>want</i>s.</p><p> <b>Future and optimization</b>In the old scheme the lower 16 registers of each kind were volatile (each function return could set these registers). This implies that you usually have to move registers from the preserved area into the lower half, during the call sequence registers are moved into the callee's lower half, from where another round through all parameters would have placed everything in the preserved area. This are three passes over all arguments - hardly to avoid in the general case.</p><p>The old call scheme reserved 4*16 registers just for function calls and returns. This accounts for 320 bytes (on a 32-bit machine) that have to be allocated per call to pass e.g. just one word argument to an one-liner function or an attribute accessor method.</p><p>Ok, we are not doing optimzation now - that's fine. But the old calling scheme would have prevented all future optimizations that will be needed. You can't do any optimizations later when the call scheme is carved in stone and just reserves half of the register resources for itself.</p><p>---<br>WWCPD<nobr> <wbr></nobr>... why we change(d) parrot's design</p> leo 2005-07-03T11:46:19+00:00 parrot