Showing posts with label cardinal. Show all posts
Showing posts with label cardinal. Show all posts

Tuesday, February 20, 2007

Serial Parrot/Cardinal Interview: Episode II

In this episode, Kevin and I talk more about Parrot and objects, other Ruby implementations, and some of the sources Kevin's been working with.

The big news in alternative implementations was a shootout by Antonio Cangiano. While I think this is still a bit premature (only YARV and Ruby 1.8.5 complete 100% of the tests, see chart below), there's a lot to learn from it. I think it can help each of the alternative implementation projects to see where they can focus some of their effort to really improve their version of Ruby.

Implementation Completeness

I know Cardinal been blocked by the lack of solid Object support in Parrot so far, but what do you think can be done to help get Cardinal 'over the hump' so that you (and other contributors) can really get some momentum going?

Kevin: Attempts could be made to work with the current object system in Parrot. Having seen the trouble others have had with the current object system, I have decided that it is not worth my time to work with the object system as is.

Allison Randal has checked in a PIR based MOP called Simple Meta Object Protocol (SMOP). SMOP in its current form only supports attributes and parent classes. Support for methods needs to be added. I have the initial translation of SMOP to C based PMC coded up. The translation however, depends on the ability to call C PMC methods from C with PIR calling conventions. I have a plan to implement this functionality and call it PMINVOKE. This is the corresponding piece to PMETHOD functionality which I recently added to Parrot. PMETHOD allows C PMC Methods to be implmented with PIR calling conventions.

You've talked about wanting to build a MOP based object system, what advantages does that have for Cardinal and Parrot?

Kevin: MOP is a huge win for Parrot. MOP will allow common Parrot infrastructure pieces to be reused to implement the distinct object systems features that each language has. Parrot developers hope that a common Meta-MOP will permit the different object system philospohies of each language to interoperate at some common denominator level. At a minimum a common Meta-MOP will permit language implementor write object system translators. JRuby is having to do this with the Java and Ruby object systems, but without the help of any low level tools or common meta object subsystem.

As you see the JRuby and rubinius teams moving ahead, what pieces of their work do you think will apply to Cardinal?

Kevin: I think the knowledge base that they possess will be beneficial to Cardinal. The JRuby and rubinius projects currently trade and share a lot of insights about the problems areas of MRI. I'm a little disappointed that the alternative implementations have not built more common infrastructure in Ruby itself. Parsing is a real problem. I believe alternative implementors should build a common ruby parsing library to support rich parsing constructs that would make parsing ruby easier. Building a parsing framework is difficult, but adding code generation backends to a completed parsing framework would be relatively easy. Antlr and Perl 6 Rules are excellent examples of parsing frameworks with multiple code generation back ends. I am as guilty as the next implmentor in this respect, because Parrot provides a very rich parsing framework (Perl 6 Rules) which I'm proponent of.

Dan talked about using the plethora of papers on optimizing register based compilers to help improve Parrot. What papers and/or projects are you watching to help with your work?

Kevin: I've read the traits papers that discusses role composition. I've also checked out and read the CLOS MOP book. The traits papers have been very educational. The unanswered question is how to compose or accomidate state. I think a mix of the C++ multiple inheritance paradigm and explicit annotations as advocated by the traits papers may be the solution for composable state.


Given Kevin's work with on and MOP, the only sponsor that made sense this week was The Art of the Metaobject Protocol. Grab a copy and learn more about MOP while supporting these interviews.

If you enjoyed this, you might also enjoy Nick Sieger's Serial JRuby Interview:

  • Episode 1, in which Charles, Thomas, and Ola talk about their plans for JRuby.
  • Episode 2, in which Charles, Thomas, and Ola talk about cooperation with the rubinius team and YARV.
  • Episode 3, in which Charles, Thomas, and Ola talk about cooperation with the rubinius team Rails and (more about) YARV.
  • Episode 4, in which Charles, Thomas, Ola, and Tor Norbye talk about JRuby and NetBeans.
  • Episode 5, in which Charles, Thomas, and Ola talk about groovy.

James Gray has also started a serial interview. He's talking with Matz and Koichi. His first episode introduces them and discusses the recent merger of the VM formerly known as YARV and Ruby 1.9.

You might also enjoy my new Serial XRuby Interview or the original serial interview with the rubinius team.

Tuesday, February 06, 2007

Parrot/Cardinal Mini-Interview

This is the second week of my break from the serial rubinius interview, and it's time for another piece on parrot and cardinal. Is there any interest in making this into a second (for me, third overall) serial interview? I'd love to do it if there's enough interest.

This week, I'm talking to Kevin Tew (who I interviewed a while ago). In addition to some general information about his Cardinal and Parrot plans, he also gives us his take on VMs supporting multiple languages and register based VMs.


Kevin, now that you're past the current round of heavy lifting involved in school, you've gotten back into Cardinal and Parrot work. Can you tell us a bit about what you've been working on and what's next on your plate?

Kevin: For those who don't know me, I'm a language junkie. I really enjoy working on the low level guts of virtual machines. Lately in Parrot, I have been working on the portion of PIR calling conventions that interface between PIR (parrot high-level assembly language) and C.

Working on Parrot has been an exercise in focus for me. Once you understand the beginnings of how languages, interpreters, and virtual machines work, it is very tempting to start/invent your own language/VM. Working on an existing language/vm project may not be as glamorous as starting your own but for me, choosing to work on Parrot has been very rewarding.

I've spent my most recent Parrot time cage cleaning inter_call.c, which is where Parrot's calling convention and subroutine argument handling code lives.

