#
# This file is in POD format; if you're not used to reading POD,
# you can run the file through "perldoc" for a plain text version.


=head1 TITLE

Parrot JIT Subsystem

=head1 VERSION

=head2 CURRENT

    Maintainer: Daniel Grunblatt 
    Class: Internals
    PDD Number: 8
    Version: 1.2
    Status: Developing
    Last Modified: 31 January 2002
    PDD Format: 1
    Language:English

=head1 ABSTRACT

This PDD describes the Parrot Just In Time compilation subsystem.

=head1 DESCRIPTION

The Just In Time, or JIT, subsystem converts a bytecode file to native machine
code instructions and executes the generated instruction sequence directly.

=head1 IMPLEMENTATION

Currently works on B<Intel x86>, B<ALPHA>, and B<SPARC version 8> processor
systems, on most operating systems.  Currently only 32-bit INTVALs are
supported.

The initial step in generating native code is to invoke B<Parrot_jit_begin>,
which generally provides architecture specific preamble code.  For each parrot
opcode in the bytecode, either a generic or opcode specific sequence of native
code is generated.  The B<.jit> files provide functions that generate native
code for specific opcode functions, for a given instruction set architecture.
If a function is not provided for a specific opcode, a generic sequence of
native code is output which calls the interpreter C function that implements
the opcode.  Such opcode are handled by B<Parrot_jit_normal_op>.

If the opcode can cause a control flow change, as in the case of a branch or
call opcode, an extended or modified version of this generic code is used that
tracks changes in the bytecode program counter with changes in the hardware
program counter.  This type of opcode is handled by B<Parrot_jit_cpcf_op>.

While generating native code, certain offsets and absolute addresses may not be
available.  This occurs with forward opcode branches, as the native code
corresponding to the branch target has not yet been generated.  On some
platforms, function calls are performed using program-counter relative
addresses.  Since the location of the buffer holding the native code may move
as code is generated (due to growing of the buffer), these relative addresses
may only be calculated once the buffer is guaranteed to no longer move.  To
handle these instances, the JIT subsystem uses "fixups", which record locations
in native code where adjustments to the native code are required. 

=head1 FILES

=over 4

=item jit/${jitcpuarch}/jit_emit.h

This file defines B<Parrot_jit_begin>, B<Parrot_jit_dofixup>,
B<Parrot_jit_normal_op> and B<Parrot_jit_cpcf_op>.  In addition, this file
defines the macros and static functions used in B<.jit> files to produce binary
representations of native instructions.

=item jit/${jitcpuarch}/core.jit

The functions to generate native code for core parrot opcodes are specified
here. To simplify the maintenance of these functions, they are specified in a
format that is pre-processed by B<jit2h.pl> to produce a valid C source file,
B<jit_cpu.c>. See L<Format of .jit Files> below.

=item jit/${jitcpuarch}/string.jit

The string subsystem.

=item include/parrot/jit.h

This file contains definitions of generic structures used by the JIT subsystem.

The B<op_jit> array of B<jit_fn_info_t> structures, provides for each opcode, a
pointer to the function that generates native code for the opcode, whether the
generic B<Parrot_jit_normal_op> or B<Parrot_jit_cpcf_op> functions or an opcode
specific function.

The B<Parrot_jit_fixup> structure records the offset in native code where a
fixup must be applied, the type of fixup required and the specific information
needed to perform the parameters of the fixup.  Currently, a fixup parameter is
either an B<opcode_t> value or a function pointer.

The B<Parrot_jit_info> structure holds data used while producing and executing
native code.  An important piece of data in this structure is the B<op_map>
array, which maps from opcode addresses to native code addresses.  

=item jit.c

