Over the weekend I've been thinking about Targeting Parrot. My
thoughts went something like this: Parrot is a register machine. The
Java virtual machine is a stack machine. Parrot is also a stack
machine. Instead of converting Java bytecode to Parrot bytecode, I can
make Parrot into a JVM. And lo, so I did (for a small number of opcodes):

This is Java source code:

public static void spin() {
  int i;
  for(i = 0, i < 12345678; i++);
  System.out.print(i);
}

which turns into the following Java bytecode:

   0 iconst_0
   1 istore_0
   2 goto 8
   5 iinc 0 1
   8 iload_0
   9 sipush 1000
  12 if_icmplt 5
  15 getstatic #3 <Field java.io.PrintStream out>
  18 iload_0
  19 invokevirtual #4 <Method void print(int)>
  22 return

On a different VM, not so far away:

# This is Parrot assembler:
      iconst_0
      istore_0
      goto      IN
REDO: iinc      0, 1
IN:   iload_0
      sipush    12345678
      if_icmplt REDO
      iload_0
      jvm_print
      end

Cute, huh? Of course, Java interpreters are very optimised (and
non-dynamic) and without JITs doing it in Parrot is about 6 times
slower, but it's interesting nevertheless. Is this the kind of thing I
should be doing? I've attached a fledgling jvm.ops. Does my C code
look ok?

Leon
-- 
Leon Brocard.............................http://www.astray.com/
Nanoware...............................http://www.nanoware.org/

.... (c) The Intergalactic Thought Association
/*
** jvm.ops
*/

VERSION = PARROT_VERSION;

=head1 NAME

jvm.ops

=cut

=head1 DESCRIPTION

Library of ops for Parrot which resemble the JVM ops

=cut

###############################################################################

=head2 Basic ops

These are the fundamental operations.

=over 4

=cut

=item B<iadd>()

Pop two integers off the stack, add them together and push the result
on the stack.

=cut

op iadd() {
  INTVAL x, y;
  stack_pop(interpreter, interpreter->user_stack, &y, STACK_ENTRY_INT);
  stack_pop(interpreter, interpreter->user_stack, &x, STACK_ENTRY_INT);
  x = x + y;
  stack_push(interpreter, interpreter->user_stack, &x, STACK_ENTRY_INT, 
STACK_CLEANUP_NULL);
  goto NEXT();
}

op iconst_0() {
  INTVAL x = 0;
  stack_push(interpreter, interpreter->user_stack, &x, STACK_ENTRY_INT, 
STACK_CLEANUP_NULL);
  goto NEXT();
}

op iconst_1() {
  INTVAL x = 1;
  stack_push(interpreter, interpreter->user_stack, &x, STACK_ENTRY_INT, 
STACK_CLEANUP_NULL);
  goto NEXT();
}

op sipush(in INT) {
  INTVAL i = $1;
  stack_push(interpreter, interpreter->user_stack, &i, STACK_ENTRY_INT, 
STACK_CLEANUP_NULL);
  goto NEXT();
}

op iload_0() {
  INTVAL i = interpreter->int_reg.registers[0];
  stack_push(interpreter, interpreter->user_stack, &i, STACK_ENTRY_INT, 
STACK_CLEANUP_NULL);
  goto NEXT();
}

op istore_0() {
  INTVAL i;
  stack_pop(interpreter, interpreter->user_stack, &i, STACK_ENTRY_INT);
  interpreter->int_reg.registers[0] = i;
  goto NEXT();
}

op jvm_print() {
  INTVAL i;
  stack_pop(interpreter, interpreter->user_stack, &i, STACK_ENTRY_INT);
  printf(INTVAL_FMT, (INTVAL)i);
  goto NEXT();
}

op iinc(in INT, in INT) {
  interpreter->int_reg.registers[$1] += $2;
  goto NEXT();
}

op if_icmplt(inconst INT) {
  INTVAL x, y;
  stack_pop(interpreter, interpreter->user_stack, &y, STACK_ENTRY_INT);
  stack_pop(interpreter, interpreter->user_stack, &x, STACK_ENTRY_INT);
  if (x < y) {
    goto OFFSET($1);
  }
  goto NEXT();
}

op goto (in INT) {
  goto OFFSET($1);
}

Reply via email to