generic-sharing 8.7 KB

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