Parrot Virtual Machine/Running Parrot

Running Parrot
Parrot can be run from the command line in a number of modes with a number of different options. There are three forms of input that Parrot can work with directly: Parrot Assembly Language (PASM), which is a low-level human readable assembly language for the virtual machine, Parrot Intermediate Representation (PIR) which is a syntactic overlay on PASM with nicer syntax for some expressions, and Parrot Bytecode (PBC) which is a compiled binary input format.

PIR and PASM are converted to PBC during normal execution. Only PBC can be executed by Parrot directly. The compilation stage to convert PIR or PASM to PBC takes some time, and can be done separately. We'll be talking about these processes a little later.

Parrot Information
To get information about the current Parrot version, type:

parrot -V

To get a list of command-line options and their purposes, type:

parrot -h

We'll discuss all the various command-line options later in this book, but it's always good to have multiple resources when a question pops up.

File Types
Files that end in  are treated as parrot bytecode files and are executed immediately. Files that end in  or   are treated as PIR or PASM source code files, respectively, and interpreted. To compile PIR or PASM into bytecode, use the  switch, as such:

parrot -o output.pbc input.pir

or

parrot -o output.pbc input.pasm

Notice that if we use a .pasm file extension, we can output to PASM instead of PBC:

parrot -o output.pasm input.pir

To force output of PBC even if the output file does not have a .pbc extension, use the  switch. To run the generated PBC file after you generate it, use the -r switch.

To force a file to be run as PASM regardless of the file extension, use the -a switch.

To force a file to be run as a PBC file, regardless of the file extension, use the -c switch.

Runtime Options
Parrot can operate with a number of additional options too.

Optimizations
Optimizations can take time to perform, but increase the execution speed of the resulting program. For simple programs, short and sloppy one-time programs, extensive optimizations might not make much sense. You would spend more time optimizing a piece of software then you even spend executing it. However, for programs which are run frequently, or for very large programs, or programs which must run continuously with good performance, optimizations can be a valuable thing. Compile a program once with optimizations, and the output optimized bytecode can be saved to disk, never needing to be optimized again (unless Parrot integrates better optimizations).

Parrot has multiple optimization options, depending on the extensiveness of the optimizations to be performed. Each can be activated using different commandline switches in the form  where the   is a character representing the type of optimization to perform:

Life info is an analysis step where code and data is traced to determine control flow patterns and lifetimes of local variables. Knowing the areas where certain variables are used and not used enables registers to be reused instead of having to allocate new ones. Knowing when certain code is unreachable enables the optimizer to ignore it completely.

Run Cores
The run core is the central loop of the Parrot program, and there are several different runcores available that specify the performance and capabilities of Parrot. Runcores determine how parrot executes the bytecode instructions that are passed into the interpreter. Runcores can perform certain tasks such as bounds-checking, testing, or debugging. Other runcores have been optimized to operate extremely quickly. Implementation details about the various cores can be found in.

Different cores can be activated by passing particular switches at the command-line. The sections below will discuss the various runcores, what they do, how they work, and how to activate them.

Slow Core
The default "slow" core treats all ops as individual C functions. Each function is called, and returns the address of the next instruction operation. Many cores, such as the tracing and debugging cores, are based on the slow core design.

Fast core
The fast core is a bare-bones core that does not perform any special operations such as tracing, debugging, or bounds-checking.

Computed Goto Core
Computed goto is a feature of some compilers that allows a  instruction to target a variable containing the address of a label, not necessarily directly to a label. By caching the addresses of all labels into an array, a jump can be made directly to the necessary instructions. This avoids the overhead of multiple subroutine calls, and can be very quick on platforms that support it. For more information about the workings of the computed-goto runcore, see the generated file.

Switch Core
The switch core uses the standard C  and   structure to select the next operation to run. At each iteration, a switch is performed, and each case represents one of the ops. After the op has been performed, control flow jumps back to the top of the switch and the cycle repeats.

Switch statements, especially those that use many consecutive values, are typically converted by the compiler into jump tables which perform very similarly to computed-goto jumps.

Variant Cores
The above cores are the basic designs upon which other specialized cores are based.

mod_parrot
Some members of the Parrot team have developed an extension for the Apache webserver that allows Parrot to be used to generate server-side content. The result of this work is, which can be used to produce web sites using PIR or PASM. This has limited usefulness by itself. However, mod_parrot allows the creation of additional modules for languages with compilers that target parrot. One notable module like this,  is a bytecode module that runs on top of mod_parrot.

More information about mod_parrot is available at its website: http://www.parrot.org/mod_parrot