*
* 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.
*/
#ifndef __MONO_HANDLE_H__
#include <mono/metadata/object.h>
#include <mono/metadata/class.h>
-#include <mono/utils/mono-error.h>
+#include <mono/utils/mono-error-internals.h>
+#include <mono/utils/mono-threads.h>
#include <mono/utils/checked-build.h>
G_BEGIN_DECLS
-/*
- * DO NOT ACCESS DIRECTLY
- * USE mono_handle_obj BELOW TO ACCESS OBJ
- *
- * The field obj is not private as there is no way to do that
- * in C, but using a C++ template would simplify that a lot
- */
-typedef struct {
- MonoObject *__private_obj;
-} MonoHandleStorage;
-typedef MonoHandleStorage* MonoHandle;
+/*
+Handle stack.
-typedef struct _MonoHandleArena MonoHandleArena;
+The handle stack is designed so it's efficient to pop a large amount of entries at once.
+The stack is made out of a series of fixed size segments.
-gsize
-mono_handle_arena_size (void);
+To do bulk operations you use a stack mark.
+
+*/
-MonoHandle
-mono_handle_arena_new (MonoHandleArena *arena, MonoObject *obj);
+/*
+3 is the number of fields besides the data in the struct;
+128 words makes each chunk 512 or 1024 bytes each
+*/
+#define OBJECTS_PER_HANDLES_CHUNK (128 - 3)
-MonoHandle
-mono_handle_arena_elevate (MonoHandleArena *arena, MonoHandle handle);
+/*
+Whether this config needs stack watermark recording to know where to start scanning from.
+*/
+#ifdef HOST_WATCHOS
+#define MONO_NEEDS_STACK_WATERMARK 1
+#endif
-void
-mono_handle_arena_stack_push (MonoHandleArena **arena_stack, MonoHandleArena *arena);
+typedef struct _HandleChunk HandleChunk;
-void
-mono_handle_arena_stack_pop (MonoHandleArena **arena_stack, MonoHandleArena *arena);
+struct _HandleChunk {
+ int size; //number of bytes
+ HandleChunk *prev, *next;
+ MonoObject *objects [OBJECTS_PER_HANDLES_CHUNK];
+};
-void
-mono_handle_arena_init (MonoHandleArena **arena_stack);
+typedef struct {
+ HandleChunk *top; //alloc from here
+ HandleChunk *bottom; //scan from here
+} HandleStack;
-void
-mono_handle_arena_cleanup (MonoHandleArena **arena_stack);
+typedef struct {
+ int size;
+ HandleChunk *chunk;
+} HandleStackMark;
-MonoHandleArena*
-mono_handle_arena_current (void);
+typedef void *MonoRawHandle;
-MonoHandleArena**
-mono_handle_arena_current_addr (void);
+typedef void (*GcScanFunc) (gpointer*, gpointer);
-#define MONO_HANDLE_ARENA_PUSH() \
- do { \
- MonoHandleArena **__arena_stack = mono_handle_arena_current_addr (); \
- MonoHandleArena *__arena = (MonoHandleArena*) g_alloca (mono_handle_arena_size ()); \
- mono_handle_arena_stack_push (__arena_stack, __arena)
-#define MONO_HANDLE_ARENA_POP() \
- mono_handle_arena_stack_pop (__arena_stack, __arena); \
- } while (0)
+MonoRawHandle mono_handle_new (MonoObject *object);
-#define MONO_HANDLE_ARENA_POP_RETURN_UNSAFE(handle,ret) \
- (ret) = (handle)->__private_obj; \
- mono_handle_arena_stack_pop (__arena_stack, __arena); \
- } while (0)
+void mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data);
+HandleStack* mono_handle_stack_alloc (void);
+void mono_handle_stack_free (HandleStack *handlestack);
+MonoRawHandle mono_stack_mark_pop_value (MonoThreadInfo *info, HandleStackMark *stackmark, MonoRawHandle value);
+void mono_stack_mark_record_size (MonoThreadInfo *info, HandleStackMark *stackmark, const char *func_name);
-#define MONO_HANDLE_ARENA_POP_RETURN(handle,ret_handle) \
- *((MonoHandle**)(&(ret_handle))) = mono_handle_elevate ((MonoHandle*)(handle)); \
- mono_handle_arena_stack_pop(__arena_stack, __arena); \
- } while (0)
-
-static inline MonoHandle
-mono_handle_new (MonoObject *obj)
+static inline void
+mono_stack_mark_init (MonoThreadInfo *info, HandleStackMark *stackmark)
{
- return mono_handle_arena_new (mono_handle_arena_current (), obj);
+ HandleStack *handles = (HandleStack *)info->handle_stack;
+ stackmark->size = handles->top->size;
+ stackmark->chunk = handles->top;
}
-static inline MonoHandle
-mono_handle_elevate (MonoHandle handle)
+static inline void
+mono_stack_mark_pop (MonoThreadInfo *info, HandleStackMark *stackmark)
{
- return mono_handle_arena_elevate (mono_handle_arena_current (), handle);
+ HandleStack *handles = (HandleStack *)info->handle_stack;
+ handles->top->size = stackmark->size;
+ mono_memory_write_barrier ();
+ handles->top = stackmark->chunk;
}
-#ifndef CHECKED_BUILD
+/*
+Icall macros
+*/
+#define SETUP_ICALL_COMMON \
+ do { \
+ MonoError error; \
+ MonoThreadInfo *__info = mono_thread_info_current (); \
+ error_init (&error); \
-#define mono_handle_obj(handle) ((handle)->__private_obj)
+#define CLEAR_ICALL_COMMON \
+ mono_error_set_pending_exception (&error);
-#define mono_handle_assign(handle,rawptr) do { (handle)->__private_obj = (rawptr); } while(0)
+#define SETUP_ICALL_FRAME \
+ HandleStackMark __mark; \
+ mono_stack_mark_init (__info, &__mark);
-#else
+#define CLEAR_ICALL_FRAME \
+ mono_stack_mark_record_size (__info, &__mark, __FUNCTION__); \
+ mono_stack_mark_pop (__info, &__mark);
-static inline void
-mono_handle_check_in_critical_section ()
+#ifdef MONO_NEEDS_STACK_WATERMARK
+
+static void
+mono_thread_info_pop_stack_mark (MonoThreadInfo *info, void *old_mark)
{
- MONO_REQ_GC_CRITICAL;
+ info->stack_mark = old_mark;
}
-#define mono_handle_obj(handle) (mono_handle_check_in_critical_section (), (handle)->__private_obj)
+static void*
+mono_thread_info_push_stack_mark (MonoThreadInfo *info, void *mark)
+{
+ void *old = info->stack_mark;
+ info->stack_mark = mark;
+ return old;
+}
-#define mono_handle_assign(handle,rawptr) do { mono_handle_check_in_critical_section (); (handle)->__private_obj = (rawptr); } while (0)
+#define SETUP_STACK_WATERMARK \
+ int __dummy; \
+ __builtin_unwind_init (); \
+ void *__old_stack_mark = mono_thread_info_push_stack_mark (__info, &__dummy);
-#endif
+#define CLEAR_STACK_WATERMARK \
+ mono_thread_info_pop_stack_mark (__info, __old_stack_mark);
-static inline MonoClass*
-mono_handle_class (MonoHandle handle)
-{
- return mono_object_get_class (handle->__private_obj);
-}
+#else
+#define SETUP_STACK_WATERMARK
+#define CLEAR_STACK_WATERMARK
+#endif
-static inline MonoDomain*
-mono_handle_domain (MonoHandle handle)
-{
- return mono_object_get_domain (handle->__private_obj);
-}
+#define ICALL_ENTRY() \
+ SETUP_ICALL_COMMON \
+ SETUP_ICALL_FRAME \
+ SETUP_STACK_WATERMARK
-#define mono_handle_obj_is_null(handle) ((handle)->__private_obj == NULL)
+#define ICALL_RETURN() \
+ do { \
+ CLEAR_STACK_WATERMARK \
+ CLEAR_ICALL_COMMON \
+ CLEAR_ICALL_FRAME \
+ return; \
+ } while (0); } while (0)
-#define MONO_HANDLE_TYPE_DECL(type) typedef struct { type *__private_obj; } type ## HandleStorage ; \
- typedef type ## HandleStorage * type ## Handle
-#define MONO_HANDLE_TYPE(type) type ## Handle
-#define MONO_HANDLE_NEW(type,obj) ((type ## Handle) mono_handle_new ((MonoObject*) (obj)))
-#define MONO_HANDLE_ELEVATE(type,handle) ((type ## Handle) mono_handle_elevate ((MonoObject*) (handle)->__private_obj))
+#define ICALL_RETURN_VAL(VAL) \
+ do { \
+ CLEAR_STACK_WATERMARK \
+ CLEAR_ICALL_COMMON \
+ CLEAR_ICALL_FRAME \
+ return VAL; \
+ } while (0); } while (0)
-#define MONO_HANDLE_ASSIGN(handle,rawptr) \
+#define ICALL_RETURN_OBJ(HANDLE) \
do { \
- mono_handle_assign ((handle), (rawptr)); \
- } while (0)
+ CLEAR_STACK_WATERMARK \
+ CLEAR_ICALL_COMMON \
+ void* __ret = MONO_HANDLE_RAW (HANDLE); \
+ CLEAR_ICALL_FRAME \
+ return __ret; \
+ } while (0); } while (0)
-#define MONO_HANDLE_SETREF(handle,fieldname,value) \
- do { \
- MonoHandle __value = (MonoHandle) (value); \
- MONO_PREPARE_GC_CRITICAL_REGION; \
- MONO_OBJECT_SETREF (mono_handle_obj ((handle)), fieldname, mono_handle_obj (__value)); \
- MONO_FINISH_GC_CRITICAL_REGION; \
- } while (0)
+/*
+Handle macros/functions
+*/
-#define MONO_HANDLE_SETREF_NULL(handle,fieldname) \
- do { \
- MONO_PREPARE_GC_CRITICAL_REGION; \
- MONO_OBJECT_SETREF (mono_handle_obj ((handle)), fieldname, NULL); \
- MONO_FINISH_GC_CRITICAL_REGION; \
- } while (0)
+#ifdef ENABLE_CHECKED_BUILD
+void mono_handle_verify (MonoRawHandle handle);
+#define HANDLE_INVARIANTS(H) mono_handle_verify((void*)(H))
+#else
+#define HANDLE_INVARIANTS(H) (0)
+#endif
+#define TYPED_HANDLE_PAYLOAD_NAME(TYPE) TYPE ## HandlePayload
+#define TYPED_HANDLE_NAME(TYPE) TYPE ## Handle
-#define MONO_HANDLE_SET(handle,fieldname,value) \
- do { \
- MONO_PREPARE_GC_CRITICAL_REGION; \
- mono_handle_obj ((handle))->fieldname = (value); \
- MONO_FINISH_GC_CRITICAL_REGION; \
- } while (0)
+/*
+ * TYPED_HANDLE_DECL(SomeType):
+ * Expands to a decl for handles to SomeType and to an internal payload struct.
+ *
+ * For example, TYPED_HANDLE_DECL(MonoObject) (see below) expands to:
+ *
+ * typedef struct {
+ * MonoObject *__obj;
+ * } MonoObjectHandlePayload;
+ *
+ * typedef MonoObjectHandlePayload* MonoObjectHandle;
+ */
+#define TYPED_HANDLE_DECL(TYPE) typedef struct { TYPE *__obj; } TYPED_HANDLE_PAYLOAD_NAME (TYPE) ; typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_HANDLE_NAME (TYPE)
+/* Have to double expand because MONO_STRUCT_OFFSET is doing token pasting on cross-compilers. */
+#define MONO_HANDLE_PAYLOAD_OFFSET_(PayloadType) MONO_STRUCT_OFFSET(PayloadType, __obj)
+#define MONO_HANDLE_PAYLOAD_OFFSET(TYPE) MONO_HANDLE_PAYLOAD_OFFSET_(TYPED_HANDLE_PAYLOAD_NAME (TYPE))
-#define MONO_HANDLE_ARRAY_SETREF(handle,index,value) \
- do { \
- MonoHandle __value = (MonoHandle) (value); \
- MONO_PREPARE_GC_CRITICAL_REGION; \
- mono_array_setref (mono_handle_obj ((handle)), (index), mono_handle_obj (__value)); \
- MONO_FINISH_GC_CRITICAL_REGION; \
- } while (0)
+#define MONO_HANDLE_INIT ((void*) mono_null_value_handle)
+#define NULL_HANDLE mono_null_value_handle
+
+//XXX add functions to get/set raw, set field, set field to null, set array, set array to null
+#define MONO_HANDLE_RAW(HANDLE) (HANDLE_INVARIANTS (HANDLE), ((HANDLE)->__obj))
+#define MONO_HANDLE_DCL(TYPE, NAME) TYPED_HANDLE_NAME(TYPE) NAME = (TYPED_HANDLE_NAME(TYPE))(mono_handle_new ((MonoObject*)(NAME ## _raw)))
+#define MONO_HANDLE_NEW(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( mono_handle_new ((MonoObject*)(VALUE)) )
+#define MONO_HANDLE_CAST(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( VALUE )
-#define MONO_HANDLE_ARRAY_SETREF_NULL(handle,index) \
- do { \
- MONO_PREPARE_GC_CRITICAL_REGION; \
- mono_array_setref (mono_handle_obj ((handle)), (index), NULL); \
- MONO_FINISH_GC_CRITICAL_REGION; \
+/*
+WARNING WARNING WARNING
+
+The following functions require a particular evaluation ordering to ensure correctness.
+We must not have exposed handles while any sort of evaluation is happening as that very evaluation might trigger
+a safepoint and break us.
+
+This is why we evaluate index and value before any call to MONO_HANDLE_RAW or other functions that deal with naked objects.
+*/
+#define MONO_HANDLE_SETRAW(HANDLE, FIELD, VALUE) do { \
+ MonoObject *__val = (MonoObject*)(VALUE); \
+ MONO_OBJECT_SETREF (MONO_HANDLE_RAW (HANDLE), FIELD, __val); \
+ } while (0);
+
+#define MONO_HANDLE_SET(HANDLE, FIELD, VALUE) do { \
+ MonoObjectHandle __val = MONO_HANDLE_CAST (MonoObject, VALUE); \
+ MONO_OBJECT_SETREF (MONO_HANDLE_RAW (HANDLE), FIELD, MONO_HANDLE_RAW (__val)); \
+ } while (0);
+
+/* VS doesn't support typeof :( :( :( */
+#define MONO_HANDLE_SETVAL(HANDLE, FIELD, TYPE, VALUE) do { \
+ TYPE __val = (VALUE); \
+ MONO_HANDLE_RAW (HANDLE)->FIELD = __val; \
+ } while (0)
+
+#define MONO_HANDLE_ARRAY_SETREF(HANDLE, IDX, VALUE) do { \
+ int __idx = (IDX); \
+ MonoObjectHandle __val = MONO_HANDLE_CAST (MonoObject, VALUE); \
+ mono_array_setref_fast (MONO_HANDLE_RAW (HANDLE), __idx, MONO_HANDLE_RAW (__val)); \
} while (0)
-
-#define MONO_HANDLE_ARRAY_SET(handle,type,index,value) \
- do { \
- MONO_PREPARE_GC_CRITICAL_REGION; \
- mono_array_set (mono_handle_obj ((handle)), type, (index), (value)); \
- MONO_FINISH_GC_CRITICAL_REGION; \
+#define MONO_HANDLE_ARRAY_SETRAW(HANDLE, IDX, VALUE) do { \
+ int __idx = (IDX); \
+ MonoObject *__val = (MonoObject*)(VALUE); \
+ mono_array_setref_fast (MONO_HANDLE_RAW (HANDLE), __idx, __val); \
} while (0)
+#define MONO_HANDLE_DOMAIN(HANDLE) (mono_object_domain (MONO_HANDLE_RAW (MONO_HANDLE_CAST (MonoObject, HANDLE))))
+/* Baked typed handles we all want */
+TYPED_HANDLE_DECL (MonoString);
+TYPED_HANDLE_DECL (MonoArray);
+TYPED_HANDLE_DECL (MonoObject);
+
+#define NULL_HANDLE_STRING MONO_HANDLE_CAST(MonoString, NULL_HANDLE)
+
+/*
+This is the constant for a handle that points nowhere.
+Init values to it.
+*/
+extern const MonoObjectHandle mono_null_value_handle;
-/* Some common handle types */
-MONO_HANDLE_TYPE_DECL (MonoArray);
-MONO_HANDLE_TYPE_DECL (MonoString);
+//FIXME this should go somewhere else
+MonoStringHandle mono_string_new_handle (MonoDomain *domain, const char *data, MonoError *error);
+MonoArrayHandle mono_array_new_handle (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error);
G_END_DECLS