[sgen] Split up concurrent sweep from worker logic
[mono.git] / mono / metadata / sgen-mono.c
1 /**
2  * \file
3  * SGen features specific to Mono.
4  *
5  * Copyright (C) 2014 Xamarin Inc
6  *
7  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
8  */
9
10 #include "config.h"
11 #ifdef HAVE_SGEN_GC
12
13 #include "sgen/sgen-gc.h"
14 #include "sgen/sgen-protocol.h"
15 #include "metadata/monitor.h"
16 #include "sgen/sgen-layout-stats.h"
17 #include "sgen/sgen-client.h"
18 #include "sgen/sgen-cardtable.h"
19 #include "sgen/sgen-pinning.h"
20 #include "sgen/sgen-workers.h"
21 #include "metadata/marshal.h"
22 #include "metadata/method-builder.h"
23 #include "metadata/abi-details.h"
24 #include "metadata/mono-gc.h"
25 #include "metadata/runtime.h"
26 #include "metadata/sgen-bridge-internals.h"
27 #include "metadata/gc-internals.h"
28 #include "metadata/handle.h"
29 #include "utils/mono-memory-model.h"
30 #include "utils/mono-logger-internals.h"
31 #include "utils/mono-threads-coop.h"
32 #include "utils/mono-threads.h"
33 #include "metadata/w32handle.h"
34
35 #ifdef HEAVY_STATISTICS
36 static guint64 stat_wbarrier_set_arrayref = 0;
37 static guint64 stat_wbarrier_value_copy = 0;
38 static guint64 stat_wbarrier_object_copy = 0;
39
40 static guint64 los_marked_cards;
41 static guint64 los_array_cards;
42 static guint64 los_array_remsets;
43 #endif
44
45 /* If set, mark stacks conservatively, even if precise marking is possible */
46 static gboolean conservative_stack_mark = FALSE;
47 /* If set, check that there are no references to the domain left at domain unload */
48 gboolean sgen_mono_xdomain_checks = FALSE;
49
50 /* Functions supplied by the runtime to be called by the GC */
51 static MonoGCCallbacks gc_callbacks;
52
53 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
54
55 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
56         a = i,
57
58 enum {
59 #include "mono/cil/opcode.def"
60         CEE_LAST
61 };
62
63 #undef OPDEF
64
65 /*
66  * Write barriers
67  */
68
69 static gboolean
70 ptr_on_stack (void *ptr)
71 {
72         gpointer stack_start = &stack_start;
73         SgenThreadInfo *info = mono_thread_info_current ();
74
75         if (ptr >= stack_start && ptr < (gpointer)info->client_info.stack_end)
76                 return TRUE;
77         return FALSE;
78 }
79
80 #ifdef SGEN_HEAVY_BINARY_PROTOCOL
81 #undef HANDLE_PTR
82 #define HANDLE_PTR(ptr,obj) do {                                        \
83                 gpointer o = *(gpointer*)(ptr);                         \
84                 if ((o)) {                                              \
85                         gpointer d = ((char*)dest) + ((char*)(ptr) - (char*)(obj)); \
86                         binary_protocol_wbarrier (d, o, (gpointer) SGEN_LOAD_VTABLE (o)); \
87                 }                                                       \
88         } while (0)
89
90 static void
91 scan_object_for_binary_protocol_copy_wbarrier (gpointer dest, char *start, mword desc)
92 {
93 #define SCAN_OBJECT_NOVTABLE
94 #include "sgen/sgen-scan-object.h"
95 }
96 #endif
97
98 void
99 mono_gc_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass *klass)
100 {
101         HEAVY_STAT (++stat_wbarrier_value_copy);
102         g_assert (klass->valuetype);
103
104         SGEN_LOG (8, "Adding value remset at %p, count %d, descr %p for class %s (%p)", dest, count, (gpointer)klass->gc_descr, klass->name, klass);
105
106         if (sgen_ptr_in_nursery (dest) || ptr_on_stack (dest) || !sgen_gc_descr_has_references ((mword)klass->gc_descr)) {
107                 size_t element_size = mono_class_value_size (klass, NULL);
108                 size_t size = count * element_size;
109                 mono_gc_memmove_atomic (dest, src, size);               
110                 return;
111         }
112
113 #ifdef SGEN_HEAVY_BINARY_PROTOCOL
114         if (binary_protocol_is_heavy_enabled ()) {
115                 size_t element_size = mono_class_value_size (klass, NULL);
116                 int i;
117                 for (i = 0; i < count; ++i) {
118                         scan_object_for_binary_protocol_copy_wbarrier ((char*)dest + i * element_size,
119                                         (char*)src + i * element_size - sizeof (MonoObject),
120                                         (mword) klass->gc_descr);
121                 }
122         }
123 #endif
124
125         sgen_get_remset ()->wbarrier_value_copy (dest, src, count, mono_class_value_size (klass, NULL));
126 }
127
128 /**
129  * mono_gc_wbarrier_object_copy:
130  *
131  * Write barrier to call when \p obj is the result of a clone or copy of an object.
132  */
133 void
134 mono_gc_wbarrier_object_copy (MonoObject* obj, MonoObject *src)
135 {
136         int size;
137
138         HEAVY_STAT (++stat_wbarrier_object_copy);
139
140         SGEN_ASSERT (6, !ptr_on_stack (obj), "Why is this called for a non-reference type?");
141         if (sgen_ptr_in_nursery (obj) || !SGEN_OBJECT_HAS_REFERENCES (src)) {
142                 size = mono_object_class (obj)->instance_size;
143                 mono_gc_memmove_aligned ((char*)obj + sizeof (MonoObject), (char*)src + sizeof (MonoObject),
144                                 size - sizeof (MonoObject));
145                 return; 
146         }
147
148 #ifdef SGEN_HEAVY_BINARY_PROTOCOL
149         if (binary_protocol_is_heavy_enabled ())
150                 scan_object_for_binary_protocol_copy_wbarrier (obj, (char*)src, (mword) src->vtable->gc_descr);
151 #endif
152
153         sgen_get_remset ()->wbarrier_object_copy (obj, src);
154 }
155
156 /**
157  * mono_gc_wbarrier_set_arrayref:
158  */
159 void
160 mono_gc_wbarrier_set_arrayref (MonoArray *arr, gpointer slot_ptr, MonoObject* value)
161 {
162         HEAVY_STAT (++stat_wbarrier_set_arrayref);
163         if (sgen_ptr_in_nursery (slot_ptr)) {
164                 *(void**)slot_ptr = value;
165                 return;
166         }
167         SGEN_LOG (8, "Adding remset at %p", slot_ptr);
168         if (value)
169                 binary_protocol_wbarrier (slot_ptr, value, value->vtable);
170
171         sgen_get_remset ()->wbarrier_set_field ((GCObject*)arr, slot_ptr, value);
172 }
173
174 /**
175  * mono_gc_wbarrier_set_field:
176  */
177 void
178 mono_gc_wbarrier_set_field (MonoObject *obj, gpointer field_ptr, MonoObject* value)
179 {
180         mono_gc_wbarrier_set_arrayref ((MonoArray*)obj, field_ptr, value);
181 }
182
183 void
184 mono_gc_wbarrier_value_copy_bitmap (gpointer _dest, gpointer _src, int size, unsigned bitmap)
185 {
186         sgen_wbarrier_value_copy_bitmap (_dest, _src, size, bitmap);
187 }
188
189 int
190 mono_gc_get_suspend_signal (void)
191 {
192         return mono_threads_suspend_get_suspend_signal ();
193 }
194
195 int
196 mono_gc_get_restart_signal (void)
197 {
198         return mono_threads_suspend_get_restart_signal ();
199 }
200
201 static MonoMethod *write_barrier_conc_method;
202 static MonoMethod *write_barrier_noconc_method;
203
204 gboolean
205 sgen_is_critical_method (MonoMethod *method)
206 {
207         return sgen_is_managed_allocator (method);
208 }
209
210 gboolean
211 sgen_has_critical_method (void)
212 {
213         return sgen_has_managed_allocator ();
214 }
215
216 static gboolean
217 ip_in_critical_region (MonoDomain *domain, gpointer ip)
218 {
219         MonoJitInfo *ji;
220         MonoMethod *method;
221
222         /*
223          * We pass false for 'try_aot' so this becomes async safe.
224          * It won't find aot methods whose jit info is not yet loaded,
225          * so we preload their jit info in the JIT.
226          */
227         ji = mono_jit_info_table_find_internal (domain, ip, FALSE, FALSE);
228         if (!ji)
229                 return FALSE;
230
231         method = mono_jit_info_get_method (ji);
232
233         return mono_runtime_is_critical_method (method) || sgen_is_critical_method (method);
234 }
235
236 gboolean
237 mono_gc_is_critical_method (MonoMethod *method)
238 {
239         return sgen_is_critical_method (method);
240 }
241
242 #ifndef DISABLE_JIT
243
244 static void
245 emit_nursery_check (MonoMethodBuilder *mb, int *nursery_check_return_labels, gboolean is_concurrent)
246 {
247         int shifted_nursery_start = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
248
249         memset (nursery_check_return_labels, 0, sizeof (int) * 2);
250         // if (ptr_in_nursery (ptr)) return;
251         /*
252          * Masking out the bits might be faster, but we would have to use 64 bit
253          * immediates, which might be slower.
254          */
255         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
256         mono_mb_emit_byte (mb, CEE_MONO_LDPTR_NURSERY_START);
257         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
258         mono_mb_emit_byte (mb, CEE_MONO_LDPTR_NURSERY_BITS);
259         mono_mb_emit_byte (mb, CEE_SHR_UN);
260         mono_mb_emit_stloc (mb, shifted_nursery_start);
261
262         mono_mb_emit_ldarg (mb, 0);
263         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
264         mono_mb_emit_byte (mb, CEE_MONO_LDPTR_NURSERY_BITS);
265         mono_mb_emit_byte (mb, CEE_SHR_UN);
266         mono_mb_emit_ldloc (mb, shifted_nursery_start);
267         nursery_check_return_labels [0] = mono_mb_emit_branch (mb, CEE_BEQ);
268
269         if (!is_concurrent) {
270                 // if (!ptr_in_nursery (*ptr)) return;
271                 mono_mb_emit_ldarg (mb, 0);
272                 mono_mb_emit_byte (mb, CEE_LDIND_I);
273                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
274                 mono_mb_emit_byte (mb, CEE_MONO_LDPTR_NURSERY_BITS);
275                 mono_mb_emit_byte (mb, CEE_SHR_UN);
276                 mono_mb_emit_ldloc (mb, shifted_nursery_start);
277                 nursery_check_return_labels [1] = mono_mb_emit_branch (mb, CEE_BNE_UN);
278         }
279 }
280 #endif
281
282 MonoMethod*
283 mono_gc_get_specific_write_barrier (gboolean is_concurrent)
284 {
285         MonoMethod *res;
286         MonoMethodBuilder *mb;
287         MonoMethodSignature *sig;
288         MonoMethod **write_barrier_method_addr;
289         WrapperInfo *info;
290 #ifdef MANAGED_WBARRIER
291         int i, nursery_check_labels [2];
292 #endif
293
294         // FIXME: Maybe create a separate version for ctors (the branch would be
295         // correctly predicted more times)
296         if (is_concurrent)
297                 write_barrier_method_addr = &write_barrier_conc_method;
298         else
299                 write_barrier_method_addr = &write_barrier_noconc_method;
300
301         if (*write_barrier_method_addr)
302                 return *write_barrier_method_addr;
303
304         /* Create the IL version of mono_gc_barrier_generic_store () */
305         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
306         sig->ret = &mono_defaults.void_class->byval_arg;
307         sig->params [0] = &mono_defaults.int_class->byval_arg;
308
309         if (is_concurrent)
310                 mb = mono_mb_new (mono_defaults.object_class, "wbarrier_conc", MONO_WRAPPER_WRITE_BARRIER);
311         else
312                 mb = mono_mb_new (mono_defaults.object_class, "wbarrier_noconc", MONO_WRAPPER_WRITE_BARRIER);
313
314 #ifndef DISABLE_JIT
315 #ifdef MANAGED_WBARRIER
316         emit_nursery_check (mb, nursery_check_labels, is_concurrent);
317         /*
318         addr = sgen_cardtable + ((address >> CARD_BITS) & CARD_MASK)
319         *addr = 1;
320
321         sgen_cardtable:
322                 LDC_PTR sgen_cardtable
323
324         address >> CARD_BITS
325                 LDARG_0
326                 LDC_I4 CARD_BITS
327                 SHR_UN
328         if (SGEN_HAVE_OVERLAPPING_CARDS) {
329                 LDC_PTR card_table_mask
330                 AND
331         }
332         AND
333         ldc_i4_1
334         stind_i1
335         */
336         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
337         mono_mb_emit_byte (mb, CEE_MONO_LDPTR_CARD_TABLE);
338         mono_mb_emit_ldarg (mb, 0);
339         mono_mb_emit_icon (mb, CARD_BITS);
340         mono_mb_emit_byte (mb, CEE_SHR_UN);
341         mono_mb_emit_byte (mb, CEE_CONV_I);
342 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
343 #if SIZEOF_VOID_P == 8
344         mono_mb_emit_icon8 (mb, CARD_MASK);
345 #else
346         mono_mb_emit_icon (mb, CARD_MASK);
347 #endif
348         mono_mb_emit_byte (mb, CEE_CONV_I);
349         mono_mb_emit_byte (mb, CEE_AND);
350 #endif
351         mono_mb_emit_byte (mb, CEE_ADD);
352         mono_mb_emit_icon (mb, 1);
353         mono_mb_emit_byte (mb, CEE_STIND_I1);
354
355         // return;
356         for (i = 0; i < 2; ++i) {
357                 if (nursery_check_labels [i])
358                         mono_mb_patch_branch (mb, nursery_check_labels [i]);
359         }
360         mono_mb_emit_byte (mb, CEE_RET);
361 #else
362         mono_mb_emit_ldarg (mb, 0);
363         mono_mb_emit_icall (mb, mono_gc_wbarrier_generic_nostore);
364         mono_mb_emit_byte (mb, CEE_RET);
365 #endif
366 #endif
367         res = mono_mb_create_method (mb, sig, 16);
368         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
369         mono_marshal_set_wrapper_info (res, info);
370         mono_mb_free (mb);
371
372         LOCK_GC;
373         if (*write_barrier_method_addr) {
374                 /* Already created */
375                 mono_free_method (res);
376         } else {
377                 /* double-checked locking */
378                 mono_memory_barrier ();
379                 *write_barrier_method_addr = res;
380         }
381         UNLOCK_GC;
382
383         return *write_barrier_method_addr;
384 }
385
386 MonoMethod*
387 mono_gc_get_write_barrier (void)
388 {
389         return mono_gc_get_specific_write_barrier (major_collector.is_concurrent);
390 }
391
392 /*
393  * Dummy filler objects
394  */
395
396 /* Vtable of the objects used to fill out nursery fragments before a collection */
397 static GCVTable array_fill_vtable;
398
399 static GCVTable
400 get_array_fill_vtable (void)
401 {
402         if (!array_fill_vtable) {
403                 static MonoClass klass;
404                 static char _vtable[sizeof(MonoVTable)+8];
405                 MonoVTable* vtable = (MonoVTable*) ALIGN_TO((mword)_vtable, 8);
406                 gsize bmap;
407
408                 MonoDomain *domain = mono_get_root_domain ();
409                 g_assert (domain);
410
411                 klass.element_class = mono_defaults.byte_class;
412                 klass.rank = 1;
413                 klass.instance_size = MONO_SIZEOF_MONO_ARRAY;
414                 klass.sizes.element_size = 1;
415                 klass.name = "array_filler_type";
416
417                 vtable->klass = &klass;
418                 bmap = 0;
419                 vtable->gc_descr = mono_gc_make_descr_for_array (TRUE, &bmap, 0, 1);
420                 vtable->rank = 1;
421
422                 array_fill_vtable = vtable;
423         }
424         return array_fill_vtable;
425 }
426
427 gboolean
428 sgen_client_array_fill_range (char *start, size_t size)
429 {
430         MonoArray *o;
431
432         if (size < MONO_SIZEOF_MONO_ARRAY) {
433                 memset (start, 0, size);
434                 return FALSE;
435         }
436
437         o = (MonoArray*)start;
438         o->obj.vtable = (MonoVTable*)get_array_fill_vtable ();
439         /* Mark this as not a real object */
440         o->obj.synchronisation = (MonoThreadsSync *)GINT_TO_POINTER (-1);
441         o->bounds = NULL;
442         o->max_length = (mono_array_size_t)(size - MONO_SIZEOF_MONO_ARRAY);
443
444         return TRUE;
445 }
446
447 void
448 sgen_client_zero_array_fill_header (void *p, size_t size)
449 {
450         if (size >= MONO_SIZEOF_MONO_ARRAY) {
451                 memset (p, 0, MONO_SIZEOF_MONO_ARRAY);
452         } else {
453                 static guint8 zeros [MONO_SIZEOF_MONO_ARRAY];
454
455                 SGEN_ASSERT (0, !memcmp (p, zeros, size), "TLAB segment must be zeroed out.");
456         }
457 }
458
459 /*
460  * Finalization
461  */
462
463 static MonoGCFinalizerCallbacks fin_callbacks;
464
465 guint
466 mono_gc_get_vtable_bits (MonoClass *klass)
467 {
468         guint res = 0;
469         /* FIXME move this to the bridge code */
470         if (sgen_need_bridge_processing ()) {
471                 switch (sgen_bridge_class_kind (klass)) {
472                 case GC_BRIDGE_TRANSPARENT_BRIDGE_CLASS:
473                 case GC_BRIDGE_OPAQUE_BRIDGE_CLASS:
474                         res = SGEN_GC_BIT_BRIDGE_OBJECT;
475                         break;
476                 case GC_BRIDGE_OPAQUE_CLASS:
477                         res = SGEN_GC_BIT_BRIDGE_OPAQUE_OBJECT;
478                         break;
479                 case GC_BRIDGE_TRANSPARENT_CLASS:
480                         break;
481                 }
482         }
483         if (fin_callbacks.is_class_finalization_aware) {
484                 if (fin_callbacks.is_class_finalization_aware (klass))
485                         res |= SGEN_GC_BIT_FINALIZER_AWARE;
486         }
487         return res;
488 }
489
490 static gboolean
491 is_finalization_aware (MonoObject *obj)
492 {
493         MonoVTable *vt = SGEN_LOAD_VTABLE (obj);
494         return (vt->gc_bits & SGEN_GC_BIT_FINALIZER_AWARE) == SGEN_GC_BIT_FINALIZER_AWARE;
495 }
496
497 void
498 sgen_client_object_queued_for_finalization (GCObject *obj)
499 {
500         if (fin_callbacks.object_queued_for_finalization && is_finalization_aware (obj))
501                 fin_callbacks.object_queued_for_finalization (obj);
502
503 #ifdef ENABLE_DTRACE
504         if (G_UNLIKELY (MONO_GC_FINALIZE_ENQUEUE_ENABLED ())) {
505                 int gen = sgen_ptr_in_nursery (obj) ? GENERATION_NURSERY : GENERATION_OLD;
506                 GCVTable vt = SGEN_LOAD_VTABLE (obj);
507                 MONO_GC_FINALIZE_ENQUEUE ((mword)obj, sgen_safe_object_get_size (obj),
508                                 sgen_client_vtable_get_namespace (vt), sgen_client_vtable_get_name (vt), gen,
509                                 sgen_client_object_has_critical_finalizer (obj));
510         }
511 #endif
512 }
513
514 void
515 mono_gc_register_finalizer_callbacks (MonoGCFinalizerCallbacks *callbacks)
516 {
517         if (callbacks->version != MONO_GC_FINALIZER_EXTENSION_VERSION)
518                 g_error ("Invalid finalizer callback version. Expected %d but got %d\n", MONO_GC_FINALIZER_EXTENSION_VERSION, callbacks->version);
519
520         fin_callbacks = *callbacks;
521 }
522
523 void
524 sgen_client_run_finalize (MonoObject *obj)
525 {
526         mono_gc_run_finalize (obj, NULL);
527 }
528
529 /**
530  * mono_gc_invoke_finalizers:
531  */
532 int
533 mono_gc_invoke_finalizers (void)
534 {
535         return sgen_gc_invoke_finalizers ();
536 }
537
538 /**
539  * mono_gc_pending_finalizers:
540  */
541 MonoBoolean
542 mono_gc_pending_finalizers (void)
543 {
544         return sgen_have_pending_finalizers ();
545 }
546
547 void
548 sgen_client_finalize_notify (void)
549 {
550         mono_gc_finalize_notify ();
551 }
552
553 void
554 mono_gc_register_for_finalization (MonoObject *obj, void *user_data)
555 {
556         sgen_object_register_for_finalization (obj, user_data);
557 }
558
559 static gboolean
560 object_in_domain_predicate (MonoObject *obj, void *user_data)
561 {
562         MonoDomain *domain = (MonoDomain *)user_data;
563         if (mono_object_domain (obj) == domain) {
564                 SGEN_LOG (5, "Unregistering finalizer for object: %p (%s)", obj, sgen_client_vtable_get_name (SGEN_LOAD_VTABLE (obj)));
565                 return TRUE;
566         }
567         return FALSE;
568 }
569
570 /**
571  * mono_gc_finalizers_for_domain:
572  * \param domain the unloading appdomain
573  * \param out_array output array
574  * \param out_size size of output array
575  * Enqueue for finalization all objects that belong to the unloading appdomain \p domain.
576  * \p suspend is used for early termination of the enqueuing process.
577  */
578 void
579 mono_gc_finalize_domain (MonoDomain *domain)
580 {
581         sgen_finalize_if (object_in_domain_predicate, domain);
582 }
583
584 void
585 mono_gc_suspend_finalizers (void)
586 {
587         sgen_set_suspend_finalizers ();
588 }
589
590 /*
591  * Ephemerons
592  */
593
594 typedef struct _EphemeronLinkNode EphemeronLinkNode;
595
596 struct _EphemeronLinkNode {
597         EphemeronLinkNode *next;
598         MonoArray *array;
599 };
600
601 typedef struct {
602        GCObject *key;
603        GCObject *value;
604 } Ephemeron;
605
606 static EphemeronLinkNode *ephemeron_list;
607
608 /* LOCKING: requires that the GC lock is held */
609 static void
610 null_ephemerons_for_domain (MonoDomain *domain)
611 {
612         EphemeronLinkNode *current = ephemeron_list, *prev = NULL;
613
614         while (current) {
615                 MonoObject *object = (MonoObject*)current->array;
616
617                 if (object)
618                         SGEN_ASSERT (0, object->vtable, "Can't have objects without vtables.");
619
620                 if (object && object->vtable->domain == domain) {
621                         EphemeronLinkNode *tmp = current;
622
623                         if (prev)
624                                 prev->next = current->next;
625                         else
626                                 ephemeron_list = current->next;
627
628                         current = current->next;
629                         sgen_free_internal (tmp, INTERNAL_MEM_EPHEMERON_LINK);
630                 } else {
631                         prev = current;
632                         current = current->next;
633                 }
634         }
635 }
636
637 /* LOCKING: requires that the GC lock is held */
638 void
639 sgen_client_clear_unreachable_ephemerons (ScanCopyContext ctx)
640 {
641         CopyOrMarkObjectFunc copy_func = ctx.ops->copy_or_mark_object;
642         SgenGrayQueue *queue = ctx.queue;
643         EphemeronLinkNode *current = ephemeron_list, *prev = NULL;
644         Ephemeron *cur, *array_end;
645         GCObject *tombstone;
646
647         while (current) {
648                 MonoArray *array = current->array;
649
650                 if (!sgen_is_object_alive_for_current_gen ((GCObject*)array)) {
651                         EphemeronLinkNode *tmp = current;
652
653                         SGEN_LOG (5, "Dead Ephemeron array at %p", array);
654
655                         if (prev)
656                                 prev->next = current->next;
657                         else
658                                 ephemeron_list = current->next;
659
660                         current = current->next;
661                         sgen_free_internal (tmp, INTERNAL_MEM_EPHEMERON_LINK);
662
663                         continue;
664                 }
665
666                 copy_func ((GCObject**)&array, queue);
667                 current->array = array;
668
669                 SGEN_LOG (5, "Clearing unreachable entries for ephemeron array at %p", array);
670
671                 cur = mono_array_addr (array, Ephemeron, 0);
672                 array_end = cur + mono_array_length_fast (array);
673                 tombstone = SGEN_LOAD_VTABLE ((GCObject*)array)->domain->ephemeron_tombstone;
674
675                 for (; cur < array_end; ++cur) {
676                         GCObject *key = cur->key;
677
678                         if (!key || key == tombstone)
679                                 continue;
680
681                         SGEN_LOG (5, "[%zd] key %p (%s) value %p (%s)", cur - mono_array_addr (array, Ephemeron, 0),
682                                 key, sgen_is_object_alive_for_current_gen (key) ? "reachable" : "unreachable",
683                                 cur->value, cur->value && sgen_is_object_alive_for_current_gen (cur->value) ? "reachable" : "unreachable");
684
685                         if (!sgen_is_object_alive_for_current_gen (key)) {
686                                 cur->key = tombstone;
687                                 cur->value = NULL;
688                                 continue;
689                         }
690                 }
691                 prev = current;
692                 current = current->next;
693         }
694 }
695
696 /*
697 LOCKING: requires that the GC lock is held
698
699 Limitations: We scan all ephemerons on every collection since the current design doesn't allow for a simple nursery/mature split.
700 */
701 gboolean
702 sgen_client_mark_ephemerons (ScanCopyContext ctx)
703 {
704         CopyOrMarkObjectFunc copy_func = ctx.ops->copy_or_mark_object;
705         SgenGrayQueue *queue = ctx.queue;
706         gboolean nothing_marked = TRUE;
707         EphemeronLinkNode *current = ephemeron_list;
708         Ephemeron *cur, *array_end;
709         GCObject *tombstone;
710
711         for (current = ephemeron_list; current; current = current->next) {
712                 MonoArray *array = current->array;
713                 SGEN_LOG (5, "Ephemeron array at %p", array);
714
715                 /*It has to be alive*/
716                 if (!sgen_is_object_alive_for_current_gen ((GCObject*)array)) {
717                         SGEN_LOG (5, "\tnot reachable");
718                         continue;
719                 }
720
721                 copy_func ((GCObject**)&array, queue);
722
723                 cur = mono_array_addr (array, Ephemeron, 0);
724                 array_end = cur + mono_array_length_fast (array);
725                 tombstone = SGEN_LOAD_VTABLE ((GCObject*)array)->domain->ephemeron_tombstone;
726
727                 for (; cur < array_end; ++cur) {
728                         GCObject *key = cur->key;
729
730                         if (!key || key == tombstone)
731                                 continue;
732
733                         SGEN_LOG (5, "[%zd] key %p (%s) value %p (%s)", cur - mono_array_addr (array, Ephemeron, 0),
734                                 key, sgen_is_object_alive_for_current_gen (key) ? "reachable" : "unreachable",
735                                 cur->value, cur->value && sgen_is_object_alive_for_current_gen (cur->value) ? "reachable" : "unreachable");
736
737                         if (sgen_is_object_alive_for_current_gen (key)) {
738                                 GCObject *value = cur->value;
739
740                                 copy_func (&cur->key, queue);
741                                 if (value) {
742                                         if (!sgen_is_object_alive_for_current_gen (value))
743                                                 nothing_marked = FALSE;
744                                         copy_func (&cur->value, queue);
745                                 }
746                         }
747                 }
748         }
749
750         SGEN_LOG (5, "Ephemeron run finished. Is it done %d", nothing_marked);
751         return nothing_marked;
752 }
753
754 gboolean
755 mono_gc_ephemeron_array_add (MonoObject *obj)
756 {
757         EphemeronLinkNode *node;
758
759         LOCK_GC;
760
761         node = (EphemeronLinkNode *)sgen_alloc_internal (INTERNAL_MEM_EPHEMERON_LINK);
762         if (!node) {
763                 UNLOCK_GC;
764                 return FALSE;
765         }
766         node->array = (MonoArray*)obj;
767         node->next = ephemeron_list;
768         ephemeron_list = node;
769
770         SGEN_LOG (5, "Registered ephemeron array %p", obj);
771
772         UNLOCK_GC;
773         return TRUE;
774 }
775
776 /*
777  * Appdomain handling
778  */
779
780 static gboolean
781 need_remove_object_for_domain (GCObject *start, MonoDomain *domain)
782 {
783         if (mono_object_domain (start) == domain) {
784                 SGEN_LOG (4, "Need to cleanup object %p", start);
785                 binary_protocol_cleanup (start, (gpointer)SGEN_LOAD_VTABLE (start), sgen_safe_object_get_size ((GCObject*)start));
786                 return TRUE;
787         }
788         return FALSE;
789 }
790
791 static void
792 process_object_for_domain_clearing (GCObject *start, MonoDomain *domain)
793 {
794         MonoVTable *vt = SGEN_LOAD_VTABLE (start);
795         if (vt->klass == mono_defaults.internal_thread_class)
796                 g_assert (mono_object_domain (start) == mono_get_root_domain ());
797         /* The object could be a proxy for an object in the domain
798            we're deleting. */
799 #ifndef DISABLE_REMOTING
800         if (mono_defaults.real_proxy_class->supertypes && mono_class_has_parent_fast (vt->klass, mono_defaults.real_proxy_class)) {
801                 MonoObject *server = ((MonoRealProxy*)start)->unwrapped_server;
802
803                 /* The server could already have been zeroed out, so
804                    we need to check for that, too. */
805                 if (server && (!SGEN_LOAD_VTABLE (server) || mono_object_domain (server) == domain)) {
806                         SGEN_LOG (4, "Cleaning up remote pointer in %p to object %p", start, server);
807                         ((MonoRealProxy*)start)->unwrapped_server = NULL;
808                 }
809         }
810 #endif
811 }
812
813 static gboolean
814 clear_domain_process_object (GCObject *obj, MonoDomain *domain)
815 {
816         gboolean remove;
817
818         process_object_for_domain_clearing (obj, domain);
819         remove = need_remove_object_for_domain (obj, domain);
820
821         if (remove && obj->synchronisation) {
822                 guint32 dislink = mono_monitor_get_object_monitor_gchandle (obj);
823                 if (dislink)
824                         mono_gchandle_free (dislink);
825         }
826
827         return remove;
828 }
829
830 static void
831 clear_domain_process_minor_object_callback (GCObject *obj, size_t size, MonoDomain *domain)
832 {
833         if (clear_domain_process_object (obj, domain)) {
834                 CANARIFY_SIZE (size);
835                 memset (obj, 0, size);
836         }
837 }
838
839 static void
840 clear_domain_process_major_object_callback (GCObject *obj, size_t size, MonoDomain *domain)
841 {
842         clear_domain_process_object (obj, domain);
843 }
844
845 static void
846 clear_domain_free_major_non_pinned_object_callback (GCObject *obj, size_t size, MonoDomain *domain)
847 {
848         if (need_remove_object_for_domain (obj, domain))
849                 major_collector.free_non_pinned_object (obj, size);
850 }
851
852 static void
853 clear_domain_free_major_pinned_object_callback (GCObject *obj, size_t size, MonoDomain *domain)
854 {
855         if (need_remove_object_for_domain (obj, domain))
856                 major_collector.free_pinned_object (obj, size);
857 }
858
859 /*
860  * When appdomains are unloaded we can easily remove objects that have finalizers,
861  * but all the others could still be present in random places on the heap.
862  * We need a sweep to get rid of them even though it's going to be costly
863  * with big heaps.
864  * The reason we need to remove them is because we access the vtable and class
865  * structures to know the object size and the reference bitmap: once the domain is
866  * unloaded the point to random memory.
867  */
868 void
869 mono_gc_clear_domain (MonoDomain * domain)
870 {
871         LOSObject *bigobj, *prev;
872         int i;
873
874         LOCK_GC;
875
876         binary_protocol_domain_unload_begin (domain);
877
878         sgen_stop_world (0);
879
880         if (sgen_concurrent_collection_in_progress ())
881                 sgen_perform_collection (0, GENERATION_OLD, "clear domain", TRUE, FALSE);
882         SGEN_ASSERT (0, !sgen_concurrent_collection_in_progress (), "We just ordered a synchronous collection.  Why are we collecting concurrently?");
883
884         major_collector.finish_sweeping ();
885
886         sgen_process_fin_stage_entries ();
887
888         sgen_clear_nursery_fragments ();
889
890         if (sgen_mono_xdomain_checks && domain != mono_get_root_domain ()) {
891                 sgen_scan_for_registered_roots_in_domain (domain, ROOT_TYPE_NORMAL);
892                 sgen_scan_for_registered_roots_in_domain (domain, ROOT_TYPE_WBARRIER);
893                 sgen_check_for_xdomain_refs ();
894         }
895
896         /*Ephemerons and dislinks must be processed before LOS since they might end up pointing
897         to memory returned to the OS.*/
898         null_ephemerons_for_domain (domain);
899         sgen_null_links_for_domain (domain);
900
901         for (i = GENERATION_NURSERY; i < GENERATION_MAX; ++i)
902                 sgen_remove_finalizers_if (object_in_domain_predicate, domain, i);
903
904         sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data,
905                         (IterateObjectCallbackFunc)clear_domain_process_minor_object_callback, domain, FALSE, TRUE);
906
907         /* We need two passes over major and large objects because
908            freeing such objects might give their memory back to the OS
909            (in the case of large objects) or obliterate its vtable
910            (pinned objects with major-copying or pinned and non-pinned
911            objects with major-mark&sweep), but we might need to
912            dereference a pointer from an object to another object if
913            the first object is a proxy. */
914         major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)clear_domain_process_major_object_callback, domain);
915         for (bigobj = los_object_list; bigobj; bigobj = bigobj->next)
916                 clear_domain_process_object ((GCObject*)bigobj->data, domain);
917
918         prev = NULL;
919         for (bigobj = los_object_list; bigobj;) {
920                 if (need_remove_object_for_domain ((GCObject*)bigobj->data, domain)) {
921                         LOSObject *to_free = bigobj;
922                         if (prev)
923                                 prev->next = bigobj->next;
924                         else
925                                 los_object_list = bigobj->next;
926                         bigobj = bigobj->next;
927                         SGEN_LOG (4, "Freeing large object %p", bigobj->data);
928                         sgen_los_free_object (to_free);
929                         continue;
930                 }
931                 prev = bigobj;
932                 bigobj = bigobj->next;
933         }
934         major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_NON_PINNED, (IterateObjectCallbackFunc)clear_domain_free_major_non_pinned_object_callback, domain);
935         major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_PINNED, (IterateObjectCallbackFunc)clear_domain_free_major_pinned_object_callback, domain);
936
937         if (domain == mono_get_root_domain ()) {
938                 sgen_pin_stats_report ();
939                 sgen_object_layout_dump (stdout);
940         }
941
942         sgen_restart_world (0);
943
944         binary_protocol_domain_unload_end (domain);
945         binary_protocol_flush_buffers (FALSE);
946
947         UNLOCK_GC;
948 }
949
950 /*
951  * Allocation
952  */
953
954 void*
955 mono_gc_alloc_obj (MonoVTable *vtable, size_t size)
956 {
957         MonoObject *obj = sgen_alloc_obj (vtable, size);
958
959         if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) {
960                 if (obj)
961                         mono_profiler_allocation (obj);
962         }
963
964         return obj;
965 }
966
967 void*
968 mono_gc_alloc_pinned_obj (MonoVTable *vtable, size_t size)
969 {
970         MonoObject *obj = sgen_alloc_obj_pinned (vtable, size);
971
972         if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) {
973                 if (obj)
974                         mono_profiler_allocation (obj);
975         }
976
977         return obj;
978 }
979
980 void*
981 mono_gc_alloc_mature (MonoVTable *vtable, size_t size)
982 {
983         MonoObject *obj = sgen_alloc_obj_mature (vtable, size);
984
985         if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) {
986                 if (obj)
987                         mono_profiler_allocation (obj);
988         }
989
990         return obj;
991 }
992
993 /**
994  * mono_gc_alloc_fixed:
995  */
996 void*
997 mono_gc_alloc_fixed (size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg)
998 {
999         /* FIXME: do a single allocation */
1000         void *res = g_calloc (1, size);
1001         if (!res)
1002                 return NULL;
1003         if (!mono_gc_register_root ((char *)res, size, descr, source, msg)) {
1004                 g_free (res);
1005                 res = NULL;
1006         }
1007         return res;
1008 }
1009
1010 /**
1011  * mono_gc_free_fixed:
1012  */
1013 void
1014 mono_gc_free_fixed (void* addr)
1015 {
1016         mono_gc_deregister_root ((char *)addr);
1017         g_free (addr);
1018 }
1019
1020 /*
1021  * Managed allocator
1022  */
1023
1024 static MonoMethod* alloc_method_cache [ATYPE_NUM];
1025 static MonoMethod* slowpath_alloc_method_cache [ATYPE_NUM];
1026 static gboolean use_managed_allocator = TRUE;
1027
1028 #ifdef MANAGED_ALLOCATION
1029 // Cache the SgenThreadInfo pointer in a local 'var'.
1030 #define EMIT_TLS_ACCESS_VAR(mb, var) \
1031         do { \
1032                 var = mono_mb_add_local ((mb), &mono_defaults.int_class->byval_arg); \
1033                 mono_mb_emit_byte ((mb), MONO_CUSTOM_PREFIX); \
1034                 mono_mb_emit_byte ((mb), CEE_MONO_TLS); \
1035                 mono_mb_emit_i4 ((mb), TLS_KEY_SGEN_THREAD_INFO); \
1036                 mono_mb_emit_stloc ((mb), (var)); \
1037         } while (0)
1038
1039 #define EMIT_TLS_ACCESS_IN_CRITICAL_REGION_ADDR(mb, var) \
1040         do { \
1041                 mono_mb_emit_ldloc ((mb), (var)); \
1042                 mono_mb_emit_icon ((mb), MONO_STRUCT_OFFSET (SgenClientThreadInfo, in_critical_region)); \
1043                 mono_mb_emit_byte ((mb), CEE_ADD); \
1044         } while (0)
1045
1046 #define EMIT_TLS_ACCESS_NEXT_ADDR(mb, var)      do {    \
1047         mono_mb_emit_ldloc ((mb), (var));               \
1048         mono_mb_emit_icon ((mb), MONO_STRUCT_OFFSET (SgenThreadInfo, tlab_next));       \
1049         mono_mb_emit_byte ((mb), CEE_ADD);              \
1050         } while (0)
1051
1052 #define EMIT_TLS_ACCESS_TEMP_END(mb, var)       do {    \
1053         mono_mb_emit_ldloc ((mb), (var));               \
1054         mono_mb_emit_icon ((mb), MONO_STRUCT_OFFSET (SgenThreadInfo, tlab_temp_end));   \
1055         mono_mb_emit_byte ((mb), CEE_ADD);              \
1056         mono_mb_emit_byte ((mb), CEE_LDIND_I);          \
1057         } while (0)
1058
1059 /* FIXME: Do this in the JIT, where specialized allocation sequences can be created
1060  * for each class. This is currently not easy to do, as it is hard to generate basic 
1061  * blocks + branches, but it is easy with the linear IL codebase.
1062  *
1063  * For this to work we'd need to solve the TLAB race, first.  Now we
1064  * require the allocator to be in a few known methods to make sure
1065  * that they are executed atomically via the restart mechanism.
1066  */
1067 static MonoMethod*
1068 create_allocator (int atype, ManagedAllocatorVariant variant)
1069 {
1070         int p_var, size_var, real_size_var, thread_var G_GNUC_UNUSED;
1071         gboolean slowpath = variant == MANAGED_ALLOCATOR_SLOW_PATH;
1072         guint32 fastpath_branch, max_size_branch, no_oom_branch;
1073         MonoMethodBuilder *mb;
1074         MonoMethod *res;
1075         MonoMethodSignature *csig;
1076         static gboolean registered = FALSE;
1077         int tlab_next_addr_var, new_next_var;
1078         const char *name = NULL;
1079         WrapperInfo *info;
1080         int num_params, i;
1081
1082         if (!registered) {
1083                 mono_register_jit_icall (mono_gc_alloc_obj, "mono_gc_alloc_obj", mono_create_icall_signature ("object ptr int"), FALSE);
1084                 mono_register_jit_icall (mono_gc_alloc_vector, "mono_gc_alloc_vector", mono_create_icall_signature ("object ptr int int"), FALSE);
1085                 mono_register_jit_icall (mono_gc_alloc_string, "mono_gc_alloc_string", mono_create_icall_signature ("object ptr int int32"), FALSE);
1086                 registered = TRUE;
1087         }
1088
1089         if (atype == ATYPE_SMALL) {
1090                 name = slowpath ? "SlowAllocSmall" : "AllocSmall";
1091         } else if (atype == ATYPE_NORMAL) {
1092                 name = slowpath ? "SlowAlloc" : "Alloc";
1093         } else if (atype == ATYPE_VECTOR) {
1094                 name = slowpath ? "SlowAllocVector" : "AllocVector";
1095         } else if (atype == ATYPE_STRING) {
1096                 name = slowpath ? "SlowAllocString" : "AllocString";
1097         } else {
1098                 g_assert_not_reached ();
1099         }
1100
1101         if (atype == ATYPE_NORMAL)
1102                 num_params = 1;
1103         else
1104                 num_params = 2;
1105
1106         csig = mono_metadata_signature_alloc (mono_defaults.corlib, num_params);
1107         if (atype == ATYPE_STRING) {
1108                 csig->ret = &mono_defaults.string_class->byval_arg;
1109                 csig->params [0] = &mono_defaults.int_class->byval_arg;
1110                 csig->params [1] = &mono_defaults.int32_class->byval_arg;
1111         } else {
1112                 csig->ret = &mono_defaults.object_class->byval_arg;
1113                 for (i = 0; i < num_params; i++)
1114                         csig->params [i] = &mono_defaults.int_class->byval_arg;
1115         }
1116
1117         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ALLOC);
1118
1119 #ifndef DISABLE_JIT
1120         if (slowpath) {
1121                 switch (atype) {
1122                 case ATYPE_NORMAL:
1123                 case ATYPE_SMALL:
1124                         mono_mb_emit_ldarg (mb, 0);
1125                         mono_mb_emit_icall (mb, ves_icall_object_new_specific);
1126                         break;
1127                 case ATYPE_VECTOR:
1128                         mono_mb_emit_ldarg (mb, 0);
1129                         mono_mb_emit_ldarg (mb, 1);
1130                         mono_mb_emit_icall (mb, ves_icall_array_new_specific);
1131                         break;
1132                 case ATYPE_STRING:
1133                         mono_mb_emit_ldarg (mb, 1);
1134                         mono_mb_emit_icall (mb, ves_icall_string_alloc);
1135                         break;
1136                 default:
1137                         g_assert_not_reached ();
1138                 }
1139
1140                 goto done;
1141         }
1142
1143         /*
1144          * Tls access might call foreign code or code without jinfo. This can
1145          * only happen if we are outside of the critical region.
1146          */
1147         EMIT_TLS_ACCESS_VAR (mb, thread_var);
1148
1149         size_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1150         if (atype == ATYPE_SMALL) {
1151                 /* size_var = size_arg */
1152                 mono_mb_emit_ldarg (mb, 1);
1153                 mono_mb_emit_stloc (mb, size_var);
1154         } else if (atype == ATYPE_NORMAL) {
1155                 /* size = vtable->klass->instance_size; */
1156                 mono_mb_emit_ldarg (mb, 0);
1157                 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoVTable, klass));
1158                 mono_mb_emit_byte (mb, CEE_ADD);
1159                 mono_mb_emit_byte (mb, CEE_LDIND_I);
1160                 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoClass, instance_size));
1161                 mono_mb_emit_byte (mb, CEE_ADD);
1162                 /* FIXME: assert instance_size stays a 4 byte integer */
1163                 mono_mb_emit_byte (mb, CEE_LDIND_U4);
1164                 mono_mb_emit_byte (mb, CEE_CONV_I);
1165                 mono_mb_emit_stloc (mb, size_var);
1166         } else if (atype == ATYPE_VECTOR) {
1167                 MonoExceptionClause *clause;
1168                 int pos, pos_leave, pos_error;
1169                 MonoClass *oom_exc_class;
1170                 MonoMethod *ctor;
1171
1172                 /*
1173                  * n > MONO_ARRAY_MAX_INDEX => OutOfMemoryException
1174                  * n < 0                    => OverflowException
1175                  *
1176                  * We can do an unsigned comparison to catch both cases, then in the error
1177                  * case compare signed to distinguish between them.
1178                  */
1179                 mono_mb_emit_ldarg (mb, 1);
1180                 mono_mb_emit_icon (mb, MONO_ARRAY_MAX_INDEX);
1181                 mono_mb_emit_byte (mb, CEE_CONV_U);
1182                 pos = mono_mb_emit_short_branch (mb, CEE_BLE_UN_S);
1183
1184                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1185                 mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN);
1186                 mono_mb_emit_ldarg (mb, 1);
1187                 mono_mb_emit_icon (mb, 0);
1188                 pos_error = mono_mb_emit_short_branch (mb, CEE_BLT_S);
1189                 mono_mb_emit_exception (mb, "OutOfMemoryException", NULL);
1190                 mono_mb_patch_short_branch (mb, pos_error);
1191                 mono_mb_emit_exception (mb, "OverflowException", NULL);
1192
1193                 mono_mb_patch_short_branch (mb, pos);
1194
1195                 clause = (MonoExceptionClause *)mono_image_alloc0 (mono_defaults.corlib, sizeof (MonoExceptionClause));
1196                 clause->try_offset = mono_mb_get_label (mb);
1197
1198                 /* vtable->klass->sizes.element_size */
1199                 mono_mb_emit_ldarg (mb, 0);
1200                 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoVTable, klass));
1201                 mono_mb_emit_byte (mb, CEE_ADD);
1202                 mono_mb_emit_byte (mb, CEE_LDIND_I);
1203                 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoClass, sizes));
1204                 mono_mb_emit_byte (mb, CEE_ADD);
1205                 mono_mb_emit_byte (mb, CEE_LDIND_U4);
1206                 mono_mb_emit_byte (mb, CEE_CONV_I);
1207
1208                 /* * n */
1209                 mono_mb_emit_ldarg (mb, 1);
1210                 mono_mb_emit_byte (mb, CEE_MUL_OVF_UN);
1211                 /* + sizeof (MonoArray) */
1212                 mono_mb_emit_icon (mb, MONO_SIZEOF_MONO_ARRAY);
1213                 mono_mb_emit_byte (mb, CEE_ADD_OVF_UN);
1214                 mono_mb_emit_stloc (mb, size_var);
1215
1216                 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
1217
1218                 /* catch */
1219                 clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
1220                 clause->try_len = mono_mb_get_pos (mb) - clause->try_offset;
1221                 clause->data.catch_class = mono_class_load_from_name (mono_defaults.corlib,
1222                                 "System", "OverflowException");
1223                 clause->handler_offset = mono_mb_get_label (mb);
1224
1225                 oom_exc_class = mono_class_load_from_name (mono_defaults.corlib,
1226                                 "System", "OutOfMemoryException");
1227                 ctor = mono_class_get_method_from_name (oom_exc_class, ".ctor", 0);
1228                 g_assert (ctor);
1229
1230                 mono_mb_emit_byte (mb, CEE_POP);
1231                 mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
1232                 mono_mb_emit_byte (mb, CEE_THROW);
1233
1234                 clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
1235                 mono_mb_set_clauses (mb, 1, clause);
1236                 mono_mb_patch_branch (mb, pos_leave);
1237                 /* end catch */
1238         } else if (atype == ATYPE_STRING) {
1239                 int pos;
1240
1241                 /*
1242                  * a string allocator method takes the args: (vtable, len)
1243                  *
1244                  * bytes = offsetof (MonoString, chars) + ((len + 1) * 2)
1245                  *
1246                  * condition:
1247                  *
1248                  * bytes <= INT32_MAX - (SGEN_ALLOC_ALIGN - 1)
1249                  *
1250                  * therefore:
1251                  *
1252                  * offsetof (MonoString, chars) + ((len + 1) * 2) <= INT32_MAX - (SGEN_ALLOC_ALIGN - 1)
1253                  * len <= (INT32_MAX - (SGEN_ALLOC_ALIGN - 1) - offsetof (MonoString, chars)) / 2 - 1
1254                  */
1255                 mono_mb_emit_ldarg (mb, 1);
1256                 mono_mb_emit_icon (mb, (INT32_MAX - (SGEN_ALLOC_ALIGN - 1) - MONO_STRUCT_OFFSET (MonoString, chars)) / 2 - 1);
1257                 pos = mono_mb_emit_short_branch (mb, MONO_CEE_BLE_UN_S);
1258
1259                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1260                 mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN);
1261                 mono_mb_emit_exception (mb, "OutOfMemoryException", NULL);
1262                 mono_mb_patch_short_branch (mb, pos);
1263
1264                 mono_mb_emit_ldarg (mb, 1);
1265                 mono_mb_emit_icon (mb, 1);
1266                 mono_mb_emit_byte (mb, MONO_CEE_SHL);
1267                 //WE manually fold the above + 2 here
1268                 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoString, chars) + 2);
1269                 mono_mb_emit_byte (mb, CEE_ADD);
1270                 mono_mb_emit_stloc (mb, size_var);
1271         } else {
1272                 g_assert_not_reached ();
1273         }
1274
1275 #ifdef MANAGED_ALLOCATOR_CAN_USE_CRITICAL_REGION
1276         EMIT_TLS_ACCESS_IN_CRITICAL_REGION_ADDR (mb, thread_var);
1277         mono_mb_emit_byte (mb, CEE_LDC_I4_1);
1278         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1279         mono_mb_emit_byte (mb, CEE_MONO_ATOMIC_STORE_I4);
1280         mono_mb_emit_i4 (mb, MONO_MEMORY_BARRIER_NONE);
1281 #endif
1282
1283         if (nursery_canaries_enabled ()) {
1284                 real_size_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1285                 mono_mb_emit_ldloc (mb, size_var);
1286                 mono_mb_emit_stloc(mb, real_size_var);
1287         }
1288         else
1289                 real_size_var = size_var;
1290
1291         /* size += ALLOC_ALIGN - 1; */
1292         mono_mb_emit_ldloc (mb, size_var);
1293         mono_mb_emit_icon (mb, SGEN_ALLOC_ALIGN - 1);
1294         mono_mb_emit_byte (mb, CEE_ADD);
1295         /* size &= ~(ALLOC_ALIGN - 1); */
1296         mono_mb_emit_icon (mb, ~(SGEN_ALLOC_ALIGN - 1));
1297         mono_mb_emit_byte (mb, CEE_AND);
1298         mono_mb_emit_stloc (mb, size_var);
1299
1300         /* if (size > MAX_SMALL_OBJ_SIZE) goto slowpath */
1301         if (atype != ATYPE_SMALL) {
1302                 mono_mb_emit_ldloc (mb, size_var);
1303                 mono_mb_emit_icon (mb, SGEN_MAX_SMALL_OBJ_SIZE);
1304                 max_size_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BGT_UN_S);
1305         }
1306
1307         /*
1308          * We need to modify tlab_next, but the JIT only supports reading, so we read
1309          * another tls var holding its address instead.
1310          */
1311
1312         /* tlab_next_addr (local) = tlab_next_addr (TLS var) */
1313         tlab_next_addr_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1314         EMIT_TLS_ACCESS_NEXT_ADDR (mb, thread_var);
1315         mono_mb_emit_stloc (mb, tlab_next_addr_var);
1316
1317         /* p = (void**)tlab_next; */
1318         p_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1319         mono_mb_emit_ldloc (mb, tlab_next_addr_var);
1320         mono_mb_emit_byte (mb, CEE_LDIND_I);
1321         mono_mb_emit_stloc (mb, p_var);
1322         
1323         /* new_next = (char*)p + size; */
1324         new_next_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1325         mono_mb_emit_ldloc (mb, p_var);
1326         mono_mb_emit_ldloc (mb, size_var);
1327         mono_mb_emit_byte (mb, CEE_CONV_I);
1328         mono_mb_emit_byte (mb, CEE_ADD);
1329
1330         if (nursery_canaries_enabled ()) {
1331                         mono_mb_emit_icon (mb, CANARY_SIZE);
1332                         mono_mb_emit_byte (mb, CEE_ADD);
1333         }
1334         mono_mb_emit_stloc (mb, new_next_var);
1335
1336         /* if (G_LIKELY (new_next < tlab_temp_end)) */
1337         mono_mb_emit_ldloc (mb, new_next_var);
1338         EMIT_TLS_ACCESS_TEMP_END (mb, thread_var);
1339         fastpath_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BLT_UN_S);
1340
1341         /* Slowpath */
1342         if (atype != ATYPE_SMALL)
1343                 mono_mb_patch_short_branch (mb, max_size_branch);
1344
1345         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1346         mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN);
1347         /*
1348          * We are no longer in a critical section. We need to do this before calling
1349          * to unmanaged land in order to avoid stw deadlocks since unmanaged code
1350          * might take locks.
1351          */
1352 #ifdef MANAGED_ALLOCATOR_CAN_USE_CRITICAL_REGION
1353         EMIT_TLS_ACCESS_IN_CRITICAL_REGION_ADDR (mb, thread_var);
1354         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1355         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1356         mono_mb_emit_byte (mb, CEE_MONO_ATOMIC_STORE_I4);
1357         mono_mb_emit_i4 (mb, MONO_MEMORY_BARRIER_NONE);
1358 #endif
1359
1360         /* FIXME: mono_gc_alloc_obj takes a 'size_t' as an argument, not an int32 */
1361         mono_mb_emit_ldarg (mb, 0);
1362         mono_mb_emit_ldloc (mb, real_size_var);
1363         if (atype == ATYPE_NORMAL || atype == ATYPE_SMALL) {
1364                 mono_mb_emit_icall (mb, mono_gc_alloc_obj);
1365         } else if (atype == ATYPE_VECTOR) {
1366                 mono_mb_emit_ldarg (mb, 1);
1367                 mono_mb_emit_icall (mb, mono_gc_alloc_vector);
1368         } else if (atype == ATYPE_STRING) {
1369                 mono_mb_emit_ldarg (mb, 1);
1370                 mono_mb_emit_icall (mb, mono_gc_alloc_string);
1371         } else {
1372                 g_assert_not_reached ();
1373         }
1374
1375         /* if (ret == NULL) throw OOM; */
1376         mono_mb_emit_byte (mb, CEE_DUP);
1377         no_oom_branch = mono_mb_emit_branch (mb, CEE_BRTRUE);
1378         mono_mb_emit_exception (mb, "OutOfMemoryException", NULL);
1379
1380         mono_mb_patch_branch (mb, no_oom_branch);
1381         mono_mb_emit_byte (mb, CEE_RET);
1382
1383         /* Fastpath */
1384         mono_mb_patch_short_branch (mb, fastpath_branch);
1385
1386         /* FIXME: Memory barrier */
1387
1388         /* tlab_next = new_next */
1389         mono_mb_emit_ldloc (mb, tlab_next_addr_var);
1390         mono_mb_emit_ldloc (mb, new_next_var);
1391         mono_mb_emit_byte (mb, CEE_STIND_I);
1392
1393         /* *p = vtable; */
1394         mono_mb_emit_ldloc (mb, p_var);
1395         mono_mb_emit_ldarg (mb, 0);
1396         mono_mb_emit_byte (mb, CEE_STIND_I);
1397
1398         /* mark object end with nursery word */
1399         if (nursery_canaries_enabled ()) {
1400                         mono_mb_emit_ldloc (mb, p_var);
1401                         mono_mb_emit_ldloc (mb, real_size_var);
1402                         mono_mb_emit_byte (mb, MONO_CEE_ADD);
1403                         mono_mb_emit_icon8 (mb, (mword) CANARY_STRING);
1404                         mono_mb_emit_icon (mb, CANARY_SIZE);
1405                         mono_mb_emit_byte (mb, MONO_CEE_PREFIX1);
1406                         mono_mb_emit_byte (mb, CEE_CPBLK);
1407         }
1408
1409         if (atype == ATYPE_VECTOR) {
1410                 /* arr->max_length = max_length; */
1411                 mono_mb_emit_ldloc (mb, p_var);
1412                 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoArray, max_length));
1413                 mono_mb_emit_ldarg (mb, 1);
1414 #ifdef MONO_BIG_ARRAYS
1415                 mono_mb_emit_byte (mb, CEE_STIND_I);
1416 #else
1417                 mono_mb_emit_byte (mb, CEE_STIND_I4);
1418 #endif
1419         } else  if (atype == ATYPE_STRING) {
1420                 /* need to set length and clear the last char */
1421                 /* s->length = len; */
1422                 mono_mb_emit_ldloc (mb, p_var);
1423                 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoString, length));
1424                 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1425                 mono_mb_emit_ldarg (mb, 1);
1426                 mono_mb_emit_byte (mb, MONO_CEE_STIND_I4);
1427         }
1428
1429 #ifdef MANAGED_ALLOCATOR_CAN_USE_CRITICAL_REGION
1430         EMIT_TLS_ACCESS_IN_CRITICAL_REGION_ADDR (mb, thread_var);
1431         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1432         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1433         mono_mb_emit_byte (mb, CEE_MONO_ATOMIC_STORE_I4);
1434 #else
1435         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1436         mono_mb_emit_byte (mb, CEE_MONO_MEMORY_BARRIER);
1437 #endif
1438         /*
1439         We must make sure both vtable and max_length are globaly visible before returning to managed land.
1440         */
1441         mono_mb_emit_i4 (mb, MONO_MEMORY_BARRIER_REL);
1442
1443         /* return p */
1444         mono_mb_emit_ldloc (mb, p_var);
1445
1446  done:
1447         mono_mb_emit_byte (mb, CEE_RET);
1448 #endif
1449
1450         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
1451         info->d.alloc.gc_name = "sgen";
1452         info->d.alloc.alloc_type = atype;
1453
1454 #ifndef DISABLE_JIT
1455         mb->init_locals = FALSE;
1456 #endif
1457
1458         res = mono_mb_create (mb, csig, 8, info);
1459         mono_mb_free (mb);
1460
1461
1462         return res;
1463 }
1464 #endif
1465
1466 int
1467 mono_gc_get_aligned_size_for_allocator (int size)
1468 {
1469         return SGEN_ALIGN_UP (size);
1470 }
1471
1472 /*
1473  * Generate an allocator method implementing the fast path of mono_gc_alloc_obj ().
1474  * The signature of the called method is:
1475  *      object allocate (MonoVTable *vtable)
1476  */
1477 MonoMethod*
1478 mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean known_instance_size)
1479 {
1480 #ifdef MANAGED_ALLOCATION
1481         if (collect_before_allocs)
1482                 return NULL;
1483         if (klass->instance_size > tlab_size)
1484                 return NULL;
1485         if (known_instance_size && ALIGN_TO (klass->instance_size, SGEN_ALLOC_ALIGN) >= SGEN_MAX_SMALL_OBJ_SIZE)
1486                 return NULL;
1487         if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass))
1488                 return NULL;
1489         if (klass->rank)
1490                 return NULL;
1491         if (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS)
1492                 return NULL;
1493         if (klass->byval_arg.type == MONO_TYPE_STRING)
1494                 return mono_gc_get_managed_allocator_by_type (ATYPE_STRING, MANAGED_ALLOCATOR_REGULAR);
1495         /* Generic classes have dynamic field and can go above MAX_SMALL_OBJ_SIZE. */
1496         if (known_instance_size)
1497                 return mono_gc_get_managed_allocator_by_type (ATYPE_SMALL, MANAGED_ALLOCATOR_REGULAR);
1498         else
1499                 return mono_gc_get_managed_allocator_by_type (ATYPE_NORMAL, MANAGED_ALLOCATOR_REGULAR);
1500 #else
1501         return NULL;
1502 #endif
1503 }
1504
1505 MonoMethod*
1506 mono_gc_get_managed_array_allocator (MonoClass *klass)
1507 {
1508 #ifdef MANAGED_ALLOCATION
1509         if (klass->rank != 1)
1510                 return NULL;
1511         if (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS)
1512                 return NULL;
1513         if (has_per_allocation_action)
1514                 return NULL;
1515         g_assert (!mono_class_has_finalizer (klass) && !mono_class_is_marshalbyref (klass));
1516
1517         return mono_gc_get_managed_allocator_by_type (ATYPE_VECTOR, MANAGED_ALLOCATOR_REGULAR);
1518 #else
1519         return NULL;
1520 #endif
1521 }
1522
1523 void
1524 sgen_set_use_managed_allocator (gboolean flag)
1525 {
1526         use_managed_allocator = flag;
1527 }
1528
1529 MonoMethod*
1530 mono_gc_get_managed_allocator_by_type (int atype, ManagedAllocatorVariant variant)
1531 {
1532 #ifdef MANAGED_ALLOCATION
1533         MonoMethod *res;
1534         MonoMethod **cache;
1535
1536         if (variant == MANAGED_ALLOCATOR_REGULAR && !use_managed_allocator)
1537                 return NULL;
1538
1539         switch (variant) {
1540         case MANAGED_ALLOCATOR_REGULAR: cache = alloc_method_cache; break;
1541         case MANAGED_ALLOCATOR_SLOW_PATH: cache = slowpath_alloc_method_cache; break;
1542         default: g_assert_not_reached (); break;
1543         }
1544
1545         res = cache [atype];
1546         if (res)
1547                 return res;
1548
1549         res = create_allocator (atype, variant);
1550         LOCK_GC;
1551         if (cache [atype]) {
1552                 mono_free_method (res);
1553                 res = cache [atype];
1554         } else {
1555                 mono_memory_barrier ();
1556                 cache [atype] = res;
1557         }
1558         UNLOCK_GC;
1559
1560         return res;
1561 #else
1562         return NULL;
1563 #endif
1564 }
1565
1566 guint32
1567 mono_gc_get_managed_allocator_types (void)
1568 {
1569         return ATYPE_NUM;
1570 }
1571
1572 gboolean
1573 sgen_is_managed_allocator (MonoMethod *method)
1574 {
1575         int i;
1576
1577         for (i = 0; i < ATYPE_NUM; ++i)
1578                 if (method == alloc_method_cache [i] || method == slowpath_alloc_method_cache [i])
1579                         return TRUE;
1580         return FALSE;
1581 }
1582
1583 gboolean
1584 sgen_has_managed_allocator (void)
1585 {
1586         int i;
1587
1588         for (i = 0; i < ATYPE_NUM; ++i)
1589                 if (alloc_method_cache [i] || slowpath_alloc_method_cache [i])
1590                         return TRUE;
1591         return FALSE;
1592 }
1593
1594 #define ARRAY_OBJ_INDEX(ptr,array,elem_size) (((char*)(ptr) - ((char*)(array) + G_STRUCT_OFFSET (MonoArray, vector))) / (elem_size))
1595
1596 gboolean
1597 sgen_client_cardtable_scan_object (GCObject *obj, guint8 *cards, ScanCopyContext ctx)
1598 {
1599         MonoVTable *vt = SGEN_LOAD_VTABLE (obj);
1600         MonoClass *klass = vt->klass;
1601
1602         SGEN_ASSERT (0, SGEN_VTABLE_HAS_REFERENCES (vt), "Why would we ever call this on reference-free objects?");
1603
1604         if (vt->rank) {
1605                 MonoArray *arr = (MonoArray*)obj;
1606                 guint8 *card_data, *card_base;
1607                 guint8 *card_data_end;
1608                 char *obj_start = (char *)sgen_card_table_align_pointer (obj);
1609                 mword bounds_size;
1610                 mword obj_size = sgen_mono_array_size (vt, arr, &bounds_size, sgen_vtable_get_descriptor (vt));
1611                 /* We don't want to scan the bounds entries at the end of multidimensional arrays */
1612                 char *obj_end = (char*)obj + obj_size - bounds_size;
1613                 size_t card_count;
1614                 size_t extra_idx = 0;
1615
1616                 mword desc = (mword)klass->element_class->gc_descr;
1617                 int elem_size = mono_array_element_size (klass);
1618
1619 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
1620                 guint8 *overflow_scan_end = NULL;
1621 #endif
1622
1623 #ifdef SGEN_OBJECT_LAYOUT_STATISTICS
1624                 if (klass->element_class->valuetype)
1625                         sgen_object_layout_scanned_vtype_array ();
1626                 else
1627                         sgen_object_layout_scanned_ref_array ();
1628 #endif
1629
1630                 if (cards)
1631                         card_data = cards;
1632                 else
1633                         card_data = sgen_card_table_get_card_scan_address ((mword)obj);
1634
1635                 card_base = card_data;
1636                 card_count = sgen_card_table_number_of_cards_in_range ((mword)obj, obj_size);
1637                 card_data_end = card_data + card_count;
1638
1639
1640 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
1641                 /*Check for overflow and if so, setup to scan in two steps*/
1642                 if (!cards && card_data_end >= SGEN_SHADOW_CARDTABLE_END) {
1643                         overflow_scan_end = sgen_shadow_cardtable + (card_data_end - SGEN_SHADOW_CARDTABLE_END);
1644                         card_data_end = SGEN_SHADOW_CARDTABLE_END;
1645                 }
1646
1647 LOOP_HEAD:
1648 #endif
1649
1650                 card_data = sgen_find_next_card (card_data, card_data_end);
1651                 for (; card_data < card_data_end; card_data = sgen_find_next_card (card_data + 1, card_data_end)) {
1652                         size_t index;
1653                         size_t idx = (card_data - card_base) + extra_idx;
1654                         char *start = (char*)(obj_start + idx * CARD_SIZE_IN_BYTES);
1655                         char *card_end = start + CARD_SIZE_IN_BYTES;
1656                         char *first_elem, *elem;
1657
1658                         HEAVY_STAT (++los_marked_cards);
1659
1660                         if (!cards)
1661                                 sgen_card_table_prepare_card_for_scanning (card_data);
1662
1663                         card_end = MIN (card_end, obj_end);
1664
1665                         if (start <= (char*)arr->vector)
1666                                 index = 0;
1667                         else
1668                                 index = ARRAY_OBJ_INDEX (start, obj, elem_size);
1669
1670                         elem = first_elem = (char*)mono_array_addr_with_size_fast ((MonoArray*)obj, elem_size, index);
1671                         if (klass->element_class->valuetype) {
1672                                 ScanVTypeFunc scan_vtype_func = ctx.ops->scan_vtype;
1673
1674                                 for (; elem < card_end; elem += elem_size)
1675                                         scan_vtype_func (obj, elem, desc, ctx.queue BINARY_PROTOCOL_ARG (elem_size));
1676                         } else {
1677                                 ScanPtrFieldFunc scan_ptr_field_func = ctx.ops->scan_ptr_field;
1678
1679                                 HEAVY_STAT (++los_array_cards);
1680                                 for (; elem < card_end; elem += SIZEOF_VOID_P)
1681                                         scan_ptr_field_func (obj, (GCObject**)elem, ctx.queue);
1682                         }
1683
1684                         binary_protocol_card_scan (first_elem, elem - first_elem);
1685                 }
1686
1687 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
1688                 if (overflow_scan_end) {
1689                         extra_idx = card_data - card_base;
1690                         card_base = card_data = sgen_shadow_cardtable;
1691                         card_data_end = overflow_scan_end;
1692                         overflow_scan_end = NULL;
1693                         goto LOOP_HEAD;
1694                 }
1695 #endif
1696                 return TRUE;
1697         }
1698
1699         return FALSE;
1700 }
1701
1702 /*
1703  * Array and string allocation
1704  */
1705
1706 void*
1707 mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length)
1708 {
1709         MonoArray *arr;
1710         TLAB_ACCESS_INIT;
1711
1712         if (!SGEN_CAN_ALIGN_UP (size))
1713                 return NULL;
1714
1715 #ifndef DISABLE_CRITICAL_REGION
1716         ENTER_CRITICAL_REGION;
1717         arr = (MonoArray*)sgen_try_alloc_obj_nolock (vtable, size);
1718         if (arr) {
1719                 /*This doesn't require fencing since EXIT_CRITICAL_REGION already does it for us*/
1720                 arr->max_length = (mono_array_size_t)max_length;
1721                 EXIT_CRITICAL_REGION;
1722                 goto done;
1723         }
1724         EXIT_CRITICAL_REGION;
1725 #endif
1726
1727         LOCK_GC;
1728
1729         arr = (MonoArray*)sgen_alloc_obj_nolock (vtable, size);
1730         if (G_UNLIKELY (!arr)) {
1731                 UNLOCK_GC;
1732                 return NULL;
1733         }
1734
1735         arr->max_length = (mono_array_size_t)max_length;
1736
1737         UNLOCK_GC;
1738
1739  done:
1740         if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
1741                 mono_profiler_allocation (&arr->obj);
1742
1743         SGEN_ASSERT (6, SGEN_ALIGN_UP (size) == SGEN_ALIGN_UP (sgen_client_par_object_get_size (vtable, (GCObject*)arr)), "Vector has incorrect size.");
1744         return arr;
1745 }
1746
1747 void*
1748 mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uintptr_t bounds_size)
1749 {
1750         MonoArray *arr;
1751         MonoArrayBounds *bounds;
1752         TLAB_ACCESS_INIT;
1753
1754         if (!SGEN_CAN_ALIGN_UP (size))
1755                 return NULL;
1756
1757 #ifndef DISABLE_CRITICAL_REGION
1758         ENTER_CRITICAL_REGION;
1759         arr = (MonoArray*)sgen_try_alloc_obj_nolock (vtable, size);
1760         if (arr) {
1761                 /*This doesn't require fencing since EXIT_CRITICAL_REGION already does it for us*/
1762                 arr->max_length = (mono_array_size_t)max_length;
1763
1764                 bounds = (MonoArrayBounds*)((char*)arr + size - bounds_size);
1765                 arr->bounds = bounds;
1766                 EXIT_CRITICAL_REGION;
1767                 goto done;
1768         }
1769         EXIT_CRITICAL_REGION;
1770 #endif
1771
1772         LOCK_GC;
1773
1774         arr = (MonoArray*)sgen_alloc_obj_nolock (vtable, size);
1775         if (G_UNLIKELY (!arr)) {
1776                 UNLOCK_GC;
1777                 return NULL;
1778         }
1779
1780         arr->max_length = (mono_array_size_t)max_length;
1781
1782         bounds = (MonoArrayBounds*)((char*)arr + size - bounds_size);
1783         arr->bounds = bounds;
1784
1785         UNLOCK_GC;
1786
1787  done:
1788         if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
1789                 mono_profiler_allocation (&arr->obj);
1790
1791         SGEN_ASSERT (6, SGEN_ALIGN_UP (size) == SGEN_ALIGN_UP (sgen_client_par_object_get_size (vtable, (GCObject*)arr)), "Array has incorrect size.");
1792         return arr;
1793 }
1794
1795 void*
1796 mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len)
1797 {
1798         MonoString *str;
1799         TLAB_ACCESS_INIT;
1800
1801         if (!SGEN_CAN_ALIGN_UP (size))
1802                 return NULL;
1803
1804 #ifndef DISABLE_CRITICAL_REGION
1805         ENTER_CRITICAL_REGION;
1806         str = (MonoString*)sgen_try_alloc_obj_nolock (vtable, size);
1807         if (str) {
1808                 /*This doesn't require fencing since EXIT_CRITICAL_REGION already does it for us*/
1809                 str->length = len;
1810                 EXIT_CRITICAL_REGION;
1811                 goto done;
1812         }
1813         EXIT_CRITICAL_REGION;
1814 #endif
1815
1816         LOCK_GC;
1817
1818         str = (MonoString*)sgen_alloc_obj_nolock (vtable, size);
1819         if (G_UNLIKELY (!str)) {
1820                 UNLOCK_GC;
1821                 return NULL;
1822         }
1823
1824         str->length = len;
1825
1826         UNLOCK_GC;
1827
1828  done:
1829         if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
1830                 mono_profiler_allocation (&str->object);
1831
1832         return str;
1833 }
1834
1835 /*
1836  * Strings
1837  */
1838
1839 void
1840 mono_gc_set_string_length (MonoString *str, gint32 new_length)
1841 {
1842         mono_unichar2 *new_end = str->chars + new_length;
1843
1844         /* zero the discarded string. This null-delimits the string and allows
1845          * the space to be reclaimed by SGen. */
1846
1847         if (nursery_canaries_enabled () && sgen_ptr_in_nursery (str)) {
1848                 CHECK_CANARY_FOR_OBJECT ((GCObject*)str, TRUE);
1849                 memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2) + CANARY_SIZE);
1850                 memcpy (new_end + 1 , CANARY_STRING, CANARY_SIZE);
1851         } else {
1852                 memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2));
1853         }
1854
1855         str->length = new_length;
1856 }
1857
1858 /*
1859  * Profiling
1860  */
1861
1862 #define GC_ROOT_NUM 32
1863 typedef struct {
1864         int count;              /* must be the first field */
1865         void *objects [GC_ROOT_NUM];
1866         int root_types [GC_ROOT_NUM];
1867         uintptr_t extra_info [GC_ROOT_NUM];
1868 } GCRootReport;
1869
1870 static void
1871 notify_gc_roots (GCRootReport *report)
1872 {
1873         if (!report->count)
1874                 return;
1875         mono_profiler_gc_roots (report->count, report->objects, report->root_types, report->extra_info);
1876         report->count = 0;
1877 }
1878
1879 static void
1880 add_profile_gc_root (GCRootReport *report, void *object, int rtype, uintptr_t extra_info)
1881 {
1882         if (report->count == GC_ROOT_NUM)
1883                 notify_gc_roots (report);
1884         report->objects [report->count] = object;
1885         report->root_types [report->count] = rtype;
1886         report->extra_info [report->count++] = (uintptr_t)SGEN_LOAD_VTABLE (object)->klass;
1887 }
1888
1889 void
1890 sgen_client_nursery_objects_pinned (void **definitely_pinned, int count)
1891 {
1892         if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS) {
1893                 GCRootReport report;
1894                 int idx;
1895                 report.count = 0;
1896                 for (idx = 0; idx < count; ++idx)
1897                         add_profile_gc_root (&report, definitely_pinned [idx], MONO_PROFILE_GC_ROOT_PINNING | MONO_PROFILE_GC_ROOT_MISC, 0);
1898                 notify_gc_roots (&report);
1899         }
1900 }
1901
1902 static void
1903 report_finalizer_roots_from_queue (SgenPointerQueue *queue)
1904 {
1905         GCRootReport report;
1906         size_t i;
1907
1908         report.count = 0;
1909         for (i = 0; i < queue->next_slot; ++i) {
1910                 void *obj = queue->data [i];
1911                 if (!obj)
1912                         continue;
1913                 add_profile_gc_root (&report, obj, MONO_PROFILE_GC_ROOT_FINALIZER, 0);
1914         }
1915         notify_gc_roots (&report);
1916 }
1917
1918 static void
1919 report_finalizer_roots (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue)
1920 {
1921         report_finalizer_roots_from_queue (fin_ready_queue);
1922         report_finalizer_roots_from_queue (critical_fin_queue);
1923 }
1924
1925 static GCRootReport *root_report;
1926
1927 static void
1928 single_arg_report_root (MonoObject **obj, void *gc_data)
1929 {
1930         if (*obj)
1931                 add_profile_gc_root (root_report, *obj, MONO_PROFILE_GC_ROOT_OTHER, 0);
1932 }
1933
1934 static void
1935 precisely_report_roots_from (GCRootReport *report, void** start_root, void** end_root, mword desc)
1936 {
1937         switch (desc & ROOT_DESC_TYPE_MASK) {
1938         case ROOT_DESC_BITMAP:
1939                 desc >>= ROOT_DESC_TYPE_SHIFT;
1940                 while (desc) {
1941                         if ((desc & 1) && *start_root) {
1942                                 add_profile_gc_root (report, *start_root, MONO_PROFILE_GC_ROOT_OTHER, 0);
1943                         }
1944                         desc >>= 1;
1945                         start_root++;
1946                 }
1947                 return;
1948         case ROOT_DESC_COMPLEX: {
1949                 gsize *bitmap_data = (gsize *)sgen_get_complex_descriptor_bitmap (desc);
1950                 gsize bwords = (*bitmap_data) - 1;
1951                 void **start_run = start_root;
1952                 bitmap_data++;
1953                 while (bwords-- > 0) {
1954                         gsize bmap = *bitmap_data++;
1955                         void **objptr = start_run;
1956                         while (bmap) {
1957                                 if ((bmap & 1) && *objptr) {
1958                                         add_profile_gc_root (report, *objptr, MONO_PROFILE_GC_ROOT_OTHER, 0);
1959                                 }
1960                                 bmap >>= 1;
1961                                 ++objptr;
1962                         }
1963                         start_run += GC_BITS_PER_WORD;
1964                 }
1965                 break;
1966         }
1967         case ROOT_DESC_VECTOR: {
1968                 void **p;
1969
1970                 for (p = start_root; p < end_root; p++) {
1971                         if (*p)
1972                                 add_profile_gc_root (report, *p, MONO_PROFILE_GC_ROOT_OTHER, 0);
1973                 }
1974                 break;
1975         }
1976         case ROOT_DESC_USER: {
1977                 MonoGCRootMarkFunc marker = (MonoGCRootMarkFunc)sgen_get_user_descriptor_func (desc);
1978                 root_report = report;
1979                 marker ((MonoObject**)start_root, single_arg_report_root, NULL);
1980                 break;
1981         }
1982         case ROOT_DESC_RUN_LEN:
1983                 g_assert_not_reached ();
1984         default:
1985                 g_assert_not_reached ();
1986         }
1987 }
1988
1989 static void
1990 report_registered_roots_by_type (int root_type)
1991 {
1992         GCRootReport report;
1993         void **start_root;
1994         RootRecord *root;
1995         report.count = 0;
1996         SGEN_HASH_TABLE_FOREACH (&roots_hash [root_type], void **, start_root, RootRecord *, root) {
1997                 SGEN_LOG (6, "Precise root scan %p-%p (desc: %p)", start_root, root->end_root, (void*)root->root_desc);
1998                 precisely_report_roots_from (&report, start_root, (void**)root->end_root, root->root_desc);
1999         } SGEN_HASH_TABLE_FOREACH_END;
2000         notify_gc_roots (&report);
2001 }
2002
2003 static void
2004 report_registered_roots (void)
2005 {
2006         report_registered_roots_by_type (ROOT_TYPE_NORMAL);
2007         report_registered_roots_by_type (ROOT_TYPE_WBARRIER);
2008 }
2009
2010 void
2011 sgen_client_collecting_minor (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue)
2012 {
2013         if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS)
2014                 report_registered_roots ();
2015         if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS)
2016                 report_finalizer_roots (fin_ready_queue, critical_fin_queue);
2017 }
2018
2019 static GCRootReport major_root_report;
2020 static gboolean profile_roots;
2021
2022 void
2023 sgen_client_collecting_major_1 (void)
2024 {
2025         profile_roots = mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS;
2026         memset (&major_root_report, 0, sizeof (GCRootReport));
2027 }
2028
2029 void
2030 sgen_client_pinned_los_object (GCObject *obj)
2031 {
2032         if (profile_roots)
2033                 add_profile_gc_root (&major_root_report, (char*)obj, MONO_PROFILE_GC_ROOT_PINNING | MONO_PROFILE_GC_ROOT_MISC, 0);
2034 }
2035
2036 void
2037 sgen_client_collecting_major_2 (void)
2038 {
2039         if (profile_roots)
2040                 notify_gc_roots (&major_root_report);
2041
2042         if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS)
2043                 report_registered_roots ();
2044 }
2045
2046 void
2047 sgen_client_collecting_major_3 (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue)
2048 {
2049         if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS)
2050                 report_finalizer_roots (fin_ready_queue, critical_fin_queue);
2051 }
2052
2053 #define MOVED_OBJECTS_NUM 64
2054 static void *moved_objects [MOVED_OBJECTS_NUM];
2055 static int moved_objects_idx = 0;
2056
2057 static SgenPointerQueue moved_objects_queue = SGEN_POINTER_QUEUE_INIT (INTERNAL_MEM_MOVED_OBJECT);
2058
2059 void
2060 mono_sgen_register_moved_object (void *obj, void *destination)
2061 {
2062         /*
2063          * This function can be called from SGen's worker threads. We want to try
2064          * and avoid exposing those threads to the profiler API, so queue up move
2065          * events and send them later when the main GC thread calls
2066          * mono_sgen_gc_event_moves ().
2067          *
2068          * TODO: Once SGen has multiple worker threads, we need to switch to a
2069          * lock-free data structure for the queue as multiple threads will be
2070          * adding to it at the same time.
2071          */
2072         if (sgen_workers_is_worker_thread (mono_native_thread_id_get ())) {
2073                 sgen_pointer_queue_add (&moved_objects_queue, obj);
2074                 sgen_pointer_queue_add (&moved_objects_queue, destination);
2075         } else {
2076                 if (moved_objects_idx == MOVED_OBJECTS_NUM) {
2077                         mono_profiler_gc_moves (moved_objects, moved_objects_idx);
2078                         moved_objects_idx = 0;
2079                 }
2080
2081                 moved_objects [moved_objects_idx++] = obj;
2082                 moved_objects [moved_objects_idx++] = destination;
2083         }
2084 }
2085
2086 void
2087 mono_sgen_gc_event_moves (void)
2088 {
2089         while (!sgen_pointer_queue_is_empty (&moved_objects_queue)) {
2090                 void *dst = sgen_pointer_queue_pop (&moved_objects_queue);
2091                 void *src = sgen_pointer_queue_pop (&moved_objects_queue);
2092
2093                 mono_sgen_register_moved_object (src, dst);
2094         }
2095
2096         if (moved_objects_idx) {
2097                 mono_profiler_gc_moves (moved_objects, moved_objects_idx);
2098                 moved_objects_idx = 0;
2099         }
2100 }
2101
2102 /*
2103  * Heap walking
2104  */
2105
2106 #define REFS_SIZE 128
2107 typedef struct {
2108         void *data;
2109         MonoGCReferences callback;
2110         int flags;
2111         int count;
2112         int called;
2113         MonoObject *refs [REFS_SIZE];
2114         uintptr_t offsets [REFS_SIZE];
2115 } HeapWalkInfo;
2116
2117 #undef HANDLE_PTR
2118 #define HANDLE_PTR(ptr,obj)     do {    \
2119                 if (*(ptr)) {   \
2120                         if (hwi->count == REFS_SIZE) {  \
2121                                 hwi->callback ((MonoObject*)start, mono_object_class (start), hwi->called? 0: size, hwi->count, hwi->refs, hwi->offsets, hwi->data);    \
2122                                 hwi->count = 0; \
2123                                 hwi->called = 1;        \
2124                         }       \
2125                         hwi->offsets [hwi->count] = (char*)(ptr)-(char*)start;  \
2126                         hwi->refs [hwi->count++] = *(ptr);      \
2127                 }       \
2128         } while (0)
2129
2130 static void
2131 collect_references (HeapWalkInfo *hwi, GCObject *obj, size_t size)
2132 {
2133         char *start = (char*)obj;
2134         mword desc = sgen_obj_get_descriptor (obj);
2135
2136 #include "sgen/sgen-scan-object.h"
2137 }
2138
2139 static void
2140 walk_references (GCObject *start, size_t size, void *data)
2141 {
2142         HeapWalkInfo *hwi = (HeapWalkInfo *)data;
2143         hwi->called = 0;
2144         hwi->count = 0;
2145         collect_references (hwi, start, size);
2146         if (hwi->count || !hwi->called)
2147                 hwi->callback (start, mono_object_class (start), hwi->called? 0: size, hwi->count, hwi->refs, hwi->offsets, hwi->data);
2148 }
2149
2150 /**
2151  * mono_gc_walk_heap:
2152  * \param flags flags for future use
2153  * \param callback a function pointer called for each object in the heap
2154  * \param data a user data pointer that is passed to callback
2155  * This function can be used to iterate over all the live objects in the heap;
2156  * for each object, \p callback is invoked, providing info about the object's
2157  * location in memory, its class, its size and the objects it references.
2158  * For each referenced object its offset from the object address is
2159  * reported in the offsets array.
2160  * The object references may be buffered, so the callback may be invoked
2161  * multiple times for the same object: in all but the first call, the size
2162  * argument will be zero.
2163  * Note that this function can be only called in the \c MONO_GC_EVENT_PRE_START_WORLD
2164  * profiler event handler.
2165  * \returns a non-zero value if the GC doesn't support heap walking
2166  */
2167 int
2168 mono_gc_walk_heap (int flags, MonoGCReferences callback, void *data)
2169 {
2170         HeapWalkInfo hwi;
2171
2172         hwi.flags = flags;
2173         hwi.callback = callback;
2174         hwi.data = data;
2175
2176         sgen_clear_nursery_fragments ();
2177         sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, walk_references, &hwi, FALSE, TRUE);
2178
2179         major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, walk_references, &hwi);
2180         sgen_los_iterate_objects (walk_references, &hwi);
2181
2182         return 0;
2183 }
2184
2185 /*
2186  * Threads
2187  */
2188
2189 void
2190 mono_gc_set_gc_callbacks (MonoGCCallbacks *callbacks)
2191 {
2192         gc_callbacks = *callbacks;
2193 }
2194
2195 MonoGCCallbacks *
2196 mono_gc_get_gc_callbacks ()
2197 {
2198         return &gc_callbacks;
2199 }
2200
2201 void
2202 sgen_client_thread_register (SgenThreadInfo* info, void *stack_bottom_fallback)
2203 {
2204         size_t stsize = 0;
2205         guint8 *staddr = NULL;
2206
2207         mono_tls_set_sgen_thread_info (info);
2208
2209         info->client_info.skip = 0;
2210
2211         info->client_info.stack_start = NULL;
2212
2213 #ifdef SGEN_POSIX_STW
2214         info->client_info.stop_count = -1;
2215         info->client_info.signal = 0;
2216 #endif
2217
2218         mono_thread_info_get_stack_bounds (&staddr, &stsize);
2219         if (staddr) {
2220                 info->client_info.stack_start_limit = staddr;
2221                 info->client_info.stack_end = staddr + stsize;
2222         } else {
2223                 gsize stack_bottom = (gsize)stack_bottom_fallback;
2224                 stack_bottom += 4095;
2225                 stack_bottom &= ~4095;
2226                 info->client_info.stack_end = (char*)stack_bottom;
2227         }
2228
2229         memset (&info->client_info.ctx, 0, sizeof (MonoContext));
2230
2231         if (mono_gc_get_gc_callbacks ()->thread_attach_func)
2232                 info->client_info.runtime_data = mono_gc_get_gc_callbacks ()->thread_attach_func ();
2233
2234         binary_protocol_thread_register ((gpointer)mono_thread_info_get_tid (info));
2235
2236         SGEN_LOG (3, "registered thread %p (%p) stack end %p", info, (gpointer)mono_thread_info_get_tid (info), info->client_info.stack_end);
2237
2238         info->client_info.info.handle_stack = mono_handle_stack_alloc ();
2239 }
2240
2241 void
2242 sgen_client_thread_unregister (SgenThreadInfo *p)
2243 {
2244         MonoNativeThreadId tid;
2245
2246         mono_tls_set_sgen_thread_info (NULL);
2247
2248         tid = mono_thread_info_get_tid (p);
2249
2250         if (p->client_info.info.runtime_thread)
2251                 mono_threads_add_joinable_thread ((gpointer)tid);
2252
2253         if (mono_gc_get_gc_callbacks ()->thread_detach_func) {
2254                 mono_gc_get_gc_callbacks ()->thread_detach_func (p->client_info.runtime_data);
2255                 p->client_info.runtime_data = NULL;
2256         }
2257
2258         binary_protocol_thread_unregister ((gpointer)tid);
2259         SGEN_LOG (3, "unregister thread %p (%p)", p, (gpointer)tid);
2260
2261         HandleStack *handles = (HandleStack*) p->client_info.info.handle_stack;
2262         p->client_info.info.handle_stack = NULL;
2263         mono_handle_stack_free (handles);
2264 }
2265
2266 void
2267 mono_gc_set_skip_thread (gboolean skip)
2268 {
2269         SgenThreadInfo *info = mono_thread_info_current ();
2270
2271         LOCK_GC;
2272         info->client_info.gc_disabled = skip;
2273         UNLOCK_GC;
2274
2275         if (skip) {
2276                 /* If we skip scanning a thread with a non-empty handle stack, we may move an
2277                  * object but fail to update the reference in the handle.
2278                  */
2279                 HandleStack *stack = info->client_info.info.handle_stack;
2280                 g_assert (stack == NULL || mono_handle_stack_is_empty (stack));
2281         }
2282 }
2283
2284 static gboolean
2285 thread_in_critical_region (SgenThreadInfo *info)
2286 {
2287         return info->client_info.in_critical_region;
2288 }
2289
2290 static void
2291 sgen_thread_attach (SgenThreadInfo *info)
2292 {
2293         if (mono_gc_get_gc_callbacks ()->thread_attach_func && !info->client_info.runtime_data)
2294                 info->client_info.runtime_data = mono_gc_get_gc_callbacks ()->thread_attach_func ();
2295 }
2296
2297 static void
2298 sgen_thread_detach (SgenThreadInfo *p)
2299 {
2300         /* If a delegate is passed to native code and invoked on a thread we dont
2301          * know about, marshal will register it with mono_threads_attach_coop, but
2302          * we have no way of knowing when that thread goes away.  SGen has a TSD
2303          * so we assume that if the domain is still registered, we can detach
2304          * the thread
2305          */
2306         if (mono_thread_internal_current_is_attached ())
2307                 mono_thread_detach_internal (mono_thread_internal_current ());
2308 }
2309
2310 /**
2311  * mono_gc_register_thread:
2312  */
2313 gboolean
2314 mono_gc_register_thread (void *baseptr)
2315 {
2316         return mono_thread_info_attach (baseptr) != NULL;
2317 }
2318
2319 /**
2320  * mono_gc_is_gc_thread:
2321  */
2322 gboolean
2323 mono_gc_is_gc_thread (void)
2324 {
2325         gboolean result;
2326         LOCK_GC;
2327         result = mono_thread_info_current () != NULL;
2328         UNLOCK_GC;
2329         return result;
2330 }
2331
2332 void
2333 sgen_client_thread_register_worker (void)
2334 {
2335         mono_thread_info_register_small_id ();
2336         mono_native_thread_set_name (mono_native_thread_id_get (), "SGen worker");
2337 }
2338
2339 /* Variables holding start/end nursery so it won't have to be passed at every call */
2340 static void *scan_area_arg_start, *scan_area_arg_end;
2341
2342 void
2343 mono_gc_conservatively_scan_area (void *start, void *end)
2344 {
2345         sgen_conservatively_pin_objects_from ((void **)start, (void **)end, scan_area_arg_start, scan_area_arg_end, PIN_TYPE_STACK);
2346 }
2347
2348 void*
2349 mono_gc_scan_object (void *obj, void *gc_data)
2350 {
2351         ScanCopyContext *ctx = (ScanCopyContext *)gc_data;
2352         ctx->ops->copy_or_mark_object ((GCObject**)&obj, ctx->queue);
2353         return obj;
2354 }
2355
2356 typedef struct {
2357         void **start_nursery;
2358         void **end_nursery;
2359 } PinHandleStackInteriorPtrData;
2360
2361 /* Called when we're scanning the handle stack imprecisely and we encounter a pointer into the
2362    middle of an object.
2363  */
2364 static void
2365 pin_handle_stack_interior_ptrs (void **ptr_slot, void *user_data)
2366 {
2367         PinHandleStackInteriorPtrData *ud = (PinHandleStackInteriorPtrData *)user_data;
2368         sgen_conservatively_pin_objects_from (ptr_slot, ptr_slot+1, ud->start_nursery, ud->end_nursery, PIN_TYPE_STACK);
2369 }
2370
2371
2372 /*
2373  * Mark from thread stacks and registers.
2374  */
2375 void
2376 sgen_client_scan_thread_data (void *start_nursery, void *end_nursery, gboolean precise, ScanCopyContext ctx)
2377 {
2378         scan_area_arg_start = start_nursery;
2379         scan_area_arg_end = end_nursery;
2380
2381         FOREACH_THREAD (info) {
2382                 int skip_reason = 0;
2383                 void *aligned_stack_start;
2384
2385                 if (info->client_info.skip) {
2386                         SGEN_LOG (3, "Skipping dead thread %p, range: %p-%p, size: %zd", info, info->client_info.stack_start, info->client_info.stack_end, (char*)info->client_info.stack_end - (char*)info->client_info.stack_start);
2387                         skip_reason = 1;
2388                 } else if (info->client_info.gc_disabled) {
2389                         SGEN_LOG (3, "GC disabled for thread %p, range: %p-%p, size: %zd", info, info->client_info.stack_start, info->client_info.stack_end, (char*)info->client_info.stack_end - (char*)info->client_info.stack_start);
2390                         skip_reason = 2;
2391                 } else if (!mono_thread_info_is_live (info)) {
2392                         SGEN_LOG (3, "Skipping non-running thread %p, range: %p-%p, size: %zd (state %x)", info, info->client_info.stack_start, info->client_info.stack_end, (char*)info->client_info.stack_end - (char*)info->client_info.stack_start, info->client_info.info.thread_state);
2393                         skip_reason = 3;
2394                 } else if (!info->client_info.stack_start) {
2395                         SGEN_LOG (3, "Skipping starting or detaching thread %p", info);
2396                         skip_reason = 4;
2397                 }
2398
2399                 binary_protocol_scan_stack ((gpointer)mono_thread_info_get_tid (info), info->client_info.stack_start, info->client_info.stack_end, skip_reason);
2400
2401                 if (skip_reason) {
2402                         if (precise) {
2403                                 /* If we skip a thread with a non-empty handle stack and then it
2404                                  * resumes running we may potentially move an object but fail to
2405                                  * update the reference in the handle.
2406                                  */
2407                                 HandleStack *stack = info->client_info.info.handle_stack;
2408                                 g_assert (stack == NULL || mono_handle_stack_is_empty (stack));
2409                         }
2410                         continue;
2411                 }
2412
2413                 g_assert (info->client_info.stack_start);
2414                 g_assert (info->client_info.stack_end);
2415
2416                 aligned_stack_start = (void*)(mword) ALIGN_TO ((mword)info->client_info.stack_start, SIZEOF_VOID_P);
2417 #ifdef HOST_WIN32
2418                 /* Windows uses a guard page before the committed stack memory pages to detect when the
2419                    stack needs to be grown. If we suspend a thread just after a function prolog has
2420                    decremented the stack pointer to point into the guard page but before the thread has
2421                    been able to read or write to that page, starting the stack scan at aligned_stack_start
2422                    will raise a STATUS_GUARD_PAGE_VIOLATION and the process will crash. This code uses
2423                    VirtualQuery() to determine whether stack_start points into the guard page and then
2424                    updates aligned_stack_start to point at the next non-guard page. */
2425                 MEMORY_BASIC_INFORMATION mem_info;
2426                 SIZE_T result = VirtualQuery(info->client_info.stack_start, &mem_info, sizeof(mem_info));
2427                 g_assert (result != 0);
2428                 if (mem_info.Protect & PAGE_GUARD) {
2429                         aligned_stack_start = ((char*) mem_info.BaseAddress) + mem_info.RegionSize;
2430                 }
2431 #endif
2432
2433                 g_assert (info->client_info.suspend_done);
2434                 SGEN_LOG (3, "Scanning thread %p, range: %p-%p, size: %zd, pinned=%zd", info, info->client_info.stack_start, info->client_info.stack_end, (char*)info->client_info.stack_end - (char*)info->client_info.stack_start, sgen_get_pinned_count ());
2435                 if (mono_gc_get_gc_callbacks ()->thread_mark_func && !conservative_stack_mark) {
2436                         mono_gc_get_gc_callbacks ()->thread_mark_func (info->client_info.runtime_data, (guint8 *)aligned_stack_start, (guint8 *)info->client_info.stack_end, precise, &ctx);
2437                 } else if (!precise) {
2438                         if (!conservative_stack_mark) {
2439                                 fprintf (stderr, "Precise stack mark not supported - disabling.\n");
2440                                 conservative_stack_mark = TRUE;
2441                         }
2442                         //FIXME we should eventually use the new stack_mark from coop
2443                         sgen_conservatively_pin_objects_from ((void **)aligned_stack_start, (void **)info->client_info.stack_end, start_nursery, end_nursery, PIN_TYPE_STACK);
2444                 }
2445
2446                 if (!precise) {
2447                         sgen_conservatively_pin_objects_from ((void**)&info->client_info.ctx, (void**)(&info->client_info.ctx + 1),
2448                                 start_nursery, end_nursery, PIN_TYPE_STACK);
2449
2450                         {
2451                                 // This is used on Coop GC for platforms where we cannot get the data for individual registers.
2452                                 // We force a spill of all registers into the stack and pass a chunk of data into sgen.
2453                                 //FIXME under coop, for now, what we need to ensure is that we scan any extra memory from info->client_info.stack_end to stack_mark
2454                                 MonoThreadUnwindState *state = &info->client_info.info.thread_saved_state [SELF_SUSPEND_STATE_INDEX];
2455                                 if (state && state->gc_stackdata) {
2456                                         sgen_conservatively_pin_objects_from ((void **)state->gc_stackdata, (void**)((char*)state->gc_stackdata + state->gc_stackdata_size),
2457                                                 start_nursery, end_nursery, PIN_TYPE_STACK);
2458                                 }
2459                         }
2460                 }
2461                 if (info->client_info.info.handle_stack) {
2462                         /*
2463                           Make two passes over the handle stack.  On the imprecise pass, pin all
2464                           objects where the handle points into the interior of the object. On the
2465                           precise pass, copy or mark all the objects that have handles to the
2466                           beginning of the object.
2467                         */
2468                         if (precise)
2469                                 mono_handle_stack_scan ((HandleStack*)info->client_info.info.handle_stack, (GcScanFunc)ctx.ops->copy_or_mark_object, ctx.queue, precise);
2470                         else {
2471                                 PinHandleStackInteriorPtrData ud = { .start_nursery = start_nursery,
2472                                                                      .end_nursery = end_nursery,
2473                                 };
2474                                 mono_handle_stack_scan ((HandleStack*)info->client_info.info.handle_stack, pin_handle_stack_interior_ptrs, &ud, precise);
2475                         }
2476                 }
2477         } FOREACH_THREAD_END
2478 }
2479
2480 /*
2481  * mono_gc_set_stack_end:
2482  *
2483  *   Set the end of the current threads stack to STACK_END. The stack space between 
2484  * STACK_END and the real end of the threads stack will not be scanned during collections.
2485  */
2486 void
2487 mono_gc_set_stack_end (void *stack_end)
2488 {
2489         SgenThreadInfo *info;
2490
2491         LOCK_GC;
2492         info = mono_thread_info_current ();
2493         if (info) {
2494                 SGEN_ASSERT (0, stack_end < info->client_info.stack_end, "Can only lower stack end");
2495                 info->client_info.stack_end = stack_end;
2496         }
2497         UNLOCK_GC;
2498 }
2499
2500 /*
2501  * Roots
2502  */
2503
2504 int
2505 mono_gc_register_root (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg)
2506 {
2507         return sgen_register_root (start, size, descr, descr ? ROOT_TYPE_NORMAL : ROOT_TYPE_PINNED, source, msg);
2508 }
2509
2510 int
2511 mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg)
2512 {
2513         return sgen_register_root (start, size, descr, ROOT_TYPE_WBARRIER, source, msg);
2514 }
2515
2516 void
2517 mono_gc_deregister_root (char* addr)
2518 {
2519         sgen_deregister_root (addr);
2520 }
2521
2522 /*
2523  * PThreads
2524  */
2525
2526 #ifndef HOST_WIN32
2527 int
2528 mono_gc_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
2529 {
2530         int res;
2531
2532         mono_threads_join_lock ();
2533         res = pthread_create (new_thread, attr, start_routine, arg);
2534         mono_threads_join_unlock ();
2535
2536         return res;
2537 }
2538 #endif
2539
2540 /*
2541  * Miscellaneous
2542  */
2543
2544 void
2545 sgen_client_total_allocated_heap_changed (size_t allocated_heap)
2546 {
2547         mono_runtime_resource_check_limit (MONO_RESOURCE_GC_HEAP, allocated_heap);
2548 }
2549
2550 gboolean
2551 mono_gc_user_markers_supported (void)
2552 {
2553         return TRUE;
2554 }
2555
2556 gboolean
2557 mono_object_is_alive (MonoObject* o)
2558 {
2559         return TRUE;
2560 }
2561
2562 int
2563 mono_gc_get_generation (MonoObject *obj)
2564 {
2565         if (sgen_ptr_in_nursery (obj))
2566                 return 0;
2567         return 1;
2568 }
2569
2570 const char *
2571 mono_gc_get_gc_name (void)
2572 {
2573         return "sgen";
2574 }
2575
2576 char*
2577 mono_gc_get_description (void)
2578 {
2579 #ifdef HAVE_CONC_GC_AS_DEFAULT
2580         return g_strdup ("sgen (concurrent by default)");
2581 #else
2582         return g_strdup ("sgen");
2583 #endif
2584 }
2585
2586 void
2587 mono_gc_set_desktop_mode (void)
2588 {
2589 }
2590
2591 gboolean
2592 mono_gc_is_moving (void)
2593 {
2594         return TRUE;
2595 }
2596
2597 gboolean
2598 mono_gc_is_disabled (void)
2599 {
2600         return FALSE;
2601 }
2602
2603 #ifdef HOST_WIN32
2604 BOOL APIENTRY mono_gc_dllmain (HMODULE module_handle, DWORD reason, LPVOID reserved)
2605 {
2606         return TRUE;
2607 }
2608 #endif
2609
2610 int
2611 mono_gc_max_generation (void)
2612 {
2613         return 1;
2614 }
2615
2616 gboolean
2617 mono_gc_precise_stack_mark_enabled (void)
2618 {
2619         return !conservative_stack_mark;
2620 }
2621
2622 void
2623 mono_gc_collect (int generation)
2624 {
2625         sgen_gc_collect (generation);
2626 }
2627
2628 int
2629 mono_gc_collection_count (int generation)
2630 {
2631         return sgen_gc_collection_count (generation);
2632 }
2633
2634 int64_t
2635 mono_gc_get_used_size (void)
2636 {
2637         return (int64_t)sgen_gc_get_used_size ();
2638 }
2639
2640 int64_t
2641 mono_gc_get_heap_size (void)
2642 {
2643         return (int64_t)sgen_gc_get_total_heap_allocation ();
2644 }
2645
2646 MonoGCDescriptor
2647 mono_gc_make_root_descr_user (MonoGCRootMarkFunc marker)
2648 {
2649         return sgen_make_user_root_descriptor (marker);
2650 }
2651
2652 MonoGCDescriptor
2653 mono_gc_make_descr_for_string (gsize *bitmap, int numbits)
2654 {
2655         return SGEN_DESC_STRING;
2656 }
2657
2658 void*
2659 mono_gc_get_nursery (int *shift_bits, size_t *size)
2660 {
2661         *size = sgen_nursery_size;
2662         *shift_bits = DEFAULT_NURSERY_BITS;
2663         return sgen_get_nursery_start ();
2664 }
2665
2666 int
2667 mono_gc_get_los_limit (void)
2668 {
2669         return SGEN_MAX_SMALL_OBJ_SIZE;
2670 }
2671
2672 gpointer
2673 sgen_client_default_metadata (void)
2674 {
2675         return mono_domain_get ();
2676 }
2677
2678 gpointer
2679 sgen_client_metadata_for_object (GCObject *obj)
2680 {
2681         return mono_object_domain (obj);
2682 }
2683
2684 /**
2685  * mono_gchandle_is_in_domain:
2686  * \param gchandle a GCHandle's handle.
2687  * \param domain An application domain.
2688  * \returns TRUE if the object wrapped by the \p gchandle belongs to the specific \p domain.
2689  */
2690 gboolean
2691 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
2692 {
2693         MonoDomain *gchandle_domain = (MonoDomain *)sgen_gchandle_get_metadata (gchandle);
2694         return domain->domain_id == gchandle_domain->domain_id;
2695 }
2696
2697 /**
2698  * mono_gchandle_free_domain:
2699  * \param unloading domain that is unloading
2700  *
2701  * Function used internally to cleanup any GC handle for objects belonging
2702  * to the specified domain during appdomain unload.
2703  */
2704 void
2705 mono_gchandle_free_domain (MonoDomain *unloading)
2706 {
2707 }
2708
2709 static gpointer
2710 null_link_if_in_domain (gpointer hidden, GCHandleType handle_type, int max_generation, gpointer user)
2711 {
2712         MonoDomain *unloading_domain = (MonoDomain *)user;
2713         MonoDomain *obj_domain;
2714         gboolean is_weak = MONO_GC_HANDLE_TYPE_IS_WEAK (handle_type);
2715         if (MONO_GC_HANDLE_IS_OBJECT_POINTER (hidden)) {
2716                 MonoObject *obj = (MonoObject *)MONO_GC_REVEAL_POINTER (hidden, is_weak);
2717                 obj_domain = mono_object_domain (obj);
2718         } else {
2719                 obj_domain = (MonoDomain *)MONO_GC_REVEAL_POINTER (hidden, is_weak);
2720         }
2721         if (unloading_domain->domain_id == obj_domain->domain_id)
2722                 return NULL;
2723         return hidden;
2724 }
2725
2726 void
2727 sgen_null_links_for_domain (MonoDomain *domain)
2728 {
2729         guint type;
2730         for (type = HANDLE_TYPE_MIN; type < HANDLE_TYPE_MAX; ++type)
2731                 sgen_gchandle_iterate ((GCHandleType)type, GENERATION_OLD, null_link_if_in_domain, domain);
2732 }
2733
2734 void
2735 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
2736 {
2737         sgen_gchandle_set_target (gchandle, obj);
2738 }
2739
2740 void
2741 sgen_client_gchandle_created (int handle_type, GCObject *obj, guint32 handle)
2742 {
2743 #ifndef DISABLE_PERFCOUNTERS
2744         mono_perfcounters->gc_num_handles++;
2745 #endif
2746         mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handle_type, handle, obj);
2747 }
2748
2749 void
2750 sgen_client_gchandle_destroyed (int handle_type, guint32 handle)
2751 {
2752 #ifndef DISABLE_PERFCOUNTERS
2753         mono_perfcounters->gc_num_handles--;
2754 #endif
2755         mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handle_type, handle, NULL);
2756 }
2757
2758 void
2759 sgen_client_ensure_weak_gchandles_accessible (void)
2760 {
2761         /*
2762          * During the second bridge processing step the world is
2763          * running again.  That step processes all weak links once
2764          * more to null those that refer to dead objects.  Before that
2765          * is completed, those links must not be followed, so we
2766          * conservatively wait for bridge processing when any weak
2767          * link is dereferenced.
2768          */
2769         /* FIXME: A GC can occur after this check fails, in which case we
2770          * should wait for bridge processing but would fail to do so.
2771          */
2772         if (G_UNLIKELY (bridge_processing_in_progress))
2773                 mono_gc_wait_for_bridge_processing ();
2774 }
2775
2776 void*
2777 mono_gc_invoke_with_gc_lock (MonoGCLockedCallbackFunc func, void *data)
2778 {
2779         void *result;
2780         LOCK_INTERRUPTION;
2781         result = func (data);
2782         UNLOCK_INTERRUPTION;
2783         return result;
2784 }
2785
2786 void
2787 mono_gc_register_altstack (gpointer stack, gint32 stack_size, gpointer altstack, gint32 altstack_size)
2788 {
2789         // FIXME:
2790 }
2791
2792 guint8*
2793 mono_gc_get_card_table (int *shift_bits, gpointer *mask)
2794 {
2795         return sgen_get_card_table_configuration (shift_bits, mask);
2796 }
2797
2798 gboolean
2799 mono_gc_card_table_nursery_check (void)
2800 {
2801         return !sgen_get_major_collector ()->is_concurrent;
2802 }
2803
2804 /* Negative value to remove */
2805 void
2806 mono_gc_add_memory_pressure (gint64 value)
2807 {
2808         /* FIXME: Implement at some point? */
2809 }
2810
2811 /*
2812  * Logging
2813  */
2814
2815 void
2816 sgen_client_degraded_allocation (size_t size)
2817 {
2818         static int last_major_gc_warned = -1;
2819         static int num_degraded = 0;
2820
2821         if (last_major_gc_warned < (int)gc_stats.major_gc_count) {
2822                 ++num_degraded;
2823                 if (num_degraded == 1 || num_degraded == 3)
2824                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "Warning: Degraded allocation.  Consider increasing nursery-size if the warning persists.");
2825                 else if (num_degraded == 10)
2826                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "Warning: Repeated degraded allocation.  Consider increasing nursery-size.");
2827                 last_major_gc_warned = gc_stats.major_gc_count;
2828         }
2829 }
2830
2831 /*
2832  * Debugging
2833  */
2834
2835 const char*
2836 sgen_client_description_for_internal_mem_type (int type)
2837 {
2838         switch (type) {
2839         case INTERNAL_MEM_EPHEMERON_LINK: return "ephemeron-link";
2840         case INTERNAL_MEM_MOVED_OBJECT: return "moved-object";
2841         default:
2842                 return NULL;
2843         }
2844 }
2845
2846 void
2847 sgen_client_pre_collection_checks (void)
2848 {
2849         if (sgen_mono_xdomain_checks) {
2850                 sgen_clear_nursery_fragments ();
2851                 sgen_check_for_xdomain_refs ();
2852         }
2853 }
2854
2855 gboolean
2856 sgen_client_vtable_is_inited (MonoVTable *vt)
2857 {
2858         return vt->klass->inited;
2859 }
2860
2861 const char*
2862 sgen_client_vtable_get_namespace (MonoVTable *vt)
2863 {
2864         return vt->klass->name_space;
2865 }
2866
2867 const char*
2868 sgen_client_vtable_get_name (MonoVTable *vt)
2869 {
2870         return vt->klass->name;
2871 }
2872
2873 /*
2874  * Initialization
2875  */
2876
2877 void
2878 sgen_client_init (void)
2879 {
2880         int dummy;
2881         MonoThreadInfoCallbacks cb;
2882
2883         cb.thread_register = sgen_thread_register;
2884         cb.thread_detach = sgen_thread_detach;
2885         cb.thread_unregister = sgen_thread_unregister;
2886         cb.thread_attach = sgen_thread_attach;
2887         cb.mono_thread_in_critical_region = thread_in_critical_region;
2888         cb.ip_in_critical_region = ip_in_critical_region;
2889
2890         mono_threads_init (&cb, sizeof (SgenThreadInfo));
2891
2892         ///* Keep this the default for now */
2893         /* Precise marking is broken on all supported targets. Disable until fixed. */
2894         conservative_stack_mark = TRUE;
2895
2896         sgen_register_fixed_internal_mem_type (INTERNAL_MEM_EPHEMERON_LINK, sizeof (EphemeronLinkNode));
2897
2898         mono_sgen_init_stw ();
2899
2900         mono_tls_init_gc_keys ();
2901
2902         mono_gc_register_thread (&dummy);
2903 }
2904
2905 gboolean
2906 sgen_client_handle_gc_param (const char *opt)
2907 {
2908         if (g_str_has_prefix (opt, "stack-mark=")) {
2909                 opt = strchr (opt, '=') + 1;
2910                 if (!strcmp (opt, "precise")) {
2911                         conservative_stack_mark = FALSE;
2912                 } else if (!strcmp (opt, "conservative")) {
2913                         conservative_stack_mark = TRUE;
2914                 } else {
2915                         sgen_env_var_error (MONO_GC_PARAMS_NAME, conservative_stack_mark ? "Using `conservative`." : "Using `precise`.",
2916                                         "Invalid value `%s` for `stack-mark` option, possible values are: `precise`, `conservative`.", opt);
2917                 }
2918         } else if (g_str_has_prefix (opt, "bridge-implementation=")) {
2919                 opt = strchr (opt, '=') + 1;
2920                 sgen_set_bridge_implementation (opt);
2921         } else if (g_str_has_prefix (opt, "toggleref-test")) {
2922                 /* FIXME: This should probably in MONO_GC_DEBUG */
2923                 sgen_register_test_toggleref_callback ();
2924         } else if (!sgen_bridge_handle_gc_param (opt)) {
2925                 return FALSE;
2926         }
2927         return TRUE;
2928 }
2929
2930 void
2931 sgen_client_print_gc_params_usage (void)
2932 {
2933         fprintf (stderr, "  stack-mark=MARK-METHOD (where MARK-METHOD is 'precise' or 'conservative')\n");
2934 }
2935
2936 gboolean
2937 sgen_client_handle_gc_debug (const char *opt)
2938 {
2939         if (!strcmp (opt, "xdomain-checks")) {
2940                 sgen_mono_xdomain_checks = TRUE;
2941         } else if (!strcmp (opt, "do-not-finalize")) {
2942                 mono_do_not_finalize = TRUE;
2943         } else if (g_str_has_prefix (opt, "do-not-finalize=")) {
2944                 opt = strchr (opt, '=') + 1;
2945                 mono_do_not_finalize = TRUE;
2946                 mono_do_not_finalize_class_names = g_strsplit (opt, ",", 0);
2947         } else if (!strcmp (opt, "log-finalizers")) {
2948                 log_finalizers = TRUE;
2949         } else if (!strcmp (opt, "no-managed-allocator")) {
2950                 sgen_set_use_managed_allocator (FALSE);
2951         } else if (!sgen_bridge_handle_gc_debug (opt)) {
2952                 return FALSE;
2953         }
2954         return TRUE;
2955 }
2956
2957 void
2958 sgen_client_print_gc_debug_usage (void)
2959 {
2960         fprintf (stderr, "  xdomain-checks\n");
2961         fprintf (stderr, "  do-not-finalize\n");
2962         fprintf (stderr, "  log-finalizers\n");
2963         fprintf (stderr, "  no-managed-allocator\n");
2964         sgen_bridge_print_gc_debug_usage ();
2965 }
2966
2967
2968 gpointer
2969 sgen_client_get_provenance (void)
2970 {
2971 #ifdef SGEN_OBJECT_PROVENANCE
2972         MonoGCCallbacks *cb = mono_gc_get_gc_callbacks ();
2973         gpointer (*get_provenance_func) (void);
2974         if (!cb)
2975                 return NULL;
2976         get_provenance_func = cb->get_provenance_func;
2977         if (get_provenance_func)
2978                 return get_provenance_func ();
2979         return NULL;
2980 #else
2981         return NULL;
2982 #endif
2983 }
2984
2985 void
2986 sgen_client_describe_invalid_pointer (GCObject *ptr)
2987 {
2988         sgen_bridge_describe_pointer (ptr);
2989 }
2990
2991 static gboolean gc_inited;
2992
2993 /**
2994  * mono_gc_base_init:
2995  */
2996 void
2997 mono_gc_base_init (void)
2998 {
2999         if (gc_inited)
3000                 return;
3001
3002         mono_counters_init ();
3003
3004 #ifndef HOST_WIN32
3005         mono_w32handle_init ();
3006 #endif
3007
3008 #ifdef HEAVY_STATISTICS
3009         mono_counters_register ("los marked cards", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &los_marked_cards);
3010         mono_counters_register ("los array cards scanned ", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &los_array_cards);
3011         mono_counters_register ("los array remsets", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &los_array_remsets);
3012
3013         mono_counters_register ("WBarrier set arrayref", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_wbarrier_set_arrayref);
3014         mono_counters_register ("WBarrier value copy", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_wbarrier_value_copy);
3015         mono_counters_register ("WBarrier object copy", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_wbarrier_object_copy);
3016 #endif
3017
3018         sgen_gc_init ();
3019
3020         gc_inited = TRUE;
3021 }
3022
3023 void
3024 mono_gc_base_cleanup (void)
3025 {
3026         sgen_thread_pool_shutdown (major_collector.get_sweep_pool ());
3027
3028         sgen_workers_shutdown ();
3029
3030         // We should have consumed any outstanding moves.
3031         g_assert (sgen_pointer_queue_is_empty (&moved_objects_queue));
3032 }
3033
3034 gboolean
3035 mono_gc_is_null (void)
3036 {
3037         return FALSE;
3038 }
3039
3040 #endif