The cleanup was in preparation for adding PMETHOD support to PMCs. For those that don't know Parrot PMCs are a pseudo C++ objects, implemented in C, upon which much of parrot is build. PMETHODs allow PMC methods, which are written in C, to support the full Parrot Calling Conventions that are available to Parrot Intermediate Representation (PIR, Parrot Assembly). Examples of PIR's enhanced calling capabilities include: optional arguments, named arguments, optional named arguments, slurpy arguments,slurpy named arguments, and array flattening.

What is next on my plate? I'd like to start working on the Parrot Object System. I noticed this past week in Parrot's weekly status meeting that Allison Randal has started working on ParrotBase based on Leo Toetsch CStruct ideas. I better dig in before I get left behind. I started implementing Stevan Little's Class::MOP (Meta Object Protocol) in C PMC's which he of course borrowed from Common Lisp. I soon realized that I wanted full calling convention support in C PMCs so I backtracked and created PMETHODS.

One of the knocks against Parrot is that it's a VM for many languages. It looks like the JVM and rubinius are headed down that road too (to some degree). How does hosting multiple languages help or hurt a VM?

Kevin: Writing a VM for multiple languages is certainly a challenge. The only other comparable VM I can think of that set out to be a VM for multiple languages would be Microsoft's CLR.

Microsoft built the CLR specifically with C# and C++ in mind. VB.NET is also becoming a mature language that is stretching the CLR design. Parrot's multiple language support is a development tactic that has shaped and insured the robustness of Parrot's implemented features. Building a VM, targeted by a spectrum of languages, requires Parrot designers to survey and research how each languages might use or pervert the VM feature in question. While the cost is substantial, I believe it is well worth the price.

Stating multiple language support as a prime object keeps Parrot designers and implementers honest. Corner cutting bits back pretty fast on the Parrot project.

Another knock is that Parrot is register based. Why don't you think this is a problem? (I also asked Dan Sugalski about this.)

Kevin: Stacks are simple to teach and simple to implement. Stack operations, however, are inherently linear. For quite a few years now, all mainstream processors have been superscalar (supporting parallel instruction execution). One of the key roles that caches and register files play in modern processors is to widen the window of instructions which can be analyzed and scheduled for parallel execution. Register based VM architectures remove the overhead of administrative stack operations and map efficiently to the data caches of modern processors.

NOTE: Dan's answer here is better than mine. The above is my opinion, I'm not well versed in this area. I know that stack lovers will say that stacks can map efficiently to register file based processors as well. It was a decision, it's made, life goes on. This issue really gets blown out of proportion. Its not that big of an issue.

Tuesday, January 30, 2007

Cardinal: A Behind the Curtains Look at Parrot

This week (and next), I'm taking some time away from the rubinius serial interview to let those guys get back to work. To keep everyone on their toes, I've got a couple of other bits lined up. This week, I asked Dan Sugalski, the original architect of Parrot, about a design decision that he made. Parrot might seem a bit far afield for a Ruby blog but there is the Cardinal project which is trying to build a Ruby front-end for it, so I don't think we're too far off the path.

Next week? You'll have to come back then and see.


In recent discussions in the Ruby world, the Parrot VM has taken some heat because of its register based design. I know you guys went through the trade-offs, but those discussions are lost in the mists of time. Could you fill everyone in?

Dan: There were a couple of reasons.

Firstly, I just like 'em. Yeah, I know, "taste" is a dodgy reason to do things, but when you're designing stuff like this, you need to do stuff that you're kinda fond of, and I was always comfortable working with register machines. Wrote more assembly than I care to think about for 6502 and 68000 family microprocessors. I liked them, was comfortable writing code for them by hand, so it was a good reason to design a register machine.

Second, there is a lot of literature out there for writing optimizers for register machines. All modern CPUs are register machines, and a lot of people have spent a lot of time figuring out how best to generate code for them. I knew that Parrot wouldn't be able to use it right away, but I was trying to plan for things in 2005, 2010, and 2020 when I started. (This was back in 2000)

Thirdly, register machines are generally more efficient than stack machines. Yeah you might see the bytecode look a little denser (which is certainly important) but there's an amazing amount of bookkeeping with a stack machine. There's an extra store for every opcode, which adds up. For example, storing 1 in register X is:


machine reg = regbase + x
store indirect 1
while a stack machine is:

machine reg = stackbase + 1
store indirect 1
store stackbase

Also on the efficiency front, stack operations are destructive, so something like:


x = x + 1
y = y + 1
requires putting that 1 on the stack twice — on a register machine you can reuse it, saving a full op. (This requires some intelligence on the part of the compiler, but it's actually a pretty simple optimization and easy for anyone past first year compiler construction to do.)

Fourthly, for JITting, we know we're targeting a register architecture — the CPU we're running on, which has registers. It's easy enough to do a naive stack VM -> native machine translation, but it's a stack transform, treating your register hardware as a stack machine, and that's inefficient. Doing a good JIT from a stack to register system is much tougher.

A register VM -> register machine translation is a lot easier. You can, of course, grab a register and use it as your 'vm register' base pointer, which is as naive as the stack transform above, but it's much simpler to get relatively efficient register machine code out of a register VM system, assuming some thought went into desinging the register VM. (Which it did.)

(The usual argument that "well, compilers build up a sort of stack-based intermediate representation before generating code" is interesting but bogus, since almost all the useful information in that intermediate representation is tossed away when the low-level stack ops are created.)

So that's basically it. One part taste, one part lots of free work to bootstrap on, and two parts efficiency.