1 /**
2  * \file
3  * Mono's client definitions for SGen.
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 #ifdef SGEN_DEFINE_OBJECT_VTABLE
11 
12 #include "sgen/sgen-archdep.h"
13 #include "utils/mono-threads.h"
14 #include "utils/mono-mmap.h"
15 #include "metadata/object-internals.h"
16 
17 typedef MonoObject GCObject;
18 typedef MonoVTable* GCVTable;
19 
20 static inline GCVTable
SGEN_LOAD_VTABLE_UNCHECKED(GCObject * obj)21 SGEN_LOAD_VTABLE_UNCHECKED (GCObject *obj)
22 {
23 	return obj->vtable;
24 }
25 
26 static inline SgenDescriptor
sgen_vtable_get_descriptor(GCVTable vtable)27 sgen_vtable_get_descriptor (GCVTable vtable)
28 {
29 	return (SgenDescriptor)vtable->gc_descr;
30 }
31 
32 typedef struct _SgenClientThreadInfo SgenClientThreadInfo;
33 struct _SgenClientThreadInfo {
34 	MonoThreadInfo info;
35 
36 	/*
37 	 * `skip` is set to TRUE when STW fails to suspend a thread, most probably because
38 	 * the underlying thread is dead.
39 	*/
40 	gboolean skip, suspend_done;
41 	volatile int in_critical_region;
42 
43 	/*
44 	This is set the argument of mono_gc_set_skip_thread.
45 
46 	A thread that knowingly holds no managed state can call this
47 	function around blocking loops to reduce the GC burden by not
48 	been scanned.
49 	*/
50 	gboolean gc_disabled;
51 
52 #ifdef SGEN_POSIX_STW
53 	/* This is -1 until the first suspend. */
54 	int signal;
55 	/* FIXME: kill this, we only use signals on systems that have rt-posix, which doesn't have issues with duplicates. */
56 	unsigned int stop_count; /* to catch duplicate signals. */
57 #endif
58 
59 	gpointer runtime_data;
60 
61 	void *stack_end;
62 	void *stack_start;
63 	void *stack_start_limit;
64 
65 	MonoContext ctx;		/* ditto */
66 };
67 
68 #else
69 
70 #include "metadata/profiler-private.h"
71 #include "utils/dtrace.h"
72 #include "utils/mono-counters.h"
73 #include "utils/mono-logger-internals.h"
74 #include "utils/mono-time.h"
75 #include "utils/mono-os-semaphore.h"
76 #include "metadata/sgen-bridge-internals.h"
77 
78 extern void mono_sgen_register_moved_object (void *obj, void *destination);
79 extern void mono_sgen_gc_event_moves (void);
80 
81 extern void mono_sgen_init_stw (void);
82 
83 enum {
84 	INTERNAL_MEM_EPHEMERON_LINK = INTERNAL_MEM_FIRST_CLIENT,
85 	INTERNAL_MEM_MOVED_OBJECT,
86 	INTERNAL_MEM_MAX
87 };
88 
89 static inline mword
sgen_mono_array_size(GCVTable vtable,MonoArray * array,mword * bounds_size,mword descr)90 sgen_mono_array_size (GCVTable vtable, MonoArray *array, mword *bounds_size, mword descr)
91 {
92 	mword size, size_without_bounds;
93 	int element_size;
94 
95 	if ((descr & DESC_TYPE_MASK) == DESC_TYPE_VECTOR)
96 		element_size = ((descr) >> VECTOR_ELSIZE_SHIFT) & MAX_ELEMENT_SIZE;
97 	else
98 		element_size = vtable->klass->sizes.element_size;
99 
100 	size_without_bounds = size = MONO_SIZEOF_MONO_ARRAY + (mword)element_size * mono_array_length_fast (array);
101 
102 	if (G_UNLIKELY (array->bounds)) {
103 		size += sizeof (mono_array_size_t) - 1;
104 		size &= ~(sizeof (mono_array_size_t) - 1);
105 		size += sizeof (MonoArrayBounds) * vtable->klass->rank;
106 	}
107 
108 	if (bounds_size)
109 		*bounds_size = size - size_without_bounds;
110 	return size;
111 }
112 
113 #define SGEN_CLIENT_OBJECT_HEADER_SIZE		(sizeof (GCObject))
114 #define SGEN_CLIENT_MINIMUM_OBJECT_SIZE		SGEN_CLIENT_OBJECT_HEADER_SIZE
115 
116 static mword /*__attribute__ ((__noinline__)) not sure if this hint is a good idea*/
sgen_client_slow_object_get_size(GCVTable vtable,GCObject * o)117 sgen_client_slow_object_get_size (GCVTable vtable, GCObject* o)
118 {
119 	MonoClass *klass = ((MonoVTable*)vtable)->klass;
120 
121 	/*
122 	 * We depend on mono_string_length_fast and
123 	 * mono_array_length_fast not using the object's vtable.
124 	 */
125 	if (klass == mono_defaults.string_class) {
126 		return G_STRUCT_OFFSET (MonoString, chars) + 2 * mono_string_length_fast ((MonoString*) o) + 2;
127 	} else if (klass->rank) {
128 		return sgen_mono_array_size (vtable, (MonoArray*)o, NULL, 0);
129 	} else {
130 		/* from a created object: the class must be inited already */
131 		return klass->instance_size;
132 	}
133 }
134 
135 /*
136  * This function can be called on an object whose first word, the
137  * vtable field, is not intact.  This is necessary for the parallel
138  * collector.
139  */
140 static MONO_NEVER_INLINE mword
sgen_client_par_object_get_size(GCVTable vtable,GCObject * o)141 sgen_client_par_object_get_size (GCVTable vtable, GCObject* o)
142 {
143 	SgenDescriptor descr = sgen_vtable_get_descriptor (vtable);
144 	mword type = descr & DESC_TYPE_MASK;
145 
146 	if (type == DESC_TYPE_RUN_LENGTH || type == DESC_TYPE_SMALL_PTRFREE) {
147 		mword size = descr & 0xfff8;
148 		SGEN_ASSERT (9, size >= sizeof (MonoObject), "Run length object size to small");
149 		return size;
150 	} else if (descr == SGEN_DESC_STRING) {
151 		return G_STRUCT_OFFSET (MonoString, chars) + 2 * mono_string_length_fast ((MonoString*) o) + 2;
152 	} else if (type == DESC_TYPE_VECTOR) {
153 		return sgen_mono_array_size (vtable, (MonoArray*)o, NULL, descr);
154 	}
155 
156 	return sgen_client_slow_object_get_size (vtable, o);
157 }
158 
159 static MONO_ALWAYS_INLINE size_t G_GNUC_UNUSED
sgen_client_array_element_size(GCVTable gc_vtable)160 sgen_client_array_element_size (GCVTable gc_vtable)
161 {
162 	MonoVTable *vt = (MonoVTable*)gc_vtable;
163 	return mono_array_element_size (vt->klass);
164 }
165 
166 static MONO_ALWAYS_INLINE G_GNUC_UNUSED char*
sgen_client_array_data_start(GCObject * obj)167 sgen_client_array_data_start (GCObject *obj)
168 {
169 	return (char*)(obj) +  G_STRUCT_OFFSET (MonoArray, vector);
170 }
171 
172 static MONO_ALWAYS_INLINE size_t G_GNUC_UNUSED
sgen_client_array_length(GCObject * obj)173 sgen_client_array_length (GCObject *obj)
174 {
175 	return mono_array_length_fast ((MonoArray*)obj);
176 }
177 
178 static MONO_ALWAYS_INLINE gboolean G_GNUC_UNUSED
sgen_client_object_is_array_fill(GCObject * o)179 sgen_client_object_is_array_fill (GCObject *o)
180 {
181 	return ((MonoObject*)o)->synchronisation == GINT_TO_POINTER (-1);
182 }
183 
184 static MONO_ALWAYS_INLINE void G_GNUC_UNUSED
sgen_client_pre_copy_checks(char * destination,GCVTable gc_vtable,void * obj,mword objsize)185 sgen_client_pre_copy_checks (char *destination, GCVTable gc_vtable, void *obj, mword objsize)
186 {
187 	MonoVTable *vt = (MonoVTable*)gc_vtable;
188 	SGEN_ASSERT (9, vt->klass->inited, "vtable %p for class %s:%s was not initialized", vt, vt->klass->name_space, vt->klass->name);
189 }
190 
191 static MONO_ALWAYS_INLINE void G_GNUC_UNUSED
sgen_client_update_copied_object(char * destination,GCVTable gc_vtable,void * obj,mword objsize)192 sgen_client_update_copied_object (char *destination, GCVTable gc_vtable, void *obj, mword objsize)
193 {
194 	MonoVTable *vt = (MonoVTable*)gc_vtable;
195 	if (G_UNLIKELY (vt->rank && ((MonoArray*)obj)->bounds)) {
196 		MonoArray *array = (MonoArray*)destination;
197 		array->bounds = (MonoArrayBounds*)((char*)destination + ((char*)((MonoArray*)obj)->bounds - (char*)obj));
198 		SGEN_LOG (9, "Array instance %p: size: %lu, rank: %d, length: %lu", array, (unsigned long)objsize, vt->rank, (unsigned long)mono_array_length (array));
199 	}
200 
201 	if (MONO_PROFILER_ENABLED (gc_moves))
202 		mono_sgen_register_moved_object (obj, destination);
203 }
204 
205 #ifdef XDOMAIN_CHECKS_IN_WBARRIER
206 extern gboolean sgen_mono_xdomain_checks;
207 
208 #define sgen_client_wbarrier_generic_nostore_check(ptr) do {		\
209 		/* FIXME: ptr_in_heap must be called with the GC lock held */ \
210 		if (sgen_mono_xdomain_checks && *(MonoObject**)ptr && ptr_in_heap (ptr)) { \
211 			char *start = find_object_for_ptr (ptr);	\
212 			MonoObject *value = *(MonoObject**)ptr;		\
213 			LOCK_GC;					\
214 			SGEN_ASSERT (0, start, "Write barrier outside an object?"); \
215 			if (start) {					\
216 				MonoObject *obj = (MonoObject*)start;	\
217 				if (obj->vtable->domain != value->vtable->domain) \
218 					SGEN_ASSERT (0, is_xdomain_ref_allowed (ptr, start, obj->vtable->domain), "Cross-domain ref not allowed"); \
219 			}						\
220 			UNLOCK_GC;					\
221 		}							\
222 	} while (0)
223 #else
224 #define sgen_client_wbarrier_generic_nostore_check(ptr)
225 #endif
226 
227 static gboolean G_GNUC_UNUSED
sgen_client_object_has_critical_finalizer(GCObject * obj)228 sgen_client_object_has_critical_finalizer (GCObject *obj)
229 {
230 	MonoClass *klass;
231 
232 	if (!mono_defaults.critical_finalizer_object)
233 		return FALSE;
234 
235 	klass = SGEN_LOAD_VTABLE (obj)->klass;
236 
237 	return mono_class_has_parent_fast (klass, mono_defaults.critical_finalizer_object);
238 }
239 
240 const char* sgen_client_vtable_get_namespace (GCVTable vtable);
241 const char* sgen_client_vtable_get_name (GCVTable vtable);
242 
243 static gboolean G_GNUC_UNUSED
sgen_client_bridge_need_processing(void)244 sgen_client_bridge_need_processing (void)
245 {
246 	return sgen_need_bridge_processing ();
247 }
248 
249 static void G_GNUC_UNUSED
sgen_client_bridge_reset_data(void)250 sgen_client_bridge_reset_data (void)
251 {
252 	sgen_bridge_reset_data ();
253 }
254 
255 static void G_GNUC_UNUSED
sgen_client_bridge_processing_stw_step(void)256 sgen_client_bridge_processing_stw_step (void)
257 {
258 	sgen_bridge_processing_stw_step ();
259 }
260 
261 static void G_GNUC_UNUSED
sgen_client_bridge_wait_for_processing(void)262 sgen_client_bridge_wait_for_processing (void)
263 {
264 	mono_gc_wait_for_bridge_processing ();
265 }
266 
267 static void G_GNUC_UNUSED
sgen_client_bridge_processing_finish(int generation)268 sgen_client_bridge_processing_finish (int generation)
269 {
270 	sgen_bridge_processing_finish (generation);
271 }
272 
273 static gboolean G_GNUC_UNUSED
sgen_client_bridge_is_bridge_object(GCObject * obj)274 sgen_client_bridge_is_bridge_object (GCObject *obj)
275 {
276 	return sgen_is_bridge_object (obj);
277 }
278 
279 static void G_GNUC_UNUSED
sgen_client_bridge_register_finalized_object(GCObject * object)280 sgen_client_bridge_register_finalized_object (GCObject *object)
281 {
282 	sgen_bridge_register_finalized_object (object);
283 }
284 
285 static void G_GNUC_UNUSED
sgen_client_binary_protocol_collection_requested(int generation,size_t requested_size,gboolean force)286 sgen_client_binary_protocol_collection_requested (int generation, size_t requested_size, gboolean force)
287 {
288 	MONO_GC_REQUESTED (generation, requested_size, force);
289 }
290 
291 static void G_GNUC_UNUSED
sgen_client_binary_protocol_collection_begin(int minor_gc_count,int generation)292 sgen_client_binary_protocol_collection_begin (int minor_gc_count, int generation)
293 {
294 	MONO_GC_BEGIN (generation);
295 
296 	MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_START, generation));
297 
298 #ifndef DISABLE_PERFCOUNTERS
299 	if (generation == GENERATION_NURSERY)
300 		mono_atomic_inc_i32 (&mono_perfcounters->gc_collections0);
301 	else
302 		mono_atomic_inc_i32 (&mono_perfcounters->gc_collections1);
303 #endif
304 }
305 
306 static void G_GNUC_UNUSED
sgen_client_binary_protocol_collection_end(int minor_gc_count,int generation,long long num_objects_scanned,long long num_unique_objects_scanned)307 sgen_client_binary_protocol_collection_end (int minor_gc_count, int generation, long long num_objects_scanned, long long num_unique_objects_scanned)
308 {
309 	MONO_GC_END (generation);
310 
311 	MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_END, generation));
312 }
313 
314 static void G_GNUC_UNUSED
sgen_client_binary_protocol_concurrent_start(void)315 sgen_client_binary_protocol_concurrent_start (void)
316 {
317 	MONO_GC_CONCURRENT_START_BEGIN (GENERATION_OLD);
318 }
319 
320 static void G_GNUC_UNUSED
sgen_client_binary_protocol_concurrent_update(void)321 sgen_client_binary_protocol_concurrent_update (void)
322 {
323 	MONO_GC_CONCURRENT_UPDATE_FINISH_BEGIN (GENERATION_OLD, sgen_get_major_collector ()->get_and_reset_num_major_objects_marked ());
324 }
325 
326 static void G_GNUC_UNUSED
sgen_client_binary_protocol_concurrent_finish(void)327 sgen_client_binary_protocol_concurrent_finish (void)
328 {
329 	MONO_GC_CONCURRENT_UPDATE_FINISH_BEGIN (GENERATION_OLD, sgen_get_major_collector ()->get_and_reset_num_major_objects_marked ());
330 }
331 
332 static void G_GNUC_UNUSED
sgen_client_binary_protocol_sweep_begin(int generation,int full_sweep)333 sgen_client_binary_protocol_sweep_begin (int generation, int full_sweep)
334 {
335 	MONO_GC_SWEEP_BEGIN (generation, full_sweep);
336 }
337 
338 static void G_GNUC_UNUSED
sgen_client_binary_protocol_sweep_end(int generation,int full_sweep)339 sgen_client_binary_protocol_sweep_end (int generation, int full_sweep)
340 {
341 	MONO_GC_SWEEP_END (generation, full_sweep);
342 }
343 
344 static void G_GNUC_UNUSED
sgen_client_binary_protocol_world_stopping(int generation,long long timestamp,gpointer thread)345 sgen_client_binary_protocol_world_stopping (int generation, long long timestamp, gpointer thread)
346 {
347 	MONO_GC_WORLD_STOP_BEGIN ();
348 }
349 
350 static void G_GNUC_UNUSED
sgen_client_binary_protocol_world_stopped(int generation,long long timestamp,long long total_major_cards,long long marked_major_cards,long long total_los_cards,long long marked_los_cards)351 sgen_client_binary_protocol_world_stopped (int generation, long long timestamp, long long total_major_cards, long long marked_major_cards, long long total_los_cards, long long marked_los_cards)
352 {
353 	MONO_GC_WORLD_STOP_END ();
354 }
355 
356 static void G_GNUC_UNUSED
sgen_client_binary_protocol_world_restarting(int generation,long long timestamp,long long total_major_cards,long long marked_major_cards,long long total_los_cards,long long marked_los_cards)357 sgen_client_binary_protocol_world_restarting (int generation, long long timestamp, long long total_major_cards, long long marked_major_cards, long long total_los_cards, long long marked_los_cards)
358 {
359 	MONO_GC_WORLD_RESTART_BEGIN (generation);
360 }
361 
362 static void G_GNUC_UNUSED
sgen_client_binary_protocol_world_restarted(int generation,long long timestamp)363 sgen_client_binary_protocol_world_restarted (int generation, long long timestamp)
364 {
365 	MONO_GC_WORLD_RESTART_END (generation);
366 }
367 
368 static void G_GNUC_UNUSED
sgen_client_binary_protocol_block_alloc(gpointer addr,size_t size)369 sgen_client_binary_protocol_block_alloc (gpointer addr, size_t size)
370 {
371 }
372 
373 static void G_GNUC_UNUSED
sgen_client_binary_protocol_block_free(gpointer addr,size_t size)374 sgen_client_binary_protocol_block_free (gpointer addr, size_t size)
375 {
376 }
377 
378 static void G_GNUC_UNUSED
sgen_client_binary_protocol_block_set_state(gpointer addr,size_t size,int old,int new_)379 sgen_client_binary_protocol_block_set_state (gpointer addr, size_t size, int old, int new_)
380 {
381 }
382 
383 static void G_GNUC_UNUSED
sgen_client_binary_protocol_mark_start(int generation)384 sgen_client_binary_protocol_mark_start (int generation)
385 {
386 }
387 
388 static void G_GNUC_UNUSED
sgen_client_binary_protocol_mark_end(int generation)389 sgen_client_binary_protocol_mark_end (int generation)
390 {
391 }
392 
393 static void G_GNUC_UNUSED
sgen_client_binary_protocol_reclaim_start(int generation)394 sgen_client_binary_protocol_reclaim_start (int generation)
395 {
396 }
397 
398 static void G_GNUC_UNUSED
sgen_client_binary_protocol_reclaim_end(int generation)399 sgen_client_binary_protocol_reclaim_end (int generation)
400 {
401 }
402 
403 static void
mono_binary_protocol_alloc_generic(gpointer obj,gpointer vtable,size_t size,gboolean pinned)404 mono_binary_protocol_alloc_generic (gpointer obj, gpointer vtable, size_t size, gboolean pinned)
405 {
406 #ifdef ENABLE_DTRACE
407 	const char *namespace = sgen_client_vtable_get_namespace (vtable);
408 	const char *name = sgen_client_vtable_get_name (vtable);
409 
410 	if (sgen_ptr_in_nursery (obj)) {
411 		if (G_UNLIKELY (MONO_GC_NURSERY_OBJ_ALLOC_ENABLED ()))
412 			MONO_GC_NURSERY_OBJ_ALLOC ((mword)obj, size, namespace, name);
413 	} else {
414 		if (size > SGEN_MAX_SMALL_OBJ_SIZE) {
415 			if (G_UNLIKELY (MONO_GC_MAJOR_OBJ_ALLOC_LARGE_ENABLED ()))
416 				MONO_GC_MAJOR_OBJ_ALLOC_LARGE ((mword)obj, size, namespace, name);
417 		} else if (pinned) {
418 			MONO_GC_MAJOR_OBJ_ALLOC_PINNED ((mword)obj, size, namespace, name);
419 		}
420 	}
421 #endif
422 }
423 
424 static void G_GNUC_UNUSED
sgen_client_binary_protocol_alloc(gpointer obj,gpointer vtable,size_t size,gpointer provenance)425 sgen_client_binary_protocol_alloc (gpointer obj, gpointer vtable, size_t size, gpointer provenance)
426 {
427 	mono_binary_protocol_alloc_generic (obj, vtable, size, FALSE);
428 }
429 
430 static void G_GNUC_UNUSED
sgen_client_binary_protocol_alloc_pinned(gpointer obj,gpointer vtable,size_t size,gpointer provenance)431 sgen_client_binary_protocol_alloc_pinned (gpointer obj, gpointer vtable, size_t size, gpointer provenance)
432 {
433 	mono_binary_protocol_alloc_generic (obj, vtable, size, TRUE);
434 }
435 
436 static void G_GNUC_UNUSED
sgen_client_binary_protocol_alloc_degraded(gpointer obj,gpointer vtable,size_t size,gpointer provenance)437 sgen_client_binary_protocol_alloc_degraded (gpointer obj, gpointer vtable, size_t size, gpointer provenance)
438 {
439 	MONO_GC_MAJOR_OBJ_ALLOC_DEGRADED ((mword)obj, size, sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable));
440 }
441 
442 static void G_GNUC_UNUSED
sgen_client_binary_protocol_card_scan(gpointer start,size_t size)443 sgen_client_binary_protocol_card_scan (gpointer start, size_t size)
444 {
445 }
446 
447 static void G_GNUC_UNUSED
sgen_client_binary_protocol_pin_stage(gpointer addr_ptr,gpointer addr)448 sgen_client_binary_protocol_pin_stage (gpointer addr_ptr, gpointer addr)
449 {
450 }
451 
452 static void G_GNUC_UNUSED
sgen_client_binary_protocol_cement_stage(gpointer addr)453 sgen_client_binary_protocol_cement_stage (gpointer addr)
454 {
455 }
456 
457 static void G_GNUC_UNUSED
sgen_client_binary_protocol_pin(gpointer obj,gpointer vtable,size_t size)458 sgen_client_binary_protocol_pin (gpointer obj, gpointer vtable, size_t size)
459 {
460 #ifdef ENABLE_DTRACE
461 	if (G_UNLIKELY (MONO_GC_OBJ_PINNED_ENABLED ())) {
462 		int gen = sgen_ptr_in_nursery (obj) ? GENERATION_NURSERY : GENERATION_OLD;
463 		MONO_GC_OBJ_PINNED ((mword)obj,
464 				sgen_safe_object_get_size (obj),
465 				sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable), gen);
466 	}
467 #endif
468 }
469 
470 static void G_GNUC_UNUSED
sgen_client_binary_protocol_mark(gpointer obj,gpointer vtable,size_t size)471 sgen_client_binary_protocol_mark (gpointer obj, gpointer vtable, size_t size)
472 {
473 }
474 
475 static void G_GNUC_UNUSED
sgen_client_binary_protocol_scan_begin(gpointer obj,gpointer vtable,size_t size)476 sgen_client_binary_protocol_scan_begin (gpointer obj, gpointer vtable, size_t size)
477 {
478 }
479 
480 static void G_GNUC_UNUSED
sgen_client_binary_protocol_scan_vtype_begin(gpointer obj,size_t size)481 sgen_client_binary_protocol_scan_vtype_begin (gpointer obj, size_t size)
482 {
483 }
484 
485 static void G_GNUC_UNUSED
sgen_client_binary_protocol_scan_process_reference(gpointer obj,gpointer ptr,gpointer value)486 sgen_client_binary_protocol_scan_process_reference (gpointer obj, gpointer ptr, gpointer value)
487 {
488 }
489 
490 static void G_GNUC_UNUSED
sgen_client_binary_protocol_scan_stack(gpointer thread,gpointer stack_start,gpointer stack_end,int skip_reason)491 sgen_client_binary_protocol_scan_stack (gpointer thread, gpointer stack_start, gpointer stack_end, int skip_reason)
492 {
493 }
494 
495 static void G_GNUC_UNUSED
sgen_client_binary_protocol_wbarrier(gpointer ptr,gpointer value,gpointer value_vtable)496 sgen_client_binary_protocol_wbarrier (gpointer ptr, gpointer value, gpointer value_vtable)
497 {
498 }
499 
500 static void G_GNUC_UNUSED
sgen_client_binary_protocol_cement(gpointer ptr,gpointer vtable,size_t size)501 sgen_client_binary_protocol_cement (gpointer ptr, gpointer vtable, size_t size)
502 {
503 #ifdef ENABLE_DTRACE
504 	if (G_UNLIKELY (MONO_GC_OBJ_CEMENTED_ENABLED())) {
505 		MONO_GC_OBJ_CEMENTED ((mword)ptr, sgen_safe_object_get_size ((GCObject*)ptr),
506 				sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable));
507 	}
508 #endif
509 }
510 
511 static void G_GNUC_UNUSED
sgen_client_binary_protocol_copy(gpointer from,gpointer to,gpointer vtable,size_t size)512 sgen_client_binary_protocol_copy (gpointer from, gpointer to, gpointer vtable, size_t size)
513 {
514 #ifdef ENABLE_DTRACE
515 	if (G_UNLIKELY (MONO_GC_OBJ_MOVED_ENABLED ())) {
516 		int dest_gen = sgen_ptr_in_nursery (to) ? GENERATION_NURSERY : GENERATION_OLD;
517 		int src_gen = sgen_ptr_in_nursery (from) ? GENERATION_NURSERY : GENERATION_OLD;
518 		MONO_GC_OBJ_MOVED ((mword)to, (mword)from, dest_gen, src_gen, size, sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable));
519 	}
520 #endif
521 }
522 
523 static void G_GNUC_UNUSED
sgen_client_binary_protocol_global_remset(gpointer ptr,gpointer value,gpointer value_vtable)524 sgen_client_binary_protocol_global_remset (gpointer ptr, gpointer value, gpointer value_vtable)
525 {
526 #ifdef ENABLE_DTRACE
527 	if (G_UNLIKELY (MONO_GC_GLOBAL_REMSET_ADD_ENABLED ())) {
528 		MONO_GC_GLOBAL_REMSET_ADD ((mword)ptr, (mword)value, sgen_safe_object_get_size (value),
529 				sgen_client_vtable_get_namespace (value_vtable), sgen_client_vtable_get_name (value_vtable));
530 	}
531 #endif
532 }
533 
534 static void G_GNUC_UNUSED
sgen_client_binary_protocol_mod_union_remset(gpointer obj,gpointer ptr,gpointer value,gpointer value_vtable)535 sgen_client_binary_protocol_mod_union_remset (gpointer obj, gpointer ptr, gpointer value, gpointer value_vtable)
536 {
537 }
538 
539 static void G_GNUC_UNUSED
sgen_client_binary_protocol_ptr_update(gpointer ptr,gpointer old_value,gpointer new_value,gpointer vtable,size_t size)540 sgen_client_binary_protocol_ptr_update (gpointer ptr, gpointer old_value, gpointer new_value, gpointer vtable, size_t size)
541 {
542 }
543 
544 static void G_GNUC_UNUSED
sgen_client_binary_protocol_cleanup(gpointer ptr,gpointer vtable,size_t size)545 sgen_client_binary_protocol_cleanup (gpointer ptr, gpointer vtable, size_t size)
546 {
547 }
548 
549 static void G_GNUC_UNUSED
sgen_client_binary_protocol_dislink_add(gpointer link,gpointer obj,gboolean track)550 sgen_client_binary_protocol_dislink_add (gpointer link, gpointer obj, gboolean track)
551 {
552 }
553 
554 static void G_GNUC_UNUSED
sgen_client_binary_protocol_dislink_update(gpointer link,gpointer obj,gboolean track)555 sgen_client_binary_protocol_dislink_update (gpointer link, gpointer obj, gboolean track)
556 {
557 #ifdef ENABLE_DTRACE
558 	if (MONO_GC_WEAK_UPDATE_ENABLED ()) {
559 		GCVTable vt = obj ? SGEN_LOAD_VTABLE (obj) : NULL;
560 		MONO_GC_WEAK_UPDATE ((mword)link,
561 				(mword)obj,
562 				obj ? (mword)sgen_safe_object_get_size (obj) : (mword)0,
563 				obj ? sgen_client_vtable_get_namespace (vt) : NULL,
564 				obj ? sgen_client_vtable_get_name (vt) : NULL,
565 				track ? 1 : 0);
566 	}
567 #endif
568 }
569 
570 static void G_GNUC_UNUSED
sgen_client_binary_protocol_dislink_remove(gpointer link,gboolean track)571 sgen_client_binary_protocol_dislink_remove (gpointer link, gboolean track)
572 {
573 }
574 
575 static void G_GNUC_UNUSED
sgen_client_binary_protocol_empty(gpointer start,size_t size)576 sgen_client_binary_protocol_empty (gpointer start, size_t size)
577 {
578 	if (sgen_ptr_in_nursery (start))
579 		MONO_GC_NURSERY_SWEPT ((mword)start, size);
580 	else
581 		MONO_GC_MAJOR_SWEPT ((mword)start, size);
582 }
583 
584 static void G_GNUC_UNUSED
sgen_client_binary_protocol_thread_suspend(gpointer thread,gpointer stopped_ip)585 sgen_client_binary_protocol_thread_suspend (gpointer thread, gpointer stopped_ip)
586 {
587 }
588 
589 static void G_GNUC_UNUSED
sgen_client_binary_protocol_thread_restart(gpointer thread)590 sgen_client_binary_protocol_thread_restart (gpointer thread)
591 {
592 }
593 
594 static void G_GNUC_UNUSED
sgen_client_binary_protocol_thread_register(gpointer thread)595 sgen_client_binary_protocol_thread_register (gpointer thread)
596 {
597 }
598 
599 static void G_GNUC_UNUSED
sgen_client_binary_protocol_thread_unregister(gpointer thread)600 sgen_client_binary_protocol_thread_unregister (gpointer thread)
601 {
602 }
603 
604 static void G_GNUC_UNUSED
sgen_client_binary_protocol_missing_remset(gpointer obj,gpointer obj_vtable,int offset,gpointer value,gpointer value_vtable,gboolean value_pinned)605 sgen_client_binary_protocol_missing_remset (gpointer obj, gpointer obj_vtable, int offset, gpointer value, gpointer value_vtable, gboolean value_pinned)
606 {
607 }
608 
609 static void G_GNUC_UNUSED
sgen_client_binary_protocol_cement_reset(void)610 sgen_client_binary_protocol_cement_reset (void)
611 {
612 }
613 
614 static void G_GNUC_UNUSED
sgen_client_binary_protocol_domain_unload_begin(gpointer domain)615 sgen_client_binary_protocol_domain_unload_begin (gpointer domain)
616 {
617 }
618 
619 static void G_GNUC_UNUSED
sgen_client_binary_protocol_domain_unload_end(gpointer domain)620 sgen_client_binary_protocol_domain_unload_end (gpointer domain)
621 {
622 }
623 
624 static void G_GNUC_UNUSED
sgen_client_binary_protocol_gray_enqueue(gpointer queue,gpointer cursor,gpointer value)625 sgen_client_binary_protocol_gray_enqueue (gpointer queue, gpointer cursor, gpointer value)
626 {
627 }
628 
629 static void G_GNUC_UNUSED
sgen_client_binary_protocol_gray_dequeue(gpointer queue,gpointer cursor,gpointer value)630 sgen_client_binary_protocol_gray_dequeue (gpointer queue, gpointer cursor, gpointer value)
631 {
632 }
633 
634 static void G_GNUC_UNUSED
sgen_client_binary_protocol_major_card_table_scan_start(long long timestamp,gboolean mod_union)635 sgen_client_binary_protocol_major_card_table_scan_start (long long timestamp, gboolean mod_union)
636 {
637 }
638 
639 static void G_GNUC_UNUSED
sgen_client_binary_protocol_major_card_table_scan_end(long long timestamp,gboolean mod_union)640 sgen_client_binary_protocol_major_card_table_scan_end (long long timestamp, gboolean mod_union)
641 {
642 }
643 
644 static void G_GNUC_UNUSED
sgen_client_binary_protocol_los_card_table_scan_start(long long timestamp,gboolean mod_union)645 sgen_client_binary_protocol_los_card_table_scan_start (long long timestamp, gboolean mod_union)
646 {
647 }
648 
649 static void G_GNUC_UNUSED
sgen_client_binary_protocol_los_card_table_scan_end(long long timestamp,gboolean mod_union)650 sgen_client_binary_protocol_los_card_table_scan_end (long long timestamp, gboolean mod_union)
651 {
652 }
653 
654 static void G_GNUC_UNUSED
sgen_client_binary_protocol_finish_gray_stack_start(long long timestamp,int generation)655 sgen_client_binary_protocol_finish_gray_stack_start (long long timestamp, int generation)
656 {
657 }
658 
659 static void G_GNUC_UNUSED
sgen_client_binary_protocol_finish_gray_stack_end(long long timestamp,int generation)660 sgen_client_binary_protocol_finish_gray_stack_end (long long timestamp, int generation)
661 {
662 }
663 
664 static void G_GNUC_UNUSED
sgen_client_binary_protocol_worker_finish(long long timestamp,gboolean forced)665 sgen_client_binary_protocol_worker_finish (long long timestamp, gboolean forced)
666 {
667 }
668 
669 static void G_GNUC_UNUSED
sgen_client_binary_protocol_evacuating_blocks(size_t block_size)670 sgen_client_binary_protocol_evacuating_blocks (size_t block_size)
671 {
672 }
673 
674 static void G_GNUC_UNUSED
sgen_client_binary_protocol_concurrent_sweep_end(long long timestamp)675 sgen_client_binary_protocol_concurrent_sweep_end (long long timestamp)
676 {
677 }
678 
679 static void G_GNUC_UNUSED
sgen_client_binary_protocol_header(long long check,int version,int ptr_size,gboolean little_endian)680 sgen_client_binary_protocol_header (long long check, int version, int ptr_size, gboolean little_endian)
681 {
682 }
683 
684 static void G_GNUC_UNUSED
sgen_client_binary_protocol_pin_stats(int objects_pinned_in_nursery,size_t bytes_pinned_in_nursery,int objects_pinned_in_major,size_t bytes_pinned_in_major)685 sgen_client_binary_protocol_pin_stats (int objects_pinned_in_nursery, size_t bytes_pinned_in_nursery, int objects_pinned_in_major, size_t bytes_pinned_in_major)
686 {
687 }
688 
689 static void G_GNUC_UNUSED
sgen_client_binary_protocol_worker_finish_stats(int worker_index,int generation,gboolean forced,long long major_scan,long long los_scan,long long work_time)690 sgen_client_binary_protocol_worker_finish_stats (int worker_index, int generation, gboolean forced, long long major_scan, long long los_scan, long long work_time)
691 {
692 }
693 
694 static void G_GNUC_UNUSED
sgen_client_binary_protocol_collection_end_stats(long long major_scan,long long los_scan,long long finish_stack)695 sgen_client_binary_protocol_collection_end_stats (long long major_scan, long long los_scan, long long finish_stack)
696 {
697 }
698 
699 #define TLAB_ACCESS_INIT	SgenThreadInfo *__thread_info__ = (SgenThreadInfo*)mono_tls_get_sgen_thread_info ()
700 #define IN_CRITICAL_REGION (__thread_info__->client_info.in_critical_region)
701 
702 /* Enter must be visible before anything is done in the critical region. */
703 #define ENTER_CRITICAL_REGION do { mono_atomic_store_acquire (&IN_CRITICAL_REGION, 1); } while (0)
704 
705 /* Exit must make sure all critical regions stores are visible before it signal the end of the region.
706  * We don't need to emit a full barrier since we
707  */
708 #define EXIT_CRITICAL_REGION  do { mono_atomic_store_release (&IN_CRITICAL_REGION, 0); } while (0)
709 
710 #ifndef DISABLE_CRITICAL_REGION
711 /*
712  * We can only use a critical region in the managed allocator if the JIT supports OP_ATOMIC_STORE_I4.
713  *
714  * TODO: Query the JIT instead of this ifdef hack.
715  */
716 #if defined (TARGET_X86) || defined (TARGET_AMD64) || (defined (TARGET_ARM) && defined (HAVE_ARMV7)) || defined (TARGET_ARM64)
717 #define MANAGED_ALLOCATOR_CAN_USE_CRITICAL_REGION
718 #endif
719 #endif
720 
721 #define SGEN_TV_DECLARE(name) gint64 name
722 #define SGEN_TV_GETTIME(tv) tv = mono_100ns_ticks ()
723 #define SGEN_TV_ELAPSED(start,end) ((gint64)(end-start))
724 
725 guint64 mono_time_since_last_stw (void);
726 
727 typedef MonoSemType SgenSemaphore;
728 
729 #define SGEN_SEMAPHORE_INIT(sem,initial)	mono_os_sem_init ((sem), (initial))
730 #define SGEN_SEMAPHORE_POST(sem)		mono_os_sem_post ((sem))
731 #define SGEN_SEMAPHORE_WAIT(sem)		mono_os_sem_wait ((sem), MONO_SEM_FLAGS_NONE)
732 
733 gboolean sgen_has_critical_method (void);
734 gboolean sgen_is_critical_method (MonoMethod *method);
735 
736 void sgen_set_use_managed_allocator (gboolean flag);
737 gboolean sgen_is_managed_allocator (MonoMethod *method);
738 gboolean sgen_has_managed_allocator (void);
739 
740 void sgen_scan_for_registered_roots_in_domain (MonoDomain *domain, int root_type);
741 void sgen_null_links_for_domain (MonoDomain *domain);
742 
743 #endif
744