}
}
-#define CEMENT_THRESHOLD 1000
-#define CEMENT_HASH_SIZE 61
-
typedef struct _CementHashEntry CementHashEntry;
struct _CementHashEntry {
char *obj;
unsigned int count;
};
-static CementHashEntry cement_hash [CEMENT_HASH_SIZE];
-static CementHashEntry cement_hash_concurrent [CEMENT_HASH_SIZE];
+static CementHashEntry cement_hash [SGEN_CEMENT_HASH_SIZE];
+static CementHashEntry cement_hash_concurrent [SGEN_CEMENT_HASH_SIZE];
static gboolean cement_enabled = TRUE;
static gboolean cement_concurrent = FALSE;
gboolean
sgen_cement_lookup (char *obj)
{
- int i = mono_aligned_addr_hash (obj) % CEMENT_HASH_SIZE;
+ int i = mono_aligned_addr_hash (obj) % SGEN_CEMENT_HASH_SIZE;
SGEN_ASSERT (5, sgen_ptr_in_nursery (obj), "Looking up cementing for non-nursery objects makes no sense");
if (cement_hash [i].obj != obj)
return FALSE;
- return cement_hash [i].count >= CEMENT_THRESHOLD;
+ return cement_hash [i].count >= SGEN_CEMENT_THRESHOLD;
}
gboolean
-sgen_cement_lookup_or_register (char *obj, gboolean concurrent_cementing)
+sgen_cement_lookup_or_register (char *obj)
{
int i;
CementHashEntry *hash;
+ gboolean concurrent_cementing = sgen_concurrent_collection_in_progress ();
if (!cement_enabled)
return FALSE;
else
hash = cement_hash;
- i = mono_aligned_addr_hash (obj) % CEMENT_HASH_SIZE;
+ /*
+ * We use modulus hashing, which is fine with constants as gcc
+ * can optimize them to multiplication, but with variable
+ * values it would be a bad idea given armv7 has no hardware
+ * for division, making it 20x slower than a multiplication.
+ *
+ * This code path can be quite hot, depending on the workload,
+ * so if we make the hash size user-adjustable we should
+ * figure out something not involving division.
+ */
+ i = mono_aligned_addr_hash (obj) % SGEN_CEMENT_HASH_SIZE;
SGEN_ASSERT (5, sgen_ptr_in_nursery (obj), "Can only cement pointers to nursery objects");
return FALSE;
}
- if (hash [i].count >= CEMENT_THRESHOLD)
+ if (hash [i].count >= SGEN_CEMENT_THRESHOLD)
return TRUE;
++hash [i].count;
-#ifdef SGEN_BINARY_PROTOCOL
- if (hash [i].count == CEMENT_THRESHOLD) {
+ if (hash [i].count == SGEN_CEMENT_THRESHOLD) {
+ if (G_UNLIKELY (MONO_GC_OBJ_CEMENTED_ENABLED())) {
+ MonoVTable *vt G_GNUC_UNUSED = (MonoVTable*)SGEN_LOAD_VTABLE (obj);
+ MONO_GC_OBJ_CEMENTED ((mword)obj, sgen_safe_object_get_size ((MonoObject*)obj),
+ vt->klass->name_space, vt->klass->name);
+ }
binary_protocol_cement (obj, (gpointer)SGEN_LOAD_VTABLE (obj),
sgen_safe_object_get_size ((MonoObject*)obj));
}
-#endif
return FALSE;
}
sgen_cement_iterate (IterateObjectCallbackFunc callback, void *callback_data)
{
int i;
- for (i = 0; i < CEMENT_HASH_SIZE; ++i) {
+ for (i = 0; i < SGEN_CEMENT_HASH_SIZE; ++i) {
if (!cement_hash [i].count)
continue;
- SGEN_ASSERT (5, cement_hash [i].count >= CEMENT_THRESHOLD, "Cementing hash inconsistent");
+ SGEN_ASSERT (5, cement_hash [i].count >= SGEN_CEMENT_THRESHOLD, "Cementing hash inconsistent");
callback (cement_hash [i].obj, 0, callback_data);
}
sgen_cement_clear_below_threshold (void)
{
int i;
- for (i = 0; i < CEMENT_HASH_SIZE; ++i) {
- if (cement_hash [i].count < CEMENT_THRESHOLD) {
+ for (i = 0; i < SGEN_CEMENT_HASH_SIZE; ++i) {
+ if (cement_hash [i].count < SGEN_CEMENT_THRESHOLD) {
cement_hash [i].obj = NULL;
cement_hash [i].count = 0;
}