#include <stdint.h>
#include "mono/utils/mono-compiler.h"
#include "mono/utils/atomic.h"
-#include "mono/utils/mono-mutex.h"
+#include "mono/utils/mono-os-mutex.h"
+#include "mono/utils/mono-coop-mutex.h"
#include "mono/sgen/sgen-conf.h"
#include "mono/sgen/sgen-hash-table.h"
#include "mono/sgen/sgen-protocol.h"
+#include "mono/sgen/gc-internal-agnostic.h"
/* The method used to clear the nursery */
/* Clearing at nursery collections is the safest, but has bad interactions with caches.
#define LOCK_DECLARE(name) mono_mutex_t name
/* if changing LOCK_INIT to something that isn't idempotent, look at
its use in mono_gc_base_init in sgen-gc.c */
-#define LOCK_INIT(name) mono_mutex_init (&(name))
-#define LOCK_GC do { \
- MONO_TRY_BLOCKING \
- mono_mutex_lock (&gc_mutex); \
- MONO_FINISH_TRY_BLOCKING \
- } while (0)
+#define LOCK_INIT(name) mono_os_mutex_init (&(name))
+#define LOCK_GC do { sgen_gc_lock (); } while (0)
#define UNLOCK_GC do { sgen_gc_unlock (); } while (0)
-extern LOCK_DECLARE (sgen_interruption_mutex);
-
-#define LOCK_INTERRUPTION do { \
- MONO_TRY_BLOCKING \
- mono_mutex_lock (&sgen_interruption_mutex); \
- MONO_FINISH_TRY_BLOCKING \
-} while (0)
+extern MonoCoopMutex sgen_interruption_mutex;
-#define UNLOCK_INTERRUPTION mono_mutex_unlock (&sgen_interruption_mutex)
+#define LOCK_INTERRUPTION mono_coop_mutex_lock (&sgen_interruption_mutex)
+#define UNLOCK_INTERRUPTION mono_coop_mutex_unlock (&sgen_interruption_mutex)
/* FIXME: Use InterlockedAdd & InterlockedAdd64 to reduce the CAS cost. */
#define SGEN_CAS InterlockedCompareExchange
return GPOINTER_TO_UINT (ptr) >> 3;
}
-/*
- * The link pointer is hidden by negating each bit. We use the lowest
- * bit of the link (before negation) to store whether it needs
- * resurrection tracking.
- */
-#define HIDE_POINTER(p,t) ((gpointer)(~((size_t)(p)|((t)?1:0))))
-#define REVEAL_POINTER(p) ((gpointer)((~(size_t)(p))&~3L))
-
#define SGEN_PTR_IN_NURSERY(p,bits,start,end) (((mword)(p) & ~((1 << (bits)) - 1)) == (mword)(start))
#ifdef USER_CONFIG
#define SGEN_POINTER_UNTAG_VTABLE(p) SGEN_POINTER_UNTAG_ALL((p))
/* returns NULL if not forwarded, or the forwarded address */
-#define SGEN_VTABLE_IS_FORWARDED(vtable) (SGEN_POINTER_IS_TAGGED_FORWARDED ((vtable)) ? SGEN_POINTER_UNTAG_VTABLE ((vtable)) : NULL)
-#define SGEN_OBJECT_IS_FORWARDED(obj) (SGEN_VTABLE_IS_FORWARDED (((mword*)(obj))[0]))
+#define SGEN_VTABLE_IS_FORWARDED(vtable) ((GCVTable *)(SGEN_POINTER_IS_TAGGED_FORWARDED ((vtable)) ? SGEN_POINTER_UNTAG_VTABLE ((vtable)) : NULL))
+#define SGEN_OBJECT_IS_FORWARDED(obj) ((GCObject *)SGEN_VTABLE_IS_FORWARDED (((mword*)(obj))[0]))
#define SGEN_VTABLE_IS_PINNED(vtable) SGEN_POINTER_IS_TAGGED_PINNED ((vtable))
#define SGEN_OBJECT_IS_PINNED(obj) (SGEN_VTABLE_IS_PINNED (((mword*)(obj))[0]))
* Since we set bits in the vtable, use the macro to load it from the pointer to
* an object that is potentially pinned.
*/
-#define SGEN_LOAD_VTABLE(obj) ((GCVTable)(SGEN_POINTER_UNTAG_ALL (SGEN_LOAD_VTABLE_UNCHECKED ((obj)))))
+#define SGEN_LOAD_VTABLE(obj) ((GCVTable)(SGEN_POINTER_UNTAG_ALL (SGEN_LOAD_VTABLE_UNCHECKED ((GCObject *)(obj)))))
/*
List of what each bit on of the vtable gc bits means.
typedef void (*CopyOrMarkObjectFunc) (GCObject**, SgenGrayQueue*);
typedef void (*ScanObjectFunc) (GCObject *obj, SgenDescriptor desc, SgenGrayQueue*);
typedef void (*ScanVTypeFunc) (GCObject *full_object, char *start, SgenDescriptor desc, SgenGrayQueue* BINARY_PROTOCOL_ARG (size_t size));
+typedef gboolean (*DrainGrayStackFunc) (SgenGrayQueue *queue);
typedef struct {
CopyOrMarkObjectFunc copy_or_mark_object;
ScanObjectFunc scan_object;
ScanVTypeFunc scan_vtype;
+ /* Drain stack optimized for the above functions */
+ DrainGrayStackFunc drain_gray_stack;
/*FIXME add allocation function? */
} SgenObjectOperations;
void sgen_pin_stats_print_class_stats (void);
void sgen_sort_addresses (void **array, size_t size);
-void sgen_add_to_global_remset (gpointer ptr, gpointer obj);
+void sgen_add_to_global_remset (gpointer ptr, GCObject *obj);
int sgen_get_current_collection_generation (void);
gboolean sgen_collection_is_concurrent (void);
gboolean supports_cardtable;
gboolean sweeps_lazily;
- /*
- * This is set to TRUE by the sweep if the next major
- * collection should be synchronous (for evacuation). For
- * non-concurrent collectors, this should be NULL.
- */
- gboolean *want_synchronous_collection;
-
void* (*alloc_heap) (mword nursery_size, mword nursery_align, int nursery_bits);
gboolean (*is_object_live) (GCObject *obj);
GCObject* (*alloc_small_pinned_obj) (GCVTable vtable, size_t size, gboolean has_references);
SgenObjectOperations major_ops_serial;
SgenObjectOperations major_ops_concurrent_start;
- SgenObjectOperations major_ops_concurrent;
SgenObjectOperations major_ops_concurrent_finish;
GCObject* (*alloc_object) (GCVTable vtable, size_t size, gboolean has_references);
void (*finish_nursery_collection) (void);
void (*start_major_collection) (void);
void (*finish_major_collection) (ScannedObjectCounts *counts);
- gboolean (*drain_gray_stack) (ScanCopyContext ctx);
gboolean (*ptr_is_in_non_pinned_space) (char *ptr, char **start);
gboolean (*ptr_is_from_pinned_alloc) (char *ptr);
void (*report_pinned_memory_usage) (void);
typedef gboolean (*SgenObjectPredicateFunc) (GCObject *obj, void *user_data);
-void sgen_null_links_if (SgenObjectPredicateFunc predicate, void *data, int generation);
+void sgen_null_links_if (SgenObjectPredicateFunc predicate, void *data, int generation, gboolean track);
gboolean sgen_gc_is_object_ready_for_finalization (GCObject *object);
void sgen_gc_lock (void);
const char* sgen_generation_name (int generation);
void sgen_finalize_in_range (int generation, ScanCopyContext ctx);
-void sgen_null_link_in_range (int generation, gboolean before_finalization, ScanCopyContext ctx);
+void sgen_null_link_in_range (int generation, ScanCopyContext ctx, gboolean track);
void sgen_process_fin_stage_entries (void);
gboolean sgen_have_pending_finalizers (void);
void sgen_object_register_for_finalization (GCObject *obj, void *user_data);
int sgen_gather_finalizers_if (SgenObjectPredicateFunc predicate, void *user_data, GCObject **out_array, int out_size);
void sgen_remove_finalizers_if (SgenObjectPredicateFunc predicate, void *user_data, int generation);
-void sgen_process_dislink_stage_entries (void);
void sgen_register_disappearing_link (GCObject *obj, void **link, gboolean track, gboolean in_gc);
GCObject* sgen_weak_link_get (void **link_addr);
-gboolean sgen_drain_gray_stack (int max_objs, ScanCopyContext ctx);
+gboolean sgen_drain_gray_stack (ScanCopyContext ctx);
enum {
SPACE_NURSERY,
int sgen_gc_invoke_finalizers (void);
+/* GC handles */
+
+void sgen_init_gchandles (void);
+
+void sgen_null_links_if (SgenObjectPredicateFunc predicate, void *data, int generation, gboolean track);
+
+typedef gpointer (*SgenGCHandleIterateCallback) (gpointer hidden, GCHandleType handle_type, int max_generation, gpointer user);
+
+void sgen_gchandle_iterate (GCHandleType handle_type, int max_generation, SgenGCHandleIterateCallback callback, gpointer user);
+void sgen_gchandle_set_target (guint32 gchandle, GCObject *obj);
+void sgen_mark_normal_gc_handles (void *addr, SgenUserMarkFunc mark_func, void *gc_data);
+gpointer sgen_gchandle_get_metadata (guint32 gchandle);
+
/* Other globals */
extern GCMemSection *nursery_section;
extern NurseryClearPolicy nursery_clear_policy;
extern gboolean sgen_try_free_some_memory;
-extern LOCK_DECLARE (gc_mutex);
+extern MonoCoopMutex gc_mutex;
/* Nursery helpers. */
void sgen_debug_verify_nursery (gboolean do_dump_nursery_content);
void sgen_debug_check_nursery_is_clean (void);
-/* Write barrier support */
-
-/*
- * This causes the compile to extend the liveness of 'v' till the call to dummy_use
- */
-static inline void
-sgen_dummy_use (gpointer v) {
-#if defined(__GNUC__)
- __asm__ volatile ("" : "=r"(v) : "r"(v));
-#elif defined(_MSC_VER)
- static volatile gpointer ptr;
- ptr = v;
-#else
-#error "Implement sgen_dummy_use for your compiler"
-#endif
-}
-
/* Environment variable parsing */
#define MONO_GC_PARAMS_NAME "MONO_GC_PARAMS"
g_warning ("CORRUPT CANARY:\naddr->%p\ntype->%s\nexcepted->'%s'\nfound->'%s'\n", (char*) addr, sgen_client_vtable_get_name (SGEN_LOAD_VTABLE ((addr))), CANARY_STRING, canary_copy); \
} }
+/*
+ * This causes the compile to extend the liveness of 'v' till the call to dummy_use
+ */
+static inline void
+sgen_dummy_use (gpointer v)
+{
+#if defined(__GNUC__)
+ __asm__ volatile ("" : "=r"(v) : "r"(v));
+#elif defined(_MSC_VER)
+ static volatile gpointer ptr;
+ ptr = v;
+#else
+#error "Implement sgen_dummy_use for your compiler"
+#endif
+}
+
#endif /* HAVE_SGEN_GC */
#endif /* __MONO_SGENGC_H__ */