*
* Authors:
* - Ludovic Henry <ludovic@xamarin.com>
+ * - Aleksey Klieger <aleksey.klieger@xamarin.com>
+ * - Rodrigo Kumpera <kumpera@xamarin.com>
*
- * Copyright 2015 Xamarin, Inc. (www.xamarin.com)
+ * Copyright 2016 Dot net foundation.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <mono/metadata/gc-internals.h>
#include <mono/utils/atomic.h>
#include <mono/utils/mono-lazy-init.h>
+#include <mono/utils/mono-threads.h>
+/* TODO (missing pieces)
-#define HANDLES_PER_CHUNK (16 - 2)
+Add counters for:
+ number of stack marks
+ stack marks per icall
+ mix/max/avg size of stack marks
+ handle stack wastage
-typedef struct _MonoHandleArenaChunk MonoHandleArenaChunk;
-struct _MonoHandleArenaChunk {
- MonoHandleArenaChunk *next;
- gsize handles_size;
- MonoHandleStorage handles [HANDLES_PER_CHUNK];
-};
+Actually do something in mono_handle_verify
-struct _MonoHandleArena {
- MonoHandleArenaChunk *chunk;
- MonoHandleArenaChunk *chunk_last;
- MonoHandleArena *prev;
-};
+Shrink the handles stack in mono_handle_stack_scan
+Properly report it to the profiler.
+Add a boehm implementation
-static mono_lazy_init_t arena_status = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
+TODO (things to explore):
-#ifdef HAVE_SGEN_GC
-static MonoGCDescriptor arena_desc = MONO_GC_DESCRIPTOR_NULL;
-#endif
-
-static MonoHandleArenaChunk *chunk_free_list = NULL;
-
-static inline MonoHandleArenaChunk*
-chunk_alloc (void)
-{
- MonoHandleArenaChunk *old, *new;
+There's no convenient way to wrap the object allocation function.
+Right now we do this:
+ MonoCultureInfoHandle culture = MONO_HANDLE_NEW (MonoCultureInfo, mono_object_new_checked (domain, klass, &error));
- do {
- old = chunk_free_list;
- if (!old) {
- MonoHandleArenaChunk *chunk;
+Maybe what we need is a round of cleanup around all exposed types in the runtime to unify all helpers under the same hoof.
+Combine: MonoDefaults, GENERATE_GET_CLASS_WITH_CACHE, TYPED_HANDLE_DECL and friends.
+ This would solve the age old issue of making it clear which types are optional and tell that to the linker.
+ We could then generate neat type safe wrappers.
+*/
- chunk = g_malloc0 (sizeof (MonoHandleArenaChunk));
- g_assert (chunk);
+const MonoObjectHandle mono_null_value_handle = NULL;
- return chunk;
- }
-
- new = old->next;
- } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, new, old) != old);
-
- memset (old, 0, sizeof (MonoHandleArenaChunk));
- return old;
-}
+#define THIS_IS_AN_OK_NUMBER_OF_HANDLES 100
-static inline void
-chunk_free (MonoHandleArenaChunk *chunk)
+/* Actual handles implementation */
+MonoRawHandle
+mono_handle_new (MonoObject *object)
{
- do {
- chunk->next = chunk_free_list;
- } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, chunk, chunk->next) != chunk->next);
-}
-
-static MonoHandle
-handle_new (MonoHandleArena *arena, MonoObject *obj)
-{
- MonoHandleArenaChunk *chunk;
-
- g_assert (arena->chunk);
- g_assert (arena->chunk_last);
-
- chunk = arena->chunk_last;
-
- if (chunk->handles_size < HANDLES_PER_CHUNK) {
- chunk->handles [chunk->handles_size].obj = obj;
- chunk->handles_size += 1;
-
- return &chunk->handles [chunk->handles_size - 1];
+ MonoThreadInfo *info = mono_thread_info_current ();
+ HandleStack *handles = (HandleStack *)info->handle_stack;
+ HandleChunk *top = handles->top;
+
+retry:
+ if (G_LIKELY (top->size < OBJECTS_PER_HANDLES_CHUNK)) {
+ MonoObject **h = &top->objects [top->size++];
+ *h = object;
+ return h;
}
-
- chunk = chunk->next = chunk_alloc ();
-
- chunk->handles [0].obj = obj;
- chunk->handles_size = 1;
-
- arena->chunk_last = chunk;
-
- return &chunk->handles [0];
+ if (G_LIKELY (top->next)) {
+ top = top->next;
+ top->size = 0;
+ handles->top = top;
+ goto retry;
+ }
+ HandleChunk *new_chunk = g_new (HandleChunk, 1);
+ new_chunk->size = 0;
+ new_chunk->prev = top;
+ new_chunk->next = NULL;
+ top->next = new_chunk;
+ handles->top = new_chunk;
+ goto retry;
}
-MonoHandle
-mono_handle_arena_new (MonoHandleArena *arena, MonoObject *obj)
-{
- g_assert (arena);
- return handle_new (arena, obj);
-}
-MonoHandle
-mono_handle_new (MonoObject *obj)
-{
- /* TODO: finish implementation by placing an arena somewhere
- * in the current thread */
- g_assert_not_reached ();
- MonoHandleArena *arena = NULL;
- return mono_handle_arena_new (arena, obj);
-}
-/*
- * Elevate the handle to the parent arena
- */
-MonoHandle
-mono_handle_arena_elevate (MonoHandleArena *arena, MonoHandle handle)
+HandleStack*
+mono_handle_stack_alloc (void)
{
- g_assert (handle);
- g_assert (arena);
- g_assert (arena->prev);
+ HandleStack *stack = g_new (HandleStack, 1);
+ HandleChunk *chunk = g_new (HandleChunk, 1);
- return handle_new (arena->prev, handle->obj);
+ stack->top = stack->bottom = chunk;
+ chunk->size = 0;
+ chunk->prev = chunk->next = NULL;
+ return stack;
}
-MonoHandle
-mono_handle_elevate (MonoHandle handle)
-{
- /* TODO: finish implementation by placing an arena somewhere
- * in the current thread */
- g_assert_not_reached ();
- MonoHandleArena *arena = NULL;
- return mono_handle_arena_elevate (arena, handle);
-}
-
-gsize
-mono_handle_arena_size (void)
+void
+mono_handle_stack_free (HandleStack *stack)
{
- return sizeof (MonoHandleArena) + sizeof (MonoHandleArenaChunk);
+ if (!stack)
+ return;
+ HandleChunk *c = stack->bottom;
+ while (c) {
+ HandleChunk *next = c->next;
+ g_free (c);
+ c = next;
+ }
+ g_free (c);
+ g_free (stack);
}
void
-mono_handle_arena_stack_push(MonoHandleArena **arena_stack, MonoHandleArena *arena)
+mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data)
{
- g_assert (arena_stack);
- g_assert (arena);
-
- arena->prev = *arena_stack;
- arena->chunk = arena->chunk_last = (MonoHandleArenaChunk*) (((char*) arena) + sizeof (MonoHandleArena));
-
- arena->chunk->next = NULL;
- arena->chunk->handles_size = 0;
- memset (&arena->chunk->handles [0], 0, sizeof (MonoHandleStorage) * HANDLES_PER_CHUNK);
-
- *arena_stack = arena;
+ HandleChunk *cur = stack->bottom;
+ HandleChunk *last = stack->top;
+
+ if (!cur)
+ return;
+
+ while (cur) {
+ int i;
+ for (i = 0; i < cur->size; ++i)
+ func ((gpointer*)&cur->objects [i], gc_data);
+ if (cur == last)
+ break;
+ cur = cur->next;
+ }
}
void
-mono_handle_arena_stack_pop(MonoHandleArena **arena_stack, MonoHandleArena *arena)
+mono_stack_mark_record_size (MonoThreadInfo *info, HandleStackMark *stackmark, const char *func_name)
{
- MonoHandleArenaChunk *chunk, *next;
-
- g_assert (arena);
- g_assert (arena->chunk);
- g_assert (arena->chunk_last);
- g_assert (arena_stack);
-
- *arena_stack = arena->prev;
-
- for (chunk = arena->chunk; chunk; chunk = next) {
- next = chunk->next;
- memset (&chunk->handles [0], 0, sizeof (MonoHandleStorage) * HANDLES_PER_CHUNK);
- if (chunk != arena->chunk)
- chunk_free (chunk);
+ HandleStack *handles = (HandleStack *)info->handle_stack;
+ HandleChunk *cur = stackmark->chunk;
+ int size = -stackmark->size; //discard the starting point of the stack
+ while (cur) {
+ size += cur->size;
+ if (cur == handles->top)
+ break;
+ cur = cur->next;
}
+
+ if (size > THIS_IS_AN_OK_NUMBER_OF_HANDLES)
+ printf ("%s USED %d handles\n", func_name, size);
}
-static void
-arena_scan (gpointer addr, MonoGCMarkFunc mark_func, gpointer gc_data)
+/*
+ * Pop the stack until @stackmark and make @value the top value.
+ *
+ * @return the new handle for what @value points to
+ */
+MonoRawHandle
+mono_stack_mark_pop_value (MonoThreadInfo *info, HandleStackMark *stackmark, MonoRawHandle value)
{
- MonoHandleArena *arena;
- MonoHandleArenaChunk *chunk;
- int i;
-
- for (arena = *(MonoHandleArena**) addr; arena; arena = arena->prev) {
- for (chunk = arena->chunk; chunk; chunk = chunk->next) {
- for (i = 0; i < chunk->handles_size; ++i) {
- if (chunk->handles [i].obj != NULL)
- mark_func (&chunk->handles [i].obj, gc_data);
- }
- }
- }
+ g_error ("impl me");
}
-static void
-initialize (void)
+/* Temporary place for some of the handle enabled wrapper functions*/
+
+MonoStringHandle
+mono_string_new_handle (MonoDomain *domain, const char *data, MonoError *error)
{
-#ifdef HAVE_SGEN_GC
- arena_desc = mono_gc_make_root_descr_user (arena_scan);
-#endif
+ return MONO_HANDLE_NEW (MonoString, mono_string_new_checked (domain, data, error));
}
-void
-mono_handle_arena_initialize (MonoHandleArena **arena_stack)
+MonoArrayHandle
+mono_array_new_handle (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
{
-#ifdef HAVE_SGEN_GC
- mono_lazy_initialize (&arena_status, initialize);
- mono_gc_register_root ((char*) arena_stack, sizeof (MonoHandleArena*), arena_desc, MONO_ROOT_SOURCE_HANDLE, "runtime threads handle arena");
-#endif
+ return MONO_HANDLE_NEW (MonoArray, mono_array_new_checked (domain, eclass, n, error));
}
+#ifdef ENABLE_CHECKED_BUILD
+/* Checked build helpers */
void
-mono_handle_arena_deinitialize (MonoHandleArena **arena_stack)
+mono_handle_verify (MonoRawHandle raw_handle)
{
-#ifdef HAVE_SGEN_GC
- mono_gc_deregister_root ((char*) arena_stack);
-#endif
+
}
-
+#endif