2004-11-08 Ben Maurer <bmaurer@ximian.com>
[mono-project.git] / docs / mini-porting.txt
blob7cf14775b1d1d659e99e864ceeab253515ef0733
1                        Mono JIT porting guide.
2                    Paolo Molaro (lupus@ximian.com)
4 * Introduction
6         This documents describes the process of porting the mono JIT
7         to a new CPU architecture. The new mono JIT has been designed
8         to make porting easier though at the same time enable the port
9         to take full advantage from the new architecture features and
10         instructions. Knowledge of the mini architecture (described in
11         the mini-doc.txt file) is a requirement for understanding this
12         guide, as well as an earlier document about porting the mono
13         interpreter (available on the web site).
14         
15         There are six main areas that a port needs to implement to
16         have a fully-functional JIT for a given architecture:
17         
18                 1) instruction selection
19                 2) native code emission
20                 3) call conventions and register allocation
21                 4) method trampolines
22                 5) exception handling
23                 6) minor helper methods
24         
25         To take advantage of some not-so-common processor features
26         (for example conditional execution of instructions as may be
27         found on ARM or ia64), it may be needed to develop an
28         high-level optimization, but doing so is not a requirement for
29         getting the JIT to work.
30         
31         We'll see in more details each of the steps required, note,
32         though, that a new port may just as well start from a
33         cut&paste of an existing port to a similar architecture (for
34         example from x86 to amd64, or from powerpc to sparc).
35         
36         The architecture specific code is split from the rest of the
37         JIT, for example the x86 specific code and data is all
38         included in the following files in the distribution:
39         
40                 mini-x86.h mini-x86.c
41                 inssel-x86.brg
42                 cpu-pentium.md
43                 tramp-x86.c 
44                 exceptions-x86.c 
45         
46         I suggest a similar split for other architectures as well.
47         
48         Note that this document is still incomplete: some sections are
49         only sketched and some are missing, but the important info to
50         get a port going is already described.
53 * Architecture-specific instructions and instruction selection.
55         The JIT already provides a set of instructions that can be
56         easily mapped to a great variety of different processor
57         instructions.  Sometimes it may be necessary or advisable to
58         add a new instruction that represent more closely an
59         instruction in the architecture.  Note that a mini instruction
60         can be used to represent also a short sequence of CPU
61         low-level instructions, but note that each instruction
62         represents the minimum amount of code the instruction
63         scheduler will handle (i.e., the scheduler won't schedule the
64         instructions that compose the low-level sequence as individual
65         instructions, but just the whole sequence, as an indivisible
66         block).
68         New instructions are created by adding a line in the
69         mini-ops.h file, assigning an opcode and a name. To specify
70         the input and output for the instruction, there are two
71         different places, depending on the context in which the
72         instruction gets used.
74         If the instruction is used in the tree representation, the
75         input and output types are defined by the BURG rules in the
76         *.brg files (the usual non-terminals are 'reg' to represent a
77         normal register, 'lreg' to represent a register or two that
78         hold a 64 bit value, freg for a floating point register).
80         If an instruction is used as a low-level CPU instruction, the
81         info is specified in a machine description file. The
82         description file is processed by the genmdesc program to
83         provide a data structure that can be easily used from C code
84         to query the needed info about the instruction.
86         As an example, let's consider the add instruction for both x86
87         and ppc:
88         
89         x86 version:
90                 add: dest:i src1:i src2:i len:2 clob:1
91         ppc version:
92                 add: dest:i src1:i src2:i len:4
93         
94         Note that the instruction takes two input integer registers on
95         both CPU, but on x86 the first source register is clobbered
96         (clob:1) and the length in bytes of the instruction differs.
98         Note that integer adds and floating point adds use different
99         opcodes, unlike the IL language (64 bit add is done with two
100         instructions on 32 bit architectures, using a add that sets
101         the carry and an add with carry).
103         A specific CPU port may assign any meaning to the clob field
104         for an instruction since the value will be processed in an
105         arch-specific file anyway.
107         See the top of the existing cpu-pentium.md file for more info
108         on other fields: the info may or may not be applicable to a
109         different CPU, in this latter case the info can be ignored.
111         The code in mini.c together with the BURG rules in inssel.brg,
112         inssel-float.brg and inssel-long32.brg provides general
113         purpose mappings from the tree representation to a set of
114         instructions that should be easily implemented in any
115         architecture.  To allow for additional arch-specific
116         functionality, an arch-specific BURG file can be used: in this
117         file arch-specific instructions can be selected that provide
118         better performance than the general instructions or that
119         provide functionality that is needed by the JIT but that
120         cannot be expressed in a general enough way.
121         
122         As an example, x86 has the special instruction "push" to make
123         it easier to implement the default call convention (passing
124         arguments on the stack): almost all the other architectures
125         don't have such an instruction (and don't need it anyway), so
126         we added a special rule in the inssel-x86.brg file for it.
127         
128         So, one of the first things needed in a port is to write a
129         cpu-$(arch).md machine description file and fill it with the
130         needed info. As a start, only a few instructions can be
131         specified, like the ones required to do simple integer
132         operations. The default rules of the instruction selector will
133         emit the common instructions and so we're ready to go for the
134         next step in porting the JIT.
135         
137 *) Native code emission
139         Since the first step in porting mono to a new CPU is to port
140         the interpreter, there should be already a file that allows
141         the emission of binary native code in a buffer for the
142         architecture. This file should be placed in the
144                 mono/arch/$(arch)/
146         directory.
148         The bulk of the code emission happens in the mini-$(arch).c
149         file, in a function called mono_arch_output_basic_block
150         (). This function takes a basic block, walks the list of
151         instructions in the block and emits the binary code for each.
152         Optionally a peephole optimization pass is done on the basic
153         block, but this can be left for later, when the port actually
154         works.
156         This function is very simple, there is just a big switch on
157         the instruction opcode and in the corresponding case the
158         functions or macros to emit the binary native code are
159         used. Note that in this function the lengths of the
160         instructions are used to determine if the buffer for the code
161         needs enlarging.
162         
163         To complete the code emission for a method, a few other
164         functions need implementing as well:
165         
166                 mono_arch_emit_prolog ()
167                 mono_arch_emit_epilog ()
168                 mono_arch_patch_code ()
169         
170         mono_arch_emit_prolog () will emit the code to setup the stack
171         frame for a method, optionally call the callbacks used in
172         profiling and tracing, and move the arguments to their home
173         location (in a caller-save register if the variable was
174         allocated to one, or in a stack location if the argument was
175         passed in a volatile register and wasn't allocated a
176         non-volatile one). caller-save registers used by the function
177         are saved in the prolog as well.
178         
179         mono_arch_emit_epilog () will emit the code needed to return
180         from the function, optionally calling the profiling or tracing
181         callbacks. At this point the basic blocks or the code that was
182         moved out of the normal flow for the function can be emitted
183         as well (this is usually done to provide better info for the
184         static branch predictor).  In the epilog, caller-save
185         registers are restored if they were used.
187         Note that, to help exception handling and stack unwinding,
188         when there is a transition from managed to unmanaged code,
189         some special processing needs to be done (basically, saving
190         all the registers and setting up the links in the Last Managed
191         Frame structure).
192         
193         When the epilog has been emitted, the upper level code
194         arranges for the buffer of memory that contains the native
195         code to be copied in an area of executable memory and at this
196         point, instructions that use relative addressing need to be
197         patched to have the right offsets: this work is done by
198         mono_arch_patch_code ().
201 * Call conventions and register allocation
203         To account for the differences in the call conventions, a few functions need to
204         be implemented.
205         
206         mono_arch_allocate_vars () assigns to both arguments and local
207         variables the offset relative to the frame register where they
208         are stored, dead variables are simply discarded. The total
209         amount of stack needed is calculated.
210         
211         mono_arch_call_opcode () is the function that more closely
212         deals with the call convention on a given system. For each
213         argument to a function call, an instruction is created that
214         actually puts the argument where needed, be it the stack or a
215         specific register. This function can also re-arrange th order
216         of evaluation when multiple arguments are involved if needed
217         (like, on x86 arguments are pushed on the stack in reverse
218         order). The function needs to carefully take into accounts
219         platform specific issues, like how structures are returned as
220         well as the differences in size and/or alignment of managed
221         and corresponding unmanaged structures.
222         
223         The other chunk of code that needs to deal with the call
224         convention and other specifics of a CPU, is the local register
225         allocator, implemented in a function named
226         mono_arch_local_regalloc (). The local allocator deals with a
227         basic block at a time and basically just allocates registers
228         for temporary values during expression evaluation, spilling
229         and unspilling as necessary.
231         The local allocator needs to take into account clobbering
232         information, both during simple instructions and during
233         function calls and it needs to deal with other
234         architecture-specific weirdnesses, like instructions that take
235         inputs only in specific registers or output only is some.
237         Some effort will be put later in moving most of the local
238         register allocator to a common file so that the code can be
239         shared more for similar, risc-like CPUs.  The register
240         allocator does a first pass on the instructions in a block,
241         collecting liveness information and in a backward pass on the
242         same list performs the actual register allocation, inserting
243         the instructions needed to spill values, if necessary.
244         
245         When this part of code is implemented, some testing can be
246         done with the generated code for the new architecture. Most
247         helpful is the use of the --regression command line switch to
248         run the regression tests (basic.cs, for example).
250         Note that the JIT will try to initialize the runtime, but it
251         may not be able yet to compile and execute complex code:
252         commenting most of the code in the mini_init() function in
253         mini.c is needed to let the JIT just compile the regression
254         tests.  Also, using multiple -v switches on the command line
255         makes the JIT dump an increasing amount of information during
256         compilation.
257         
258         
259 * Method trampolines
261         To get better startup performance, the JIT actually compiles a
262         method only when needed. To achieve this, when a call to a
263         method is compiled, we actually emit a call to a magic
264         trampoline. The magic trampoline is a function written in
265         assembly that invokes the compiler to compile the given method
266         and jumps to the newly compiled code, ensuring the arguments
267         it received are passed correctly to the actual method.
269         Before jumping to the new code, though, the magic trampoline
270         takes care of patching the call site so that next time the
271         call will go directly to the method instead of the
272         trampoline. How does this all work?
274         mono_arch_create_jit_trampoline () creates a small function
275         that just preserves the arguments passed to it and adds an
276         additional argument (the method to compile) before calling the
277         generic trampoline. This small function is called the specific
278         trampoline, because it is method-specific (the method to
279         compile is hard-code in the instruction stream).
281         The generic trampoline saves all the arguments that could get
282         clobbered and calls a C function that will do two things:
283         
284         *) actually call the JIT to compile the method
285         *) identify the calling code so that it can be patched to call directly
286         the actual method
287         
288         If the 'this' argument to a method is a boxed valuetype that
289         is passed to a method that expects just a pointer to the data,
290         an additional unboxing trampoline will need to be inserted as
291         well.
292         
294 * Exception handling
296         Exception handling is likely the most difficult part of the
297         port, as it needs to deal with unwinding (both managed and
298         unmanaged code) and calling catch and filter blocks. It also
299         needs to deal with signals, because mono takes advantage of
300         the MMU in the CPU and of the operation system to handle
301         dereferences of the NULL pointer. Some of the function needed
302         to implement the mechanisms are:
303         
304         mono_arch_get_throw_exception () returns a function that takes
305         an exception object and invokes an arch-specific function that
306         will enter the exception processing.  To do so, all the
307         relevant registers need to be saved and passed on.
308         
309         mono_arch_handle_exception () this function takes the
310         exception thrown and a context that describes the state of the
311         CPU at the time the exception was thrown. The function needs
312         to implement the exception handling mechanism, so it makes a
313         search for an handler for the exception and if none is found,
314         it follows the unhandled exception path (that can print a
315         trace and exit or just abort the current thread). The
316         difficulty here is to unwind the stack correctly, by restoring
317         the register state at each call site in the call chain,
318         calling finally, filters and handler blocks while doing so.
319         
320         As part of exception handling a couple of internal calls need
321         to be implemented as well.
323         ves_icall_get_frame_info () returns info about a specific
324         frame.
326         mono_jit_walk_stack () walks the stack and calls a callback with info for
327         each frame found.
329         ves_icall_get_trace () return an array of StackFrame objects.
330         
331 ** Code generation for filter/finally handlers
333         Filter and finally handlers are called from 2 different locations:
334         
335                1.) from within the method containing the exception clauses
336                2.) from the stack unwinding code
337         
338         To make this possible we implement them like subroutines,
339         ending with a "return" statement. The subroutine does not save
340         the base pointer, because we need access to the local
341         variables of the enclosing method. Its is possible that
342         instructions inside those handlers modify the stack pointer,
343         thus we save the stack pointer at the start of the handler,
344         and restore it at the end. We have to use a "call" instruction
345         to execute such finally handlers.
346         
347         The MIR code for filter and finally handlers looks like:
348         
349             OP_START_HANDLER
350             ...
351             OP_END_FINALLY | OP_ENDFILTER(reg)
352         
353         OP_START_HANDLER: should save the stack pointer somewhere
354         OP_END_FINALLY: restores the stack pointers and returns.
355         OP_ENDFILTER (reg): restores the stack pointers and returns the value in "reg".
356         
357 ** Calling finally/filter handlers 
359         There is a special opcode to call those handler, its called
360         OP_CALL_HANDLER. It simple emits a call instruction.
361         
362         Its a bit more complex to call handler from outside (in the
363         stack unwinding code), because we have to restore the whole
364         context of the method first. After that we simply emit a call
365         instruction to invoke the handler. Its usually possible to use
366         the same code to call filter and finally handlers (see
367         arch_get_call_filter).
368         
369 ** Calling catch handlers
371         Catch handlers are always called from the stack unwinding
372         code. Unlike finally clauses or filters, catch handler never
373         return. Instead we simply restore the whole context, and
374         restart execution at the catch handler.
375         
376 ** Passing Exception objects to catch handlers and filters.
378         We use a local variable to store exception objects. The stack
379         unwinding code must store the exception object into this
380         variable before calling catch handler or filter.
381         
382 * Minor helper methods
384         A few minor helper methods are referenced from the arch-independent code.
385         Some of them are:
386         
387         *) mono_arch_cpu_optimizations ()
388                 This function returns a mask of optimizations that
389                 should be enabled for the current CPU and a mask of
390                 optimizations that should be excluded, instead.
391         
392         *) mono_arch_regname ()
393                 Returns the name for a numeric register.
394         
395         *) mono_arch_get_allocatable_int_vars ()
396                 Returns a list of variables that can be allocated to
397                 the integer registers in the current architecture.
398         
399         *) mono_arch_get_global_int_regs ()
400                 Returns a list of caller-save registers that can be
401                 used to allocate variables in the current method.
402         
403         *) mono_arch_instrument_mem_needs ()
404         *) mono_arch_instrument_prolog ()
405         *) mono_arch_instrument_epilog ()
406                 Functions needed to implement the profiling interface.
407         
408         
409 * Writing regression tests
411         Regression tests for the JIT should be written for any bug
412         found in the JIT in one of the *.cs files in the mini
413         directory. Eventually all the operations of the JIT should be
414         tested (including the ones that get selected only when some
415         specific optimization is enabled).
416         
418 * Platform specific optimizations
420         An example of a platform-specific optimization is the peephole
421         optimization: we look at a small window of code at a time and
422         we replace one or more instructions with others that perform
423         better for the given architecture or CPU.
424         
425 * 64 bit support tips, by Zoltan Varga (vargaz@gmail.com)
427         For a 64-bit port of the Mono runtime, you will typically do
428         the following:
430                 * need to use inssel-long.brg instead of
431                   inssel-long32.brg.
433                 * need to implement lots of new opcodes:
434                        OP_I<OP> is 32 bit op
435                        OP_L<OP> and CEE_<OP> are 64 bit ops
438         The 64 bit version of an existing port might share the code
439         with the 32 bit port (for example SPARC/SPARV9), or it might
440         be separate (x86/AMD64).  
442         That will depend on the similarities of the two instructions
443         sets/ABIs etc.
445         The runtime and most parts of the JIT are 64 bit clean
446         at this point, so the only parts which require changing are
447         the arch dependent files.
451