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