Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorMiguel de Icaza <miguel@gnome.org>2009-04-22 22:22:37 +0400
committerMiguel de Icaza <miguel@gnome.org>2009-04-22 22:22:37 +0400
commit1f781d02dc9d52b625e83691e2a05c20ba4167ec (patch)
tree2ebd6ccc34cc9961fe836cb55446b26a56974d9a /docs
parent87f46ffb330520d02a06b77efb1db0c447b6cf3d (diff)
Move two other documents to the Wiki
svn path=/trunk/mono/; revision=132386
Diffstat (limited to 'docs')
-rw-r--r--docs/generic-sharing223
-rw-r--r--docs/mini-porting.txt531
2 files changed, 0 insertions, 754 deletions
diff --git a/docs/generic-sharing b/docs/generic-sharing
deleted file mode 100644
index a3bc994ba18..00000000000
--- a/docs/generic-sharing
+++ /dev/null
@@ -1,223 +0,0 @@
--*- outline -*-
-
-Generic code sharing
-====================
-
-* Porting
-
-** Generic class init trampoline
-
-The generic class init trampoline is very similar to the class init
-trampoline, with the exception that the VTable of the class to be
-inited is passed in a register, MONO_ARCH_VTABLE_REG. That register
-can be the same as the IMT register.
-
-The call to the generic class init trampoline is never patched because
-the VTable is not constant - it depends on the type arguments of the
-class/method doing the call to the trampoline. For that reason, the
-trampoline needs a fast path for the case that the class is already
-inited, i.e. the trampoline needs to check the initialized bit of the
-MonoVTable and immediately return if it is set. See tramp-x86.c for
-how to portably figure out the number of the bit in the bit-field that
-needs to be checked.
-
-Since the MONO_ARCH_VTABLE_REG is needed by the generic class init
-trampoline function (in mini-trampolines.c) it needs to be saved by
-the generic trampoline code in the register save block which is passed
-to the trampoline. This also applies to the RGCTX fetch trampoline
-(see below).
-
-Like the normal class init trampoline, the result of the generic class
-init trampoline function is not a pointer to code that needs to be
-jumped to. Instead, just like for the class init trampoline, the
-generic trampoline code must return to the caller instead of jumping
-to the returned value. The same applies for the RGCTX fetch
-trampoline (see below).
-
-** RGCTX register
-
-Generic shared code needs access to type information. This
-information is contained in a RGCTX for non-generic methods and in an
-MRGCTX for generic methods. It is passed in one of several ways,
-depending on the type of the called method:
-
- 1. Non-generic non-static methods of reference types have access to
- the RGCTX via the "this" argument (this->vtable->rgctx).
-
- 2. Non-generic static methods of reference types and non-generic
- methods of value types need to be passed a pointer to the
- caller's class's VTable in the MONO_ARCH_RGCTX_REG register.
-
- 3. Generic methods need to be passed a pointer to the MRGCTX in the
- MONO_ARCH_RGCTX_REG register.
-
-The MONO_ARCH_RGCTX_REG must not be clobbered by trampolines.
-
-MONO_ARCH_RGCTX_REG can be the same as the IMT register for now, but
-this might change in the future when we implement virtual generic
-method calls (more) efficiently.
-
-This register lifetime starts at the call site that loads it and
-ends in the callee prologue when it is either discarded or stored
-into a local variable.
-
-It's better to avoid registers used for argument passing for the RGCTX
-as it would make the code dealing with calling conventions code a lot
-harder.
-
-** Method prologue
-
-Generic shared code that have a RGCTX receive it in RGCTX_REG. There
-must be a check in mono_arch_emit_prolog for MonoCompile::rgctx_var
-and if set store it. See mini-x86.c for reference.
-
-** Dealing with types
-
-Types passed to arch functions might be type parameters
-(MONO_TYPE_(M)VAR) if the MonoGenericSharingContext* argument is
-non-NULL. For example, an argument or return type in a method passed
-to mono_arch_find_this_argument() could be a MONO_TYPE_VAR. To guard
-for that case use mini_get_basic_type_from_generic() on the type. See
-get_call_info() in mini-x86.c, for example.
-
-** (M)RGCTX lazy fetch trampoline
-
-The purpose of the lazy fetch trampoline is to fetch a slot from an
-(M)RGCTX which might not be inited, yet. In the latter case, it needs
-to go make a transition to unmanaged code to fill the slot. This is
-the layout of a RGCTX:
-
- +---------------------------------+
- | next | slot 0 | slot 1 | slot 2 |
- +--|------------------------------+
- |
- +-----+
- | +---------------------------------
- +->| next | slot 3 | slot 4 | slot 5 ....
- +--|------------------------------
- |
- +-----+
- | +------------------------------------
- +->| next | slot 10 | slot 11 | slot 12 ....
- +--|---------------------------------
- .
- .
- .
-
-For fetching a slot from a RGCTX the trampoline is passed a pointer
-(as a normal integer argument) to the VTable. From there it has to
-fetch the pointer to the RGCTX, which might be null. Then it has to
-traverse the correct number of "next" links, each of which might be
-NULL. Arriving at the right array it needs to fetch the slot, which
-might also be NULL. If any of the NULL cases, the trampoline must
-transition to unmanaged code to potentially setup the RGCTX and fill
-the slot. Here is pseudo-code for fetching slot 11:
-
- ; vtable ptr in r1
- ; fetch RGCTX array 0
- r2 = *(r1 + offsetof(MonoVTable, runtime_generic_context))
- if r2 == NULL goto unmanaged
- ; fetch RGCTX array 1
- r2 = *r2
- if r2 == NULL goto unmanaged
- ; fetch RGCTX array 2
- r2 = *r2
- if r2 == NULL goto unmanaged
- ; fetch slot 11
- r2 = *(r2 + 2 * sizeof (gpointer))
- if r2 == NULL goto unmanaged
- return r2
- unmanaged:
- jump unmanaged_fetch_code
-
-The number of slots in the arrays must be obtained from the function
-mono_class_rgctx_get_array_size().
-
-The MRGCTX case is different in two aspects. First, the trampoline is
-not passed a pointer to a VTable, but a pointer directly to the
-MRGCTX, which is guaranteed not to be NULL (any of the next pointers
-and any of the slots can be NULL, though). Second, the layout of the
-first array is slightly different, in that the first two slots are
-occupied by a pointers to the class's VTable and to the method's
-method_inst. The next pointer is in the third slot and the first
-actual slot, "slot 0", in the fourth:
-
- +--------------------------------------------------------+
- | vtable | method_inst | next | slot 0 | slot 1 | slot 2 |
- +-------------------------|------------------------------+
- .
- .
-
-All other arrays have the same layout as the RGCTX ones, except
-possibly for their length.
-
-The function to create the trampoline,
-mono_arch_create_rgctx_lazy_fetch_trampoline(), gets passed an encoded
-slot number. Use the macro MONO_RGCTX_SLOT_IS_MRGCTX to query whether
-a trampoline for an MRGCTX is needed, as opposed to one for a RGCTX.
-Use MONO_RGCTX_SLOT_INDEX to get the index of the slot (like 2 for
-"slot 2" as above).
-
-The unmanaged fetch code is yet another trampoline created via
-mono_arch_create_specific_trampoline(), of type
-MONO_TRAMPOLINE_RGCTX_LAZY_FETCH. It's given the slot number as the
-trampoline argument. In addition, the pointer to the VTable/MRGCTX is
-passed in MONO_ARCH_VTABLE_REG (like the VTable to the generic class
-init trampoline - see above).
-
-Like the class init and generic class init trampolines, the RGCTX
-fetch trampoline code doesn't return code that must be jumped to, so,
-like for those trampolines (see above), the generic trampoline code
-must do a normal return instead.
-
-
-* Getting generics information about a stack frame
-
-If a method is compiled with generic sharing, its MonoJitInfo has
-has_generic_jit_info set. In that case, the MonoJitInfo is followed
-(after the MonoJitExceptionInfo array) by a MonoGenericJitInfo.
-
-The MonoGenericJitInfo contains information about the location of the
-this/vtable/MRGCTX variable, if the has_this flag is set. If that is
-the case, there are two possibilities:
-
- 1. this_in_reg is set. this_reg is the number of the register where
- the variable is stored.
-
- 2. this_in_reg is not set. The variable is stored at offset
- this_offset from the address in the register with number
- this_reg.
-
-The variable can either point to the "this" object, to a vtable or to
-an MRGCTX:
-
- 1. If the method is a non-generic non-static method of a reference
- type, the variable points to the "this" object.
-
- 2. If the method is a non-generic static method or a non-generic
- method of a value type, the variable points to the vtable of the
- class.
-
- 3. If the method is a generic method, the variable points to the
- MRGCTX of the method.
-
-
-* Layout of the MRGCTX
-
-The MRGCTX is a structure that starts with
-MonoMethodRuntimeGenericContext, which contains a pointer to the
-vtable of the class and a pointer to the MonoGenericInst with the type
-arguments for the method.
-
-
-* Blog posts about generic code sharing
-
-http://schani.wordpress.com/2007/09/22/generics-sharing-in-mono/
-http://schani.wordpress.com/2007/10/12/the-trouble-with-shared-generics/
-http://schani.wordpress.com/2007/10/15/a-quick-generics-sharing-update/
-http://schani.wordpress.com/2008/01/29/other-types/
-http://schani.wordpress.com/2008/02/25/generic-types-are-lazy/
-http://schani.wordpress.com/2008/03/10/sharing-static-methods/
-http://schani.wordpress.com/2008/04/22/sharing-everything-and-saving-memory/
-http://schani.wordpress.com/2008/06/02/sharing-generic-methods/
-http://schani.wordpress.com/2008/06/27/another-generic-sharing-update/
diff --git a/docs/mini-porting.txt b/docs/mini-porting.txt
deleted file mode 100644
index e629aff8df7..00000000000
--- a/docs/mini-porting.txt
+++ /dev/null
@@ -1,531 +0,0 @@
- Mono JIT porting guide.
- Paolo Molaro (lupus@ximian.com)
-
-* Introduction
-
- This documents describes the process of porting the mono JIT
- to a new CPU architecture. The new mono JIT has been designed
- to make porting easier though at the same time enable the port
- to take full advantage from the new architecture features and
- instructions. Knowledge of the mini architecture (described in
- the mini-doc.txt file) is a requirement for understanding this
- guide, as well as an earlier document about porting the mono
- interpreter (available on the web site).
-
- There are six main areas that a port needs to implement to
- have a fully-functional JIT for a given architecture:
-
- 1) instruction selection
- 2) native code emission
- 3) call conventions and register allocation
- 4) method trampolines
- 5) exception handling
- 6) minor helper methods
-
- To take advantage of some not-so-common processor features
- (for example conditional execution of instructions as may be
- found on ARM or ia64), it may be needed to develop an
- high-level optimization, but doing so is not a requirement for
- getting the JIT to work.
-
- We'll see in more details each of the steps required, note,
- though, that a new port may just as well start from a
- cut&paste of an existing port to a similar architecture (for
- example from x86 to amd64, or from powerpc to sparc).
-
- The architecture specific code is split from the rest of the
- JIT, for example the x86 specific code and data is all
- included in the following files in the distribution:
-
- mini-x86.h mini-x86.c
- inssel-x86.brg
- cpu-pentium.md
- tramp-x86.c
- exceptions-x86.c
-
- I suggest a similar split for other architectures as well.
-
- Note that this document is still incomplete: some sections are
- only sketched and some are missing, but the important info to
- get a port going is already described.
-
-
-* Architecture-specific instructions and instruction selection.
-
- The JIT already provides a set of instructions that can be
- easily mapped to a great variety of different processor
- instructions. Sometimes it may be necessary or advisable to
- add a new instruction that represent more closely an
- instruction in the architecture. Note that a mini instruction
- can be used to represent also a short sequence of CPU
- low-level instructions, but note that each instruction
- represents the minimum amount of code the instruction
- scheduler will handle (i.e., the scheduler won't schedule the
- instructions that compose the low-level sequence as individual
- instructions, but just the whole sequence, as an indivisible
- block).
-
- New instructions are created by adding a line in the
- mini-ops.h file, assigning an opcode and a name. To specify
- the input and output for the instruction, there are two
- different places, depending on the context in which the
- instruction gets used.
-
- If the instruction is used in the tree representation, the
- input and output types are defined by the BURG rules in the
- *.brg files (the usual non-terminals are 'reg' to represent a
- normal register, 'lreg' to represent a register or two that
- hold a 64 bit value, freg for a floating point register).
-
- If an instruction is used as a low-level CPU instruction, the
- info is specified in a machine description file. The
- description file is processed by the genmdesc program to
- provide a data structure that can be easily used from C code
- to query the needed info about the instruction.
-
- As an example, let's consider the add instruction for both x86
- and ppc:
-
- x86 version:
- add: dest:i src1:i src2:i len:2 clob:1
- ppc version:
- add: dest:i src1:i src2:i len:4
-
- Note that the instruction takes two input integer registers on
- both CPU, but on x86 the first source register is clobbered
- (clob:1) and the length in bytes of the instruction differs.
-
- Note that integer adds and floating point adds use different
- opcodes, unlike the IL language (64 bit add is done with two
- instructions on 32 bit architectures, using a add that sets
- the carry and an add with carry).
-
- A specific CPU port may assign any meaning to the clob field
- for an instruction since the value will be processed in an
- arch-specific file anyway.
-
- See the top of the existing cpu-pentium.md file for more info
- on other fields: the info may or may not be applicable to a
- different CPU, in this latter case the info can be ignored.
-
- The code in mini.c together with the BURG rules in inssel.brg,
- inssel-float.brg and inssel-long32.brg provides general
- purpose mappings from the tree representation to a set of
- instructions that should be easily implemented in any
- architecture. To allow for additional arch-specific
- functionality, an arch-specific BURG file can be used: in this
- file arch-specific instructions can be selected that provide
- better performance than the general instructions or that
- provide functionality that is needed by the JIT but that
- cannot be expressed in a general enough way.
-
- As an example, x86 has the special instruction "push" to make
- it easier to implement the default call convention (passing
- arguments on the stack): almost all the other architectures
- don't have such an instruction (and don't need it anyway), so
- we added a special rule in the inssel-x86.brg file for it.
-
- So, one of the first things needed in a port is to write a
- cpu-$(arch).md machine description file and fill it with the
- needed info. As a start, only a few instructions can be
- specified, like the ones required to do simple integer
- operations. The default rules of the instruction selector will
- emit the common instructions and so we're ready to go for the
- next step in porting the JIT.
-
-
-*) Native code emission
-
- Since the first step in porting mono to a new CPU is to port
- the interpreter, there should be already a file that allows
- the emission of binary native code in a buffer for the
- architecture. This file should be placed in the
-
- mono/arch/$(arch)/
-
- directory.
-
- The bulk of the code emission happens in the mini-$(arch).c
- file, in a function called mono_arch_output_basic_block
- (). This function takes a basic block, walks the list of
- instructions in the block and emits the binary code for each.
- Optionally a peephole optimization pass is done on the basic
- block, but this can be left for later, when the port actually
- works.
-
- This function is very simple, there is just a big switch on
- the instruction opcode and in the corresponding case the
- functions or macros to emit the binary native code are
- used. Note that in this function the lengths of the
- instructions are used to determine if the buffer for the code
- needs enlarging.
-
- To complete the code emission for a method, a few other
- functions need implementing as well:
-
- mono_arch_emit_prolog ()
- mono_arch_emit_epilog ()
- mono_arch_patch_code ()
-
- mono_arch_emit_prolog () will emit the code to setup the stack
- frame for a method, optionally call the callbacks used in
- profiling and tracing, and move the arguments to their home
- location (in a caller-save register if the variable was
- allocated to one, or in a stack location if the argument was
- passed in a volatile register and wasn't allocated a
- non-volatile one). caller-save registers used by the function
- are saved in the prolog as well.
-
- mono_arch_emit_epilog () will emit the code needed to return
- from the function, optionally calling the profiling or tracing
- callbacks. At this point the basic blocks or the code that was
- moved out of the normal flow for the function can be emitted
- as well (this is usually done to provide better info for the
- static branch predictor). In the epilog, caller-save
- registers are restored if they were used.
-
- Note that, to help exception handling and stack unwinding,
- when there is a transition from managed to unmanaged code,
- some special processing needs to be done (basically, saving
- all the registers and setting up the links in the Last Managed
- Frame structure).
-
- When the epilog has been emitted, the upper level code
- arranges for the buffer of memory that contains the native
- code to be copied in an area of executable memory and at this
- point, instructions that use relative addressing need to be
- patched to have the right offsets: this work is done by
- mono_arch_patch_code ().
-
-
-* Call conventions and register allocation
-
- To account for the differences in the call conventions, a few functions need to
- be implemented.
-
- mono_arch_allocate_vars () assigns to both arguments and local
- variables the offset relative to the frame register where they
- are stored, dead variables are simply discarded. The total
- amount of stack needed is calculated.
-
- mono_arch_call_opcode () is the function that more closely
- deals with the call convention on a given system. For each
- argument to a function call, an instruction is created that
- actually puts the argument where needed, be it the stack or a
- specific register. This function can also re-arrange th order
- of evaluation when multiple arguments are involved if needed
- (like, on x86 arguments are pushed on the stack in reverse
- order). The function needs to carefully take into accounts
- platform specific issues, like how structures are returned as
- well as the differences in size and/or alignment of managed
- and corresponding unmanaged structures.
-
- The other chunk of code that needs to deal with the call
- convention and other specifics of a CPU, is the local register
- allocator, implemented in a function named
- mono_arch_local_regalloc (). The local allocator deals with a
- basic block at a time and basically just allocates registers
- for temporary values during expression evaluation, spilling
- and unspilling as necessary.
-
- The local allocator needs to take into account clobbering
- information, both during simple instructions and during
- function calls and it needs to deal with other
- architecture-specific weirdnesses, like instructions that take
- inputs only in specific registers or output only is some.
-
- Some effort will be put later in moving most of the local
- register allocator to a common file so that the code can be
- shared more for similar, risc-like CPUs. The register
- allocator does a first pass on the instructions in a block,
- collecting liveness information and in a backward pass on the
- same list performs the actual register allocation, inserting
- the instructions needed to spill values, if necessary.
-
- The cross-platform local register allocator is now implemented
- and it is documented in the jit-regalloc file.
-
- When this part of code is implemented, some testing can be
- done with the generated code for the new architecture. Most
- helpful is the use of the --regression command line switch to
- run the regression tests (basic.cs, for example).
-
- Note that the JIT will try to initialize the runtime, but it
- may not be able yet to compile and execute complex code:
- commenting most of the code in the mini_init() function in
- mini.c is needed to let the JIT just compile the regression
- tests. Also, using multiple -v switches on the command line
- makes the JIT dump an increasing amount of information during
- compilation.
-
- Values loaded into registers need to be extened as needed by
- the ECMA specs:
-
- *) integers smaller than 4 bytes are extended to int32 values
- *) 32 bit floats are extended to double precision (in particular
- this means that currently all the floating point operations operate
- on doubles)
-
-* Method trampolines
-
- To get better startup performance, the JIT actually compiles a
- method only when needed. To achieve this, when a call to a
- method is compiled, we actually emit a call to a magic
- trampoline. The magic trampoline is a function written in
- assembly that invokes the compiler to compile the given method
- and jumps to the newly compiled code, ensuring the arguments
- it received are passed correctly to the actual method.
-
- Before jumping to the new code, though, the magic trampoline
- takes care of patching the call site so that next time the
- call will go directly to the method instead of the
- trampoline. How does this all work?
-
- mono_arch_create_jit_trampoline () creates a small function
- that just preserves the arguments passed to it and adds an
- additional argument (the method to compile) before calling the
- generic trampoline. This small function is called the specific
- trampoline, because it is method-specific (the method to
- compile is hard-code in the instruction stream).
-
- The generic trampoline saves all the arguments that could get
- clobbered and calls a C function that will do two things:
-
- *) actually call the JIT to compile the method
- *) identify the calling code so that it can be patched to call directly
- the actual method
-
- If the 'this' argument to a method is a boxed valuetype that
- is passed to a method that expects just a pointer to the data,
- an additional unboxing trampoline will need to be inserted as
- well.
-
-
-* Exception handling
-
- Exception handling is likely the most difficult part of the
- port, as it needs to deal with unwinding (both managed and
- unmanaged code) and calling catch and filter blocks. It also
- needs to deal with signals, because mono takes advantage of
- the MMU in the CPU and of the operation system to handle
- dereferences of the NULL pointer. Some of the function needed
- to implement the mechanisms are:
-
- mono_arch_get_throw_exception () returns a function that takes
- an exception object and invokes an arch-specific function that
- will enter the exception processing. To do so, all the
- relevant registers need to be saved and passed on.
-
- mono_arch_handle_exception () this function takes the
- exception thrown and a context that describes the state of the
- CPU at the time the exception was thrown. The function needs
- to implement the exception handling mechanism, so it makes a
- search for an handler for the exception and if none is found,
- it follows the unhandled exception path (that can print a
- trace and exit or just abort the current thread). The
- difficulty here is to unwind the stack correctly, by restoring
- the register state at each call site in the call chain,
- calling finally, filters and handler blocks while doing so.
-
- As part of exception handling a couple of internal calls need
- to be implemented as well.
-
- ves_icall_get_frame_info () returns info about a specific
- frame.
-
- mono_jit_walk_stack () walks the stack and calls a callback with info for
- each frame found.
-
- ves_icall_get_trace () return an array of StackFrame objects.
-
-** Code generation for filter/finally handlers
-
- Filter and finally handlers are called from 2 different locations:
-
- 1.) from within the method containing the exception clauses
- 2.) from the stack unwinding code
-
- To make this possible we implement them like subroutines,
- ending with a "return" statement. The subroutine does not save
- the base pointer, because we need access to the local
- variables of the enclosing method. Its is possible that
- instructions inside those handlers modify the stack pointer,
- thus we save the stack pointer at the start of the handler,
- and restore it at the end. We have to use a "call" instruction
- to execute such finally handlers.
-
- The MIR code for filter and finally handlers looks like:
-
- OP_START_HANDLER
- ...
- OP_END_FINALLY | OP_ENDFILTER(reg)
-
- OP_START_HANDLER: should save the stack pointer somewhere
- OP_END_FINALLY: restores the stack pointers and returns.
- OP_ENDFILTER (reg): restores the stack pointers and returns the value in "reg".
-
-** Calling finally/filter handlers
-
- There is a special opcode to call those handler, its called
- OP_CALL_HANDLER. It simple emits a call instruction.
-
- Its a bit more complex to call handler from outside (in the
- stack unwinding code), because we have to restore the whole
- context of the method first. After that we simply emit a call
- instruction to invoke the handler. Its usually possible to use
- the same code to call filter and finally handlers (see
- arch_get_call_filter).
-
-** Calling catch handlers
-
- Catch handlers are always called from the stack unwinding
- code. Unlike finally clauses or filters, catch handler never
- return. Instead we simply restore the whole context, and
- restart execution at the catch handler.
-
-** Passing Exception objects to catch handlers and filters.
-
- We use a local variable to store exception objects. The stack
- unwinding code must store the exception object into this
- variable before calling catch handler or filter.
-
-* Minor helper methods
-
- A few minor helper methods are referenced from the arch-independent code.
- Some of them are:
-
- *) mono_arch_cpu_optimizations ()
- This function returns a mask of optimizations that
- should be enabled for the current CPU and a mask of
- optimizations that should be excluded, instead.
-
- *) mono_arch_regname ()
- Returns the name for a numeric register.
-
- *) mono_arch_get_allocatable_int_vars ()
- Returns a list of variables that can be allocated to
- the integer registers in the current architecture.
-
- *) mono_arch_get_global_int_regs ()
- Returns a list of caller-save registers that can be
- used to allocate variables in the current method.
-
- *) mono_arch_instrument_mem_needs ()
- *) mono_arch_instrument_prolog ()
- *) mono_arch_instrument_epilog ()
- Functions needed to implement the profiling interface.
-
-* Testing the port
-
- The JIT has a set of regression tests in *.cs files inside the
- mini directory.
-
- The usual method of testing a port is by compiling these tests on
- another machine with a working runtime by typing 'make rcheck',
- then copying TestDriver.dll and *.exe to the mini directory. The
- tests can be run by typing:
-
- ./mono --regression <exe file name>
-
- The suggested order for working through these tests is the
- following:
-
- - basic.exe
- - basic-long.exe
- - basic-float.exe
- - basic-calls.exe
- - objects.exe
- - arrays.exe
- - exceptions.exe
- - iltests.exe
- - generics.exe
-
-* Writing regression tests
-
- Regression tests for the JIT should be written for any bug
- found in the JIT in one of the *.cs files in the mini
- directory. Eventually all the operations of the JIT should be
- tested (including the ones that get selected only when some
- specific optimization is enabled).
-
-
-* Platform specific optimizations
-
- An example of a platform-specific optimization is the peephole
- optimization: we look at a small window of code at a time and
- we replace one or more instructions with others that perform
- better for the given architecture or CPU.
-
-* 64 bit support tips, by Zoltan Varga (vargaz@gmail.com)
-
- For a 64-bit port of the Mono runtime, you will typically do
- the following:
-
- * need to use inssel-long.brg instead of
- inssel-long32.brg.
-
- * need to implement lots of new opcodes:
- OP_I<OP> is 32 bit op
- OP_L<OP> and CEE_<OP> are 64 bit ops
-
-
- The 64 bit version of an existing port might share the code
- with the 32 bit port (for example SPARC/SPARV9), or it might
- be separate (x86/AMD64).
-
- That will depend on the similarities of the two instructions
- sets/ABIs etc.
-
- The runtime and most parts of the JIT are 64 bit clean
- at this point, so the only parts which require changing are
- the arch dependent files.
-
-* Function descriptors
-
- Some ABIs, like those for IA64 and PPC64, don't use direct
- function pointers, but so called function descriptors. A
- function descriptor is a short data structure which contains
- at least a pointer to the code of the function and a pointer
- to a GOT/TOC, which needs to be loaded into a specific
- register prior to jumping to the function. Global variables
- and large constants are accessed through that register.
-
- Mono does not need function descriptors for the JITted code,
- but we need to handle them when calling unmanaged code and we
- need to create them when passing managed code to unmanaged
- code.
-
- mono_create_ftnptr() creates a function descriptor for a piece
- of generated code within a specific domain.
-
- mono_get_addr_from_ftnptr() returns the pointer to the native
- code in a function descriptor. Never use this function to
- generate a jump to a function without loading the GOT/TOC
- register unless the function descriptor was created by
- mono_create_ftnptr().
-
- See the sources for IA64 and PPC64 on when to create and when
- to dereference function descriptors. On PPC64 function
- descriptors for various generated helper functions (in
- exceptions-ppc.c and tramp-ppc.c) are generated in front of
- the code they refer to (see ppc_create_pre_code_ftnptr()). On
- IA64 they are created separately.
-
-* Emulated opcodes
-
- Mini has code for emulating quite a few opcodes, most notably
- operations on longs, int/float conversions and atomic
- operations. If an architecture wishes such an opcode to be
- emulated, mini produces icalls instead of those opcodes. This
- should only be considered when the operation cannot be
- implemented efficiently and thus the overhead occured by the
- icall is not relatively large. Emulation of operations is
- controlled by #defines in the arch header, but the naming is
- not consistent. They usually start with MONO_ARCH_EMULATE_,
- MONO_ARCH_NO_EMULATE_ and MONO_ARCH_HAVE_.
-
-* Generic code sharing
-
- Generic code sharing is optional. See the file
- "generic-sharing" for information on how to support it on an
- architecture.