B<build_asm>() is the main routine of the code generator, which loops over the
parrot bytecode, calling the code generating routines for each opcode while
filling in the B<op_map> array.  This array is used by the JIT subsystem to
perform certain types of fixups on native code, as well as by the native code
itself to convert bytecode program counters values (opcode_t *'s) to hardware
program counter values.

The bytecode is considered an array of B<opcode_t> sized elements, with
parallel entries in B<op_map>.  B<op_map> is initially populated with the
offsets into the native code corresponding to the opcodes in the bytecode.
Once code generation is complete and fixups have been applied, the native code
offsets are converted to absolute addresses.  This trades the low up-front cost
of converting all offsets once, for the unknown cost of repeatedly converting
these offsets while executing native code.
 
=item jit2h.pl

Preprocesses the .jit files to produce and prints the struct opcode_assembly_t.

=back


=head1 Format of .jit Files

Jit files are interpreted as follows:

=over 4

=item I<op-name> { I<body> }

Where I<op-name> is the name of the Parrot opcode, and I<body> consists of C
syntax code which may contain any of the identifiers listed in the following
section.

=item Identifiers

In general, prefixing an identifier with I<&> yields the address of the
referenced Parrot register or constant.  If an identifier is given without a
prefix, the value is returned by default.   To emphasis the use of the value,
the I<*> prefix may be used.  Since Parrot register values vary during code
execution, their values can not be obtained through identifier substitution
alone.

B<INT_REG[n]>

Gets replaced by the C<INTVAL> register specified in the I<n>th argument.

B<NUM_REG[n]>

Gets replaced by the C<FLOATVAL> register specified in the I<n>th argument.

B<STRING_REG[n]>

Gets replaced by the C<STRING> register specified in the I<n>th argument.

B<INT_CONST[n]>

Gets replaced by the C<INTVAL> constant specified in the I<n>th argument.

B<NUM_CONST[n]>

Gets replaced by the C<FLOATVAL> constant specified in the I<n>th argument.

B<STRING_CONST_strstart[n]>

Gets replaced by C<strstart> of the C<STRING> constant specified in the I<n>th argument.

B<STRING_CONST_buflen[n]>

Gets replaced by C<buflen> of the C<STRING> constant specified in the I<n>th argument.

B<STRING_CONST_flags[n]>

Gets replaced by C<flags> of the C<STRING> constant specified in the I<n>th argument.

B<STRING_CONST_strlen[n]>

Gets replaced by C<strlen> of the C<STRING> constant specified in the I<n>th argument.

B<STRING_CONST_encoding[n]>

Gets replaced by C<encoding> of the C<STRING> constant specified in the I<n>th argument.

B<STRING_CONST_type[n]>

Gets replaced by C<type> of the C<STRING> constant specified in the I<n>th argument.

B<STRING_CONST_language[n]>

Gets replaced by C<language> of the C<STRING> constant specified in the I<n>th argument.

B<CONST_INT[n]>

Gets replaced by the I<n>th integer constant defined in jit.c

B<CONST_FLOAT[n]>

Gets replaced by the I<n>th floatval constant defined in jit.c

B<CONST_CHAR[n]>

Gets replaced by the I<n>th char constant defined in jit.c

B<TEMP_INT[n]>

Gets replaced by the I<n>th temporary integer array.

B<TEMP_FLOAT[n]>

Gets replaced by the I<n>th temporary float array.

B<TEMP_CHAR[n]>

Gets replaced by the I<n>th temporary char array.

B<&INTERPRETER[n]>

Gets replaced by the address of the interpreter.

B<*CUR_OPCODE[n]>

Gets replaced by the address of the current opcode in the Parrot bytecode.

=item B<FUNC>(I<func-name>, I<arg1>, ..., I<argN>)

Call a function defined in another C<.jit> file (except from the core).

=item B<SYSTEM_CALL>(I<syscall-name>, I<arg1>, ..., I<argN>)

Call a system call.

=item B<CALL>(I<func-name>, I<arg1>, ..., I<argN>)

Call a C function. The idea is to replace all the B<CALL>() with B<FUNC>().

=item Arguments to CALL and SYSTEMCALL

The arguments to CALL and SYSTEMCALL must be preceeded by I<V> to indicate that the value should be taken as an immediate or I<A> to indicate that the value should be dereferenced.

=back

=head1 ALPHA Notes

The access to Parrot registers is done relative to C<$6>, all other memory access is done relative to C<$27>, to access float constants relative to C<$7> so you must preside the instruction with I<ldah $7,0($27)>.

=head1 EXAMPLE

Let's see how this work:

B<Parrot Assembly:>
 
 set I0,8
 set I2,I0
 print "Big piece of JIT\n"
 time I0
 end

B<Parrot Bytecode:> (only the bytecode segment is showed) 
 
 +-----------------------------------------------+
 | 63 | 0 | 8 | 62 | 2 | 0 | 24 | 0 | 48 | 0 | 0 |  
 +-|------------|------------|--------|--------|-+
   |            |            |        |        |
   |            |            |        |        +-- end (no arguments)
   |            |            |        +----------- time_i (1 argument)
   |            |            +-------------------- print_sc (1 argument)
   |            +--------------------------------- set_i_i (2 arguments)
   +---------------------------------------------- set_i_ic (2 arguments)

Please note that the opcode numbers used might have already changed.

B<Intel x86 assembly version of the Parrot ops:>

 Parrot_set_i_ic {
    movl *INT_CONST[2],&INT_REG[1]
 }

 Parrot_set_i_i {
    movl &INT_REG[2],%eax
    movl %eax,&INT_REG[1]
 }

 Parrot_print_sc {
    movl $1,&TEMP_INT[1]
    SYSTEMCALL(WRITE,3, A&TEMP_INT[1] V&STRING_CONST_strstart[1] V*STRING_CONST_strlen[1])
 }

 Parrot_end {
    leave
    ret
 }

Note that there is no Parrot_time_i so, the code generated by the C compiler for Parrot_time_i will be called.

B<Intel x86 object code of the Parrot ops:>

 Parrot_set_i_ic {
    \xc7\x05\x00\x00\x00\x00\x00\x00\x00\x00 # mov $0,0x0
 }

 Parrot_set_i_i {
    \xa1\x00\x00\x00\x00                     # mov 0x0,%eax
    \xa3\x00\x00\x00\x00                     # mov %eax,0x0
 }

 Parrot_print_sc {
    \xc7\x05\x00\x00\x00\x00\x01\x00\x00\x00 # mov $1,0x0
    \x68\x00\x00\x00\x00                     # push 0x0
    \x68\x00\x00\x00\x00                     # push 0x0
    \xff\x35\x00\x00\x00\x00                 # push $0
    \x50                                     # push 
    \xb8\x04\x00\x00\x00                     # mov $4,%eax
    \xcd\x80                                 # int 80h
    \x72\x00                                 # jb 0
 }

 Parrot_end {
    \xc9                                     # leave
    \xc3                                     # ret
 } 

 Parrot_time_i {
    \x68\x00\x00\x00\x00                     # pushl 0x0
    \x68\x00\x00\x00\x00                     # pushl 0x0
    \xe8\x00\x00\x00\x00                     # call 0x0
    \x83\xc4\x08                             # add $0x8,%esp
 }

The object code for time_i is the same that for any opcode that isn't implemented in core.jit 

B<Build process:>
 
 Memory dump of the JIT code being generated:

  +-----------------------------------------+
  | 0x55 0x89 0xe5 0xc7 0x05 0x00 0x00 0x00 |
  | 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 |
  +-----------------------------------------+

That is the state after the code for the first op has been copied. The B<0x55 0x89 0xe5> you see before the object code for Parrot_set_i_ic is the output of Parrot::Jit->init() 

 Fill it with addresses and/or values:

  +-----------------------------------------+
  | 0x55 0x89 0xe5 0xc7 0x05 0x00 0xa0 0x10 |
  | 0x00 0x08 0x00 0x00 0x00 0x00 0x00 0x00 |
  +-----------------------------------------+

The address of I0 (&intepreter->int_reg.registers[0]) is 0x10a000 (or whatever), so the first 4 bytes after the opcode number are filled with it, and the other contiguous 4 with the constant it self.

The same process is done one time per opcode.
 
 The final result:

  +-----------------------------------------+
  | 0x55 0x89 0xe5 0xc7 0x05 0x00 0xa0 0x10 |
  | 0x00 0x08 0x00 0x00 0x00 0xa1 0x00 0xa0 |
  | 0x10 0x00 0xa3 0x08 0xa0 0x10 0x00 0xc7 |
  | 0x05 0x54 0x7a 0x10 0x00 0x01 0x00 0x00 |
  | 0x00 0x68 0x11 0x00 0x00 0x00 0x68 0x18 | 
  | 0xb0 0x10 0x00 0xff 0x35 0x54 0x7a 0x10 |
  | 0x00 0x50 0xb8 0x04 0x00 0x00 0x00 0xcd |
  | 0x80 0x72 0x00 0x68 0x00 0xa0 0x10 0x00 |
  | 0x68 0xe0 0x60 0x12 0x00 0xe8 0xae 0xdb |
  | 0xed 0xff 0x83 0xc4 0x08 0xc9 0xc3 0x00 |
  +-----------------------------------------+

This code is ready to be called.

