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);
}