PageRenderTime 68ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 1ms

/mono/metadata/object.c

https://bitbucket.org/danipen/mono
C | 6619 lines | 4349 code | 831 blank | 1439 comment | 913 complexity | cfd99e509ea9c9a7059291fd6f301eeb MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * object.c: Object creation for the Mono runtime
  3. *
  4. * Author:
  5. * Miguel de Icaza (miguel@ximian.com)
  6. * Paolo Molaro (lupus@ximian.com)
  7. *
  8. * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
  9. * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
  10. * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
  11. */
  12. #include <config.h>
  13. #ifdef HAVE_ALLOCA_H
  14. #include <alloca.h>
  15. #endif
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18. #include <signal.h>
  19. #include <string.h>
  20. #include <mono/metadata/mono-endian.h>
  21. #include <mono/metadata/tabledefs.h>
  22. #include <mono/metadata/tokentype.h>
  23. #include <mono/metadata/loader.h>
  24. #include <mono/metadata/object.h>
  25. #include <mono/metadata/gc-internal.h>
  26. #include <mono/metadata/exception.h>
  27. #include <mono/metadata/domain-internals.h>
  28. #include "mono/metadata/metadata-internals.h"
  29. #include "mono/metadata/class-internals.h"
  30. #include <mono/metadata/assembly.h>
  31. #include <mono/metadata/threadpool.h>
  32. #include <mono/metadata/marshal.h>
  33. #include "mono/metadata/debug-helpers.h"
  34. #include "mono/metadata/marshal.h"
  35. #include <mono/metadata/threads.h>
  36. #include <mono/metadata/threads-types.h>
  37. #include <mono/metadata/environment.h>
  38. #include "mono/metadata/profiler-private.h"
  39. #include "mono/metadata/security-manager.h"
  40. #include "mono/metadata/mono-debug-debugger.h"
  41. #include <mono/metadata/gc-internal.h>
  42. #include <mono/metadata/verify-internals.h>
  43. #include <mono/utils/strenc.h>
  44. #include <mono/utils/mono-counters.h>
  45. #include <mono/utils/mono-error-internals.h>
  46. #include <mono/utils/mono-memory-model.h>
  47. #include "cominterop.h"
  48. #ifdef HAVE_BOEHM_GC
  49. #define NEED_TO_ZERO_PTRFREE 1
  50. #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
  51. #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
  52. #ifdef HAVE_GC_GCJ_MALLOC
  53. #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
  54. #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
  55. #else
  56. #define GC_NO_DESCRIPTOR (NULL)
  57. #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
  58. #endif
  59. #else
  60. #ifdef HAVE_SGEN_GC
  61. #define GC_NO_DESCRIPTOR (NULL)
  62. #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
  63. #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
  64. #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
  65. #else
  66. #define NEED_TO_ZERO_PTRFREE 1
  67. #define GC_NO_DESCRIPTOR (NULL)
  68. #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
  69. #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
  70. #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
  71. #endif
  72. #endif
  73. static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
  74. static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
  75. static void
  76. get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
  77. static MonoString*
  78. mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
  79. static void
  80. free_main_args (void);
  81. static char *
  82. mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
  83. #define ldstr_lock() EnterCriticalSection (&ldstr_section)
  84. #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
  85. static CRITICAL_SECTION ldstr_section;
  86. static gboolean profile_allocs = TRUE;
  87. void
  88. mono_runtime_object_init (MonoObject *this)
  89. {
  90. MonoMethod *method = NULL;
  91. MonoClass *klass = this->vtable->klass;
  92. method = mono_class_get_method_from_name (klass, ".ctor", 0);
  93. if (!method)
  94. g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
  95. if (method->klass->valuetype)
  96. this = mono_object_unbox (this);
  97. mono_runtime_invoke (method, this, NULL, NULL);
  98. }
  99. /* The pseudo algorithm for type initialization from the spec
  100. Note it doesn't say anything about domains - only threads.
  101. 2. If the type is initialized you are done.
  102. 2.1. If the type is not yet initialized, try to take an
  103. initialization lock.
  104. 2.2. If successful, record this thread as responsible for
  105. initializing the type and proceed to step 2.3.
  106. 2.2.1. If not, see whether this thread or any thread
  107. waiting for this thread to complete already holds the lock.
  108. 2.2.2. If so, return since blocking would create a deadlock. This thread
  109. will now see an incompletely initialized state for the type,
  110. but no deadlock will arise.
  111. 2.2.3 If not, block until the type is initialized then return.
  112. 2.3 Initialize the parent type and then all interfaces implemented
  113. by this type.
  114. 2.4 Execute the type initialization code for this type.
  115. 2.5 Mark the type as initialized, release the initialization lock,
  116. awaken any threads waiting for this type to be initialized,
  117. and return.
  118. */
  119. typedef struct
  120. {
  121. guint32 initializing_tid;
  122. guint32 waiting_count;
  123. gboolean done;
  124. CRITICAL_SECTION initialization_section;
  125. } TypeInitializationLock;
  126. /* for locking access to type_initialization_hash and blocked_thread_hash */
  127. #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
  128. #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
  129. static CRITICAL_SECTION type_initialization_section;
  130. /* from vtable to lock */
  131. static GHashTable *type_initialization_hash;
  132. /* from thread id to thread id being waited on */
  133. static GHashTable *blocked_thread_hash;
  134. /* Main thread */
  135. static MonoThread *main_thread;
  136. /* Functions supplied by the runtime */
  137. static MonoRuntimeCallbacks callbacks;
  138. /**
  139. * mono_thread_set_main:
  140. * @thread: thread to set as the main thread
  141. *
  142. * This function can be used to instruct the runtime to treat @thread
  143. * as the main thread, ie, the thread that would normally execute the Main()
  144. * method. This basically means that at the end of @thread, the runtime will
  145. * wait for the existing foreground threads to quit and other such details.
  146. */
  147. void
  148. mono_thread_set_main (MonoThread *thread)
  149. {
  150. static gboolean registered = FALSE;
  151. if (!registered) {
  152. MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
  153. registered = TRUE;
  154. }
  155. main_thread = thread;
  156. }
  157. MonoThread*
  158. mono_thread_get_main (void)
  159. {
  160. return main_thread;
  161. }
  162. void
  163. mono_type_initialization_init (void)
  164. {
  165. InitializeCriticalSection (&type_initialization_section);
  166. type_initialization_hash = g_hash_table_new (NULL, NULL);
  167. blocked_thread_hash = g_hash_table_new (NULL, NULL);
  168. InitializeCriticalSection (&ldstr_section);
  169. }
  170. void
  171. mono_type_initialization_cleanup (void)
  172. {
  173. #if 0
  174. /* This is causing race conditions with
  175. * mono_release_type_locks
  176. */
  177. DeleteCriticalSection (&type_initialization_section);
  178. g_hash_table_destroy (type_initialization_hash);
  179. type_initialization_hash = NULL;
  180. #endif
  181. DeleteCriticalSection (&ldstr_section);
  182. g_hash_table_destroy (blocked_thread_hash);
  183. blocked_thread_hash = NULL;
  184. free_main_args ();
  185. }
  186. /**
  187. * get_type_init_exception_for_vtable:
  188. *
  189. * Return the stored type initialization exception for VTABLE.
  190. */
  191. static MonoException*
  192. get_type_init_exception_for_vtable (MonoVTable *vtable)
  193. {
  194. MonoDomain *domain = vtable->domain;
  195. MonoClass *klass = vtable->klass;
  196. MonoException *ex;
  197. gchar *full_name;
  198. if (!vtable->init_failed)
  199. g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
  200. /*
  201. * If the initializing thread was rudely aborted, the exception is not stored
  202. * in the hash.
  203. */
  204. ex = NULL;
  205. mono_domain_lock (domain);
  206. if (domain->type_init_exception_hash)
  207. ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
  208. mono_domain_unlock (domain);
  209. if (!ex) {
  210. if (klass->name_space && *klass->name_space)
  211. full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
  212. else
  213. full_name = g_strdup (klass->name);
  214. ex = mono_get_exception_type_initialization (full_name, NULL);
  215. g_free (full_name);
  216. }
  217. return ex;
  218. }
  219. /*
  220. * mono_runtime_class_init:
  221. * @vtable: vtable that needs to be initialized
  222. *
  223. * This routine calls the class constructor for @vtable.
  224. */
  225. void
  226. mono_runtime_class_init (MonoVTable *vtable)
  227. {
  228. mono_runtime_class_init_full (vtable, TRUE);
  229. }
  230. /*
  231. * mono_runtime_class_init_full:
  232. * @vtable that neeeds to be initialized
  233. * @raise_exception is TRUE, exceptions are raised intead of returned
  234. *
  235. */
  236. MonoException *
  237. mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
  238. {
  239. MonoException *exc;
  240. MonoException *exc_to_throw;
  241. MonoMethod *method = NULL;
  242. MonoClass *klass;
  243. gchar *full_name;
  244. MONO_ARCH_SAVE_REGS;
  245. if (vtable->initialized)
  246. return NULL;
  247. exc = NULL;
  248. klass = vtable->klass;
  249. if (!klass->image->checked_module_cctor) {
  250. mono_image_check_for_module_cctor (klass->image);
  251. if (klass->image->has_module_cctor) {
  252. MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
  253. MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
  254. if (!module_vtable)
  255. return NULL;
  256. exc = mono_runtime_class_init_full (module_vtable, raise_exception);
  257. if (exc)
  258. return exc;
  259. }
  260. }
  261. method = mono_class_get_cctor (klass);
  262. if (method) {
  263. MonoDomain *domain = vtable->domain;
  264. TypeInitializationLock *lock;
  265. guint32 tid = GetCurrentThreadId();
  266. int do_initialization = 0;
  267. MonoDomain *last_domain = NULL;
  268. mono_type_initialization_lock ();
  269. /* double check... */
  270. if (vtable->initialized) {
  271. mono_type_initialization_unlock ();
  272. return NULL;
  273. }
  274. if (vtable->init_failed) {
  275. mono_type_initialization_unlock ();
  276. /* The type initialization already failed once, rethrow the same exception */
  277. if (raise_exception)
  278. mono_raise_exception (get_type_init_exception_for_vtable (vtable));
  279. return get_type_init_exception_for_vtable (vtable);
  280. }
  281. lock = g_hash_table_lookup (type_initialization_hash, vtable);
  282. if (lock == NULL) {
  283. /* This thread will get to do the initialization */
  284. if (mono_domain_get () != domain) {
  285. /* Transfer into the target domain */
  286. last_domain = mono_domain_get ();
  287. if (!mono_domain_set (domain, FALSE)) {
  288. vtable->initialized = 1;
  289. mono_type_initialization_unlock ();
  290. if (raise_exception)
  291. mono_raise_exception (mono_get_exception_appdomain_unloaded ());
  292. return mono_get_exception_appdomain_unloaded ();
  293. }
  294. }
  295. lock = g_malloc (sizeof(TypeInitializationLock));
  296. InitializeCriticalSection (&lock->initialization_section);
  297. lock->initializing_tid = tid;
  298. lock->waiting_count = 1;
  299. lock->done = FALSE;
  300. /* grab the vtable lock while this thread still owns type_initialization_section */
  301. EnterCriticalSection (&lock->initialization_section);
  302. g_hash_table_insert (type_initialization_hash, vtable, lock);
  303. do_initialization = 1;
  304. } else {
  305. gpointer blocked;
  306. TypeInitializationLock *pending_lock;
  307. if (lock->initializing_tid == tid || lock->done) {
  308. mono_type_initialization_unlock ();
  309. return NULL;
  310. }
  311. /* see if the thread doing the initialization is already blocked on this thread */
  312. blocked = GUINT_TO_POINTER (lock->initializing_tid);
  313. while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
  314. if (pending_lock->initializing_tid == tid) {
  315. if (!pending_lock->done) {
  316. mono_type_initialization_unlock ();
  317. return NULL;
  318. } else {
  319. /* the thread doing the initialization is blocked on this thread,
  320. but on a lock that has already been freed. It just hasn't got
  321. time to awake */
  322. break;
  323. }
  324. }
  325. blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
  326. }
  327. ++lock->waiting_count;
  328. /* record the fact that we are waiting on the initializing thread */
  329. g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
  330. }
  331. mono_type_initialization_unlock ();
  332. if (do_initialization) {
  333. mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
  334. /* If the initialization failed, mark the class as unusable. */
  335. /* Avoid infinite loops */
  336. if (!(exc == NULL ||
  337. (klass->image == mono_defaults.corlib &&
  338. !strcmp (klass->name_space, "System") &&
  339. !strcmp (klass->name, "TypeInitializationException")))) {
  340. vtable->init_failed = 1;
  341. if (klass->name_space && *klass->name_space)
  342. full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
  343. else
  344. full_name = g_strdup (klass->name);
  345. exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
  346. g_free (full_name);
  347. /*
  348. * Store the exception object so it could be thrown on subsequent
  349. * accesses.
  350. */
  351. mono_domain_lock (domain);
  352. if (!domain->type_init_exception_hash)
  353. domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
  354. mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
  355. mono_domain_unlock (domain);
  356. }
  357. if (last_domain)
  358. mono_domain_set (last_domain, TRUE);
  359. lock->done = TRUE;
  360. LeaveCriticalSection (&lock->initialization_section);
  361. } else {
  362. /* this just blocks until the initializing thread is done */
  363. EnterCriticalSection (&lock->initialization_section);
  364. LeaveCriticalSection (&lock->initialization_section);
  365. }
  366. mono_type_initialization_lock ();
  367. if (lock->initializing_tid != tid)
  368. g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
  369. --lock->waiting_count;
  370. if (lock->waiting_count == 0) {
  371. DeleteCriticalSection (&lock->initialization_section);
  372. g_hash_table_remove (type_initialization_hash, vtable);
  373. g_free (lock);
  374. }
  375. mono_memory_barrier ();
  376. if (!vtable->init_failed)
  377. vtable->initialized = 1;
  378. mono_type_initialization_unlock ();
  379. if (vtable->init_failed) {
  380. /* Either we were the initializing thread or we waited for the initialization */
  381. if (raise_exception)
  382. mono_raise_exception (get_type_init_exception_for_vtable (vtable));
  383. return get_type_init_exception_for_vtable (vtable);
  384. }
  385. } else {
  386. vtable->initialized = 1;
  387. return NULL;
  388. }
  389. return NULL;
  390. }
  391. static
  392. gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
  393. {
  394. MonoVTable *vtable = (MonoVTable*)key;
  395. TypeInitializationLock *lock = (TypeInitializationLock*) value;
  396. if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
  397. lock->done = TRUE;
  398. /*
  399. * Have to set this since it cannot be set by the normal code in
  400. * mono_runtime_class_init (). In this case, the exception object is not stored,
  401. * and get_type_init_exception_for_class () needs to be aware of this.
  402. */
  403. vtable->init_failed = 1;
  404. LeaveCriticalSection (&lock->initialization_section);
  405. --lock->waiting_count;
  406. if (lock->waiting_count == 0) {
  407. DeleteCriticalSection (&lock->initialization_section);
  408. g_free (lock);
  409. return TRUE;
  410. }
  411. }
  412. return FALSE;
  413. }
  414. void
  415. mono_release_type_locks (MonoInternalThread *thread)
  416. {
  417. mono_type_initialization_lock ();
  418. g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
  419. mono_type_initialization_unlock ();
  420. }
  421. static gpointer
  422. default_trampoline (MonoMethod *method)
  423. {
  424. return method;
  425. }
  426. static gpointer
  427. default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
  428. {
  429. g_assert_not_reached ();
  430. return NULL;
  431. }
  432. #ifndef DISABLE_REMOTING
  433. static gpointer
  434. default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
  435. {
  436. g_error ("remoting not installed");
  437. return NULL;
  438. }
  439. static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
  440. #endif
  441. static gpointer
  442. default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
  443. {
  444. g_assert_not_reached ();
  445. return NULL;
  446. }
  447. static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
  448. static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
  449. static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
  450. static MonoImtThunkBuilder imt_thunk_builder = NULL;
  451. #define ARCH_USE_IMT (imt_thunk_builder != NULL)
  452. #if (MONO_IMT_SIZE > 32)
  453. #error "MONO_IMT_SIZE cannot be larger than 32"
  454. #endif
  455. void
  456. mono_install_callbacks (MonoRuntimeCallbacks *cbs)
  457. {
  458. memcpy (&callbacks, cbs, sizeof (*cbs));
  459. }
  460. MonoRuntimeCallbacks*
  461. mono_get_runtime_callbacks (void)
  462. {
  463. return &callbacks;
  464. }
  465. void
  466. mono_install_trampoline (MonoTrampoline func)
  467. {
  468. arch_create_jit_trampoline = func? func: default_trampoline;
  469. }
  470. void
  471. mono_install_jump_trampoline (MonoJumpTrampoline func)
  472. {
  473. arch_create_jump_trampoline = func? func: default_jump_trampoline;
  474. }
  475. #ifndef DISABLE_REMOTING
  476. void
  477. mono_install_remoting_trampoline (MonoRemotingTrampoline func)
  478. {
  479. arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
  480. }
  481. #endif
  482. void
  483. mono_install_delegate_trampoline (MonoDelegateTrampoline func)
  484. {
  485. arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
  486. }
  487. void
  488. mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
  489. imt_thunk_builder = func;
  490. }
  491. static MonoCompileFunc default_mono_compile_method = NULL;
  492. /**
  493. * mono_install_compile_method:
  494. * @func: function to install
  495. *
  496. * This is a VM internal routine
  497. */
  498. void
  499. mono_install_compile_method (MonoCompileFunc func)
  500. {
  501. default_mono_compile_method = func;
  502. }
  503. /**
  504. * mono_compile_method:
  505. * @method: The method to compile.
  506. *
  507. * This JIT-compiles the method, and returns the pointer to the native code
  508. * produced.
  509. */
  510. gpointer
  511. mono_compile_method (MonoMethod *method)
  512. {
  513. if (!default_mono_compile_method) {
  514. g_error ("compile method called on uninitialized runtime");
  515. return NULL;
  516. }
  517. return default_mono_compile_method (method);
  518. }
  519. gpointer
  520. mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
  521. {
  522. return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
  523. }
  524. gpointer
  525. mono_runtime_create_delegate_trampoline (MonoClass *klass)
  526. {
  527. return arch_create_delegate_trampoline (mono_domain_get (), klass);
  528. }
  529. static MonoFreeMethodFunc default_mono_free_method = NULL;
  530. /**
  531. * mono_install_free_method:
  532. * @func: pointer to the MonoFreeMethodFunc used to release a method
  533. *
  534. * This is an internal VM routine, it is used for the engines to
  535. * register a handler to release the resources associated with a method.
  536. *
  537. * Methods are freed when no more references to the delegate that holds
  538. * them are left.
  539. */
  540. void
  541. mono_install_free_method (MonoFreeMethodFunc func)
  542. {
  543. default_mono_free_method = func;
  544. }
  545. /**
  546. * mono_runtime_free_method:
  547. * @domain; domain where the method is hosted
  548. * @method: method to release
  549. *
  550. * This routine is invoked to free the resources associated with
  551. * a method that has been JIT compiled. This is used to discard
  552. * methods that were used only temporarily (for example, used in marshalling)
  553. *
  554. */
  555. void
  556. mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
  557. {
  558. if (default_mono_free_method != NULL)
  559. default_mono_free_method (domain, method);
  560. mono_method_clear_object (domain, method);
  561. mono_free_method (method);
  562. }
  563. /*
  564. * The vtables in the root appdomain are assumed to be reachable by other
  565. * roots, and we don't use typed allocation in the other domains.
  566. */
  567. /* The sync block is no longer a GC pointer */
  568. #define GC_HEADER_BITMAP (0)
  569. #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
  570. static gsize*
  571. compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
  572. {
  573. MonoClassField *field;
  574. MonoClass *p;
  575. guint32 pos;
  576. int max_size;
  577. if (static_fields)
  578. max_size = mono_class_data_size (class) / sizeof (gpointer);
  579. else
  580. max_size = class->instance_size / sizeof (gpointer);
  581. if (max_size > size) {
  582. g_assert (offset <= 0);
  583. bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
  584. size = max_size;
  585. }
  586. #ifdef HAVE_SGEN_GC
  587. /*An Ephemeron cannot be marked by sgen*/
  588. if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
  589. *max_set = 0;
  590. memset (bitmap, 0, size / 8);
  591. return bitmap;
  592. }
  593. #endif
  594. for (p = class; p != NULL; p = p->parent) {
  595. gpointer iter = NULL;
  596. while ((field = mono_class_get_fields (p, &iter))) {
  597. MonoType *type;
  598. if (static_fields) {
  599. if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
  600. continue;
  601. if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
  602. continue;
  603. } else {
  604. if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
  605. continue;
  606. }
  607. /* FIXME: should not happen, flag as type load error */
  608. if (field->type->byref)
  609. break;
  610. if (static_fields && field->offset == -1)
  611. /* special static */
  612. continue;
  613. pos = field->offset / sizeof (gpointer);
  614. pos += offset;
  615. type = mono_type_get_underlying_type (field->type);
  616. switch (type->type) {
  617. case MONO_TYPE_I:
  618. case MONO_TYPE_PTR:
  619. case MONO_TYPE_FNPTR:
  620. break;
  621. /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
  622. case MONO_TYPE_U:
  623. #ifdef HAVE_SGEN_GC
  624. break;
  625. #else
  626. if (class->image != mono_defaults.corlib)
  627. break;
  628. #endif
  629. case MONO_TYPE_STRING:
  630. case MONO_TYPE_SZARRAY:
  631. case MONO_TYPE_CLASS:
  632. case MONO_TYPE_OBJECT:
  633. case MONO_TYPE_ARRAY:
  634. g_assert ((field->offset % sizeof(gpointer)) == 0);
  635. g_assert (pos < size || pos <= max_size);
  636. bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
  637. *max_set = MAX (*max_set, pos);
  638. break;
  639. case MONO_TYPE_GENERICINST:
  640. if (!mono_type_generic_inst_is_valuetype (type)) {
  641. g_assert ((field->offset % sizeof(gpointer)) == 0);
  642. bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
  643. *max_set = MAX (*max_set, pos);
  644. break;
  645. } else {
  646. /* fall through */
  647. }
  648. case MONO_TYPE_VALUETYPE: {
  649. MonoClass *fclass = mono_class_from_mono_type (field->type);
  650. if (fclass->has_references) {
  651. /* remove the object header */
  652. compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
  653. }
  654. break;
  655. }
  656. case MONO_TYPE_I1:
  657. case MONO_TYPE_U1:
  658. case MONO_TYPE_I2:
  659. case MONO_TYPE_U2:
  660. case MONO_TYPE_I4:
  661. case MONO_TYPE_U4:
  662. case MONO_TYPE_I8:
  663. case MONO_TYPE_U8:
  664. case MONO_TYPE_R4:
  665. case MONO_TYPE_R8:
  666. case MONO_TYPE_BOOLEAN:
  667. case MONO_TYPE_CHAR:
  668. break;
  669. default:
  670. g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
  671. break;
  672. }
  673. }
  674. if (static_fields)
  675. break;
  676. }
  677. return bitmap;
  678. }
  679. /**
  680. * mono_class_compute_bitmap:
  681. *
  682. * Mono internal function to compute a bitmap of reference fields in a class.
  683. */
  684. gsize*
  685. mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
  686. {
  687. return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
  688. }
  689. #if 0
  690. /*
  691. * similar to the above, but sets the bits in the bitmap for any non-ref field
  692. * and ignores static fields
  693. */
  694. static gsize*
  695. compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
  696. {
  697. MonoClassField *field;
  698. MonoClass *p;
  699. guint32 pos, pos2;
  700. int max_size;
  701. max_size = class->instance_size / sizeof (gpointer);
  702. if (max_size >= size) {
  703. bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
  704. }
  705. for (p = class; p != NULL; p = p->parent) {
  706. gpointer iter = NULL;
  707. while ((field = mono_class_get_fields (p, &iter))) {
  708. MonoType *type;
  709. if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
  710. continue;
  711. /* FIXME: should not happen, flag as type load error */
  712. if (field->type->byref)
  713. break;
  714. pos = field->offset / sizeof (gpointer);
  715. pos += offset;
  716. type = mono_type_get_underlying_type (field->type);
  717. switch (type->type) {
  718. #if SIZEOF_VOID_P == 8
  719. case MONO_TYPE_I:
  720. case MONO_TYPE_U:
  721. case MONO_TYPE_PTR:
  722. case MONO_TYPE_FNPTR:
  723. #endif
  724. case MONO_TYPE_I8:
  725. case MONO_TYPE_U8:
  726. case MONO_TYPE_R8:
  727. if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
  728. pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
  729. bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
  730. }
  731. /* fall through */
  732. #if SIZEOF_VOID_P == 4
  733. case MONO_TYPE_I:
  734. case MONO_TYPE_U:
  735. case MONO_TYPE_PTR:
  736. case MONO_TYPE_FNPTR:
  737. #endif
  738. case MONO_TYPE_I4:
  739. case MONO_TYPE_U4:
  740. case MONO_TYPE_R4:
  741. if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
  742. pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
  743. bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
  744. }
  745. /* fall through */
  746. case MONO_TYPE_CHAR:
  747. case MONO_TYPE_I2:
  748. case MONO_TYPE_U2:
  749. if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
  750. pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
  751. bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
  752. }
  753. /* fall through */
  754. case MONO_TYPE_BOOLEAN:
  755. case MONO_TYPE_I1:
  756. case MONO_TYPE_U1:
  757. bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
  758. break;
  759. case MONO_TYPE_STRING:
  760. case MONO_TYPE_SZARRAY:
  761. case MONO_TYPE_CLASS:
  762. case MONO_TYPE_OBJECT:
  763. case MONO_TYPE_ARRAY:
  764. break;
  765. case MONO_TYPE_GENERICINST:
  766. if (!mono_type_generic_inst_is_valuetype (type)) {
  767. break;
  768. } else {
  769. /* fall through */
  770. }
  771. case MONO_TYPE_VALUETYPE: {
  772. MonoClass *fclass = mono_class_from_mono_type (field->type);
  773. /* remove the object header */
  774. compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
  775. break;
  776. }
  777. default:
  778. g_assert_not_reached ();
  779. break;
  780. }
  781. }
  782. }
  783. return bitmap;
  784. }
  785. /**
  786. * mono_class_insecure_overlapping:
  787. * check if a class with explicit layout has references and non-references
  788. * fields overlapping.
  789. *
  790. * Returns: TRUE if it is insecure to load the type.
  791. */
  792. gboolean
  793. mono_class_insecure_overlapping (MonoClass *klass)
  794. {
  795. int max_set = 0;
  796. gsize *bitmap;
  797. gsize default_bitmap [4] = {0};
  798. gsize *nrbitmap;
  799. gsize default_nrbitmap [4] = {0};
  800. int i, insecure = FALSE;
  801. return FALSE;
  802. bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
  803. nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
  804. for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
  805. int idx = i % (sizeof (bitmap [0]) * 8);
  806. if (bitmap [idx] & nrbitmap [idx]) {
  807. insecure = TRUE;
  808. break;
  809. }
  810. }
  811. if (bitmap != default_bitmap)
  812. g_free (bitmap);
  813. if (nrbitmap != default_nrbitmap)
  814. g_free (nrbitmap);
  815. if (insecure) {
  816. g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
  817. return FALSE;
  818. }
  819. return insecure;
  820. }
  821. #endif
  822. MonoString*
  823. mono_string_alloc (int length)
  824. {
  825. return mono_string_new_size (mono_domain_get (), length);
  826. }
  827. void
  828. mono_class_compute_gc_descriptor (MonoClass *class)
  829. {
  830. int max_set = 0;
  831. gsize *bitmap;
  832. gsize default_bitmap [4] = {0};
  833. static gboolean gcj_inited = FALSE;
  834. if (!gcj_inited) {
  835. mono_loader_lock ();
  836. mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
  837. mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
  838. mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
  839. mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
  840. #ifdef HAVE_GC_GCJ_MALLOC
  841. /*
  842. * This is not needed unless the relevant code in mono_get_allocation_ftn () is
  843. * turned on.
  844. */
  845. #if 0
  846. #ifdef GC_REDIRECT_TO_LOCAL
  847. mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
  848. mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
  849. #endif
  850. mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
  851. mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
  852. #endif
  853. #endif
  854. gcj_inited = TRUE;
  855. mono_loader_unlock ();
  856. }
  857. if (!class->inited)
  858. mono_class_init (class);
  859. if (class->gc_descr_inited)
  860. return;
  861. class->gc_descr_inited = TRUE;
  862. class->gc_descr = GC_NO_DESCRIPTOR;
  863. bitmap = default_bitmap;
  864. if (class == mono_defaults.string_class) {
  865. class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
  866. } else if (class->rank) {
  867. mono_class_compute_gc_descriptor (class->element_class);
  868. if (!class->element_class->valuetype) {
  869. gsize abm = 1;
  870. class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
  871. /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
  872. class->name_space, class->name);*/
  873. } else {
  874. /* remove the object header */
  875. bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
  876. class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
  877. /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
  878. class->name_space, class->name);*/
  879. if (bitmap != default_bitmap)
  880. g_free (bitmap);
  881. }
  882. } else {
  883. /*static int count = 0;
  884. if (count++ > 58)
  885. return;*/
  886. bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
  887. class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
  888. /*
  889. if (class->gc_descr == GC_NO_DESCRIPTOR)
  890. g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
  891. */
  892. /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
  893. if (bitmap != default_bitmap)
  894. g_free (bitmap);
  895. }
  896. }
  897. /**
  898. * field_is_special_static:
  899. * @fklass: The MonoClass to look up.
  900. * @field: The MonoClassField describing the field.
  901. *
  902. * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
  903. * SPECIAL_STATIC_NONE otherwise.
  904. */
  905. static gint32
  906. field_is_special_static (MonoClass *fklass, MonoClassField *field)
  907. {
  908. MonoCustomAttrInfo *ainfo;
  909. int i;
  910. ainfo = mono_custom_attrs_from_field (fklass, field);
  911. if (!ainfo)
  912. return FALSE;
  913. for (i = 0; i < ainfo->num_attrs; ++i) {
  914. MonoClass *klass = ainfo->attrs [i].ctor->klass;
  915. if (klass->image == mono_defaults.corlib) {
  916. if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
  917. mono_custom_attrs_free (ainfo);
  918. return SPECIAL_STATIC_THREAD;
  919. }
  920. else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
  921. mono_custom_attrs_free (ainfo);
  922. return SPECIAL_STATIC_CONTEXT;
  923. }
  924. }
  925. }
  926. mono_custom_attrs_free (ainfo);
  927. return SPECIAL_STATIC_NONE;
  928. }
  929. #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
  930. #define mix(a,b,c) { \
  931. a -= c; a ^= rot(c, 4); c += b; \
  932. b -= a; b ^= rot(a, 6); a += c; \
  933. c -= b; c ^= rot(b, 8); b += a; \
  934. a -= c; a ^= rot(c,16); c += b; \
  935. b -= a; b ^= rot(a,19); a += c; \
  936. c -= b; c ^= rot(b, 4); b += a; \
  937. }
  938. #define final(a,b,c) { \
  939. c ^= b; c -= rot(b,14); \
  940. a ^= c; a -= rot(c,11); \
  941. b ^= a; b -= rot(a,25); \
  942. c ^= b; c -= rot(b,16); \
  943. a ^= c; a -= rot(c,4); \
  944. b ^= a; b -= rot(a,14); \
  945. c ^= b; c -= rot(b,24); \
  946. }
  947. /*
  948. * mono_method_get_imt_slot:
  949. *
  950. * The IMT slot is embedded into AOTed code, so this must return the same value
  951. * for the same method across all executions. This means:
  952. * - pointers shouldn't be used as hash values.
  953. * - mono_metadata_str_hash () should be used for hashing strings.
  954. */
  955. guint32
  956. mono_method_get_imt_slot (MonoMethod *method)
  957. {
  958. MonoMethodSignature *sig;
  959. int hashes_count;
  960. guint32 *hashes_start, *hashes;
  961. guint32 a, b, c;
  962. int i;
  963. /* This can be used to stress tests the collision code */
  964. //return 0;
  965. /*
  966. * We do this to simplify generic sharing. It will hurt
  967. * performance in cases where a class implements two different
  968. * instantiations of the same generic interface.
  969. * The code in build_imt_slots () depends on this.
  970. */
  971. if (method->is_inflated)
  972. method = ((MonoMethodInflated*)method)->declaring;
  973. sig = mono_method_signature (method);
  974. hashes_count = sig->param_count + 4;
  975. hashes_start = malloc (hashes_count * sizeof (guint32));
  976. hashes = hashes_start;
  977. if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
  978. g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
  979. method->klass->name_space, method->klass->name, method->name);
  980. }
  981. /* Initialize hashes */
  982. hashes [0] = mono_metadata_str_hash (method->klass->name);
  983. hashes [1] = mono_metadata_str_hash (method->klass->name_space);
  984. hashes [2] = mono_metadata_str_hash (method->name);
  985. hashes [3] = mono_metadata_type_hash (sig->ret);
  986. for (i = 0; i < sig->param_count; i++) {
  987. hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
  988. }
  989. /* Setup internal state */
  990. a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
  991. /* Handle most of the hashes */
  992. while (hashes_count > 3) {
  993. a += hashes [0];
  994. b += hashes [1];
  995. c += hashes [2];
  996. mix (a,b,c);
  997. hashes_count -= 3;
  998. hashes += 3;
  999. }
  1000. /* Handle the last 3 hashes (all the case statements fall through) */
  1001. switch (hashes_count) {
  1002. case 3 : c += hashes [2];
  1003. case 2 : b += hashes [1];
  1004. case 1 : a += hashes [0];
  1005. final (a,b,c);
  1006. case 0: /* nothing left to add */
  1007. break;
  1008. }
  1009. free (hashes_start);
  1010. /* Report the result */
  1011. return c % MONO_IMT_SIZE;
  1012. }
  1013. #undef rot
  1014. #undef mix
  1015. #undef final
  1016. #define DEBUG_IMT 0
  1017. static void
  1018. add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
  1019. guint32 imt_slot = mono_method_get_imt_slot (method);
  1020. MonoImtBuilderEntry *entry;
  1021. if (slot_num >= 0 && imt_slot != slot_num) {
  1022. /* we build just a single imt slot and this is not it */
  1023. return;
  1024. }
  1025. entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
  1026. entry->key = method;
  1027. entry->value.vtable_slot = vtable_slot;
  1028. entry->next = imt_builder [imt_slot];
  1029. if (imt_builder [imt_slot] != NULL) {
  1030. entry->children = imt_builder [imt_slot]->children + 1;
  1031. if (entry->children == 1) {
  1032. mono_stats.imt_slots_with_collisions++;
  1033. *imt_collisions_bitmap |= (1 << imt_slot);
  1034. }
  1035. } else {
  1036. entry->children = 0;
  1037. mono_stats.imt_used_slots++;
  1038. }
  1039. imt_builder [imt_slot] = entry;
  1040. #if DEBUG_IMT
  1041. {
  1042. char *method_name = mono_method_full_name (method, TRUE);
  1043. printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
  1044. method, method_name, imt_slot, vtable_slot, entry->children);
  1045. g_free (method_name);
  1046. }
  1047. #endif
  1048. }
  1049. #if DEBUG_IMT
  1050. static void
  1051. print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
  1052. if (e != NULL) {
  1053. MonoMethod *method = e->key;
  1054. printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
  1055. message,
  1056. num,
  1057. method,
  1058. method->klass->name_space,
  1059. method->klass->name,
  1060. method->name);
  1061. } else {
  1062. printf (" * %s: NULL\n", message);
  1063. }
  1064. }
  1065. #endif
  1066. static int
  1067. compare_imt_builder_entries (const void *p1, const void *p2) {
  1068. MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
  1069. MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
  1070. return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
  1071. }
  1072. static int
  1073. imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
  1074. {
  1075. int count = end - start;
  1076. int chunk_start = out_array->len;
  1077. if (count < 4) {
  1078. int i;
  1079. for (i = start; i < end; ++i) {
  1080. MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
  1081. item->key = sorted_array [i]->key;
  1082. item->value = sorted_array [i]->value;
  1083. item->has_target_code = sorted_array [i]->has_target_code;
  1084. item->is_equals = TRUE;
  1085. if (i < end - 1)
  1086. item->check_target_idx = out_array->len + 1;
  1087. else
  1088. item->check_target_idx = 0;
  1089. g_ptr_array_add (out_array, item);
  1090. }
  1091. } else {
  1092. int middle = start + count / 2;
  1093. MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
  1094. item->key = sorted_array [middle]->key;
  1095. item->is_equals = FALSE;
  1096. g_ptr_array_add (out_array, item);
  1097. imt_emit_ir (sorted_array, start, middle, out_array);
  1098. item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
  1099. }
  1100. return chunk_start;
  1101. }
  1102. static GPtrArray*
  1103. imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
  1104. int number_of_entries = entries->children + 1;
  1105. MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
  1106. GPtrArray *result = g_ptr_array_new ();
  1107. MonoImtBuilderEntry *current_entry;
  1108. int i;
  1109. for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
  1110. sorted_array [i] = current_entry;
  1111. }
  1112. qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
  1113. /*for (i = 0; i < number_of_entries; i++) {
  1114. print_imt_entry (" sorted array:", sorted_array [i], i);
  1115. }*/
  1116. imt_emit_ir (sorted_array, 0, number_of_entries, result);
  1117. free (sorted_array);
  1118. return result;
  1119. }
  1120. static gpointer
  1121. initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
  1122. {
  1123. if (imt_builder_entry != NULL) {
  1124. if (imt_builder_entry->children == 0 && !fail_tramp) {
  1125. /* No collision, return the vtable slot contents */
  1126. return vtable->vtable [imt_builder_entry->value.vtable_slot];
  1127. } else {
  1128. /* Collision, build the thunk */
  1129. GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
  1130. gpointer result;
  1131. int i;
  1132. result = imt_thunk_builder (vtable, domain,
  1133. (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
  1134. for (i = 0; i < imt_ir->len; ++i)
  1135. g_free (g_ptr_array_index (imt_ir, i));
  1136. g_ptr_array_free (imt_ir, TRUE);
  1137. return result;
  1138. }
  1139. } else {
  1140. if (fail_tramp)
  1141. return fail_tramp;
  1142. else
  1143. /* Empty slot */
  1144. return NULL;
  1145. }
  1146. }
  1147. static MonoImtBuilderEntry*
  1148. get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
  1149. /*
  1150. * LOCKING: requires the loader and domain locks.
  1151. *
  1152. */
  1153. static void
  1154. build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
  1155. {
  1156. int i;
  1157. GSList *list_item;
  1158. guint32 imt_collisions_bitmap = 0;
  1159. MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
  1160. int method_count = 0;
  1161. gboolean record_method_count_for_max_collisions = FALSE;
  1162. gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
  1163. #if DEBUG_IMT
  1164. printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
  1165. #endif
  1166. for (i = 0; i < klass->interface_offsets_count; ++i) {
  1167. MonoClass *iface = klass->interfaces_packed [i];
  1168. int interface_offset = klass->interface_offsets_packed [i];
  1169. int method_slot_in_interface, vt_slot;
  1170. if (mono_class_has_variant_generic_params (iface))
  1171. has_variant_iface = TRUE;
  1172. vt_slot = interface_offset;
  1173. for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
  1174. MonoMethod *method;
  1175. if (slot_num >= 0 && iface->is_inflated) {
  1176. /*
  1177. * The imt slot of the method is the same as for its declaring method,
  1178. * see the comment in mono_method_get_imt_slot (), so we can
  1179. * avoid inflating methods which will be discarded by
  1180. * add_imt_builder_entry anyway.
  1181. */
  1182. method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
  1183. if (mono_method_get_imt_slot (method) != slot_num) {
  1184. vt_slot ++;
  1185. continue;
  1186. }
  1187. }
  1188. method = mono_class_get_method_by_index (iface, method_slot_in_interface);
  1189. if (method->is_generic) {
  1190. has_generic_virtual = TRUE;
  1191. vt_slot ++;
  1192. continue;
  1193. }
  1194. if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
  1195. add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
  1196. vt_slot ++;
  1197. }
  1198. }
  1199. }
  1200. if (extra_interfaces) {
  1201. int interface_offset = klass->vtable_size;
  1202. for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
  1203. MonoClass* iface = list_item->data;
  1204. int method_slot_in_interface;
  1205. for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
  1206. MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
  1207. add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
  1208. }
  1209. interface_offset += iface->method.count;
  1210. }
  1211. }
  1212. for (i = 0; i < MONO_IMT_SIZE; ++i) {
  1213. /* overwrite the imt slot only if we're building all the entries or if
  1214. * we're building this specific one
  1215. */
  1216. if (slot_num < 0 || i == slot_num) {
  1217. MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
  1218. if (entries) {
  1219. if (imt_builder [i]) {
  1220. MonoImtBuilderEntry *entry;
  1221. /* Link entries with imt_builder [i] */
  1222. for (entry = entries; entry->next; entry = entry->next) {
  1223. #if DEBUG_IMT
  1224. MonoMethod *method = (MonoMethod*)entry->key;
  1225. char *method_name = mono_method_full_name (method, TRUE);
  1226. printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
  1227. g_free (method_name);
  1228. #endif
  1229. }
  1230. entry->next = imt_builder [i];
  1231. entries->children += imt_builder [i]->children + 1;
  1232. }
  1233. imt_builder [i] = entries;
  1234. }
  1235. if (has_generic_virtual || has_variant_iface) {
  1236. /*
  1237. * There might be collisions later when the the thunk is expanded.
  1238. */
  1239. imt_collisions_bitmap |= (1 << i);
  1240. /*
  1241. * The IMT thunk might be called with an instance of one of the
  1242. * generic virtual methods, so has to fallback to the IMT trampoline.
  1243. */
  1244. imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
  1245. } else {
  1246. imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
  1247. }
  1248. #if DEBUG_IMT
  1249. printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
  1250. #endif
  1251. }
  1252. if (imt_builder [i] != NULL) {
  1253. int methods_in_slot = imt_builder [i]->children + 1;
  1254. if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
  1255. mono_stats.imt_max_collisions_in_slot = methods_in_slot;
  1256. record_method_count_for_max_collisions = TRUE;
  1257. }
  1258. method_count += methods_in_slot;
  1259. }
  1260. }
  1261. mono_stats.imt_number_of_methods += method_count;
  1262. if (record_method_count_for_max_collisions) {
  1263. mono_stats.imt_method_count_when_max_collisions = method_count;
  1264. }
  1265. for (i = 0; i < MONO_IMT_SIZE; i++) {
  1266. MonoImtBuilderEntry* entry = imt_builder [i];
  1267. while (entry != NULL) {
  1268. MonoImtBuilderEntry* next = entry->next;
  1269. g_free (entry);
  1270. entry = next;
  1271. }
  1272. }
  1273. free (imt_builder);
  1274. /* we OR the bitmap since we may build just a single imt slot at a time */
  1275. vt->imt_collisions_bitmap |= imt_collisions_bitmap;
  1276. }
  1277. static void
  1278. build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
  1279. build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
  1280. }
  1281. /**
  1282. * mono_vtable_build_imt_slot:
  1283. * @vtable: virtual object table struct
  1284. * @imt_slot: slot in the IMT table
  1285. *
  1286. * Fill the given @imt_slot in the IMT table of @vtable with
  1287. * a trampoline or a thunk for the case of collisions.
  1288. * This is part of the internal mono API.
  1289. *
  1290. * LOCKING: Take the domain lock.
  1291. */
  1292. void
  1293. mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
  1294. {
  1295. gpointer *imt = (gpointer*)vtable;
  1296. imt -= MONO_IMT_SIZE;
  1297. g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
  1298. /* no support for extra interfaces: the proxy objects will need
  1299. * to build the complete IMT
  1300. * Update and heck needs to ahppen inside the proper domain lock, as all
  1301. * the changes made to a MonoVTable.
  1302. */
  1303. mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
  1304. mono_domain_lock (vtable->domain);
  1305. /* we change the slot only if it wasn't changed from the generic imt trampoline already */
  1306. if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
  1307. build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
  1308. mono_domain_unlock (vtable->domain);
  1309. mono_loader_unlock ();
  1310. }
  1311. /*
  1312. * The first two free list entries both belong to the wait list: The
  1313. * first entry is the pointer to the head of the list and the second
  1314. * entry points to the last element. That way appending and removing
  1315. * the first element are both O(1) operations.
  1316. */
  1317. #ifdef MONO_SMALL_CONFIG
  1318. #define NUM_FREE_LISTS 6
  1319. #else
  1320. #define NUM_FREE_LISTS 12
  1321. #endif
  1322. #define FIRST_FREE_LIST_SIZE 64
  1323. #define MAX_WAIT_LENGTH 50
  1324. #define THUNK_THRESHOLD 10
  1325. /*
  1326. * LOCKING: The domain lock must be held.
  1327. */
  1328. static void
  1329. init_thunk_free_lists (MonoDomain *domain)
  1330. {
  1331. if (domain->thunk_free_lists)
  1332. return;
  1333. domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
  1334. }
  1335. static int
  1336. list_index_for_size (int item_size)
  1337. {
  1338. int i = 2;
  1339. int size = FIRST_FREE_LIST_SIZE;
  1340. while (item_size > size && i < NUM_FREE_LISTS - 1) {
  1341. i++;
  1342. size <<= 1;
  1343. }
  1344. return i;
  1345. }
  1346. /**
  1347. * mono_method_alloc_generic_virtual_thunk:
  1348. * @domain: a domain
  1349. * @size: size in bytes
  1350. *
  1351. * Allocs size bytes to be used for the code of a generic virtual
  1352. * thunk. It's either allocated from the domain's code manager or
  1353. * reused from a previously invalidated piece.
  1354. *
  1355. * LOCKING: The domain lock must be held.
  1356. */
  1357. gpointer
  1358. mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
  1359. {
  1360. static gboolean inited = FALSE;
  1361. static int generic_virtual_thunks_size = 0;
  1362. guint32 *p;
  1363. int i;
  1364. MonoThunkFreeList **l;
  1365. init_thunk_free_lists (domain);
  1366. size += sizeof (guint32);
  1367. if (size < sizeof (MonoThunkFreeList))
  1368. size = sizeof (MonoThunkFreeList);
  1369. i = list_index_for_size (size);
  1370. for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
  1371. if ((*l)->size >= size) {
  1372. MonoThunkFreeList *item = *l;
  1373. *l = item->next;
  1374. return ((guint32*)item) + 1;
  1375. }
  1376. }
  1377. /* no suitable item found - search lists of larger sizes */
  1378. while (++i < NUM_FREE_LISTS) {
  1379. MonoThunkFreeList *item = domain->thunk_free_lists [i];
  1380. if (!item)
  1381. continue;
  1382. g_assert (item->size > size);
  1383. domain->thunk_free_lists [i] = item->next;
  1384. return ((guint32*)item) + 1;
  1385. }
  1386. /* still nothing found - allocate it */
  1387. if (!inited) {
  1388. mono_counters_register ("Generic virtual thunk bytes",
  1389. MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
  1390. inited = TRUE;
  1391. }
  1392. generic_virtual_thunks_size += size;
  1393. p = mono_domain_code_reserve (domain, size);
  1394. *p = size;
  1395. mono_domain_lock (domain);
  1396. if (!domain->generic_virtual_thunks)
  1397. domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
  1398. g_hash_table_insert (domain->generic_virtual_thunks, p, p);
  1399. mono_domain_unlock (domain);
  1400. return p + 1;
  1401. }
  1402. /*
  1403. * LOCKING: The domain lock must be held.
  1404. */
  1405. static void
  1406. invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
  1407. {
  1408. guint32 *p = code;
  1409. MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
  1410. gboolean found = FALSE;
  1411. mono_domain_lock (domain);
  1412. if (!domain->generic_virtual_thunks)
  1413. domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
  1414. if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
  1415. found = TRUE;
  1416. mono_domain_unlock (domain);
  1417. if (!found)
  1418. /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
  1419. return;
  1420. init_thunk_free_lists (domain);
  1421. while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
  1422. MonoThunkFreeList *item = domain->thunk_free_lists [0];
  1423. int length = item->length;
  1424. int i;
  1425. /* unlink the first item from the wait list */
  1426. domain->thunk_free_lists [0] = item->next;
  1427. domain->thunk_free_lists [0]->length = length - 1;
  1428. i = list_index_for_size (item->size);
  1429. /* put it in the free list */
  1430. item->next = domain->thunk_free_lists [i];
  1431. domain->thunk_free_lists [i] = item;
  1432. }
  1433. l->next = NULL;
  1434. if (domain->thunk_free_lists [1]) {
  1435. domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
  1436. domain->thunk_free_lists [0]->length++;
  1437. } else {
  1438. g_assert (!domain->thunk_free_lists [0]);
  1439. domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
  1440. domain->thunk_free_lists [0]->length = 1;
  1441. }
  1442. }
  1443. typedef struct _GenericVirtualCase {
  1444. MonoMethod *method;
  1445. gpointer code;
  1446. int count;
  1447. struct _GenericVirtualCase *next;
  1448. } GenericVirtualCase;
  1449. /*
  1450. * get_generic_virtual_entries:
  1451. *
  1452. * Return IMT entries for the generic virtual method instances and
  1453. * variant interface methods for vtable slot
  1454. * VTABLE_SLOT.
  1455. */
  1456. static MonoImtBuilderEntry*
  1457. get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
  1458. {
  1459. GenericVirtualCase *list;
  1460. MonoImtBuilderEntry *entries;
  1461. mono_domain_lock (domain);
  1462. if (!domain->generic_virtual_cases)
  1463. domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
  1464. list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
  1465. entries = NULL;
  1466. for (; list; list = list->next) {
  1467. MonoImtBuilderEntry *entry;
  1468. if (list->count < THUNK_THRESHOLD)
  1469. continue;
  1470. entry = g_new0 (MonoImtBuilderEntry, 1);
  1471. entry->key = list->method;
  1472. entry->v

Large files files are truncated, but you can click here to view the full file