X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fhandle.h;h=5de55eebc824540879dedab9bb5e555c99fc3276;hb=8bbca2bada9398b3a5ddfec0c3c890054c1e8bdc;hp=f5e8d29ba3088aa08a9acf3f2e4686ab5e9965db;hpb=d326ae2998c679e1e78897cfcb2d5fd4fbcf2c8d;p=mono.git diff --git a/mono/metadata/handle.h b/mono/metadata/handle.h index f5e8d29ba30..5de55eebc82 100644 --- a/mono/metadata/handle.h +++ b/mono/metadata/handle.h @@ -1,5 +1,6 @@ -/* - * handle.h: Handle to object in native code +/** + * \file + * Handle to object in native code * * Authors: * - Ludovic Henry @@ -24,7 +25,6 @@ G_BEGIN_DECLS - /* Handle stack. @@ -50,20 +50,51 @@ Whether this config needs stack watermark recording to know where to start scann typedef struct _HandleChunk HandleChunk; +/* define MONO_HANDLE_TRACK_OWNER to store the file and line number of each call to MONO_HANDLE_NEW + * in the handle stack. (This doubles the amount of memory used for handles, so it's only useful for debugging). + */ +/*#define MONO_HANDLE_TRACK_OWNER*/ + +/* define MONO_HANDLE_TRACK_SP to record the C stack pointer at the time of each HANDLE_FUNCTION_ENTER and + * to ensure that when a new handle is allocated the previous newest handle is not lower in the stack. + * This is useful to catch missing HANDLE_FUNCTION_ENTER / HANDLE_FUNCTION_RETURN pairs which could cause + * handle leaks. + */ +/*#define MONO_HANDLE_TRACK_SP*/ + +typedef struct { + gpointer o; /* MonoObject ptr or interior ptr */ +#ifdef MONO_HANDLE_TRACK_OWNER + const char *owner; +#endif +#ifdef MONO_HANDLE_TRACK_SP + gpointer alloc_sp; /* sp from HandleStack:stackmark_sp at time of allocation */ +#endif +} HandleChunkElem; + struct _HandleChunk { - int size; //number of bytes + int size; //number of handles HandleChunk *prev, *next; - MonoObject *objects [OBJECTS_PER_HANDLES_CHUNK]; + HandleChunkElem elems [OBJECTS_PER_HANDLES_CHUNK]; }; typedef struct { HandleChunk *top; //alloc from here HandleChunk *bottom; //scan from here +#ifdef MONO_HANDLE_TRACK_SP + gpointer stackmark_sp; // C stack pointer top when from most recent mono_stack_mark_init +#endif + /* Chunk for storing interior pointers. Not extended right now */ + HandleChunk *interior; } HandleStack; +// Keep this in sync with RuntimeStructs.cs typedef struct { - int size; + int size, interior_size; HandleChunk *chunk; +#ifdef MONO_HANDLE_TRACK_SP + gpointer prev_sp; // C stack pointer from prior mono_stack_mark_init +#endif } HandleStackMark; typedef void *MonoRawHandle; @@ -71,28 +102,57 @@ typedef void *MonoRawHandle; typedef void (*GcScanFunc) (gpointer*, gpointer); +#ifndef MONO_HANDLE_TRACK_OWNER MonoRawHandle mono_handle_new (MonoObject *object); +MonoRawHandle mono_handle_new_full (gpointer rawptr, gboolean interior); +MonoRawHandle mono_handle_new_interior (gpointer rawptr); +#else +MonoRawHandle mono_handle_new (MonoObject *object, const char* owner); +MonoRawHandle mono_handle_new_full (gpointer rawptr, gboolean interior, const char *owner); +MonoRawHandle mono_handle_new_interior (gpointer rawptr, const char *owner); +#endif -void mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data); +void mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data, gboolean precise); +gboolean mono_handle_stack_is_empty (HandleStack *stack); 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); +void mono_handle_stack_free_domain (HandleStack *stack, MonoDomain *domain); -static void +#ifdef MONO_HANDLE_TRACK_SP +void mono_handle_chunk_leak_check (HandleStack *handles); +#endif + +static inline void mono_stack_mark_init (MonoThreadInfo *info, HandleStackMark *stackmark) { +#ifdef MONO_HANDLE_TRACK_SP + gpointer sptop = (gpointer)(intptr_t)&stackmark; +#endif HandleStack *handles = (HandleStack *)info->handle_stack; stackmark->size = handles->top->size; stackmark->chunk = handles->top; + stackmark->interior_size = handles->interior->size; +#ifdef MONO_HANDLE_TRACK_SP + stackmark->prev_sp = handles->stackmark_sp; + handles->stackmark_sp = sptop; +#endif } -static void +static inline void mono_stack_mark_pop (MonoThreadInfo *info, HandleStackMark *stackmark) { HandleStack *handles = (HandleStack *)info->handle_stack; - handles->top = stackmark->chunk; - handles->top->size = stackmark->size; + HandleChunk *old_top = stackmark->chunk; + old_top->size = stackmark->size; + mono_memory_write_barrier (); + handles->top = old_top; + handles->interior->size = stackmark->interior_size; +#ifdef MONO_HANDLE_TRACK_SP + mono_memory_write_barrier (); /* write to top before prev_sp */ + handles->stackmark_sp = stackmark->prev_sp; +#endif } /* @@ -115,6 +175,38 @@ Icall macros mono_stack_mark_record_size (__info, &__mark, __FUNCTION__); \ mono_stack_mark_pop (__info, &__mark); +#define CLEAR_ICALL_FRAME_VALUE(RESULT, HANDLE) \ + mono_stack_mark_record_size (__info, &__mark, __FUNCTION__); \ + (RESULT) = mono_stack_mark_pop_value (__info, &__mark, (HANDLE)); + + +#define HANDLE_FUNCTION_ENTER() do { \ + MonoThreadInfo *__info = mono_thread_info_current (); \ + SETUP_ICALL_FRAME \ + +#define HANDLE_FUNCTION_RETURN() \ + CLEAR_ICALL_FRAME; \ + } while (0) + +#define HANDLE_FUNCTION_RETURN_VAL(VAL) \ + CLEAR_ICALL_FRAME; \ + return (VAL); \ + } while (0) + +#define HANDLE_FUNCTION_RETURN_OBJ(HANDLE) \ + do { \ + void* __result = (MONO_HANDLE_RAW (HANDLE)); \ + CLEAR_ICALL_FRAME; \ + return __result; \ + } while (0); } while (0); + +#define HANDLE_FUNCTION_RETURN_REF(TYPE, HANDLE) \ + do { \ + MonoRawHandle __result; \ + CLEAR_ICALL_FRAME_VALUE (__result, ((MonoRawHandle) (HANDLE))); \ + return MONO_HANDLE_CAST (TYPE, __result); \ + } while (0); } while (0); + #ifdef MONO_NEEDS_STACK_WATERMARK static void @@ -187,6 +279,14 @@ void mono_handle_verify (MonoRawHandle handle); #define TYPED_HANDLE_PAYLOAD_NAME(TYPE) TYPE ## HandlePayload #define TYPED_HANDLE_NAME(TYPE) TYPE ## Handle +#define TYPED_OUT_HANDLE_NAME(TYPE) TYPE ## HandleOut + +#ifdef MONO_HANDLE_TRACK_OWNER +#define STRINGIFY_(x) #x +#define STRINGIFY(x) STRINGIFY_(x) +#define HANDLE_OWNER_STRINGIFY(file,lineno) (const char*) (file ":" STRINGIFY(lineno)) +#endif + /* * TYPED_HANDLE_DECL(SomeType): @@ -195,25 +295,50 @@ void mono_handle_verify (MonoRawHandle handle); * For example, TYPED_HANDLE_DECL(MonoObject) (see below) expands to: * * typedef struct { - * MonoObject *__obj; + * MonoObject *__raw; * } MonoObjectHandlePayload; * * typedef MonoObjectHandlePayload* MonoObjectHandle; + * typedef MonoObjectHandlePayload* MonoObjectHandleOut; */ -#define TYPED_HANDLE_DECL(TYPE) typedef struct { TYPE *__obj; } TYPED_HANDLE_PAYLOAD_NAME (TYPE) ; typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_HANDLE_NAME (TYPE) +#define TYPED_HANDLE_DECL(TYPE) \ + typedef struct { TYPE *__raw; } TYPED_HANDLE_PAYLOAD_NAME (TYPE) ; \ + typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_HANDLE_NAME (TYPE); \ + typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_OUT_HANDLE_NAME (TYPE) +/* + * TYPED_VALUE_HANDLE_DECL(SomeType): + * Expands to a decl for handles to SomeType (which is a managed valuetype (likely a struct) of some sort) and to an internal payload struct. + * For example TYPED_HANDLE_DECL(MonoMethodInfo) expands to: + * + * typedef struct { + * MonoMethodInfo *__raw; + * } MonoMethodInfoHandlePayload; + * typedef MonoMethodInfoHandlePayload* MonoMethodInfoHandle; + */ +#define TYPED_VALUE_HANDLE_DECL(TYPE) TYPED_HANDLE_DECL(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_(PayloadType) MONO_STRUCT_OFFSET(PayloadType, __raw) #define MONO_HANDLE_PAYLOAD_OFFSET(TYPE) MONO_HANDLE_PAYLOAD_OFFSET_(TYPED_HANDLE_PAYLOAD_NAME (TYPE)) #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_RAW(HANDLE) (HANDLE_INVARIANTS (HANDLE), ((HANDLE)->__raw)) +#define MONO_HANDLE_DCL(TYPE, NAME) TYPED_HANDLE_NAME(TYPE) NAME = MONO_HANDLE_NEW (TYPE, (NAME ## _raw)) + +#ifndef MONO_HANDLE_TRACK_OWNER #define MONO_HANDLE_NEW(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( mono_handle_new ((MonoObject*)(VALUE)) ) +#else +#define MONO_HANDLE_NEW(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( mono_handle_new ((MonoObject*)(VALUE), HANDLE_OWNER_STRINGIFY(__FILE__, __LINE__))) +#endif + #define MONO_HANDLE_CAST(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( VALUE ) +#define MONO_HANDLE_IS_NULL(HANDLE) (MONO_HANDLE_RAW(HANDLE) == NULL) + + /* WARNING WARNING WARNING @@ -226,12 +351,22 @@ This is why we evaluate index and value before any call to MONO_HANDLE_RAW or ot #define MONO_HANDLE_SETRAW(HANDLE, FIELD, VALUE) do { \ MonoObject *__val = (MonoObject*)(VALUE); \ MONO_OBJECT_SETREF (MONO_HANDLE_RAW (HANDLE), FIELD, __val); \ - } while (0); + } 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); + } while (0) + +/* N.B. RESULT is evaluated before HANDLE */ +#define MONO_HANDLE_GET(RESULT, HANDLE, FIELD) do { \ + MonoObjectHandle __dest = MONO_HANDLE_CAST(MonoObject, RESULT); \ + mono_gc_wbarrier_generic_store (&__dest->__raw, (MonoObject*)(MONO_HANDLE_RAW(HANDLE)->FIELD)); \ + } while (0) + +#define MONO_HANDLE_NEW_GET(TYPE,HANDLE,FIELD) (MONO_HANDLE_NEW(TYPE,MONO_HANDLE_RAW(HANDLE)->FIELD)) + +#define MONO_HANDLE_GETVAL(HANDLE, FIELD) (MONO_HANDLE_RAW(HANDLE)->FIELD) /* VS doesn't support typeof :( :( :( */ #define MONO_HANDLE_SETVAL(HANDLE, FIELD, TYPE, VALUE) do { \ @@ -245,17 +380,68 @@ This is why we evaluate index and value before any call to MONO_HANDLE_RAW or ot mono_array_setref_fast (MONO_HANDLE_RAW (HANDLE), __idx, MONO_HANDLE_RAW (__val)); \ } while (0) +#define MONO_HANDLE_ARRAY_SETVAL(HANDLE, TYPE, IDX, VALUE) do { \ + int __idx = (IDX); \ + TYPE __val = (VALUE); \ + mono_array_set (MONO_HANDLE_RAW (HANDLE), TYPE, __idx, __val); \ + } while (0) + #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); \ + mono_array_setref_fast (MONO_HANDLE_RAW (HANDLE), __idx, __val); \ + } while (0) + +/* N.B. DEST is evaluated AFTER all the other arguments */ +#define MONO_HANDLE_ARRAY_GETVAL(DEST, HANDLE, TYPE, IDX) do { \ + MonoArrayHandle __arr = (HANDLE); \ + int __idx = (IDX); \ + TYPE __result = mono_array_get (MONO_HANDLE_RAW(__arr), TYPE, __idx); \ + (DEST) = __result; \ + } while (0) + +#define MONO_HANDLE_ARRAY_GETREF(DEST, HANDLE, IDX) do { \ + mono_handle_array_getref (MONO_HANDLE_CAST(MonoObject, (DEST)), (HANDLE), (IDX)); \ } while (0) +#define MONO_HANDLE_ASSIGN(DESTH, SRCH) \ + mono_handle_assign (MONO_HANDLE_CAST (MonoObject, (DESTH)), MONO_HANDLE_CAST(MonoObject, (SRCH))) + +#define MONO_HANDLE_DOMAIN(HANDLE) (mono_object_domain (MONO_HANDLE_RAW (MONO_HANDLE_CAST (MonoObject, HANDLE)))) + +/* Given an object and a MonoClassField, return the value (must be non-object) + * of the field. It's the caller's responsibility to check that the object is + * of the correct class. */ +#define MONO_HANDLE_GET_FIELD_VAL(HANDLE,TYPE,FIELD) *(TYPE *)(mono_handle_unsafe_field_addr (MONO_HANDLE_CAST (MonoObject, (HANDLE)), (FIELD))) + +#define MONO_HANDLE_NEW_GET_FIELD(HANDLE,TYPE,FIELD) MONO_HANDLE_NEW (TYPE, *(TYPE**)(mono_handle_unsafe_field_addr (MONO_HANDLE_CAST (MonoObject, (HANDLE)), (FIELD)))) + +#define MONO_HANDLE_SET_FIELD_VAL(HANDLE,TYPE,FIELD,VAL) do { \ + MonoObjectHandle __obj = (HANDLE); \ + MonoClassField *__field = (FIELD); \ + TYPE __value = (VAL); \ + *(TYPE*)(mono_handle_unsafe_field_addr (__obj, __field)) = __value; \ + } while (0) + +#define MONO_HANDLE_SET_FIELD_REF(HANDLE,FIELD,VALH) do { \ + MonoObjectHandle __obj = MONO_HANDLE_CAST (MonoObject, (HANDLE)); \ + MonoClassField *__field = (FIELD); \ + MonoObjectHandle __value = MONO_HANDLE_CAST (MonoObject, (VALH)); \ + mono_gc_wbarrier_generic_store (mono_handle_unsafe_field_addr (__obj, __field), MONO_HANDLE_RAW (__value)); \ + } while (0) /* Baked typed handles we all want */ TYPED_HANDLE_DECL (MonoString); TYPED_HANDLE_DECL (MonoArray); TYPED_HANDLE_DECL (MonoObject); +TYPED_HANDLE_DECL (MonoException); +TYPED_HANDLE_DECL (MonoAppContext); + +/* Unfortunately MonoThreadHandle is already a typedef used for something unrelated. So + * the coop handle for MonoThread* is MonoThreadObjectHandle. + */ +typedef MonoThread MonoThreadObject; +TYPED_HANDLE_DECL (MonoThreadObject); #define NULL_HANDLE_STRING MONO_HANDLE_CAST(MonoString, NULL_HANDLE) @@ -265,10 +451,70 @@ Init values to it. */ extern const MonoObjectHandle mono_null_value_handle; +static inline void +mono_handle_assign (MonoObjectHandleOut dest, MonoObjectHandle src) +{ + mono_gc_wbarrier_generic_store (&dest->__raw, src ? MONO_HANDLE_RAW(src) : NULL); +} + +/* It is unsafe to call this function directly - it does not pin the handle! Use MONO_HANDLE_GET_FIELD_VAL(). */ +static inline gchar* +mono_handle_unsafe_field_addr (MonoObjectHandle h, MonoClassField *field) +{ + return ((gchar *)MONO_HANDLE_RAW (h)) + field->offset; +} //FIXME this should go somewhere else -MonoStringHandle mono_string_new_handle (MonoDomain *domain, const char *data); +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); +MonoArrayHandle +mono_array_new_full_handle (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error); + + +uintptr_t mono_array_handle_length (MonoArrayHandle arr); + +static inline void +mono_handle_array_getref (MonoObjectHandleOut dest, MonoArrayHandle array, uintptr_t index) +{ + mono_gc_wbarrier_generic_store (&dest->__raw, mono_array_get (MONO_HANDLE_RAW (array),gpointer, index)); +} + +#define mono_handle_class(o) mono_object_class (MONO_HANDLE_RAW (o)) + +/* Local handles to global GC handles and back */ + +uint32_t +mono_gchandle_from_handle (MonoObjectHandle handle, mono_bool pinned); + +MonoObjectHandle +mono_gchandle_get_target_handle (uint32_t gchandle); + +void +mono_array_handle_memcpy_refs (MonoArrayHandle dest, uintptr_t dest_idx, MonoArrayHandle src, uintptr_t src_idx, uintptr_t len); + +/* Pins the MonoArray using a gchandle and returns a pointer to the + * element with the given index (where each element is of the given + * size. Call mono_gchandle_free to unpin. + */ +gpointer +mono_array_handle_pin_with_size (MonoArrayHandle handle, int size, uintptr_t index, uint32_t *gchandle); + +#define MONO_ARRAY_HANDLE_PIN(handle,type,index,gchandle_out) mono_array_handle_pin_with_size (MONO_HANDLE_CAST(MonoArray,(handle)), sizeof (type), (index), (gchandle_out)) + +gunichar2 * +mono_string_handle_pin_chars (MonoStringHandle s, uint32_t *gchandle_out); + +gpointer +mono_object_handle_pin_unbox (MonoObjectHandle boxed_valuetype_obj, uint32_t *gchandle_out); + +void +mono_error_set_exception_handle (MonoError *error, MonoExceptionHandle exc); + +MonoAppContextHandle +mono_context_get_handle (void); + +void +mono_context_set_handle (MonoAppContextHandle new_context); G_END_DECLS