* Copyright 2011 Xamarin, Inc.
* Copyright (C) 2012 Xamarin Inc
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License 2.0 as published by the Free Software Foundation;
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License 2.0 along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
/*
static __thread char *tlab_real_end;
/* Used by the managed allocator/wbarrier */
static __thread char **tlab_next_addr MONO_ATTR_USED;
+#ifndef SGEN_WITHOUT_MONO
+static __thread volatile int *in_critical_region_addr MONO_ATTR_USED;
+#endif
#endif
#ifdef HAVE_KW_THREAD
#define TLAB_REAL_END (__thread_info__->tlab_real_end)
#endif
-static void*
+static GCObject*
alloc_degraded (GCVTable vtable, size_t size, gboolean for_mature)
{
- void *p;
+ GCObject *p;
if (!for_mature) {
sgen_client_degraded_allocation (size);
SGEN_ATOMIC_ADD_P (degraded_mode, size);
- sgen_ensure_free_space (size);
+ sgen_ensure_free_space (size, GENERATION_OLD);
} else {
if (sgen_need_major_collection (size))
sgen_perform_collection (size, GENERATION_OLD, "mature allocation failure", !for_mature);
* so when we scan the thread stacks for pinned objects, we can start
* a search for the pinned object in SGEN_SCAN_START_SIZE chunks.
*/
-void*
+GCObject*
sgen_alloc_obj_nolock (GCVTable vtable, size_t size)
{
/* FIXME: handle OOM */
*/
if (real_size > SGEN_MAX_SMALL_OBJ_SIZE) {
- p = sgen_los_alloc_large_inner (vtable, ALIGN_UP (real_size));
+ p = (void **)sgen_los_alloc_large_inner (vtable, ALIGN_UP (real_size));
} else {
/* tlab_next and tlab_temp_end are TLS vars so accessing them might be expensive */
if (G_LIKELY (new_next < TLAB_TEMP_END)) {
/* Fast path */
- /*
- * FIXME: We might need a memory barrier here so the change to tlab_next is
- * visible before the vtable store.
- */
-
CANARIFY_ALLOC(p,real_size);
SGEN_LOG (6, "Allocated object %p, vtable: %p (%s), size: %zd", p, vtable, sgen_client_vtable_get_name (vtable), size);
binary_protocol_alloc (p , vtable, size, sgen_client_get_provenance ());
g_assert (*p == NULL);
mono_atomic_store_seq (p, vtable);
- return p;
+ return (GCObject*)p;
}
/* Slow path */
available_in_tlab = (int)(TLAB_REAL_END - TLAB_NEXT);//We'll never have tlabs > 2Gb
if (size > tlab_size || available_in_tlab > SGEN_MAX_NURSERY_WASTE) {
/* Allocate directly from the nursery */
- p = sgen_nursery_alloc (size);
+ p = (void **)sgen_nursery_alloc (size);
if (!p) {
/*
* We couldn't allocate from the nursery, so we try
* always loop we will loop endlessly in the case of
* OOM).
*/
- sgen_ensure_free_space (real_size);
+ sgen_ensure_free_space (real_size, GENERATION_NURSERY);
if (!degraded_mode)
- p = sgen_nursery_alloc (size);
+ p = (void **)sgen_nursery_alloc (size);
}
if (!p)
return alloc_degraded (vtable, size, FALSE);
SGEN_LOG (3, "Retire TLAB: %p-%p [%ld]", TLAB_START, TLAB_REAL_END, (long)(TLAB_REAL_END - TLAB_NEXT - size));
sgen_nursery_retire_region (p, available_in_tlab);
- p = sgen_nursery_alloc_range (tlab_size, size, &alloc_size);
+ p = (void **)sgen_nursery_alloc_range (tlab_size, size, &alloc_size);
if (!p) {
/* See comment above in similar case. */
- sgen_ensure_free_space (tlab_size);
+ sgen_ensure_free_space (tlab_size, GENERATION_NURSERY);
if (!degraded_mode)
- p = sgen_nursery_alloc_range (tlab_size, size, &alloc_size);
+ p = (void **)sgen_nursery_alloc_range (tlab_size, size, &alloc_size);
}
if (!p)
return alloc_degraded (vtable, size, FALSE);
zero_tlab_if_necessary (TLAB_START, alloc_size);
/* Allocate from the TLAB */
- p = (void*)TLAB_NEXT;
+ p = (void **)TLAB_NEXT;
TLAB_NEXT += size;
sgen_set_nursery_scan_start ((char*)p);
}
mono_atomic_store_seq (p, vtable);
}
- return p;
+ return (GCObject*)p;
}
-void*
+GCObject*
sgen_try_alloc_obj_nolock (GCVTable vtable, size_t size)
{
void **p;
if (G_UNLIKELY (size > tlab_size)) {
/* Allocate directly from the nursery */
- p = sgen_nursery_alloc (size);
+ p = (void **)sgen_nursery_alloc (size);
if (!p)
return NULL;
sgen_set_nursery_scan_start ((char*)p);
}
} else if (available_in_tlab > SGEN_MAX_NURSERY_WASTE) {
/* Allocate directly from the nursery */
- p = sgen_nursery_alloc (size);
+ p = (void **)sgen_nursery_alloc (size);
if (!p)
return NULL;
size_t alloc_size = 0;
sgen_nursery_retire_region (p, available_in_tlab);
- new_next = sgen_nursery_alloc_range (tlab_size, size, &alloc_size);
+ new_next = (char *)sgen_nursery_alloc_range (tlab_size, size, &alloc_size);
p = (void**)new_next;
if (!p)
return NULL;
mono_atomic_store_seq (p, vtable);
- return p;
+ return (GCObject*)p;
}
-void*
+GCObject*
sgen_alloc_obj (GCVTable vtable, size_t size)
{
- void *res;
+ GCObject *res;
TLAB_ACCESS_INIT;
if (!SGEN_CAN_ALIGN_UP (size))
return NULL;
-#ifndef DISABLE_CRITICAL_REGION
-
if (G_UNLIKELY (has_per_allocation_action)) {
static int alloc_count;
int current_alloc = InterlockedIncrement (&alloc_count);
return res;
}
EXIT_CRITICAL_REGION;
-#endif
+
LOCK_GC;
res = sgen_alloc_obj_nolock (vtable, size);
UNLOCK_GC;
- if (G_UNLIKELY (!res))
- sgen_client_out_of_memory (size);
return res;
}
* To be used for interned strings and possibly MonoThread, reflection handles.
* We may want to explicitly free these objects.
*/
-void*
+GCObject*
sgen_alloc_obj_pinned (GCVTable vtable, size_t size)
{
- void **p;
+ GCObject *p;
if (!SGEN_CAN_ALIGN_UP (size))
return NULL;
if (size > SGEN_MAX_SMALL_OBJ_SIZE) {
/* large objects are always pinned anyway */
- p = sgen_los_alloc_large_inner (vtable, size);
+ p = (GCObject *)sgen_los_alloc_large_inner (vtable, size);
} else {
SGEN_ASSERT (9, sgen_client_vtable_is_inited (vtable), "class %s:%s is not initialized", sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable));
p = major_collector.alloc_small_pinned_obj (vtable, size, SGEN_VTABLE_HAS_REFERENCES (vtable));
return p;
}
-void*
+GCObject*
sgen_alloc_obj_mature (GCVTable vtable, size_t size)
{
- void *res;
+ GCObject *res;
if (!SGEN_CAN_ALIGN_UP (size))
return NULL;
#ifdef HAVE_KW_THREAD
tlab_next_addr = &tlab_next;
+#ifndef SGEN_WITHOUT_MONO
+ in_critical_region_addr = &info->client_info.in_critical_region;
+#endif
#endif
}
void
sgen_clear_tlabs (void)
{
- SgenThreadInfo *info;
-
FOREACH_THREAD (info) {
/* A new TLAB will be allocated when the thread does its first allocation */
*info->tlab_start_addr = NULL;
*info->tlab_next_addr = NULL;
*info->tlab_temp_end_addr = NULL;
*info->tlab_real_end_addr = NULL;
- } END_FOREACH_THREAD
+ } FOREACH_THREAD_END
}
void
#if defined(HAVE_KW_THREAD) && !defined(SGEN_WITHOUT_MONO)
int tlab_next_addr_offset = -1;
int tlab_temp_end_offset = -1;
-
+ int in_critical_region_addr_offset = -1;
MONO_THREAD_VAR_OFFSET (tlab_next_addr, tlab_next_addr_offset);
MONO_THREAD_VAR_OFFSET (tlab_temp_end, tlab_temp_end_offset);
+ MONO_THREAD_VAR_OFFSET (in_critical_region_addr, in_critical_region_addr_offset);
mono_tls_key_set_offset (TLS_KEY_SGEN_TLAB_NEXT_ADDR, tlab_next_addr_offset);
mono_tls_key_set_offset (TLS_KEY_SGEN_TLAB_TEMP_END, tlab_temp_end_offset);
-
- g_assert (tlab_next_addr_offset != -1);
- g_assert (tlab_temp_end_offset != -1);
+ mono_tls_key_set_offset (TLS_KEY_SGEN_IN_CRITICAL_REGION_ADDR, in_critical_region_addr_offset);
#endif
#ifdef HEAVY_STATISTICS