X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fobject.c;h=652d4321b8a66d545228b39ac5e272effe61c3ac;hb=2d41a134bfd3583e5639556bc5c9a0378841f3fc;hp=11f6e03eecd348ef09ecc318246d44e31159173c;hpb=44d1dbcd2c2855c4540ad2e1d37b0fb118094f8a;p=mono.git diff --git a/mono/metadata/object.c b/mono/metadata/object.c index 11f6e03eecd..652d4321b8a 100644 --- a/mono/metadata/object.c +++ b/mono/metadata/object.c @@ -15,33 +15,135 @@ #include #include #include -#if G_BYTE_ORDER != G_LITTLE_ENDIAN -#include -#include /* for PAGESIZE */ -#ifndef PAGESIZE -#define PAGESIZE 4096 -#endif +#if HAVE_BOEHM_GC +#include #endif -static void -default_runtime_object_init (MonoObject *o) +MonoStats mono_stats; + +void +mono_runtime_object_init (MonoObject *this) { - return; -} + int i; + MonoMethod *method = NULL; + MonoClass *klass = this->vtable->klass; + + for (i = 0; i < klass->method.count; ++i) { + if (!strcmp (".ctor", klass->methods [i]->name) && + klass->methods [i]->signature->param_count == 0) { + method = klass->methods [i]; + break; + } + } + + g_assert (method); -MonoRuntimeObjectInit mono_runtime_object_init = default_runtime_object_init; -MonoRuntimeExecMain mono_runtime_exec_main = NULL; + mono_runtime_invoke (method, this, NULL); +} +/* + * runtime_class_init: + * @klass: klass that needs to be initialized + * + * This routine calls the class constructor for @class. + */ void -mono_install_runtime_object_init (MonoRuntimeObjectInit func) +mono_runtime_class_init (MonoClass *klass) { - mono_runtime_object_init = func? func: default_runtime_object_init; + int i; + + for (i = 0; i < klass->method.count; ++i) { + MonoMethod *method = klass->methods [i]; + if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && + (strcmp (".cctor", method->name) == 0)) { + mono_runtime_invoke (method, NULL, NULL); + return; + } + } + /* No class constructor found */ +} + +static MonoInvokeFunc default_mono_runtime_invoke = NULL; + +MonoObject* +mono_runtime_invoke (MonoMethod *method, void *obj, void **params) +{ + if (!default_mono_runtime_invoke) { + g_error ("runtime invoke called on uninitialized runtime"); + return NULL; + } + return default_mono_runtime_invoke (method, obj, params); +} + +int +mono_runtime_exec_main (MonoMethod *method, MonoArray *args) +{ + gpointer pa [1]; + + pa [0] = args; + + if (method->signature->ret->type == MONO_TYPE_I4) { + MonoObject *res; + res = mono_runtime_invoke (method, NULL, pa); + return *(guint32 *)((char *)res + sizeof (MonoObject)); + } else { + mono_runtime_invoke (method, NULL, pa); + return 0; + } } void -mono_install_runtime_exec_main (MonoRuntimeExecMain func) +mono_install_runtime_invoke (MonoInvokeFunc func) { - mono_runtime_exec_main = func; + default_mono_runtime_invoke = func; +} + +MonoObject* +mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params) +{ + MonoMethodSignature *sig = method->signature; + gpointer *pa; + int i; + + pa = alloca (sizeof (gpointer) * params->bounds->length); + + for (i = 0; i < params->bounds->length; i++) { + if (sig->params [i]->byref) { + /* nothing to do */ + } + + switch (sig->params [i]->type) { + case MONO_TYPE_U1: + case MONO_TYPE_I1: + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_U2: + case MONO_TYPE_I2: + case MONO_TYPE_CHAR: + case MONO_TYPE_U: + case MONO_TYPE_I: + case MONO_TYPE_U4: + case MONO_TYPE_I4: + case MONO_TYPE_U8: + case MONO_TYPE_I8: + case MONO_TYPE_VALUETYPE: + pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject); + break; + case MONO_TYPE_STRING: + case MONO_TYPE_OBJECT: + case MONO_TYPE_CLASS: + pa [i] = (char *)(((gpointer *)params->vector)[i]); + break; + default: + g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type); + } + } + + if (!strcmp (method->name, ".ctor")) { + obj = mono_object_new (mono_domain_get (), method->klass); + mono_runtime_invoke (method, obj, pa); + return obj; + } else + return mono_runtime_invoke (method, obj, pa); } /** @@ -56,7 +158,11 @@ mono_install_runtime_exec_main (MonoRuntimeExecMain func) void * mono_object_allocate (size_t size) { +#if HAVE_BOEHM_GC + void *o = GC_debug_malloc (size, "object", 1); +#else void *o = calloc (1, size); +#endif return o; } @@ -70,10 +176,14 @@ mono_object_allocate (size_t size) void mono_object_free (MonoObject *o) { +#if HAVE_BOEHM_GC + g_error ("mono_object_free called with boehm gc."); +#else MonoClass *c = o->vtable->klass; memset (o, 0, c->instance_size); free (o); +#endif } /** @@ -86,12 +196,22 @@ mono_object_free (MonoObject *o) MonoObject * mono_object_new (MonoDomain *domain, MonoClass *klass) { + static guint32 uoid = 0; MonoObject *o; + mono_stats.new_object_count++; + if (!klass->inited) mono_class_init (klass); - o = mono_object_allocate (klass->instance_size); + if (klass->ghcimpl) { + o = mono_object_allocate (klass->instance_size); + } else { + guint32 *t; + t = mono_object_allocate (klass->instance_size + 4); + *t = ++uoid; + o = (MonoObject *)(++t); + } o->vtable = mono_class_vtable (domain, klass); return o; @@ -150,7 +270,7 @@ mono_array_clone (MonoArray *array) guint32 *sizes; MonoClass *klass = array->obj.vtable->klass; - sizes = g_malloc (klass->rank * sizeof(guint32) * 2); + sizes = alloca (klass->rank * sizeof(guint32) * 2); size = mono_array_element_size (klass); for (i = 0; i < klass->rank; ++i) { sizes [i] = array->bounds [i].length; @@ -164,11 +284,21 @@ mono_array_clone (MonoArray *array) return o; } +/* + * mono_array_new_full: + * @domain: domain where the object is created + * @array_class: array class + * @lengths: lengths for each dimension in the array + * @lower_bounds: lower bounds for each dimension in the array (may be NULL) + * + * This routine creates a new array objects with the given dimensions, + * lower bounds and type. + */ MonoArray* mono_array_new_full (MonoDomain *domain, MonoClass *array_class, guint32 *lengths, guint32 *lower_bounds) { - guint32 byte_len; + guint32 byte_len, len; MonoObject *o; MonoArray *array; MonoArrayBounds *bounds; @@ -178,16 +308,22 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_class_init (array_class); byte_len = mono_array_element_size (array_class); + len = 1; +#if HAVE_BOEHM_GC + bounds = GC_debug_malloc (sizeof (MonoArrayBounds) * array_class->rank, "bounds", 0); +#else bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank); +#endif for (i = 0; i < array_class->rank; ++i) { bounds [i].length = lengths [i]; - byte_len *= lengths [i]; + len *= lengths [i]; } if (lower_bounds) for (i = 0; i < array_class->rank; ++i) bounds [i].lower_bound = lower_bounds [i]; + byte_len *= len; /* * Following three lines almost taken from mono_object_new (): * they need to be kept in sync. @@ -200,25 +336,25 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class, array = (MonoArray*)o; array->bounds = bounds; - array->max_length = bounds [0].length; + array->max_length = len; return array; } /* * mono_array_new: - * @image: image where the object is being referenced + * @domain: domain where the object is created * @eclass: element class * @n: number of array elements * - * This routine creates a new szarray with @n elements of type @token + * This routine creates a new szarray with @n elements of type @eclass. */ MonoArray * mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n) { MonoClass *ac; - ac = mono_array_class_get (eclass, 1); + ac = mono_array_class_get (&eclass->byval_arg, 1); g_assert (ac != NULL); return mono_array_new_full (domain, ac, &n, NULL); @@ -240,7 +376,7 @@ mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len) s = (MonoString*)mono_object_new (domain, mono_defaults.string_class); g_assert (s != NULL); - ca = (MonoArray *)mono_array_new (domain, mono_defaults.string_class, len); + ca = (MonoArray *)mono_array_new (domain, mono_defaults.char_class, len); g_assert (ca != NULL); s->c_str = ca; @@ -251,6 +387,34 @@ mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len) return s; } +/* + * mono_string_new_len: + * @text: a pointer to an utf8 string + * @length: number of bytes in @text to consider + * + * Returns: A newly created string object which contains @text. + */ +MonoString* +mono_string_new_len (MonoDomain *domain, const char *text, guint length) +{ + GError *error = NULL; + MonoString *o = NULL; + guint16 *ut; + glong items_written; + + + ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error); + + if (!error) + o = mono_string_new_utf16 (domain, ut, items_written); + else + g_error_free (error); + + g_free (ut); + + return o; +} + /** * mono_string_new: * @text: a pointer to an utf8 string @@ -280,6 +444,20 @@ mono_string_new (MonoDomain *domain, const char *text) return o; } +/* + * mono_string_new_wrapper: + * @text: pointer to utf8 characters. + * + * Helper function to create a string object from @text in the current domain. + */ +MonoString* +mono_string_new_wrapper (const char *text) +{ + MonoDomain *domain = mono_domain_get (); + + return mono_string_new (domain, text); +} + /** * mono_value_box: * @class: the class of the value @@ -333,46 +511,30 @@ mono_object_isinst (MonoObject *obj, MonoClass *klass) vt->interface_offsets [klass->interface_id]) return obj; } else { - if ((oklass->baseval - klass->baseval) <= klass->diffval) + if (oklass == mono_defaults.transparent_proxy_class) { + /* fixme: add check for IRemotingTypeInfo */ + MonoRealProxy *rp = ((MonoTransparentProxy *)obj)->rp; + MonoType *type; + type = ((MonoReflectionType *)rp->class_to_proxy)->type; + oklass = mono_class_from_mono_type (type); + } + if (oklass->rank && oklass->rank == klass->rank) { + if ((oklass->element_class->baseval - klass->element_class->baseval) <= + klass->element_class->diffval) + return obj; + } else if ((oklass->baseval - klass->baseval) <= klass->diffval) return obj; } return NULL; } - -typedef struct { - MonoString *obj; - MonoString *found; -} InternCheck; - -static void -check_interned (gpointer key, MonoString *value, InternCheck *check) -{ - if (value == check->obj) - check->found = value; -} - -MonoString* -mono_string_is_interned (MonoString *o) -{ - InternCheck check; - check.obj = o; - check.found = NULL; - - /* - * Yes, this is slow. Our System.String implementation needs to be redone. - * And GLib needs foreach() methods that can be stopped halfway. - */ - g_hash_table_foreach (((MonoObject *)o)->vtable->domain->ldstr_table, (GHFunc)check_interned, &check); - return check.found; -} - -MonoString* -mono_string_intern (MonoString *str) +static MonoString* +mono_string_is_interned_lookup (MonoString *str, int insert) { - GHashTable *ldstr_table; + MonoGHashTable *ldstr_table; MonoString *res; + MonoDomain *domain; char *ins = g_malloc (4 + str->length * 2); char *p; int bloblen; @@ -384,55 +546,104 @@ mono_string_intern (MonoString *str) p = ins; mono_metadata_encode_value (bloblen + 2 * str->length, p, &p); bloblen = (p - ins) + 2 * str->length; + /* + * ins is stored in the hash table as a key and needs to have the same + * representation as in the metadata: we swap the character bytes on big + * endian boxes. + */ +#if G_BYTE_ORDER != G_LITTLE_ENDIAN + { + int i; + char *p2 = mono_array_addr (str->c_str, char, 0); + for (i = 0; i < str->length; ++i) { + *p++ = p2 [1]; + *p++ = p2 [0]; + p2 += 2; + } + } +#else memcpy (p, str->c_str->vector, str->length * 2); - ldstr_table = ((MonoObject *)str)->vtable->domain->ldstr_table; - if ((res = g_hash_table_lookup (ldstr_table, ins))) { +#endif + domain = ((MonoObject *)str)->vtable->domain; + ldstr_table = domain->ldstr_table; + mono_domain_lock (domain); + if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) { + mono_domain_unlock (domain); g_free (ins); return res; } - g_hash_table_insert (ldstr_table, ins, str); - return str; + if (insert) { + mono_g_hash_table_insert (ldstr_table, ins, str); + mono_domain_unlock (domain); + return str; + } + mono_domain_unlock (domain); + g_free (ins); + return NULL; +} + +MonoString* +mono_string_is_interned (MonoString *o) +{ + return mono_string_is_interned_lookup (o, FALSE); } MonoString* -mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 index) +mono_string_intern (MonoString *str) +{ + return mono_string_is_interned_lookup (str, TRUE); +} + +/* + * mono_ldstr: + * @domain: the domain where the string will be used. + * @image: a metadata context + * @idx: index into the user string table. + * + * Implementation for the ldstr opcode. + */ +MonoString* +mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx) { const char *str, *sig; MonoString *o; size_t len2; - sig = str = mono_metadata_user_string (image, index); - len2 = mono_metadata_decode_blob_size (str, &str); - - if ((o = g_hash_table_lookup (domain->ldstr_table, sig))) + sig = str = mono_metadata_user_string (image, idx); + + mono_domain_lock (domain); + if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) { + mono_domain_unlock (domain); return o; + } + len2 = mono_metadata_decode_blob_size (str, &str); + len2 >>= 1; + + o = mono_string_new_utf16 (domain, (guint16*)str, len2); #if G_BYTE_ORDER != G_LITTLE_ENDIAN -#define SWAP16(x) (x) = GUINT16_FROM_LE ((x)) { - gint i; - guint16 *s; - - /* FIXME: it will be better to just add WRITE and after get it to previous state */ - mprotect ((void *) ((int) str & ~(PAGESIZE - 1)), len2 + ((int) str & (PAGESIZE - 1)), - PROT_READ | PROT_WRITE | PROT_EXEC); - len2 >>= 1; - /* printf ("swap %p\n", str); */ - for (i = 0, s = (guint16 *) str; i < len2; i++, s++) { - *s = ((*s & 0xff) << 8) | (*s >> 8); + int i; + guint16 *p2 = (guint16*)mono_array_addr (o->c_str, guint16, 0); + for (i = 0; i < len2; ++i) { + *p2 = GUINT16_FROM_LE (*p2); + ++p2; } } -#undef SWAP16 -#else - len2 >>= 1; #endif - - o = mono_string_new_utf16 (domain, (guint16*)str, len2); - g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o); + mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o); + mono_domain_unlock (domain); return o; } +/* + * mono_string_to_utf8: + * @s: a System.String + * + * Return the UTF8 representation for @s. + * the resulting buffer nedds to be freed with g_free(). + */ char * mono_string_to_utf8 (MonoString *s) { @@ -449,13 +660,22 @@ mono_string_to_utf8 (MonoString *s) g_assert (vector != NULL); as = g_utf16_to_utf8 ((gunichar2 *)vector, s->length, NULL, NULL, &error); - - g_assert (!error); + if (error) + g_warning (error->message); return as; } -char * +/* + * mono_string_to_utf16: + * @s: a MonoString + * + * Return an null-terminated array of the utf-16 chars + * contained in @s. The result must be freed with g_free(). + * This is a temporary helper until our string implementation + * is reworked to always include the null terminating char. + */ +gunichar2 * mono_string_to_utf16 (MonoString *s) { char *as; @@ -467,12 +687,12 @@ mono_string_to_utf16 (MonoString *s) as [(s->length * 2) + 1] = '\0'; if (!s->length || !s->c_str) { - return (as); + return (gunichar2 *)(as); } memcpy (as, mono_string_chars(s), s->length * 2); - return (as); + return (gunichar2 *)(as); } static void @@ -490,9 +710,178 @@ mono_install_handler (MonoExceptionFunc func) ex_handler = func? func: default_ex_handler; } +/* + * mono_raise_exception: + * @ex: exception object + * + * Signal the runtime that the exception @ex has been raised in unmanaged code. + */ void mono_raise_exception (MonoException *ex) { ex_handler (ex); } +MonoWaitHandle * +mono_wait_handle_new (MonoDomain *domain, HANDLE handle) +{ + MonoWaitHandle *res; + + res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class); + + res->handle = handle; + + return res; +} + +MonoAsyncResult * +mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data) +{ + MonoAsyncResult *res; + + res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class); + + res->data = data; + res->async_state = state; + res->handle = (MonoObject *)mono_wait_handle_new (domain, handle); + res->sync_completed = FALSE; + res->completed = FALSE; + + return res; +} + +void +mono_message_init (MonoDomain *domain, + MonoMethodMessage *this, + MonoReflectionMethod *method, + MonoArray *out_args) +{ + MonoMethodSignature *sig = method->method->signature; + MonoString *name; + int i, j; + char **names; + guint8 arg_type; + + this->method = method; + + this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count); + this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count); + + names = g_new (char *, sig->param_count); + mono_method_get_param_names (method->method, (const char **) names); + this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count); + + for (i = 0; i < sig->param_count; i++) { + name = mono_string_new (domain, names [i]); + mono_array_set (this->names, gpointer, i, name); + } + + g_free (names); + + for (i = 0, j = 0; i < sig->param_count; i++) { + + if (sig->params [i]->byref) { + if (out_args) { + gpointer arg = mono_array_get (out_args, gpointer, j); + mono_array_set (this->args, gpointer, i, arg); + j++; + } + arg_type = 2; + if (sig->params [i]->attrs & PARAM_ATTRIBUTE_IN) + arg_type |= 1; + } else { + arg_type = 1; + } + + mono_array_set (this->arg_types, guint8, i, arg_type); + } +} + +/** + * mono_remoting_invoke: + * @real_proxy: pointer to a RealProxy object + * @msg: The MonoMethodMessage to execute + * @exc: used to store exceptions + * @out_args: used to store output arguments + * + * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an + * IMessage interface and it is not trivial to extract results from there. So + * we call an helper method PrivateInvoke instead of calling + * RealProxy::Invoke() directly. + * + * Returns: the result object. + */ +MonoObject * +mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, + MonoObject **exc, MonoArray **out_args) +{ + static MonoMethod *im = NULL; + gpointer pa [4]; + + //static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL; + + /* fixme: make this domain dependent */ + if (!im) { + MonoClass *klass; + int i; + + klass = mono_defaults.real_proxy_class; + + for (i = 0; i < klass->method.count; ++i) { + if (!strcmp ("PrivateInvoke", klass->methods [i]->name) && + klass->methods [i]->signature->param_count == 4) { + im = klass->methods [i]; + break; + } + } + + g_assert (im); + } + + pa [0] = real_proxy; + pa [1] = msg; + pa [2] = exc; + pa [3] = out_args; + + return mono_runtime_invoke (im, NULL, pa); +} + +MonoObject * +mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, + MonoObject **exc, MonoArray **out_args) +{ + if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) { + + return mono_remoting_invoke ((MonoObject *)((MonoTransparentProxy *)target)->rp, + msg, exc, out_args); + + } else { + MonoDomain *domain = mono_domain_get (); + MonoMethod *method = msg->method->method; + MonoMethodSignature *sig = method->signature; + MonoObject *res; + int i, j, outarg_count = 0; + + for (i = 0; i < sig->param_count; i++) { + if (sig->params [i]->byref) + outarg_count++; + } + + *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count); + *exc = NULL; + + for (i = 0, j = 0; i < sig->param_count; i++) { + if (sig->params [i]->byref) { + gpointer arg; + arg = mono_array_get (msg->args, gpointer, i); + mono_array_set (*out_args, gpointer, j, arg); + j++; + } + } + + return mono_runtime_invoke_array (method, target, msg->args); + } +} + + +