1 /**
2 * \file
3 * Object creation for the Mono runtime
4 *
5 * Author:
6 * Miguel de Icaza (miguel@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
8 *
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
11 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13 */
14 #include <config.h>
15 #ifdef HAVE_ALLOCA_H
16 #include <alloca.h>
17 #endif
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <mono/metadata/mono-endian.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/tokentype.h>
24 #include <mono/metadata/loader.h>
25 #include <mono/metadata/object.h>
26 #include <mono/metadata/gc-internals.h>
27 #include <mono/metadata/exception.h>
28 #include <mono/metadata/exception-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include "mono/metadata/metadata-internals.h"
31 #include "mono/metadata/class-internals.h"
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/marshal.h>
34 #include "mono/metadata/debug-helpers.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/verify-internals.h>
41 #include <mono/metadata/reflection-internals.h>
42 #include <mono/metadata/w32event.h>
43 #include <mono/metadata/custom-attrs-internals.h>
44 #include <mono/utils/strenc.h>
45 #include <mono/utils/mono-counters.h>
46 #include <mono/utils/mono-error-internals.h>
47 #include <mono/utils/mono-memory-model.h>
48 #include <mono/utils/checked-build.h>
49 #include <mono/utils/mono-threads.h>
50 #include <mono/utils/mono-threads-coop.h>
51 #include <mono/utils/mono-logger-internals.h>
52 #include "cominterop.h"
53 #include <mono/utils/w32api.h>
54 #include <mono/utils/unlocked.h>
55
56 static void
57 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
58
59 static MonoString*
60 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
61
62 static void
63 free_main_args (void);
64
65 static char *
66 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
67
68 static void
69 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
70
71 static MonoMethod*
72 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
73
74 /* Class lazy loading functions */
75 static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
76 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
77 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
78 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
79 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
80
81
82 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
83 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
84 static mono_mutex_t ldstr_section;
85
86
87 /**
88 * mono_runtime_object_init:
89 * \param this_obj the object to initialize
90 * This function calls the zero-argument constructor (which must
91 * exist) for the given object.
92 */
93 void
mono_runtime_object_init(MonoObject * this_obj)94 mono_runtime_object_init (MonoObject *this_obj)
95 {
96 MonoError error;
97 mono_runtime_object_init_checked (this_obj, &error);
98 mono_error_assert_ok (&error);
99 }
100
101 /**
102 * mono_runtime_object_init_checked:
103 * \param this_obj the object to initialize
104 * \param error set on error.
105 * This function calls the zero-argument constructor (which must
106 * exist) for the given object and returns TRUE on success, or FALSE
107 * on error and sets \p error.
108 */
109 gboolean
mono_runtime_object_init_checked(MonoObject * this_obj,MonoError * error)110 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
111 {
112 MONO_REQ_GC_UNSAFE_MODE;
113
114 MonoMethod *method = NULL;
115 MonoClass *klass = this_obj->vtable->klass;
116
117 error_init (error);
118 method = mono_class_get_method_from_name (klass, ".ctor", 0);
119 if (!method)
120 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
121
122 if (method->klass->valuetype)
123 this_obj = (MonoObject *)mono_object_unbox (this_obj);
124
125 mono_runtime_invoke_checked (method, this_obj, NULL, error);
126 return is_ok (error);
127 }
128
129 /* The pseudo algorithm for type initialization from the spec
130 Note it doesn't say anything about domains - only threads.
131
132 2. If the type is initialized you are done.
133 2.1. If the type is not yet initialized, try to take an
134 initialization lock.
135 2.2. If successful, record this thread as responsible for
136 initializing the type and proceed to step 2.3.
137 2.2.1. If not, see whether this thread or any thread
138 waiting for this thread to complete already holds the lock.
139 2.2.2. If so, return since blocking would create a deadlock. This thread
140 will now see an incompletely initialized state for the type,
141 but no deadlock will arise.
142 2.2.3 If not, block until the type is initialized then return.
143 2.3 Initialize the parent type and then all interfaces implemented
144 by this type.
145 2.4 Execute the type initialization code for this type.
146 2.5 Mark the type as initialized, release the initialization lock,
147 awaken any threads waiting for this type to be initialized,
148 and return.
149
150 */
151
152 typedef struct
153 {
154 MonoNativeThreadId initializing_tid;
155 guint32 waiting_count;
156 gboolean done;
157 MonoCoopMutex mutex;
158 /* condvar used to wait for 'done' becoming TRUE */
159 MonoCoopCond cond;
160 } TypeInitializationLock;
161
162 /* for locking access to type_initialization_hash and blocked_thread_hash */
163 static MonoCoopMutex type_initialization_section;
164
165 static inline void
mono_type_initialization_lock(void)166 mono_type_initialization_lock (void)
167 {
168 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
169 mono_coop_mutex_lock (&type_initialization_section);
170 }
171
172 static inline void
mono_type_initialization_unlock(void)173 mono_type_initialization_unlock (void)
174 {
175 mono_coop_mutex_unlock (&type_initialization_section);
176 }
177
178 static void
mono_type_init_lock(TypeInitializationLock * lock)179 mono_type_init_lock (TypeInitializationLock *lock)
180 {
181 MONO_REQ_GC_NEUTRAL_MODE;
182
183 mono_coop_mutex_lock (&lock->mutex);
184 }
185
186 static void
mono_type_init_unlock(TypeInitializationLock * lock)187 mono_type_init_unlock (TypeInitializationLock *lock)
188 {
189 mono_coop_mutex_unlock (&lock->mutex);
190 }
191
192 /* from vtable to lock */
193 static GHashTable *type_initialization_hash;
194
195 /* from thread id to thread id being waited on */
196 static GHashTable *blocked_thread_hash;
197
198 /* Main thread */
199 static MonoThread *main_thread;
200
201 /* Functions supplied by the runtime */
202 static MonoRuntimeCallbacks callbacks;
203
204 /**
205 * mono_thread_set_main:
206 * \param thread thread to set as the main thread
207 * This function can be used to instruct the runtime to treat \p thread
208 * as the main thread, ie, the thread that would normally execute the \c Main
209 * method. This basically means that at the end of \p thread, the runtime will
210 * wait for the existing foreground threads to quit and other such details.
211 */
212 void
mono_thread_set_main(MonoThread * thread)213 mono_thread_set_main (MonoThread *thread)
214 {
215 MONO_REQ_GC_UNSAFE_MODE;
216
217 static gboolean registered = FALSE;
218
219 if (!registered) {
220 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
221 registered = TRUE;
222 }
223
224 main_thread = thread;
225 }
226
227 /**
228 * mono_thread_get_main:
229 */
230 MonoThread*
mono_thread_get_main(void)231 mono_thread_get_main (void)
232 {
233 MONO_REQ_GC_UNSAFE_MODE;
234
235 return main_thread;
236 }
237
238 void
mono_type_initialization_init(void)239 mono_type_initialization_init (void)
240 {
241 mono_coop_mutex_init_recursive (&type_initialization_section);
242 type_initialization_hash = g_hash_table_new (NULL, NULL);
243 blocked_thread_hash = g_hash_table_new (NULL, NULL);
244 mono_os_mutex_init_recursive (&ldstr_section);
245 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
246 }
247
248 void
mono_type_initialization_cleanup(void)249 mono_type_initialization_cleanup (void)
250 {
251 #if 0
252 /* This is causing race conditions with
253 * mono_release_type_locks
254 */
255 mono_coop_mutex_destroy (&type_initialization_section);
256 g_hash_table_destroy (type_initialization_hash);
257 type_initialization_hash = NULL;
258 #endif
259 mono_os_mutex_destroy (&ldstr_section);
260 g_hash_table_destroy (blocked_thread_hash);
261 blocked_thread_hash = NULL;
262
263 free_main_args ();
264 }
265
266 /**
267 * get_type_init_exception_for_vtable:
268 *
269 * Return the stored type initialization exception for VTABLE.
270 */
271 static MonoException*
get_type_init_exception_for_vtable(MonoVTable * vtable)272 get_type_init_exception_for_vtable (MonoVTable *vtable)
273 {
274 MONO_REQ_GC_UNSAFE_MODE;
275
276 MonoError error;
277 MonoDomain *domain = vtable->domain;
278 MonoClass *klass = vtable->klass;
279 MonoException *ex;
280 gchar *full_name;
281
282 if (!vtable->init_failed)
283 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
284
285 /*
286 * If the initializing thread was rudely aborted, the exception is not stored
287 * in the hash.
288 */
289 ex = NULL;
290 mono_domain_lock (domain);
291 if (domain->type_init_exception_hash)
292 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
293 mono_domain_unlock (domain);
294
295 if (!ex) {
296 if (klass->name_space && *klass->name_space)
297 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
298 else
299 full_name = g_strdup (klass->name);
300 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
301 g_free (full_name);
302 return_val_if_nok (&error, NULL);
303 }
304
305 return ex;
306 }
307
308 /**
309 * mono_runtime_class_init:
310 * \param vtable vtable that needs to be initialized
311 * This routine calls the class constructor for \p vtable.
312 */
313 void
mono_runtime_class_init(MonoVTable * vtable)314 mono_runtime_class_init (MonoVTable *vtable)
315 {
316 MONO_REQ_GC_UNSAFE_MODE;
317 MonoError error;
318
319 mono_runtime_class_init_full (vtable, &error);
320 mono_error_assert_ok (&error);
321 }
322
323 /*
324 * Returns TRUE if the lock was freed.
325 * LOCKING: Caller should hold type_initialization_lock.
326 */
327 static gboolean
unref_type_lock(TypeInitializationLock * lock)328 unref_type_lock (TypeInitializationLock *lock)
329 {
330 --lock->waiting_count;
331 if (lock->waiting_count == 0) {
332 mono_coop_mutex_destroy (&lock->mutex);
333 mono_coop_cond_destroy (&lock->cond);
334 g_free (lock);
335 return TRUE;
336 } else {
337 return FALSE;
338 }
339 }
340
341 /**
342 * mono_runtime_class_init_full:
343 * \param vtable that neeeds to be initialized
344 * \param error set on error
345 * \returns TRUE if class constructor \c .cctor has been initialized successfully, or FALSE otherwise and sets \p error.
346 */
347 gboolean
mono_runtime_class_init_full(MonoVTable * vtable,MonoError * error)348 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
349 {
350 MONO_REQ_GC_UNSAFE_MODE;
351
352 MonoMethod *method = NULL;
353 MonoClass *klass;
354 gchar *full_name;
355 MonoDomain *domain = vtable->domain;
356 TypeInitializationLock *lock;
357 MonoNativeThreadId tid;
358 int do_initialization = 0;
359 MonoDomain *last_domain = NULL;
360 gboolean pending_tae = FALSE;
361
362 error_init (error);
363
364 if (vtable->initialized)
365 return TRUE;
366
367 klass = vtable->klass;
368
369 if (!klass->image->checked_module_cctor) {
370 mono_image_check_for_module_cctor (klass->image);
371 if (klass->image->has_module_cctor) {
372 MonoClass *module_klass;
373 MonoVTable *module_vtable;
374
375 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
376 if (!module_klass) {
377 return FALSE;
378 }
379
380 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
381 if (!module_vtable)
382 return FALSE;
383 if (!mono_runtime_class_init_full (module_vtable, error))
384 return FALSE;
385 }
386 }
387 method = mono_class_get_cctor (klass);
388 if (!method) {
389 vtable->initialized = 1;
390 return TRUE;
391 }
392
393 tid = mono_native_thread_id_get ();
394
395 /*
396 * Due some preprocessing inside a global lock. If we are the first thread
397 * trying to initialize this class, create a separate lock+cond var, and
398 * acquire it before leaving the global lock. The other threads will wait
399 * on this cond var.
400 */
401
402 mono_type_initialization_lock ();
403 /* double check... */
404 if (vtable->initialized) {
405 mono_type_initialization_unlock ();
406 return TRUE;
407 }
408 if (vtable->init_failed) {
409 mono_type_initialization_unlock ();
410
411 /* The type initialization already failed once, rethrow the same exception */
412 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
413 return FALSE;
414 }
415 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
416 if (lock == NULL) {
417 /* This thread will get to do the initialization */
418 if (mono_domain_get () != domain) {
419 /* Transfer into the target domain */
420 last_domain = mono_domain_get ();
421 if (!mono_domain_set (domain, FALSE)) {
422 vtable->initialized = 1;
423 mono_type_initialization_unlock ();
424 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
425 return FALSE;
426 }
427 }
428 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
429 mono_coop_mutex_init_recursive (&lock->mutex);
430 mono_coop_cond_init (&lock->cond);
431 lock->initializing_tid = tid;
432 lock->waiting_count = 1;
433 lock->done = FALSE;
434 g_hash_table_insert (type_initialization_hash, vtable, lock);
435 do_initialization = 1;
436 } else {
437 gpointer blocked;
438 TypeInitializationLock *pending_lock;
439
440 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
441 mono_type_initialization_unlock ();
442 return TRUE;
443 }
444 /* see if the thread doing the initialization is already blocked on this thread */
445 gboolean is_blocked = TRUE;
446 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
447 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
448 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
449 if (!pending_lock->done) {
450 mono_type_initialization_unlock ();
451 return TRUE;
452 } else {
453 /* the thread doing the initialization is blocked on this thread,
454 but on a lock that has already been freed. It just hasn't got
455 time to awake */
456 is_blocked = FALSE;
457 break;
458 }
459 }
460 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
461 }
462 ++lock->waiting_count;
463 /* record the fact that we are waiting on the initializing thread */
464 if (is_blocked)
465 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
466 }
467 mono_type_initialization_unlock ();
468
469 if (do_initialization) {
470 MonoException *exc = NULL;
471
472 /* We are holding the per-vtable lock, do the actual initialization */
473
474 mono_threads_begin_abort_protected_block ();
475 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
476 mono_threads_end_abort_protected_block ();
477
478 //exception extracted, error will be set to the right value later
479 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
480 exc = mono_error_convert_to_exception (error);
481 else
482 mono_error_cleanup (error);
483
484 error_init (error);
485
486 /* If the initialization failed, mark the class as unusable. */
487 /* Avoid infinite loops */
488 if (!(!exc ||
489 (klass->image == mono_defaults.corlib &&
490 !strcmp (klass->name_space, "System") &&
491 !strcmp (klass->name, "TypeInitializationException")))) {
492 vtable->init_failed = 1;
493
494 if (klass->name_space && *klass->name_space)
495 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
496 else
497 full_name = g_strdup (klass->name);
498
499 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
500 g_free (full_name);
501
502 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
503
504 /*
505 * Store the exception object so it could be thrown on subsequent
506 * accesses.
507 */
508 mono_domain_lock (domain);
509 if (!domain->type_init_exception_hash)
510 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "type initialization exceptions table");
511 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
512 mono_domain_unlock (domain);
513 }
514
515 if (last_domain)
516 mono_domain_set (last_domain, TRUE);
517
518 /* Signal to the other threads that we are done */
519 mono_type_init_lock (lock);
520 lock->done = TRUE;
521 mono_coop_cond_broadcast (&lock->cond);
522 mono_type_init_unlock (lock);
523
524 /*
525 * This can happen if the cctor self-aborts. We need to reactivate tae
526 * (next interruption checkpoint will throw it) and make sure we won't
527 * throw tie for the type.
528 */
529 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class) {
530 pending_tae = TRUE;
531 mono_thread_resume_interruption (FALSE);
532 }
533 } else {
534 /* this just blocks until the initializing thread is done */
535 mono_type_init_lock (lock);
536 while (!lock->done)
537 mono_coop_cond_wait (&lock->cond, &lock->mutex);
538 mono_type_init_unlock (lock);
539 }
540
541 /* Do cleanup and setting vtable->initialized inside the global lock again */
542 mono_type_initialization_lock ();
543 if (!do_initialization)
544 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
545 gboolean deleted = unref_type_lock (lock);
546 if (deleted)
547 g_hash_table_remove (type_initialization_hash, vtable);
548 /* Have to set this here since we check it inside the global lock */
549 if (do_initialization && !vtable->init_failed)
550 vtable->initialized = 1;
551 mono_type_initialization_unlock ();
552
553 /* If vtable init fails because of TAE, we don't throw TIE, only the TAE */
554 if (vtable->init_failed && !pending_tae) {
555 /* Either we were the initializing thread or we waited for the initialization */
556 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
557 return FALSE;
558 }
559 return TRUE;
560 }
561
562 static
release_type_locks(gpointer key,gpointer value,gpointer user)563 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
564 {
565 MONO_REQ_GC_NEUTRAL_MODE;
566
567 MonoVTable *vtable = (MonoVTable*)key;
568
569 TypeInitializationLock *lock = (TypeInitializationLock*) value;
570 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
571 lock->done = TRUE;
572 /*
573 * Have to set this since it cannot be set by the normal code in
574 * mono_runtime_class_init (). In this case, the exception object is not stored,
575 * and get_type_init_exception_for_class () needs to be aware of this.
576 */
577 mono_type_init_lock (lock);
578 vtable->init_failed = 1;
579 mono_coop_cond_broadcast (&lock->cond);
580 mono_type_init_unlock (lock);
581 gboolean deleted = unref_type_lock (lock);
582 if (deleted)
583 return TRUE;
584 }
585 return FALSE;
586 }
587
588 void
mono_release_type_locks(MonoInternalThread * thread)589 mono_release_type_locks (MonoInternalThread *thread)
590 {
591 MONO_REQ_GC_UNSAFE_MODE;
592
593 mono_type_initialization_lock ();
594 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
595 mono_type_initialization_unlock ();
596 }
597
598 #ifndef DISABLE_REMOTING
599
600 static gpointer
create_remoting_trampoline(MonoDomain * domain,MonoMethod * method,MonoRemotingTarget target,MonoError * error)601 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
602 {
603 if (!callbacks.create_remoting_trampoline)
604 g_error ("remoting not installed");
605 return callbacks.create_remoting_trampoline (domain, method, target, error);
606 }
607
608 #endif
609
610 static MonoImtTrampolineBuilder imt_trampoline_builder;
611 static gboolean always_build_imt_trampolines;
612
613 #if (MONO_IMT_SIZE > 32)
614 #error "MONO_IMT_SIZE cannot be larger than 32"
615 #endif
616
617 void
mono_install_callbacks(MonoRuntimeCallbacks * cbs)618 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
619 {
620 memcpy (&callbacks, cbs, sizeof (*cbs));
621 }
622
623 MonoRuntimeCallbacks*
mono_get_runtime_callbacks(void)624 mono_get_runtime_callbacks (void)
625 {
626 return &callbacks;
627 }
628
629 void
mono_install_imt_trampoline_builder(MonoImtTrampolineBuilder func)630 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
631 {
632 imt_trampoline_builder = func;
633 }
634
635 void
mono_set_always_build_imt_trampolines(gboolean value)636 mono_set_always_build_imt_trampolines (gboolean value)
637 {
638 always_build_imt_trampolines = value;
639 }
640
641 /**
642 * mono_compile_method:
643 * \param method The method to compile.
644 * This JIT-compiles the method, and returns the pointer to the native code
645 * produced.
646 */
647 gpointer
mono_compile_method(MonoMethod * method)648 mono_compile_method (MonoMethod *method)
649 {
650 MonoError error;
651 gpointer result = mono_compile_method_checked (method, &error);
652 mono_error_cleanup (&error);
653 return result;
654 }
655
656 /**
657 * mono_compile_method_checked:
658 * \param method The method to compile.
659 * \param error set on error.
660 * This JIT-compiles the method, and returns the pointer to the native code
661 * produced. On failure returns NULL and sets \p error.
662 */
663 gpointer
mono_compile_method_checked(MonoMethod * method,MonoError * error)664 mono_compile_method_checked (MonoMethod *method, MonoError *error)
665 {
666 gpointer res;
667
668 MONO_REQ_GC_NEUTRAL_MODE
669
670 error_init (error);
671
672 g_assert (callbacks.compile_method);
673 res = callbacks.compile_method (method, error);
674 return res;
675 }
676
677 gpointer
mono_runtime_create_jump_trampoline(MonoDomain * domain,MonoMethod * method,gboolean add_sync_wrapper,MonoError * error)678 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
679 {
680 gpointer res;
681
682 MONO_REQ_GC_NEUTRAL_MODE;
683
684 error_init (error);
685 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
686 return res;
687 }
688
689 gpointer
mono_runtime_create_delegate_trampoline(MonoClass * klass)690 mono_runtime_create_delegate_trampoline (MonoClass *klass)
691 {
692 MONO_REQ_GC_NEUTRAL_MODE
693
694 g_assert (callbacks.create_delegate_trampoline);
695 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
696 }
697
698 /**
699 * mono_runtime_free_method:
700 * \param domain domain where the method is hosted
701 * \param method method to release
702 * This routine is invoked to free the resources associated with
703 * a method that has been JIT compiled. This is used to discard
704 * methods that were used only temporarily (for example, used in marshalling)
705 */
706 void
mono_runtime_free_method(MonoDomain * domain,MonoMethod * method)707 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
708 {
709 MONO_REQ_GC_NEUTRAL_MODE
710
711 if (callbacks.free_method)
712 callbacks.free_method (domain, method);
713
714 mono_method_clear_object (domain, method);
715
716 mono_free_method (method);
717 }
718
719 /*
720 * The vtables in the root appdomain are assumed to be reachable by other
721 * roots, and we don't use typed allocation in the other domains.
722 */
723
724 /* The sync block is no longer a GC pointer */
725 #define GC_HEADER_BITMAP (0)
726
727 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
728
729 static gsize*
compute_class_bitmap(MonoClass * klass,gsize * bitmap,int size,int offset,int * max_set,gboolean static_fields)730 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
731 {
732 MONO_REQ_GC_NEUTRAL_MODE;
733
734 MonoClassField *field;
735 MonoClass *p;
736 guint32 pos;
737 int max_size;
738
739 if (static_fields)
740 max_size = mono_class_data_size (klass) / sizeof (gpointer);
741 else
742 max_size = klass->instance_size / sizeof (gpointer);
743 if (max_size > size) {
744 g_assert (offset <= 0);
745 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
746 size = max_size;
747 }
748
749 /* An Ephemeron cannot be marked by sgen */
750 if (mono_gc_is_moving () && !static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
751 *max_set = 0;
752 memset (bitmap, 0, size / 8);
753 return bitmap;
754 }
755
756 for (p = klass; p != NULL; p = p->parent) {
757 gpointer iter = NULL;
758 while ((field = mono_class_get_fields (p, &iter))) {
759 MonoType *type;
760
761 if (static_fields) {
762 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
763 continue;
764 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
765 continue;
766 } else {
767 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
768 continue;
769 }
770 /* FIXME: should not happen, flag as type load error */
771 if (field->type->byref)
772 break;
773
774 if (static_fields && field->offset == -1)
775 /* special static */
776 continue;
777
778 pos = field->offset / sizeof (gpointer);
779 pos += offset;
780
781 type = mono_type_get_underlying_type (field->type);
782 switch (type->type) {
783 case MONO_TYPE_U:
784 case MONO_TYPE_I:
785 case MONO_TYPE_PTR:
786 case MONO_TYPE_FNPTR:
787 break;
788 case MONO_TYPE_STRING:
789 case MONO_TYPE_SZARRAY:
790 case MONO_TYPE_CLASS:
791 case MONO_TYPE_OBJECT:
792 case MONO_TYPE_ARRAY:
793 g_assert ((field->offset % sizeof(gpointer)) == 0);
794
795 g_assert (pos < size || pos <= max_size);
796 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
797 *max_set = MAX (*max_set, pos);
798 break;
799 case MONO_TYPE_GENERICINST:
800 if (!mono_type_generic_inst_is_valuetype (type)) {
801 g_assert ((field->offset % sizeof(gpointer)) == 0);
802
803 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
804 *max_set = MAX (*max_set, pos);
805 break;
806 } else {
807 /* fall through */
808 }
809 case MONO_TYPE_VALUETYPE: {
810 MonoClass *fclass = mono_class_from_mono_type (field->type);
811 if (fclass->has_references) {
812 /* remove the object header */
813 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
814 }
815 break;
816 }
817 case MONO_TYPE_I1:
818 case MONO_TYPE_U1:
819 case MONO_TYPE_I2:
820 case MONO_TYPE_U2:
821 case MONO_TYPE_I4:
822 case MONO_TYPE_U4:
823 case MONO_TYPE_I8:
824 case MONO_TYPE_U8:
825 case MONO_TYPE_R4:
826 case MONO_TYPE_R8:
827 case MONO_TYPE_BOOLEAN:
828 case MONO_TYPE_CHAR:
829 break;
830 default:
831 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
832 break;
833 }
834 }
835 if (static_fields)
836 break;
837 }
838 return bitmap;
839 }
840
841 /**
842 * mono_class_compute_bitmap:
843 *
844 * Mono internal function to compute a bitmap of reference fields in a class.
845 */
846 gsize*
mono_class_compute_bitmap(MonoClass * klass,gsize * bitmap,int size,int offset,int * max_set,gboolean static_fields)847 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
848 {
849 MONO_REQ_GC_NEUTRAL_MODE;
850
851 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
852 }
853
854 #if 0
855 /*
856 * similar to the above, but sets the bits in the bitmap for any non-ref field
857 * and ignores static fields
858 */
859 static gsize*
860 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
861 {
862 MonoClassField *field;
863 MonoClass *p;
864 guint32 pos, pos2;
865 int max_size;
866
867 max_size = class->instance_size / sizeof (gpointer);
868 if (max_size >= size) {
869 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
870 }
871
872 for (p = class; p != NULL; p = p->parent) {
873 gpointer iter = NULL;
874 while ((field = mono_class_get_fields (p, &iter))) {
875 MonoType *type;
876
877 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
878 continue;
879 /* FIXME: should not happen, flag as type load error */
880 if (field->type->byref)
881 break;
882
883 pos = field->offset / sizeof (gpointer);
884 pos += offset;
885
886 type = mono_type_get_underlying_type (field->type);
887 switch (type->type) {
888 #if SIZEOF_VOID_P == 8
889 case MONO_TYPE_I:
890 case MONO_TYPE_U:
891 case MONO_TYPE_PTR:
892 case MONO_TYPE_FNPTR:
893 #endif
894 case MONO_TYPE_I8:
895 case MONO_TYPE_U8:
896 case MONO_TYPE_R8:
897 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
898 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
899 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
900 }
901 /* fall through */
902 #if SIZEOF_VOID_P == 4
903 case MONO_TYPE_I:
904 case MONO_TYPE_U:
905 case MONO_TYPE_PTR:
906 case MONO_TYPE_FNPTR:
907 #endif
908 case MONO_TYPE_I4:
909 case MONO_TYPE_U4:
910 case MONO_TYPE_R4:
911 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
912 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
913 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
914 }
915 /* fall through */
916 case MONO_TYPE_CHAR:
917 case MONO_TYPE_I2:
918 case MONO_TYPE_U2:
919 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
920 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
921 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
922 }
923 /* fall through */
924 case MONO_TYPE_BOOLEAN:
925 case MONO_TYPE_I1:
926 case MONO_TYPE_U1:
927 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
928 break;
929 case MONO_TYPE_STRING:
930 case MONO_TYPE_SZARRAY:
931 case MONO_TYPE_CLASS:
932 case MONO_TYPE_OBJECT:
933 case MONO_TYPE_ARRAY:
934 break;
935 case MONO_TYPE_GENERICINST:
936 if (!mono_type_generic_inst_is_valuetype (type)) {
937 break;
938 } else {
939 /* fall through */
940 }
941 case MONO_TYPE_VALUETYPE: {
942 MonoClass *fclass = mono_class_from_mono_type (field->type);
943 /* remove the object header */
944 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
945 break;
946 }
947 default:
948 g_assert_not_reached ();
949 break;
950 }
951 }
952 }
953 return bitmap;
954 }
955
956 /**
957 * mono_class_insecure_overlapping:
958 * check if a class with explicit layout has references and non-references
959 * fields overlapping.
960 *
961 * Returns: TRUE if it is insecure to load the type.
962 */
963 gboolean
964 mono_class_insecure_overlapping (MonoClass *klass)
965 {
966 int max_set = 0;
967 gsize *bitmap;
968 gsize default_bitmap [4] = {0};
969 gsize *nrbitmap;
970 gsize default_nrbitmap [4] = {0};
971 int i, insecure = FALSE;
972 return FALSE;
973
974 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
975 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
976
977 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
978 int idx = i % (sizeof (bitmap [0]) * 8);
979 if (bitmap [idx] & nrbitmap [idx]) {
980 insecure = TRUE;
981 break;
982 }
983 }
984 if (bitmap != default_bitmap)
985 g_free (bitmap);
986 if (nrbitmap != default_nrbitmap)
987 g_free (nrbitmap);
988 if (insecure) {
989 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
990 return FALSE;
991 }
992 return insecure;
993 }
994 #endif
995
996 MonoString*
ves_icall_string_alloc(int length)997 ves_icall_string_alloc (int length)
998 {
999 MonoError error;
1000 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
1001 mono_error_set_pending_exception (&error);
1002
1003 return str;
1004 }
1005
1006 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
1007
1008 /* LOCKING: Acquires the loader lock */
1009 /*
1010 * Sets the following fields in KLASS:
1011 * - gc_desc
1012 * - gc_descr_inited
1013 */
1014 void
mono_class_compute_gc_descriptor(MonoClass * klass)1015 mono_class_compute_gc_descriptor (MonoClass *klass)
1016 {
1017 MONO_REQ_GC_NEUTRAL_MODE;
1018
1019 int max_set = 0;
1020 gsize *bitmap;
1021 gsize default_bitmap [4] = {0};
1022 MonoGCDescriptor gc_descr;
1023
1024 if (!klass->inited)
1025 mono_class_init (klass);
1026
1027 if (klass->gc_descr_inited)
1028 return;
1029
1030 bitmap = default_bitmap;
1031 if (klass == mono_defaults.string_class) {
1032 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1033 } else if (klass->rank) {
1034 mono_class_compute_gc_descriptor (klass->element_class);
1035 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1036 gsize abm = 1;
1037 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1038 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1039 class->name_space, class->name);*/
1040 } else {
1041 /* remove the object header */
1042 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1043 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass));
1044 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1045 class->name_space, class->name);*/
1046 }
1047 } else {
1048 /*static int count = 0;
1049 if (count++ > 58)
1050 return;*/
1051 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1052 /*
1053 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1054 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1055 */
1056 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1057
1058 if (klass->has_weak_fields) {
1059 gsize *weak_bitmap = NULL;
1060 int weak_bitmap_nbits = 0;
1061
1062 weak_bitmap = (gsize *)mono_class_alloc0 (klass, klass->instance_size / sizeof (gsize));
1063 if (mono_class_has_static_metadata (klass)) {
1064 for (MonoClass *p = klass; p != NULL; p = p->parent) {
1065 gpointer iter = NULL;
1066 guint32 first_field_idx = mono_class_get_first_field_idx (p);
1067 MonoClassField *field;
1068
1069 while ((field = mono_class_get_fields (p, &iter))) {
1070 guint32 field_idx = first_field_idx + (field - p->fields);
1071 if (MONO_TYPE_IS_REFERENCE (field->type) && mono_assembly_is_weak_field (p->image, field_idx + 1)) {
1072 int pos = field->offset / sizeof (gpointer);
1073 if (pos + 1 > weak_bitmap_nbits)
1074 weak_bitmap_nbits = pos + 1;
1075 weak_bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
1076 }
1077 }
1078 }
1079 }
1080
1081 for (int pos = 0; pos < weak_bitmap_nbits; ++pos) {
1082 if (weak_bitmap [pos / BITMAP_EL_SIZE] & ((gsize)1) << (pos % BITMAP_EL_SIZE)) {
1083 /* Clear the normal bitmap so these refs don't keep an object alive */
1084 bitmap [pos / BITMAP_EL_SIZE] &= ~(((gsize)1) << (pos % BITMAP_EL_SIZE));
1085 }
1086 }
1087
1088 mono_loader_lock ();
1089 mono_class_set_weak_bitmap (klass, weak_bitmap_nbits, weak_bitmap);
1090 mono_loader_unlock ();
1091 }
1092
1093 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1094 }
1095
1096 if (bitmap != default_bitmap)
1097 g_free (bitmap);
1098
1099 /* Publish the data */
1100 mono_loader_lock ();
1101 klass->gc_descr = gc_descr;
1102 mono_memory_barrier ();
1103 klass->gc_descr_inited = TRUE;
1104 mono_loader_unlock ();
1105 }
1106
1107 /**
1108 * field_is_special_static:
1109 * @fklass: The MonoClass to look up.
1110 * @field: The MonoClassField describing the field.
1111 *
1112 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1113 * SPECIAL_STATIC_NONE otherwise.
1114 */
1115 static gint32
field_is_special_static(MonoClass * fklass,MonoClassField * field)1116 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1117 {
1118 MONO_REQ_GC_NEUTRAL_MODE;
1119
1120 MonoError error;
1121 MonoCustomAttrInfo *ainfo;
1122 int i;
1123 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1124 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1125 if (!ainfo)
1126 return FALSE;
1127 for (i = 0; i < ainfo->num_attrs; ++i) {
1128 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1129 if (klass->image == mono_defaults.corlib) {
1130 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1131 mono_custom_attrs_free (ainfo);
1132 return SPECIAL_STATIC_THREAD;
1133 }
1134 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1135 mono_custom_attrs_free (ainfo);
1136 return SPECIAL_STATIC_CONTEXT;
1137 }
1138 }
1139 }
1140 mono_custom_attrs_free (ainfo);
1141 return SPECIAL_STATIC_NONE;
1142 }
1143
1144 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1145 #define mix(a,b,c) { \
1146 a -= c; a ^= rot(c, 4); c += b; \
1147 b -= a; b ^= rot(a, 6); a += c; \
1148 c -= b; c ^= rot(b, 8); b += a; \
1149 a -= c; a ^= rot(c,16); c += b; \
1150 b -= a; b ^= rot(a,19); a += c; \
1151 c -= b; c ^= rot(b, 4); b += a; \
1152 }
1153 #define final(a,b,c) { \
1154 c ^= b; c -= rot(b,14); \
1155 a ^= c; a -= rot(c,11); \
1156 b ^= a; b -= rot(a,25); \
1157 c ^= b; c -= rot(b,16); \
1158 a ^= c; a -= rot(c,4); \
1159 b ^= a; b -= rot(a,14); \
1160 c ^= b; c -= rot(b,24); \
1161 }
1162
1163 /*
1164 * mono_method_get_imt_slot:
1165 *
1166 * The IMT slot is embedded into AOTed code, so this must return the same value
1167 * for the same method across all executions. This means:
1168 * - pointers shouldn't be used as hash values.
1169 * - mono_metadata_str_hash () should be used for hashing strings.
1170 */
1171 guint32
mono_method_get_imt_slot(MonoMethod * method)1172 mono_method_get_imt_slot (MonoMethod *method)
1173 {
1174 MONO_REQ_GC_NEUTRAL_MODE;
1175
1176 MonoMethodSignature *sig;
1177 int hashes_count;
1178 guint32 *hashes_start, *hashes;
1179 guint32 a, b, c;
1180 int i;
1181
1182 /* This can be used to stress tests the collision code */
1183 //return 0;
1184
1185 /*
1186 * We do this to simplify generic sharing. It will hurt
1187 * performance in cases where a class implements two different
1188 * instantiations of the same generic interface.
1189 * The code in build_imt_slots () depends on this.
1190 */
1191 if (method->is_inflated)
1192 method = ((MonoMethodInflated*)method)->declaring;
1193
1194 sig = mono_method_signature (method);
1195 hashes_count = sig->param_count + 4;
1196 hashes_start = (guint32 *)g_malloc (hashes_count * sizeof (guint32));
1197 hashes = hashes_start;
1198
1199 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1200 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1201 method->klass->name_space, method->klass->name, method->name);
1202 }
1203
1204 /* Initialize hashes */
1205 hashes [0] = mono_metadata_str_hash (method->klass->name);
1206 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1207 hashes [2] = mono_metadata_str_hash (method->name);
1208 hashes [3] = mono_metadata_type_hash (sig->ret);
1209 for (i = 0; i < sig->param_count; i++) {
1210 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1211 }
1212
1213 /* Setup internal state */
1214 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1215
1216 /* Handle most of the hashes */
1217 while (hashes_count > 3) {
1218 a += hashes [0];
1219 b += hashes [1];
1220 c += hashes [2];
1221 mix (a,b,c);
1222 hashes_count -= 3;
1223 hashes += 3;
1224 }
1225
1226 /* Handle the last 3 hashes (all the case statements fall through) */
1227 switch (hashes_count) {
1228 case 3 : c += hashes [2];
1229 case 2 : b += hashes [1];
1230 case 1 : a += hashes [0];
1231 final (a,b,c);
1232 case 0: /* nothing left to add */
1233 break;
1234 }
1235
1236 g_free (hashes_start);
1237 /* Report the result */
1238 return c % MONO_IMT_SIZE;
1239 }
1240 #undef rot
1241 #undef mix
1242 #undef final
1243
1244 #define DEBUG_IMT 0
1245
1246 static void
add_imt_builder_entry(MonoImtBuilderEntry ** imt_builder,MonoMethod * method,guint32 * imt_collisions_bitmap,int vtable_slot,int slot_num)1247 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1248 MONO_REQ_GC_NEUTRAL_MODE;
1249
1250 guint32 imt_slot = mono_method_get_imt_slot (method);
1251 MonoImtBuilderEntry *entry;
1252
1253 if (slot_num >= 0 && imt_slot != slot_num) {
1254 /* we build just a single imt slot and this is not it */
1255 return;
1256 }
1257
1258 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1259 entry->key = method;
1260 entry->value.vtable_slot = vtable_slot;
1261 entry->next = imt_builder [imt_slot];
1262 if (imt_builder [imt_slot] != NULL) {
1263 entry->children = imt_builder [imt_slot]->children + 1;
1264 if (entry->children == 1) {
1265 UnlockedIncrement (&mono_stats.imt_slots_with_collisions);
1266 *imt_collisions_bitmap |= (1 << imt_slot);
1267 }
1268 } else {
1269 entry->children = 0;
1270 UnlockedIncrement (&mono_stats.imt_used_slots);
1271 }
1272 imt_builder [imt_slot] = entry;
1273 #if DEBUG_IMT
1274 {
1275 char *method_name = mono_method_full_name (method, TRUE);
1276 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1277 method, method_name, imt_slot, vtable_slot, entry->children);
1278 g_free (method_name);
1279 }
1280 #endif
1281 }
1282
1283 #if DEBUG_IMT
1284 static void
print_imt_entry(const char * message,MonoImtBuilderEntry * e,int num)1285 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1286 if (e != NULL) {
1287 MonoMethod *method = e->key;
1288 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1289 message,
1290 num,
1291 method,
1292 method->klass->name_space,
1293 method->klass->name,
1294 method->name);
1295 } else {
1296 printf (" * %s: NULL\n", message);
1297 }
1298 }
1299 #endif
1300
1301 static int
compare_imt_builder_entries(const void * p1,const void * p2)1302 compare_imt_builder_entries (const void *p1, const void *p2) {
1303 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1304 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1305
1306 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1307 }
1308
1309 static int
imt_emit_ir(MonoImtBuilderEntry ** sorted_array,int start,int end,GPtrArray * out_array)1310 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1311 {
1312 MONO_REQ_GC_NEUTRAL_MODE;
1313
1314 int count = end - start;
1315 int chunk_start = out_array->len;
1316 if (count < 4) {
1317 int i;
1318 for (i = start; i < end; ++i) {
1319 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1320 item->key = sorted_array [i]->key;
1321 item->value = sorted_array [i]->value;
1322 item->has_target_code = sorted_array [i]->has_target_code;
1323 item->is_equals = TRUE;
1324 if (i < end - 1)
1325 item->check_target_idx = out_array->len + 1;
1326 else
1327 item->check_target_idx = 0;
1328 g_ptr_array_add (out_array, item);
1329 }
1330 } else {
1331 int middle = start + count / 2;
1332 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1333
1334 item->key = sorted_array [middle]->key;
1335 item->is_equals = FALSE;
1336 g_ptr_array_add (out_array, item);
1337 imt_emit_ir (sorted_array, start, middle, out_array);
1338 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1339 }
1340 return chunk_start;
1341 }
1342
1343 static GPtrArray*
imt_sort_slot_entries(MonoImtBuilderEntry * entries)1344 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1345 MONO_REQ_GC_NEUTRAL_MODE;
1346
1347 int number_of_entries = entries->children + 1;
1348 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)g_malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1349 GPtrArray *result = g_ptr_array_new ();
1350 MonoImtBuilderEntry *current_entry;
1351 int i;
1352
1353 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1354 sorted_array [i] = current_entry;
1355 }
1356 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1357
1358 /*for (i = 0; i < number_of_entries; i++) {
1359 print_imt_entry (" sorted array:", sorted_array [i], i);
1360 }*/
1361
1362 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1363
1364 g_free (sorted_array);
1365 return result;
1366 }
1367
1368 static gpointer
initialize_imt_slot(MonoVTable * vtable,MonoDomain * domain,MonoImtBuilderEntry * imt_builder_entry,gpointer fail_tramp)1369 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1370 {
1371 MONO_REQ_GC_NEUTRAL_MODE;
1372
1373 if (imt_builder_entry != NULL) {
1374 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1375 /* No collision, return the vtable slot contents */
1376 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1377 } else {
1378 /* Collision, build the trampoline */
1379 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1380 gpointer result;
1381 int i;
1382 result = imt_trampoline_builder (vtable, domain,
1383 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1384 for (i = 0; i < imt_ir->len; ++i)
1385 g_free (g_ptr_array_index (imt_ir, i));
1386 g_ptr_array_free (imt_ir, TRUE);
1387 return result;
1388 }
1389 } else {
1390 if (fail_tramp)
1391 return fail_tramp;
1392 else
1393 /* Empty slot */
1394 return NULL;
1395 }
1396 }
1397
1398 static MonoImtBuilderEntry*
1399 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1400
1401 /*
1402 * LOCKING: requires the loader and domain locks.
1403 *
1404 */
1405 static void
build_imt_slots(MonoClass * klass,MonoVTable * vt,MonoDomain * domain,gpointer * imt,GSList * extra_interfaces,int slot_num)1406 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1407 {
1408 MONO_REQ_GC_NEUTRAL_MODE;
1409
1410 int i;
1411 GSList *list_item;
1412 guint32 imt_collisions_bitmap = 0;
1413 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)g_calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1414 int method_count = 0;
1415 gboolean record_method_count_for_max_collisions = FALSE;
1416 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1417
1418 #if DEBUG_IMT
1419 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1420 #endif
1421 for (i = 0; i < klass->interface_offsets_count; ++i) {
1422 MonoClass *iface = klass->interfaces_packed [i];
1423 int interface_offset = klass->interface_offsets_packed [i];
1424 int method_slot_in_interface, vt_slot;
1425
1426 if (mono_class_has_variant_generic_params (iface))
1427 has_variant_iface = TRUE;
1428
1429 mono_class_setup_methods (iface);
1430 vt_slot = interface_offset;
1431 int mcount = mono_class_get_method_count (iface);
1432 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1433 MonoMethod *method;
1434
1435 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1436 /*
1437 * The imt slot of the method is the same as for its declaring method,
1438 * see the comment in mono_method_get_imt_slot (), so we can
1439 * avoid inflating methods which will be discarded by
1440 * add_imt_builder_entry anyway.
1441 */
1442 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1443 if (mono_method_get_imt_slot (method) != slot_num) {
1444 vt_slot ++;
1445 continue;
1446 }
1447 }
1448 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1449 if (method->is_generic) {
1450 has_generic_virtual = TRUE;
1451 vt_slot ++;
1452 continue;
1453 }
1454
1455 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1456 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1457 vt_slot ++;
1458 }
1459 }
1460 }
1461 if (extra_interfaces) {
1462 int interface_offset = klass->vtable_size;
1463
1464 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1465 MonoClass* iface = (MonoClass *)list_item->data;
1466 int method_slot_in_interface;
1467 int mcount = mono_class_get_method_count (iface);
1468 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1469 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1470
1471 if (method->is_generic)
1472 has_generic_virtual = TRUE;
1473 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1474 }
1475 interface_offset += mcount;
1476 }
1477 }
1478 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1479 /* overwrite the imt slot only if we're building all the entries or if
1480 * we're building this specific one
1481 */
1482 if (slot_num < 0 || i == slot_num) {
1483 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1484
1485 if (entries) {
1486 if (imt_builder [i]) {
1487 MonoImtBuilderEntry *entry;
1488
1489 /* Link entries with imt_builder [i] */
1490 for (entry = entries; entry->next; entry = entry->next) {
1491 #if DEBUG_IMT
1492 MonoMethod *method = (MonoMethod*)entry->key;
1493 char *method_name = mono_method_full_name (method, TRUE);
1494 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1495 g_free (method_name);
1496 #endif
1497 }
1498 entry->next = imt_builder [i];
1499 entries->children += imt_builder [i]->children + 1;
1500 }
1501 imt_builder [i] = entries;
1502 }
1503
1504 if (has_generic_virtual || has_variant_iface) {
1505 /*
1506 * There might be collisions later when the the trampoline is expanded.
1507 */
1508 imt_collisions_bitmap |= (1 << i);
1509
1510 /*
1511 * The IMT trampoline might be called with an instance of one of the
1512 * generic virtual methods, so has to fallback to the IMT trampoline.
1513 */
1514 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1515 } else {
1516 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1517 }
1518 #if DEBUG_IMT
1519 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1520 #endif
1521 }
1522
1523 if (imt_builder [i] != NULL) {
1524 int methods_in_slot = imt_builder [i]->children + 1;
1525 if (methods_in_slot > UnlockedRead (&mono_stats.imt_max_collisions_in_slot)) {
1526 UnlockedWrite (&mono_stats.imt_max_collisions_in_slot, methods_in_slot);
1527 record_method_count_for_max_collisions = TRUE;
1528 }
1529 method_count += methods_in_slot;
1530 }
1531 }
1532
1533 UnlockedAdd (&mono_stats.imt_number_of_methods, method_count);
1534 if (record_method_count_for_max_collisions) {
1535 UnlockedWrite (&mono_stats.imt_method_count_when_max_collisions, method_count);
1536 }
1537
1538 for (i = 0; i < MONO_IMT_SIZE; i++) {
1539 MonoImtBuilderEntry* entry = imt_builder [i];
1540 while (entry != NULL) {
1541 MonoImtBuilderEntry* next = entry->next;
1542 g_free (entry);
1543 entry = next;
1544 }
1545 }
1546 g_free (imt_builder);
1547 /* we OR the bitmap since we may build just a single imt slot at a time */
1548 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1549 }
1550
1551 static void
build_imt(MonoClass * klass,MonoVTable * vt,MonoDomain * domain,gpointer * imt,GSList * extra_interfaces)1552 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1553 MONO_REQ_GC_NEUTRAL_MODE;
1554
1555 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1556 }
1557
1558 /**
1559 * mono_vtable_build_imt_slot:
1560 * \param vtable virtual object table struct
1561 * \param imt_slot slot in the IMT table
1562 * Fill the given \p imt_slot in the IMT table of \p vtable with
1563 * a trampoline or a trampoline for the case of collisions.
1564 * This is part of the internal mono API.
1565 * LOCKING: Take the domain lock.
1566 */
1567 void
mono_vtable_build_imt_slot(MonoVTable * vtable,int imt_slot)1568 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1569 {
1570 MONO_REQ_GC_NEUTRAL_MODE;
1571
1572 gpointer *imt = (gpointer*)vtable;
1573 imt -= MONO_IMT_SIZE;
1574 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1575
1576 /* no support for extra interfaces: the proxy objects will need
1577 * to build the complete IMT
1578 * Update and heck needs to ahppen inside the proper domain lock, as all
1579 * the changes made to a MonoVTable.
1580 */
1581 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1582 mono_domain_lock (vtable->domain);
1583 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1584 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1585 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1586 mono_domain_unlock (vtable->domain);
1587 mono_loader_unlock ();
1588 }
1589
1590 #define THUNK_THRESHOLD 10
1591
1592 /**
1593 * mono_method_alloc_generic_virtual_trampoline:
1594 * \param domain a domain
1595 * \param size size in bytes
1596 * Allocs \p size bytes to be used for the code of a generic virtual
1597 * trampoline. It's either allocated from the domain's code manager or
1598 * reused from a previously invalidated piece.
1599 * LOCKING: The domain lock must be held.
1600 */
1601 gpointer
mono_method_alloc_generic_virtual_trampoline(MonoDomain * domain,int size)1602 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1603 {
1604 MONO_REQ_GC_NEUTRAL_MODE;
1605
1606 static gboolean inited = FALSE;
1607 static int generic_virtual_trampolines_size = 0;
1608
1609 if (!inited) {
1610 mono_counters_register ("Generic virtual trampoline bytes",
1611 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1612 inited = TRUE;
1613 }
1614 generic_virtual_trampolines_size += size;
1615
1616 return mono_domain_code_reserve (domain, size);
1617 }
1618
1619 typedef struct _GenericVirtualCase {
1620 MonoMethod *method;
1621 gpointer code;
1622 int count;
1623 struct _GenericVirtualCase *next;
1624 } GenericVirtualCase;
1625
1626 /*
1627 * get_generic_virtual_entries:
1628 *
1629 * Return IMT entries for the generic virtual method instances and
1630 * variant interface methods for vtable slot
1631 * VTABLE_SLOT.
1632 */
1633 static MonoImtBuilderEntry*
get_generic_virtual_entries(MonoDomain * domain,gpointer * vtable_slot)1634 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1635 {
1636 MONO_REQ_GC_NEUTRAL_MODE;
1637
1638 GenericVirtualCase *list;
1639 MonoImtBuilderEntry *entries;
1640
1641 mono_domain_lock (domain);
1642 if (!domain->generic_virtual_cases)
1643 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1644
1645 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1646
1647 entries = NULL;
1648 for (; list; list = list->next) {
1649 MonoImtBuilderEntry *entry;
1650
1651 if (list->count < THUNK_THRESHOLD)
1652 continue;
1653
1654 entry = g_new0 (MonoImtBuilderEntry, 1);
1655 entry->key = list->method;
1656 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1657 entry->has_target_code = 1;
1658 if (entries)
1659 entry->children = entries->children + 1;
1660 entry->next = entries;
1661 entries = entry;
1662 }
1663
1664 mono_domain_unlock (domain);
1665
1666 /* FIXME: Leaking memory ? */
1667 return entries;
1668 }
1669
1670 /**
1671 * \param domain a domain
1672 * \param vtable_slot pointer to the vtable slot
1673 * \param method the inflated generic virtual method
1674 * \param code the method's code
1675 *
1676 * Registers a call via unmanaged code to a generic virtual method
1677 * instantiation or variant interface method. If the number of calls reaches a threshold
1678 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1679 * virtual method trampoline.
1680 */
1681 void
mono_method_add_generic_virtual_invocation(MonoDomain * domain,MonoVTable * vtable,gpointer * vtable_slot,MonoMethod * method,gpointer code)1682 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1683 gpointer *vtable_slot,
1684 MonoMethod *method, gpointer code)
1685 {
1686 MONO_REQ_GC_NEUTRAL_MODE;
1687
1688 static gboolean inited = FALSE;
1689 static int num_added = 0;
1690 static int num_freed = 0;
1691
1692 GenericVirtualCase *gvc, *list;
1693 MonoImtBuilderEntry *entries;
1694 int i;
1695 GPtrArray *sorted;
1696
1697 mono_domain_lock (domain);
1698 if (!domain->generic_virtual_cases)
1699 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1700
1701 if (!inited) {
1702 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1703 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1704 inited = TRUE;
1705 }
1706
1707 /* Check whether the case was already added */
1708 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1709 gvc = list;
1710 while (gvc) {
1711 if (gvc->method == method)
1712 break;
1713 gvc = gvc->next;
1714 }
1715
1716 /* If not found, make a new one */
1717 if (!gvc) {
1718 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1719 gvc->method = method;
1720 gvc->code = code;
1721 gvc->count = 0;
1722 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1723
1724 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1725
1726 num_added++;
1727 }
1728
1729 if (++gvc->count == THUNK_THRESHOLD) {
1730 gpointer *old_thunk = (void **)*vtable_slot;
1731 gpointer vtable_trampoline = NULL;
1732 gpointer imt_trampoline = NULL;
1733
1734 if ((gpointer)vtable_slot < (gpointer)vtable) {
1735 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1736 int imt_slot = MONO_IMT_SIZE + displacement;
1737
1738 /* Force the rebuild of the trampoline at the next call */
1739 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1740 *vtable_slot = imt_trampoline;
1741 } else {
1742 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1743
1744 entries = get_generic_virtual_entries (domain, vtable_slot);
1745
1746 sorted = imt_sort_slot_entries (entries);
1747
1748 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1749 vtable_trampoline);
1750
1751 while (entries) {
1752 MonoImtBuilderEntry *next = entries->next;
1753 g_free (entries);
1754 entries = next;
1755 }
1756
1757 for (i = 0; i < sorted->len; ++i)
1758 g_free (g_ptr_array_index (sorted, i));
1759 g_ptr_array_free (sorted, TRUE);
1760
1761 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1762 num_freed ++;
1763 }
1764 }
1765
1766 mono_domain_unlock (domain);
1767 }
1768
1769 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1770
1771 /**
1772 * mono_class_vtable:
1773 * \param domain the application domain
1774 * \param class the class to initialize
1775 * VTables are domain specific because we create domain specific code, and
1776 * they contain the domain specific static class data.
1777 * On failure, NULL is returned, and \c class->exception_type is set.
1778 */
1779 MonoVTable *
mono_class_vtable(MonoDomain * domain,MonoClass * klass)1780 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1781 {
1782 MonoError error;
1783 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1784 mono_error_cleanup (&error);
1785 return vtable;
1786 }
1787
1788 /**
1789 * mono_class_vtable_full:
1790 * \param domain the application domain
1791 * \param class the class to initialize
1792 * \param error set on failure.
1793 * VTables are domain specific because we create domain specific code, and
1794 * they contain the domain specific static class data.
1795 */
1796 MonoVTable *
mono_class_vtable_full(MonoDomain * domain,MonoClass * klass,MonoError * error)1797 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1798 {
1799 MONO_REQ_GC_UNSAFE_MODE;
1800
1801 MonoClassRuntimeInfo *runtime_info;
1802
1803 error_init (error);
1804
1805 g_assert (klass);
1806
1807 if (mono_class_has_failure (klass)) {
1808 mono_error_set_for_class_failure (error, klass);
1809 return NULL;
1810 }
1811
1812 /* this check can be inlined in jitted code, too */
1813 runtime_info = klass->runtime_info;
1814 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1815 return runtime_info->domain_vtables [domain->domain_id];
1816 return mono_class_create_runtime_vtable (domain, klass, error);
1817 }
1818
1819 /**
1820 * mono_class_try_get_vtable:
1821 * \param domain the application domain
1822 * \param class the class to initialize
1823 * This function tries to get the associated vtable from \p class if
1824 * it was already created.
1825 */
1826 MonoVTable *
mono_class_try_get_vtable(MonoDomain * domain,MonoClass * klass)1827 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1828 {
1829 MONO_REQ_GC_NEUTRAL_MODE;
1830
1831 MonoClassRuntimeInfo *runtime_info;
1832
1833 g_assert (klass);
1834
1835 runtime_info = klass->runtime_info;
1836 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1837 return runtime_info->domain_vtables [domain->domain_id];
1838 return NULL;
1839 }
1840
1841 static gpointer*
alloc_vtable(MonoDomain * domain,size_t vtable_size,size_t imt_table_bytes)1842 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1843 {
1844 MONO_REQ_GC_NEUTRAL_MODE;
1845
1846 size_t alloc_offset;
1847
1848 /*
1849 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1850 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1851 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1852 */
1853 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1854 g_assert ((imt_table_bytes & 7) == 4);
1855 vtable_size += 4;
1856 alloc_offset = 4;
1857 } else {
1858 alloc_offset = 0;
1859 }
1860
1861 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1862 }
1863
1864 static MonoVTable *
mono_class_create_runtime_vtable(MonoDomain * domain,MonoClass * klass,MonoError * error)1865 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1866 {
1867 MONO_REQ_GC_UNSAFE_MODE;
1868
1869 MonoVTable *vt;
1870 MonoClassRuntimeInfo *runtime_info, *old_info;
1871 MonoClassField *field;
1872 char *t;
1873 int i, vtable_slots;
1874 size_t imt_table_bytes;
1875 int gc_bits;
1876 guint32 vtable_size, class_size;
1877 gpointer iter;
1878 gpointer *interface_offsets;
1879
1880 error_init (error);
1881
1882 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1883 mono_domain_lock (domain);
1884 runtime_info = klass->runtime_info;
1885 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1886 mono_domain_unlock (domain);
1887 mono_loader_unlock ();
1888 return runtime_info->domain_vtables [domain->domain_id];
1889 }
1890 if (!klass->inited || mono_class_has_failure (klass)) {
1891 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1892 mono_domain_unlock (domain);
1893 mono_loader_unlock ();
1894 mono_error_set_for_class_failure (error, klass);
1895 return NULL;
1896 }
1897 }
1898
1899 /* Array types require that their element type be valid*/
1900 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1901 MonoClass *element_class = klass->element_class;
1902 if (!element_class->inited)
1903 mono_class_init (element_class);
1904
1905 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1906 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1907 mono_class_setup_vtable (element_class);
1908
1909 if (mono_class_has_failure (element_class)) {
1910 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1911 if (!mono_class_has_failure (klass))
1912 mono_class_set_type_load_failure (klass, "");
1913 mono_domain_unlock (domain);
1914 mono_loader_unlock ();
1915 mono_error_set_for_class_failure (error, klass);
1916 return NULL;
1917 }
1918 }
1919
1920 /*
1921 * For some classes, mono_class_init () already computed klass->vtable_size, and
1922 * that is all that is needed because of the vtable trampolines.
1923 */
1924 if (!klass->vtable_size)
1925 mono_class_setup_vtable (klass);
1926
1927 if (mono_class_is_ginst (klass) && !klass->vtable)
1928 mono_class_check_vtable_constraints (klass, NULL);
1929
1930 /* Initialize klass->has_finalize */
1931 mono_class_has_finalizer (klass);
1932
1933 if (mono_class_has_failure (klass)) {
1934 mono_domain_unlock (domain);
1935 mono_loader_unlock ();
1936 mono_error_set_for_class_failure (error, klass);
1937 return NULL;
1938 }
1939
1940 vtable_slots = klass->vtable_size;
1941 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1942 class_size = mono_class_data_size (klass);
1943 if (class_size)
1944 vtable_slots++;
1945
1946 if (klass->interface_offsets_count) {
1947 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1948 UnlockedIncrement (&mono_stats.imt_number_of_tables);
1949 UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
1950 } else {
1951 imt_table_bytes = 0;
1952 }
1953
1954 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1955
1956 UnlockedIncrement (&mono_stats.used_class_count);
1957 UnlockedAdd (&mono_stats.class_vtable_size, vtable_size);
1958
1959 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1960 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1961 g_assert (!((gsize)vt & 7));
1962
1963 vt->klass = klass;
1964 vt->rank = klass->rank;
1965 vt->domain = domain;
1966
1967 mono_class_compute_gc_descriptor (klass);
1968 /*
1969 * For Boehm:
1970 * We can't use typed allocation in the non-root domains, since the
1971 * collector needs the GC descriptor stored in the vtable even after
1972 * the mempool containing the vtable is destroyed when the domain is
1973 * unloaded. An alternative might be to allocate vtables in the GC
1974 * heap, but this does not seem to work (it leads to crashes inside
1975 * libgc). If that approach is tried, two gc descriptors need to be
1976 * allocated for each class: one for the root domain, and one for all
1977 * other domains. The second descriptor should contain a bit for the
1978 * vtable field in MonoObject, since we can no longer assume the
1979 * vtable is reachable by other roots after the appdomain is unloaded.
1980 */
1981 if (!mono_gc_is_moving () && domain != mono_get_root_domain () && !mono_dont_free_domains)
1982 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1983 else
1984 vt->gc_descr = klass->gc_descr;
1985
1986 gc_bits = mono_gc_get_vtable_bits (klass);
1987 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1988
1989 vt->gc_bits = gc_bits;
1990
1991 if (class_size) {
1992 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1993 if (klass->has_static_refs) {
1994 MonoGCDescriptor statics_gc_descr;
1995 int max_set = 0;
1996 gsize default_bitmap [4] = {0};
1997 gsize *bitmap;
1998
1999 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2000 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2001 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2002 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2003 if (bitmap != default_bitmap)
2004 g_free (bitmap);
2005 } else {
2006 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2007 }
2008 vt->has_static_fields = TRUE;
2009 UnlockedAdd (&mono_stats.class_static_data_size, class_size);
2010 }
2011
2012 iter = NULL;
2013 while ((field = mono_class_get_fields (klass, &iter))) {
2014 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2015 continue;
2016 if (mono_field_is_deleted (field))
2017 continue;
2018 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2019 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2020 if (special_static != SPECIAL_STATIC_NONE) {
2021 guint32 size, offset;
2022 gint32 align;
2023 gsize default_bitmap [4] = {0};
2024 gsize *bitmap;
2025 int max_set = 0;
2026 int numbits;
2027 MonoClass *fclass;
2028 if (mono_type_is_reference (field->type)) {
2029 default_bitmap [0] = 1;
2030 numbits = 1;
2031 bitmap = default_bitmap;
2032 } else if (mono_type_is_struct (field->type)) {
2033 fclass = mono_class_from_mono_type (field->type);
2034 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2035 numbits = max_set + 1;
2036 } else {
2037 default_bitmap [0] = 0;
2038 numbits = 0;
2039 bitmap = default_bitmap;
2040 }
2041 size = mono_type_size (field->type, &align);
2042 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2043 if (!domain->special_static_fields)
2044 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2045 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2046 if (bitmap != default_bitmap)
2047 g_free (bitmap);
2048 /*
2049 * This marks the field as special static to speed up the
2050 * checks in mono_field_static_get/set_value ().
2051 */
2052 field->offset = -1;
2053 continue;
2054 }
2055 }
2056 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2057 MonoClass *fklass = mono_class_from_mono_type (field->type);
2058 const char *data = mono_field_get_data (field);
2059
2060 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2061 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2062 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2063 if (!data)
2064 continue;
2065 if (fklass->valuetype) {
2066 memcpy (t, data, mono_class_value_size (fklass, NULL));
2067 } else {
2068 /* it's a pointer type: add check */
2069 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2070 *t = *(char *)data;
2071 }
2072 continue;
2073 }
2074 }
2075
2076 vt->max_interface_id = klass->max_interface_id;
2077 vt->interface_bitmap = klass->interface_bitmap;
2078
2079 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2080 // class->name, klass->interface_offsets_count);
2081
2082 /* Initialize vtable */
2083 if (callbacks.get_vtable_trampoline) {
2084 // This also covers the AOT case
2085 for (i = 0; i < klass->vtable_size; ++i) {
2086 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2087 }
2088 } else {
2089 mono_class_setup_vtable (klass);
2090
2091 for (i = 0; i < klass->vtable_size; ++i) {
2092 MonoMethod *cm;
2093
2094 cm = klass->vtable [i];
2095 if (cm) {
2096 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2097 if (!is_ok (error)) {
2098 mono_domain_unlock (domain);
2099 mono_loader_unlock ();
2100 return NULL;
2101 }
2102 }
2103 }
2104 }
2105
2106 if (imt_table_bytes) {
2107 /* Now that the vtable is full, we can actually fill up the IMT */
2108 for (i = 0; i < MONO_IMT_SIZE; ++i)
2109 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2110 }
2111
2112 /*
2113 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2114 * re-acquire them and check if another thread has created the vtable in the meantime.
2115 */
2116 /* Special case System.MonoType to avoid infinite recursion */
2117 if (klass != mono_defaults.runtimetype_class) {
2118 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2119 if (!is_ok (error)) {
2120 mono_domain_unlock (domain);
2121 mono_loader_unlock ();
2122 return NULL;
2123 }
2124
2125 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2126 /* This is unregistered in
2127 unregister_vtable_reflection_type() in
2128 domain.c. */
2129 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2130 }
2131
2132 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2133
2134 /* class_vtable_array keeps an array of created vtables
2135 */
2136 g_ptr_array_add (domain->class_vtable_array, vt);
2137 /* klass->runtime_info is protected by the loader lock, both when
2138 * it it enlarged and when it is stored info.
2139 */
2140
2141 /*
2142 * Store the vtable in klass->runtime_info.
2143 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2144 */
2145 mono_memory_barrier ();
2146
2147 old_info = klass->runtime_info;
2148 if (old_info && old_info->max_domain >= domain->domain_id) {
2149 /* someone already created a large enough runtime info */
2150 old_info->domain_vtables [domain->domain_id] = vt;
2151 } else {
2152 int new_size = domain->domain_id;
2153 if (old_info)
2154 new_size = MAX (new_size, old_info->max_domain);
2155 new_size++;
2156 /* make the new size a power of two */
2157 i = 2;
2158 while (new_size > i)
2159 i <<= 1;
2160 new_size = i;
2161 /* this is a bounded memory retention issue: may want to
2162 * handle it differently when we'll have a rcu-like system.
2163 */
2164 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2165 runtime_info->max_domain = new_size - 1;
2166 /* copy the stuff from the older info */
2167 if (old_info) {
2168 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2169 }
2170 runtime_info->domain_vtables [domain->domain_id] = vt;
2171 /* keep this last*/
2172 mono_memory_barrier ();
2173 klass->runtime_info = runtime_info;
2174 }
2175
2176 if (klass == mono_defaults.runtimetype_class) {
2177 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2178 if (!is_ok (error)) {
2179 mono_domain_unlock (domain);
2180 mono_loader_unlock ();
2181 return NULL;
2182 }
2183
2184 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2185 /* This is unregistered in
2186 unregister_vtable_reflection_type() in
2187 domain.c. */
2188 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2189 }
2190
2191 mono_domain_unlock (domain);
2192 mono_loader_unlock ();
2193
2194 /* make sure the parent is initialized */
2195 /*FIXME shouldn't this fail the current type?*/
2196 if (klass->parent)
2197 mono_class_vtable_full (domain, klass->parent, error);
2198
2199 return vt;
2200 }
2201
2202 #ifndef DISABLE_REMOTING
2203 /**
2204 * mono_remote_class_is_interface_proxy:
2205 * \param remote_class
2206 *
2207 * Returns TRUE if the given remote class is a proxying an interface (as
2208 * opposed to a class deriving from MarshalByRefObject).
2209 */
2210 gboolean
mono_remote_class_is_interface_proxy(MonoRemoteClass * remote_class)2211 mono_remote_class_is_interface_proxy (MonoRemoteClass *remote_class)
2212 {
2213 /* This if condition is taking advantage of how mono_remote_class ()
2214 * works: if that code changes, this needs to change too. */
2215 return (remote_class->interface_count >= 1 &&
2216 remote_class->proxy_class == mono_defaults.marshalbyrefobject_class);
2217 }
2218
2219 /**
2220 * mono_class_proxy_vtable:
2221 * \param domain the application domain
2222 * \param remove_class the remote class
2223 * \param error set on error
2224 * Creates a vtable for transparent proxies. It is basically
2225 * a copy of the real vtable of the class wrapped in \p remote_class,
2226 * but all function pointers invoke the remoting functions, and
2227 * \c vtable->klass points to the transparent proxy class, and not to \p class.
2228 *
2229 * On failure returns NULL and sets \p error
2230 */
2231 static MonoVTable *
mono_class_proxy_vtable(MonoDomain * domain,MonoRemoteClass * remote_class,MonoRemotingTarget target_type,MonoError * error)2232 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2233 {
2234 MONO_REQ_GC_UNSAFE_MODE;
2235
2236 MonoVTable *vt, *pvt;
2237 int i, j, vtsize, extra_interface_vtsize = 0;
2238 guint32 max_interface_id;
2239 MonoClass *k;
2240 GSList *extra_interfaces = NULL;
2241 MonoClass *klass = remote_class->proxy_class;
2242 gpointer *interface_offsets;
2243 uint8_t *bitmap = NULL;
2244 int bsize;
2245 size_t imt_table_bytes;
2246
2247 #ifdef COMPRESSED_INTERFACE_BITMAP
2248 int bcsize;
2249 #endif
2250
2251 error_init (error);
2252
2253 vt = mono_class_vtable (domain, klass);
2254 g_assert (vt); /*FIXME property handle failure*/
2255 max_interface_id = vt->max_interface_id;
2256
2257 /* Calculate vtable space for extra interfaces */
2258 for (j = 0; j < remote_class->interface_count; j++) {
2259 MonoClass* iclass = remote_class->interfaces[j];
2260 GPtrArray *ifaces;
2261 int method_count;
2262
2263 /*FIXME test for interfaces with variant generic arguments*/
2264 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2265 continue; /* interface implemented by the class */
2266 if (g_slist_find (extra_interfaces, iclass))
2267 continue;
2268
2269 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2270
2271 method_count = mono_class_num_methods (iclass);
2272
2273 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2274 goto_if_nok (error, failure);
2275 if (ifaces) {
2276 for (i = 0; i < ifaces->len; ++i) {
2277 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2278 /*FIXME test for interfaces with variant generic arguments*/
2279 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2280 continue; /* interface implemented by the class */
2281 if (g_slist_find (extra_interfaces, ic))
2282 continue;
2283 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2284 method_count += mono_class_num_methods (ic);
2285 }
2286 g_ptr_array_free (ifaces, TRUE);
2287 ifaces = NULL;
2288 }
2289
2290 extra_interface_vtsize += method_count * sizeof (gpointer);
2291 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2292 }
2293
2294 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2295 UnlockedIncrement (&mono_stats.imt_number_of_tables);
2296 UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
2297
2298 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2299
2300 UnlockedAdd (&mono_stats.class_vtable_size, vtsize + extra_interface_vtsize);
2301
2302 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2303 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2304 g_assert (!((gsize)pvt & 7));
2305
2306 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2307
2308 pvt->klass = mono_defaults.transparent_proxy_class;
2309 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2310 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2311
2312 if (mono_remote_class_is_interface_proxy (remote_class)) {
2313 /* If it's a transparent proxy for an interface, set the
2314 * MonoVTable:type to the interface type, not the placeholder
2315 * MarshalByRefObject class. This is used when mini JITs calls
2316 * to Object.GetType ()
2317 */
2318 MonoType *itf_proxy_type = &remote_class->interfaces[0]->byval_arg;
2319 pvt->type = mono_type_get_object_checked (domain, itf_proxy_type, error);
2320 goto_if_nok (error, failure);
2321 }
2322
2323 /* initialize vtable */
2324 mono_class_setup_vtable (klass);
2325 for (i = 0; i < klass->vtable_size; ++i) {
2326 MonoMethod *cm;
2327
2328 if ((cm = klass->vtable [i])) {
2329 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2330 goto_if_nok (error, failure);
2331 } else
2332 pvt->vtable [i] = NULL;
2333 }
2334
2335 if (mono_class_is_abstract (klass)) {
2336 /* create trampolines for abstract methods */
2337 for (k = klass; k; k = k->parent) {
2338 MonoMethod* m;
2339 gpointer iter = NULL;
2340 while ((m = mono_class_get_methods (k, &iter)))
2341 if (!pvt->vtable [m->slot]) {
2342 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2343 goto_if_nok (error, failure);
2344 }
2345 }
2346 }
2347
2348 pvt->max_interface_id = max_interface_id;
2349 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2350 #ifdef COMPRESSED_INTERFACE_BITMAP
2351 bitmap = (uint8_t *)g_malloc0 (bsize);
2352 #else
2353 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2354 #endif
2355
2356 for (i = 0; i < klass->interface_offsets_count; ++i) {
2357 int interface_id = klass->interfaces_packed [i]->interface_id;
2358 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2359 }
2360
2361 if (extra_interfaces) {
2362 int slot = klass->vtable_size;
2363 MonoClass* interf;
2364 gpointer iter;
2365 MonoMethod* cm;
2366 GSList *list_item;
2367
2368 /* Create trampolines for the methods of the interfaces */
2369 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2370 interf = (MonoClass *)list_item->data;
2371
2372 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2373
2374 iter = NULL;
2375 j = 0;
2376 while ((cm = mono_class_get_methods (interf, &iter))) {
2377 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2378 goto_if_nok (error, failure);
2379 }
2380
2381 slot += mono_class_num_methods (interf);
2382 }
2383 }
2384
2385 /* Now that the vtable is full, we can actually fill up the IMT */
2386 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2387 if (extra_interfaces) {
2388 g_slist_free (extra_interfaces);
2389 }
2390
2391 #ifdef COMPRESSED_INTERFACE_BITMAP
2392 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2393 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2394 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2395 g_free (bitmap);
2396 #else
2397 pvt->interface_bitmap = bitmap;
2398 #endif
2399 return pvt;
2400 failure:
2401 if (extra_interfaces)
2402 g_slist_free (extra_interfaces);
2403 #ifdef COMPRESSED_INTERFACE_BITMAP
2404 g_free (bitmap);
2405 #endif
2406 return NULL;
2407 }
2408
2409 #endif /* DISABLE_REMOTING */
2410
2411 /**
2412 * mono_class_field_is_special_static:
2413 * \returns whether \p field is a thread/context static field.
2414 */
2415 gboolean
mono_class_field_is_special_static(MonoClassField * field)2416 mono_class_field_is_special_static (MonoClassField *field)
2417 {
2418 MONO_REQ_GC_NEUTRAL_MODE
2419
2420 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2421 return FALSE;
2422 if (mono_field_is_deleted (field))
2423 return FALSE;
2424 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2425 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2426 return TRUE;
2427 }
2428 return FALSE;
2429 }
2430
2431 /**
2432 * mono_class_field_get_special_static_type:
2433 * \param field The \c MonoClassField describing the field.
2434 * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2435 * \c SPECIAL_STATIC_NONE otherwise.
2436 */
2437 guint32
mono_class_field_get_special_static_type(MonoClassField * field)2438 mono_class_field_get_special_static_type (MonoClassField *field)
2439 {
2440 MONO_REQ_GC_NEUTRAL_MODE
2441
2442 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2443 return SPECIAL_STATIC_NONE;
2444 if (mono_field_is_deleted (field))
2445 return SPECIAL_STATIC_NONE;
2446 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2447 return field_is_special_static (field->parent, field);
2448 return SPECIAL_STATIC_NONE;
2449 }
2450
2451 /**
2452 * mono_class_has_special_static_fields:
2453 * \returns whether \p klass has any thread/context static fields.
2454 */
2455 gboolean
mono_class_has_special_static_fields(MonoClass * klass)2456 mono_class_has_special_static_fields (MonoClass *klass)
2457 {
2458 MONO_REQ_GC_NEUTRAL_MODE
2459
2460 MonoClassField *field;
2461 gpointer iter;
2462
2463 iter = NULL;
2464 while ((field = mono_class_get_fields (klass, &iter))) {
2465 g_assert (field->parent == klass);
2466 if (mono_class_field_is_special_static (field))
2467 return TRUE;
2468 }
2469
2470 return FALSE;
2471 }
2472
2473 #ifndef DISABLE_REMOTING
2474 /**
2475 * create_remote_class_key:
2476 * Creates an array of pointers that can be used as a hash key for a remote class.
2477 * The first element of the array is the number of pointers.
2478 */
2479 static gpointer*
create_remote_class_key(MonoRemoteClass * remote_class,MonoClass * extra_class)2480 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2481 {
2482 MONO_REQ_GC_NEUTRAL_MODE;
2483
2484 gpointer *key;
2485 int i, j;
2486
2487 if (remote_class == NULL) {
2488 if (mono_class_is_interface (extra_class)) {
2489 key = (void **)g_malloc (sizeof(gpointer) * 3);
2490 key [0] = GINT_TO_POINTER (2);
2491 key [1] = mono_defaults.marshalbyrefobject_class;
2492 key [2] = extra_class;
2493 } else {
2494 key = (void **)g_malloc (sizeof(gpointer) * 2);
2495 key [0] = GINT_TO_POINTER (1);
2496 key [1] = extra_class;
2497 }
2498 } else {
2499 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2500 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2501 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2502 key [1] = remote_class->proxy_class;
2503
2504 // Keep the list of interfaces sorted
2505 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2506 if (extra_class && remote_class->interfaces [i] > extra_class) {
2507 key [j++] = extra_class;
2508 extra_class = NULL;
2509 }
2510 key [j] = remote_class->interfaces [i];
2511 }
2512 if (extra_class)
2513 key [j] = extra_class;
2514 } else {
2515 // Replace the old class. The interface list is the same
2516 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2517 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2518 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2519 for (i = 0; i < remote_class->interface_count; i++)
2520 key [2 + i] = remote_class->interfaces [i];
2521 }
2522 }
2523
2524 return key;
2525 }
2526
2527 /**
2528 * copy_remote_class_key:
2529 *
2530 * Make a copy of KEY in the domain and return the copy.
2531 */
2532 static gpointer*
copy_remote_class_key(MonoDomain * domain,gpointer * key)2533 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2534 {
2535 MONO_REQ_GC_NEUTRAL_MODE
2536
2537 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2538 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2539
2540 memcpy (mp_key, key, key_size);
2541
2542 return mp_key;
2543 }
2544
2545 /**
2546 * mono_remote_class:
2547 * \param domain the application domain
2548 * \param class_name name of the remote class
2549 * \param error set on error
2550 * Creates and initializes a \c MonoRemoteClass object for a remote type.
2551 * On failure returns NULL and sets \p error
2552 */
2553 MonoRemoteClass*
mono_remote_class(MonoDomain * domain,MonoStringHandle class_name,MonoClass * proxy_class,MonoError * error)2554 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2555 {
2556 MONO_REQ_GC_UNSAFE_MODE;
2557
2558 MonoRemoteClass *rc;
2559 gpointer* key, *mp_key;
2560 char *name;
2561
2562 error_init (error);
2563
2564 key = create_remote_class_key (NULL, proxy_class);
2565
2566 mono_domain_lock (domain);
2567 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2568
2569 if (rc) {
2570 g_free (key);
2571 mono_domain_unlock (domain);
2572 return rc;
2573 }
2574
2575 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2576 if (!is_ok (error)) {
2577 g_free (key);
2578 mono_domain_unlock (domain);
2579 return NULL;
2580 }
2581
2582 mp_key = copy_remote_class_key (domain, key);
2583 g_free (key);
2584 key = mp_key;
2585
2586 if (mono_class_is_interface (proxy_class)) {
2587 /* If we need to proxy an interface, we use this stylized
2588 * representation (interface_count >= 1, proxy_class is
2589 * MarshalByRefObject). The code in
2590 * mono_remote_class_is_interface_proxy () depends on being
2591 * able to detect that we're doing this, so if this
2592 * representation changes, change GetType, too. */
2593 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2594 rc->interface_count = 1;
2595 rc->interfaces [0] = proxy_class;
2596 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2597 } else {
2598 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2599 rc->interface_count = 0;
2600 rc->proxy_class = proxy_class;
2601 }
2602
2603 rc->default_vtable = NULL;
2604 rc->xdomain_vtable = NULL;
2605 rc->proxy_class_name = name;
2606 #ifndef DISABLE_PERFCOUNTERS
2607 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, mono_string_length (MONO_HANDLE_RAW (class_name)) + 1);
2608 #endif
2609
2610 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2611
2612 mono_domain_unlock (domain);
2613 return rc;
2614 }
2615
2616 /**
2617 * clone_remote_class:
2618 * Creates a copy of the remote_class, adding the provided class or interface
2619 */
2620 static MonoRemoteClass*
clone_remote_class(MonoDomain * domain,MonoRemoteClass * remote_class,MonoClass * extra_class)2621 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2622 {
2623 MONO_REQ_GC_NEUTRAL_MODE;
2624
2625 MonoRemoteClass *rc;
2626 gpointer* key, *mp_key;
2627
2628 key = create_remote_class_key (remote_class, extra_class);
2629 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2630 if (rc != NULL) {
2631 g_free (key);
2632 return rc;
2633 }
2634
2635 mp_key = copy_remote_class_key (domain, key);
2636 g_free (key);
2637 key = mp_key;
2638
2639 if (mono_class_is_interface (extra_class)) {
2640 int i,j;
2641 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2642 rc->proxy_class = remote_class->proxy_class;
2643 rc->interface_count = remote_class->interface_count + 1;
2644
2645 // Keep the list of interfaces sorted, since the hash key of
2646 // the remote class depends on this
2647 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2648 if (remote_class->interfaces [i] > extra_class && i == j)
2649 rc->interfaces [j++] = extra_class;
2650 rc->interfaces [j] = remote_class->interfaces [i];
2651 }
2652 if (i == j)
2653 rc->interfaces [j] = extra_class;
2654 } else {
2655 // Replace the old class. The interface array is the same
2656 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2657 rc->proxy_class = extra_class;
2658 rc->interface_count = remote_class->interface_count;
2659 if (rc->interface_count > 0)
2660 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2661 }
2662
2663 rc->default_vtable = NULL;
2664 rc->xdomain_vtable = NULL;
2665 rc->proxy_class_name = remote_class->proxy_class_name;
2666
2667 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2668
2669 return rc;
2670 }
2671
2672 gpointer
mono_remote_class_vtable(MonoDomain * domain,MonoRemoteClass * remote_class,MonoRealProxyHandle rp,MonoError * error)2673 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2674 {
2675 MONO_REQ_GC_UNSAFE_MODE;
2676
2677 error_init (error);
2678
2679 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2680 mono_domain_lock (domain);
2681 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2682 if (target_domain_id != -1) {
2683 if (remote_class->xdomain_vtable == NULL)
2684 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2685 mono_domain_unlock (domain);
2686 mono_loader_unlock ();
2687 return_val_if_nok (error, NULL);
2688 return remote_class->xdomain_vtable;
2689 }
2690 if (remote_class->default_vtable == NULL) {
2691 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2692 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2693
2694 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2695 MonoClass *klass = mono_class_from_mono_type (type);
2696 #ifndef DISABLE_COM
2697 if ((mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) && !mono_vtable_is_remote (mono_class_vtable (mono_domain_get (), klass)))
2698 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2699 else
2700 #endif
2701 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2702 /* N.B. both branches of the if modify error */
2703 if (!is_ok (error)) {
2704 mono_domain_unlock (domain);
2705 mono_loader_unlock ();
2706 return NULL;
2707 }
2708 }
2709
2710 mono_domain_unlock (domain);
2711 mono_loader_unlock ();
2712 return remote_class->default_vtable;
2713 }
2714
2715 /**
2716 * mono_upgrade_remote_class:
2717 * \param domain the application domain
2718 * \param tproxy the proxy whose remote class has to be upgraded.
2719 * \param klass class to which the remote class can be casted.
2720 * \param error set on error
2721 * Updates the vtable of the remote class by adding the necessary method slots
2722 * and interface offsets so it can be safely casted to klass. klass can be a
2723 * class or an interface. On success returns TRUE, on failure returns FALSE and sets \p error.
2724 */
2725 gboolean
mono_upgrade_remote_class(MonoDomain * domain,MonoObjectHandle proxy_object,MonoClass * klass,MonoError * error)2726 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2727 {
2728 MONO_REQ_GC_UNSAFE_MODE;
2729
2730 error_init (error);
2731
2732 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2733 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2734
2735 gboolean redo_vtable;
2736 if (mono_class_is_interface (klass)) {
2737 int i;
2738 redo_vtable = TRUE;
2739 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2740 if (remote_class->interfaces [i] == klass)
2741 redo_vtable = FALSE;
2742 }
2743 else {
2744 redo_vtable = (remote_class->proxy_class != klass);
2745 }
2746
2747 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2748 mono_domain_lock (domain);
2749 if (redo_vtable) {
2750 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2751 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2752 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2753 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2754 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2755 goto_if_nok (error, leave);
2756 }
2757
2758 leave:
2759 mono_domain_unlock (domain);
2760 mono_loader_unlock ();
2761 return is_ok (error);
2762 }
2763 #endif /* DISABLE_REMOTING */
2764
2765
2766 /**
2767 * mono_object_get_virtual_method:
2768 * \param obj object to operate on.
2769 * \param method method
2770 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2771 * the instance of a callvirt of \p method.
2772 */
2773 MonoMethod*
mono_object_get_virtual_method(MonoObject * obj_raw,MonoMethod * method)2774 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2775 {
2776 MONO_REQ_GC_UNSAFE_MODE;
2777 HANDLE_FUNCTION_ENTER ();
2778 MonoError error;
2779 MONO_HANDLE_DCL (MonoObject, obj);
2780 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2781 mono_error_assert_ok (&error);
2782 HANDLE_FUNCTION_RETURN_VAL (result);
2783 }
2784
2785 /**
2786 * mono_object_handle_get_virtual_method:
2787 * \param obj object to operate on.
2788 * \param method method
2789 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2790 * the instance of a callvirt of \p method.
2791 */
2792 MonoMethod*
mono_object_handle_get_virtual_method(MonoObjectHandle obj,MonoMethod * method,MonoError * error)2793 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2794 {
2795 error_init (error);
2796
2797 gboolean is_proxy = FALSE;
2798 MonoClass *klass = mono_handle_class (obj);
2799 if (mono_class_is_transparent_proxy (klass)) {
2800 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2801 klass = remote_class->proxy_class;
2802 is_proxy = TRUE;
2803 }
2804 return class_get_virtual_method (klass, method, is_proxy, error);
2805 }
2806
2807 static MonoMethod*
class_get_virtual_method(MonoClass * klass,MonoMethod * method,gboolean is_proxy,MonoError * error)2808 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2809 {
2810 error_init (error);
2811
2812
2813 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2814 return method;
2815
2816 mono_class_setup_vtable (klass);
2817 MonoMethod **vtable = klass->vtable;
2818
2819 if (method->slot == -1) {
2820 /* method->slot might not be set for instances of generic methods */
2821 if (method->is_inflated) {
2822 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2823 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2824 } else {
2825 if (!is_proxy)
2826 g_assert_not_reached ();
2827 }
2828 }
2829
2830 MonoMethod *res = NULL;
2831 /* check method->slot is a valid index: perform isinstance? */
2832 if (method->slot != -1) {
2833 if (mono_class_is_interface (method->klass)) {
2834 if (!is_proxy) {
2835 gboolean variance_used = FALSE;
2836 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2837 g_assert (iface_offset > 0);
2838 res = vtable [iface_offset + method->slot];
2839 }
2840 } else {
2841 res = vtable [method->slot];
2842 }
2843 }
2844
2845 #ifndef DISABLE_REMOTING
2846 if (is_proxy) {
2847 /* It may be an interface, abstract class method or generic method */
2848 if (!res || mono_method_signature (res)->generic_param_count)
2849 res = method;
2850
2851 /* generic methods demand invoke_with_check */
2852 if (mono_method_signature (res)->generic_param_count)
2853 res = mono_marshal_get_remoting_invoke_with_check (res);
2854 else {
2855 #ifndef DISABLE_COM
2856 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2857 res = mono_cominterop_get_invoke (res);
2858 else
2859 #endif
2860 res = mono_marshal_get_remoting_invoke (res);
2861 }
2862 } else
2863 #endif
2864 {
2865 if (method->is_inflated) {
2866 /* Have to inflate the result */
2867 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2868 }
2869 }
2870
2871 return res;
2872 }
2873
2874 static MonoObject*
do_runtime_invoke(MonoMethod * method,void * obj,void ** params,MonoObject ** exc,MonoError * error)2875 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2876 {
2877 MONO_REQ_GC_UNSAFE_MODE;
2878
2879 MonoObject *result = NULL;
2880
2881 g_assert (callbacks.runtime_invoke);
2882
2883 error_init (error);
2884
2885 MONO_PROFILER_RAISE (method_begin_invoke, (method));
2886
2887 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2888
2889 MONO_PROFILER_RAISE (method_end_invoke, (method));
2890
2891 if (!mono_error_ok (error))
2892 return NULL;
2893
2894 return result;
2895 }
2896
2897 /**
2898 * mono_runtime_invoke:
2899 * \param method method to invoke
2900 * \param obj object instance
2901 * \param params arguments to the method
2902 * \param exc exception information.
2903 * Invokes the method represented by \p method on the object \p obj.
2904 * \p obj is the \c this pointer, it should be NULL for static
2905 * methods, a \c MonoObject* for object instances and a pointer to
2906 * the value type for value types.
2907 *
2908 * The params array contains the arguments to the method with the
2909 * same convention: \c MonoObject* pointers for object instances and
2910 * pointers to the value type otherwise.
2911 *
2912 * From unmanaged code you'll usually use the
2913 * \c mono_runtime_invoke variant.
2914 *
2915 * Note that this function doesn't handle virtual methods for
2916 * you, it will exec the exact method you pass: we still need to
2917 * expose a function to lookup the derived class implementation
2918 * of a virtual method (there are examples of this in the code,
2919 * though).
2920 *
2921 * You can pass NULL as the \p exc argument if you don't want to
2922 * catch exceptions, otherwise, \c *exc will be set to the exception
2923 * thrown, if any. if an exception is thrown, you can't use the
2924 * \c MonoObject* result from the function.
2925 *
2926 * If the method returns a value type, it is boxed in an object
2927 * reference.
2928 */
2929 MonoObject*
mono_runtime_invoke(MonoMethod * method,void * obj,void ** params,MonoObject ** exc)2930 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2931 {
2932 MonoError error;
2933 MonoObject *res;
2934 if (exc) {
2935 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2936 if (*exc == NULL && !mono_error_ok(&error)) {
2937 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2938 } else
2939 mono_error_cleanup (&error);
2940 } else {
2941 res = mono_runtime_invoke_checked (method, obj, params, &error);
2942 mono_error_raise_exception_deprecated (&error); /* OK to throw, external only without a good alternative */
2943 }
2944 return res;
2945 }
2946
2947 /**
2948 * mono_runtime_try_invoke:
2949 * \param method method to invoke
2950 * \param obj object instance
2951 * \param params arguments to the method
2952 * \param exc exception information.
2953 * \param error set on error
2954 * Invokes the method represented by \p method on the object \p obj.
2955 *
2956 * \p obj is the \c this pointer, it should be NULL for static
2957 * methods, a \c MonoObject* for object instances and a pointer to
2958 * the value type for value types.
2959 *
2960 * The params array contains the arguments to the method with the
2961 * same convention: \c MonoObject* pointers for object instances and
2962 * pointers to the value type otherwise.
2963 *
2964 * From unmanaged code you'll usually use the
2965 * mono_runtime_invoke() variant.
2966 *
2967 * Note that this function doesn't handle virtual methods for
2968 * you, it will exec the exact method you pass: we still need to
2969 * expose a function to lookup the derived class implementation
2970 * of a virtual method (there are examples of this in the code,
2971 * though).
2972 *
2973 * For this function, you must not pass NULL as the \p exc argument if
2974 * you don't want to catch exceptions, use
2975 * mono_runtime_invoke_checked(). If an exception is thrown, you
2976 * can't use the \c MonoObject* result from the function.
2977 *
2978 * If this method cannot be invoked, \p error will be set and \p exc and
2979 * the return value must not be used.
2980 *
2981 * If the method returns a value type, it is boxed in an object
2982 * reference.
2983 */
2984 MonoObject*
mono_runtime_try_invoke(MonoMethod * method,void * obj,void ** params,MonoObject ** exc,MonoError * error)2985 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2986 {
2987 MONO_REQ_GC_UNSAFE_MODE;
2988
2989 g_assert (exc != NULL);
2990
2991 if (mono_runtime_get_no_exec ())
2992 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2993
2994 return do_runtime_invoke (method, obj, params, exc, error);
2995 }
2996
2997 /**
2998 * mono_runtime_invoke_checked:
2999 * \param method method to invoke
3000 * \param obj object instance
3001 * \param params arguments to the method
3002 * \param error set on error
3003 * Invokes the method represented by \p method on the object \p obj.
3004 *
3005 * \p obj is the \c this pointer, it should be NULL for static
3006 * methods, a \c MonoObject* for object instances and a pointer to
3007 * the value type for value types.
3008 *
3009 * The \p params array contains the arguments to the method with the
3010 * same convention: \c MonoObject* pointers for object instances and
3011 * pointers to the value type otherwise.
3012 *
3013 * From unmanaged code you'll usually use the
3014 * mono_runtime_invoke() variant.
3015 *
3016 * Note that this function doesn't handle virtual methods for
3017 * you, it will exec the exact method you pass: we still need to
3018 * expose a function to lookup the derived class implementation
3019 * of a virtual method (there are examples of this in the code,
3020 * though).
3021 *
3022 * If an exception is thrown, you can't use the \c MonoObject* result
3023 * from the function.
3024 *
3025 * If this method cannot be invoked, \p error will be set. If the
3026 * method throws an exception (and we're in coop mode) the exception
3027 * will be set in \p error.
3028 *
3029 * If the method returns a value type, it is boxed in an object
3030 * reference.
3031 */
3032 MonoObject*
mono_runtime_invoke_checked(MonoMethod * method,void * obj,void ** params,MonoError * error)3033 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3034 {
3035 MONO_REQ_GC_UNSAFE_MODE;
3036
3037 if (mono_runtime_get_no_exec ())
3038 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3039
3040 return do_runtime_invoke (method, obj, params, NULL, error);
3041 }
3042
3043 /**
3044 * mono_method_get_unmanaged_thunk:
3045 * \param method method to generate a thunk for.
3046 *
3047 * Returns an \c unmanaged->managed thunk that can be used to call
3048 * a managed method directly from C.
3049 *
3050 * The thunk's C signature closely matches the managed signature:
3051 *
3052 * C#: <code>public bool Equals (object obj);</code>
3053 *
3054 * C: <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3055 *
3056 * The 1st (<code>this</code>) parameter must not be used with static methods:
3057 *
3058 * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
3059 *
3060 * C: <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
3061 *
3062 * The last argument must be a non-null \c MonoException* pointer.
3063 * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3064 * exception has been thrown in managed code. Otherwise it will point
3065 * to the \c MonoException* caught by the thunk. In this case, the result of
3066 * the thunk is undefined:
3067 *
3068 * <pre>
3069 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3070 *
3071 * MonoException *ex = NULL;
3072 *
3073 * Equals func = mono_method_get_unmanaged_thunk (method);
3074 *
3075 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3076 *
3077 * if (ex) {
3078 *
3079 * // handle exception
3080 *
3081 * }
3082 * </pre>
3083 *
3084 * The calling convention of the thunk matches the platform's default
3085 * convention. This means that under Windows, C declarations must
3086 * contain the \c __stdcall attribute:
3087 *
3088 * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3089 *
3090 * LIMITATIONS
3091 *
3092 * Value type arguments and return values are treated as they were objects:
3093 *
3094 * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3095 * C: <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3096 *
3097 * Arguments must be properly boxed upon trunk's invocation, while return
3098 * values must be unboxed.
3099 */
3100 gpointer
mono_method_get_unmanaged_thunk(MonoMethod * method)3101 mono_method_get_unmanaged_thunk (MonoMethod *method)
3102 {
3103 MONO_REQ_GC_NEUTRAL_MODE;
3104 MONO_REQ_API_ENTRYPOINT;
3105
3106 MonoError error;
3107 gpointer res;
3108
3109 g_assert (!mono_threads_is_coop_enabled ());
3110
3111 MONO_ENTER_GC_UNSAFE;
3112 method = mono_marshal_get_thunk_invoke_wrapper (method);
3113 res = mono_compile_method_checked (method, &error);
3114 mono_error_cleanup (&error);
3115 MONO_EXIT_GC_UNSAFE;
3116
3117 return res;
3118 }
3119
3120 void
mono_copy_value(MonoType * type,void * dest,void * value,int deref_pointer)3121 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3122 {
3123 MONO_REQ_GC_UNSAFE_MODE;
3124
3125 int t;
3126 if (type->byref) {
3127 /* object fields cannot be byref, so we don't need a
3128 wbarrier here */
3129 gpointer *p = (gpointer*)dest;
3130 *p = value;
3131 return;
3132 }
3133 t = type->type;
3134 handle_enum:
3135 switch (t) {
3136 case MONO_TYPE_BOOLEAN:
3137 case MONO_TYPE_I1:
3138 case MONO_TYPE_U1: {
3139 guint8 *p = (guint8*)dest;
3140 *p = value ? *(guint8*)value : 0;
3141 return;
3142 }
3143 case MONO_TYPE_I2:
3144 case MONO_TYPE_U2:
3145 case MONO_TYPE_CHAR: {
3146 guint16 *p = (guint16*)dest;
3147 *p = value ? *(guint16*)value : 0;
3148 return;
3149 }
3150 #if SIZEOF_VOID_P == 4
3151 case MONO_TYPE_I:
3152 case MONO_TYPE_U:
3153 #endif
3154 case MONO_TYPE_I4:
3155 case MONO_TYPE_U4: {
3156 gint32 *p = (gint32*)dest;
3157 *p = value ? *(gint32*)value : 0;
3158 return;
3159 }
3160 #if SIZEOF_VOID_P == 8
3161 case MONO_TYPE_I:
3162 case MONO_TYPE_U:
3163 #endif
3164 case MONO_TYPE_I8:
3165 case MONO_TYPE_U8: {
3166 gint64 *p = (gint64*)dest;
3167 *p = value ? *(gint64*)value : 0;
3168 return;
3169 }
3170 case MONO_TYPE_R4: {
3171 float *p = (float*)dest;
3172 *p = value ? *(float*)value : 0;
3173 return;
3174 }
3175 case MONO_TYPE_R8: {
3176 double *p = (double*)dest;
3177 *p = value ? *(double*)value : 0;
3178 return;
3179 }
3180 case MONO_TYPE_STRING:
3181 case MONO_TYPE_SZARRAY:
3182 case MONO_TYPE_CLASS:
3183 case MONO_TYPE_OBJECT:
3184 case MONO_TYPE_ARRAY:
3185 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3186 return;
3187 case MONO_TYPE_FNPTR:
3188 case MONO_TYPE_PTR: {
3189 gpointer *p = (gpointer*)dest;
3190 *p = deref_pointer? *(gpointer*)value: value;
3191 return;
3192 }
3193 case MONO_TYPE_VALUETYPE:
3194 /* note that 't' and 'type->type' can be different */
3195 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3196 t = mono_class_enum_basetype (type->data.klass)->type;
3197 goto handle_enum;
3198 } else {
3199 MonoClass *klass = mono_class_from_mono_type (type);
3200 int size = mono_class_value_size (klass, NULL);
3201 if (value == NULL)
3202 mono_gc_bzero_atomic (dest, size);
3203 else
3204 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3205 }
3206 return;
3207 case MONO_TYPE_GENERICINST:
3208 t = type->data.generic_class->container_class->byval_arg.type;
3209 goto handle_enum;
3210 default:
3211 g_error ("got type %x", type->type);
3212 }
3213 }
3214
3215 /**
3216 * mono_field_set_value:
3217 * \param obj Instance object
3218 * \param field \c MonoClassField describing the field to set
3219 * \param value The value to be set
3220 *
3221 * Sets the value of the field described by \p field in the object instance \p obj
3222 * to the value passed in \p value. This method should only be used for instance
3223 * fields. For static fields, use \c mono_field_static_set_value.
3224 *
3225 * The value must be in the native format of the field type.
3226 */
3227 void
mono_field_set_value(MonoObject * obj,MonoClassField * field,void * value)3228 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3229 {
3230 MONO_REQ_GC_UNSAFE_MODE;
3231
3232 void *dest;
3233
3234 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3235
3236 dest = (char*)obj + field->offset;
3237 mono_copy_value (field->type, dest, value, FALSE);
3238 }
3239
3240 /**
3241 * mono_field_static_set_value:
3242 * \param field \c MonoClassField describing the field to set
3243 * \param value The value to be set
3244 * Sets the value of the static field described by \p field
3245 * to the value passed in \p value.
3246 * The value must be in the native format of the field type.
3247 */
3248 void
mono_field_static_set_value(MonoVTable * vt,MonoClassField * field,void * value)3249 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3250 {
3251 MONO_REQ_GC_UNSAFE_MODE;
3252
3253 void *dest;
3254
3255 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3256 /* you cant set a constant! */
3257 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3258
3259 if (field->offset == -1) {
3260 /* Special static */
3261 gpointer addr;
3262
3263 mono_domain_lock (vt->domain);
3264 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3265 mono_domain_unlock (vt->domain);
3266 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3267 } else {
3268 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3269 }
3270 mono_copy_value (field->type, dest, value, FALSE);
3271 }
3272
3273 /**
3274 * mono_vtable_get_static_field_data:
3275 *
3276 * Internal use function: return a pointer to the memory holding the static fields
3277 * for a class or NULL if there are no static fields.
3278 * This is exported only for use by the debugger.
3279 */
3280 void *
mono_vtable_get_static_field_data(MonoVTable * vt)3281 mono_vtable_get_static_field_data (MonoVTable *vt)
3282 {
3283 MONO_REQ_GC_NEUTRAL_MODE
3284
3285 if (!vt->has_static_fields)
3286 return NULL;
3287 return vt->vtable [vt->klass->vtable_size];
3288 }
3289
3290 static guint8*
mono_field_get_addr(MonoObject * obj,MonoVTable * vt,MonoClassField * field)3291 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3292 {
3293 MONO_REQ_GC_UNSAFE_MODE;
3294
3295 guint8 *src;
3296
3297 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3298 if (field->offset == -1) {
3299 /* Special static */
3300 gpointer addr;
3301
3302 mono_domain_lock (vt->domain);
3303 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3304 mono_domain_unlock (vt->domain);
3305 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3306 } else {
3307 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3308 }
3309 } else {
3310 src = (guint8*)obj + field->offset;
3311 }
3312
3313 return src;
3314 }
3315
3316 /**
3317 * mono_field_get_value:
3318 * \param obj Object instance
3319 * \param field \c MonoClassField describing the field to fetch information from
3320 * \param value pointer to the location where the value will be stored
3321 * Use this routine to get the value of the field \p field in the object
3322 * passed.
3323 *
3324 * The pointer provided by value must be of the field type, for reference
3325 * types this is a \c MonoObject*, for value types its the actual pointer to
3326 * the value type.
3327 *
3328 * For example:
3329 *
3330 * <pre>
3331 * int i;
3332 *
3333 * mono_field_get_value (obj, int_field, &i);
3334 * </pre>
3335 */
3336 void
mono_field_get_value(MonoObject * obj,MonoClassField * field,void * value)3337 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3338 {
3339 MONO_REQ_GC_UNSAFE_MODE;
3340
3341 void *src;
3342
3343 g_assert (obj);
3344
3345 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3346
3347 src = (char*)obj + field->offset;
3348 mono_copy_value (field->type, value, src, TRUE);
3349 }
3350
3351 /**
3352 * mono_field_get_value_object:
3353 * \param domain domain where the object will be created (if boxing)
3354 * \param field \c MonoClassField describing the field to fetch information from
3355 * \param obj The object instance for the field.
3356 * \returns a new \c MonoObject with the value from the given field. If the
3357 * field represents a value type, the value is boxed.
3358 */
3359 MonoObject *
mono_field_get_value_object(MonoDomain * domain,MonoClassField * field,MonoObject * obj)3360 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3361 {
3362 MonoError error;
3363 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3364 mono_error_assert_ok (&error);
3365 return result;
3366 }
3367
3368 /**
3369 * mono_field_get_value_object_checked:
3370 * \param domain domain where the object will be created (if boxing)
3371 * \param field \c MonoClassField describing the field to fetch information from
3372 * \param obj The object instance for the field.
3373 * \param error Set on error.
3374 * \returns a new \c MonoObject with the value from the given field. If the
3375 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3376 */
3377 MonoObject *
mono_field_get_value_object_checked(MonoDomain * domain,MonoClassField * field,MonoObject * obj,MonoError * error)3378 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3379 {
3380 MONO_REQ_GC_UNSAFE_MODE;
3381
3382 error_init (error);
3383
3384 MonoObject *o;
3385 MonoClass *klass;
3386 MonoVTable *vtable = NULL;
3387 gchar *v;
3388 gboolean is_static = FALSE;
3389 gboolean is_ref = FALSE;
3390 gboolean is_literal = FALSE;
3391 gboolean is_ptr = FALSE;
3392 MonoType *type = mono_field_get_type_checked (field, error);
3393
3394 return_val_if_nok (error, NULL);
3395
3396 switch (type->type) {
3397 case MONO_TYPE_STRING:
3398 case MONO_TYPE_OBJECT:
3399 case MONO_TYPE_CLASS:
3400 case MONO_TYPE_ARRAY:
3401 case MONO_TYPE_SZARRAY:
3402 is_ref = TRUE;
3403 break;
3404 case MONO_TYPE_U1:
3405 case MONO_TYPE_I1:
3406 case MONO_TYPE_BOOLEAN:
3407 case MONO_TYPE_U2:
3408 case MONO_TYPE_I2:
3409 case MONO_TYPE_CHAR:
3410 case MONO_TYPE_U:
3411 case MONO_TYPE_I:
3412 case MONO_TYPE_U4:
3413 case MONO_TYPE_I4:
3414 case MONO_TYPE_R4:
3415 case MONO_TYPE_U8:
3416 case MONO_TYPE_I8:
3417 case MONO_TYPE_R8:
3418 case MONO_TYPE_VALUETYPE:
3419 is_ref = type->byref;
3420 break;
3421 case MONO_TYPE_GENERICINST:
3422 is_ref = !mono_type_generic_inst_is_valuetype (type);
3423 break;
3424 case MONO_TYPE_PTR:
3425 is_ptr = TRUE;
3426 break;
3427 default:
3428 g_error ("type 0x%x not handled in "
3429 "mono_field_get_value_object", type->type);
3430 return NULL;
3431 }
3432
3433 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3434 is_literal = TRUE;
3435
3436 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3437 is_static = TRUE;
3438
3439 if (!is_literal) {
3440 vtable = mono_class_vtable_full (domain, field->parent, error);
3441 return_val_if_nok (error, NULL);
3442
3443 if (!vtable->initialized) {
3444 mono_runtime_class_init_full (vtable, error);
3445 return_val_if_nok (error, NULL);
3446 }
3447 }
3448 } else {
3449 g_assert (obj);
3450 }
3451
3452 if (is_ref) {
3453 if (is_literal) {
3454 get_default_field_value (domain, field, &o, error);
3455 return_val_if_nok (error, NULL);
3456 } else if (is_static) {
3457 mono_field_static_get_value_checked (vtable, field, &o, error);
3458 return_val_if_nok (error, NULL);
3459 } else {
3460 mono_field_get_value (obj, field, &o);
3461 }
3462 return o;
3463 }
3464
3465 if (is_ptr) {
3466 static MonoMethod *m;
3467 gpointer args [2];
3468 gpointer *ptr;
3469 gpointer v;
3470
3471 if (!m) {
3472 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3473 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3474 g_assert (m);
3475 }
3476
3477 v = &ptr;
3478 if (is_literal) {
3479 get_default_field_value (domain, field, v, error);
3480 return_val_if_nok (error, NULL);
3481 } else if (is_static) {
3482 mono_field_static_get_value_checked (vtable, field, v, error);
3483 return_val_if_nok (error, NULL);
3484 } else {
3485 mono_field_get_value (obj, field, v);
3486 }
3487
3488 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3489 args [0] = ptr ? *ptr : NULL;
3490 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3491 return_val_if_nok (error, NULL);
3492
3493 o = mono_runtime_invoke_checked (m, NULL, args, error);
3494 return_val_if_nok (error, NULL);
3495
3496 return o;
3497 }
3498
3499 /* boxed value type */
3500 klass = mono_class_from_mono_type (type);
3501
3502 if (mono_class_is_nullable (klass))
3503 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3504
3505 o = mono_object_new_checked (domain, klass, error);
3506 return_val_if_nok (error, NULL);
3507 v = ((gchar *) o) + sizeof (MonoObject);
3508
3509 if (is_literal) {
3510 get_default_field_value (domain, field, v, error);
3511 return_val_if_nok (error, NULL);
3512 } else if (is_static) {
3513 mono_field_static_get_value_checked (vtable, field, v, error);
3514 return_val_if_nok (error, NULL);
3515 } else {
3516 mono_field_get_value (obj, field, v);
3517 }
3518
3519 return o;
3520 }
3521
3522 int
mono_get_constant_value_from_blob(MonoDomain * domain,MonoTypeEnum type,const char * blob,void * value,MonoError * error)3523 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3524 {
3525 MONO_REQ_GC_UNSAFE_MODE;
3526
3527 error_init (error);
3528 int retval = 0;
3529 const char *p = blob;
3530 mono_metadata_decode_blob_size (p, &p);
3531
3532 switch (type) {
3533 case MONO_TYPE_BOOLEAN:
3534 case MONO_TYPE_U1:
3535 case MONO_TYPE_I1:
3536 *(guint8 *) value = *p;
3537 break;
3538 case MONO_TYPE_CHAR:
3539 case MONO_TYPE_U2:
3540 case MONO_TYPE_I2:
3541 *(guint16*) value = read16 (p);
3542 break;
3543 case MONO_TYPE_U4:
3544 case MONO_TYPE_I4:
3545 *(guint32*) value = read32 (p);
3546 break;
3547 case MONO_TYPE_U8:
3548 case MONO_TYPE_I8:
3549 *(guint64*) value = read64 (p);
3550 break;
3551 case MONO_TYPE_R4:
3552 readr4 (p, (float*) value);
3553 break;
3554 case MONO_TYPE_R8:
3555 readr8 (p, (double*) value);
3556 break;
3557 case MONO_TYPE_STRING:
3558 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3559 break;
3560 case MONO_TYPE_CLASS:
3561 *(gpointer*) value = NULL;
3562 break;
3563 default:
3564 retval = -1;
3565 g_warning ("type 0x%02x should not be in constant table", type);
3566 }
3567 return retval;
3568 }
3569
3570 static void
get_default_field_value(MonoDomain * domain,MonoClassField * field,void * value,MonoError * error)3571 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3572 {
3573 MONO_REQ_GC_NEUTRAL_MODE;
3574
3575 MonoTypeEnum def_type;
3576 const char* data;
3577
3578 error_init (error);
3579
3580 data = mono_class_get_field_default_value (field, &def_type);
3581 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3582 }
3583
3584 void
mono_field_static_get_value_for_thread(MonoInternalThread * thread,MonoVTable * vt,MonoClassField * field,void * value,MonoError * error)3585 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3586 {
3587 MONO_REQ_GC_UNSAFE_MODE;
3588
3589 void *src;
3590
3591 error_init (error);
3592
3593 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3594
3595 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3596 get_default_field_value (vt->domain, field, value, error);
3597 return;
3598 }
3599
3600 if (field->offset == -1) {
3601 /* Special static */
3602 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3603 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3604 } else {
3605 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3606 }
3607 mono_copy_value (field->type, value, src, TRUE);
3608 }
3609
3610 /**
3611 * mono_field_static_get_value:
3612 * \param vt vtable to the object
3613 * \param field \c MonoClassField describing the field to fetch information from
3614 * \param value where the value is returned
3615 * Use this routine to get the value of the static field \p field value.
3616 *
3617 * The pointer provided by value must be of the field type, for reference
3618 * types this is a \c MonoObject*, for value types its the actual pointer to
3619 * the value type.
3620 *
3621 * For example:
3622 *
3623 * <pre>
3624 * int i;
3625 *
3626 * mono_field_static_get_value (vt, int_field, &i);
3627 * </pre>
3628 */
3629 void
mono_field_static_get_value(MonoVTable * vt,MonoClassField * field,void * value)3630 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3631 {
3632 MONO_REQ_GC_NEUTRAL_MODE;
3633
3634 MonoError error;
3635 mono_field_static_get_value_checked (vt, field, value, &error);
3636 mono_error_cleanup (&error);
3637 }
3638
3639 /**
3640 * mono_field_static_get_value_checked:
3641 * \param vt vtable to the object
3642 * \param field \c MonoClassField describing the field to fetch information from
3643 * \param value where the value is returned
3644 * \param error set on error
3645 * Use this routine to get the value of the static field \p field value.
3646 *
3647 * The pointer provided by value must be of the field type, for reference
3648 * types this is a \c MonoObject*, for value types its the actual pointer to
3649 * the value type.
3650 *
3651 * For example:
3652 * int i;
3653 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3654 * if (!is_ok (error)) { ... }
3655 *
3656 * On failure sets \p error.
3657 */
3658 void
mono_field_static_get_value_checked(MonoVTable * vt,MonoClassField * field,void * value,MonoError * error)3659 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3660 {
3661 MONO_REQ_GC_NEUTRAL_MODE;
3662
3663 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3664 }
3665
3666 /**
3667 * mono_property_set_value:
3668 * \param prop MonoProperty to set
3669 * \param obj instance object on which to act
3670 * \param params parameters to pass to the propery
3671 * \param exc optional exception
3672 * Invokes the property's set method with the given arguments on the
3673 * object instance obj (or NULL for static properties).
3674 *
3675 * You can pass NULL as the exc argument if you don't want to
3676 * catch exceptions, otherwise, \c *exc will be set to the exception
3677 * thrown, if any. if an exception is thrown, you can't use the
3678 * \c MonoObject* result from the function.
3679 */
3680 void
mono_property_set_value(MonoProperty * prop,void * obj,void ** params,MonoObject ** exc)3681 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3682 {
3683 MONO_REQ_GC_UNSAFE_MODE;
3684
3685 MonoError error;
3686 do_runtime_invoke (prop->set, obj, params, exc, &error);
3687 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3688 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3689 } else {
3690 mono_error_cleanup (&error);
3691 }
3692 }
3693
3694 /**
3695 * mono_property_set_value_checked:
3696 * \param prop \c MonoProperty to set
3697 * \param obj instance object on which to act
3698 * \param params parameters to pass to the propery
3699 * \param error set on error
3700 * Invokes the property's set method with the given arguments on the
3701 * object instance \p obj (or NULL for static properties).
3702 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3703 * If an exception is thrown, it will be caught and returned via \p error.
3704 */
3705 gboolean
mono_property_set_value_checked(MonoProperty * prop,void * obj,void ** params,MonoError * error)3706 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3707 {
3708 MONO_REQ_GC_UNSAFE_MODE;
3709
3710 MonoObject *exc;
3711
3712 error_init (error);
3713 do_runtime_invoke (prop->set, obj, params, &exc, error);
3714 if (exc != NULL && is_ok (error))
3715 mono_error_set_exception_instance (error, (MonoException*)exc);
3716 return is_ok (error);
3717 }
3718
3719 /**
3720 * mono_property_get_value:
3721 * \param prop \c MonoProperty to fetch
3722 * \param obj instance object on which to act
3723 * \param params parameters to pass to the propery
3724 * \param exc optional exception
3725 * Invokes the property's \c get method with the given arguments on the
3726 * object instance \p obj (or NULL for static properties).
3727 *
3728 * You can pass NULL as the \p exc argument if you don't want to
3729 * catch exceptions, otherwise, \c *exc will be set to the exception
3730 * thrown, if any. if an exception is thrown, you can't use the
3731 * \c MonoObject* result from the function.
3732 *
3733 * \returns the value from invoking the \c get method on the property.
3734 */
3735 MonoObject*
mono_property_get_value(MonoProperty * prop,void * obj,void ** params,MonoObject ** exc)3736 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3737 {
3738 MONO_REQ_GC_UNSAFE_MODE;
3739
3740 MonoError error;
3741 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3742 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3743 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3744 } else {
3745 mono_error_cleanup (&error); /* FIXME don't raise here */
3746 }
3747
3748 return val;
3749 }
3750
3751 /**
3752 * mono_property_get_value_checked:
3753 * \param prop \c MonoProperty to fetch
3754 * \param obj instance object on which to act
3755 * \param params parameters to pass to the propery
3756 * \param error set on error
3757 * Invokes the property's \c get method with the given arguments on the
3758 * object instance obj (or NULL for static properties).
3759 *
3760 * If an exception is thrown, you can't use the
3761 * \c MonoObject* result from the function. The exception will be propagated via \p error.
3762 *
3763 * \returns the value from invoking the get method on the property. On
3764 * failure returns NULL and sets \p error.
3765 */
3766 MonoObject*
mono_property_get_value_checked(MonoProperty * prop,void * obj,void ** params,MonoError * error)3767 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3768 {
3769 MONO_REQ_GC_UNSAFE_MODE;
3770
3771 MonoObject *exc;
3772 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3773 if (exc != NULL && !is_ok (error))
3774 mono_error_set_exception_instance (error, (MonoException*) exc);
3775 if (!is_ok (error))
3776 val = NULL;
3777 return val;
3778 }
3779
3780
3781 /*
3782 * mono_nullable_init:
3783 * @buf: The nullable structure to initialize.
3784 * @value: the value to initialize from
3785 * @klass: the type for the object
3786 *
3787 * Initialize the nullable structure pointed to by @buf from @value which
3788 * should be a boxed value type. The size of @buf should be able to hold
3789 * as much data as the @klass->instance_size (which is the number of bytes
3790 * that will be copies).
3791 *
3792 * Since Nullables have variable structure, we can not define a C
3793 * structure for them.
3794 */
3795 void
mono_nullable_init(guint8 * buf,MonoObject * value,MonoClass * klass)3796 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3797 {
3798 MONO_REQ_GC_UNSAFE_MODE;
3799
3800 MonoClass *param_class = klass->cast_class;
3801
3802 mono_class_setup_fields (klass);
3803 g_assert (klass->fields_inited);
3804
3805 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3806 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3807
3808 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3809 if (value) {
3810 if (param_class->has_references)
3811 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3812 else
3813 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3814 } else {
3815 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3816 }
3817 }
3818
3819 /*
3820 * mono_nullable_init_from_handle:
3821 * @buf: The nullable structure to initialize.
3822 * @value: the value to initialize from
3823 * @klass: the type for the object
3824 *
3825 * Initialize the nullable structure pointed to by @buf from @value which
3826 * should be a boxed value type. The size of @buf should be able to hold
3827 * as much data as the @klass->instance_size (which is the number of bytes
3828 * that will be copies).
3829 *
3830 * Since Nullables have variable structure, we can not define a C
3831 * structure for them.
3832 */
3833 void
mono_nullable_init_from_handle(guint8 * buf,MonoObjectHandle value,MonoClass * klass)3834 mono_nullable_init_from_handle (guint8 *buf, MonoObjectHandle value, MonoClass *klass)
3835 {
3836 MONO_REQ_GC_UNSAFE_MODE;
3837
3838 MonoClass *param_class = klass->cast_class;
3839
3840 mono_class_setup_fields (klass);
3841 g_assert (klass->fields_inited);
3842
3843 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3844 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3845
3846 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = MONO_HANDLE_IS_NULL (value) ? 0 : 1;
3847 if (!MONO_HANDLE_IS_NULL (value)) {
3848 uint32_t value_gchandle = 0;
3849 gpointer src = mono_object_handle_pin_unbox (value, &value_gchandle);
3850 if (param_class->has_references)
3851 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), src, 1, param_class);
3852 else
3853 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), src, mono_class_value_size (param_class, NULL));
3854 mono_gchandle_free (value_gchandle);
3855 } else {
3856 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3857 }
3858 }
3859
3860
3861
3862 /**
3863 * mono_nullable_box:
3864 * \param buf The buffer representing the data to be boxed
3865 * \param klass the type to box it as.
3866 * \param error set on error
3867 *
3868 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
3869 * \p buf. On failure returns NULL and sets \p error.
3870 */
3871 MonoObject*
mono_nullable_box(guint8 * buf,MonoClass * klass,MonoError * error)3872 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3873 {
3874 MONO_REQ_GC_UNSAFE_MODE;
3875
3876 error_init (error);
3877 MonoClass *param_class = klass->cast_class;
3878
3879 mono_class_setup_fields (klass);
3880 g_assert (klass->fields_inited);
3881
3882 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3883 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3884
3885 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3886 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3887 return_val_if_nok (error, NULL);
3888 if (param_class->has_references)
3889 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3890 else
3891 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3892 return o;
3893 }
3894 else
3895 return NULL;
3896 }
3897
3898 /**
3899 * mono_get_delegate_invoke:
3900 * \param klass The delegate class
3901 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
3902 */
3903 MonoMethod *
mono_get_delegate_invoke(MonoClass * klass)3904 mono_get_delegate_invoke (MonoClass *klass)
3905 {
3906 MONO_REQ_GC_NEUTRAL_MODE;
3907
3908 MonoMethod *im;
3909
3910 /* This is called at runtime, so avoid the slower search in metadata */
3911 mono_class_setup_methods (klass);
3912 if (mono_class_has_failure (klass))
3913 return NULL;
3914 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3915 return im;
3916 }
3917
3918 /**
3919 * mono_get_delegate_begin_invoke:
3920 * \param klass The delegate class
3921 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3922 */
3923 MonoMethod *
mono_get_delegate_begin_invoke(MonoClass * klass)3924 mono_get_delegate_begin_invoke (MonoClass *klass)
3925 {
3926 MONO_REQ_GC_NEUTRAL_MODE;
3927
3928 MonoMethod *im;
3929
3930 /* This is called at runtime, so avoid the slower search in metadata */
3931 mono_class_setup_methods (klass);
3932 if (mono_class_has_failure (klass))
3933 return NULL;
3934 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3935 return im;
3936 }
3937
3938 /**
3939 * mono_get_delegate_end_invoke:
3940 * \param klass The delegate class
3941 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3942 */
3943 MonoMethod *
mono_get_delegate_end_invoke(MonoClass * klass)3944 mono_get_delegate_end_invoke (MonoClass *klass)
3945 {
3946 MONO_REQ_GC_NEUTRAL_MODE;
3947
3948 MonoMethod *im;
3949
3950 /* This is called at runtime, so avoid the slower search in metadata */
3951 mono_class_setup_methods (klass);
3952 if (mono_class_has_failure (klass))
3953 return NULL;
3954 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3955 return im;
3956 }
3957
3958 /**
3959 * mono_runtime_delegate_invoke:
3960 * \param delegate pointer to a delegate object.
3961 * \param params parameters for the delegate.
3962 * \param exc Pointer to the exception result.
3963 *
3964 * Invokes the delegate method \p delegate with the parameters provided.
3965 *
3966 * You can pass NULL as the \p exc argument if you don't want to
3967 * catch exceptions, otherwise, \c *exc will be set to the exception
3968 * thrown, if any. if an exception is thrown, you can't use the
3969 * \c MonoObject* result from the function.
3970 */
3971 MonoObject*
mono_runtime_delegate_invoke(MonoObject * delegate,void ** params,MonoObject ** exc)3972 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3973 {
3974 MONO_REQ_GC_UNSAFE_MODE;
3975
3976 MonoError error;
3977 if (exc) {
3978 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3979 if (*exc) {
3980 mono_error_cleanup (&error);
3981 return NULL;
3982 } else {
3983 if (!is_ok (&error))
3984 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3985 return result;
3986 }
3987 } else {
3988 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3989 mono_error_raise_exception_deprecated (&error); /* OK to throw, external only without a good alternative */
3990 return result;
3991 }
3992 }
3993
3994 /**
3995 * mono_runtime_delegate_try_invoke:
3996 * \param delegate pointer to a delegate object.
3997 * \param params parameters for the delegate.
3998 * \param exc Pointer to the exception result.
3999 * \param error set on error
4000 * Invokes the delegate method \p delegate with the parameters provided.
4001 *
4002 * You can pass NULL as the \p exc argument if you don't want to
4003 * catch exceptions, otherwise, \c *exc will be set to the exception
4004 * thrown, if any. On failure to execute, \p error will be set.
4005 * if an exception is thrown, you can't use the
4006 * \c MonoObject* result from the function.
4007 */
4008 MonoObject*
mono_runtime_delegate_try_invoke(MonoObject * delegate,void ** params,MonoObject ** exc,MonoError * error)4009 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
4010 {
4011 MONO_REQ_GC_UNSAFE_MODE;
4012
4013 error_init (error);
4014 MonoMethod *im;
4015 MonoClass *klass = delegate->vtable->klass;
4016 MonoObject *o;
4017
4018 im = mono_get_delegate_invoke (klass);
4019 if (!im)
4020 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
4021
4022 if (exc) {
4023 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
4024 } else {
4025 o = mono_runtime_invoke_checked (im, delegate, params, error);
4026 }
4027
4028 return o;
4029 }
4030
4031 /**
4032 * mono_runtime_delegate_invoke_checked:
4033 * \param delegate pointer to a delegate object.
4034 * \param params parameters for the delegate.
4035 * \param error set on error
4036 * Invokes the delegate method \p delegate with the parameters provided.
4037 * On failure \p error will be set and you can't use the \c MonoObject*
4038 * result from the function.
4039 */
4040 MonoObject*
mono_runtime_delegate_invoke_checked(MonoObject * delegate,void ** params,MonoError * error)4041 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
4042 {
4043 error_init (error);
4044 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
4045 }
4046
4047 static char **main_args = NULL;
4048 static int num_main_args = 0;
4049
4050 /**
4051 * mono_runtime_get_main_args:
4052 * \returns A \c MonoArray with the arguments passed to the main program
4053 */
4054 MonoArray*
mono_runtime_get_main_args(void)4055 mono_runtime_get_main_args (void)
4056 {
4057 HANDLE_FUNCTION_ENTER ();
4058 MONO_REQ_GC_UNSAFE_MODE;
4059 MonoError error;
4060 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
4061 error_init (&error);
4062 MonoArrayHandle arg_array = mono_runtime_get_main_args_handle (&error);
4063 goto_if_nok (&error, leave);
4064 MONO_HANDLE_ASSIGN (result, arg_array);
4065 leave:
4066 /* FIXME: better external API that doesn't swallow the error */
4067 mono_error_cleanup (&error);
4068 HANDLE_FUNCTION_RETURN_OBJ (result);
4069 }
4070
4071 static gboolean
handle_main_arg_array_set(MonoDomain * domain,int idx,MonoArrayHandle dest,MonoError * error)4072 handle_main_arg_array_set (MonoDomain *domain, int idx, MonoArrayHandle dest, MonoError *error)
4073 {
4074 HANDLE_FUNCTION_ENTER ();
4075 error_init (error);
4076 MonoStringHandle value = mono_string_new_handle (domain, main_args [idx], error);
4077 goto_if_nok (error, leave);
4078 MONO_HANDLE_ARRAY_SETREF (dest, idx, value);
4079 leave:
4080 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
4081 }
4082
4083 /**
4084 * mono_runtime_get_main_args_handle:
4085 * \param error set on error
4086 * \returns a \c MonoArray with the arguments passed to the main
4087 * program. On failure returns NULL and sets \p error.
4088 */
4089 MonoArrayHandle
mono_runtime_get_main_args_handle(MonoError * error)4090 mono_runtime_get_main_args_handle (MonoError *error)
4091 {
4092 HANDLE_FUNCTION_ENTER ();
4093 MonoArrayHandle array;
4094 int i;
4095 MonoDomain *domain = mono_domain_get ();
4096 error_init (error);
4097
4098 array = mono_array_new_handle (domain, mono_defaults.string_class, num_main_args, error);
4099 if (!is_ok (error)) {
4100 array = MONO_HANDLE_CAST (MonoArray, NULL_HANDLE);
4101 goto leave;
4102 }
4103 for (i = 0; i < num_main_args; ++i) {
4104 if (!handle_main_arg_array_set (domain, i, array, error))
4105 goto leave;
4106 }
4107 leave:
4108 HANDLE_FUNCTION_RETURN_REF (MonoArray, array);
4109 }
4110
4111 static void
free_main_args(void)4112 free_main_args (void)
4113 {
4114 MONO_REQ_GC_NEUTRAL_MODE;
4115
4116 int i;
4117
4118 for (i = 0; i < num_main_args; ++i)
4119 g_free (main_args [i]);
4120 g_free (main_args);
4121 num_main_args = 0;
4122 main_args = NULL;
4123 }
4124
4125 /**
4126 * mono_runtime_set_main_args:
4127 * \param argc number of arguments from the command line
4128 * \param argv array of strings from the command line
4129 * Set the command line arguments from an embedding application that doesn't otherwise call
4130 * \c mono_runtime_run_main.
4131 */
4132 int
mono_runtime_set_main_args(int argc,char * argv[])4133 mono_runtime_set_main_args (int argc, char* argv[])
4134 {
4135 MONO_REQ_GC_NEUTRAL_MODE;
4136
4137 int i;
4138
4139 free_main_args ();
4140 main_args = g_new0 (char*, argc);
4141 num_main_args = argc;
4142
4143 for (i = 0; i < argc; ++i) {
4144 gchar *utf8_arg;
4145
4146 utf8_arg = mono_utf8_from_external (argv[i]);
4147 if (utf8_arg == NULL) {
4148 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4149 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4150 exit (-1);
4151 }
4152
4153 main_args [i] = utf8_arg;
4154 }
4155
4156 return 0;
4157 }
4158
4159 /*
4160 * Prepare an array of arguments in order to execute a standard Main()
4161 * method (argc/argv contains the executable name). This method also
4162 * sets the command line argument value needed by System.Environment.
4163 *
4164 */
4165 static MonoArray*
prepare_run_main(MonoMethod * method,int argc,char * argv[])4166 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4167 {
4168 MONO_REQ_GC_UNSAFE_MODE;
4169
4170 MonoError error;
4171 int i;
4172 MonoArray *args = NULL;
4173 MonoDomain *domain = mono_domain_get ();
4174 gchar *utf8_fullpath;
4175 MonoMethodSignature *sig;
4176
4177 g_assert (method != NULL);
4178
4179 mono_thread_set_main (mono_thread_current ());
4180
4181 main_args = g_new0 (char*, argc);
4182 num_main_args = argc;
4183
4184 if (!g_path_is_absolute (argv [0])) {
4185 gchar *basename = g_path_get_basename (argv [0]);
4186 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4187 basename,
4188 NULL);
4189
4190 utf8_fullpath = mono_utf8_from_external (fullpath);
4191 if(utf8_fullpath == NULL) {
4192 /* Printing the arg text will cause glib to
4193 * whinge about "Invalid UTF-8", but at least
4194 * its relevant, and shows the problem text
4195 * string.
4196 */
4197 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4198 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4199 exit (-1);
4200 }
4201
4202 g_free (fullpath);
4203 g_free (basename);
4204 } else {
4205 utf8_fullpath = mono_utf8_from_external (argv[0]);
4206 if(utf8_fullpath == NULL) {
4207 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4208 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4209 exit (-1);
4210 }
4211 }
4212
4213 main_args [0] = utf8_fullpath;
4214
4215 for (i = 1; i < argc; ++i) {
4216 gchar *utf8_arg;
4217
4218 utf8_arg=mono_utf8_from_external (argv[i]);
4219 if(utf8_arg==NULL) {
4220 /* Ditto the comment about Invalid UTF-8 here */
4221 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4222 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4223 exit (-1);
4224 }
4225
4226 main_args [i] = utf8_arg;
4227 }
4228 argc--;
4229 argv++;
4230
4231 sig = mono_method_signature (method);
4232 if (!sig) {
4233 g_print ("Unable to load Main method.\n");
4234 exit (-1);
4235 }
4236
4237 if (sig->param_count) {
4238 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4239 mono_error_assert_ok (&error);
4240 for (i = 0; i < argc; ++i) {
4241 /* The encodings should all work, given that
4242 * we've checked all these args for the
4243 * main_args array.
4244 */
4245 gchar *str = mono_utf8_from_external (argv [i]);
4246 MonoString *arg = mono_string_new_checked (domain, str, &error);
4247 mono_error_assert_ok (&error);
4248 mono_array_setref (args, i, arg);
4249 g_free (str);
4250 }
4251 } else {
4252 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4253 mono_error_assert_ok (&error);
4254 }
4255
4256 mono_assembly_set_main (method->klass->image->assembly);
4257
4258 return args;
4259 }
4260
4261 /**
4262 * mono_runtime_run_main:
4263 * \param method the method to start the application with (usually <code>Main</code>)
4264 * \param argc number of arguments from the command line
4265 * \param argv array of strings from the command line
4266 * \param exc excetption results
4267 * Execute a standard \c Main method (\p argc / \p argv contains the
4268 * executable name). This method also sets the command line argument value
4269 * needed by \c System.Environment.
4270 */
4271 int
mono_runtime_run_main(MonoMethod * method,int argc,char * argv[],MonoObject ** exc)4272 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4273 MonoObject **exc)
4274 {
4275 MONO_REQ_GC_UNSAFE_MODE;
4276
4277 MonoError error;
4278 MonoArray *args = prepare_run_main (method, argc, argv);
4279 int res;
4280 if (exc) {
4281 res = mono_runtime_try_exec_main (method, args, exc);
4282 } else {
4283 res = mono_runtime_exec_main_checked (method, args, &error);
4284 mono_error_raise_exception_deprecated (&error); /* OK to throw, external only without a better alternative */
4285 }
4286 return res;
4287 }
4288
4289 /**
4290 * mono_runtime_run_main_checked:
4291 * \param method the method to start the application with (usually \c Main)
4292 * \param argc number of arguments from the command line
4293 * \param argv array of strings from the command line
4294 * \param error set on error
4295 *
4296 * Execute a standard \c Main method (\p argc / \p argv contains the
4297 * executable name). This method also sets the command line argument value
4298 * needed by \c System.Environment. On failure sets \p error.
4299 */
4300 int
mono_runtime_run_main_checked(MonoMethod * method,int argc,char * argv[],MonoError * error)4301 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4302 MonoError *error)
4303 {
4304 error_init (error);
4305 MonoArray *args = prepare_run_main (method, argc, argv);
4306 return mono_runtime_exec_main_checked (method, args, error);
4307 }
4308
4309 /**
4310 * mono_runtime_try_run_main:
4311 * \param method the method to start the application with (usually \c Main)
4312 * \param argc number of arguments from the command line
4313 * \param argv array of strings from the command line
4314 * \param exc set if \c Main throws an exception
4315 * \param error set if \c Main can't be executed
4316 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4317 * name). This method also sets the command line argument value needed
4318 * by \c System.Environment. On failure sets \p error if Main can't be
4319 * executed or \p exc if it threw an exception.
4320 */
4321 int
mono_runtime_try_run_main(MonoMethod * method,int argc,char * argv[],MonoObject ** exc)4322 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4323 MonoObject **exc)
4324 {
4325 g_assert (exc);
4326 MonoArray *args = prepare_run_main (method, argc, argv);
4327 return mono_runtime_try_exec_main (method, args, exc);
4328 }
4329
4330
4331 static MonoObject*
serialize_object(MonoObject * obj,gboolean * failure,MonoObject ** exc)4332 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4333 {
4334 static MonoMethod *serialize_method;
4335
4336 MonoError error;
4337 void *params [1];
4338 MonoObject *array;
4339
4340 if (!serialize_method) {
4341 MonoClass *klass = mono_class_get_remoting_services_class ();
4342 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4343 }
4344
4345 if (!serialize_method) {
4346 *failure = TRUE;
4347 return NULL;
4348 }
4349
4350 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4351
4352 params [0] = obj;
4353 *exc = NULL;
4354
4355 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4356 if (*exc == NULL && !mono_error_ok (&error))
4357 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4358 else
4359 mono_error_cleanup (&error);
4360
4361 if (*exc)
4362 *failure = TRUE;
4363
4364 return array;
4365 }
4366
4367 static MonoObject*
deserialize_object(MonoObject * obj,gboolean * failure,MonoObject ** exc)4368 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4369 {
4370 MONO_REQ_GC_UNSAFE_MODE;
4371
4372 static MonoMethod *deserialize_method;
4373
4374 MonoError error;
4375 void *params [1];
4376 MonoObject *result;
4377
4378 if (!deserialize_method) {
4379 MonoClass *klass = mono_class_get_remoting_services_class ();
4380 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4381 }
4382 if (!deserialize_method) {
4383 *failure = TRUE;
4384 return NULL;
4385 }
4386
4387 params [0] = obj;
4388 *exc = NULL;
4389
4390 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4391 if (*exc == NULL && !mono_error_ok (&error))
4392 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4393 else
4394 mono_error_cleanup (&error);
4395
4396 if (*exc)
4397 *failure = TRUE;
4398
4399 return result;
4400 }
4401
4402 #ifndef DISABLE_REMOTING
4403 static MonoObject*
make_transparent_proxy(MonoObject * obj,MonoError * error)4404 make_transparent_proxy (MonoObject *obj, MonoError *error)
4405 {
4406 MONO_REQ_GC_UNSAFE_MODE;
4407
4408 static MonoMethod *get_proxy_method;
4409
4410 MonoDomain *domain = mono_domain_get ();
4411 MonoRealProxy *real_proxy;
4412 MonoReflectionType *reflection_type;
4413 MonoTransparentProxy *transparent_proxy;
4414
4415 error_init (error);
4416
4417 if (!get_proxy_method)
4418 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4419
4420 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4421
4422 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4423 return_val_if_nok (error, NULL);
4424 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4425 return_val_if_nok (error, NULL);
4426
4427 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4428 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4429
4430 MonoObject *exc = NULL;
4431
4432 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4433 if (exc != NULL && is_ok (error))
4434 mono_error_set_exception_instance (error, (MonoException*)exc);
4435
4436 return (MonoObject*) transparent_proxy;
4437 }
4438 #endif /* DISABLE_REMOTING */
4439
4440 /**
4441 * mono_object_xdomain_representation
4442 * \param obj an object
4443 * \param target_domain a domain
4444 * \param error set on error.
4445 * Creates a representation of obj in the domain \p target_domain. This
4446 * is either a copy of \p obj arrived through via serialization and
4447 * deserialization or a proxy, depending on whether the object is
4448 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4449 * If the object cannot be represented in \p target_domain, NULL is
4450 * returned and \p error is set appropriately.
4451 */
4452 MonoObject*
mono_object_xdomain_representation(MonoObject * obj,MonoDomain * target_domain,MonoError * error)4453 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4454 {
4455 MONO_REQ_GC_UNSAFE_MODE;
4456
4457 error_init (error);
4458 MonoObject *deserialized = NULL;
4459
4460 #ifndef DISABLE_REMOTING
4461 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4462 deserialized = make_transparent_proxy (obj, error);
4463 }
4464 else
4465 #endif
4466 {
4467 gboolean failure = FALSE;
4468 MonoDomain *domain = mono_domain_get ();
4469 MonoObject *serialized;
4470 MonoObject *exc = NULL;
4471
4472 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4473 serialized = serialize_object (obj, &failure, &exc);
4474 mono_domain_set_internal_with_options (target_domain, FALSE);
4475 if (!failure)
4476 deserialized = deserialize_object (serialized, &failure, &exc);
4477 if (domain != target_domain)
4478 mono_domain_set_internal_with_options (domain, FALSE);
4479 if (failure)
4480 mono_error_set_exception_instance (error, (MonoException*)exc);
4481 }
4482
4483 return deserialized;
4484 }
4485
4486 /* Used in call_unhandled_exception_delegate */
4487 static MonoObject *
create_unhandled_exception_eventargs(MonoObject * exc,MonoError * error)4488 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4489 {
4490 MONO_REQ_GC_UNSAFE_MODE;
4491
4492 error_init (error);
4493 MonoClass *klass;
4494 gpointer args [2];
4495 MonoMethod *method = NULL;
4496 MonoBoolean is_terminating = TRUE;
4497 MonoObject *obj;
4498
4499 klass = mono_class_get_unhandled_exception_event_args_class ();
4500 mono_class_init (klass);
4501
4502 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4503 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4504 g_assert (method);
4505
4506 args [0] = exc;
4507 args [1] = &is_terminating;
4508
4509 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4510 return_val_if_nok (error, NULL);
4511
4512 mono_runtime_invoke_checked (method, obj, args, error);
4513 return_val_if_nok (error, NULL);
4514
4515 return obj;
4516 }
4517
4518 /* Used in mono_unhandled_exception */
4519 static void
call_unhandled_exception_delegate(MonoDomain * domain,MonoObject * delegate,MonoObject * exc)4520 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4521 MONO_REQ_GC_UNSAFE_MODE;
4522
4523 MonoError error;
4524 MonoObject *e = NULL;
4525 gpointer pa [2];
4526 MonoDomain *current_domain = mono_domain_get ();
4527
4528 if (domain != current_domain)
4529 mono_domain_set_internal_with_options (domain, FALSE);
4530
4531 g_assert (domain == mono_object_domain (domain->domain));
4532
4533 if (mono_object_domain (exc) != domain) {
4534
4535 exc = mono_object_xdomain_representation (exc, domain, &error);
4536 if (!exc) {
4537 if (!is_ok (&error)) {
4538 MonoError inner_error;
4539 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4540 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4541 mono_error_assert_ok (&inner_error);
4542 } else {
4543 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4544 "System.Runtime.Serialization", "SerializationException",
4545 "Could not serialize unhandled exception.");
4546 }
4547 }
4548 }
4549 g_assert (mono_object_domain (exc) == domain);
4550
4551 pa [0] = domain->domain;
4552 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4553 mono_error_assert_ok (&error);
4554 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4555 if (!is_ok (&error)) {
4556 if (e == NULL)
4557 e = (MonoObject*)mono_error_convert_to_exception (&error);
4558 else
4559 mono_error_cleanup (&error);
4560 }
4561
4562 if (domain != current_domain)
4563 mono_domain_set_internal_with_options (current_domain, FALSE);
4564
4565 if (e) {
4566 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4567 if (!mono_error_ok (&error)) {
4568 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4569 mono_error_cleanup (&error);
4570 } else {
4571 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4572 g_free (msg);
4573 }
4574 }
4575 }
4576
4577 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4578
4579 /**
4580 * mono_runtime_unhandled_exception_policy_set:
4581 * \param policy the new policy
4582 * This is a VM internal routine.
4583 * Sets the runtime policy for handling unhandled exceptions.
4584 */
4585 void
mono_runtime_unhandled_exception_policy_set(MonoRuntimeUnhandledExceptionPolicy policy)4586 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4587 runtime_unhandled_exception_policy = policy;
4588 }
4589
4590 /**
4591 * mono_runtime_unhandled_exception_policy_get:
4592 *
4593 * This is a VM internal routine.
4594 *
4595 * Gets the runtime policy for handling unhandled exceptions.
4596 */
4597 MonoRuntimeUnhandledExceptionPolicy
mono_runtime_unhandled_exception_policy_get(void)4598 mono_runtime_unhandled_exception_policy_get (void) {
4599 return runtime_unhandled_exception_policy;
4600 }
4601
4602 /**
4603 * mono_unhandled_exception:
4604 * \param exc exception thrown
4605 * This is a VM internal routine.
4606 *
4607 * We call this function when we detect an unhandled exception
4608 * in the default domain.
4609 *
4610 * It invokes the \c UnhandledException event in \c AppDomain or prints
4611 * a warning to the console
4612 */
4613 void
mono_unhandled_exception(MonoObject * exc_raw)4614 mono_unhandled_exception (MonoObject *exc_raw)
4615 {
4616 MonoError error;
4617 HANDLE_FUNCTION_ENTER ();
4618 MONO_HANDLE_DCL (MonoObject, exc);
4619 error_init (&error);
4620 mono_unhandled_exception_checked (exc, &error);
4621 mono_error_assert_ok (&error);
4622 HANDLE_FUNCTION_RETURN ();
4623 }
4624
4625 /**
4626 * mono_unhandled_exception:
4627 * @exc: exception thrown
4628 *
4629 * This is a VM internal routine.
4630 *
4631 * We call this function when we detect an unhandled exception
4632 * in the default domain.
4633 *
4634 * It invokes the * UnhandledException event in AppDomain or prints
4635 * a warning to the console
4636 */
4637 void
mono_unhandled_exception_checked(MonoObjectHandle exc,MonoError * error)4638 mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
4639 {
4640 MONO_REQ_GC_UNSAFE_MODE;
4641
4642 error_init (error);
4643 MonoClassField *field;
4644 MonoDomain *current_domain, *root_domain;
4645 MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);
4646
4647 MonoClass *klass = mono_handle_class (exc);
4648 /*
4649 * AppDomainUnloadedException don't behave like unhandled exceptions unless thrown from
4650 * a thread started in unmanaged world.
4651 * https://msdn.microsoft.com/en-us/library/system.appdomainunloadedexception(v=vs.110).aspx#Anchor_6
4652 */
4653 if (klass == mono_defaults.threadabortexception_class ||
4654 (klass == mono_class_get_appdomain_unloaded_exception_class () &&
4655 mono_thread_info_current ()->runtime_thread))
4656 return;
4657
4658 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4659 g_assert (field);
4660
4661 current_domain = mono_domain_get ();
4662 root_domain = mono_get_root_domain ();
4663
4664 MonoObjectHandle root_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, error)); /* FIXME use handles for mono_field_get_value_object_checked */
4665 return_if_nok (error);
4666 if (current_domain != root_domain) {
4667 MONO_HANDLE_ASSIGN (current_appdomain_delegate, MONO_HANDLE_NEW (MonoObject, mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, error))); /* FIXME use handles for mono_field_get_value_object_checked */
4668 return_if_nok (error);
4669 }
4670
4671 if (MONO_HANDLE_IS_NULL (current_appdomain_delegate) && MONO_HANDLE_IS_NULL (root_appdomain_delegate)) {
4672 mono_print_unhandled_exception (MONO_HANDLE_RAW (exc)); /* FIXME use handles for mono_print_unhandled_exception */
4673 } else {
4674 /* unhandled exception callbacks must not be aborted */
4675 mono_threads_begin_abort_protected_block ();
4676 if (!MONO_HANDLE_IS_NULL (root_appdomain_delegate))
4677 call_unhandled_exception_delegate (root_domain, MONO_HANDLE_RAW (root_appdomain_delegate), MONO_HANDLE_RAW (exc)); /* FIXME use handles in call_unhandled_exception_delegate */
4678 if (!MONO_HANDLE_IS_NULL (current_appdomain_delegate))
4679 call_unhandled_exception_delegate (current_domain, MONO_HANDLE_RAW (current_appdomain_delegate), MONO_HANDLE_RAW (exc));
4680 mono_threads_end_abort_protected_block ();
4681 }
4682
4683 /* set exitcode only if we will abort the process */
4684 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4685 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4686 {
4687 mono_environment_exitcode_set (1);
4688 }
4689 }
4690
4691 /**
4692 * mono_runtime_exec_managed_code:
4693 * \param domain Application domain
4694 * \param main_func function to invoke from the execution thread
4695 * \param main_args parameter to the main_func
4696 * Launch a new thread to execute a function
4697 *
4698 * \p main_func is called back from the thread with main_args as the
4699 * parameter. The callback function is expected to start \c Main
4700 * eventually. This function then waits for all managed threads to
4701 * finish.
4702 * It is not necessary anymore to execute managed code in a subthread,
4703 * so this function should not be used anymore by default: just
4704 * execute the code and then call mono_thread_manage().
4705 */
4706 void
mono_runtime_exec_managed_code(MonoDomain * domain,MonoMainThreadFunc main_func,gpointer main_args)4707 mono_runtime_exec_managed_code (MonoDomain *domain,
4708 MonoMainThreadFunc main_func,
4709 gpointer main_args)
4710 {
4711 MonoError error;
4712 mono_thread_create_checked (domain, main_func, main_args, &error);
4713 mono_error_assert_ok (&error);
4714
4715 mono_thread_manage ();
4716 }
4717
4718 static void
prepare_thread_to_exec_main(MonoDomain * domain,MonoMethod * method)4719 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4720 {
4721 MonoInternalThread* thread = mono_thread_internal_current ();
4722 MonoCustomAttrInfo* cinfo;
4723 gboolean has_stathread_attribute;
4724
4725 if (!domain->entry_assembly) {
4726 gchar *str;
4727 MonoError error;
4728 MonoAssembly *assembly;
4729
4730 assembly = method->klass->image->assembly;
4731 domain->entry_assembly = assembly;
4732 /* Domains created from another domain already have application_base and configuration_file set */
4733 if (domain->setup->application_base == NULL) {
4734 MonoString *basedir = mono_string_new_checked (domain, assembly->basedir, &error);
4735 mono_error_assert_ok (&error);
4736 MONO_OBJECT_SETREF (domain->setup, application_base, basedir);
4737 }
4738
4739 if (domain->setup->configuration_file == NULL) {
4740 str = g_strconcat (assembly->image->name, ".config", NULL);
4741 MonoString *config_file = mono_string_new_checked (domain, str, &error);
4742 mono_error_assert_ok (&error);
4743 MONO_OBJECT_SETREF (domain->setup, configuration_file, config_file);
4744 g_free (str);
4745 mono_domain_set_options_from_config (domain);
4746 }
4747 }
4748
4749 MonoError cattr_error;
4750 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4751 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4752 if (cinfo) {
4753 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4754 if (!cinfo->cached)
4755 mono_custom_attrs_free (cinfo);
4756 } else {
4757 has_stathread_attribute = FALSE;
4758 }
4759 if (has_stathread_attribute) {
4760 thread->apartment_state = ThreadApartmentState_STA;
4761 } else {
4762 thread->apartment_state = ThreadApartmentState_MTA;
4763 }
4764 mono_thread_init_apartment_state ();
4765
4766 }
4767
4768 static int
do_exec_main_checked(MonoMethod * method,MonoArray * args,MonoError * error)4769 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4770 {
4771 MONO_REQ_GC_UNSAFE_MODE;
4772
4773 gpointer pa [1];
4774 int rval;
4775
4776 error_init (error);
4777 g_assert (args);
4778
4779 pa [0] = args;
4780
4781 /* FIXME: check signature of method */
4782 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4783 MonoObject *res;
4784 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4785 if (is_ok (error))
4786 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4787 else
4788 rval = -1;
4789 mono_environment_exitcode_set (rval);
4790 } else {
4791 mono_runtime_invoke_checked (method, NULL, pa, error);
4792
4793 if (is_ok (error))
4794 rval = 0;
4795 else {
4796 rval = -1;
4797 }
4798 }
4799 return rval;
4800 }
4801
4802 static int
do_try_exec_main(MonoMethod * method,MonoArray * args,MonoObject ** exc)4803 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4804 {
4805 MONO_REQ_GC_UNSAFE_MODE;
4806
4807 gpointer pa [1];
4808 int rval;
4809
4810 g_assert (args);
4811 g_assert (exc);
4812
4813 pa [0] = args;
4814
4815 /* FIXME: check signature of method */
4816 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4817 MonoError inner_error;
4818 MonoObject *res;
4819 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4820 if (*exc == NULL && !mono_error_ok (&inner_error))
4821 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4822 else
4823 mono_error_cleanup (&inner_error);
4824
4825 if (*exc == NULL)
4826 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4827 else
4828 rval = -1;
4829
4830 mono_environment_exitcode_set (rval);
4831 } else {
4832 MonoError inner_error;
4833 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4834 if (*exc == NULL && !mono_error_ok (&inner_error))
4835 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4836 else
4837 mono_error_cleanup (&inner_error);
4838
4839 if (*exc == NULL)
4840 rval = 0;
4841 else {
4842 /* If the return type of Main is void, only
4843 * set the exitcode if an exception was thrown
4844 * (we don't want to blow away an
4845 * explicitly-set exit code)
4846 */
4847 rval = -1;
4848 mono_environment_exitcode_set (rval);
4849 }
4850 }
4851
4852 return rval;
4853 }
4854
4855 /*
4856 * Execute a standard Main() method (args doesn't contain the
4857 * executable name).
4858 */
4859 int
mono_runtime_exec_main(MonoMethod * method,MonoArray * args,MonoObject ** exc)4860 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4861 {
4862 MonoError error;
4863 prepare_thread_to_exec_main (mono_object_domain (args), method);
4864 if (exc) {
4865 int rval = do_try_exec_main (method, args, exc);
4866 return rval;
4867 } else {
4868 int rval = do_exec_main_checked (method, args, &error);
4869 mono_error_raise_exception_deprecated (&error); /* OK to throw, external only with no better option */
4870 return rval;
4871 }
4872 }
4873
4874 /*
4875 * Execute a standard Main() method (args doesn't contain the
4876 * executable name).
4877 *
4878 * On failure sets @error
4879 */
4880 int
mono_runtime_exec_main_checked(MonoMethod * method,MonoArray * args,MonoError * error)4881 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4882 {
4883 error_init (error);
4884 prepare_thread_to_exec_main (mono_object_domain (args), method);
4885 return do_exec_main_checked (method, args, error);
4886 }
4887
4888 /*
4889 * Execute a standard Main() method (args doesn't contain the
4890 * executable name).
4891 *
4892 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4893 */
4894 int
mono_runtime_try_exec_main(MonoMethod * method,MonoArray * args,MonoObject ** exc)4895 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4896 {
4897 prepare_thread_to_exec_main (mono_object_domain (args), method);
4898 return do_try_exec_main (method, args, exc);
4899 }
4900
4901
4902
4903 /** invoke_array_extract_argument:
4904 * @params: array of arguments to the method.
4905 * @i: the index of the argument to extract.
4906 * @t: ith type from the method signature.
4907 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4908 * @error: set on error.
4909 *
4910 * Given an array of method arguments, return the ith one using the corresponding type
4911 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4912 *
4913 * On failure sets @error and returns NULL.
4914 */
4915 static gpointer
invoke_array_extract_argument(MonoArray * params,int i,MonoType * t,gboolean * has_byref_nullables,MonoError * error)4916 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4917 {
4918 MonoType *t_orig = t;
4919 gpointer result = NULL;
4920 error_init (error);
4921 again:
4922 switch (t->type) {
4923 case MONO_TYPE_U1:
4924 case MONO_TYPE_I1:
4925 case MONO_TYPE_BOOLEAN:
4926 case MONO_TYPE_U2:
4927 case MONO_TYPE_I2:
4928 case MONO_TYPE_CHAR:
4929 case MONO_TYPE_U:
4930 case MONO_TYPE_I:
4931 case MONO_TYPE_U4:
4932 case MONO_TYPE_I4:
4933 case MONO_TYPE_U8:
4934 case MONO_TYPE_I8:
4935 case MONO_TYPE_R4:
4936 case MONO_TYPE_R8:
4937 case MONO_TYPE_VALUETYPE:
4938 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4939 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4940 result = mono_array_get (params, MonoObject*, i);
4941 if (t->byref)
4942 *has_byref_nullables = TRUE;
4943 } else {
4944 /* MS seems to create the objects if a null is passed in */
4945 gboolean was_null = FALSE;
4946 if (!mono_array_get (params, MonoObject*, i)) {
4947 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4948 return_val_if_nok (error, NULL);
4949 mono_array_setref (params, i, o);
4950 was_null = TRUE;
4951 }
4952
4953 if (t->byref) {
4954 /*
4955 * We can't pass the unboxed vtype byref to the callee, since
4956 * that would mean the callee would be able to modify boxed
4957 * primitive types. So we (and MS) make a copy of the boxed
4958 * object, pass that to the callee, and replace the original
4959 * boxed object in the arg array with the copy.
4960 */
4961 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4962 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4963 return_val_if_nok (error, NULL);
4964 mono_array_setref (params, i, copy);
4965 }
4966
4967 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4968 if (!t->byref && was_null)
4969 mono_array_setref (params, i, NULL);
4970 }
4971 break;
4972 case MONO_TYPE_STRING:
4973 case MONO_TYPE_OBJECT:
4974 case MONO_TYPE_CLASS:
4975 case MONO_TYPE_ARRAY:
4976 case MONO_TYPE_SZARRAY:
4977 if (t->byref)
4978 result = mono_array_addr (params, MonoObject*, i);
4979 // FIXME: I need to check this code path
4980 else
4981 result = mono_array_get (params, MonoObject*, i);
4982 break;
4983 case MONO_TYPE_GENERICINST:
4984 if (t->byref)
4985 t = &t->data.generic_class->container_class->this_arg;
4986 else
4987 t = &t->data.generic_class->container_class->byval_arg;
4988 goto again;
4989 case MONO_TYPE_PTR: {
4990 MonoObject *arg;
4991
4992 /* The argument should be an IntPtr */
4993 arg = mono_array_get (params, MonoObject*, i);
4994 if (arg == NULL) {
4995 result = NULL;
4996 } else {
4997 g_assert (arg->vtable->klass == mono_defaults.int_class);
4998 result = ((MonoIntPtr*)arg)->m_value;
4999 }
5000 break;
5001 }
5002 default:
5003 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
5004 }
5005 return result;
5006 }
5007 /**
5008 * mono_runtime_invoke_array:
5009 * \param method method to invoke
5010 * \param obj object instance
5011 * \param params arguments to the method
5012 * \param exc exception information.
5013 * Invokes the method represented by \p method on the object \p obj.
5014 *
5015 * \p obj is the \c this pointer, it should be NULL for static
5016 * methods, a \c MonoObject* for object instances and a pointer to
5017 * the value type for value types.
5018 *
5019 * The \p params array contains the arguments to the method with the
5020 * same convention: \c MonoObject* pointers for object instances and
5021 * pointers to the value type otherwise. The \c _invoke_array
5022 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5023 * in this case the value types are boxed inside the
5024 * respective reference representation.
5025 *
5026 * From unmanaged code you'll usually use the
5027 * mono_runtime_invoke_checked() variant.
5028 *
5029 * Note that this function doesn't handle virtual methods for
5030 * you, it will exec the exact method you pass: we still need to
5031 * expose a function to lookup the derived class implementation
5032 * of a virtual method (there are examples of this in the code,
5033 * though).
5034 *
5035 * You can pass NULL as the \p exc argument if you don't want to
5036 * catch exceptions, otherwise, \c *exc will be set to the exception
5037 * thrown, if any. if an exception is thrown, you can't use the
5038 * \c MonoObject* result from the function.
5039 *
5040 * If the method returns a value type, it is boxed in an object
5041 * reference.
5042 */
5043 MonoObject*
mono_runtime_invoke_array(MonoMethod * method,void * obj,MonoArray * params,MonoObject ** exc)5044 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5045 MonoObject **exc)
5046 {
5047 MonoError error;
5048 if (exc) {
5049 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
5050 if (*exc) {
5051 mono_error_cleanup (&error);
5052 return NULL;
5053 } else {
5054 if (!is_ok (&error))
5055 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
5056 return result;
5057 }
5058 } else {
5059 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
5060 mono_error_raise_exception_deprecated (&error); /* OK to throw, external only without a good alternative */
5061 return result;
5062 }
5063 }
5064
5065 /**
5066 * mono_runtime_invoke_array_checked:
5067 * \param method method to invoke
5068 * \param obj object instance
5069 * \param params arguments to the method
5070 * \param error set on failure.
5071 * Invokes the method represented by \p method on the object \p obj.
5072 *
5073 * \p obj is the \c this pointer, it should be NULL for static
5074 * methods, a \c MonoObject* for object instances and a pointer to
5075 * the value type for value types.
5076 *
5077 * The \p params array contains the arguments to the method with the
5078 * same convention: \c MonoObject* pointers for object instances and
5079 * pointers to the value type otherwise. The \c _invoke_array
5080 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
5081 * in this case the value types are boxed inside the
5082 * respective reference representation.
5083 *
5084 * From unmanaged code you'll usually use the
5085 * mono_runtime_invoke_checked() variant.
5086 *
5087 * Note that this function doesn't handle virtual methods for
5088 * you, it will exec the exact method you pass: we still need to
5089 * expose a function to lookup the derived class implementation
5090 * of a virtual method (there are examples of this in the code,
5091 * though).
5092 *
5093 * On failure or exception, \p error will be set. In that case, you
5094 * can't use the \c MonoObject* result from the function.
5095 *
5096 * If the method returns a value type, it is boxed in an object
5097 * reference.
5098 */
5099 MonoObject*
mono_runtime_invoke_array_checked(MonoMethod * method,void * obj,MonoArray * params,MonoError * error)5100 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
5101 MonoError *error)
5102 {
5103 error_init (error);
5104 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5105 }
5106
5107 /**
5108 * mono_runtime_try_invoke_array:
5109 * \param method method to invoke
5110 * \param obj object instance
5111 * \param params arguments to the method
5112 * \param exc exception information.
5113 * \param error set on failure.
5114 * Invokes the method represented by \p method on the object \p obj.
5115 *
5116 * \p obj is the \c this pointer, it should be NULL for static
5117 * methods, a \c MonoObject* for object instances and a pointer to
5118 * the value type for value types.
5119 *
5120 * The \p params array contains the arguments to the method with the
5121 * same convention: \c MonoObject* pointers for object instances and
5122 * pointers to the value type otherwise. The \c _invoke_array
5123 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5124 * in this case the value types are boxed inside the
5125 * respective reference representation.
5126 *
5127 * From unmanaged code you'll usually use the
5128 * mono_runtime_invoke_checked() variant.
5129 *
5130 * Note that this function doesn't handle virtual methods for
5131 * you, it will exec the exact method you pass: we still need to
5132 * expose a function to lookup the derived class implementation
5133 * of a virtual method (there are examples of this in the code,
5134 * though).
5135 *
5136 * You can pass NULL as the \p exc argument if you don't want to catch
5137 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
5138 * any. On other failures, \p error will be set. If an exception is
5139 * thrown or there's an error, you can't use the \c MonoObject* result
5140 * from the function.
5141 *
5142 * If the method returns a value type, it is boxed in an object
5143 * reference.
5144 */
5145 MonoObject*
mono_runtime_try_invoke_array(MonoMethod * method,void * obj,MonoArray * params,MonoObject ** exc,MonoError * error)5146 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5147 MonoObject **exc, MonoError *error)
5148 {
5149 MONO_REQ_GC_UNSAFE_MODE;
5150
5151 error_init (error);
5152
5153 MonoMethodSignature *sig = mono_method_signature (method);
5154 gpointer *pa = NULL;
5155 MonoObject *res;
5156 int i;
5157 gboolean has_byref_nullables = FALSE;
5158
5159 if (NULL != params) {
5160 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5161 for (i = 0; i < mono_array_length (params); i++) {
5162 MonoType *t = sig->params [i];
5163 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5164 return_val_if_nok (error, NULL);
5165 }
5166 }
5167
5168 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5169 void *o = obj;
5170
5171 if (mono_class_is_nullable (method->klass)) {
5172 /* Need to create a boxed vtype instead */
5173 g_assert (!obj);
5174
5175 if (!params)
5176 return NULL;
5177 else {
5178 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5179 }
5180 }
5181
5182 if (!obj) {
5183 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5184 mono_error_assert_ok (error);
5185 g_assert (obj); /*maybe we should raise a TLE instead?*/
5186 #ifndef DISABLE_REMOTING
5187 if (mono_object_is_transparent_proxy (obj)) {
5188 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5189 }
5190 #endif
5191 if (method->klass->valuetype)
5192 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5193 else
5194 o = obj;
5195 } else if (method->klass->valuetype) {
5196 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5197 return_val_if_nok (error, NULL);
5198 }
5199
5200 if (exc) {
5201 mono_runtime_try_invoke (method, o, pa, exc, error);
5202 } else {
5203 mono_runtime_invoke_checked (method, o, pa, error);
5204 }
5205
5206 return (MonoObject *)obj;
5207 } else {
5208 if (mono_class_is_nullable (method->klass)) {
5209 MonoObject *nullable;
5210
5211 /* Convert the unboxed vtype into a Nullable structure */
5212 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5213 return_val_if_nok (error, NULL);
5214
5215 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5216 return_val_if_nok (error, NULL);
5217 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5218 obj = mono_object_unbox (nullable);
5219 }
5220
5221 /* obj must be already unboxed if needed */
5222 if (exc) {
5223 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5224 } else {
5225 res = mono_runtime_invoke_checked (method, obj, pa, error);
5226 }
5227 return_val_if_nok (error, NULL);
5228
5229 if (sig->ret->type == MONO_TYPE_PTR) {
5230 MonoClass *pointer_class;
5231 static MonoMethod *box_method;
5232 void *box_args [2];
5233 MonoObject *box_exc;
5234
5235 /*
5236 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5237 * convert it to a Pointer object.
5238 */
5239 pointer_class = mono_class_get_pointer_class ();
5240 if (!box_method)
5241 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5242
5243 g_assert (res->vtable->klass == mono_defaults.int_class);
5244 box_args [0] = ((MonoIntPtr*)res)->m_value;
5245 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5246 return_val_if_nok (error, NULL);
5247
5248 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5249 g_assert (box_exc == NULL);
5250 mono_error_assert_ok (error);
5251 }
5252
5253 if (has_byref_nullables) {
5254 /*
5255 * The runtime invoke wrapper already converted byref nullables back,
5256 * and stored them in pa, we just need to copy them back to the
5257 * managed array.
5258 */
5259 for (i = 0; i < mono_array_length (params); i++) {
5260 MonoType *t = sig->params [i];
5261
5262 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5263 mono_array_setref (params, i, pa [i]);
5264 }
5265 }
5266
5267 return res;
5268 }
5269 }
5270
5271 /**
5272 * mono_object_new:
5273 * \param klass the class of the object that we want to create
5274 * \returns a newly created object whose definition is
5275 * looked up using \p klass. This will not invoke any constructors,
5276 * so the consumer of this routine has to invoke any constructors on
5277 * its own to initialize the object.
5278 *
5279 * It returns NULL on failure.
5280 */
5281 MonoObject *
mono_object_new(MonoDomain * domain,MonoClass * klass)5282 mono_object_new (MonoDomain *domain, MonoClass *klass)
5283 {
5284 MONO_REQ_GC_UNSAFE_MODE;
5285
5286 MonoError error;
5287
5288 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5289
5290 mono_error_cleanup (&error);
5291 return result;
5292 }
5293
5294 MonoObject *
ves_icall_object_new(MonoDomain * domain,MonoClass * klass)5295 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5296 {
5297 MONO_REQ_GC_UNSAFE_MODE;
5298
5299 MonoError error;
5300
5301 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5302
5303 mono_error_set_pending_exception (&error);
5304 return result;
5305 }
5306
5307 /**
5308 * mono_object_new_checked:
5309 * \param klass the class of the object that we want to create
5310 * \param error set on error
5311 * \returns a newly created object whose definition is
5312 * looked up using \p klass. This will not invoke any constructors,
5313 * so the consumer of this routine has to invoke any constructors on
5314 * its own to initialize the object.
5315 *
5316 * It returns NULL on failure and sets \p error.
5317 */
5318 MonoObject *
mono_object_new_checked(MonoDomain * domain,MonoClass * klass,MonoError * error)5319 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5320 {
5321 MONO_REQ_GC_UNSAFE_MODE;
5322
5323 MonoVTable *vtable;
5324
5325 vtable = mono_class_vtable_full (domain, klass, error);
5326 if (!is_ok (error))
5327 return NULL;
5328
5329 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5330 return o;
5331 }
5332
5333 /**
5334 * mono_object_new_pinned:
5335 *
5336 * Same as mono_object_new, but the returned object will be pinned.
5337 * For SGEN, these objects will only be freed at appdomain unload.
5338 */
5339 MonoObject *
mono_object_new_pinned(MonoDomain * domain,MonoClass * klass,MonoError * error)5340 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5341 {
5342 MONO_REQ_GC_UNSAFE_MODE;
5343
5344 MonoVTable *vtable;
5345
5346 error_init (error);
5347
5348 vtable = mono_class_vtable (domain, klass);
5349 g_assert (vtable); /* FIXME don't swallow the error */
5350
5351 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5352
5353 if (G_UNLIKELY (!o))
5354 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5355 else if (G_UNLIKELY (vtable->klass->has_finalize))
5356 mono_object_register_finalizer (o);
5357
5358 return o;
5359 }
5360
5361 /**
5362 * mono_object_new_specific:
5363 * \param vtable the vtable of the object that we want to create
5364 * \returns A newly created object with class and domain specified
5365 * by \p vtable
5366 */
5367 MonoObject *
mono_object_new_specific(MonoVTable * vtable)5368 mono_object_new_specific (MonoVTable *vtable)
5369 {
5370 MonoError error;
5371 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5372 mono_error_cleanup (&error);
5373
5374 return o;
5375 }
5376
5377 MonoObject *
mono_object_new_specific_checked(MonoVTable * vtable,MonoError * error)5378 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5379 {
5380 MONO_REQ_GC_UNSAFE_MODE;
5381
5382 MonoObject *o;
5383
5384 error_init (error);
5385
5386 /* check for is_com_object for COM Interop */
5387 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5388 {
5389 gpointer pa [1];
5390 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5391
5392 if (im == NULL) {
5393 MonoClass *klass = mono_class_get_activation_services_class ();
5394
5395 if (!klass->inited)
5396 mono_class_init (klass);
5397
5398 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5399 if (!im) {
5400 mono_error_set_not_supported (error, "Linked away.");
5401 return NULL;
5402 }
5403 vtable->domain->create_proxy_for_type_method = im;
5404 }
5405
5406 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5407 if (!mono_error_ok (error))
5408 return NULL;
5409
5410 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5411 if (!mono_error_ok (error))
5412 return NULL;
5413
5414 if (o != NULL)
5415 return o;
5416 }
5417
5418 return mono_object_new_alloc_specific_checked (vtable, error);
5419 }
5420
5421 MonoObject *
ves_icall_object_new_specific(MonoVTable * vtable)5422 ves_icall_object_new_specific (MonoVTable *vtable)
5423 {
5424 MonoError error;
5425 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5426 mono_error_set_pending_exception (&error);
5427
5428 return o;
5429 }
5430
5431 /**
5432 * mono_object_new_alloc_specific:
5433 * \param vtable virtual table for the object.
5434 * This function allocates a new \c MonoObject with the type derived
5435 * from the \p vtable information. If the class of this object has a
5436 * finalizer, then the object will be tracked for finalization.
5437 *
5438 * This method might raise an exception on errors. Use the
5439 * \c mono_object_new_fast_checked method if you want to manually raise
5440 * the exception.
5441 *
5442 * \returns the allocated object.
5443 */
5444 MonoObject *
mono_object_new_alloc_specific(MonoVTable * vtable)5445 mono_object_new_alloc_specific (MonoVTable *vtable)
5446 {
5447 MonoError error;
5448 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5449 mono_error_cleanup (&error);
5450
5451 return o;
5452 }
5453
5454 /**
5455 * mono_object_new_alloc_specific_checked:
5456 * \param vtable virtual table for the object.
5457 * \param error holds the error return value.
5458 *
5459 * This function allocates a new \c MonoObject with the type derived
5460 * from the \p vtable information. If the class of this object has a
5461 * finalizer, then the object will be tracked for finalization.
5462 *
5463 * If there is not enough memory, the \p error parameter will be set
5464 * and will contain a user-visible message with the amount of bytes
5465 * that were requested.
5466 *
5467 * \returns the allocated object, or NULL if there is not enough memory
5468 */
5469 MonoObject *
mono_object_new_alloc_specific_checked(MonoVTable * vtable,MonoError * error)5470 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5471 {
5472 MONO_REQ_GC_UNSAFE_MODE;
5473
5474 MonoObject *o;
5475
5476 error_init (error);
5477
5478 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5479
5480 if (G_UNLIKELY (!o))
5481 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5482 else if (G_UNLIKELY (vtable->klass->has_finalize || vtable->klass->has_weak_fields)) {
5483 if (vtable->klass->has_finalize)
5484 mono_object_register_finalizer (o);
5485 if (vtable->klass->has_weak_fields)
5486 mono_gc_register_obj_with_weak_fields (o);
5487 }
5488
5489 return o;
5490 }
5491
5492 /**
5493 * mono_object_new_fast:
5494 * \param vtable virtual table for the object.
5495 *
5496 * This function allocates a new \c MonoObject with the type derived
5497 * from the \p vtable information. The returned object is not tracked
5498 * for finalization. If your object implements a finalizer, you should
5499 * use \c mono_object_new_alloc_specific instead.
5500 *
5501 * This method might raise an exception on errors. Use the
5502 * \c mono_object_new_fast_checked method if you want to manually raise
5503 * the exception.
5504 *
5505 * \returns the allocated object.
5506 */
5507 MonoObject*
mono_object_new_fast(MonoVTable * vtable)5508 mono_object_new_fast (MonoVTable *vtable)
5509 {
5510 MonoError error;
5511 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5512 mono_error_cleanup (&error);
5513
5514 return o;
5515 }
5516
5517 /**
5518 * mono_object_new_fast_checked:
5519 * \param vtable virtual table for the object.
5520 * \param error holds the error return value.
5521 *
5522 * This function allocates a new \c MonoObject with the type derived
5523 * from the \p vtable information. The returned object is not tracked
5524 * for finalization. If your object implements a finalizer, you should
5525 * use \c mono_object_new_alloc_specific_checked instead.
5526 *
5527 * If there is not enough memory, the \p error parameter will be set
5528 * and will contain a user-visible message with the amount of bytes
5529 * that were requested.
5530 *
5531 * \returns the allocated object, or NULL if there is not enough memory
5532 */
5533 MonoObject*
mono_object_new_fast_checked(MonoVTable * vtable,MonoError * error)5534 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5535 {
5536 MONO_REQ_GC_UNSAFE_MODE;
5537
5538 MonoObject *o;
5539
5540 error_init (error);
5541
5542 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5543
5544 if (G_UNLIKELY (!o))
5545 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5546
5547 return o;
5548 }
5549
5550 MonoObject*
mono_object_new_mature(MonoVTable * vtable,MonoError * error)5551 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5552 {
5553 MONO_REQ_GC_UNSAFE_MODE;
5554
5555 MonoObject *o;
5556
5557 error_init (error);
5558
5559 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5560
5561 if (G_UNLIKELY (!o))
5562 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5563 else if (G_UNLIKELY (vtable->klass->has_finalize))
5564 mono_object_register_finalizer (o);
5565
5566 return o;
5567 }
5568
5569 /**
5570 * mono_object_new_from_token:
5571 * \param image Context where the type_token is hosted
5572 * \param token a token of the type that we want to create
5573 * \returns A newly created object whose definition is
5574 * looked up using \p token in the \p image image
5575 */
5576 MonoObject *
mono_object_new_from_token(MonoDomain * domain,MonoImage * image,guint32 token)5577 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5578 {
5579 MONO_REQ_GC_UNSAFE_MODE;
5580
5581 MonoError error;
5582 MonoObject *result;
5583 MonoClass *klass;
5584
5585 klass = mono_class_get_checked (image, token, &error);
5586 mono_error_assert_ok (&error);
5587
5588 result = mono_object_new_checked (domain, klass, &error);
5589
5590 mono_error_cleanup (&error);
5591 return result;
5592
5593 }
5594
5595
5596 /**
5597 * mono_object_clone:
5598 * \param obj the object to clone
5599 * \returns A newly created object who is a shallow copy of \p obj
5600 */
5601 MonoObject *
mono_object_clone(MonoObject * obj)5602 mono_object_clone (MonoObject *obj)
5603 {
5604 MonoError error;
5605 MonoObject *o = mono_object_clone_checked (obj, &error);
5606 mono_error_cleanup (&error);
5607
5608 return o;
5609 }
5610
5611 MonoObject *
mono_object_clone_checked(MonoObject * obj,MonoError * error)5612 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5613 {
5614 MONO_REQ_GC_UNSAFE_MODE;
5615
5616 MonoObject *o;
5617 int size;
5618
5619 error_init (error);
5620
5621 size = obj->vtable->klass->instance_size;
5622
5623 if (obj->vtable->klass->rank)
5624 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5625
5626 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5627
5628 if (G_UNLIKELY (!o)) {
5629 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5630 return NULL;
5631 }
5632
5633 /* If the object doesn't contain references this will do a simple memmove. */
5634 mono_gc_wbarrier_object_copy (o, obj);
5635
5636 if (obj->vtable->klass->has_finalize)
5637 mono_object_register_finalizer (o);
5638 return o;
5639 }
5640
5641 /**
5642 * mono_array_full_copy:
5643 * \param src source array to copy
5644 * \param dest destination array
5645 * Copies the content of one array to another with exactly the same type and size.
5646 */
5647 void
mono_array_full_copy(MonoArray * src,MonoArray * dest)5648 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5649 {
5650 MONO_REQ_GC_UNSAFE_MODE;
5651
5652 uintptr_t size;
5653 MonoClass *klass = src->obj.vtable->klass;
5654
5655 g_assert (klass == dest->obj.vtable->klass);
5656
5657 size = mono_array_length (src);
5658 g_assert (size == mono_array_length (dest));
5659 size *= mono_array_element_size (klass);
5660
5661 array_full_copy_unchecked_size (src, dest, klass, size);
5662 }
5663
5664 static void
array_full_copy_unchecked_size(MonoArray * src,MonoArray * dest,MonoClass * klass,uintptr_t size)5665 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5666 {
5667 if (mono_gc_is_moving ()) {
5668 if (klass->element_class->valuetype) {
5669 if (klass->element_class->has_references)
5670 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5671 else
5672 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5673 } else {
5674 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5675 }
5676 } else {
5677 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5678 }
5679 }
5680
5681 /**
5682 * mono_array_clone_in_domain:
5683 * \param domain the domain in which the array will be cloned into
5684 * \param array the array to clone
5685 * \param error set on error
5686 * This routine returns a copy of the array that is hosted on the
5687 * specified \c MonoDomain. On failure returns NULL and sets \p error.
5688 */
5689 MonoArrayHandle
mono_array_clone_in_domain(MonoDomain * domain,MonoArrayHandle array_handle,MonoError * error)5690 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5691 {
5692 MONO_REQ_GC_UNSAFE_MODE;
5693
5694 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5695 uintptr_t size = 0;
5696 MonoClass *klass = mono_handle_class (array_handle);
5697
5698 error_init (error);
5699
5700 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5701 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5702
5703 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5704 MonoArrayHandle o;
5705 if (array_bounds == NULL) {
5706 size = mono_array_handle_length (array_handle);
5707 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5708 goto_if_nok (error, leave);
5709 size *= mono_array_element_size (klass);
5710 } else {
5711 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5712 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5713 size = mono_array_element_size (klass);
5714 for (int i = 0; i < klass->rank; ++i) {
5715 sizes [i] = array_bounds [i].length;
5716 size *= array_bounds [i].length;
5717 lower_bounds [i] = array_bounds [i].lower_bound;
5718 }
5719 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5720 goto_if_nok (error, leave);
5721 }
5722
5723 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5724 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5725 mono_gchandle_free (dst_handle);
5726
5727 MONO_HANDLE_ASSIGN (result, o);
5728
5729 leave:
5730 mono_gchandle_free (src_handle);
5731 return result;
5732 }
5733
5734 /**
5735 * mono_array_clone:
5736 * \param array the array to clone
5737 * \returns A newly created array who is a shallow copy of \p array
5738 */
5739 MonoArray*
mono_array_clone(MonoArray * array)5740 mono_array_clone (MonoArray *array)
5741 {
5742 MONO_REQ_GC_UNSAFE_MODE;
5743
5744 MonoError error;
5745 MonoArray *result = mono_array_clone_checked (array, &error);
5746 mono_error_cleanup (&error);
5747 return result;
5748 }
5749
5750 /**
5751 * mono_array_clone_checked:
5752 * \param array the array to clone
5753 * \param error set on error
5754 * \returns A newly created array who is a shallow copy of \p array. On
5755 * failure returns NULL and sets \p error.
5756 */
5757 MonoArray*
mono_array_clone_checked(MonoArray * array_raw,MonoError * error)5758 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5759 {
5760 MONO_REQ_GC_UNSAFE_MODE;
5761 HANDLE_FUNCTION_ENTER ();
5762 /* FIXME: callers of mono_array_clone_checked should use handles */
5763 error_init (error);
5764 MONO_HANDLE_DCL (MonoArray, array);
5765 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5766 HANDLE_FUNCTION_RETURN_OBJ (result);
5767 }
5768
5769 /* helper macros to check for overflow when calculating the size of arrays */
5770 #ifdef MONO_BIG_ARRAYS
5771 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5772 #define MYGUINT_MAX MYGUINT64_MAX
5773 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5774 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5775 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5776 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5777 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5778 #else
5779 #define MYGUINT32_MAX 4294967295U
5780 #define MYGUINT_MAX MYGUINT32_MAX
5781 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5782 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5783 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5784 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5785 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5786 #endif
5787
5788 gboolean
mono_array_calc_byte_len(MonoClass * klass,uintptr_t len,uintptr_t * res)5789 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5790 {
5791 MONO_REQ_GC_NEUTRAL_MODE;
5792
5793 uintptr_t byte_len;
5794
5795 byte_len = mono_array_element_size (klass);
5796 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5797 return FALSE;
5798 byte_len *= len;
5799 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5800 return FALSE;
5801 byte_len += MONO_SIZEOF_MONO_ARRAY;
5802
5803 *res = byte_len;
5804
5805 return TRUE;
5806 }
5807
5808 /**
5809 * mono_array_new_full:
5810 * \param domain domain where the object is created
5811 * \param array_class array class
5812 * \param lengths lengths for each dimension in the array
5813 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5814 * This routine creates a new array object with the given dimensions,
5815 * lower bounds and type.
5816 */
5817 MonoArray*
mono_array_new_full(MonoDomain * domain,MonoClass * array_class,uintptr_t * lengths,intptr_t * lower_bounds)5818 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5819 {
5820 MonoError error;
5821 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5822 mono_error_cleanup (&error);
5823
5824 return array;
5825 }
5826
5827 MonoArray*
mono_array_new_full_checked(MonoDomain * domain,MonoClass * array_class,uintptr_t * lengths,intptr_t * lower_bounds,MonoError * error)5828 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5829 {
5830 MONO_REQ_GC_UNSAFE_MODE;
5831
5832 uintptr_t byte_len = 0, len, bounds_size;
5833 MonoObject *o;
5834 MonoArray *array;
5835 MonoArrayBounds *bounds;
5836 MonoVTable *vtable;
5837 int i;
5838
5839 error_init (error);
5840
5841 if (!array_class->inited)
5842 mono_class_init (array_class);
5843
5844 len = 1;
5845
5846 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5847 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5848 len = lengths [0];
5849 if (len > MONO_ARRAY_MAX_INDEX) {
5850 mono_error_set_generic_error (error, "System", "OverflowException", "");
5851 return NULL;
5852 }
5853 bounds_size = 0;
5854 } else {
5855 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5856
5857 for (i = 0; i < array_class->rank; ++i) {
5858 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5859 mono_error_set_generic_error (error, "System", "OverflowException", "");
5860 return NULL;
5861 }
5862 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5863 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5864 return NULL;
5865 }
5866 len *= lengths [i];
5867 }
5868 }
5869
5870 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5871 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5872 return NULL;
5873 }
5874
5875 if (bounds_size) {
5876 /* align */
5877 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5878 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5879 return NULL;
5880 }
5881 byte_len = (byte_len + 3) & ~3;
5882 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5883 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5884 return NULL;
5885 }
5886 byte_len += bounds_size;
5887 }
5888 /*
5889 * Following three lines almost taken from mono_object_new ():
5890 * they need to be kept in sync.
5891 */
5892 vtable = mono_class_vtable_full (domain, array_class, error);
5893 return_val_if_nok (error, NULL);
5894
5895 if (bounds_size)
5896 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5897 else
5898 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5899
5900 if (G_UNLIKELY (!o)) {
5901 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5902 return NULL;
5903 }
5904
5905 array = (MonoArray*)o;
5906
5907 bounds = array->bounds;
5908
5909 if (bounds_size) {
5910 for (i = 0; i < array_class->rank; ++i) {
5911 bounds [i].length = lengths [i];
5912 if (lower_bounds)
5913 bounds [i].lower_bound = lower_bounds [i];
5914 }
5915 }
5916
5917 return array;
5918 }
5919
5920 /**
5921 * mono_array_new:
5922 * \param domain domain where the object is created
5923 * \param eclass element class
5924 * \param n number of array elements
5925 * This routine creates a new szarray with \p n elements of type \p eclass.
5926 */
5927 MonoArray *
mono_array_new(MonoDomain * domain,MonoClass * eclass,uintptr_t n)5928 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5929 {
5930 MONO_REQ_GC_UNSAFE_MODE;
5931
5932 MonoError error;
5933 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5934 mono_error_cleanup (&error);
5935 return result;
5936 }
5937
5938 /**
5939 * mono_array_new_checked:
5940 * \param domain domain where the object is created
5941 * \param eclass element class
5942 * \param n number of array elements
5943 * \param error set on error
5944 * This routine creates a new szarray with \p n elements of type \p eclass.
5945 * On failure returns NULL and sets \p error.
5946 */
5947 MonoArray *
mono_array_new_checked(MonoDomain * domain,MonoClass * eclass,uintptr_t n,MonoError * error)5948 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5949 {
5950 MonoClass *ac;
5951
5952 error_init (error);
5953
5954 ac = mono_array_class_get (eclass, 1);
5955 g_assert (ac);
5956
5957 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5958 return_val_if_nok (error, NULL);
5959
5960 return mono_array_new_specific_checked (vtable, n, error);
5961 }
5962
5963 MonoArray*
ves_icall_array_new(MonoDomain * domain,MonoClass * eclass,uintptr_t n)5964 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5965 {
5966 MonoError error;
5967 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5968 mono_error_set_pending_exception (&error);
5969
5970 return arr;
5971 }
5972
5973 /**
5974 * mono_array_new_specific:
5975 * \param vtable a vtable in the appropriate domain for an initialized class
5976 * \param n number of array elements
5977 * This routine is a fast alternative to \c mono_array_new for code which
5978 * can be sure about the domain it operates in.
5979 */
5980 MonoArray *
mono_array_new_specific(MonoVTable * vtable,uintptr_t n)5981 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5982 {
5983 MonoError error;
5984 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5985 mono_error_cleanup (&error);
5986
5987 return arr;
5988 }
5989
5990 MonoArray*
mono_array_new_specific_checked(MonoVTable * vtable,uintptr_t n,MonoError * error)5991 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5992 {
5993 MONO_REQ_GC_UNSAFE_MODE;
5994
5995 MonoObject *o;
5996 uintptr_t byte_len;
5997
5998 error_init (error);
5999
6000 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
6001 mono_error_set_generic_error (error, "System", "OverflowException", "");
6002 return NULL;
6003 }
6004
6005 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
6006 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6007 return NULL;
6008 }
6009 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
6010
6011 if (G_UNLIKELY (!o)) {
6012 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
6013 return NULL;
6014 }
6015
6016 return (MonoArray*)o;
6017 }
6018
6019 MonoArray*
ves_icall_array_new_specific(MonoVTable * vtable,uintptr_t n)6020 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
6021 {
6022 MonoError error;
6023 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
6024 mono_error_set_pending_exception (&error);
6025
6026 return arr;
6027 }
6028
6029 /**
6030 * mono_string_empty_wrapper:
6031 *
6032 * Returns: The same empty string instance as the managed string.Empty
6033 */
6034 MonoString*
mono_string_empty_wrapper(void)6035 mono_string_empty_wrapper (void)
6036 {
6037 MonoDomain *domain = mono_domain_get ();
6038 return mono_string_empty (domain);
6039 }
6040
6041 /**
6042 * mono_string_empty:
6043 *
6044 * Returns: The same empty string instance as the managed string.Empty
6045 */
6046 MonoString*
mono_string_empty(MonoDomain * domain)6047 mono_string_empty (MonoDomain *domain)
6048 {
6049 g_assert (domain);
6050 g_assert (domain->empty_string);
6051 return domain->empty_string;
6052 }
6053
6054 /**
6055 * mono_string_new_utf16:
6056 * \param text a pointer to an utf16 string
6057 * \param len the length of the string
6058 * \returns A newly created string object which contains \p text.
6059 */
6060 MonoString *
mono_string_new_utf16(MonoDomain * domain,const guint16 * text,gint32 len)6061 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6062 {
6063 MONO_REQ_GC_UNSAFE_MODE;
6064
6065 MonoError error;
6066 MonoString *res = NULL;
6067 res = mono_string_new_utf16_checked (domain, text, len, &error);
6068 mono_error_cleanup (&error);
6069
6070 return res;
6071 }
6072
6073 /**
6074 * mono_string_new_utf16_checked:
6075 * \param text a pointer to an utf16 string
6076 * \param len the length of the string
6077 * \param error written on error.
6078 * \returns A newly created string object which contains \p text.
6079 * On error, returns NULL and sets \p error.
6080 */
6081 MonoString *
mono_string_new_utf16_checked(MonoDomain * domain,const guint16 * text,gint32 len,MonoError * error)6082 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6083 {
6084 MONO_REQ_GC_UNSAFE_MODE;
6085
6086 MonoString *s;
6087
6088 error_init (error);
6089
6090 s = mono_string_new_size_checked (domain, len, error);
6091 if (s != NULL)
6092 memcpy (mono_string_chars (s), text, len * 2);
6093
6094 return s;
6095 }
6096
6097 /**
6098 * mono_string_new_utf16_handle:
6099 * \param text a pointer to an utf16 string
6100 * \param len the length of the string
6101 * \param error written on error.
6102 * \returns A newly created string object which contains \p text.
6103 * On error, returns NULL and sets \p error.
6104 */
6105 MonoStringHandle
mono_string_new_utf16_handle(MonoDomain * domain,const guint16 * text,gint32 len,MonoError * error)6106 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6107 {
6108 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6109 }
6110
6111 /**
6112 * mono_string_new_utf32_checked:
6113 * \param text a pointer to an utf32 string
6114 * \param len the length of the string
6115 * \param error set on failure.
6116 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6117 */
6118 static MonoString *
mono_string_new_utf32_checked(MonoDomain * domain,const mono_unichar4 * text,gint32 len,MonoError * error)6119 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6120 {
6121 MONO_REQ_GC_UNSAFE_MODE;
6122
6123 MonoString *s;
6124 mono_unichar2 *utf16_output = NULL;
6125 gint32 utf16_len = 0;
6126 GError *gerror = NULL;
6127 glong items_written;
6128
6129 error_init (error);
6130 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6131
6132 if (gerror)
6133 g_error_free (gerror);
6134
6135 while (utf16_output [utf16_len]) utf16_len++;
6136
6137 s = mono_string_new_size_checked (domain, utf16_len, error);
6138 return_val_if_nok (error, NULL);
6139
6140 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6141
6142 g_free (utf16_output);
6143
6144 return s;
6145 }
6146
6147 /**
6148 * mono_string_new_utf32:
6149 * \param text a pointer to a UTF-32 string
6150 * \param len the length of the string
6151 * \returns A newly created string object which contains \p text.
6152 */
6153 MonoString *
mono_string_new_utf32(MonoDomain * domain,const mono_unichar4 * text,gint32 len)6154 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6155 {
6156 MonoError error;
6157 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6158 mono_error_cleanup (&error);
6159 return result;
6160 }
6161
6162 /**
6163 * mono_string_new_size:
6164 * \param text a pointer to a UTF-16 string
6165 * \param len the length of the string
6166 * \returns A newly created string object of \p len
6167 */
6168 MonoString *
mono_string_new_size(MonoDomain * domain,gint32 len)6169 mono_string_new_size (MonoDomain *domain, gint32 len)
6170 {
6171 MonoError error;
6172 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6173 mono_error_cleanup (&error);
6174
6175 return str;
6176 }
6177
6178 MonoString *
mono_string_new_size_checked(MonoDomain * domain,gint32 len,MonoError * error)6179 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6180 {
6181 MONO_REQ_GC_UNSAFE_MODE;
6182
6183 MonoString *s;
6184 MonoVTable *vtable;
6185 size_t size;
6186
6187 error_init (error);
6188
6189 /* check for overflow */
6190 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6191 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6192 return NULL;
6193 }
6194
6195 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6196 g_assert (size > 0);
6197
6198 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6199 g_assert (vtable);
6200
6201 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6202
6203 if (G_UNLIKELY (!s)) {
6204 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6205 return NULL;
6206 }
6207
6208 return s;
6209 }
6210
6211 /**
6212 * mono_string_new_len:
6213 * \param text a pointer to an utf8 string
6214 * \param length number of bytes in \p text to consider
6215 * \returns A newly created string object which contains \p text.
6216 */
6217 MonoString*
mono_string_new_len(MonoDomain * domain,const char * text,guint length)6218 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6219 {
6220 MONO_REQ_GC_UNSAFE_MODE;
6221
6222 MonoError error;
6223 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6224 mono_error_cleanup (&error);
6225 return result;
6226 }
6227
6228 /**
6229 * mono_string_new_len_checked:
6230 * \param text a pointer to an utf8 string
6231 * \param length number of bytes in \p text to consider
6232 * \param error set on error
6233 * \returns A newly created string object which contains \p text. On
6234 * failure returns NULL and sets \p error.
6235 */
6236 MonoString*
mono_string_new_len_checked(MonoDomain * domain,const char * text,guint length,MonoError * error)6237 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6238 {
6239 MONO_REQ_GC_UNSAFE_MODE;
6240
6241 error_init (error);
6242
6243 GError *eg_error = NULL;
6244 MonoString *o = NULL;
6245 guint16 *ut = NULL;
6246 glong items_written;
6247
6248 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6249
6250 if (!eg_error)
6251 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6252 else
6253 g_error_free (eg_error);
6254
6255 g_free (ut);
6256
6257 return o;
6258 }
6259
6260 /**
6261 * mono_string_new:
6262 * \param text a pointer to a UTF-8 string
6263 * \deprecated Use \c mono_string_new_checked in new code.
6264 * This function asserts if it cannot allocate a new string.
6265 * \returns A newly created string object which contains \p text.
6266 */
6267 MonoString*
mono_string_new(MonoDomain * domain,const char * text)6268 mono_string_new (MonoDomain *domain, const char *text)
6269 {
6270 MonoError error;
6271 MonoString *res = NULL;
6272 res = mono_string_new_checked (domain, text, &error);
6273 mono_error_assert_ok (&error);
6274 return res;
6275 }
6276
6277 /**
6278 * mono_string_new_checked:
6279 * \param text a pointer to an utf8 string
6280 * \param merror set on error
6281 * \returns A newly created string object which contains \p text.
6282 * On error returns NULL and sets \p merror.
6283 */
6284 MonoString*
mono_string_new_checked(MonoDomain * domain,const char * text,MonoError * error)6285 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6286 {
6287 MONO_REQ_GC_UNSAFE_MODE;
6288
6289 GError *eg_error = NULL;
6290 MonoString *o = NULL;
6291 guint16 *ut;
6292 glong items_written;
6293 int l;
6294
6295 error_init (error);
6296
6297 l = strlen (text);
6298
6299 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6300
6301 if (!eg_error) {
6302 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6303 } else {
6304 mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6305 }
6306
6307 g_free (ut);
6308
6309 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6310 #if 0
6311 gunichar2 *str;
6312 const gchar *end;
6313 int len;
6314 MonoString *o = NULL;
6315
6316 if (!g_utf8_validate (text, -1, &end)) {
6317 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6318 goto leave;
6319 }
6320
6321 len = g_utf8_strlen (text, -1);
6322 o = mono_string_new_size_checked (domain, len, error);
6323 if (!o)
6324 goto leave;
6325 str = mono_string_chars (o);
6326
6327 while (text < end) {
6328 *str++ = g_utf8_get_char (text);
6329 text = g_utf8_next_char (text);
6330 }
6331
6332 leave:
6333 #endif
6334 return o;
6335 }
6336
6337 /**
6338 * mono_string_new_wrapper:
6339 * \param text pointer to UTF-8 characters.
6340 * Helper function to create a string object from \p text in the current domain.
6341 */
6342 MonoString*
mono_string_new_wrapper(const char * text)6343 mono_string_new_wrapper (const char *text)
6344 {
6345 MONO_REQ_GC_UNSAFE_MODE;
6346
6347 MonoDomain *domain = mono_domain_get ();
6348
6349 if (text) {
6350 MonoError error;
6351 MonoString *result = mono_string_new_checked (domain, text, &error);
6352 mono_error_assert_ok (&error);
6353 return result;
6354 }
6355
6356 return NULL;
6357 }
6358
6359 /**
6360 * mono_value_box:
6361 * \param class the class of the value
6362 * \param value a pointer to the unboxed data
6363 * \returns A newly created object which contains \p value.
6364 */
6365 MonoObject *
mono_value_box(MonoDomain * domain,MonoClass * klass,gpointer value)6366 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6367 {
6368 MonoError error;
6369 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6370 mono_error_cleanup (&error);
6371 return result;
6372 }
6373
6374 /**
6375 * mono_value_box_checked:
6376 * \param domain the domain of the new object
6377 * \param class the class of the value
6378 * \param value a pointer to the unboxed data
6379 * \param error set on error
6380 * \returns A newly created object which contains \p value. On failure
6381 * returns NULL and sets \p error.
6382 */
6383 MonoObject *
mono_value_box_checked(MonoDomain * domain,MonoClass * klass,gpointer value,MonoError * error)6384 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6385 {
6386 MONO_REQ_GC_UNSAFE_MODE;
6387 MonoObject *res;
6388 int size;
6389 MonoVTable *vtable;
6390
6391 error_init (error);
6392
6393 g_assert (klass->valuetype);
6394 if (mono_class_is_nullable (klass))
6395 return mono_nullable_box ((guint8 *)value, klass, error);
6396
6397 vtable = mono_class_vtable (domain, klass);
6398 if (!vtable)
6399 return NULL;
6400 size = mono_class_instance_size (klass);
6401 res = mono_object_new_alloc_specific_checked (vtable, error);
6402 return_val_if_nok (error, NULL);
6403
6404 size = size - sizeof (MonoObject);
6405
6406 if (mono_gc_is_moving ()) {
6407 g_assert (size == mono_class_value_size (klass, NULL));
6408 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6409 } else {
6410 #if NO_UNALIGNED_ACCESS
6411 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6412 #else
6413 switch (size) {
6414 case 1:
6415 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6416 break;
6417 case 2:
6418 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6419 break;
6420 case 4:
6421 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6422 break;
6423 case 8:
6424 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6425 break;
6426 default:
6427 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6428 }
6429 #endif
6430 }
6431 if (klass->has_finalize) {
6432 mono_object_register_finalizer (res);
6433 return_val_if_nok (error, NULL);
6434 }
6435 return res;
6436 }
6437
6438 /**
6439 * mono_value_copy:
6440 * \param dest destination pointer
6441 * \param src source pointer
6442 * \param klass a valuetype class
6443 * Copy a valuetype from \p src to \p dest. This function must be used
6444 * when \p klass contains reference fields.
6445 */
6446 void
mono_value_copy(gpointer dest,gpointer src,MonoClass * klass)6447 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6448 {
6449 MONO_REQ_GC_UNSAFE_MODE;
6450
6451 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6452 }
6453
6454 /**
6455 * mono_value_copy_array:
6456 * \param dest destination array
6457 * \param dest_idx index in the \p dest array
6458 * \param src source pointer
6459 * \param count number of items
6460 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
6461 * This function must be used when \p klass contains references fields.
6462 * Overlap is handled.
6463 */
6464 void
mono_value_copy_array(MonoArray * dest,int dest_idx,gpointer src,int count)6465 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6466 {
6467 MONO_REQ_GC_UNSAFE_MODE;
6468
6469 int size = mono_array_element_size (dest->obj.vtable->klass);
6470 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6471 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6472 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6473 }
6474
6475 /**
6476 * mono_object_get_domain:
6477 * \param obj object to query
6478 * \returns the \c MonoDomain where the object is hosted
6479 */
6480 MonoDomain*
mono_object_get_domain(MonoObject * obj)6481 mono_object_get_domain (MonoObject *obj)
6482 {
6483 MONO_REQ_GC_UNSAFE_MODE;
6484
6485 return mono_object_domain (obj);
6486 }
6487
6488 /**
6489 * mono_object_get_class:
6490 * \param obj object to query
6491 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6492 * \returns the \c MonoClass of the object.
6493 */
6494 MonoClass*
mono_object_get_class(MonoObject * obj)6495 mono_object_get_class (MonoObject *obj)
6496 {
6497 MONO_REQ_GC_UNSAFE_MODE;
6498
6499 return mono_object_class (obj);
6500 }
6501 /**
6502 * mono_object_get_size:
6503 * \param o object to query
6504 * \returns the size, in bytes, of \p o
6505 */
6506 guint
mono_object_get_size(MonoObject * o)6507 mono_object_get_size (MonoObject* o)
6508 {
6509 MONO_REQ_GC_UNSAFE_MODE;
6510
6511 MonoClass* klass = mono_object_class (o);
6512 if (klass == mono_defaults.string_class) {
6513 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6514 } else if (o->vtable->rank) {
6515 MonoArray *array = (MonoArray*)o;
6516 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6517 if (array->bounds) {
6518 size += 3;
6519 size &= ~3;
6520 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6521 }
6522 return size;
6523 } else {
6524 return mono_class_instance_size (klass);
6525 }
6526 }
6527
6528 /**
6529 * mono_object_unbox:
6530 * \param obj object to unbox
6531 * \returns a pointer to the start of the valuetype boxed in this
6532 * object.
6533 *
6534 * This method will assert if the object passed is not a valuetype.
6535 */
6536 gpointer
mono_object_unbox(MonoObject * obj)6537 mono_object_unbox (MonoObject *obj)
6538 {
6539 MONO_REQ_GC_UNSAFE_MODE;
6540
6541 /* add assert for valuetypes? */
6542 g_assert (obj->vtable->klass->valuetype);
6543 return ((char*)obj) + sizeof (MonoObject);
6544 }
6545
6546 /**
6547 * mono_object_isinst:
6548 * \param obj an object
6549 * \param klass a pointer to a class
6550 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6551 */
6552 MonoObject *
mono_object_isinst(MonoObject * obj_raw,MonoClass * klass)6553 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6554 {
6555 MONO_REQ_GC_UNSAFE_MODE;
6556
6557 HANDLE_FUNCTION_ENTER ();
6558 MONO_HANDLE_DCL (MonoObject, obj);
6559 MonoError error;
6560 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6561 mono_error_cleanup (&error);
6562 HANDLE_FUNCTION_RETURN_OBJ (result);
6563 }
6564
6565
6566 /**
6567 * mono_object_isinst_checked:
6568 * \param obj an object
6569 * \param klass a pointer to a class
6570 * \param error set on error
6571 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6572 * On failure returns NULL and sets \p error.
6573 */
6574 MonoObject *
mono_object_isinst_checked(MonoObject * obj_raw,MonoClass * klass,MonoError * error)6575 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6576 {
6577 MONO_REQ_GC_UNSAFE_MODE;
6578
6579 HANDLE_FUNCTION_ENTER ();
6580 error_init (error);
6581 MONO_HANDLE_DCL (MonoObject, obj);
6582 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6583 HANDLE_FUNCTION_RETURN_OBJ (result);
6584 }
6585
6586 /**
6587 * mono_object_handle_isinst:
6588 * \param obj an object
6589 * \param klass a pointer to a class
6590 * \param error set on error
6591 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6592 * On failure returns NULL and sets \p error.
6593 */
6594 MonoObjectHandle
mono_object_handle_isinst(MonoObjectHandle obj,MonoClass * klass,MonoError * error)6595 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6596 {
6597 error_init (error);
6598
6599 if (!klass->inited)
6600 mono_class_init (klass);
6601
6602 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6603 return mono_object_handle_isinst_mbyref (obj, klass, error);
6604 }
6605
6606 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6607
6608 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6609 MONO_HANDLE_ASSIGN (result, obj);
6610 return result;
6611 }
6612
6613 /**
6614 * mono_object_isinst_mbyref:
6615 */
6616 MonoObject *
mono_object_isinst_mbyref(MonoObject * obj_raw,MonoClass * klass)6617 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6618 {
6619 MONO_REQ_GC_UNSAFE_MODE;
6620
6621 HANDLE_FUNCTION_ENTER ();
6622 MonoError error;
6623 MONO_HANDLE_DCL (MonoObject, obj);
6624 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6625 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6626 HANDLE_FUNCTION_RETURN_OBJ (result);
6627 }
6628
6629 MonoObjectHandle
mono_object_handle_isinst_mbyref(MonoObjectHandle obj,MonoClass * klass,MonoError * error)6630 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6631 {
6632 error_init (error);
6633
6634 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6635
6636 if (MONO_HANDLE_IS_NULL (obj))
6637 goto leave;
6638
6639 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6640
6641 if (mono_class_is_interface (klass)) {
6642 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6643 MONO_HANDLE_ASSIGN (result, obj);
6644 goto leave;
6645 }
6646
6647 /* casting an array one of the invariant interfaces that must act as such */
6648 if (klass->is_array_special_interface) {
6649 if (mono_class_is_assignable_from (klass, vt->klass)) {
6650 MONO_HANDLE_ASSIGN (result, obj);
6651 goto leave;
6652 }
6653 }
6654
6655 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6656 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6657 MONO_HANDLE_ASSIGN (result, obj);
6658 goto leave;
6659 }
6660 } else {
6661 MonoClass *oklass = vt->klass;
6662 if (mono_class_is_transparent_proxy (oklass)){
6663 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6664 oklass = remote_class->proxy_class;
6665 }
6666
6667 mono_class_setup_supertypes (klass);
6668 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6669 MONO_HANDLE_ASSIGN (result, obj);
6670 goto leave;
6671 }
6672 }
6673 #ifndef DISABLE_REMOTING
6674 if (mono_class_is_transparent_proxy (vt->klass))
6675 {
6676 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6677 if (!custom_type_info)
6678 goto leave;
6679 MonoDomain *domain = mono_domain_get ();
6680 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6681 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6682 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6683 MonoMethod *im = NULL;
6684 gpointer pa [2];
6685
6686 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6687 if (!im) {
6688 mono_error_set_not_supported (error, "Linked away.");
6689 goto leave;
6690 }
6691 im = mono_object_handle_get_virtual_method (rp, im, error);
6692 goto_if_nok (error, leave);
6693 g_assert (im);
6694
6695 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6696 goto_if_nok (error, leave);
6697
6698 pa [0] = MONO_HANDLE_RAW (reftype);
6699 pa [1] = MONO_HANDLE_RAW (obj);
6700 MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
6701 goto_if_nok (error, leave);
6702
6703 if (*(MonoBoolean *) mono_object_unbox(res)) {
6704 /* Update the vtable of the remote type, so it can safely cast to this new type */
6705 mono_upgrade_remote_class (domain, obj, klass, error);
6706 goto_if_nok (error, leave);
6707 MONO_HANDLE_ASSIGN (result, obj);
6708 }
6709 }
6710 #endif /* DISABLE_REMOTING */
6711 leave:
6712 return result;
6713 }
6714
6715 /**
6716 * mono_object_castclass_mbyref:
6717 * \param obj an object
6718 * \param klass a pointer to a class
6719 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6720 */
6721 MonoObject *
mono_object_castclass_mbyref(MonoObject * obj_raw,MonoClass * klass)6722 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6723 {
6724 MONO_REQ_GC_UNSAFE_MODE;
6725 HANDLE_FUNCTION_ENTER ();
6726 MonoError error;
6727 MONO_HANDLE_DCL (MonoObject, obj);
6728 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6729 if (MONO_HANDLE_IS_NULL (obj))
6730 goto leave;
6731 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6732 mono_error_cleanup (&error);
6733 leave:
6734 HANDLE_FUNCTION_RETURN_OBJ (result);
6735 }
6736
6737 typedef struct {
6738 MonoDomain *orig_domain;
6739 MonoString *ins;
6740 MonoString *res;
6741 } LDStrInfo;
6742
6743 static void
str_lookup(MonoDomain * domain,gpointer user_data)6744 str_lookup (MonoDomain *domain, gpointer user_data)
6745 {
6746 MONO_REQ_GC_UNSAFE_MODE;
6747
6748 LDStrInfo *info = (LDStrInfo *)user_data;
6749 if (info->res || domain == info->orig_domain)
6750 return;
6751 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6752 }
6753
6754 static MonoString*
mono_string_get_pinned(MonoString * str,MonoError * error)6755 mono_string_get_pinned (MonoString *str, MonoError *error)
6756 {
6757 MONO_REQ_GC_UNSAFE_MODE;
6758
6759 error_init (error);
6760
6761 /* We only need to make a pinned version of a string if this is a moving GC */
6762 if (!mono_gc_is_moving ())
6763 return str;
6764 int size;
6765 MonoString *news;
6766 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6767 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6768 if (news) {
6769 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6770 news->length = mono_string_length (str);
6771 } else {
6772 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6773 }
6774 return news;
6775 }
6776
6777 static MonoString*
mono_string_is_interned_lookup(MonoString * str,int insert,MonoError * error)6778 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6779 {
6780 MONO_REQ_GC_UNSAFE_MODE;
6781
6782 MonoGHashTable *ldstr_table;
6783 MonoString *s, *res;
6784 MonoDomain *domain;
6785
6786 error_init (error);
6787
6788 domain = ((MonoObject *)str)->vtable->domain;
6789 ldstr_table = domain->ldstr_table;
6790 ldstr_lock ();
6791 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6792 if (res) {
6793 ldstr_unlock ();
6794 return res;
6795 }
6796 if (insert) {
6797 /* Allocate outside the lock */
6798 ldstr_unlock ();
6799 s = mono_string_get_pinned (str, error);
6800 return_val_if_nok (error, NULL);
6801 if (s) {
6802 ldstr_lock ();
6803 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6804 if (res) {
6805 ldstr_unlock ();
6806 return res;
6807 }
6808 mono_g_hash_table_insert (ldstr_table, s, s);
6809 ldstr_unlock ();
6810 }
6811 return s;
6812 } else {
6813 LDStrInfo ldstr_info;
6814 ldstr_info.orig_domain = domain;
6815 ldstr_info.ins = str;
6816 ldstr_info.res = NULL;
6817
6818 mono_domain_foreach (str_lookup, &ldstr_info);
6819 if (ldstr_info.res) {
6820 /*
6821 * the string was already interned in some other domain:
6822 * intern it in the current one as well.
6823 */
6824 mono_g_hash_table_insert (ldstr_table, str, str);
6825 ldstr_unlock ();
6826 return str;
6827 }
6828 }
6829 ldstr_unlock ();
6830 return NULL;
6831 }
6832
6833 /**
6834 * mono_string_is_interned:
6835 * \param o String to probe
6836 * \returns Whether the string has been interned.
6837 */
6838 MonoString*
mono_string_is_interned(MonoString * o)6839 mono_string_is_interned (MonoString *o)
6840 {
6841 MonoError error;
6842 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6843 /* This function does not fail. */
6844 mono_error_assert_ok (&error);
6845 return result;
6846 }
6847
6848 /**
6849 * mono_string_intern:
6850 * \param o String to intern
6851 * Interns the string passed.
6852 * \returns The interned string.
6853 */
6854 MonoString*
mono_string_intern(MonoString * str)6855 mono_string_intern (MonoString *str)
6856 {
6857 MonoError error;
6858 MonoString *result = mono_string_intern_checked (str, &error);
6859 mono_error_assert_ok (&error);
6860 return result;
6861 }
6862
6863 /**
6864 * mono_string_intern_checked:
6865 * \param o String to intern
6866 * \param error set on error.
6867 * Interns the string passed.
6868 * \returns The interned string. On failure returns NULL and sets \p error
6869 */
6870 MonoString*
mono_string_intern_checked(MonoString * str,MonoError * error)6871 mono_string_intern_checked (MonoString *str, MonoError *error)
6872 {
6873 MONO_REQ_GC_UNSAFE_MODE;
6874
6875 error_init (error);
6876
6877 return mono_string_is_interned_lookup (str, TRUE, error);
6878 }
6879
6880 /**
6881 * mono_ldstr:
6882 * \param domain the domain where the string will be used.
6883 * \param image a metadata context
6884 * \param idx index into the user string table.
6885 * Implementation for the \c ldstr opcode.
6886 * \returns a loaded string from the \p image / \p idx combination.
6887 */
6888 MonoString*
mono_ldstr(MonoDomain * domain,MonoImage * image,guint32 idx)6889 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6890 {
6891 MonoError error;
6892 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6893 mono_error_cleanup (&error);
6894 return result;
6895 }
6896
6897 /**
6898 * mono_ldstr_checked:
6899 * \param domain the domain where the string will be used.
6900 * \param image a metadata context
6901 * \param idx index into the user string table.
6902 * \param error set on error.
6903 * Implementation for the \c ldstr opcode.
6904 * \returns A loaded string from the \p image / \p idx combination.
6905 * On failure returns NULL and sets \p error.
6906 */
6907 MonoString*
mono_ldstr_checked(MonoDomain * domain,MonoImage * image,guint32 idx,MonoError * error)6908 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6909 {
6910 MONO_REQ_GC_UNSAFE_MODE;
6911 error_init (error);
6912
6913 if (image->dynamic) {
6914 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6915 return str;
6916 } else {
6917 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6918 return NULL; /*FIXME we should probably be raising an exception here*/
6919 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6920 return str;
6921 }
6922 }
6923
6924 /**
6925 * mono_ldstr_metadata_sig
6926 * \param domain the domain for the string
6927 * \param sig the signature of a metadata string
6928 * \param error set on error
6929 * \returns a \c MonoString for a string stored in the metadata. On
6930 * failure returns NULL and sets \p error.
6931 */
6932 static MonoString*
mono_ldstr_metadata_sig(MonoDomain * domain,const char * sig,MonoError * error)6933 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6934 {
6935 MONO_REQ_GC_UNSAFE_MODE;
6936
6937 error_init (error);
6938 const char *str = sig;
6939 MonoString *o, *interned;
6940 size_t len2;
6941
6942 len2 = mono_metadata_decode_blob_size (str, &str);
6943 len2 >>= 1;
6944
6945 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6946 return_val_if_nok (error, NULL);
6947 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6948 {
6949 int i;
6950 guint16 *p2 = (guint16*)mono_string_chars (o);
6951 for (i = 0; i < len2; ++i) {
6952 *p2 = GUINT16_FROM_LE (*p2);
6953 ++p2;
6954 }
6955 }
6956 #endif
6957 ldstr_lock ();
6958 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6959 ldstr_unlock ();
6960 if (interned)
6961 return interned; /* o will get garbage collected */
6962
6963 o = mono_string_get_pinned (o, error);
6964 if (o) {
6965 ldstr_lock ();
6966 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6967 if (!interned) {
6968 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6969 interned = o;
6970 }
6971 ldstr_unlock ();
6972 }
6973
6974 return interned;
6975 }
6976
6977 /*
6978 * mono_ldstr_utf8:
6979 *
6980 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6981 * of an object.
6982 */
6983 char*
mono_ldstr_utf8(MonoImage * image,guint32 idx,MonoError * error)6984 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6985 {
6986 const char *str;
6987 size_t len2;
6988 long written = 0;
6989 char *as;
6990 GError *gerror = NULL;
6991
6992 error_init (error);
6993
6994 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6995 return NULL; /*FIXME we should probably be raising an exception here*/
6996 str = mono_metadata_user_string (image, idx);
6997
6998 len2 = mono_metadata_decode_blob_size (str, &str);
6999 len2 >>= 1;
7000
7001 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
7002 if (gerror) {
7003 mono_error_set_argument (error, "string", "%s", gerror->message);
7004 g_error_free (gerror);
7005 return NULL;
7006 }
7007 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7008 if (len2 > written) {
7009 /* allocate the total length and copy the part of the string that has been converted */
7010 char *as2 = (char *)g_malloc0 (len2);
7011 memcpy (as2, as, written);
7012 g_free (as);
7013 as = as2;
7014 }
7015
7016 return as;
7017 }
7018
7019 /**
7020 * mono_string_to_utf8:
7021 * \param s a \c System.String
7022 * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
7023 * \returns the UTF-8 representation for \p s.
7024 * The resulting buffer needs to be freed with \c mono_free().
7025 */
7026 char *
mono_string_to_utf8(MonoString * s)7027 mono_string_to_utf8 (MonoString *s)
7028 {
7029 MONO_REQ_GC_UNSAFE_MODE;
7030
7031 MonoError error;
7032 char *result = mono_string_to_utf8_checked (s, &error);
7033
7034 if (!is_ok (&error)) {
7035 mono_error_cleanup (&error);
7036 return NULL;
7037 }
7038 return result;
7039 }
7040
7041 /**
7042 * mono_string_to_utf8_checked:
7043 * \param s a \c System.String
7044 * \param error a \c MonoError.
7045 * Converts a \c MonoString to its UTF-8 representation. May fail; check
7046 * \p error to determine whether the conversion was successful.
7047 * The resulting buffer should be freed with \c mono_free().
7048 */
7049 char *
mono_string_to_utf8_checked(MonoString * s,MonoError * error)7050 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7051 {
7052 MONO_REQ_GC_UNSAFE_MODE;
7053
7054 long written = 0;
7055 char *as;
7056 GError *gerror = NULL;
7057
7058 error_init (error);
7059
7060 if (s == NULL)
7061 return NULL;
7062
7063 if (!s->length)
7064 return g_strdup ("");
7065
7066 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7067 if (gerror) {
7068 mono_error_set_argument (error, "string", "%s", gerror->message);
7069 g_error_free (gerror);
7070 return NULL;
7071 }
7072 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7073 if (s->length > written) {
7074 /* allocate the total length and copy the part of the string that has been converted */
7075 char *as2 = (char *)g_malloc0 (s->length);
7076 memcpy (as2, as, written);
7077 g_free (as);
7078 as = as2;
7079 }
7080
7081 return as;
7082 }
7083
7084 char *
mono_string_handle_to_utf8(MonoStringHandle s,MonoError * error)7085 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7086 {
7087 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7088 }
7089
7090 /**
7091 * mono_string_to_utf8_ignore:
7092 * \param s a MonoString
7093 * Converts a \c MonoString to its UTF-8 representation. Will ignore
7094 * invalid surrogate pairs.
7095 * The resulting buffer should be freed with \c mono_free().
7096 */
7097 char *
mono_string_to_utf8_ignore(MonoString * s)7098 mono_string_to_utf8_ignore (MonoString *s)
7099 {
7100 MONO_REQ_GC_UNSAFE_MODE;
7101
7102 long written = 0;
7103 char *as;
7104
7105 if (s == NULL)
7106 return NULL;
7107
7108 if (!s->length)
7109 return g_strdup ("");
7110
7111 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7112
7113 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7114 if (s->length > written) {
7115 /* allocate the total length and copy the part of the string that has been converted */
7116 char *as2 = (char *)g_malloc0 (s->length);
7117 memcpy (as2, as, written);
7118 g_free (as);
7119 as = as2;
7120 }
7121
7122 return as;
7123 }
7124
7125 /**
7126 * mono_string_to_utf8_image_ignore:
7127 * \param s a \c System.String
7128 * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7129 */
7130 char *
mono_string_to_utf8_image_ignore(MonoImage * image,MonoString * s)7131 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7132 {
7133 MONO_REQ_GC_UNSAFE_MODE;
7134
7135 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7136 }
7137
7138 /**
7139 * mono_string_to_utf8_mp_ignore:
7140 * \param s a \c System.String
7141 * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7142 */
7143 char *
mono_string_to_utf8_mp_ignore(MonoMemPool * mp,MonoString * s)7144 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7145 {
7146 MONO_REQ_GC_UNSAFE_MODE;
7147
7148 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7149 }
7150
7151
7152 /**
7153 * mono_string_to_utf16:
7154 * \param s a \c MonoString
7155 * \returns a null-terminated array of the UTF-16 chars
7156 * contained in \p s. The result must be freed with \c g_free().
7157 * This is a temporary helper until our string implementation
7158 * is reworked to always include the null-terminating char.
7159 */
7160 mono_unichar2*
mono_string_to_utf16(MonoString * s)7161 mono_string_to_utf16 (MonoString *s)
7162 {
7163 MONO_REQ_GC_UNSAFE_MODE;
7164
7165 char *as;
7166
7167 if (s == NULL)
7168 return NULL;
7169
7170 as = (char *)g_malloc ((s->length * 2) + 2);
7171 as [(s->length * 2)] = '\0';
7172 as [(s->length * 2) + 1] = '\0';
7173
7174 if (!s->length) {
7175 return (gunichar2 *)(as);
7176 }
7177
7178 memcpy (as, mono_string_chars(s), s->length * 2);
7179 return (gunichar2 *)(as);
7180 }
7181
7182 /**
7183 * mono_string_to_utf32:
7184 * \param s a \c MonoString
7185 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7186 * contained in \p s. The result must be freed with \c g_free().
7187 */
7188 mono_unichar4*
mono_string_to_utf32(MonoString * s)7189 mono_string_to_utf32 (MonoString *s)
7190 {
7191 MONO_REQ_GC_UNSAFE_MODE;
7192
7193 mono_unichar4 *utf32_output = NULL;
7194 GError *error = NULL;
7195 glong items_written;
7196
7197 if (s == NULL)
7198 return NULL;
7199
7200 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7201
7202 if (error)
7203 g_error_free (error);
7204
7205 return utf32_output;
7206 }
7207
7208 /**
7209 * mono_string_from_utf16:
7210 * \param data the UTF-16 string (LPWSTR) to convert
7211 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7212 * \returns a \c MonoString.
7213 */
7214 MonoString *
mono_string_from_utf16(gunichar2 * data)7215 mono_string_from_utf16 (gunichar2 *data)
7216 {
7217 MonoError error;
7218 MonoString *result = mono_string_from_utf16_checked (data, &error);
7219 mono_error_cleanup (&error);
7220 return result;
7221 }
7222
7223 /**
7224 * mono_string_from_utf16_checked:
7225 * \param data the UTF-16 string (LPWSTR) to convert
7226 * \param error set on error
7227 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7228 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7229 */
7230 MonoString *
mono_string_from_utf16_checked(gunichar2 * data,MonoError * error)7231 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7232 {
7233
7234 MONO_REQ_GC_UNSAFE_MODE;
7235
7236 error_init (error);
7237 MonoDomain *domain = mono_domain_get ();
7238 int len = 0;
7239
7240 if (!data)
7241 return NULL;
7242
7243 while (data [len]) len++;
7244
7245 return mono_string_new_utf16_checked (domain, data, len, error);
7246 }
7247
7248 /**
7249 * mono_string_from_utf32:
7250 * \param data the UTF-32 string (LPWSTR) to convert
7251 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7252 * \returns a \c MonoString.
7253 */
7254 MonoString *
mono_string_from_utf32(mono_unichar4 * data)7255 mono_string_from_utf32 (mono_unichar4 *data)
7256 {
7257 MonoError error;
7258 MonoString *result = mono_string_from_utf32_checked (data, &error);
7259 mono_error_cleanup (&error);
7260 return result;
7261 }
7262
7263 /**
7264 * mono_string_from_utf32_checked:
7265 * \param data the UTF-32 string (LPWSTR) to convert
7266 * \param error set on error
7267 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7268 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7269 */
7270 MonoString *
mono_string_from_utf32_checked(mono_unichar4 * data,MonoError * error)7271 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7272 {
7273 MONO_REQ_GC_UNSAFE_MODE;
7274
7275 error_init (error);
7276 MonoString* result = NULL;
7277 mono_unichar2 *utf16_output = NULL;
7278 GError *gerror = NULL;
7279 glong items_written;
7280 int len = 0;
7281
7282 if (!data)
7283 return NULL;
7284
7285 while (data [len]) len++;
7286
7287 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7288
7289 if (gerror)
7290 g_error_free (gerror);
7291
7292 result = mono_string_from_utf16_checked (utf16_output, error);
7293 g_free (utf16_output);
7294 return result;
7295 }
7296
7297 static char *
mono_string_to_utf8_internal(MonoMemPool * mp,MonoImage * image,MonoString * s,gboolean ignore_error,MonoError * error)7298 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7299 {
7300 MONO_REQ_GC_UNSAFE_MODE;
7301
7302 char *r;
7303 char *mp_s;
7304 int len;
7305
7306 if (ignore_error) {
7307 r = mono_string_to_utf8_ignore (s);
7308 } else {
7309 r = mono_string_to_utf8_checked (s, error);
7310 if (!mono_error_ok (error))
7311 return NULL;
7312 }
7313
7314 if (!mp && !image)
7315 return r;
7316
7317 len = strlen (r) + 1;
7318 if (mp)
7319 mp_s = (char *)mono_mempool_alloc (mp, len);
7320 else
7321 mp_s = (char *)mono_image_alloc (image, len);
7322
7323 memcpy (mp_s, r, len);
7324
7325 g_free (r);
7326
7327 return mp_s;
7328 }
7329
7330 /**
7331 * mono_string_to_utf8_image:
7332 * \param s a \c System.String
7333 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7334 */
7335 char *
mono_string_to_utf8_image(MonoImage * image,MonoStringHandle s,MonoError * error)7336 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7337 {
7338 MONO_REQ_GC_UNSAFE_MODE;
7339
7340 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7341 }
7342
7343 /**
7344 * mono_string_to_utf8_mp:
7345 * \param s a \c System.String
7346 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7347 */
7348 char *
mono_string_to_utf8_mp(MonoMemPool * mp,MonoString * s,MonoError * error)7349 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7350 {
7351 MONO_REQ_GC_UNSAFE_MODE;
7352
7353 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7354 }
7355
7356
7357 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7358
7359 void
mono_install_eh_callbacks(MonoRuntimeExceptionHandlingCallbacks * cbs)7360 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7361 {
7362 eh_callbacks = *cbs;
7363 }
7364
7365 MonoRuntimeExceptionHandlingCallbacks *
mono_get_eh_callbacks(void)7366 mono_get_eh_callbacks (void)
7367 {
7368 return &eh_callbacks;
7369 }
7370
7371 /**
7372 * mono_raise_exception:
7373 * \param ex exception object
7374 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7375 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
7376 */
7377 void
mono_raise_exception(MonoException * ex)7378 mono_raise_exception (MonoException *ex)
7379 {
7380 mono_raise_exception_deprecated (ex);
7381 }
7382
7383 /*
7384 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
7385 */
7386 void
mono_raise_exception_deprecated(MonoException * ex)7387 mono_raise_exception_deprecated (MonoException *ex)
7388 {
7389 MONO_REQ_GC_UNSAFE_MODE;
7390
7391 eh_callbacks.mono_raise_exception (ex);
7392 }
7393
7394 /**
7395 * mono_reraise_exception:
7396 * \param ex exception object
7397 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7398 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
7399 */
7400 void
mono_reraise_exception(MonoException * ex)7401 mono_reraise_exception (MonoException *ex)
7402 {
7403 mono_reraise_exception_deprecated (ex);
7404 }
7405
7406 /*
7407 * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
7408 */
7409 void
mono_reraise_exception_deprecated(MonoException * ex)7410 mono_reraise_exception_deprecated (MonoException *ex)
7411 {
7412 MONO_REQ_GC_UNSAFE_MODE;
7413
7414 eh_callbacks.mono_reraise_exception (ex);
7415 }
7416
7417 /*
7418 * CTX must point to managed code.
7419 */
7420 void
mono_raise_exception_with_context(MonoException * ex,MonoContext * ctx)7421 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7422 {
7423 MONO_REQ_GC_UNSAFE_MODE;
7424
7425 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7426 }
7427
7428 /**
7429 * mono_wait_handle_new:
7430 * \param domain Domain where the object will be created
7431 * \param handle Handle for the wait handle
7432 * \param error set on error.
7433 * \returns A new \c MonoWaitHandle created in the given domain for the
7434 * given handle. On failure returns NULL and sets \p error.
7435 */
7436 MonoWaitHandle *
mono_wait_handle_new(MonoDomain * domain,HANDLE handle,MonoError * error)7437 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7438 {
7439 MONO_REQ_GC_UNSAFE_MODE;
7440
7441 MonoWaitHandle *res;
7442 gpointer params [1];
7443 static MonoMethod *handle_set;
7444
7445 error_init (error);
7446 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7447 return_val_if_nok (error, NULL);
7448
7449 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7450 if (!handle_set)
7451 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7452
7453 params [0] = &handle;
7454
7455 mono_runtime_invoke_checked (handle_set, res, params, error);
7456 return res;
7457 }
7458
7459 HANDLE
mono_wait_handle_get_handle(MonoWaitHandle * handle)7460 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7461 {
7462 MONO_REQ_GC_UNSAFE_MODE;
7463
7464 static MonoClassField *f_safe_handle = NULL;
7465 MonoSafeHandle *sh;
7466
7467 if (!f_safe_handle) {
7468 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7469 g_assert (f_safe_handle);
7470 }
7471
7472 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7473 return sh->handle;
7474 }
7475
7476
7477 static MonoObject*
mono_runtime_capture_context(MonoDomain * domain,MonoError * error)7478 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7479 {
7480 #ifdef HOST_WASM
7481 return mono_runtime_invoke_checked (mono_get_context_capture_method (), NULL, NULL, error);
7482 #else
7483 MONO_REQ_GC_UNSAFE_MODE;
7484
7485 RuntimeInvokeFunction runtime_invoke;
7486
7487 error_init (error);
7488
7489 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7490 MonoMethod *method = mono_get_context_capture_method ();
7491 MonoMethod *wrapper;
7492 if (!method)
7493 return NULL;
7494 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7495 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7496 return_val_if_nok (error, NULL);
7497 domain->capture_context_method = mono_compile_method_checked (method, error);
7498 return_val_if_nok (error, NULL);
7499 }
7500
7501 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7502
7503 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7504 #endif
7505 }
7506 /**
7507 * mono_async_result_new:
7508 * \param domain domain where the object will be created.
7509 * \param handle wait handle.
7510 * \param state state to pass to AsyncResult
7511 * \param data C closure data.
7512 * \param error set on error.
7513 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7514 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7515 * On failure returns NULL and sets \p error.
7516 */
7517 MonoAsyncResult *
mono_async_result_new(MonoDomain * domain,HANDLE handle,MonoObject * state,gpointer data,MonoObject * object_data,MonoError * error)7518 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7519 {
7520 MONO_REQ_GC_UNSAFE_MODE;
7521
7522 error_init (error);
7523 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7524 return_val_if_nok (error, NULL);
7525 MonoObject *context = mono_runtime_capture_context (domain, error);
7526 return_val_if_nok (error, NULL);
7527 /* we must capture the execution context from the original thread */
7528 if (context) {
7529 MONO_OBJECT_SETREF (res, execution_context, context);
7530 /* note: result may be null if the flow is suppressed */
7531 }
7532
7533 res->data = (void **)data;
7534 MONO_OBJECT_SETREF (res, object_data, object_data);
7535 MONO_OBJECT_SETREF (res, async_state, state);
7536 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7537 return_val_if_nok (error, NULL);
7538 if (handle != NULL)
7539 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7540
7541 res->sync_completed = FALSE;
7542 res->completed = FALSE;
7543
7544 return res;
7545 }
7546
7547 MonoObject *
ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke(MonoAsyncResult * ares)7548 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7549 {
7550 MONO_REQ_GC_UNSAFE_MODE;
7551
7552 MonoError error;
7553 MonoAsyncCall *ac;
7554 MonoObject *res;
7555
7556 g_assert (ares);
7557 g_assert (ares->async_delegate);
7558
7559 ac = (MonoAsyncCall*) ares->object_data;
7560 if (!ac) {
7561 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7562 if (mono_error_set_pending_exception (&error))
7563 return NULL;
7564 } else {
7565 gpointer wait_event = NULL;
7566
7567 ac->msg->exc = NULL;
7568
7569 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7570
7571 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7572 mono_threads_begin_abort_protected_block ();
7573
7574 if (!ac->msg->exc) {
7575 MonoException *ex = mono_error_convert_to_exception (&error);
7576 ac->msg->exc = (MonoObject *)ex;
7577 } else {
7578 mono_error_cleanup (&error);
7579 }
7580
7581 MONO_OBJECT_SETREF (ac, res, res);
7582
7583 mono_monitor_enter ((MonoObject*) ares);
7584 ares->completed = 1;
7585 if (ares->handle)
7586 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7587 mono_monitor_exit ((MonoObject*) ares);
7588
7589 if (wait_event != NULL)
7590 mono_w32event_set (wait_event);
7591
7592 error_init (&error); //the else branch would leave it in an undefined state
7593 if (ac->cb_method)
7594 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7595
7596 mono_threads_end_abort_protected_block ();
7597
7598 if (mono_error_set_pending_exception (&error))
7599 return NULL;
7600 }
7601
7602 return res;
7603 }
7604
7605 gboolean
mono_message_init(MonoDomain * domain,MonoMethodMessage * this_obj,MonoReflectionMethod * method,MonoArray * out_args,MonoError * error)7606 mono_message_init (MonoDomain *domain,
7607 MonoMethodMessage *this_obj,
7608 MonoReflectionMethod *method,
7609 MonoArray *out_args,
7610 MonoError *error)
7611 {
7612 MONO_REQ_GC_UNSAFE_MODE;
7613
7614 static MonoMethod *init_message_method = NULL;
7615
7616 if (!init_message_method) {
7617 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7618 g_assert (init_message_method != NULL);
7619 }
7620
7621 error_init (error);
7622 /* FIXME set domain instead? */
7623 g_assert (domain == mono_domain_get ());
7624
7625 gpointer args[2];
7626
7627 args[0] = method;
7628 args[1] = out_args;
7629
7630 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7631 return is_ok (error);
7632 }
7633
7634 #ifndef DISABLE_REMOTING
7635 /**
7636 * mono_remoting_invoke:
7637 * \param real_proxy pointer to a \c RealProxy object
7638 * \param msg The \c MonoMethodMessage to execute
7639 * \param exc used to store exceptions
7640 * \param out_args used to store output arguments
7641 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7642 * \c IMessage interface and it is not trivial to extract results from there. So
7643 * we call an helper method \c PrivateInvoke instead of calling
7644 * \c RealProxy::Invoke() directly.
7645 * \returns the result object.
7646 */
7647 MonoObject *
mono_remoting_invoke(MonoObject * real_proxy,MonoMethodMessage * msg,MonoObject ** exc,MonoArray ** out_args,MonoError * error)7648 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7649 {
7650 MONO_REQ_GC_UNSAFE_MODE;
7651
7652 MonoObject *o;
7653 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7654 gpointer pa [4];
7655
7656 g_assert (exc);
7657
7658 error_init (error);
7659
7660 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7661
7662 if (!im) {
7663 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7664 if (!im) {
7665 mono_error_set_not_supported (error, "Linked away.");
7666 return NULL;
7667 }
7668 real_proxy->vtable->domain->private_invoke_method = im;
7669 }
7670
7671 pa [0] = real_proxy;
7672 pa [1] = msg;
7673 pa [2] = exc;
7674 pa [3] = out_args;
7675
7676 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7677 return_val_if_nok (error, NULL);
7678
7679 return o;
7680 }
7681 #endif
7682
7683 MonoObject *
mono_message_invoke(MonoObject * target,MonoMethodMessage * msg,MonoObject ** exc,MonoArray ** out_args,MonoError * error)7684 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7685 MonoObject **exc, MonoArray **out_args, MonoError *error)
7686 {
7687 MONO_REQ_GC_UNSAFE_MODE;
7688
7689 static MonoClass *object_array_klass;
7690 error_init (error);
7691
7692 MonoDomain *domain;
7693 MonoMethod *method;
7694 MonoMethodSignature *sig;
7695 MonoArray *arr;
7696 int i, j, outarg_count = 0;
7697
7698 #ifndef DISABLE_REMOTING
7699 if (target && mono_object_is_transparent_proxy (target)) {
7700 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7701 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7702 target = tp->rp->unwrapped_server;
7703 } else {
7704 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7705 }
7706 }
7707 #endif
7708
7709 domain = mono_domain_get ();
7710 method = msg->method->method;
7711 sig = mono_method_signature (method);
7712
7713 for (i = 0; i < sig->param_count; i++) {
7714 if (sig->params [i]->byref)
7715 outarg_count++;
7716 }
7717
7718 if (!object_array_klass) {
7719 MonoClass *klass;
7720
7721 klass = mono_array_class_get (mono_defaults.object_class, 1);
7722 g_assert (klass);
7723
7724 mono_memory_barrier ();
7725 object_array_klass = klass;
7726 }
7727
7728 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7729 return_val_if_nok (error, NULL);
7730
7731 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7732 *exc = NULL;
7733
7734 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7735 return_val_if_nok (error, NULL);
7736
7737 for (i = 0, j = 0; i < sig->param_count; i++) {
7738 if (sig->params [i]->byref) {
7739 MonoObject* arg;
7740 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7741 mono_array_setref (*out_args, j, arg);
7742 j++;
7743 }
7744 }
7745
7746 return ret;
7747 }
7748
7749 /**
7750 * prepare_to_string_method:
7751 * @obj: The object
7752 * @target: Set to @obj or unboxed value if a valuetype
7753 *
7754 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7755 */
7756 static MonoMethod *
prepare_to_string_method(MonoObject * obj,void ** target)7757 prepare_to_string_method (MonoObject *obj, void **target)
7758 {
7759 MONO_REQ_GC_UNSAFE_MODE;
7760
7761 static MonoMethod *to_string = NULL;
7762 MonoMethod *method;
7763 g_assert (target);
7764 g_assert (obj);
7765
7766 *target = obj;
7767
7768 if (!to_string)
7769 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7770
7771 method = mono_object_get_virtual_method (obj, to_string);
7772
7773 // Unbox value type if needed
7774 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7775 *target = mono_object_unbox (obj);
7776 }
7777 return method;
7778 }
7779
7780 /**
7781 * mono_object_to_string:
7782 * \param obj The object
7783 * \param exc Any exception thrown by \c ToString. May be NULL.
7784 * \returns the result of calling \c ToString on an object.
7785 */
7786 MonoString *
mono_object_to_string(MonoObject * obj,MonoObject ** exc)7787 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7788 {
7789 MonoError error;
7790 MonoString *s = NULL;
7791 void *target;
7792 MonoMethod *method = prepare_to_string_method (obj, &target);
7793 if (exc) {
7794 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7795 if (*exc == NULL && !mono_error_ok (&error))
7796 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7797 else
7798 mono_error_cleanup (&error);
7799 } else {
7800 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7801 mono_error_raise_exception_deprecated (&error); /* OK to throw, external only without a good alternative */
7802 }
7803
7804 return s;
7805 }
7806
7807 /**
7808 * mono_object_to_string_checked:
7809 * \param obj The object
7810 * \param error Set on error.
7811 * \returns the result of calling \c ToString() on an object. If the
7812 * method cannot be invoked or if it raises an exception, sets \p error
7813 * and returns NULL.
7814 */
7815 MonoString *
mono_object_to_string_checked(MonoObject * obj,MonoError * error)7816 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7817 {
7818 error_init (error);
7819 void *target;
7820 MonoMethod *method = prepare_to_string_method (obj, &target);
7821 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7822 }
7823
7824 /**
7825 * mono_object_try_to_string:
7826 * \param obj The object
7827 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7828 * \param error Set if method cannot be invoked.
7829 * \returns the result of calling \c ToString() on an object. If the
7830 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7831 * and returns NULL.
7832 */
7833 MonoString *
mono_object_try_to_string(MonoObject * obj,MonoObject ** exc,MonoError * error)7834 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7835 {
7836 g_assert (exc);
7837 error_init (error);
7838 void *target;
7839 MonoMethod *method = prepare_to_string_method (obj, &target);
7840 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7841 }
7842
7843
7844
7845 static char *
get_native_backtrace(MonoException * exc_raw)7846 get_native_backtrace (MonoException *exc_raw)
7847 {
7848 HANDLE_FUNCTION_ENTER ();
7849 MONO_HANDLE_DCL(MonoException, exc);
7850 char * trace = mono_exception_handle_get_native_backtrace (exc);
7851 HANDLE_FUNCTION_RETURN_VAL (trace);
7852 }
7853
7854 /**
7855 * mono_print_unhandled_exception:
7856 * \param exc The exception
7857 * Prints the unhandled exception.
7858 */
7859 void
mono_print_unhandled_exception(MonoObject * exc)7860 mono_print_unhandled_exception (MonoObject *exc)
7861 {
7862 MONO_REQ_GC_UNSAFE_MODE;
7863
7864 MonoString * str;
7865 char *message = (char*)"";
7866 gboolean free_message = FALSE;
7867 MonoError error;
7868
7869 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7870 message = g_strdup ("OutOfMemoryException");
7871 free_message = TRUE;
7872 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7873 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7874 free_message = TRUE;
7875 } else {
7876
7877 if (((MonoException*)exc)->native_trace_ips) {
7878 message = get_native_backtrace ((MonoException*)exc);
7879 free_message = TRUE;
7880 } else {
7881 MonoObject *other_exc = NULL;
7882 str = mono_object_try_to_string (exc, &other_exc, &error);
7883 if (other_exc == NULL && !is_ok (&error))
7884 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7885 else
7886 mono_error_cleanup (&error);
7887 if (other_exc) {
7888 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7889 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7890
7891 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7892 original_backtrace, nested_backtrace);
7893
7894 g_free (original_backtrace);
7895 g_free (nested_backtrace);
7896 free_message = TRUE;
7897 } else if (str) {
7898 message = mono_string_to_utf8_checked (str, &error);
7899 if (!mono_error_ok (&error)) {
7900 mono_error_cleanup (&error);
7901 message = (char *) "";
7902 } else {
7903 free_message = TRUE;
7904 }
7905 }
7906 }
7907 }
7908
7909 /*
7910 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7911 * exc->vtable->klass->name, message);
7912 */
7913 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7914
7915 if (free_message)
7916 g_free (message);
7917 }
7918
7919 /**
7920 * mono_delegate_ctor_with_method:
7921 * \param this pointer to an uninitialized delegate object
7922 * \param target target object
7923 * \param addr pointer to native code
7924 * \param method method
7925 * \param error set on error.
7926 * Initialize a delegate and sets a specific method, not the one
7927 * associated with \p addr. This is useful when sharing generic code.
7928 * In that case \p addr will most probably not be associated with the
7929 * correct instantiation of the method.
7930 * On failure returns FALSE and sets \p error.
7931 */
7932 gboolean
mono_delegate_ctor_with_method(MonoObjectHandle this_obj,MonoObjectHandle target,gpointer addr,MonoMethod * method,MonoError * error)7933 mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
7934 {
7935 MONO_REQ_GC_UNSAFE_MODE;
7936
7937 error_init (error);
7938 MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj);
7939
7940 g_assert (!MONO_HANDLE_IS_NULL (this_obj));
7941 g_assert (addr);
7942
7943 MonoClass *klass = mono_handle_class (this_obj);
7944 g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class));
7945
7946 if (method)
7947 MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
7948
7949 UnlockedIncrement (&mono_stats.delegate_creations);
7950
7951 #ifndef DISABLE_REMOTING
7952 if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
7953 if (callbacks.interp_get_remoting_invoke) {
7954 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, callbacks.interp_get_remoting_invoke (addr, error));
7955 } else {
7956 g_assert (method);
7957 method = mono_marshal_get_remoting_invoke (method);
7958 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
7959 }
7960 return_val_if_nok (error, FALSE);
7961 MONO_HANDLE_SET (delegate, target, target);
7962 } else
7963 #endif
7964 {
7965 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);
7966 MONO_HANDLE_SET (delegate, target, target);
7967 }
7968
7969 MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate)));
7970 if (callbacks.init_delegate)
7971 callbacks.init_delegate (MONO_HANDLE_RAW (delegate)); /* FIXME: update init_delegate callback to take a MonoDelegateHandle */
7972 return TRUE;
7973 }
7974
7975 /**
7976 * mono_delegate_ctor:
7977 * \param this pointer to an uninitialized delegate object
7978 * \param target target object
7979 * \param addr pointer to native code
7980 * \param error set on error.
7981 * This is used to initialize a delegate.
7982 * On failure returns FALSE and sets \p error.
7983 */
7984 gboolean
mono_delegate_ctor(MonoObjectHandle this_obj,MonoObjectHandle target,gpointer addr,MonoError * error)7985 mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
7986 {
7987 MONO_REQ_GC_UNSAFE_MODE;
7988
7989 error_init (error);
7990 MonoDomain *domain = mono_domain_get ();
7991 MonoJitInfo *ji;
7992 MonoMethod *method = NULL;
7993
7994 g_assert (addr);
7995
7996 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7997 /* Shared code */
7998 if (!ji && domain != mono_get_root_domain ())
7999 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
8000 if (ji) {
8001 method = mono_jit_info_get_method (ji);
8002 g_assert (!mono_class_is_gtd (method->klass));
8003 }
8004
8005 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
8006 }
8007
8008 /**
8009 * mono_method_call_message_new:
8010 * \param method method to encapsulate
8011 * \param params parameters to the method
8012 * \param invoke optional, delegate invoke.
8013 * \param cb async callback delegate.
8014 * \param state state passed to the async callback.
8015 * \param error set on error.
8016 * Translates arguments pointers into a \c MonoMethodMessage.
8017 * On failure returns NULL and sets \p error.
8018 */
8019 MonoMethodMessage *
mono_method_call_message_new(MonoMethod * method,gpointer * params,MonoMethod * invoke,MonoDelegate ** cb,MonoObject ** state,MonoError * error)8020 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
8021 MonoDelegate **cb, MonoObject **state, MonoError *error)
8022 {
8023 MONO_REQ_GC_UNSAFE_MODE;
8024
8025 error_init (error);
8026
8027 MonoDomain *domain = mono_domain_get ();
8028 MonoMethodSignature *sig = mono_method_signature (method);
8029 MonoMethodMessage *msg;
8030 int i, count;
8031
8032 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8033 return_val_if_nok (error, NULL);
8034
8035 if (invoke) {
8036 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
8037 return_val_if_nok (error, NULL);
8038 mono_message_init (domain, msg, rm, NULL, error);
8039 return_val_if_nok (error, NULL);
8040 count = sig->param_count - 2;
8041 } else {
8042 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
8043 return_val_if_nok (error, NULL);
8044 mono_message_init (domain, msg, rm, NULL, error);
8045 return_val_if_nok (error, NULL);
8046 count = sig->param_count;
8047 }
8048
8049 for (i = 0; i < count; i++) {
8050 gpointer vpos;
8051 MonoClass *klass;
8052 MonoObject *arg;
8053
8054 if (sig->params [i]->byref)
8055 vpos = *((gpointer *)params [i]);
8056 else
8057 vpos = params [i];
8058
8059 klass = mono_class_from_mono_type (sig->params [i]);
8060
8061 if (klass->valuetype) {
8062 arg = mono_value_box_checked (domain, klass, vpos, error);
8063 return_val_if_nok (error, NULL);
8064 } else
8065 arg = *((MonoObject **)vpos);
8066
8067 mono_array_setref (msg->args, i, arg);
8068 }
8069
8070 if (cb != NULL && state != NULL) {
8071 *cb = *((MonoDelegate **)params [i]);
8072 i++;
8073 *state = *((MonoObject **)params [i]);
8074 }
8075
8076 return msg;
8077 }
8078
8079 /**
8080 * mono_method_return_message_restore:
8081 *
8082 * Restore results from message based processing back to arguments pointers
8083 */
8084 void
mono_method_return_message_restore(MonoMethod * method,gpointer * params,MonoArray * out_args,MonoError * error)8085 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8086 {
8087 MONO_REQ_GC_UNSAFE_MODE;
8088
8089 error_init (error);
8090
8091 MonoMethodSignature *sig = mono_method_signature (method);
8092 int i, j, type, size, out_len;
8093
8094 if (out_args == NULL)
8095 return;
8096 out_len = mono_array_length (out_args);
8097 if (out_len == 0)
8098 return;
8099
8100 for (i = 0, j = 0; i < sig->param_count; i++) {
8101 MonoType *pt = sig->params [i];
8102
8103 if (pt->byref) {
8104 char *arg;
8105 if (j >= out_len) {
8106 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8107 return;
8108 }
8109
8110 arg = (char *)mono_array_get (out_args, gpointer, j);
8111 type = pt->type;
8112
8113 g_assert (type != MONO_TYPE_VOID);
8114
8115 if (MONO_TYPE_IS_REFERENCE (pt)) {
8116 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8117 } else {
8118 if (arg) {
8119 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8120 size = mono_class_value_size (klass, NULL);
8121 if (klass->has_references)
8122 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8123 else
8124 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8125 } else {
8126 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8127 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8128 }
8129 }
8130
8131 j++;
8132 }
8133 }
8134 }
8135
8136 #ifndef DISABLE_REMOTING
8137
8138 /**
8139 * mono_load_remote_field:
8140 * \param this pointer to an object
8141 * \param klass klass of the object containing \p field
8142 * \param field the field to load
8143 * \param res a storage to store the result
8144 * This method is called by the runtime on attempts to load fields of
8145 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8146 * the object containing \p field. \p res is a storage location which can be
8147 * used to store the result.
8148 * \returns an address pointing to the value of field.
8149 */
8150 gpointer
mono_load_remote_field(MonoObject * this_obj,MonoClass * klass,MonoClassField * field,gpointer * res)8151 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8152 {
8153 MonoError error;
8154 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8155 mono_error_cleanup (&error);
8156 return result;
8157 }
8158
8159 /**
8160 * mono_load_remote_field_checked:
8161 * \param this pointer to an object
8162 * \param klass klass of the object containing \p field
8163 * \param field the field to load
8164 * \param res a storage to store the result
8165 * \param error set on error
8166 * This method is called by the runtime on attempts to load fields of
8167 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8168 * the object containing \p field. \p res is a storage location which can be
8169 * used to store the result.
8170 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8171 */
8172 gpointer
mono_load_remote_field_checked(MonoObject * this_obj,MonoClass * klass,MonoClassField * field,gpointer * res,MonoError * error)8173 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8174 {
8175 MONO_REQ_GC_UNSAFE_MODE;
8176
8177 static MonoMethod *getter = NULL;
8178
8179 error_init (error);
8180
8181 MonoDomain *domain = mono_domain_get ();
8182 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8183 MonoClass *field_class;
8184 MonoMethodMessage *msg;
8185 MonoArray *out_args;
8186 MonoObject *exc;
8187 char* full_name;
8188
8189 g_assert (mono_object_is_transparent_proxy (this_obj));
8190 g_assert (res != NULL);
8191
8192 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8193 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8194 return res;
8195 }
8196
8197 if (!getter) {
8198 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8199 if (!getter) {
8200 mono_error_set_not_supported (error, "Linked away.");
8201 return NULL;
8202 }
8203 }
8204
8205 field_class = mono_class_from_mono_type (field->type);
8206
8207 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8208 return_val_if_nok (error, NULL);
8209 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8210 return_val_if_nok (error, NULL);
8211 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8212 return_val_if_nok (error, NULL);
8213 mono_message_init (domain, msg, rm, out_args, error);
8214 return_val_if_nok (error, NULL);
8215
8216 full_name = mono_type_get_full_name (klass);
8217 MonoString *full_name_str = mono_string_new_checked (domain, full_name, error);
8218 g_free (full_name);
8219 return_val_if_nok (error, NULL);
8220 mono_array_setref (msg->args, 0, full_name_str);
8221 MonoString *field_name = mono_string_new_checked (domain, mono_field_get_name (field), error);
8222 return_val_if_nok (error, NULL);
8223 mono_array_setref (msg->args, 1, field_name);
8224
8225 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8226 return_val_if_nok (error, NULL);
8227
8228 if (exc) {
8229 mono_error_set_exception_instance (error, (MonoException *)exc);
8230 return NULL;
8231 }
8232
8233 if (mono_array_length (out_args) == 0)
8234 return NULL;
8235
8236 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8237
8238 if (field_class->valuetype) {
8239 return ((char *)*res) + sizeof (MonoObject);
8240 } else
8241 return res;
8242 }
8243
8244 /**
8245 * mono_load_remote_field_new:
8246 * \param this
8247 * \param klass
8248 * \param field
8249 * Missing documentation.
8250 */
8251 MonoObject *
mono_load_remote_field_new(MonoObject * this_obj,MonoClass * klass,MonoClassField * field)8252 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8253 {
8254 MonoError error;
8255
8256 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8257 mono_error_cleanup (&error);
8258 return result;
8259 }
8260
8261 /**
8262 * mono_load_remote_field_new_checked:
8263 * \param this pointer to an object
8264 * \param klass klass of the object containing \p field
8265 * \param field the field to load
8266 * \param error set on error.
8267 * This method is called by the runtime on attempts to load fields of
8268 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8269 * the object containing \p field.
8270 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
8271 */
8272 MonoObject *
mono_load_remote_field_new_checked(MonoObject * this_obj,MonoClass * klass,MonoClassField * field,MonoError * error)8273 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8274 {
8275 MONO_REQ_GC_UNSAFE_MODE;
8276
8277 error_init (error);
8278
8279 static MonoMethod *tp_load = NULL;
8280
8281 g_assert (mono_object_is_transparent_proxy (this_obj));
8282
8283 if (!tp_load) {
8284 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8285 if (!tp_load) {
8286 mono_error_set_not_supported (error, "Linked away.");
8287 return NULL;
8288 }
8289 }
8290
8291 /* MonoType *type = mono_class_get_type (klass); */
8292
8293 gpointer args[2];
8294 args [0] = &klass;
8295 args [1] = &field;
8296
8297 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8298 }
8299
8300 /**
8301 * mono_store_remote_field:
8302 * \param this_obj pointer to an object
8303 * \param klass klass of the object containing \p field
8304 * \param field the field to load
8305 * \param val the value/object to store
8306 * This method is called by the runtime on attempts to store fields of
8307 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8308 * the object containing \p field. \p val is the new value to store in \p field.
8309 */
8310 void
mono_store_remote_field(MonoObject * this_obj,MonoClass * klass,MonoClassField * field,gpointer val)8311 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8312 {
8313 MonoError error;
8314 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8315 mono_error_cleanup (&error);
8316 }
8317
8318 /**
8319 * mono_store_remote_field_checked:
8320 * \param this_obj pointer to an object
8321 * \param klass klass of the object containing \p field
8322 * \param field the field to load
8323 * \param val the value/object to store
8324 * \param error set on error
8325 * This method is called by the runtime on attempts to store fields of
8326 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8327 * the object containing \p field. \p val is the new value to store in \p field.
8328 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8329 */
8330 gboolean
mono_store_remote_field_checked(MonoObject * this_obj,MonoClass * klass,MonoClassField * field,gpointer val,MonoError * error)8331 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8332 {
8333
8334 MONO_REQ_GC_UNSAFE_MODE;
8335
8336 error_init (error);
8337
8338 MonoDomain *domain = mono_domain_get ();
8339 MonoClass *field_class;
8340 MonoObject *arg;
8341
8342 g_assert (mono_object_is_transparent_proxy (this_obj));
8343
8344 field_class = mono_class_from_mono_type (field->type);
8345
8346 if (field_class->valuetype) {
8347 arg = mono_value_box_checked (domain, field_class, val, error);
8348 return_val_if_nok (error, FALSE);
8349 } else {
8350 arg = *((MonoObject**)val);
8351 }
8352
8353 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8354 }
8355
8356 /**
8357 * mono_store_remote_field_new:
8358 * \param this_obj
8359 * \param klass
8360 * \param field
8361 * \param arg
8362 * Missing documentation
8363 */
8364 void
mono_store_remote_field_new(MonoObject * this_obj,MonoClass * klass,MonoClassField * field,MonoObject * arg)8365 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8366 {
8367 MonoError error;
8368 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8369 mono_error_cleanup (&error);
8370 }
8371
8372 /**
8373 * mono_store_remote_field_new_checked:
8374 * \param this_obj
8375 * \param klass
8376 * \param field
8377 * \param arg
8378 * \param error
8379 * Missing documentation
8380 */
8381 gboolean
mono_store_remote_field_new_checked(MonoObject * this_obj,MonoClass * klass,MonoClassField * field,MonoObject * arg,MonoError * error)8382 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8383 {
8384 MONO_REQ_GC_UNSAFE_MODE;
8385
8386 static MonoMethod *tp_store = NULL;
8387
8388 error_init (error);
8389
8390 g_assert (mono_object_is_transparent_proxy (this_obj));
8391
8392 if (!tp_store) {
8393 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8394 if (!tp_store) {
8395 mono_error_set_not_supported (error, "Linked away.");
8396 return FALSE;
8397 }
8398 }
8399
8400 gpointer args[3];
8401 args [0] = &klass;
8402 args [1] = &field;
8403 args [2] = arg;
8404
8405 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8406 return is_ok (error);
8407 }
8408 #endif
8409
8410 /**
8411 * mono_create_ftnptr:
8412 *
8413 * Given a function address, create a function descriptor for it.
8414 * This is only needed on some platforms.
8415 */
8416 gpointer
mono_create_ftnptr(MonoDomain * domain,gpointer addr)8417 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8418 {
8419 return callbacks.create_ftnptr (domain, addr);
8420 }
8421
8422 /*
8423 * mono_get_addr_from_ftnptr:
8424 *
8425 * Given a pointer to a function descriptor, return the function address.
8426 * This is only needed on some platforms.
8427 */
8428 gpointer
mono_get_addr_from_ftnptr(gpointer descr)8429 mono_get_addr_from_ftnptr (gpointer descr)
8430 {
8431 return callbacks.get_addr_from_ftnptr (descr);
8432 }
8433
8434 /**
8435 * mono_string_chars:
8436 * \param s a \c MonoString
8437 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8438 */
8439 gunichar2 *
mono_string_chars(MonoString * s)8440 mono_string_chars (MonoString *s)
8441 {
8442 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8443
8444 return s->chars;
8445 }
8446
8447 /**
8448 * mono_string_length:
8449 * \param s MonoString
8450 * \returns the length in characters of the string
8451 */
8452 int
mono_string_length(MonoString * s)8453 mono_string_length (MonoString *s)
8454 {
8455 MONO_REQ_GC_UNSAFE_MODE;
8456
8457 return s->length;
8458 }
8459
8460 /**
8461 * mono_string_handle_length:
8462 * \param s \c MonoString
8463 * \returns the length in characters of the string
8464 */
8465 int
mono_string_handle_length(MonoStringHandle s)8466 mono_string_handle_length (MonoStringHandle s)
8467 {
8468 MONO_REQ_GC_UNSAFE_MODE;
8469
8470 return MONO_HANDLE_GETVAL (s, length);
8471 }
8472
8473
8474 /**
8475 * mono_array_length:
8476 * \param array a \c MonoArray*
8477 * \returns the total number of elements in the array. This works for
8478 * both vectors and multidimensional arrays.
8479 */
8480 uintptr_t
mono_array_length(MonoArray * array)8481 mono_array_length (MonoArray *array)
8482 {
8483 MONO_REQ_GC_UNSAFE_MODE;
8484
8485 return array->max_length;
8486 }
8487
8488 /**
8489 * mono_array_addr_with_size:
8490 * \param array a \c MonoArray*
8491 * \param size size of the array elements
8492 * \param idx index into the array
8493 * Use this function to obtain the address for the \p idx item on the
8494 * \p array containing elements of size \p size.
8495 *
8496 * This method performs no bounds checking or type checking.
8497 * \returns the address of the \p idx element in the array.
8498 */
8499 char*
mono_array_addr_with_size(MonoArray * array,int size,uintptr_t idx)8500 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8501 {
8502 MONO_REQ_GC_UNSAFE_MODE;
8503
8504 return ((char*)(array)->vector) + size * idx;
8505 }
8506
8507
8508 MonoArray *
mono_glist_to_array(GList * list,MonoClass * eclass,MonoError * error)8509 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8510 {
8511 MonoDomain *domain = mono_domain_get ();
8512 MonoArray *res;
8513 int len, i;
8514
8515 error_init (error);
8516 if (!list)
8517 return NULL;
8518
8519 len = g_list_length (list);
8520 res = mono_array_new_checked (domain, eclass, len, error);
8521 return_val_if_nok (error, NULL);
8522
8523 for (i = 0; list; list = list->next, i++)
8524 mono_array_set (res, gpointer, i, list->data);
8525
8526 return res;
8527 }
8528
8529 #if NEVER_DEFINED
8530 /*
8531 * The following section is purely to declare prototypes and
8532 * document the API, as these C files are processed by our
8533 * tool
8534 */
8535
8536 /**
8537 * mono_array_set:
8538 * \param array array to alter
8539 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8540 * \param index index into the array
8541 * \param value value to set
8542 * Value Type version: This sets the \p index's element of the \p array
8543 * with elements of size sizeof(type) to the provided \p value.
8544 *
8545 * This macro does not attempt to perform type checking or bounds checking.
8546 *
8547 * Use this to set value types in a \c MonoArray.
8548 */
mono_array_set(MonoArray * array,Type element_type,uintptr_t index,Value value)8549 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8550 {
8551 }
8552
8553 /**
8554 * mono_array_setref:
8555 * \param array array to alter
8556 * \param index index into the array
8557 * \param value value to set
8558 * Reference Type version. This sets the \p index's element of the
8559 * \p array with elements of size sizeof(type) to the provided \p value.
8560 *
8561 * This macro does not attempt to perform type checking or bounds checking.
8562 *
8563 * Use this to reference types in a \c MonoArray.
8564 */
mono_array_setref(MonoArray * array,uintptr_t index,MonoObject * object)8565 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8566 {
8567 }
8568
8569 /**
8570 * mono_array_get:
8571 * \param array array on which to operate on
8572 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8573 * \param index index into the array
8574 *
8575 * Use this macro to retrieve the \p index element of an \p array and
8576 * extract the value assuming that the elements of the array match
8577 * the provided type value.
8578 *
8579 * This method can be used with both arrays holding value types and
8580 * reference types. For reference types, the \p type parameter should
8581 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8582 *
8583 * This macro does not attempt to perform type checking or bounds checking.
8584 *
8585 * \returns The element at the \p index position in the \p array.
8586 */
mono_array_get(MonoArray * array,Type element_type,uintptr_t index)8587 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
8588 {
8589 }
8590 #endif
8591
8592