PageRenderTime 44ms CodeModel.GetById 36ms RepoModel.GetById 0ms 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
  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->value.target_code = mono_get_addr_from_ftnptr (list->code);
  1473. entry->has_target_code = 1;
  1474. if (entries)
  1475. entry->children = entries->children + 1;
  1476. entry->next = entries;
  1477. entries = entry;
  1478. }
  1479. mono_domain_unlock (domain);
  1480. /* FIXME: Leaking memory ? */
  1481. return entries;
  1482. }
  1483. /**
  1484. * mono_method_add_generic_virtual_invocation:
  1485. * @domain: a domain
  1486. * @vtable_slot: pointer to the vtable slot
  1487. * @method: the inflated generic virtual method
  1488. * @code: the method's code
  1489. *
  1490. * Registers a call via unmanaged code to a generic virtual method
  1491. * instantiation or variant interface method. If the number of calls reaches a threshold
  1492. * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
  1493. * virtual method thunk.
  1494. */
  1495. void
  1496. mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
  1497. gpointer *vtable_slot,
  1498. MonoMethod *method, gpointer code)
  1499. {
  1500. static gboolean inited = FALSE;
  1501. static int num_added = 0;
  1502. GenericVirtualCase *gvc, *list;
  1503. MonoImtBuilderEntry *entries;
  1504. int i;
  1505. GPtrArray *sorted;
  1506. mono_domain_lock (domain);
  1507. if (!domain->generic_virtual_cases)
  1508. domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
  1509. /* Check whether the case was already added */
  1510. list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
  1511. gvc = list;
  1512. while (gvc) {
  1513. if (gvc->method == method)
  1514. break;
  1515. gvc = gvc->next;
  1516. }
  1517. /* If not found, make a new one */
  1518. if (!gvc) {
  1519. gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
  1520. gvc->method = method;
  1521. gvc->code = code;
  1522. gvc->count = 0;
  1523. gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
  1524. g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
  1525. if (!inited) {
  1526. mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
  1527. inited = TRUE;
  1528. }
  1529. num_added++;
  1530. }
  1531. if (++gvc->count == THUNK_THRESHOLD) {
  1532. gpointer *old_thunk = *vtable_slot;
  1533. gpointer vtable_trampoline = NULL;
  1534. gpointer imt_trampoline = NULL;
  1535. if ((gpointer)vtable_slot < (gpointer)vtable) {
  1536. int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
  1537. int imt_slot = MONO_IMT_SIZE + displacement;
  1538. /* Force the rebuild of the thunk at the next call */
  1539. imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
  1540. *vtable_slot = imt_trampoline;
  1541. } else {
  1542. vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
  1543. entries = get_generic_virtual_entries (domain, vtable_slot);
  1544. sorted = imt_sort_slot_entries (entries);
  1545. *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
  1546. vtable_trampoline);
  1547. while (entries) {
  1548. MonoImtBuilderEntry *next = entries->next;
  1549. g_free (entries);
  1550. entries = next;
  1551. }
  1552. for (i = 0; i < sorted->len; ++i)
  1553. g_free (g_ptr_array_index (sorted, i));
  1554. g_ptr_array_free (sorted, TRUE);
  1555. }
  1556. #ifndef __native_client__
  1557. /* We don't re-use any thunks as there is a lot of overhead */
  1558. /* to deleting and re-using code in Native Client. */
  1559. if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
  1560. invalidate_generic_virtual_thunk (domain, old_thunk);
  1561. #endif
  1562. }
  1563. mono_domain_unlock (domain);
  1564. }
  1565. static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
  1566. /**
  1567. * mono_class_vtable:
  1568. * @domain: the application domain
  1569. * @class: the class to initialize
  1570. *
  1571. * VTables are domain specific because we create domain specific code, and
  1572. * they contain the domain specific static class data.
  1573. * On failure, NULL is returned, and class->exception_type is set.
  1574. */
  1575. MonoVTable *
  1576. mono_class_vtable (MonoDomain *domain, MonoClass *class)
  1577. {
  1578. return mono_class_vtable_full (domain, class, FALSE);
  1579. }
  1580. /**
  1581. * mono_class_vtable_full:
  1582. * @domain: the application domain
  1583. * @class: the class to initialize
  1584. * @raise_on_error if an exception should be raised on failure or not
  1585. *
  1586. * VTables are domain specific because we create domain specific code, and
  1587. * they contain the domain specific static class data.
  1588. */
  1589. MonoVTable *
  1590. mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
  1591. {
  1592. MonoClassRuntimeInfo *runtime_info;
  1593. g_assert (class);
  1594. if (class->exception_type) {
  1595. if (raise_on_error)
  1596. mono_raise_exception (mono_class_get_exception_for_failure (class));
  1597. return NULL;
  1598. }
  1599. /* this check can be inlined in jitted code, too */
  1600. runtime_info = class->runtime_info;
  1601. if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
  1602. return runtime_info->domain_vtables [domain->domain_id];
  1603. return mono_class_create_runtime_vtable (domain, class, raise_on_error);
  1604. }
  1605. /**
  1606. * mono_class_try_get_vtable:
  1607. * @domain: the application domain
  1608. * @class: the class to initialize
  1609. *
  1610. * This function tries to get the associated vtable from @class if
  1611. * it was already created.
  1612. */
  1613. MonoVTable *
  1614. mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
  1615. {
  1616. MonoClassRuntimeInfo *runtime_info;
  1617. g_assert (class);
  1618. runtime_info = class->runtime_info;
  1619. if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
  1620. return runtime_info->domain_vtables [domain->domain_id];
  1621. return NULL;
  1622. }
  1623. static MonoVTable *
  1624. mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
  1625. {
  1626. MonoVTable *vt;
  1627. MonoClassRuntimeInfo *runtime_info, *old_info;
  1628. MonoClassField *field;
  1629. char *t;
  1630. int i, vtable_slots;
  1631. int imt_table_bytes = 0;
  1632. int gc_bits;
  1633. guint32 vtable_size, class_size;
  1634. guint32 cindex;
  1635. gpointer iter;
  1636. gpointer *interface_offsets;
  1637. mono_loader_lock (); /*FIXME mono_class_init acquires it*/
  1638. mono_domain_lock (domain);
  1639. runtime_info = class->runtime_info;
  1640. if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
  1641. mono_domain_unlock (domain);
  1642. mono_loader_unlock ();
  1643. return runtime_info->domain_vtables [domain->domain_id];
  1644. }
  1645. if (!class->inited || class->exception_type) {
  1646. if (!mono_class_init (class) || class->exception_type) {
  1647. mono_domain_unlock (domain);
  1648. mono_loader_unlock ();
  1649. if (raise_on_error)
  1650. mono_raise_exception (mono_class_get_exception_for_failure (class));
  1651. return NULL;
  1652. }
  1653. }
  1654. /* Array types require that their element type be valid*/
  1655. if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
  1656. MonoClass *element_class = class->element_class;
  1657. if (!element_class->inited)
  1658. mono_class_init (element_class);
  1659. /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
  1660. if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
  1661. mono_class_setup_vtable (element_class);
  1662. if (element_class->exception_type != MONO_EXCEPTION_NONE) {
  1663. /*Can happen if element_class only got bad after mono_class_setup_vtable*/
  1664. if (class->exception_type == MONO_EXCEPTION_NONE)
  1665. mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
  1666. mono_domain_unlock (domain);
  1667. mono_loader_unlock ();
  1668. if (raise_on_error)
  1669. mono_raise_exception (mono_class_get_exception_for_failure (class));
  1670. return NULL;
  1671. }
  1672. }
  1673. /*
  1674. * For some classes, mono_class_init () already computed class->vtable_size, and
  1675. * that is all that is needed because of the vtable trampolines.
  1676. */
  1677. if (!class->vtable_size)
  1678. mono_class_setup_vtable (class);
  1679. if (class->generic_class && !class->vtable)
  1680. mono_class_check_vtable_constraints (class, NULL);
  1681. /* Initialize klass->has_finalize */
  1682. mono_class_has_finalizer (class);
  1683. if (class->exception_type) {
  1684. mono_domain_unlock (domain);
  1685. mono_loader_unlock ();
  1686. if (raise_on_error)
  1687. mono_raise_exception (mono_class_get_exception_for_failure (class));
  1688. return NULL;
  1689. }
  1690. vtable_slots = class->vtable_size;
  1691. /* we add an additional vtable slot to store the pointer to static field data only when needed */
  1692. class_size = mono_class_data_size (class);
  1693. if (class_size)
  1694. vtable_slots++;
  1695. if (ARCH_USE_IMT) {
  1696. vtable_size = MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
  1697. if (class->interface_offsets_count) {
  1698. imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
  1699. vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
  1700. mono_stats.imt_number_of_tables++;
  1701. mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
  1702. }
  1703. } else {
  1704. vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
  1705. MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
  1706. }
  1707. mono_stats.used_class_count++;
  1708. mono_stats.class_vtable_size += vtable_size;
  1709. interface_offsets = mono_domain_alloc0 (domain, vtable_size);
  1710. if (ARCH_USE_IMT)
  1711. vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
  1712. else
  1713. vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
  1714. vt->klass = class;
  1715. vt->rank = class->rank;
  1716. vt->domain = domain;
  1717. mono_class_compute_gc_descriptor (class);
  1718. /*
  1719. * We can't use typed allocation in the non-root domains, since the
  1720. * collector needs the GC descriptor stored in the vtable even after
  1721. * the mempool containing the vtable is destroyed when the domain is
  1722. * unloaded. An alternative might be to allocate vtables in the GC
  1723. * heap, but this does not seem to work (it leads to crashes inside
  1724. * libgc). If that approach is tried, two gc descriptors need to be
  1725. * allocated for each class: one for the root domain, and one for all
  1726. * other domains. The second descriptor should contain a bit for the
  1727. * vtable field in MonoObject, since we can no longer assume the
  1728. * vtable is reachable by other roots after the appdomain is unloaded.
  1729. */
  1730. #ifdef HAVE_BOEHM_GC
  1731. if (domain != mono_get_root_domain () && !mono_dont_free_domains)
  1732. vt->gc_descr = GC_NO_DESCRIPTOR;
  1733. else
  1734. #endif
  1735. vt->gc_descr = class->gc_descr;
  1736. gc_bits = mono_gc_get_vtable_bits (class);
  1737. g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
  1738. vt->gc_bits = gc_bits;
  1739. if (class_size) {
  1740. /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
  1741. if (class->has_static_refs) {
  1742. gpointer statics_gc_descr;
  1743. int max_set = 0;
  1744. gsize default_bitmap [4] = {0};
  1745. gsize *bitmap;
  1746. bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
  1747. /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
  1748. statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
  1749. vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
  1750. mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
  1751. if (bitmap != default_bitmap)
  1752. g_free (bitmap);
  1753. } else {
  1754. vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
  1755. }
  1756. vt->has_static_fields = TRUE;
  1757. mono_stats.class_static_data_size += class_size;
  1758. }
  1759. cindex = -1;
  1760. iter = NULL;
  1761. while ((field = mono_class_get_fields (class, &iter))) {
  1762. if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
  1763. continue;
  1764. if (mono_field_is_deleted (field))
  1765. continue;
  1766. if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
  1767. gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
  1768. if (special_static != SPECIAL_STATIC_NONE) {
  1769. guint32 size, offset;
  1770. gint32 align;
  1771. gsize default_bitmap [4] = {0};
  1772. gsize *bitmap;
  1773. int max_set = 0;
  1774. int numbits;
  1775. MonoClass *fclass;
  1776. if (mono_type_is_reference (field->type)) {
  1777. default_bitmap [0] = 1;
  1778. numbits = 1;
  1779. bitmap = default_bitmap;
  1780. } else if (mono_type_is_struct (field->type)) {
  1781. fclass = mono_class_from_mono_type (field->type);
  1782. bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
  1783. numbits = max_set + 1;
  1784. } else {
  1785. default_bitmap [0] = 0;
  1786. numbits = 0;
  1787. bitmap = default_bitmap;
  1788. }
  1789. size = mono_type_size (field->type, &align);
  1790. offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
  1791. if (!domain->special_static_fields)
  1792. domain->special_static_fields = g_hash_table_new (NULL, NULL);
  1793. g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
  1794. if (bitmap != default_bitmap)
  1795. g_free (bitmap);
  1796. /*
  1797. * This marks the field as special static to speed up the
  1798. * checks in mono_field_static_get/set_value ().
  1799. */
  1800. field->offset = -1;
  1801. continue;
  1802. }
  1803. }
  1804. if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
  1805. MonoClass *fklass = mono_class_from_mono_type (field->type);
  1806. const char *data = mono_field_get_data (field);
  1807. g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
  1808. t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
  1809. /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
  1810. if (!data)
  1811. continue;
  1812. if (fklass->valuetype) {
  1813. memcpy (t, data, mono_class_value_size (fklass, NULL));
  1814. } else {
  1815. /* it's a pointer type: add check */
  1816. g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
  1817. *t = *(char *)data;
  1818. }
  1819. continue;
  1820. }
  1821. }
  1822. vt->max_interface_id = class->max_interface_id;
  1823. vt->interface_bitmap = class->interface_bitmap;
  1824. //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
  1825. // class->name, class->interface_offsets_count);
  1826. if (! ARCH_USE_IMT) {
  1827. /* initialize interface offsets */
  1828. for (i = 0; i < class->interface_offsets_count; ++i) {
  1829. int interface_id = class->interfaces_packed [i]->interface_id;
  1830. int slot = class->interface_offsets_packed [i];
  1831. interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
  1832. }
  1833. }
  1834. /* Initialize vtable */
  1835. if (callbacks.get_vtable_trampoline) {
  1836. // This also covers the AOT case
  1837. for (i = 0; i < class->vtable_size; ++i) {
  1838. vt->vtable [i] = callbacks.get_vtable_trampoline (i);
  1839. }
  1840. } else {
  1841. mono_class_setup_vtable (class);
  1842. for (i = 0; i < class->vtable_size; ++i) {
  1843. MonoMethod *cm;
  1844. if ((cm = class->vtable [i]))
  1845. vt->vtable [i] = arch_create_jit_trampoline (cm);
  1846. }
  1847. }
  1848. if (ARCH_USE_IMT && imt_table_bytes) {
  1849. /* Now that the vtable is full, we can actually fill up the IMT */
  1850. if (callbacks.get_imt_trampoline) {
  1851. /* lazy construction of the IMT entries enabled */
  1852. for (i = 0; i < MONO_IMT_SIZE; ++i)
  1853. interface_offsets [i] = callbacks.get_imt_trampoline (i);
  1854. } else {
  1855. build_imt (class, vt, domain, interface_offsets, NULL);
  1856. }
  1857. }
  1858. /*
  1859. * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
  1860. * re-acquire them and check if another thread has created the vtable in the meantime.
  1861. */
  1862. /* Special case System.MonoType to avoid infinite recursion */
  1863. if (class != mono_defaults.monotype_class) {
  1864. /*FIXME check for OOM*/
  1865. vt->type = mono_type_get_object (domain, &class->byval_arg);
  1866. if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
  1867. /* This is unregistered in
  1868. unregister_vtable_reflection_type() in
  1869. domain.c. */
  1870. MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
  1871. }
  1872. if (mono_class_is_contextbound (class))
  1873. vt->remote = 1;
  1874. else
  1875. vt->remote = 0;
  1876. /* class_vtable_array keeps an array of created vtables
  1877. */
  1878. g_ptr_array_add (domain->class_vtable_array, vt);
  1879. /* class->runtime_info is protected by the loader lock, both when
  1880. * it it enlarged and when it is stored info.
  1881. */
  1882. /*
  1883. * Store the vtable in class->runtime_info.
  1884. * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
  1885. */
  1886. mono_memory_barrier ();
  1887. old_info = class->runtime_info;
  1888. if (old_info && old_info->max_domain >= domain->domain_id) {
  1889. /* someone already created a large enough runtime info */
  1890. old_info->domain_vtables [domain->domain_id] = vt;
  1891. } else {
  1892. int new_size = domain->domain_id;
  1893. if (old_info)
  1894. new_size = MAX (new_size, old_info->max_domain);
  1895. new_size++;
  1896. /* make the new size a power of two */
  1897. i = 2;
  1898. while (new_size > i)
  1899. i <<= 1;
  1900. new_size = i;
  1901. /* this is a bounded memory retention issue: may want to
  1902. * handle it differently when we'll have a rcu-like system.
  1903. */
  1904. runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
  1905. runtime_info->max_domain = new_size - 1;
  1906. /* copy the stuff from the older info */
  1907. if (old_info) {
  1908. memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
  1909. }
  1910. runtime_info->domain_vtables [domain->domain_id] = vt;
  1911. /* keep this last*/
  1912. mono_memory_barrier ();
  1913. class->runtime_info = runtime_info;
  1914. }
  1915. if (class == mono_defaults.monotype_class) {
  1916. /*FIXME check for OOM*/
  1917. vt->type = mono_type_get_object (domain, &class->byval_arg);
  1918. if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
  1919. /* This is unregistered in
  1920. unregister_vtable_reflection_type() in
  1921. domain.c. */
  1922. MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
  1923. }
  1924. mono_domain_unlock (domain);
  1925. mono_loader_unlock ();
  1926. /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
  1927. if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
  1928. mono_raise_exception (mono_class_get_exception_for_failure (class));
  1929. /* make sure the parent is initialized */
  1930. /*FIXME shouldn't this fail the current type?*/
  1931. if (class->parent)
  1932. mono_class_vtable_full (domain, class->parent, raise_on_error);
  1933. return vt;
  1934. }
  1935. #ifndef DISABLE_REMOTING
  1936. /**
  1937. * mono_class_proxy_vtable:
  1938. * @domain: the application domain
  1939. * @remove_class: the remote class
  1940. *
  1941. * Creates a vtable for transparent proxies. It is basically
  1942. * a copy of the real vtable of the class wrapped in @remote_class,
  1943. * but all function pointers invoke the remoting functions, and
  1944. * vtable->klass points to the transparent proxy class, and not to @class.
  1945. */
  1946. static MonoVTable *
  1947. mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
  1948. {
  1949. MonoError error;
  1950. MonoVTable *vt, *pvt;
  1951. int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
  1952. MonoClass *k;
  1953. GSList *extra_interfaces = NULL;
  1954. MonoClass *class = remote_class->proxy_class;
  1955. gpointer *interface_offsets;
  1956. uint8_t *bitmap;
  1957. int bsize;
  1958. #ifdef COMPRESSED_INTERFACE_BITMAP
  1959. int bcsize;
  1960. #endif
  1961. vt = mono_class_vtable (domain, class);
  1962. g_assert (vt); /*FIXME property handle failure*/
  1963. max_interface_id = vt->max_interface_id;
  1964. /* Calculate vtable space for extra interfaces */
  1965. for (j = 0; j < remote_class->interface_count; j++) {
  1966. MonoClass* iclass = remote_class->interfaces[j];
  1967. GPtrArray *ifaces;
  1968. int method_count;
  1969. /*FIXME test for interfaces with variant generic arguments*/
  1970. if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
  1971. continue; /* interface implemented by the class */
  1972. if (g_slist_find (extra_interfaces, iclass))
  1973. continue;
  1974. extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
  1975. method_count = mono_class_num_methods (iclass);
  1976. ifaces = mono_class_get_implemented_interfaces (iclass, &error);
  1977. g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
  1978. if (ifaces) {
  1979. for (i = 0; i < ifaces->len; ++i) {
  1980. MonoClass *ic = g_ptr_array_index (ifaces, i);
  1981. /*FIXME test for interfaces with variant generic arguments*/
  1982. if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
  1983. continue; /* interface implemented by the class */
  1984. if (g_slist_find (extra_interfaces, ic))
  1985. continue;
  1986. extra_interfaces = g_slist_prepend (extra_interfaces, ic);
  1987. method_count += mono_class_num_methods (ic);
  1988. }
  1989. g_ptr_array_free (ifaces, TRUE);
  1990. }
  1991. extra_interface_vtsize += method_count * sizeof (gpointer);
  1992. if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
  1993. }
  1994. if (ARCH_USE_IMT) {
  1995. mono_stats.imt_number_of_tables++;
  1996. mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
  1997. vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
  1998. MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
  1999. } else {
  2000. vtsize = sizeof (gpointer) * (max_interface_id + 1) +
  2001. MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
  2002. }
  2003. mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
  2004. interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
  2005. if (ARCH_USE_IMT)
  2006. pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
  2007. else
  2008. pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
  2009. memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
  2010. pvt->klass = mono_defaults.transparent_proxy_class;
  2011. /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
  2012. pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
  2013. /* initialize vtable */
  2014. mono_class_setup_vtable (class);
  2015. for (i = 0; i < class->vtable_size; ++i) {
  2016. MonoMethod *cm;
  2017. if ((cm = class->vtable [i]))
  2018. pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
  2019. else
  2020. pvt->vtable [i] = NULL;
  2021. }
  2022. if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
  2023. /* create trampolines for abstract methods */
  2024. for (k = class; k; k = k->parent) {
  2025. MonoMethod* m;
  2026. gpointer iter = NULL;
  2027. while ((m = mono_class_get_methods (k, &iter)))
  2028. if (!pvt->vtable [m->slot])
  2029. pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
  2030. }
  2031. }
  2032. pvt->max_interface_id = max_interface_id;
  2033. bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
  2034. #ifdef COMPRESSED_INTERFACE_BITMAP
  2035. bitmap = g_malloc0 (bsize);
  2036. #else
  2037. bitmap = mono_domain_alloc0 (domain, bsize);
  2038. #endif
  2039. if (! ARCH_USE_IMT) {
  2040. /* initialize interface offsets */
  2041. for (i = 0; i < class->interface_offsets_count; ++i) {
  2042. int interface_id = class->interfaces_packed [i]->interface_id;
  2043. int slot = class->interface_offsets_packed [i];
  2044. interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
  2045. }
  2046. }
  2047. for (i = 0; i < class->interface_offsets_count; ++i) {
  2048. int interface_id = class->interfaces_packed [i]->interface_id;
  2049. bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
  2050. }
  2051. if (extra_interfaces) {
  2052. int slot = class->vtable_size;
  2053. MonoClass* interf;
  2054. gpointer iter;
  2055. MonoMethod* cm;
  2056. GSList *list_item;
  2057. /* Create trampolines for the methods of the interfaces */
  2058. for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
  2059. interf = list_item->data;
  2060. if (! ARCH_USE_IMT) {
  2061. interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
  2062. }
  2063. bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
  2064. iter = NULL;
  2065. j = 0;
  2066. while ((cm = mono_class_get_methods (interf, &iter)))
  2067. pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
  2068. slot += mono_class_num_methods (interf);
  2069. }
  2070. if (! ARCH_USE_IMT) {
  2071. g_slist_free (extra_interfaces);
  2072. }
  2073. }
  2074. if (ARCH_USE_IMT) {
  2075. /* Now that the vtable is full, we can actually fill up the IMT */
  2076. build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
  2077. if (extra_interfaces) {
  2078. g_slist_free (extra_interfaces);
  2079. }
  2080. }
  2081. #ifdef COMPRESSED_INTERFACE_BITMAP
  2082. bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
  2083. pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
  2084. mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
  2085. g_free (bitmap);
  2086. #else
  2087. pvt->interface_bitmap = bitmap;
  2088. #endif
  2089. return pvt;
  2090. }
  2091. #endif /* DISABLE_REMOTING */
  2092. /**
  2093. * mono_class_field_is_special_static:
  2094. *
  2095. * Returns whether @field is a thread/context static field.
  2096. */
  2097. gboolean
  2098. mono_class_field_is_special_static (MonoClassField *field)
  2099. {
  2100. if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
  2101. return FALSE;
  2102. if (mono_field_is_deleted (field))
  2103. return FALSE;
  2104. if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
  2105. if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
  2106. return TRUE;
  2107. }
  2108. return FALSE;
  2109. }
  2110. /**
  2111. * mono_class_field_get_special_static_type:
  2112. * @field: The MonoClassField describing the field.
  2113. *
  2114. * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
  2115. * SPECIAL_STATIC_NONE otherwise.
  2116. */
  2117. guint32
  2118. mono_class_field_get_special_static_type (MonoClassField *field)
  2119. {
  2120. if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
  2121. return SPECIAL_STATIC_NONE;
  2122. if (mono_field_is_deleted (field))
  2123. return SPECIAL_STATIC_NONE;
  2124. if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
  2125. return field_is_special_static (field->parent, field);
  2126. return SPECIAL_STATIC_NONE;
  2127. }
  2128. /**
  2129. * mono_class_has_special_static_fields:
  2130. *
  2131. * Returns whenever @klass has any thread/context static fields.
  2132. */
  2133. gboolean
  2134. mono_class_has_special_static_fields (MonoClass *klass)
  2135. {
  2136. MonoClassField *field;
  2137. gpointer iter;
  2138. iter = NULL;
  2139. while ((field = mono_class_get_fields (klass, &iter))) {
  2140. g_assert (field->parent == klass);
  2141. if (mono_class_field_is_special_static (field))
  2142. return TRUE;
  2143. }
  2144. return FALSE;
  2145. }
  2146. #ifndef DISABLE_REMOTING
  2147. /**
  2148. * create_remote_class_key:
  2149. * Creates an array of pointers that can be used as a hash key for a remote class.
  2150. * The first element of the array is the number of pointers.
  2151. */
  2152. static gpointer*
  2153. create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
  2154. {
  2155. gpointer *key;
  2156. int i, j;
  2157. if (remote_class == NULL) {
  2158. if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
  2159. key = g_malloc (sizeof(gpointer) * 3);
  2160. key [0] = GINT_TO_POINTER (2);
  2161. key [1] = mono_defaults.marshalbyrefobject_class;
  2162. key [2] = extra_class;
  2163. } else {
  2164. key = g_malloc (sizeof(gpointer) * 2);
  2165. key [0] = GINT_TO_POINTER (1);
  2166. key [1] = extra_class;
  2167. }
  2168. } else {
  2169. if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
  2170. key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
  2171. key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
  2172. key [1] = remote_class->proxy_class;
  2173. // Keep the list of interfaces sorted
  2174. for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
  2175. if (extra_class && remote_class->interfaces [i] > extra_class) {
  2176. key [j++] = extra_class;
  2177. extra_class = NULL;
  2178. }
  2179. key [j] = remote_class->interfaces [i];
  2180. }
  2181. if (extra_class)
  2182. key [j] = extra_class;
  2183. } else {
  2184. // Replace the old class. The interface list is the same
  2185. key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
  2186. key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
  2187. key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
  2188. for (i = 0; i < remote_class->interface_count; i++)
  2189. key [2 + i] = remote_class->interfaces [i];
  2190. }
  2191. }
  2192. return key;
  2193. }
  2194. /**
  2195. * copy_remote_class_key:
  2196. *
  2197. * Make a copy of KEY in the domain and return the copy.
  2198. */
  2199. static gpointer*
  2200. copy_remote_class_key (MonoDomain *domain, gpointer *key)
  2201. {
  2202. int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
  2203. gpointer *mp_key = mono_domain_alloc (domain, key_size);
  2204. memcpy (mp_key, key, key_size);
  2205. return mp_key;
  2206. }
  2207. /**
  2208. * mono_remote_class:
  2209. * @domain: the application domain
  2210. * @class_name: name of the remote class
  2211. *
  2212. * Creates and initializes a MonoRemoteClass object for a remote type.
  2213. *
  2214. * Can raise an exception on failure.
  2215. */
  2216. MonoRemoteClass*
  2217. mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
  2218. {
  2219. MonoError error;
  2220. MonoRemoteClass *rc;
  2221. gpointer* key, *mp_key;
  2222. char *name;
  2223. key = create_remote_class_key (NULL, proxy_class);
  2224. mono_domain_lock (domain);
  2225. rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
  2226. if (rc) {
  2227. g_free (key);
  2228. mono_domain_unlock (domain);
  2229. return rc;
  2230. }
  2231. name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
  2232. if (!mono_error_ok (&error)) {
  2233. g_free (key);
  2234. mono_domain_unlock (domain);
  2235. mono_error_raise_exception (&error);
  2236. }
  2237. mp_key = copy_remote_class_key (domain, key);
  2238. g_free (key);
  2239. key = mp_key;
  2240. if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
  2241. rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
  2242. rc->interface_count = 1;
  2243. rc->interfaces [0] = proxy_class;
  2244. rc->proxy_class = mono_defaults.marshalbyrefobject_class;
  2245. } else {
  2246. rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
  2247. rc->interface_count = 0;
  2248. rc->proxy_class = proxy_class;
  2249. }
  2250. rc->default_vtable = NULL;
  2251. rc->xdomain_vtable = NULL;
  2252. rc->proxy_class_name = name;
  2253. #ifndef DISABLE_PERFCOUNTERS
  2254. mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
  2255. #endif
  2256. g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
  2257. mono_domain_unlock (domain);
  2258. return rc;
  2259. }
  2260. /**
  2261. * clone_remote_class:
  2262. * Creates a copy of the remote_class, adding the provided class or interface
  2263. */
  2264. static MonoRemoteClass*
  2265. clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
  2266. {
  2267. MonoRemoteClass *rc;
  2268. gpointer* key, *mp_key;
  2269. key = create_remote_class_key (remote_class, extra_class);
  2270. rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
  2271. if (rc != NULL) {
  2272. g_free (key);
  2273. return rc;
  2274. }
  2275. mp_key = copy_remote_class_key (domain, key);
  2276. g_free (key);
  2277. key = mp_key;
  2278. if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
  2279. int i,j;
  2280. rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
  2281. rc->proxy_class = remote_class->proxy_class;
  2282. rc->interface_count = remote_class->interface_count + 1;
  2283. // Keep the list of interfaces sorted, since the hash key of
  2284. // the remote class depends on this
  2285. for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
  2286. if (remote_class->interfaces [i] > extra_class && i == j)
  2287. rc->interfaces [j++] = extra_class;
  2288. rc->interfaces [j] = remote_class->interfaces [i];
  2289. }
  2290. if (i == j)
  2291. rc->interfaces [j] = extra_class;
  2292. } else {
  2293. // Replace the old class. The interface array is the same
  2294. rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
  2295. rc->proxy_class = extra_class;
  2296. rc->interface_count = remote_class->interface_count;
  2297. if (rc->interface_count > 0)
  2298. memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
  2299. }
  2300. rc->default_vtable = NULL;
  2301. rc->xdomain_vtable = NULL;
  2302. rc->proxy_class_name = remote_class->proxy_class_name;
  2303. g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
  2304. return rc;
  2305. }
  2306. gpointer
  2307. mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
  2308. {
  2309. mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
  2310. mono_domain_lock (domain);
  2311. if (rp->target_domain_id != -1) {
  2312. if (remote_class->xdomain_vtable == NULL)
  2313. remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
  2314. mono_domain_unlock (domain);
  2315. mono_loader_unlock ();
  2316. return remote_class->xdomain_vtable;
  2317. }
  2318. if (remote_class->default_vtable == NULL) {
  2319. MonoType *type;
  2320. MonoClass *klass;
  2321. type = ((MonoReflectionType *)rp->class_to_proxy)->type;
  2322. klass = mono_class_from_mono_type (type);
  2323. #ifndef DISABLE_COM
  2324. if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
  2325. remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
  2326. else
  2327. #endif
  2328. remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
  2329. }
  2330. mono_domain_unlock (domain);
  2331. mono_loader_unlock ();
  2332. return remote_class->default_vtable;
  2333. }
  2334. /**
  2335. * mono_upgrade_remote_class:
  2336. * @domain: the application domain
  2337. * @tproxy: the proxy whose remote class has to be upgraded.
  2338. * @klass: class to which the remote class can be casted.
  2339. *
  2340. * Updates the vtable of the remote class by adding the necessary method slots
  2341. * and interface offsets so it can be safely casted to klass. klass can be a
  2342. * class or an interface.
  2343. */
  2344. void
  2345. mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
  2346. {
  2347. MonoTransparentProxy *tproxy;
  2348. MonoRemoteClass *remote_class;
  2349. gboolean redo_vtable;
  2350. mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
  2351. mono_domain_lock (domain);
  2352. tproxy = (MonoTransparentProxy*) proxy_object;
  2353. remote_class = tproxy->remote_class;
  2354. if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
  2355. int i;
  2356. redo_vtable = TRUE;
  2357. for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
  2358. if (remote_class->interfaces [i] == klass)
  2359. redo_vtable = FALSE;
  2360. }
  2361. else {
  2362. redo_vtable = (remote_class->proxy_class != klass);
  2363. }
  2364. if (redo_vtable) {
  2365. tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
  2366. proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
  2367. }
  2368. mono_domain_unlock (domain);
  2369. mono_loader_unlock ();
  2370. }
  2371. #endif /* DISABLE_REMOTING */
  2372. /**
  2373. * mono_object_get_virtual_method:
  2374. * @obj: object to operate on.
  2375. * @method: method
  2376. *
  2377. * Retrieves the MonoMethod that would be called on obj if obj is passed as
  2378. * the instance of a callvirt of method.
  2379. */
  2380. MonoMethod*
  2381. mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
  2382. {
  2383. MonoClass *klass;
  2384. MonoMethod **vtable;
  2385. gboolean is_proxy = FALSE;
  2386. MonoMethod *res = NULL;
  2387. klass = mono_object_class (obj);
  2388. #ifndef DISABLE_REMOTING
  2389. if (klass == mono_defaults.transparent_proxy_class) {
  2390. klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
  2391. is_proxy = TRUE;
  2392. }
  2393. #endif
  2394. if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
  2395. return method;
  2396. mono_class_setup_vtable (klass);
  2397. vtable = klass->vtable;
  2398. if (method->slot == -1) {
  2399. /* method->slot might not be set for instances of generic methods */
  2400. if (method->is_inflated) {
  2401. g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
  2402. method->slot = ((MonoMethodInflated*)method)->declaring->slot;
  2403. } else {
  2404. if (!is_proxy)
  2405. g_assert_not_reached ();
  2406. }
  2407. }
  2408. /* check method->slot is a valid index: perform isinstance? */
  2409. if (method->slot != -1) {
  2410. if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
  2411. if (!is_proxy) {
  2412. gboolean variance_used = FALSE;
  2413. int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
  2414. g_assert (iface_offset > 0);
  2415. res = vtable [iface_offset + method->slot];
  2416. }
  2417. } else {
  2418. res = vtable [method->slot];
  2419. }
  2420. }
  2421. #ifndef DISABLE_REMOTING
  2422. if (is_proxy) {
  2423. /* It may be an interface, abstract class method or generic method */
  2424. if (!res || mono_method_signature (res)->generic_param_count)
  2425. res = method;
  2426. /* generic methods demand invoke_with_check */
  2427. if (mono_method_signature (res)->generic_param_count)
  2428. res = mono_marshal_get_remoting_invoke_with_check (res);
  2429. else {
  2430. #ifndef DISABLE_COM
  2431. if (klass == mono_defaults.com_object_class || klass->is_com_object)
  2432. res = mono_cominterop_get_invoke (res);
  2433. else
  2434. #endif
  2435. res = mono_marshal_get_remoting_invoke (res);
  2436. }
  2437. } else
  2438. #endif
  2439. {
  2440. if (method->is_inflated) {
  2441. /* Have to inflate the result */
  2442. res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
  2443. }
  2444. }
  2445. g_assert (res);
  2446. return res;
  2447. }
  2448. static MonoObject*
  2449. dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
  2450. {
  2451. g_error ("runtime invoke called on uninitialized runtime");
  2452. return NULL;
  2453. }
  2454. static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
  2455. /**
  2456. * mono_runtime_invoke:
  2457. * @method: method to invoke
  2458. * @obJ: object instance
  2459. * @params: arguments to the method
  2460. * @exc: exception information.
  2461. *
  2462. * Invokes the method represented by @method on the object @obj.
  2463. *
  2464. * obj is the 'this' pointer, it should be NULL for static
  2465. * methods, a MonoObject* for object instances and a pointer to
  2466. * the value type for value types.
  2467. *
  2468. * The params array contains the arguments to the method with the
  2469. * same convention: MonoObject* pointers for object instances and
  2470. * pointers to the value type otherwise.
  2471. *
  2472. * From unmanaged code you'll usually use the
  2473. * mono_runtime_invoke() variant.
  2474. *
  2475. * Note that this function doesn't handle virtual methods for
  2476. * you, it will exec the exact method you pass: we still need to
  2477. * expose a function to lookup the derived class implementation
  2478. * of a virtual method (there are examples of this in the code,
  2479. * though).
  2480. *
  2481. * You can pass NULL as the exc argument if you don't want to
  2482. * catch exceptions, otherwise, *exc will be set to the exception
  2483. * thrown, if any. if an exception is thrown, you can't use the
  2484. * MonoObject* result from the function.
  2485. *
  2486. * If the method returns a value type, it is boxed in an object
  2487. * reference.
  2488. */
  2489. MonoObject*
  2490. mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
  2491. {
  2492. MonoObject *result;
  2493. if (mono_runtime_get_no_exec ())
  2494. g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
  2495. if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
  2496. mono_profiler_method_start_invoke (method);
  2497. result = default_mono_runtime_invoke (method, obj, params, exc);
  2498. if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
  2499. mono_profiler_method_end_invoke (method);
  2500. return result;
  2501. }
  2502. /**
  2503. * mono_method_get_unmanaged_thunk:
  2504. * @method: method to generate a thunk for.
  2505. *
  2506. * Returns an unmanaged->managed thunk that can be used to call
  2507. * a managed method directly from C.
  2508. *
  2509. * The thunk's C signature closely matches the managed signature:
  2510. *
  2511. * C#: public bool Equals (object obj);
  2512. * C: typedef MonoBoolean (*Equals)(MonoObject*,
  2513. * MonoObject*, MonoException**);
  2514. *
  2515. * The 1st ("this") parameter must not be used with static methods:
  2516. *
  2517. * C#: public static bool ReferenceEquals (object a, object b);
  2518. * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
  2519. * MonoException**);
  2520. *
  2521. * The last argument must be a non-null pointer of a MonoException* pointer.
  2522. * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
  2523. * exception has been thrown in managed code. Otherwise it will point
  2524. * to the MonoException* caught by the thunk. In this case, the result of
  2525. * the thunk is undefined:
  2526. *
  2527. * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
  2528. * MonoException *ex = NULL;
  2529. * Equals func = mono_method_get_unmanaged_thunk (method);
  2530. * MonoBoolean res = func (thisObj, objToCompare, &ex);
  2531. * if (ex) {
  2532. * // handle exception
  2533. * }
  2534. *
  2535. * The calling convention of the thunk matches the platform's default
  2536. * convention. This means that under Windows, C declarations must
  2537. * contain the __stdcall attribute:
  2538. *
  2539. * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
  2540. * MonoObject*, MonoException**);
  2541. *
  2542. * LIMITATIONS
  2543. *
  2544. * Value type arguments and return values are treated as they were objects:
  2545. *
  2546. * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
  2547. * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
  2548. *
  2549. * Arguments must be properly boxed upon trunk's invocation, while return
  2550. * values must be unboxed.
  2551. */
  2552. gpointer
  2553. mono_method_get_unmanaged_thunk (MonoMethod *method)
  2554. {
  2555. method = mono_marshal_get_thunk_invoke_wrapper (method);
  2556. return mono_compile_method (method);
  2557. }
  2558. static void
  2559. set_value (MonoType *type, void *dest, void *value, int deref_pointer)
  2560. {
  2561. int t;
  2562. if (type->byref) {
  2563. /* object fields cannot be byref, so we don't need a
  2564. wbarrier here */
  2565. gpointer *p = (gpointer*)dest;
  2566. *p = value;
  2567. return;
  2568. }
  2569. t = type->type;
  2570. handle_enum:
  2571. switch (t) {
  2572. case MONO_TYPE_BOOLEAN:
  2573. case MONO_TYPE_I1:
  2574. case MONO_TYPE_U1: {
  2575. guint8 *p = (guint8*)dest;
  2576. *p = value ? *(guint8*)value : 0;
  2577. return;
  2578. }
  2579. case MONO_TYPE_I2:
  2580. case MONO_TYPE_U2:
  2581. case MONO_TYPE_CHAR: {
  2582. guint16 *p = (guint16*)dest;
  2583. *p = value ? *(guint16*)value : 0;
  2584. return;
  2585. }
  2586. #if SIZEOF_VOID_P == 4
  2587. case MONO_TYPE_I:
  2588. case MONO_TYPE_U:
  2589. #endif
  2590. case MONO_TYPE_I4:
  2591. case MONO_TYPE_U4: {
  2592. gint32 *p = (gint32*)dest;
  2593. *p = value ? *(gint32*)value : 0;
  2594. return;
  2595. }
  2596. #if SIZEOF_VOID_P == 8
  2597. case MONO_TYPE_I:
  2598. case MONO_TYPE_U:
  2599. #endif
  2600. case MONO_TYPE_I8:
  2601. case MONO_TYPE_U8: {
  2602. gint64 *p = (gint64*)dest;
  2603. *p = value ? *(gint64*)value : 0;
  2604. return;
  2605. }
  2606. case MONO_TYPE_R4: {
  2607. float *p = (float*)dest;
  2608. *p = value ? *(float*)value : 0;
  2609. return;
  2610. }
  2611. case MONO_TYPE_R8: {
  2612. double *p = (double*)dest;
  2613. *p = value ? *(double*)value : 0;
  2614. return;
  2615. }
  2616. case MONO_TYPE_STRING:
  2617. case MONO_TYPE_SZARRAY:
  2618. case MONO_TYPE_CLASS:
  2619. case MONO_TYPE_OBJECT:
  2620. case MONO_TYPE_ARRAY:
  2621. mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
  2622. return;
  2623. case MONO_TYPE_FNPTR:
  2624. case MONO_TYPE_PTR: {
  2625. gpointer *p = (gpointer*)dest;
  2626. *p = deref_pointer? *(gpointer*)value: value;
  2627. return;
  2628. }
  2629. case MONO_TYPE_VALUETYPE:
  2630. /* note that 't' and 'type->type' can be different */
  2631. if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
  2632. t = mono_class_enum_basetype (type->data.klass)->type;
  2633. goto handle_enum;
  2634. } else {
  2635. MonoClass *class = mono_class_from_mono_type (type);
  2636. int size = mono_class_value_size (class, NULL);
  2637. if (value == NULL)
  2638. mono_gc_bzero (dest, size);
  2639. else
  2640. mono_gc_wbarrier_value_copy (dest, value, 1, class);
  2641. }
  2642. return;
  2643. case MONO_TYPE_GENERICINST:
  2644. t = type->data.generic_class->container_class->byval_arg.type;
  2645. goto handle_enum;
  2646. default:
  2647. g_error ("got type %x", type->type);
  2648. }
  2649. }
  2650. /**
  2651. * mono_field_set_value:
  2652. * @obj: Instance object
  2653. * @field: MonoClassField describing the field to set
  2654. * @value: The value to be set
  2655. *
  2656. * Sets the value of the field described by @field in the object instance @obj
  2657. * to the value passed in @value. This method should only be used for instance
  2658. * fields. For static fields, use mono_field_static_set_value.
  2659. *
  2660. * The value must be on the native format of the field type.
  2661. */
  2662. void
  2663. mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
  2664. {
  2665. void *dest;
  2666. g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
  2667. dest = (char*)obj + field->offset;
  2668. set_value (field->type, dest, value, FALSE);
  2669. }
  2670. /**
  2671. * mono_field_static_set_value:
  2672. * @field: MonoClassField describing the field to set
  2673. * @value: The value to be set
  2674. *
  2675. * Sets the value of the static field described by @field
  2676. * to the value passed in @value.
  2677. *
  2678. * The value must be on the native format of the field type.
  2679. */
  2680. void
  2681. mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
  2682. {
  2683. void *dest;
  2684. g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
  2685. /* you cant set a constant! */
  2686. g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
  2687. if (field->offset == -1) {
  2688. /* Special static */
  2689. gpointer addr;
  2690. mono_domain_lock (vt->domain);
  2691. addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
  2692. mono_domain_unlock (vt->domain);
  2693. dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
  2694. } else {
  2695. dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
  2696. }
  2697. set_value (field->type, dest, value, FALSE);
  2698. }
  2699. /**
  2700. * mono_vtable_get_static_field_data:
  2701. *
  2702. * Internal use function: return a pointer to the memory holding the static fields
  2703. * for a class or NULL if there are no static fields.
  2704. * This is exported only for use by the debugger.
  2705. */
  2706. void *
  2707. mono_vtable_get_static_field_data (MonoVTable *vt)
  2708. {
  2709. if (!vt->has_static_fields)
  2710. return NULL;
  2711. return vt->vtable [vt->klass->vtable_size];
  2712. }
  2713. static guint8*
  2714. mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
  2715. {
  2716. guint8 *src;
  2717. if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
  2718. if (field->offset == -1) {
  2719. /* Special static */
  2720. gpointer addr;
  2721. mono_domain_lock (vt->domain);
  2722. addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
  2723. mono_domain_unlock (vt->domain);
  2724. src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
  2725. } else {
  2726. src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
  2727. }
  2728. } else {
  2729. src = (guint8*)obj + field->offset;
  2730. }
  2731. return src;
  2732. }
  2733. /**
  2734. * mono_field_get_value:
  2735. * @obj: Object instance
  2736. * @field: MonoClassField describing the field to fetch information from
  2737. * @value: pointer to the location where the value will be stored
  2738. *
  2739. * Use this routine to get the value of the field @field in the object
  2740. * passed.
  2741. *
  2742. * The pointer provided by value must be of the field type, for reference
  2743. * types this is a MonoObject*, for value types its the actual pointer to
  2744. * the value type.
  2745. *
  2746. * For example:
  2747. * int i;
  2748. * mono_field_get_value (obj, int_field, &i);
  2749. */
  2750. void
  2751. mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
  2752. {
  2753. void *src;
  2754. g_assert (obj);
  2755. g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
  2756. src = (char*)obj + field->offset;
  2757. set_value (field->type, value, src, TRUE);
  2758. }
  2759. /**
  2760. * mono_field_get_value_object:
  2761. * @domain: domain where the object will be created (if boxing)
  2762. * @field: MonoClassField describing the field to fetch information from
  2763. * @obj: The object instance for the field.
  2764. *
  2765. * Returns: a new MonoObject with the value from the given field. If the
  2766. * field represents a value type, the value is boxed.
  2767. *
  2768. */
  2769. MonoObject *
  2770. mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
  2771. {
  2772. MonoObject *o;
  2773. MonoClass *klass;
  2774. MonoVTable *vtable = NULL;
  2775. gchar *v;
  2776. gboolean is_static = FALSE;
  2777. gboolean is_ref = FALSE;
  2778. gboolean is_literal = FALSE;
  2779. gboolean is_ptr = FALSE;
  2780. MonoError error;
  2781. MonoType *type = mono_field_get_type_checked (field, &error);
  2782. if (!mono_error_ok (&error))
  2783. mono_error_raise_exception (&error);
  2784. switch (type->type) {
  2785. case MONO_TYPE_STRING:
  2786. case MONO_TYPE_OBJECT:
  2787. case MONO_TYPE_CLASS:
  2788. case MONO_TYPE_ARRAY:
  2789. case MONO_TYPE_SZARRAY:
  2790. is_ref = TRUE;
  2791. break;
  2792. case MONO_TYPE_U1:
  2793. case MONO_TYPE_I1:
  2794. case MONO_TYPE_BOOLEAN:
  2795. case MONO_TYPE_U2:
  2796. case MONO_TYPE_I2:
  2797. case MONO_TYPE_CHAR:
  2798. case MONO_TYPE_U:
  2799. case MONO_TYPE_I:
  2800. case MONO_TYPE_U4:
  2801. case MONO_TYPE_I4:
  2802. case MONO_TYPE_R4:
  2803. case MONO_TYPE_U8:
  2804. case MONO_TYPE_I8:
  2805. case MONO_TYPE_R8:
  2806. case MONO_TYPE_VALUETYPE:
  2807. is_ref = type->byref;
  2808. break;
  2809. case MONO_TYPE_GENERICINST:
  2810. is_ref = !mono_type_generic_inst_is_valuetype (type);
  2811. break;
  2812. case MONO_TYPE_PTR:
  2813. is_ptr = TRUE;
  2814. break;
  2815. default:
  2816. g_error ("type 0x%x not handled in "
  2817. "mono_field_get_value_object", type->type);
  2818. return NULL;
  2819. }
  2820. if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
  2821. is_literal = TRUE;
  2822. if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
  2823. is_static = TRUE;
  2824. if (!is_literal) {
  2825. vtable = mono_class_vtable (domain, field->parent);
  2826. if (!vtable) {
  2827. char *name = mono_type_get_full_name (field->parent);
  2828. /*FIXME extend this to use the MonoError api*/
  2829. g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
  2830. g_free (name);
  2831. return NULL;
  2832. }
  2833. if (!vtable->initialized)
  2834. mono_runtime_class_init (vtable);
  2835. }
  2836. } else {
  2837. g_assert (obj);
  2838. }
  2839. if (is_ref) {
  2840. if (is_literal) {
  2841. get_default_field_value (domain, field, &o);
  2842. } else if (is_static) {
  2843. mono_field_static_get_value (vtable, field, &o);
  2844. } else {
  2845. mono_field_get_value (obj, field, &o);
  2846. }
  2847. return o;
  2848. }
  2849. if (is_ptr) {
  2850. static MonoMethod *m;
  2851. gpointer args [2];
  2852. gpointer *ptr;
  2853. gpointer v;
  2854. if (!m) {
  2855. MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
  2856. m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
  2857. g_assert (m);
  2858. }
  2859. v = &ptr;
  2860. if (is_literal) {
  2861. get_default_field_value (domain, field, v);
  2862. } else if (is_static) {
  2863. mono_field_static_get_value (vtable, field, v);
  2864. } else {
  2865. mono_field_get_value (obj, field, v);
  2866. }
  2867. /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
  2868. args [0] = *ptr;
  2869. args [1] = mono_type_get_object (mono_domain_get (), type);
  2870. return mono_runtime_invoke (m, NULL, args, NULL);
  2871. }
  2872. /* boxed value type */
  2873. klass = mono_class_from_mono_type (type);
  2874. if (mono_class_is_nullable (klass))
  2875. return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
  2876. o = mono_object_new (domain, klass);
  2877. v = ((gchar *) o) + sizeof (MonoObject);
  2878. if (is_literal) {
  2879. get_default_field_value (domain, field, v);
  2880. } else if (is_static) {
  2881. mono_field_static_get_value (vtable, field, v);
  2882. } else {
  2883. mono_field_get_value (obj, field, v);
  2884. }
  2885. return o;
  2886. }
  2887. int
  2888. mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
  2889. {
  2890. int retval = 0;
  2891. const char *p = blob;
  2892. mono_metadata_decode_blob_size (p, &p);
  2893. switch (type) {
  2894. case MONO_TYPE_BOOLEAN:
  2895. case MONO_TYPE_U1:
  2896. case MONO_TYPE_I1:
  2897. *(guint8 *) value = *p;
  2898. break;
  2899. case MONO_TYPE_CHAR:
  2900. case MONO_TYPE_U2:
  2901. case MONO_TYPE_I2:
  2902. *(guint16*) value = read16 (p);
  2903. break;
  2904. case MONO_TYPE_U4:
  2905. case MONO_TYPE_I4:
  2906. *(guint32*) value = read32 (p);
  2907. break;
  2908. case MONO_TYPE_U8:
  2909. case MONO_TYPE_I8:
  2910. *(guint64*) value = read64 (p);
  2911. break;
  2912. case MONO_TYPE_R4:
  2913. readr4 (p, (float*) value);
  2914. break;
  2915. case MONO_TYPE_R8:
  2916. readr8 (p, (double*) value);
  2917. break;
  2918. case MONO_TYPE_STRING:
  2919. *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
  2920. break;
  2921. case MONO_TYPE_CLASS:
  2922. *(gpointer*) value = NULL;
  2923. break;
  2924. default:
  2925. retval = -1;
  2926. g_warning ("type 0x%02x should not be in constant table", type);
  2927. }
  2928. return retval;
  2929. }
  2930. static void
  2931. get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
  2932. {
  2933. MonoTypeEnum def_type;
  2934. const char* data;
  2935. data = mono_class_get_field_default_value (field, &def_type);
  2936. mono_get_constant_value_from_blob (domain, def_type, data, value);
  2937. }
  2938. void
  2939. mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
  2940. {
  2941. void *src;
  2942. g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
  2943. if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
  2944. get_default_field_value (vt->domain, field, value);
  2945. return;
  2946. }
  2947. if (field->offset == -1) {
  2948. /* Special static */
  2949. gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
  2950. src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
  2951. } else {
  2952. src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
  2953. }
  2954. set_value (field->type, value, src, TRUE);
  2955. }
  2956. /**
  2957. * mono_field_static_get_value:
  2958. * @vt: vtable to the object
  2959. * @field: MonoClassField describing the field to fetch information from
  2960. * @value: where the value is returned
  2961. *
  2962. * Use this routine to get the value of the static field @field value.
  2963. *
  2964. * The pointer provided by value must be of the field type, for reference
  2965. * types this is a MonoObject*, for value types its the actual pointer to
  2966. * the value type.
  2967. *
  2968. * For example:
  2969. * int i;
  2970. * mono_field_static_get_value (vt, int_field, &i);
  2971. */
  2972. void
  2973. mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
  2974. {
  2975. return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
  2976. }
  2977. /**
  2978. * mono_property_set_value:
  2979. * @prop: MonoProperty to set
  2980. * @obj: instance object on which to act
  2981. * @params: parameters to pass to the propery
  2982. * @exc: optional exception
  2983. *
  2984. * Invokes the property's set method with the given arguments on the
  2985. * object instance obj (or NULL for static properties).
  2986. *
  2987. * You can pass NULL as the exc argument if you don't want to
  2988. * catch exceptions, otherwise, *exc will be set to the exception
  2989. * thrown, if any. if an exception is thrown, you can't use the
  2990. * MonoObject* result from the function.
  2991. */
  2992. void
  2993. mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
  2994. {
  2995. default_mono_runtime_invoke (prop->set, obj, params, exc);
  2996. }
  2997. /**
  2998. * mono_property_get_value:
  2999. * @prop: MonoProperty to fetch
  3000. * @obj: instance object on which to act
  3001. * @params: parameters to pass to the propery
  3002. * @exc: optional exception
  3003. *
  3004. * Invokes the property's get method with the given arguments on the
  3005. * object instance obj (or NULL for static properties).
  3006. *
  3007. * You can pass NULL as the exc argument if you don't want to
  3008. * catch exceptions, otherwise, *exc will be set to the exception
  3009. * thrown, if any. if an exception is thrown, you can't use the
  3010. * MonoObject* result from the function.
  3011. *
  3012. * Returns: the value from invoking the get method on the property.
  3013. */
  3014. MonoObject*
  3015. mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
  3016. {
  3017. return default_mono_runtime_invoke (prop->get, obj, params, exc);
  3018. }
  3019. /*
  3020. * mono_nullable_init:
  3021. * @buf: The nullable structure to initialize.
  3022. * @value: the value to initialize from
  3023. * @klass: the type for the object
  3024. *
  3025. * Initialize the nullable structure pointed to by @buf from @value which
  3026. * should be a boxed value type. The size of @buf should be able to hold
  3027. * as much data as the @klass->instance_size (which is the number of bytes
  3028. * that will be copies).
  3029. *
  3030. * Since Nullables have variable structure, we can not define a C
  3031. * structure for them.
  3032. */
  3033. void
  3034. mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
  3035. {
  3036. MonoClass *param_class = klass->cast_class;
  3037. mono_class_setup_fields_locking (klass);
  3038. g_assert (klass->fields_inited);
  3039. g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
  3040. g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
  3041. *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
  3042. if (value) {
  3043. if (param_class->has_references)
  3044. mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
  3045. else
  3046. mono_gc_memmove (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
  3047. } else {
  3048. mono_gc_bzero (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
  3049. }
  3050. }
  3051. /**
  3052. * mono_nullable_box:
  3053. * @buf: The buffer representing the data to be boxed
  3054. * @klass: the type to box it as.
  3055. *
  3056. * Creates a boxed vtype or NULL from the Nullable structure pointed to by
  3057. * @buf.
  3058. */
  3059. MonoObject*
  3060. mono_nullable_box (guint8 *buf, MonoClass *klass)
  3061. {
  3062. MonoClass *param_class = klass->cast_class;
  3063. mono_class_setup_fields_locking (klass);
  3064. g_assert (klass->fields_inited);
  3065. g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
  3066. g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
  3067. if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
  3068. MonoObject *o = mono_object_new (mono_domain_get (), param_class);
  3069. if (param_class->has_references)
  3070. mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
  3071. else
  3072. mono_gc_memmove (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
  3073. return o;
  3074. }
  3075. else
  3076. return NULL;
  3077. }
  3078. /**
  3079. * mono_get_delegate_invoke:
  3080. * @klass: The delegate class
  3081. *
  3082. * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
  3083. */
  3084. MonoMethod *
  3085. mono_get_delegate_invoke (MonoClass *klass)
  3086. {
  3087. MonoMethod *im;
  3088. /* This is called at runtime, so avoid the slower search in metadata */
  3089. mono_class_setup_methods (klass);
  3090. if (klass->exception_type)
  3091. return NULL;
  3092. im = mono_class_get_method_from_name (klass, "Invoke", -1);
  3093. return im;
  3094. }
  3095. /**
  3096. * mono_get_delegate_begin_invoke:
  3097. * @klass: The delegate class
  3098. *
  3099. * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
  3100. */
  3101. MonoMethod *
  3102. mono_get_delegate_begin_invoke (MonoClass *klass)
  3103. {
  3104. MonoMethod *im;
  3105. /* This is called at runtime, so avoid the slower search in metadata */
  3106. mono_class_setup_methods (klass);
  3107. if (klass->exception_type)
  3108. return NULL;
  3109. im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
  3110. return im;
  3111. }
  3112. /**
  3113. * mono_get_delegate_end_invoke:
  3114. * @klass: The delegate class
  3115. *
  3116. * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
  3117. */
  3118. MonoMethod *
  3119. mono_get_delegate_end_invoke (MonoClass *klass)
  3120. {
  3121. MonoMethod *im;
  3122. /* This is called at runtime, so avoid the slower search in metadata */
  3123. mono_class_setup_methods (klass);
  3124. if (klass->exception_type)
  3125. return NULL;
  3126. im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
  3127. return im;
  3128. }
  3129. /**
  3130. * mono_runtime_delegate_invoke:
  3131. * @delegate: pointer to a delegate object.
  3132. * @params: parameters for the delegate.
  3133. * @exc: Pointer to the exception result.
  3134. *
  3135. * Invokes the delegate method @delegate with the parameters provided.
  3136. *
  3137. * You can pass NULL as the exc argument if you don't want to
  3138. * catch exceptions, otherwise, *exc will be set to the exception
  3139. * thrown, if any. if an exception is thrown, you can't use the
  3140. * MonoObject* result from the function.
  3141. */
  3142. MonoObject*
  3143. mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
  3144. {
  3145. MonoMethod *im;
  3146. MonoClass *klass = delegate->vtable->klass;
  3147. im = mono_get_delegate_invoke (klass);
  3148. if (!im)
  3149. g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
  3150. return mono_runtime_invoke (im, delegate, params, exc);
  3151. }
  3152. static char **main_args = NULL;
  3153. static int num_main_args;
  3154. /**
  3155. * mono_runtime_get_main_args:
  3156. *
  3157. * Returns: a MonoArray with the arguments passed to the main program
  3158. */
  3159. MonoArray*
  3160. mono_runtime_get_main_args (void)
  3161. {
  3162. MonoArray *res;
  3163. int i;
  3164. MonoDomain *domain = mono_domain_get ();
  3165. if (!main_args)
  3166. return NULL;
  3167. res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
  3168. for (i = 0; i < num_main_args; ++i)
  3169. mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
  3170. return res;
  3171. }
  3172. static void
  3173. free_main_args (void)
  3174. {
  3175. int i;
  3176. for (i = 0; i < num_main_args; ++i)
  3177. g_free (main_args [i]);
  3178. g_free (main_args);
  3179. }
  3180. /**
  3181. * mono_runtime_run_main:
  3182. * @method: the method to start the application with (usually Main)
  3183. * @argc: number of arguments from the command line
  3184. * @argv: array of strings from the command line
  3185. * @exc: excetption results
  3186. *
  3187. * Execute a standard Main() method (argc/argv contains the
  3188. * executable name). This method also sets the command line argument value
  3189. * needed by System.Environment.
  3190. *
  3191. *
  3192. */
  3193. int
  3194. mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
  3195. MonoObject **exc)
  3196. {
  3197. int i;
  3198. MonoArray *args = NULL;
  3199. MonoDomain *domain = mono_domain_get ();
  3200. gchar *utf8_fullpath;
  3201. MonoMethodSignature *sig;
  3202. g_assert (method != NULL);
  3203. mono_thread_set_main (mono_thread_current ());
  3204. main_args = g_new0 (char*, argc);
  3205. num_main_args = argc;
  3206. if (!g_path_is_absolute (argv [0])) {
  3207. gchar *basename = g_path_get_basename (argv [0]);
  3208. gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
  3209. basename,
  3210. NULL);
  3211. utf8_fullpath = mono_utf8_from_external (fullpath);
  3212. if(utf8_fullpath == NULL) {
  3213. /* Printing the arg text will cause glib to
  3214. * whinge about "Invalid UTF-8", but at least
  3215. * its relevant, and shows the problem text
  3216. * string.
  3217. */
  3218. g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
  3219. g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
  3220. exit (-1);
  3221. }
  3222. g_free (fullpath);
  3223. g_free (basename);
  3224. } else {
  3225. utf8_fullpath = mono_utf8_from_external (argv[0]);
  3226. if(utf8_fullpath == NULL) {
  3227. g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
  3228. g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
  3229. exit (-1);
  3230. }
  3231. }
  3232. main_args [0] = utf8_fullpath;
  3233. for (i = 1; i < argc; ++i) {
  3234. gchar *utf8_arg;
  3235. utf8_arg=mono_utf8_from_external (argv[i]);
  3236. if(utf8_arg==NULL) {
  3237. /* Ditto the comment about Invalid UTF-8 here */
  3238. g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
  3239. g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
  3240. exit (-1);
  3241. }
  3242. main_args [i] = utf8_arg;
  3243. }
  3244. argc--;
  3245. argv++;
  3246. sig = mono_method_signature (method);
  3247. if (!sig) {
  3248. g_print ("Unable to load Main method.\n");
  3249. exit (-1);
  3250. }
  3251. if (sig->param_count) {
  3252. args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
  3253. for (i = 0; i < argc; ++i) {
  3254. /* The encodings should all work, given that
  3255. * we've checked all these args for the
  3256. * main_args array.
  3257. */
  3258. gchar *str = mono_utf8_from_external (argv [i]);
  3259. MonoString *arg = mono_string_new (domain, str);
  3260. mono_array_setref (args, i, arg);
  3261. g_free (str);
  3262. }
  3263. } else {
  3264. args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
  3265. }
  3266. mono_assembly_set_main (method->klass->image->assembly);
  3267. return mono_runtime_exec_main (method, args, exc);
  3268. }
  3269. static MonoObject*
  3270. serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
  3271. {
  3272. static MonoMethod *serialize_method;
  3273. void *params [1];
  3274. MonoObject *array;
  3275. if (!serialize_method) {
  3276. MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
  3277. serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
  3278. }
  3279. if (!serialize_method) {
  3280. *failure = TRUE;
  3281. return NULL;
  3282. }
  3283. g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
  3284. params [0] = obj;
  3285. *exc = NULL;
  3286. array = mono_runtime_invoke (serialize_method, NULL, params, exc);
  3287. if (*exc)
  3288. *failure = TRUE;
  3289. return array;
  3290. }
  3291. static MonoObject*
  3292. deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
  3293. {
  3294. static MonoMethod *deserialize_method;
  3295. void *params [1];
  3296. MonoObject *result;
  3297. if (!deserialize_method) {
  3298. MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
  3299. deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
  3300. }
  3301. if (!deserialize_method) {
  3302. *failure = TRUE;
  3303. return NULL;
  3304. }
  3305. params [0] = obj;
  3306. *exc = NULL;
  3307. result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
  3308. if (*exc)
  3309. *failure = TRUE;
  3310. return result;
  3311. }
  3312. #ifndef DISABLE_REMOTING
  3313. static MonoObject*
  3314. make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
  3315. {
  3316. static MonoMethod *get_proxy_method;
  3317. MonoDomain *domain = mono_domain_get ();
  3318. MonoRealProxy *real_proxy;
  3319. MonoReflectionType *reflection_type;
  3320. MonoTransparentProxy *transparent_proxy;
  3321. if (!get_proxy_method)
  3322. get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
  3323. g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
  3324. real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
  3325. reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
  3326. MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
  3327. MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
  3328. *exc = NULL;
  3329. transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
  3330. if (*exc)
  3331. *failure = TRUE;
  3332. return (MonoObject*) transparent_proxy;
  3333. }
  3334. #endif /* DISABLE_REMOTING */
  3335. /**
  3336. * mono_object_xdomain_representation
  3337. * @obj: an object
  3338. * @target_domain: a domain
  3339. * @exc: pointer to a MonoObject*
  3340. *
  3341. * Creates a representation of obj in the domain target_domain. This
  3342. * is either a copy of obj arrived through via serialization and
  3343. * deserialization or a proxy, depending on whether the object is
  3344. * serializable or marshal by ref. obj must not be in target_domain.
  3345. *
  3346. * If the object cannot be represented in target_domain, NULL is
  3347. * returned and *exc is set to an appropriate exception.
  3348. */
  3349. MonoObject*
  3350. mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
  3351. {
  3352. MonoObject *deserialized = NULL;
  3353. gboolean failure = FALSE;
  3354. *exc = NULL;
  3355. #ifndef DISABLE_REMOTING
  3356. if (mono_class_is_marshalbyref (mono_object_class (obj))) {
  3357. deserialized = make_transparent_proxy (obj, &failure, exc);
  3358. }
  3359. else
  3360. #endif
  3361. {
  3362. MonoDomain *domain = mono_domain_get ();
  3363. MonoObject *serialized;
  3364. mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
  3365. serialized = serialize_object (obj, &failure, exc);
  3366. mono_domain_set_internal_with_options (target_domain, FALSE);
  3367. if (!failure)
  3368. deserialized = deserialize_object (serialized, &failure, exc);
  3369. if (domain != target_domain)
  3370. mono_domain_set_internal_with_options (domain, FALSE);
  3371. }
  3372. return deserialized;
  3373. }
  3374. /* Used in call_unhandled_exception_delegate */
  3375. static MonoObject *
  3376. create_unhandled_exception_eventargs (MonoObject *exc)
  3377. {
  3378. MonoClass *klass;
  3379. gpointer args [2];
  3380. MonoMethod *method = NULL;
  3381. MonoBoolean is_terminating = TRUE;
  3382. MonoObject *obj;
  3383. klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
  3384. g_assert (klass);
  3385. mono_class_init (klass);
  3386. /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
  3387. method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
  3388. g_assert (method);
  3389. args [0] = exc;
  3390. args [1] = &is_terminating;
  3391. obj = mono_object_new (mono_domain_get (), klass);
  3392. mono_runtime_invoke (method, obj, args, NULL);
  3393. return obj;
  3394. }
  3395. /* Used in mono_unhandled_exception */
  3396. static void
  3397. call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
  3398. MonoObject *e = NULL;
  3399. gpointer pa [2];
  3400. MonoDomain *current_domain = mono_domain_get ();
  3401. if (domain != current_domain)
  3402. mono_domain_set_internal_with_options (domain, FALSE);
  3403. g_assert (domain == mono_object_domain (domain->domain));
  3404. if (mono_object_domain (exc) != domain) {
  3405. MonoObject *serialization_exc;
  3406. exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
  3407. if (!exc) {
  3408. if (serialization_exc) {
  3409. MonoObject *dummy;
  3410. exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
  3411. g_assert (exc);
  3412. } else {
  3413. exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
  3414. "System.Runtime.Serialization", "SerializationException",
  3415. "Could not serialize unhandled exception.");
  3416. }
  3417. }
  3418. }
  3419. g_assert (mono_object_domain (exc) == domain);
  3420. pa [0] = domain->domain;
  3421. pa [1] = create_unhandled_exception_eventargs (exc);
  3422. mono_runtime_delegate_invoke (delegate, pa, &e);
  3423. if (domain != current_domain)
  3424. mono_domain_set_internal_with_options (current_domain, FALSE);
  3425. if (e) {
  3426. MonoError error;
  3427. gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
  3428. if (!mono_error_ok (&error)) {
  3429. g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
  3430. mono_error_cleanup (&error);
  3431. } else {
  3432. g_warning ("exception inside UnhandledException handler: %s\n", msg);
  3433. g_free (msg);
  3434. }
  3435. }
  3436. }
  3437. static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
  3438. /**
  3439. * mono_runtime_unhandled_exception_policy_set:
  3440. * @policy: the new policy
  3441. *
  3442. * This is a VM internal routine.
  3443. *
  3444. * Sets the runtime policy for handling unhandled exceptions.
  3445. */
  3446. void
  3447. mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
  3448. runtime_unhandled_exception_policy = policy;
  3449. }
  3450. /**
  3451. * mono_runtime_unhandled_exception_policy_get:
  3452. *
  3453. * This is a VM internal routine.
  3454. *
  3455. * Gets the runtime policy for handling unhandled exceptions.
  3456. */
  3457. MonoRuntimeUnhandledExceptionPolicy
  3458. mono_runtime_unhandled_exception_policy_get (void) {
  3459. return runtime_unhandled_exception_policy;
  3460. }
  3461. /**
  3462. * mono_unhandled_exception:
  3463. * @exc: exception thrown
  3464. *
  3465. * This is a VM internal routine.
  3466. *
  3467. * We call this function when we detect an unhandled exception
  3468. * in the default domain.
  3469. *
  3470. * It invokes the * UnhandledException event in AppDomain or prints
  3471. * a warning to the console
  3472. */
  3473. void
  3474. mono_unhandled_exception (MonoObject *exc)
  3475. {
  3476. MonoDomain *current_domain = mono_domain_get ();
  3477. MonoDomain *root_domain = mono_get_root_domain ();
  3478. MonoClassField *field;
  3479. MonoObject *current_appdomain_delegate;
  3480. MonoObject *root_appdomain_delegate;
  3481. field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
  3482. "UnhandledException");
  3483. g_assert (field);
  3484. if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
  3485. gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
  3486. (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
  3487. root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
  3488. if (current_domain != root_domain) {
  3489. current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
  3490. } else {
  3491. current_appdomain_delegate = NULL;
  3492. }
  3493. /* set exitcode only if we will abort the process */
  3494. if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
  3495. if (abort_process)
  3496. mono_environment_exitcode_set (1);
  3497. mono_print_unhandled_exception (exc);
  3498. } else {
  3499. if (root_appdomain_delegate) {
  3500. call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
  3501. }
  3502. if (current_appdomain_delegate) {
  3503. call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
  3504. }
  3505. }
  3506. }
  3507. }
  3508. /**
  3509. * mono_runtime_exec_managed_code:
  3510. * @domain: Application domain
  3511. * @main_func: function to invoke from the execution thread
  3512. * @main_args: parameter to the main_func
  3513. *
  3514. * Launch a new thread to execute a function
  3515. *
  3516. * main_func is called back from the thread with main_args as the
  3517. * parameter. The callback function is expected to start Main()
  3518. * eventually. This function then waits for all managed threads to
  3519. * finish.
  3520. * It is not necesseray anymore to execute managed code in a subthread,
  3521. * so this function should not be used anymore by default: just
  3522. * execute the code and then call mono_thread_manage ().
  3523. */
  3524. void
  3525. mono_runtime_exec_managed_code (MonoDomain *domain,
  3526. MonoMainThreadFunc main_func,
  3527. gpointer main_args)
  3528. {
  3529. mono_thread_create (domain, main_func, main_args);
  3530. mono_thread_manage ();
  3531. }
  3532. /*
  3533. * Execute a standard Main() method (args doesn't contain the
  3534. * executable name).
  3535. */
  3536. int
  3537. mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
  3538. {
  3539. MonoDomain *domain;
  3540. gpointer pa [1];
  3541. int rval;
  3542. MonoCustomAttrInfo* cinfo;
  3543. gboolean has_stathread_attribute;
  3544. MonoInternalThread* thread = mono_thread_internal_current ();
  3545. g_assert (args);
  3546. pa [0] = args;
  3547. domain = mono_object_domain (args);
  3548. if (!domain->entry_assembly) {
  3549. gchar *str;
  3550. MonoAssembly *assembly;
  3551. assembly = method->klass->image->assembly;
  3552. domain->entry_assembly = assembly;
  3553. /* Domains created from another domain already have application_base and configuration_file set */
  3554. if (domain->setup->application_base == NULL) {
  3555. MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
  3556. }
  3557. if (domain->setup->configuration_file == NULL) {
  3558. str = g_strconcat (assembly->image->name, ".config", NULL);
  3559. MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
  3560. g_free (str);
  3561. mono_set_private_bin_path_from_config (domain);
  3562. }
  3563. }
  3564. cinfo = mono_custom_attrs_from_method (method);
  3565. if (cinfo) {
  3566. static MonoClass *stathread_attribute = NULL;
  3567. if (!stathread_attribute)
  3568. stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
  3569. has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
  3570. if (!cinfo->cached)
  3571. mono_custom_attrs_free (cinfo);
  3572. } else {
  3573. has_stathread_attribute = FALSE;
  3574. }
  3575. if (has_stathread_attribute) {
  3576. thread->apartment_state = ThreadApartmentState_STA;
  3577. } else {
  3578. thread->apartment_state = ThreadApartmentState_MTA;
  3579. }
  3580. mono_thread_init_apartment_state ();
  3581. mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
  3582. /* FIXME: check signature of method */
  3583. if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
  3584. MonoObject *res;
  3585. res = mono_runtime_invoke (method, NULL, pa, exc);
  3586. if (!exc || !*exc)
  3587. rval = *(guint32 *)((char *)res + sizeof (MonoObject));
  3588. else
  3589. rval = -1;
  3590. mono_environment_exitcode_set (rval);
  3591. } else {
  3592. mono_runtime_invoke (method, NULL, pa, exc);
  3593. if (!exc || !*exc)
  3594. rval = 0;
  3595. else {
  3596. /* If the return type of Main is void, only
  3597. * set the exitcode if an exception was thrown
  3598. * (we don't want to blow away an
  3599. * explicitly-set exit code)
  3600. */
  3601. rval = -1;
  3602. mono_environment_exitcode_set (rval);
  3603. }
  3604. }
  3605. mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
  3606. return rval;
  3607. }
  3608. /**
  3609. * mono_install_runtime_invoke:
  3610. * @func: Function to install
  3611. *
  3612. * This is a VM internal routine
  3613. */
  3614. void
  3615. mono_install_runtime_invoke (MonoInvokeFunc func)
  3616. {
  3617. default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
  3618. }
  3619. /**
  3620. * mono_runtime_invoke_array:
  3621. * @method: method to invoke
  3622. * @obJ: object instance
  3623. * @params: arguments to the method
  3624. * @exc: exception information.
  3625. *
  3626. * Invokes the method represented by @method on the object @obj.
  3627. *
  3628. * obj is the 'this' pointer, it should be NULL for static
  3629. * methods, a MonoObject* for object instances and a pointer to
  3630. * the value type for value types.
  3631. *
  3632. * The params array contains the arguments to the method with the
  3633. * same convention: MonoObject* pointers for object instances and
  3634. * pointers to the value type otherwise. The _invoke_array
  3635. * variant takes a C# object[] as the params argument (MonoArray
  3636. * *params): in this case the value types are boxed inside the
  3637. * respective reference representation.
  3638. *
  3639. * From unmanaged code you'll usually use the
  3640. * mono_runtime_invoke() variant.
  3641. *
  3642. * Note that this function doesn't handle virtual methods for
  3643. * you, it will exec the exact method you pass: we still need to
  3644. * expose a function to lookup the derived class implementation
  3645. * of a virtual method (there are examples of this in the code,
  3646. * though).
  3647. *
  3648. * You can pass NULL as the exc argument if you don't want to
  3649. * catch exceptions, otherwise, *exc will be set to the exception
  3650. * thrown, if any. if an exception is thrown, you can't use the
  3651. * MonoObject* result from the function.
  3652. *
  3653. * If the method returns a value type, it is boxed in an object
  3654. * reference.
  3655. */
  3656. MonoObject*
  3657. mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
  3658. MonoObject **exc)
  3659. {
  3660. MonoMethodSignature *sig = mono_method_signature (method);
  3661. gpointer *pa = NULL;
  3662. MonoObject *res;
  3663. int i;
  3664. gboolean has_byref_nullables = FALSE;
  3665. if (NULL != params) {
  3666. pa = alloca (sizeof (gpointer) * mono_array_length (params));
  3667. for (i = 0; i < mono_array_length (params); i++) {
  3668. MonoType *t = sig->params [i];
  3669. again:
  3670. switch (t->type) {
  3671. case MONO_TYPE_U1:
  3672. case MONO_TYPE_I1:
  3673. case MONO_TYPE_BOOLEAN:
  3674. case MONO_TYPE_U2:
  3675. case MONO_TYPE_I2:
  3676. case MONO_TYPE_CHAR:
  3677. case MONO_TYPE_U:
  3678. case MONO_TYPE_I:
  3679. case MONO_TYPE_U4:
  3680. case MONO_TYPE_I4:
  3681. case MONO_TYPE_U8:
  3682. case MONO_TYPE_I8:
  3683. case MONO_TYPE_R4:
  3684. case MONO_TYPE_R8:
  3685. case MONO_TYPE_VALUETYPE:
  3686. if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
  3687. /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
  3688. pa [i] = mono_array_get (params, MonoObject*, i);
  3689. if (t->byref)
  3690. has_byref_nullables = TRUE;
  3691. } else {
  3692. /* MS seems to create the objects if a null is passed in */
  3693. if (!mono_array_get (params, MonoObject*, i))
  3694. mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
  3695. if (t->byref) {
  3696. /*
  3697. * We can't pass the unboxed vtype byref to the callee, since
  3698. * that would mean the callee would be able to modify boxed
  3699. * primitive types. So we (and MS) make a copy of the boxed
  3700. * object, pass that to the callee, and replace the original
  3701. * boxed object in the arg array with the copy.
  3702. */
  3703. MonoObject *orig = mono_array_get (params, MonoObject*, i);
  3704. MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
  3705. mono_array_setref (params, i, copy);
  3706. }
  3707. pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
  3708. }
  3709. break;
  3710. case MONO_TYPE_STRING:
  3711. case MONO_TYPE_OBJECT:
  3712. case MONO_TYPE_CLASS:
  3713. case MONO_TYPE_ARRAY:
  3714. case MONO_TYPE_SZARRAY:
  3715. if (t->byref)
  3716. pa [i] = mono_array_addr (params, MonoObject*, i);
  3717. // FIXME: I need to check this code path
  3718. else
  3719. pa [i] = mono_array_get (params, MonoObject*, i);
  3720. break;
  3721. case MONO_TYPE_GENERICINST:
  3722. if (t->byref)
  3723. t = &t->data.generic_class->container_class->this_arg;
  3724. else
  3725. t = &t->data.generic_class->container_class->byval_arg;
  3726. goto again;
  3727. case MONO_TYPE_PTR: {
  3728. MonoObject *arg;
  3729. /* The argument should be an IntPtr */
  3730. arg = mono_array_get (params, MonoObject*, i);
  3731. if (arg == NULL) {
  3732. pa [i] = NULL;
  3733. } else {
  3734. g_assert (arg->vtable->klass == mono_defaults.int_class);
  3735. pa [i] = ((MonoIntPtr*)arg)->m_value;
  3736. }
  3737. break;
  3738. }
  3739. default:
  3740. g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
  3741. }
  3742. }
  3743. }
  3744. if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
  3745. void *o = obj;
  3746. if (mono_class_is_nullable (method->klass)) {
  3747. /* Need to create a boxed vtype instead */
  3748. g_assert (!obj);
  3749. if (!params)
  3750. return NULL;
  3751. else
  3752. return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
  3753. }
  3754. if (!obj) {
  3755. obj = mono_object_new (mono_domain_get (), method->klass);
  3756. g_assert (obj); /*maybe we should raise a TLE instead?*/
  3757. #ifndef DISABLE_REMOTING
  3758. if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
  3759. method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
  3760. }
  3761. #endif
  3762. if (method->klass->valuetype)
  3763. o = mono_object_unbox (obj);
  3764. else
  3765. o = obj;
  3766. } else if (method->klass->valuetype) {
  3767. obj = mono_value_box (mono_domain_get (), method->klass, obj);
  3768. }
  3769. mono_runtime_invoke (method, o, pa, exc);
  3770. return obj;
  3771. } else {
  3772. if (mono_class_is_nullable (method->klass)) {
  3773. MonoObject *nullable;
  3774. /* Convert the unboxed vtype into a Nullable structure */
  3775. nullable = mono_object_new (mono_domain_get (), method->klass);
  3776. mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
  3777. obj = mono_object_unbox (nullable);
  3778. }
  3779. /* obj must be already unboxed if needed */
  3780. res = mono_runtime_invoke (method, obj, pa, exc);
  3781. if (sig->ret->type == MONO_TYPE_PTR) {
  3782. MonoClass *pointer_class;
  3783. static MonoMethod *box_method;
  3784. void *box_args [2];
  3785. MonoObject *box_exc;
  3786. /*
  3787. * The runtime-invoke wrapper returns a boxed IntPtr, need to
  3788. * convert it to a Pointer object.
  3789. */
  3790. pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
  3791. if (!box_method)
  3792. box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
  3793. g_assert (res->vtable->klass == mono_defaults.int_class);
  3794. box_args [0] = ((MonoIntPtr*)res)->m_value;
  3795. box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
  3796. res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
  3797. g_assert (!box_exc);
  3798. }
  3799. if (has_byref_nullables) {
  3800. /*
  3801. * The runtime invoke wrapper already converted byref nullables back,
  3802. * and stored them in pa, we just need to copy them back to the
  3803. * managed array.
  3804. */
  3805. for (i = 0; i < mono_array_length (params); i++) {
  3806. MonoType *t = sig->params [i];
  3807. if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
  3808. mono_array_setref (params, i, pa [i]);
  3809. }
  3810. }
  3811. return res;
  3812. }
  3813. }
  3814. static void
  3815. arith_overflow (void)
  3816. {
  3817. mono_raise_exception (mono_get_exception_overflow ());
  3818. }
  3819. /**
  3820. * mono_object_allocate:
  3821. * @size: number of bytes to allocate
  3822. *
  3823. * This is a very simplistic routine until we have our GC-aware
  3824. * memory allocator.
  3825. *
  3826. * Returns: an allocated object of size @size, or NULL on failure.
  3827. */
  3828. static inline void *
  3829. mono_object_allocate (size_t size, MonoVTable *vtable)
  3830. {
  3831. MonoObject *o;
  3832. mono_stats.new_object_count++;
  3833. ALLOC_OBJECT (o, vtable, size);
  3834. return o;
  3835. }
  3836. /**
  3837. * mono_object_allocate_ptrfree:
  3838. * @size: number of bytes to allocate
  3839. *
  3840. * Note that the memory allocated is not zeroed.
  3841. * Returns: an allocated object of size @size, or NULL on failure.
  3842. */
  3843. static inline void *
  3844. mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
  3845. {
  3846. MonoObject *o;
  3847. mono_stats.new_object_count++;
  3848. ALLOC_PTRFREE (o, vtable, size);
  3849. return o;
  3850. }
  3851. static inline void *
  3852. mono_object_allocate_spec (size_t size, MonoVTable *vtable)
  3853. {
  3854. void *o;
  3855. ALLOC_TYPED (o, size, vtable);
  3856. mono_stats.new_object_count++;
  3857. return o;
  3858. }
  3859. /**
  3860. * mono_object_new:
  3861. * @klass: the class of the object that we want to create
  3862. *
  3863. * Returns: a newly created object whose definition is
  3864. * looked up using @klass. This will not invoke any constructors,
  3865. * so the consumer of this routine has to invoke any constructors on
  3866. * its own to initialize the object.
  3867. *
  3868. * It returns NULL on failure.
  3869. */
  3870. MonoObject *
  3871. mono_object_new (MonoDomain *domain, MonoClass *klass)
  3872. {
  3873. MonoVTable *vtable;
  3874. MONO_ARCH_SAVE_REGS;
  3875. vtable = mono_class_vtable (domain, klass);
  3876. if (!vtable)
  3877. return NULL;
  3878. return mono_object_new_specific (vtable);
  3879. }
  3880. /**
  3881. * mono_object_new_pinned:
  3882. *
  3883. * Same as mono_object_new, but the returned object will be pinned.
  3884. * For SGEN, these objects will only be freed at appdomain unload.
  3885. */
  3886. MonoObject *
  3887. mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
  3888. {
  3889. MonoVTable *vtable;
  3890. MONO_ARCH_SAVE_REGS;
  3891. vtable = mono_class_vtable (domain, klass);
  3892. if (!vtable)
  3893. return NULL;
  3894. #ifdef HAVE_SGEN_GC
  3895. return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
  3896. #else
  3897. return mono_object_new_specific (vtable);
  3898. #endif
  3899. }
  3900. /**
  3901. * mono_object_new_specific:
  3902. * @vtable: the vtable of the object that we want to create
  3903. *
  3904. * Returns: A newly created object with class and domain specified
  3905. * by @vtable
  3906. */
  3907. MonoObject *
  3908. mono_object_new_specific (MonoVTable *vtable)
  3909. {
  3910. MonoObject *o;
  3911. MONO_ARCH_SAVE_REGS;
  3912. /* check for is_com_object for COM Interop */
  3913. if (vtable->remote || vtable->klass->is_com_object)
  3914. {
  3915. gpointer pa [1];
  3916. MonoMethod *im = vtable->domain->create_proxy_for_type_method;
  3917. if (im == NULL) {
  3918. MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
  3919. if (!klass->inited)
  3920. mono_class_init (klass);
  3921. im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
  3922. g_assert (im);
  3923. vtable->domain->create_proxy_for_type_method = im;
  3924. }
  3925. pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
  3926. o = mono_runtime_invoke (im, NULL, pa, NULL);
  3927. if (o != NULL) return o;
  3928. }
  3929. return mono_object_new_alloc_specific (vtable);
  3930. }
  3931. MonoObject *
  3932. mono_object_new_alloc_specific (MonoVTable *vtable)
  3933. {
  3934. MonoObject *o;
  3935. if (!vtable->klass->has_references) {
  3936. o = mono_object_new_ptrfree (vtable);
  3937. } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
  3938. o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
  3939. } else {
  3940. /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
  3941. o = mono_object_allocate (vtable->klass->instance_size, vtable);
  3942. }
  3943. if (G_UNLIKELY (vtable->klass->has_finalize))
  3944. mono_object_register_finalizer (o);
  3945. if (G_UNLIKELY (profile_allocs))
  3946. mono_profiler_allocation (o, vtable->klass);
  3947. return o;
  3948. }
  3949. MonoObject*
  3950. mono_object_new_fast (MonoVTable *vtable)
  3951. {
  3952. MonoObject *o;
  3953. ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
  3954. return o;
  3955. }
  3956. static MonoObject*
  3957. mono_object_new_ptrfree (MonoVTable *vtable)
  3958. {
  3959. MonoObject *obj;
  3960. ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
  3961. #if NEED_TO_ZERO_PTRFREE
  3962. /* an inline memset is much faster for the common vcase of small objects
  3963. * note we assume the allocated size is a multiple of sizeof (void*).
  3964. */
  3965. if (vtable->klass->instance_size < 128) {
  3966. gpointer *p, *end;
  3967. end = (gpointer*)((char*)obj + vtable->klass->instance_size);
  3968. p = (gpointer*)((char*)obj + sizeof (MonoObject));
  3969. while (p < end) {
  3970. *p = NULL;
  3971. ++p;
  3972. }
  3973. } else {
  3974. memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
  3975. }
  3976. #endif
  3977. return obj;
  3978. }
  3979. static MonoObject*
  3980. mono_object_new_ptrfree_box (MonoVTable *vtable)
  3981. {
  3982. MonoObject *obj;
  3983. ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
  3984. /* the object will be boxed right away, no need to memzero it */
  3985. return obj;
  3986. }
  3987. /**
  3988. * mono_class_get_allocation_ftn:
  3989. * @vtable: vtable
  3990. * @for_box: the object will be used for boxing
  3991. * @pass_size_in_words:
  3992. *
  3993. * Return the allocation function appropriate for the given class.
  3994. */
  3995. void*
  3996. mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
  3997. {
  3998. *pass_size_in_words = FALSE;
  3999. if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
  4000. profile_allocs = FALSE;
  4001. if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
  4002. return mono_object_new_specific;
  4003. if (!vtable->klass->has_references) {
  4004. //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
  4005. if (for_box)
  4006. return mono_object_new_ptrfree_box;
  4007. return mono_object_new_ptrfree;
  4008. }
  4009. if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
  4010. return mono_object_new_fast;
  4011. /*
  4012. * FIXME: This is actually slower than mono_object_new_fast, because
  4013. * of the overhead of parameter passing.
  4014. */
  4015. /*
  4016. *pass_size_in_words = TRUE;
  4017. #ifdef GC_REDIRECT_TO_LOCAL
  4018. return GC_local_gcj_fast_malloc;
  4019. #else
  4020. return GC_gcj_fast_malloc;
  4021. #endif
  4022. */
  4023. }
  4024. return mono_object_new_specific;
  4025. }
  4026. /**
  4027. * mono_object_new_from_token:
  4028. * @image: Context where the type_token is hosted
  4029. * @token: a token of the type that we want to create
  4030. *
  4031. * Returns: A newly created object whose definition is
  4032. * looked up using @token in the @image image
  4033. */
  4034. MonoObject *
  4035. mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
  4036. {
  4037. MonoClass *class;
  4038. class = mono_class_get (image, token);
  4039. return mono_object_new (domain, class);
  4040. }
  4041. /**
  4042. * mono_object_clone:
  4043. * @obj: the object to clone
  4044. *
  4045. * Returns: A newly created object who is a shallow copy of @obj
  4046. */
  4047. MonoObject *
  4048. mono_object_clone (MonoObject *obj)
  4049. {
  4050. MonoObject *o;
  4051. int size = obj->vtable->klass->instance_size;
  4052. if (obj->vtable->klass->rank)
  4053. return (MonoObject*)mono_array_clone ((MonoArray*)obj);
  4054. o = mono_object_allocate (size, obj->vtable);
  4055. if (obj->vtable->klass->has_references) {
  4056. mono_gc_wbarrier_object_copy (o, obj);
  4057. } else {
  4058. int size = obj->vtable->klass->instance_size;
  4059. /* do not copy the sync state */
  4060. mono_gc_memmove ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
  4061. }
  4062. if (G_UNLIKELY (profile_allocs))
  4063. mono_profiler_allocation (o, obj->vtable->klass);
  4064. if (obj->vtable->klass->has_finalize)
  4065. mono_object_register_finalizer (o);
  4066. return o;
  4067. }
  4068. /**
  4069. * mono_array_full_copy:
  4070. * @src: source array to copy
  4071. * @dest: destination array
  4072. *
  4073. * Copies the content of one array to another with exactly the same type and size.
  4074. */
  4075. void
  4076. mono_array_full_copy (MonoArray *src, MonoArray *dest)
  4077. {
  4078. uintptr_t size;
  4079. MonoClass *klass = src->obj.vtable->klass;
  4080. MONO_ARCH_SAVE_REGS;
  4081. g_assert (klass == dest->obj.vtable->klass);
  4082. size = mono_array_length (src);
  4083. g_assert (size == mono_array_length (dest));
  4084. size *= mono_array_element_size (klass);
  4085. #ifdef HAVE_SGEN_GC
  4086. if (klass->element_class->valuetype) {
  4087. if (klass->element_class->has_references)
  4088. mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
  4089. else
  4090. mono_gc_memmove (&dest->vector, &src->vector, size);
  4091. } else {
  4092. mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
  4093. }
  4094. #else
  4095. mono_gc_memmove (&dest->vector, &src->vector, size);
  4096. #endif
  4097. }
  4098. /**
  4099. * mono_array_clone_in_domain:
  4100. * @domain: the domain in which the array will be cloned into
  4101. * @array: the array to clone
  4102. *
  4103. * This routine returns a copy of the array that is hosted on the
  4104. * specified MonoDomain.
  4105. */
  4106. MonoArray*
  4107. mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
  4108. {
  4109. MonoArray *o;
  4110. uintptr_t size, i;
  4111. uintptr_t *sizes;
  4112. MonoClass *klass = array->obj.vtable->klass;
  4113. MONO_ARCH_SAVE_REGS;
  4114. if (array->bounds == NULL) {
  4115. size = mono_array_length (array);
  4116. o = mono_array_new_full (domain, klass, &size, NULL);
  4117. size *= mono_array_element_size (klass);
  4118. #ifdef HAVE_SGEN_GC
  4119. if (klass->element_class->valuetype) {
  4120. if (klass->element_class->has_references)
  4121. mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
  4122. else
  4123. mono_gc_memmove (&o->vector, &array->vector, size);
  4124. } else {
  4125. mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
  4126. }
  4127. #else
  4128. mono_gc_memmove (&o->vector, &array->vector, size);
  4129. #endif
  4130. return o;
  4131. }
  4132. sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
  4133. size = mono_array_element_size (klass);
  4134. for (i = 0; i < klass->rank; ++i) {
  4135. sizes [i] = array->bounds [i].length;
  4136. size *= array->bounds [i].length;
  4137. sizes [i + klass->rank] = array->bounds [i].lower_bound;
  4138. }
  4139. o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
  4140. #ifdef HAVE_SGEN_GC
  4141. if (klass->element_class->valuetype) {
  4142. if (klass->element_class->has_references)
  4143. mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
  4144. else
  4145. mono_gc_memmove (&o->vector, &array->vector, size);
  4146. } else {
  4147. mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
  4148. }
  4149. #else
  4150. mono_gc_memmove (&o->vector, &array->vector, size);
  4151. #endif
  4152. return o;
  4153. }
  4154. /**
  4155. * mono_array_clone:
  4156. * @array: the array to clone
  4157. *
  4158. * Returns: A newly created array who is a shallow copy of @array
  4159. */
  4160. MonoArray*
  4161. mono_array_clone (MonoArray *array)
  4162. {
  4163. return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
  4164. }
  4165. /* helper macros to check for overflow when calculating the size of arrays */
  4166. #ifdef MONO_BIG_ARRAYS
  4167. #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
  4168. #define MYGUINT_MAX MYGUINT64_MAX
  4169. #define CHECK_ADD_OVERFLOW_UN(a,b) \
  4170. (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
  4171. #define CHECK_MUL_OVERFLOW_UN(a,b) \
  4172. (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
  4173. ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
  4174. #else
  4175. #define MYGUINT32_MAX 4294967295U
  4176. #define MYGUINT_MAX MYGUINT32_MAX
  4177. #define CHECK_ADD_OVERFLOW_UN(a,b) \
  4178. (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
  4179. #define CHECK_MUL_OVERFLOW_UN(a,b) \
  4180. (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
  4181. ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
  4182. #endif
  4183. gboolean
  4184. mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
  4185. {
  4186. uintptr_t byte_len;
  4187. byte_len = mono_array_element_size (class);
  4188. if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
  4189. return FALSE;
  4190. byte_len *= len;
  4191. if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
  4192. return FALSE;
  4193. byte_len += sizeof (MonoArray);
  4194. *res = byte_len;
  4195. return TRUE;
  4196. }
  4197. /**
  4198. * mono_array_new_full:
  4199. * @domain: domain where the object is created
  4200. * @array_class: array class
  4201. * @lengths: lengths for each dimension in the array
  4202. * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
  4203. *
  4204. * This routine creates a new array objects with the given dimensions,
  4205. * lower bounds and type.
  4206. */
  4207. MonoArray*
  4208. mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
  4209. {
  4210. uintptr_t byte_len, len, bounds_size;
  4211. MonoObject *o;
  4212. MonoArray *array;
  4213. MonoArrayBounds *bounds;
  4214. MonoVTable *vtable;
  4215. int i;
  4216. if (!array_class->inited)
  4217. mono_class_init (array_class);
  4218. len = 1;
  4219. /* A single dimensional array with a 0 lower bound is the same as an szarray */
  4220. if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
  4221. len = lengths [0];
  4222. if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
  4223. arith_overflow ();
  4224. bounds_size = 0;
  4225. } else {
  4226. bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
  4227. for (i = 0; i < array_class->rank; ++i) {
  4228. if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
  4229. arith_overflow ();
  4230. if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
  4231. mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  4232. len *= lengths [i];
  4233. }
  4234. }
  4235. if (!mono_array_calc_byte_len (array_class, len, &byte_len))
  4236. mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  4237. if (bounds_size) {
  4238. /* align */
  4239. if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
  4240. mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  4241. byte_len = (byte_len + 3) & ~3;
  4242. if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
  4243. mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  4244. byte_len += bounds_size;
  4245. }
  4246. /*
  4247. * Following three lines almost taken from mono_object_new ():
  4248. * they need to be kept in sync.
  4249. */
  4250. vtable = mono_class_vtable_full (domain, array_class, TRUE);
  4251. #ifndef HAVE_SGEN_GC
  4252. if (!array_class->has_references) {
  4253. o = mono_object_allocate_ptrfree (byte_len, vtable);
  4254. #if NEED_TO_ZERO_PTRFREE
  4255. memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
  4256. #endif
  4257. } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
  4258. o = mono_object_allocate_spec (byte_len, vtable);
  4259. }else {
  4260. o = mono_object_allocate (byte_len, vtable);
  4261. }
  4262. array = (MonoArray*)o;
  4263. array->max_length = len;
  4264. if (bounds_size) {
  4265. bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
  4266. array->bounds = bounds;
  4267. }
  4268. #else
  4269. if (bounds_size)
  4270. o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
  4271. else
  4272. o = mono_gc_alloc_vector (vtable, byte_len, len);
  4273. array = (MonoArray*)o;
  4274. mono_stats.new_object_count++;
  4275. bounds = array->bounds;
  4276. #endif
  4277. if (bounds_size) {
  4278. for (i = 0; i < array_class->rank; ++i) {
  4279. bounds [i].length = lengths [i];
  4280. if (lower_bounds)
  4281. bounds [i].lower_bound = lower_bounds [i];
  4282. }
  4283. }
  4284. if (G_UNLIKELY (profile_allocs))
  4285. mono_profiler_allocation (o, array_class);
  4286. return array;
  4287. }
  4288. /**
  4289. * mono_array_new:
  4290. * @domain: domain where the object is created
  4291. * @eclass: element class
  4292. * @n: number of array elements
  4293. *
  4294. * This routine creates a new szarray with @n elements of type @eclass.
  4295. */
  4296. MonoArray *
  4297. mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
  4298. {
  4299. MonoClass *ac;
  4300. MONO_ARCH_SAVE_REGS;
  4301. ac = mono_array_class_get (eclass, 1);
  4302. g_assert (ac);
  4303. return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
  4304. }
  4305. /**
  4306. * mono_array_new_specific:
  4307. * @vtable: a vtable in the appropriate domain for an initialized class
  4308. * @n: number of array elements
  4309. *
  4310. * This routine is a fast alternative to mono_array_new() for code which
  4311. * can be sure about the domain it operates in.
  4312. */
  4313. MonoArray *
  4314. mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
  4315. {
  4316. MonoObject *o;
  4317. MonoArray *ao;
  4318. uintptr_t byte_len;
  4319. MONO_ARCH_SAVE_REGS;
  4320. if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
  4321. arith_overflow ();
  4322. return NULL;
  4323. }
  4324. if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
  4325. mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  4326. return NULL;
  4327. }
  4328. #ifndef HAVE_SGEN_GC
  4329. if (!vtable->klass->has_references) {
  4330. o = mono_object_allocate_ptrfree (byte_len, vtable);
  4331. #if NEED_TO_ZERO_PTRFREE
  4332. ((MonoArray*)o)->bounds = NULL;
  4333. memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
  4334. #endif
  4335. } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
  4336. o = mono_object_allocate_spec (byte_len, vtable);
  4337. } else {
  4338. /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
  4339. o = mono_object_allocate (byte_len, vtable);
  4340. }
  4341. ao = (MonoArray *)o;
  4342. ao->max_length = n;
  4343. #else
  4344. o = mono_gc_alloc_vector (vtable, byte_len, n);
  4345. ao = (MonoArray*)o;
  4346. mono_stats.new_object_count++;
  4347. #endif
  4348. if (G_UNLIKELY (profile_allocs))
  4349. mono_profiler_allocation (o, vtable->klass);
  4350. return ao;
  4351. }
  4352. /**
  4353. * mono_string_new_utf16:
  4354. * @text: a pointer to an utf16 string
  4355. * @len: the length of the string
  4356. *
  4357. * Returns: A newly created string object which contains @text.
  4358. */
  4359. MonoString *
  4360. mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
  4361. {
  4362. MonoString *s;
  4363. s = mono_string_new_size (domain, len);
  4364. g_assert (s != NULL);
  4365. memcpy (mono_string_chars (s), text, len * 2);
  4366. return s;
  4367. }
  4368. /**
  4369. * mono_string_new_size:
  4370. * @text: a pointer to an utf16 string
  4371. * @len: the length of the string
  4372. *
  4373. * Returns: A newly created string object of @len
  4374. */
  4375. MonoString *
  4376. mono_string_new_size (MonoDomain *domain, gint32 len)
  4377. {
  4378. MonoString *s;
  4379. MonoVTable *vtable;
  4380. size_t size = (sizeof (MonoString) + ((len + 1) * 2));
  4381. /* overflow ? can't fit it, can't allocate it! */
  4382. if (len > size)
  4383. mono_gc_out_of_memory (-1);
  4384. vtable = mono_class_vtable (domain, mono_defaults.string_class);
  4385. g_assert (vtable);
  4386. #ifndef HAVE_SGEN_GC
  4387. s = mono_object_allocate_ptrfree (size, vtable);
  4388. s->length = len;
  4389. #else
  4390. s = mono_gc_alloc_string (vtable, size, len);
  4391. #endif
  4392. #if NEED_TO_ZERO_PTRFREE
  4393. s->chars [len] = 0;
  4394. #endif
  4395. if (G_UNLIKELY (profile_allocs))
  4396. mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
  4397. return s;
  4398. }
  4399. /**
  4400. * mono_string_new_len:
  4401. * @text: a pointer to an utf8 string
  4402. * @length: number of bytes in @text to consider
  4403. *
  4404. * Returns: A newly created string object which contains @text.
  4405. */
  4406. MonoString*
  4407. mono_string_new_len (MonoDomain *domain, const char *text, guint length)
  4408. {
  4409. GError *error = NULL;
  4410. MonoString *o = NULL;
  4411. guint16 *ut;
  4412. glong items_written;
  4413. ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
  4414. if (!error)
  4415. o = mono_string_new_utf16 (domain, ut, items_written);
  4416. else
  4417. g_error_free (error);
  4418. g_free (ut);
  4419. return o;
  4420. }
  4421. /**
  4422. * mono_string_new:
  4423. * @text: a pointer to an utf8 string
  4424. *
  4425. * Returns: A newly created string object which contains @text.
  4426. */
  4427. MonoString*
  4428. mono_string_new (MonoDomain *domain, const char *text)
  4429. {
  4430. GError *error = NULL;
  4431. MonoString *o = NULL;
  4432. guint16 *ut;
  4433. glong items_written;
  4434. int l;
  4435. l = strlen (text);
  4436. ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
  4437. if (!error)
  4438. o = mono_string_new_utf16 (domain, ut, items_written);
  4439. else
  4440. g_error_free (error);
  4441. g_free (ut);
  4442. /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
  4443. #if 0
  4444. gunichar2 *str;
  4445. const gchar *end;
  4446. int len;
  4447. MonoString *o = NULL;
  4448. if (!g_utf8_validate (text, -1, &end))
  4449. return NULL;
  4450. len = g_utf8_strlen (text, -1);
  4451. o = mono_string_new_size (domain, len);
  4452. str = mono_string_chars (o);
  4453. while (text < end) {
  4454. *str++ = g_utf8_get_char (text);
  4455. text = g_utf8_next_char (text);
  4456. }
  4457. #endif
  4458. return o;
  4459. }
  4460. /**
  4461. * mono_string_new_wrapper:
  4462. * @text: pointer to utf8 characters.
  4463. *
  4464. * Helper function to create a string object from @text in the current domain.
  4465. */
  4466. MonoString*
  4467. mono_string_new_wrapper (const char *text)
  4468. {
  4469. MonoDomain *domain = mono_domain_get ();
  4470. MONO_ARCH_SAVE_REGS;
  4471. if (text)
  4472. return mono_string_new (domain, text);
  4473. return NULL;
  4474. }
  4475. /**
  4476. * mono_value_box:
  4477. * @class: the class of the value
  4478. * @value: a pointer to the unboxed data
  4479. *
  4480. * Returns: A newly created object which contains @value.
  4481. */
  4482. MonoObject *
  4483. mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
  4484. {
  4485. MonoObject *res;
  4486. int size;
  4487. MonoVTable *vtable;
  4488. g_assert (class->valuetype);
  4489. if (mono_class_is_nullable (class))
  4490. return mono_nullable_box (value, class);
  4491. vtable = mono_class_vtable (domain, class);
  4492. if (!vtable)
  4493. return NULL;
  4494. size = mono_class_instance_size (class);
  4495. res = mono_object_new_alloc_specific (vtable);
  4496. if (G_UNLIKELY (profile_allocs))
  4497. mono_profiler_allocation (res, class);
  4498. size = size - sizeof (MonoObject);
  4499. #ifdef HAVE_SGEN_GC
  4500. g_assert (size == mono_class_value_size (class, NULL));
  4501. mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
  4502. #else
  4503. #if NO_UNALIGNED_ACCESS
  4504. mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
  4505. #else
  4506. switch (size) {
  4507. case 1:
  4508. *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
  4509. break;
  4510. case 2:
  4511. *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
  4512. break;
  4513. case 4:
  4514. *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
  4515. break;
  4516. case 8:
  4517. *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
  4518. break;
  4519. default:
  4520. mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
  4521. }
  4522. #endif
  4523. #endif
  4524. if (class->has_finalize)
  4525. mono_object_register_finalizer (res);
  4526. return res;
  4527. }
  4528. /*
  4529. * mono_value_copy:
  4530. * @dest: destination pointer
  4531. * @src: source pointer
  4532. * @klass: a valuetype class
  4533. *
  4534. * Copy a valuetype from @src to @dest. This function must be used
  4535. * when @klass contains references fields.
  4536. */
  4537. void
  4538. mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
  4539. {
  4540. mono_gc_wbarrier_value_copy (dest, src, 1, klass);
  4541. }
  4542. /*
  4543. * mono_value_copy_array:
  4544. * @dest: destination array
  4545. * @dest_idx: index in the @dest array
  4546. * @src: source pointer
  4547. * @count: number of items
  4548. *
  4549. * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
  4550. * This function must be used when @klass contains references fields.
  4551. * Overlap is handled.
  4552. */
  4553. void
  4554. mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
  4555. {
  4556. int size = mono_array_element_size (dest->obj.vtable->klass);
  4557. char *d = mono_array_addr_with_size (dest, size, dest_idx);
  4558. g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
  4559. mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
  4560. }
  4561. /**
  4562. * mono_object_get_domain:
  4563. * @obj: object to query
  4564. *
  4565. * Returns: the MonoDomain where the object is hosted
  4566. */
  4567. MonoDomain*
  4568. mono_object_get_domain (MonoObject *obj)
  4569. {
  4570. return mono_object_domain (obj);
  4571. }
  4572. /**
  4573. * mono_object_get_class:
  4574. * @obj: object to query
  4575. *
  4576. * Returns: the MonOClass of the object.
  4577. */
  4578. MonoClass*
  4579. mono_object_get_class (MonoObject *obj)
  4580. {
  4581. return mono_object_class (obj);
  4582. }
  4583. /**
  4584. * mono_object_get_size:
  4585. * @o: object to query
  4586. *
  4587. * Returns: the size, in bytes, of @o
  4588. */
  4589. guint
  4590. mono_object_get_size (MonoObject* o)
  4591. {
  4592. MonoClass* klass = mono_object_class (o);
  4593. if (klass == mono_defaults.string_class) {
  4594. return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
  4595. } else if (o->vtable->rank) {
  4596. MonoArray *array = (MonoArray*)o;
  4597. size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
  4598. if (array->bounds) {
  4599. size += 3;
  4600. size &= ~3;
  4601. size += sizeof (MonoArrayBounds) * o->vtable->rank;
  4602. }
  4603. return size;
  4604. } else {
  4605. return mono_class_instance_size (klass);
  4606. }
  4607. }
  4608. /**
  4609. * mono_object_unbox:
  4610. * @obj: object to unbox
  4611. *
  4612. * Returns: a pointer to the start of the valuetype boxed in this
  4613. * object.
  4614. *
  4615. * This method will assert if the object passed is not a valuetype.
  4616. */
  4617. gpointer
  4618. mono_object_unbox (MonoObject *obj)
  4619. {
  4620. /* add assert for valuetypes? */
  4621. g_assert (obj->vtable->klass->valuetype);
  4622. return ((char*)obj) + sizeof (MonoObject);
  4623. }
  4624. /**
  4625. * mono_object_isinst:
  4626. * @obj: an object
  4627. * @klass: a pointer to a class
  4628. *
  4629. * Returns: @obj if @obj is derived from @klass
  4630. */
  4631. MonoObject *
  4632. mono_object_isinst (MonoObject *obj, MonoClass *klass)
  4633. {
  4634. if (!klass->inited)
  4635. mono_class_init (klass);
  4636. if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
  4637. return mono_object_isinst_mbyref (obj, klass);
  4638. if (!obj)
  4639. return NULL;
  4640. return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
  4641. }
  4642. MonoObject *
  4643. mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
  4644. {
  4645. MonoVTable *vt;
  4646. if (!obj)
  4647. return NULL;
  4648. vt = obj->vtable;
  4649. if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
  4650. if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
  4651. return obj;
  4652. }
  4653. /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
  4654. if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
  4655. return obj;
  4656. } else {
  4657. MonoClass *oklass = vt->klass;
  4658. if (mono_class_is_transparent_proxy (oklass))
  4659. oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
  4660. mono_class_setup_supertypes (klass);
  4661. if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
  4662. return obj;
  4663. }
  4664. #ifndef DISABLE_REMOTING
  4665. if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
  4666. {
  4667. MonoDomain *domain = mono_domain_get ();
  4668. MonoObject *res;
  4669. MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
  4670. MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
  4671. MonoMethod *im = NULL;
  4672. gpointer pa [2];
  4673. im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
  4674. im = mono_object_get_virtual_method (rp, im);
  4675. g_assert (im);
  4676. pa [0] = mono_type_get_object (domain, &klass->byval_arg);
  4677. pa [1] = obj;
  4678. res = mono_runtime_invoke (im, rp, pa, NULL);
  4679. if (*(MonoBoolean *) mono_object_unbox(res)) {
  4680. /* Update the vtable of the remote type, so it can safely cast to this new type */
  4681. mono_upgrade_remote_class (domain, obj, klass);
  4682. return obj;
  4683. }
  4684. }
  4685. #endif /* DISABLE_REMOTING */
  4686. return NULL;
  4687. }
  4688. /**
  4689. * mono_object_castclass_mbyref:
  4690. * @obj: an object
  4691. * @klass: a pointer to a class
  4692. *
  4693. * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
  4694. */
  4695. MonoObject *
  4696. mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
  4697. {
  4698. if (!obj) return NULL;
  4699. if (mono_object_isinst_mbyref (obj, klass)) return obj;
  4700. mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
  4701. "System",
  4702. "InvalidCastException"));
  4703. return NULL;
  4704. }
  4705. typedef struct {
  4706. MonoDomain *orig_domain;
  4707. MonoString *ins;
  4708. MonoString *res;
  4709. } LDStrInfo;
  4710. static void
  4711. str_lookup (MonoDomain *domain, gpointer user_data)
  4712. {
  4713. LDStrInfo *info = user_data;
  4714. if (info->res || domain == info->orig_domain)
  4715. return;
  4716. info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
  4717. }
  4718. #ifdef HAVE_SGEN_GC
  4719. static MonoString*
  4720. mono_string_get_pinned (MonoString *str)
  4721. {
  4722. int size;
  4723. MonoString *news;
  4724. size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
  4725. news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
  4726. if (news) {
  4727. memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
  4728. news->length = mono_string_length (str);
  4729. }
  4730. return news;
  4731. }
  4732. #else
  4733. #define mono_string_get_pinned(str) (str)
  4734. #endif
  4735. static MonoString*
  4736. mono_string_is_interned_lookup (MonoString *str, int insert)
  4737. {
  4738. MonoGHashTable *ldstr_table;
  4739. MonoString *res;
  4740. MonoDomain *domain;
  4741. domain = ((MonoObject *)str)->vtable->domain;
  4742. ldstr_table = domain->ldstr_table;
  4743. ldstr_lock ();
  4744. if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
  4745. ldstr_unlock ();
  4746. return res;
  4747. }
  4748. if (insert) {
  4749. str = mono_string_get_pinned (str);
  4750. if (str)
  4751. mono_g_hash_table_insert (ldstr_table, str, str);
  4752. ldstr_unlock ();
  4753. return str;
  4754. } else {
  4755. LDStrInfo ldstr_info;
  4756. ldstr_info.orig_domain = domain;
  4757. ldstr_info.ins = str;
  4758. ldstr_info.res = NULL;
  4759. mono_domain_foreach (str_lookup, &ldstr_info);
  4760. if (ldstr_info.res) {
  4761. /*
  4762. * the string was already interned in some other domain:
  4763. * intern it in the current one as well.
  4764. */
  4765. mono_g_hash_table_insert (ldstr_table, str, str);
  4766. ldstr_unlock ();
  4767. return str;
  4768. }
  4769. }
  4770. ldstr_unlock ();
  4771. return NULL;
  4772. }
  4773. /**
  4774. * mono_string_is_interned:
  4775. * @o: String to probe
  4776. *
  4777. * Returns whether the string has been interned.
  4778. */
  4779. MonoString*
  4780. mono_string_is_interned (MonoString *o)
  4781. {
  4782. return mono_string_is_interned_lookup (o, FALSE);
  4783. }
  4784. /**
  4785. * mono_string_intern:
  4786. * @o: String to intern
  4787. *
  4788. * Interns the string passed.
  4789. * Returns: The interned string.
  4790. */
  4791. MonoString*
  4792. mono_string_intern (MonoString *str)
  4793. {
  4794. return mono_string_is_interned_lookup (str, TRUE);
  4795. }
  4796. /**
  4797. * mono_ldstr:
  4798. * @domain: the domain where the string will be used.
  4799. * @image: a metadata context
  4800. * @idx: index into the user string table.
  4801. *
  4802. * Implementation for the ldstr opcode.
  4803. * Returns: a loaded string from the @image/@idx combination.
  4804. */
  4805. MonoString*
  4806. mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
  4807. {
  4808. MONO_ARCH_SAVE_REGS;
  4809. if (image->dynamic) {
  4810. MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
  4811. return str;
  4812. } else {
  4813. if (!mono_verifier_verify_string_signature (image, idx, NULL))
  4814. return NULL; /*FIXME we should probably be raising an exception here*/
  4815. return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
  4816. }
  4817. }
  4818. /**
  4819. * mono_ldstr_metadata_sig
  4820. * @domain: the domain for the string
  4821. * @sig: the signature of a metadata string
  4822. *
  4823. * Returns: a MonoString for a string stored in the metadata
  4824. */
  4825. static MonoString*
  4826. mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
  4827. {
  4828. const char *str = sig;
  4829. MonoString *o, *interned;
  4830. size_t len2;
  4831. len2 = mono_metadata_decode_blob_size (str, &str);
  4832. len2 >>= 1;
  4833. o = mono_string_new_utf16 (domain, (guint16*)str, len2);
  4834. #if G_BYTE_ORDER != G_LITTLE_ENDIAN
  4835. {
  4836. int i;
  4837. guint16 *p2 = (guint16*)mono_string_chars (o);
  4838. for (i = 0; i < len2; ++i) {
  4839. *p2 = GUINT16_FROM_LE (*p2);
  4840. ++p2;
  4841. }
  4842. }
  4843. #endif
  4844. ldstr_lock ();
  4845. if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
  4846. ldstr_unlock ();
  4847. /* o will get garbage collected */
  4848. return interned;
  4849. }
  4850. o = mono_string_get_pinned (o);
  4851. if (o)
  4852. mono_g_hash_table_insert (domain->ldstr_table, o, o);
  4853. ldstr_unlock ();
  4854. return o;
  4855. }
  4856. /**
  4857. * mono_string_to_utf8:
  4858. * @s: a System.String
  4859. *
  4860. * Returns the UTF8 representation for @s.
  4861. * The resulting buffer needs to be freed with mono_free().
  4862. *
  4863. * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
  4864. */
  4865. char *
  4866. mono_string_to_utf8 (MonoString *s)
  4867. {
  4868. MonoError error;
  4869. char *result = mono_string_to_utf8_checked (s, &error);
  4870. if (!mono_error_ok (&error))
  4871. mono_error_raise_exception (&error);
  4872. return result;
  4873. }
  4874. /**
  4875. * mono_string_to_utf8_checked:
  4876. * @s: a System.String
  4877. * @error: a MonoError.
  4878. *
  4879. * Converts a MonoString to its UTF8 representation. May fail; check
  4880. * @error to determine whether the conversion was successful.
  4881. * The resulting buffer should be freed with mono_free().
  4882. */
  4883. char *
  4884. mono_string_to_utf8_checked (MonoString *s, MonoError *error)
  4885. {
  4886. long written = 0;
  4887. char *as;
  4888. GError *gerror = NULL;
  4889. mono_error_init (error);
  4890. if (s == NULL)
  4891. return NULL;
  4892. if (!s->length)
  4893. return g_strdup ("");
  4894. as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
  4895. if (gerror) {
  4896. mono_error_set_argument (error, "string", "%s", gerror->message);
  4897. g_error_free (gerror);
  4898. return NULL;
  4899. }
  4900. /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
  4901. if (s->length > written) {
  4902. /* allocate the total length and copy the part of the string that has been converted */
  4903. char *as2 = g_malloc0 (s->length);
  4904. memcpy (as2, as, written);
  4905. g_free (as);
  4906. as = as2;
  4907. }
  4908. return as;
  4909. }
  4910. /**
  4911. * mono_string_to_utf8_ignore:
  4912. * @s: a MonoString
  4913. *
  4914. * Converts a MonoString to its UTF8 representation. Will ignore
  4915. * invalid surrogate pairs.
  4916. * The resulting buffer should be freed with mono_free().
  4917. *
  4918. */
  4919. char *
  4920. mono_string_to_utf8_ignore (MonoString *s)
  4921. {
  4922. long written = 0;
  4923. char *as;
  4924. if (s == NULL)
  4925. return NULL;
  4926. if (!s->length)
  4927. return g_strdup ("");
  4928. as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
  4929. /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
  4930. if (s->length > written) {
  4931. /* allocate the total length and copy the part of the string that has been converted */
  4932. char *as2 = g_malloc0 (s->length);
  4933. memcpy (as2, as, written);
  4934. g_free (as);
  4935. as = as2;
  4936. }
  4937. return as;
  4938. }
  4939. /**
  4940. * mono_string_to_utf8_image_ignore:
  4941. * @s: a System.String
  4942. *
  4943. * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
  4944. */
  4945. char *
  4946. mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
  4947. {
  4948. return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
  4949. }
  4950. /**
  4951. * mono_string_to_utf8_mp_ignore:
  4952. * @s: a System.String
  4953. *
  4954. * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
  4955. */
  4956. char *
  4957. mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
  4958. {
  4959. return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
  4960. }
  4961. /**
  4962. * mono_string_to_utf16:
  4963. * @s: a MonoString
  4964. *
  4965. * Return an null-terminated array of the utf-16 chars
  4966. * contained in @s. The result must be freed with g_free().
  4967. * This is a temporary helper until our string implementation
  4968. * is reworked to always include the null terminating char.
  4969. */
  4970. mono_unichar2*
  4971. mono_string_to_utf16 (MonoString *s)
  4972. {
  4973. char *as;
  4974. if (s == NULL)
  4975. return NULL;
  4976. as = g_malloc ((s->length * 2) + 2);
  4977. as [(s->length * 2)] = '\0';
  4978. as [(s->length * 2) + 1] = '\0';
  4979. if (!s->length) {
  4980. return (gunichar2 *)(as);
  4981. }
  4982. memcpy (as, mono_string_chars(s), s->length * 2);
  4983. return (gunichar2 *)(as);
  4984. }
  4985. /**
  4986. * mono_string_from_utf16:
  4987. * @data: the UTF16 string (LPWSTR) to convert
  4988. *
  4989. * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
  4990. *
  4991. * Returns: a MonoString.
  4992. */
  4993. MonoString *
  4994. mono_string_from_utf16 (gunichar2 *data)
  4995. {
  4996. MonoDomain *domain = mono_domain_get ();
  4997. int len = 0;
  4998. if (!data)
  4999. return NULL;
  5000. while (data [len]) len++;
  5001. return mono_string_new_utf16 (domain, data, len);
  5002. }
  5003. static char *
  5004. mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
  5005. {
  5006. char *r;
  5007. char *mp_s;
  5008. int len;
  5009. if (ignore_error) {
  5010. r = mono_string_to_utf8_ignore (s);
  5011. } else {
  5012. r = mono_string_to_utf8_checked (s, error);
  5013. if (!mono_error_ok (error))
  5014. return NULL;
  5015. }
  5016. if (!mp && !image)
  5017. return r;
  5018. len = strlen (r) + 1;
  5019. if (mp)
  5020. mp_s = mono_mempool_alloc (mp, len);
  5021. else
  5022. mp_s = mono_image_alloc (image, len);
  5023. memcpy (mp_s, r, len);
  5024. g_free (r);
  5025. return mp_s;
  5026. }
  5027. /**
  5028. * mono_string_to_utf8_image:
  5029. * @s: a System.String
  5030. *
  5031. * Same as mono_string_to_utf8, but allocate the string from the image mempool.
  5032. */
  5033. char *
  5034. mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
  5035. {
  5036. return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
  5037. }
  5038. /**
  5039. * mono_string_to_utf8_mp:
  5040. * @s: a System.String
  5041. *
  5042. * Same as mono_string_to_utf8, but allocate the string from a mempool.
  5043. */
  5044. char *
  5045. mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
  5046. {
  5047. return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
  5048. }
  5049. static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
  5050. void
  5051. mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
  5052. {
  5053. eh_callbacks = *cbs;
  5054. }
  5055. MonoRuntimeExceptionHandlingCallbacks *
  5056. mono_get_eh_callbacks (void)
  5057. {
  5058. return &eh_callbacks;
  5059. }
  5060. /**
  5061. * mono_raise_exception:
  5062. * @ex: exception object
  5063. *
  5064. * Signal the runtime that the exception @ex has been raised in unmanaged code.
  5065. */
  5066. void
  5067. mono_raise_exception (MonoException *ex)
  5068. {
  5069. /*
  5070. * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
  5071. * that will cause gcc to omit the function epilog, causing problems when
  5072. * the JIT tries to walk the stack, since the return address on the stack
  5073. * will point into the next function in the executable, not this one.
  5074. */
  5075. eh_callbacks.mono_raise_exception (ex);
  5076. }
  5077. void
  5078. mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
  5079. {
  5080. eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
  5081. }
  5082. /**
  5083. * mono_wait_handle_new:
  5084. * @domain: Domain where the object will be created
  5085. * @handle: Handle for the wait handle
  5086. *
  5087. * Returns: A new MonoWaitHandle created in the given domain for the given handle
  5088. */
  5089. MonoWaitHandle *
  5090. mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
  5091. {
  5092. MonoWaitHandle *res;
  5093. gpointer params [1];
  5094. static MonoMethod *handle_set;
  5095. res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
  5096. /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
  5097. if (!handle_set)
  5098. handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
  5099. params [0] = &handle;
  5100. mono_runtime_invoke (handle_set, res, params, NULL);
  5101. return res;
  5102. }
  5103. HANDLE
  5104. mono_wait_handle_get_handle (MonoWaitHandle *handle)
  5105. {
  5106. static MonoClassField *f_os_handle;
  5107. static MonoClassField *f_safe_handle;
  5108. if (!f_os_handle && !f_safe_handle) {
  5109. f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
  5110. f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
  5111. }
  5112. if (f_os_handle) {
  5113. HANDLE retval;
  5114. mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
  5115. return retval;
  5116. } else {
  5117. MonoSafeHandle *sh;
  5118. mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
  5119. return sh->handle;
  5120. }
  5121. }
  5122. static MonoObject*
  5123. mono_runtime_capture_context (MonoDomain *domain)
  5124. {
  5125. RuntimeInvokeFunction runtime_invoke;
  5126. if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
  5127. MonoMethod *method = mono_get_context_capture_method ();
  5128. MonoMethod *wrapper;
  5129. if (!method)
  5130. return NULL;
  5131. wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
  5132. domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
  5133. domain->capture_context_method = mono_compile_method (method);
  5134. }
  5135. runtime_invoke = domain->capture_context_runtime_invoke;
  5136. return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
  5137. }
  5138. /**
  5139. * mono_async_result_new:
  5140. * @domain:domain where the object will be created.
  5141. * @handle: wait handle.
  5142. * @state: state to pass to AsyncResult
  5143. * @data: C closure data.
  5144. *
  5145. * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
  5146. * If the handle is not null, the handle is initialized to a MonOWaitHandle.
  5147. *
  5148. */
  5149. MonoAsyncResult *
  5150. mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
  5151. {
  5152. MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
  5153. MonoObject *context = mono_runtime_capture_context (domain);
  5154. /* we must capture the execution context from the original thread */
  5155. if (context) {
  5156. MONO_OBJECT_SETREF (res, execution_context, context);
  5157. /* note: result may be null if the flow is suppressed */
  5158. }
  5159. res->data = data;
  5160. MONO_OBJECT_SETREF (res, object_data, object_data);
  5161. MONO_OBJECT_SETREF (res, async_state, state);
  5162. if (handle != NULL)
  5163. MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
  5164. res->sync_completed = FALSE;
  5165. res->completed = FALSE;
  5166. return res;
  5167. }
  5168. void
  5169. mono_message_init (MonoDomain *domain,
  5170. MonoMethodMessage *this,
  5171. MonoReflectionMethod *method,
  5172. MonoArray *out_args)
  5173. {
  5174. static MonoClass *object_array_klass;
  5175. static MonoClass *byte_array_klass;
  5176. static MonoClass *string_array_klass;
  5177. MonoMethodSignature *sig = mono_method_signature (method->method);
  5178. MonoString *name;
  5179. int i, j;
  5180. char **names;
  5181. guint8 arg_type;
  5182. if (!object_array_klass) {
  5183. MonoClass *klass;
  5184. klass = mono_array_class_get (mono_defaults.byte_class, 1);
  5185. g_assert (klass);
  5186. byte_array_klass = klass;
  5187. klass = mono_array_class_get (mono_defaults.string_class, 1);
  5188. g_assert (klass);
  5189. string_array_klass = klass;
  5190. klass = mono_array_class_get (mono_defaults.object_class, 1);
  5191. g_assert (klass);
  5192. mono_atomic_store_release (&object_array_klass, klass);
  5193. }
  5194. MONO_OBJECT_SETREF (this, method, method);
  5195. MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
  5196. MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
  5197. this->async_result = NULL;
  5198. this->call_type = CallType_Sync;
  5199. names = g_new (char *, sig->param_count);
  5200. mono_method_get_param_names (method->method, (const char **) names);
  5201. MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
  5202. for (i = 0; i < sig->param_count; i++) {
  5203. name = mono_string_new (domain, names [i]);
  5204. mono_array_setref (this->names, i, name);
  5205. }
  5206. g_free (names);
  5207. for (i = 0, j = 0; i < sig->param_count; i++) {
  5208. if (sig->params [i]->byref) {
  5209. if (out_args) {
  5210. MonoObject* arg = mono_array_get (out_args, gpointer, j);
  5211. mono_array_setref (this->args, i, arg);
  5212. j++;
  5213. }
  5214. arg_type = 2;
  5215. if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
  5216. arg_type |= 1;
  5217. } else {
  5218. arg_type = 1;
  5219. if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
  5220. arg_type |= 4;
  5221. }
  5222. mono_array_set (this->arg_types, guint8, i, arg_type);
  5223. }
  5224. }
  5225. #ifndef DISABLE_REMOTING
  5226. /**
  5227. * mono_remoting_invoke:
  5228. * @real_proxy: pointer to a RealProxy object
  5229. * @msg: The MonoMethodMessage to execute
  5230. * @exc: used to store exceptions
  5231. * @out_args: used to store output arguments
  5232. *
  5233. * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
  5234. * IMessage interface and it is not trivial to extract results from there. So
  5235. * we call an helper method PrivateInvoke instead of calling
  5236. * RealProxy::Invoke() directly.
  5237. *
  5238. * Returns: the result object.
  5239. */
  5240. MonoObject *
  5241. mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
  5242. MonoObject **exc, MonoArray **out_args)
  5243. {
  5244. MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
  5245. gpointer pa [4];
  5246. /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
  5247. if (!im) {
  5248. im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
  5249. g_assert (im);
  5250. real_proxy->vtable->domain->private_invoke_method = im;
  5251. }
  5252. pa [0] = real_proxy;
  5253. pa [1] = msg;
  5254. pa [2] = exc;
  5255. pa [3] = out_args;
  5256. return mono_runtime_invoke (im, NULL, pa, exc);
  5257. }
  5258. #endif
  5259. MonoObject *
  5260. mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
  5261. MonoObject **exc, MonoArray **out_args)
  5262. {
  5263. static MonoClass *object_array_klass;
  5264. MonoDomain *domain;
  5265. MonoMethod *method;
  5266. MonoMethodSignature *sig;
  5267. MonoObject *ret;
  5268. int i, j, outarg_count = 0;
  5269. #ifndef DISABLE_REMOTING
  5270. if (target && mono_object_is_transparent_proxy (target)) {
  5271. MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
  5272. if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
  5273. target = tp->rp->unwrapped_server;
  5274. } else {
  5275. return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
  5276. }
  5277. }
  5278. #endif
  5279. domain = mono_domain_get ();
  5280. method = msg->method->method;
  5281. sig = mono_method_signature (method);
  5282. for (i = 0; i < sig->param_count; i++) {
  5283. if (sig->params [i]->byref)
  5284. outarg_count++;
  5285. }
  5286. if (!object_array_klass) {
  5287. MonoClass *klass;
  5288. klass = mono_array_class_get (mono_defaults.object_class, 1);
  5289. g_assert (klass);
  5290. mono_memory_barrier ();
  5291. object_array_klass = klass;
  5292. }
  5293. /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
  5294. *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
  5295. *exc = NULL;
  5296. ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
  5297. for (i = 0, j = 0; i < sig->param_count; i++) {
  5298. if (sig->params [i]->byref) {
  5299. MonoObject* arg;
  5300. arg = mono_array_get (msg->args, gpointer, i);
  5301. mono_array_setref (*out_args, j, arg);
  5302. j++;
  5303. }
  5304. }
  5305. return ret;
  5306. }
  5307. /**
  5308. * mono_object_to_string:
  5309. * @obj: The object
  5310. * @exc: Any exception thrown by ToString (). May be NULL.
  5311. *
  5312. * Returns: the result of calling ToString () on an object.
  5313. */
  5314. MonoString *
  5315. mono_object_to_string (MonoObject *obj, MonoObject **exc)
  5316. {
  5317. static MonoMethod *to_string = NULL;
  5318. MonoMethod *method;
  5319. g_assert (obj);
  5320. if (!to_string)
  5321. to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
  5322. method = mono_object_get_virtual_method (obj, to_string);
  5323. return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
  5324. }
  5325. /**
  5326. * mono_print_unhandled_exception:
  5327. * @exc: The exception
  5328. *
  5329. * Prints the unhandled exception.
  5330. */
  5331. void
  5332. mono_print_unhandled_exception (MonoObject *exc)
  5333. {
  5334. MonoString * str;
  5335. char *message = (char*)"";
  5336. gboolean free_message = FALSE;
  5337. MonoError error;
  5338. if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
  5339. message = g_strdup ("OutOfMemoryException");
  5340. free_message = TRUE;
  5341. } else {
  5342. if (((MonoException*)exc)->native_trace_ips) {
  5343. message = mono_exception_get_native_backtrace ((MonoException*)exc);
  5344. free_message = TRUE;
  5345. } else {
  5346. MonoObject *other_exc = NULL;
  5347. str = mono_object_to_string (exc, &other_exc);
  5348. if (other_exc) {
  5349. message = g_strdup ("Nested exception, bailing out");
  5350. } else if (str) {
  5351. message = mono_string_to_utf8_checked (str, &error);
  5352. if (!mono_error_ok (&error)) {
  5353. mono_error_cleanup (&error);
  5354. message = (char *) "";
  5355. } else {
  5356. free_message = TRUE;
  5357. }
  5358. }
  5359. }
  5360. }
  5361. /*
  5362. * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
  5363. * exc->vtable->klass->name, message);
  5364. */
  5365. g_printerr ("\nUnhandled Exception:\n%s\n", message);
  5366. if (free_message)
  5367. g_free (message);
  5368. }
  5369. /**
  5370. * mono_delegate_ctor:
  5371. * @this: pointer to an uninitialized delegate object
  5372. * @target: target object
  5373. * @addr: pointer to native code
  5374. * @method: method
  5375. *
  5376. * Initialize a delegate and sets a specific method, not the one
  5377. * associated with addr. This is useful when sharing generic code.
  5378. * In that case addr will most probably not be associated with the
  5379. * correct instantiation of the method.
  5380. */
  5381. void
  5382. mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
  5383. {
  5384. MonoDelegate *delegate = (MonoDelegate *)this;
  5385. MonoClass *class;
  5386. g_assert (this);
  5387. g_assert (addr);
  5388. if (method)
  5389. delegate->method = method;
  5390. class = this->vtable->klass;
  5391. mono_stats.delegate_creations++;
  5392. #ifndef DISABLE_REMOTING
  5393. if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
  5394. g_assert (method);
  5395. method = mono_marshal_get_remoting_invoke (method);
  5396. delegate->method_ptr = mono_compile_method (method);
  5397. MONO_OBJECT_SETREF (delegate, target, target);
  5398. } else
  5399. #endif
  5400. {
  5401. delegate->method_ptr = addr;
  5402. MONO_OBJECT_SETREF (delegate, target, target);
  5403. }
  5404. delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
  5405. }
  5406. /**
  5407. * mono_delegate_ctor:
  5408. * @this: pointer to an uninitialized delegate object
  5409. * @target: target object
  5410. * @addr: pointer to native code
  5411. *
  5412. * This is used to initialize a delegate.
  5413. */
  5414. void
  5415. mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
  5416. {
  5417. MonoDomain *domain = mono_domain_get ();
  5418. MonoJitInfo *ji;
  5419. MonoMethod *method = NULL;
  5420. g_assert (addr);
  5421. ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
  5422. /* Shared code */
  5423. if (!ji && domain != mono_get_root_domain ())
  5424. ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
  5425. if (ji) {
  5426. method = ji->method;
  5427. g_assert (!method->klass->generic_container);
  5428. }
  5429. mono_delegate_ctor_with_method (this, target, addr, method);
  5430. }
  5431. /**
  5432. * mono_method_call_message_new:
  5433. * @method: method to encapsulate
  5434. * @params: parameters to the method
  5435. * @invoke: optional, delegate invoke.
  5436. * @cb: async callback delegate.
  5437. * @state: state passed to the async callback.
  5438. *
  5439. * Translates arguments pointers into a MonoMethodMessage.
  5440. */
  5441. MonoMethodMessage *
  5442. mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
  5443. MonoDelegate **cb, MonoObject **state)
  5444. {
  5445. MonoDomain *domain = mono_domain_get ();
  5446. MonoMethodSignature *sig = mono_method_signature (method);
  5447. MonoMethodMessage *msg;
  5448. int i, count, type;
  5449. msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
  5450. if (invoke) {
  5451. mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
  5452. count = sig->param_count - 2;
  5453. } else {
  5454. mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
  5455. count = sig->param_count;
  5456. }
  5457. for (i = 0; i < count; i++) {
  5458. gpointer vpos;
  5459. MonoClass *class;
  5460. MonoObject *arg;
  5461. if (sig->params [i]->byref)
  5462. vpos = *((gpointer *)params [i]);
  5463. else
  5464. vpos = params [i];
  5465. type = sig->params [i]->type;
  5466. class = mono_class_from_mono_type (sig->params [i]);
  5467. if (class->valuetype)
  5468. arg = mono_value_box (domain, class, vpos);
  5469. else
  5470. arg = *((MonoObject **)vpos);
  5471. mono_array_setref (msg->args, i, arg);
  5472. }
  5473. if (cb != NULL && state != NULL) {
  5474. *cb = *((MonoDelegate **)params [i]);
  5475. i++;
  5476. *state = *((MonoObject **)params [i]);
  5477. }
  5478. return msg;
  5479. }
  5480. /**
  5481. * mono_method_return_message_restore:
  5482. *
  5483. * Restore results from message based processing back to arguments pointers
  5484. */
  5485. void
  5486. mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
  5487. {
  5488. MonoMethodSignature *sig = mono_method_signature (method);
  5489. int i, j, type, size, out_len;
  5490. if (out_args == NULL)
  5491. return;
  5492. out_len = mono_array_length (out_args);
  5493. if (out_len == 0)
  5494. return;
  5495. for (i = 0, j = 0; i < sig->param_count; i++) {
  5496. MonoType *pt = sig->params [i];
  5497. if (pt->byref) {
  5498. char *arg;
  5499. if (j >= out_len)
  5500. mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
  5501. arg = mono_array_get (out_args, gpointer, j);
  5502. type = pt->type;
  5503. g_assert (type != MONO_TYPE_VOID);
  5504. if (MONO_TYPE_IS_REFERENCE (pt)) {
  5505. mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
  5506. } else {
  5507. if (arg) {
  5508. MonoClass *class = ((MonoObject*)arg)->vtable->klass;
  5509. size = mono_class_value_size (class, NULL);
  5510. if (class->has_references)
  5511. mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
  5512. else
  5513. mono_gc_memmove (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
  5514. } else {
  5515. size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
  5516. mono_gc_bzero (*((gpointer *)params [i]), size);
  5517. }
  5518. }
  5519. j++;
  5520. }
  5521. }
  5522. }
  5523. #ifndef DISABLE_REMOTING
  5524. /**
  5525. * mono_load_remote_field:
  5526. * @this: pointer to an object
  5527. * @klass: klass of the object containing @field
  5528. * @field: the field to load
  5529. * @res: a storage to store the result
  5530. *
  5531. * This method is called by the runtime on attempts to load fields of
  5532. * transparent proxy objects. @this points to such TP, @klass is the class of
  5533. * the object containing @field. @res is a storage location which can be
  5534. * used to store the result.
  5535. *
  5536. * Returns: an address pointing to the value of field.
  5537. */
  5538. gpointer
  5539. mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
  5540. {
  5541. static MonoMethod *getter = NULL;
  5542. MonoDomain *domain = mono_domain_get ();
  5543. MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
  5544. MonoClass *field_class;
  5545. MonoMethodMessage *msg;
  5546. MonoArray *out_args;
  5547. MonoObject *exc;
  5548. char* full_name;
  5549. g_assert (mono_object_is_transparent_proxy (this));
  5550. g_assert (res != NULL);
  5551. if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
  5552. mono_field_get_value (tp->rp->unwrapped_server, field, res);
  5553. return res;
  5554. }
  5555. if (!getter) {
  5556. getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
  5557. g_assert (getter);
  5558. }
  5559. field_class = mono_class_from_mono_type (field->type);
  5560. msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
  5561. out_args = mono_array_new (domain, mono_defaults.object_class, 1);
  5562. mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
  5563. full_name = mono_type_get_full_name (klass);
  5564. mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
  5565. mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
  5566. g_free (full_name);
  5567. mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
  5568. if (exc) mono_raise_exception ((MonoException *)exc);
  5569. if (mono_array_length (out_args) == 0)
  5570. return NULL;
  5571. *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
  5572. if (field_class->valuetype) {
  5573. return ((char *)*res) + sizeof (MonoObject);
  5574. } else
  5575. return res;
  5576. }
  5577. /**
  5578. * mono_load_remote_field_new:
  5579. * @this:
  5580. * @klass:
  5581. * @field:
  5582. *
  5583. * Missing documentation.
  5584. */
  5585. MonoObject *
  5586. mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
  5587. {
  5588. static MonoMethod *getter = NULL;
  5589. MonoDomain *domain = mono_domain_get ();
  5590. MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
  5591. MonoClass *field_class;
  5592. MonoMethodMessage *msg;
  5593. MonoArray *out_args;
  5594. MonoObject *exc, *res;
  5595. char* full_name;
  5596. g_assert (mono_object_is_transparent_proxy (this));
  5597. field_class = mono_class_from_mono_type (field->type);
  5598. if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
  5599. gpointer val;
  5600. if (field_class->valuetype) {
  5601. res = mono_object_new (domain, field_class);
  5602. val = ((gchar *) res) + sizeof (MonoObject);
  5603. } else {
  5604. val = &res;
  5605. }
  5606. mono_field_get_value (tp->rp->unwrapped_server, field, val);
  5607. return res;
  5608. }
  5609. if (!getter) {
  5610. getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
  5611. g_assert (getter);
  5612. }
  5613. msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
  5614. out_args = mono_array_new (domain, mono_defaults.object_class, 1);
  5615. mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
  5616. full_name = mono_type_get_full_name (klass);
  5617. mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
  5618. mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
  5619. g_free (full_name);
  5620. mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
  5621. if (exc) mono_raise_exception ((MonoException *)exc);
  5622. if (mono_array_length (out_args) == 0)
  5623. res = NULL;
  5624. else
  5625. res = mono_array_get (out_args, MonoObject *, 0);
  5626. return res;
  5627. }
  5628. /**
  5629. * mono_store_remote_field:
  5630. * @this: pointer to an object
  5631. * @klass: klass of the object containing @field
  5632. * @field: the field to load
  5633. * @val: the value/object to store
  5634. *
  5635. * This method is called by the runtime on attempts to store fields of
  5636. * transparent proxy objects. @this points to such TP, @klass is the class of
  5637. * the object containing @field. @val is the new value to store in @field.
  5638. */
  5639. void
  5640. mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
  5641. {
  5642. static MonoMethod *setter = NULL;
  5643. MonoDomain *domain = mono_domain_get ();
  5644. MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
  5645. MonoClass *field_class;
  5646. MonoMethodMessage *msg;
  5647. MonoArray *out_args;
  5648. MonoObject *exc;
  5649. MonoObject *arg;
  5650. char* full_name;
  5651. g_assert (mono_object_is_transparent_proxy (this));
  5652. field_class = mono_class_from_mono_type (field->type);
  5653. if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
  5654. if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
  5655. else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
  5656. return;
  5657. }
  5658. if (!setter) {
  5659. setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
  5660. g_assert (setter);
  5661. }
  5662. if (field_class->valuetype)
  5663. arg = mono_value_box (domain, field_class, val);
  5664. else
  5665. arg = *((MonoObject **)val);
  5666. msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
  5667. mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
  5668. full_name = mono_type_get_full_name (klass);
  5669. mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
  5670. mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
  5671. mono_array_setref (msg->args, 2, arg);
  5672. g_free (full_name);
  5673. mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
  5674. if (exc) mono_raise_exception ((MonoException *)exc);
  5675. }
  5676. /**
  5677. * mono_store_remote_field_new:
  5678. * @this:
  5679. * @klass:
  5680. * @field:
  5681. * @arg:
  5682. *
  5683. * Missing documentation
  5684. */
  5685. void
  5686. mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
  5687. {
  5688. static MonoMethod *setter = NULL;
  5689. MonoDomain *domain = mono_domain_get ();
  5690. MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
  5691. MonoClass *field_class;
  5692. MonoMethodMessage *msg;
  5693. MonoArray *out_args;
  5694. MonoObject *exc;
  5695. char* full_name;
  5696. g_assert (mono_object_is_transparent_proxy (this));
  5697. field_class = mono_class_from_mono_type (field->type);
  5698. if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
  5699. if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
  5700. else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
  5701. return;
  5702. }
  5703. if (!setter) {
  5704. setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
  5705. g_assert (setter);
  5706. }
  5707. msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
  5708. mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
  5709. full_name = mono_type_get_full_name (klass);
  5710. mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
  5711. mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
  5712. mono_array_setref (msg->args, 2, arg);
  5713. g_free (full_name);
  5714. mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
  5715. if (exc) mono_raise_exception ((MonoException *)exc);
  5716. }
  5717. #endif
  5718. /*
  5719. * mono_create_ftnptr:
  5720. *
  5721. * Given a function address, create a function descriptor for it.
  5722. * This is only needed on some platforms.
  5723. */
  5724. gpointer
  5725. mono_create_ftnptr (MonoDomain *domain, gpointer addr)
  5726. {
  5727. return callbacks.create_ftnptr (domain, addr);
  5728. }
  5729. /*
  5730. * mono_get_addr_from_ftnptr:
  5731. *
  5732. * Given a pointer to a function descriptor, return the function address.
  5733. * This is only needed on some platforms.
  5734. */
  5735. gpointer
  5736. mono_get_addr_from_ftnptr (gpointer descr)
  5737. {
  5738. return callbacks.get_addr_from_ftnptr (descr);
  5739. }
  5740. /**
  5741. * mono_string_chars:
  5742. * @s: a MonoString
  5743. *
  5744. * Returns a pointer to the UCS16 characters stored in the MonoString
  5745. */
  5746. gunichar2 *
  5747. mono_string_chars (MonoString *s)
  5748. {
  5749. return s->chars;
  5750. }
  5751. /**
  5752. * mono_string_length:
  5753. * @s: MonoString
  5754. *
  5755. * Returns the lenght in characters of the string
  5756. */
  5757. int
  5758. mono_string_length (MonoString *s)
  5759. {
  5760. return s->length;
  5761. }
  5762. /**
  5763. * mono_array_length:
  5764. * @array: a MonoArray*
  5765. *
  5766. * Returns the total number of elements in the array. This works for
  5767. * both vectors and multidimensional arrays.
  5768. */
  5769. uintptr_t
  5770. mono_array_length (MonoArray *array)
  5771. {
  5772. return array->max_length;
  5773. }
  5774. /**
  5775. * mono_array_addr_with_size:
  5776. * @array: a MonoArray*
  5777. * @size: size of the array elements
  5778. * @idx: index into the array
  5779. *
  5780. * Returns the address of the @idx element in the array.
  5781. */
  5782. char*
  5783. mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
  5784. {
  5785. return ((char*)(array)->vector) + size * idx;
  5786. }