2008-12-09 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / docs / generic-sharing
1 -*- outline -*-
2
3 Generic code sharing
4 ====================
5
6 * Porting
7
8 ** Generic class init trampoline
9
10 The generic class init trampoline is very similar to the class init
11 trampoline, with the exception that the VTable of the class to be
12 inited is passed in a register, MONO_ARCH_VTABLE_REG.  That register
13 can be the same as the IMT register.
14
15 The call to the generic class init trampoline is never patched because
16 the VTable is not constant - it depends on the type arguments of the
17 class/method doing the call to the trampoline.  For that reason, the
18 trampoline needs a fast path for the case that the class is already
19 inited, i.e. the trampoline needs to check the initialized bit of the
20 MonoVTable and immediately return if it is set.  See tramp-x86.c for
21 how to portably figure out the number of the bit in the bit-field that
22 needs to be checked.
23
24 Since the MONO_ARCH_VTABLE_REG is needed by the generic class init
25 trampoline function (in mini-trampolines.c) it needs to be saved by
26 the generic trampoline code in the register save block which is passed
27 to the trampoline.  This also applies to the RGCTX fetch trampoline
28 (see below).
29
30 Like the normal class init trampoline, the result of the generic class
31 init trampoline function is not a pointer to code that needs to be
32 jumped to.  Instead, just like for the class init trampoline, the
33 generic trampoline code must return to the caller instead of jumping
34 to the returned value.  The same applies for the RGCTX fetch
35 trampoline (see below).
36
37 ** RGCTX register
38
39 Generic shared code needs access to type information.  This
40 information is contained in a RGCTX for non-generic methods and in an
41 MRGCTX for generic methods.  It is passed in one of several ways,
42 depending on the type of the called method:
43
44   1. Non-generic non-static methods of reference types have access to
45      the RGCTX via the "this" argument (this->vtable->rgctx).
46
47   2. Non-generic static methods of reference types and non-generic
48      methods of value types need to be passed a pointer to the
49      caller's class's VTable in the MONO_ARCH_RGCTX_REG register.
50
51   3. Generic methods need to be passed a pointer to the MRGCTX in the
52      MONO_ARCH_RGCTX_REG register.
53
54 The MONO_ARCH_RGCTX_REG must not be clobbered by trampolines.
55
56 MONO_ARCH_RGCTX_REG can be the same as the IMT register for now, but
57 this might change in the future when we implement virtual generic
58 method calls (more) efficiently.
59
60 This register lifetime starts at the call site that loads it and
61 ends in the callee prologue when it is either discarded or stored
62 into a local variable.
63
64 It's better to avoid registers used for argument passing for the RGCTX
65 as it would make the code dealing with calling conventions code a lot
66 harder.
67
68 ** Method prologue
69
70 Generic shared code that have a RGCTX receive it in RGCTX_REG.  There
71 must be a check in mono_arch_emit_prolog for MonoCompile::rgctx_var
72 and if set store it.  See mini-x86.c for reference.
73
74 ** Dealing with types
75
76 Types passed to arch functions might be type parameters
77 (MONO_TYPE_(M)VAR) if the MonoGenericSharingContext* argument is
78 non-NULL.  For example, an argument or return type in a method passed
79 to mono_arch_find_this_argument() could be a MONO_TYPE_VAR.  To guard
80 for that case use mini_get_basic_type_from_generic() on the type.  See
81 get_call_info() in mini-x86.c, for example.
82
83 ** (M)RGCTX lazy fetch trampoline
84
85 The purpose of the lazy fetch trampoline is to fetch a slot from an
86 (M)RGCTX which might not be inited, yet.  In the latter case, it needs
87 to go make a transition to unmanaged code to fill the slot.  This is
88 the layout of a RGCTX:
89
90      +---------------------------------+
91      | next | slot 0 | slot 1 | slot 2 |
92      +--|------------------------------+
93         |
94   +-----+
95   |  +---------------------------------
96   +->| next | slot 3 | slot 4 | slot 5 ....
97      +--|------------------------------
98         |
99   +-----+
100   |  +------------------------------------
101   +->| next | slot 10 | slot 11 | slot 12 ....
102      +--|---------------------------------
103         .
104         .
105         .
106
107 For fetching a slot from a RGCTX the trampoline is passed a pointer
108 (as a normal integer argument) to the VTable.  From there it has to
109 fetch the pointer to the RGCTX, which might be null.  Then it has to
110 traverse the correct number of "next" links, each of which might be
111 NULL.  Arriving at the right array it needs to fetch the slot, which
112 might also be NULL.  If any of the NULL cases, the trampoline must
113 transition to unmanaged code to potentially setup the RGCTX and fill
114 the slot.  Here is pseudo-code for fetching slot 11:
115
116     ; vtable ptr in r1
117     ; fetch RGCTX array 0
118     r2 = *(r1 + offsetof(MonoVTable, runtime_generic_context))
119     if r2 == NULL goto unmanaged
120     ; fetch RGCTX array 1
121     r2 = *r2
122     if r2 == NULL goto unmanaged
123     ; fetch RGCTX array 2
124     r2 = *r2
125     if r2 == NULL goto unmanaged
126     ; fetch slot 11
127     r2 = *(r2 + 2 * sizeof (gpointer))
128     if r2 == NULL goto unmanaged
129     return r2
130   unmanaged:
131     jump unmanaged_fetch_code
132
133 The number of slots in the arrays must be obtained from the function
134 mono_class_rgctx_get_array_size().
135
136 The MRGCTX case is different in two aspects.  First, the trampoline is
137 not passed a pointer to a VTable, but a pointer directly to the
138 MRGCTX, which is guaranteed not to be NULL (any of the next pointers
139 and any of the slots can be NULL, though).  Second, the layout of the
140 first array is slightly different, in that the first two slots are
141 occupied by a pointers to the class's VTable and to the method's
142 method_inst.  The next pointer is in the third slot and the first
143 actual slot, "slot 0", in the fourth:
144
145      +--------------------------------------------------------+
146      | vtable | method_inst | next | slot 0 | slot 1 | slot 2 |
147      +-------------------------|------------------------------+
148                                .
149                                .
150
151 All other arrays have the same layout as the RGCTX ones, except
152 possibly for their length.
153
154 The function to create the trampoline,
155 mono_arch_create_rgctx_lazy_fetch_trampoline(), gets passed an encoded
156 slot number.  Use the macro MONO_RGCTX_SLOT_IS_MRGCTX to query whether
157 a trampoline for an MRGCTX is needed, as opposed to one for a RGCTX.
158 Use MONO_RGCTX_SLOT_INDEX to get the index of the slot (like 2 for
159 "slot 2" as above).
160
161 The unmanaged fetch code is yet another trampoline created via
162 mono_arch_create_specific_trampoline(), of type
163 MONO_TRAMPOLINE_RGCTX_LAZY_FETCH.  It's given the slot number as the
164 trampoline argument.  In addition, the pointer to the VTable/MRGCTX is
165 passed in MONO_ARCH_VTABLE_REG (like the VTable to the generic class
166 init trampoline - see above).
167
168 Like the class init and generic class init trampolines, the RGCTX
169 fetch trampoline code doesn't return code that must be jumped to, so,
170 like for those trampolines (see above), the generic trampoline code
171 must do a normal return instead.
172
173
174 * Getting generics information about a stack frame
175
176 If a method is compiled with generic sharing, its MonoJitInfo has
177 has_generic_jit_info set.  In that case, the MonoJitInfo is followed
178 (after the MonoJitExceptionInfo array) by a MonoGenericJitInfo.
179
180 The MonoGenericJitInfo contains information about the location of the
181 this/vtable/MRGCTX variable, if the has_this flag is set.  If that is
182 the case, there are two possibilities:
183
184   1. this_in_reg is set.  this_reg is the number of the register where
185      the variable is stored.
186
187   2. this_in_reg is not set.  The variable is stored at offset
188      this_offset from the address in the register with number
189      this_reg.
190
191 The variable can either point to the "this" object, to a vtable or to
192 an MRGCTX:
193
194   1. If the method is a non-generic non-static method of a reference
195      type, the variable points to the "this" object.
196
197   2. If the method is a non-generic static method or a non-generic
198      method of a value type, the variable points to the vtable of the
199      class.
200
201   3. If the method is a generic method, the variable points to the
202      MRGCTX of the method.
203
204
205 * Layout of the MRGCTX
206
207 The MRGCTX is a structure that starts with
208 MonoMethodRuntimeGenericContext, which contains a pointer to the
209 vtable of the class and a pointer to the MonoGenericInst with the type
210 arguments for the method.
211
212
213 * Blog posts about generic code sharing
214
215 http://schani.wordpress.com/2007/09/22/generics-sharing-in-mono/
216 http://schani.wordpress.com/2007/10/12/the-trouble-with-shared-generics/
217 http://schani.wordpress.com/2007/10/15/a-quick-generics-sharing-update/
218 http://schani.wordpress.com/2008/01/29/other-types/
219 http://schani.wordpress.com/2008/02/25/generic-types-are-lazy/
220 http://schani.wordpress.com/2008/03/10/sharing-static-methods/
221 http://schani.wordpress.com/2008/04/22/sharing-everything-and-saving-memory/
222 http://schani.wordpress.com/2008/06/02/sharing-generic-methods/
223 http://schani.wordpress.com/2008/06/27/another-generic-sharing-update/