Listen Print

Beginning PMCs

by Jeffrey Goff
January 30, 2002

One of the best things about Parrot is that it's not just for Perl implementors. Parrot 0.0.3 came with support for extensible data types that can be used to implement the types used in your favorite language. The mechanism by which these types are extensible is called the PMC.

The PMC, or Parrot Magic Cookie, type is a special data container for user-defined data types. Because these user-defined types are essentially implementations of a set of methods, we refer to them as PMC classes. Currently, the legal PMC classes are the PerlInt, PerlNum, PerlString, PerlArray, and PerlHash types. The PerlInt, PerlNum and PerlString data types combine to form the PerlScalar data type.

PMC registers, unlike the basic Integer, Number, and String registers, must be specially allocated with the new P0, PMCType instruction. Other operations like set P0,5 are handled by special functions that are implemented by the PMC class. The rest of this article is about how to create your own PMC class implementation, alongside the PerlInt and PerlHash data types.

For our example, we're going to implement a simple queue data structure. Our queue will be a set of integers; the queue will grow when an integer is assigned to it, and will shrink when an integer is read from it. We'll use the PerlInt class as a basis, so it may be helpful to look at some examples of operations that use it:

  new P0, PerlInt  # Create a new PMC in the 'PerlInt' class
  set P0, 1234     # Set the value of the PMC to 1234
  set P0, "4567"   # Set the value of the PMC to 4567
  set P0, 12.34    # Set the value of the PMC to 12
  set I0, P0       # Set I0 to the current value of the PMC
  print P0
  print "n"

Note that no special instructions like set_string or set_float were required to assign data of different types to the PMC. Each instruction does the Right Thing given the initial type of the PMC. This has several important consequences when designing new data types, the largest of which is that it generally isn't necessary to add special instructions to access data contained within a PMC.

On the other side, this means that PMCs should attempt to behave rationally in all situations. It's not an onerous requirement, but in some cases, rational behavior is hard to define. Queues are fairly simple to define though, in terms of behavior. A queue has one way to get data in and one way to get data out.

Since we can use one instruction for multiple classes, we'll use set Pn,In to add an integer to the queue, and set In,Pn to get an element out of the queue. The last operation we need to perform on a queue is to determine whether the queue is empty. The PerlArray class uses set In,Pn to return the length of the array into In, but we've already decided to use that to get an integer out of the queue.

Instead of set In,Pn to determine how many elements are in the queue, all we really need to know is whether the queue is empty or in use. For that, we can use the handy boolean operator, if Pn,In. Here, the integer register is actually the number of instructions to skip over if the condition is true. We'll have it branch if the queue is empty.

So, our IntQueue data type will implement three instructions. First, the set Pn,In instruction will add an integer to the queue. Second, when the queue is empty, if Pn,In will branch to the appropriate offset. Finally, set In,Pn will dequeue the last integer in the queue and place it into the appropriate integer register.

Some sample source using IntQueue may come in handy at this time:

  new P0, IntQueue   # Create the queue
  set P0, 7          # Enqueue 7
  set P0, -43        # Enqueue -43
  set I0, P0         # Dequeue 7
  print I0           # Should print '7'.
  if P0, QUEUE_emPTY # Goto label 'QUEUE_emPTY'

Core Operations

Before forging ahead with the IntQueue, let's take a look at the core operations file. Within your CVS tarball, open parrot/core.ops and search for the set operations. While there are files such as parrot/core_ops.c and parrot/Parrot/OpLib/core_ops.pm, this is the master file. Changes in parrot/core_ops.c will be overwritten the next time you build, so make your edits to parrot/core.ops.

Having said that, let's look at a sample PMC operation.

  inline op set(out PMC, in NUM) {
    $1->vtable->set_number(interpreter,$1,$2);
    goto NEXT();
  }

Since core.ops is split into a Perl and C source file, the syntax is, of necessity, a mixture of Perl and C. The 'inline' declaration is a hint to the JIT compiler, which is beyond the scope of the article. Parameters also have hints for the JIT compiler, but the most important bits here are the PMC and NUM tags, because these let the compiler know what types this operation can take.

When preprocessing into Perl, the prototype is the only piece of interest, as the assembler only needs to know the name and parameter list in order to build the assembly code.

C preprocessing is a bit more complicated, but still fairly straightforward. Tokens like $2 are replaced with the appropriate code to access the declared parameter, and a few keywords like NEXT() are replaced with code to return the next instruction in the stream.

With the exception of those tags, the rest of the code is pure C, with access to all of the Parrot internals. Of course, you shouldn't access such things as the register internals, but the rest of the C API is available, the most common APIs being located in parrot/include/parrot/string.h and parrot/include/parrot/key.h, the latter primarily being used for aggregate data structures.

The preprocessor, while slightly confusing, is much more flexible than the current system of nested CPP macros that Perl currently uses, and hopefully easier to understand.

Pages: 1, 2

Next Pagearrow





Contact Us | Advertise with Us | Privacy Policy | Press Center | Jobs | Submissions Guidelines

Copyright © 2000-2008 O’Reilly Media, Inc. All Rights Reserved. | (707) 827-7000 / (800) 998-9938
All trademarks and registered trademarks appearing on the O'Reilly Network are the property of their respective owners.

For problems or assistance with this site, email