2004-08-05 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mono / metadata / icall.c
index 87ddf07786c685dc5f144ff4df9cad87e035f913..7ec90b4f5064edae040e72472f60d63019a2e453 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <mono/metadata/object.h>
 #include <mono/metadata/threads.h>
+#include <mono/metadata/threads-types.h>
 #include <mono/metadata/threadpool.h>
 #include <mono/metadata/monitor.h>
 #include <mono/metadata/reflection.h>
@@ -33,7 +34,9 @@
 #include <mono/metadata/mono-endian.h>
 #include <mono/metadata/tokentype.h>
 #include <mono/metadata/unicode.h>
-#include <mono/metadata/appdomain.h>
+#include <mono/metadata/domain-internals.h>
+#include <mono/metadata/metadata-internals.h>
+#include <mono/metadata/class-internals.h>
 #include <mono/metadata/marshal.h>
 #include <mono/metadata/gc-internal.h>
 #include <mono/metadata/rand.h>
@@ -1802,6 +1805,13 @@ ves_icall_TypeBuilder_get_IsGenericParameter (MonoReflectionTypeBuilder *tb)
        return FALSE;
 }
 
+static void
+ves_icall_EnumBuilder_setup_enum_type (MonoReflectionType *enumtype,
+                                                                          MonoReflectionType *t)
+{
+       enumtype->type = t->type;
+}
+
 static MonoReflectionType*
 ves_icall_MonoGenericInst_GetParentType (MonoReflectionGenericInst *type)
 {
@@ -2148,6 +2158,7 @@ ves_icall_InternalInvoke (MonoReflectionMethod *method, MonoObject *this, MonoAr
         */
        MonoMethod *m = method->method;
        int pcount;
+       void *obj = this;
 
        MONO_ARCH_SAVE_REGS;
 
@@ -2155,6 +2166,9 @@ ves_icall_InternalInvoke (MonoReflectionMethod *method, MonoObject *this, MonoAr
                if (!mono_object_isinst (this, m->klass))
                        mono_raise_exception (mono_exception_from_name (mono_defaults.corlib, "System.Reflection", "TargetException"));
                m = mono_object_get_virtual_method (this, m);
+               /* must pass the pointer to the value for valuetype methods */
+               if (m->klass->valuetype)
+                       obj = mono_object_unbox (this);
        } else if (!(m->flags & METHOD_ATTRIBUTE_STATIC) && strcmp (m->name, ".ctor") && !m->wrapper_type)
                mono_raise_exception (mono_exception_from_name (mono_defaults.corlib, "System.Reflection", "TargetException"));
 
@@ -2183,7 +2197,7 @@ ves_icall_InternalInvoke (MonoReflectionMethod *method, MonoObject *this, MonoAr
 
                return (MonoObject*)mono_array_new_full (mono_object_domain (params), m->klass, lengths, lower_bounds);
        }
-       return mono_runtime_invoke_array (m, this, params, NULL);
+       return mono_runtime_invoke_array (m, obj, params, NULL);
 }
 
 static MonoObject *
@@ -2207,23 +2221,27 @@ ves_icall_InternalExecute (MonoReflectionMethod *method, MonoObject *this, MonoA
 
                        str = mono_string_to_utf8 (name);
                
-                       for (i = 0; i < k->field.count; i++) {
-                               if (!strcmp (k->fields [i].name, str)) {
-                                       MonoClass *field_klass =  mono_class_from_mono_type (k->fields [i].type);
-                                       if (field_klass->valuetype)
-                                               result = mono_value_box (domain, field_klass,
-                                                                        (char *)this + k->fields [i].offset);
-                                       else 
-                                               result = *((gpointer *)((char *)this + k->fields [i].offset));
-                               
-                                       g_assert (result);
-                                       out_args = mono_array_new (domain, mono_defaults.object_class, 1);
-                                       *outArgs = out_args;
-                                       mono_array_set (out_args, gpointer, 0, result);
-                                       g_free (str);
-                                       return NULL;
+                       do {
+                               for (i = 0; i < k->field.count; i++) {
+                                       if (!strcmp (k->fields [i].name, str)) {
+                                               MonoClass *field_klass =  mono_class_from_mono_type (k->fields [i].type);
+                                               if (field_klass->valuetype)
+                                                       result = mono_value_box (domain, field_klass,
+                                                                                (char *)this + k->fields [i].offset);
+                                               else 
+                                                       result = *((gpointer *)((char *)this + k->fields [i].offset));
+                                       
+                                               g_assert (result);
+                                               out_args = mono_array_new (domain, mono_defaults.object_class, 1);
+                                               *outArgs = out_args;
+                                               mono_array_set (out_args, gpointer, 0, result);
+                                               g_free (str);
+                                               return NULL;
+                                       }
                                }
-                       }
+                               k = k->parent;
+                       } 
+                       while (k != NULL);
 
                        g_free (str);
                        g_assert_not_reached ();
@@ -2236,25 +2254,29 @@ ves_icall_InternalExecute (MonoReflectionMethod *method, MonoObject *this, MonoA
 
                        str = mono_string_to_utf8 (name);
                
-                       for (i = 0; i < k->field.count; i++) {
-                               if (!strcmp (k->fields [i].name, str)) {
-                                       MonoClass *field_klass =  mono_class_from_mono_type (k->fields [i].type);
-                                       MonoObject *val = mono_array_get (params, gpointer, 2);
-
-                                       if (field_klass->valuetype) {
-                                               size = mono_type_size (k->fields [i].type, &align);
-                                               memcpy ((char *)this + k->fields [i].offset, 
-                                                       ((char *)val) + sizeof (MonoObject), size);
-                                       } else 
-                                               *(MonoObject**)((char *)this + k->fields [i].offset) = val;
-                               
-                                       out_args = mono_array_new (domain, mono_defaults.object_class, 0);
-                                       *outArgs = out_args;
-
-                                       g_free (str);
-                                       return NULL;
+                       do {
+                               for (i = 0; i < k->field.count; i++) {
+                                       if (!strcmp (k->fields [i].name, str)) {
+                                               MonoClass *field_klass =  mono_class_from_mono_type (k->fields [i].type);
+                                               MonoObject *val = mono_array_get (params, gpointer, 2);
+       
+                                               if (field_klass->valuetype) {
+                                                       size = mono_type_size (k->fields [i].type, &align);
+                                                       memcpy ((char *)this + k->fields [i].offset, 
+                                                               ((char *)val) + sizeof (MonoObject), size);
+                                               } else 
+                                                       *(MonoObject**)((char *)this + k->fields [i].offset) = val;
+                                       
+                                               out_args = mono_array_new (domain, mono_defaults.object_class, 0);
+                                               *outArgs = out_args;
+       
+                                               g_free (str);
+                                               return NULL;
+                                       }
                                }
-                       }
+                               k = k->parent;
+                       } 
+                       while (k != NULL);
 
                        g_free (str);
                        g_assert_not_reached ();
@@ -2273,6 +2295,8 @@ ves_icall_InternalExecute (MonoReflectionMethod *method, MonoObject *this, MonoA
        if (!strcmp (method->method->name, ".ctor"))
                g_assert_not_reached ();
 
+       /* This can be called only on MBR objects, so no need to unbox for valuetypes. */
+       g_assert (!method->method->klass->valuetype);
        result = mono_runtime_invoke_array (method->method, this, params, NULL);
 
        for (i = 0, j = 0; i < mono_array_length (params); i++) {
@@ -2378,15 +2402,15 @@ ves_icall_get_enum_info (MonoReflectionType *type, MonoEnumInfo *info)
                if (mono_field_is_deleted (field))
                        continue;
                mono_array_set (info->names, gpointer, j, mono_string_new (domain, field->name));
-               if (!field->def_value) {
-                       field->def_value = g_new0 (MonoConstant, 1);
+
+               if (!field->data) {
                        crow = mono_metadata_get_constant_index (enumc->image, MONO_TOKEN_FIELD_DEF | (i+enumc->field.first+1), crow + 1);
-                       field->def_value->type = mono_metadata_decode_row_col (&enumc->image->tables [MONO_TABLE_CONSTANT], crow-1, MONO_CONSTANT_TYPE);
+                       field->def_type = mono_metadata_decode_row_col (&enumc->image->tables [MONO_TABLE_CONSTANT], crow-1, MONO_CONSTANT_TYPE);
                        crow = mono_metadata_decode_row_col (&enumc->image->tables [MONO_TABLE_CONSTANT], crow-1, MONO_CONSTANT_VALUE);
-                       field->def_value->value = (gpointer)mono_metadata_blob_heap (enumc->image, crow);
+                       field->data = (gpointer)mono_metadata_blob_heap (enumc->image, crow);
                }
 
-               p = field->def_value->value;
+               p = field->data;
                len = mono_metadata_decode_blob_size (p, &p);
                switch (enumc->enum_basetype->type) {
                case MONO_TYPE_U1:
@@ -3178,6 +3202,7 @@ ves_icall_System_Reflection_Assembly_GetReferencedAssemblies (MonoReflectionAsse
        MonoAssembly **ptr;
        MonoDomain *domain = mono_object_domain (assembly);
        int i, count = 0;
+       static MonoMethod *create_culture = NULL;
 
        MONO_ARCH_SAVE_REGS;
 
@@ -3188,7 +3213,15 @@ ves_icall_System_Reflection_Assembly_GetReferencedAssemblies (MonoReflectionAsse
        for (ptr = assembly->assembly->image->references; ptr && *ptr; ptr++)
                count++;
 
-       result = mono_array_new (mono_object_domain (assembly), System_Reflection_AssemblyName, count);
+       result = mono_array_new (domain, System_Reflection_AssemblyName, count);
+
+       if (count > 0) {
+               MonoMethodDesc *desc = mono_method_desc_new (
+                       "System.Globalization.CultureInfo:CreateSpecificCulture(string)", TRUE);
+               create_culture = mono_method_desc_search_in_image (desc, mono_defaults.corlib);
+               g_assert (create_culture);
+               mono_method_desc_free (desc);
+       }
 
        for (i = 0; i < count; i++) {
                MonoAssembly *assem = assembly->assembly->image->references [i];
@@ -3204,6 +3237,27 @@ ves_icall_System_Reflection_Assembly_GetReferencedAssemblies (MonoReflectionAsse
                aname->minor = assem->aname.minor;
                aname->build = assem->aname.build;
                aname->revision = assem->aname.revision;
+               aname->revision = assem->aname.revision;
+               aname->hashalg = assem->aname.hash_alg;
+               aname->flags = assem->aname.flags;
+
+               if (create_culture) {
+                       gpointer args [1];
+                       args [0] = mono_string_new (domain, assem->aname.culture);
+                       aname->cultureInfo = mono_runtime_invoke (create_culture, NULL, args, NULL);
+               }
+
+               if (assem->aname.public_key) {
+                       guint32 pkey_len;
+                       const char *pkey_ptr = assem->aname.public_key;
+                       pkey_len = mono_metadata_decode_blob_size (pkey_ptr, &pkey_ptr);
+
+                       aname->publicKey = mono_array_new (domain, mono_defaults.byte_class, pkey_len);
+                       memcpy (mono_array_addr (aname->publicKey, guint8, 0), pkey_ptr, pkey_len);
+               }
+
+               /* public key token isn't copied - the class library will 
+                  automatically generate it from the public key if required */
 
                absolute = g_build_filename (assem->basedir, assem->image->module_name, NULL);
                codebase = g_filename_to_uri (absolute, NULL, NULL);
@@ -3320,8 +3374,8 @@ ves_icall_System_Reflection_Assembly_GetManifestResourceInternal (MonoReflection
                 * this code should only be called after obtaining the 
                 * ResourceInfo and handling the other cases.
                 */
-               g_assert ((impl & IMPLEMENTATION_MASK) == IMPLEMENTATION_FILE);
-               file_idx = impl >> IMPLEMENTATION_BITS;
+               g_assert ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE);
+               file_idx = impl >> MONO_IMPLEMENTATION_BITS;
 
                module = mono_image_load_file_for_image (assembly->assembly->image, file_idx);
                if (!module)
@@ -3362,9 +3416,9 @@ ves_icall_System_Reflection_Assembly_GetManifestResourceInfoInternal (MonoReflec
                info->location = RESOURCE_LOCATION_EMBEDDED | RESOURCE_LOCATION_IN_MANIFEST;
        }
        else {
-               switch (cols [MONO_MANIFEST_IMPLEMENTATION] & IMPLEMENTATION_MASK) {
-               case IMPLEMENTATION_FILE:
-                       i = cols [MONO_MANIFEST_IMPLEMENTATION] >> IMPLEMENTATION_BITS;
+               switch (cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) {
+               case MONO_IMPLEMENTATION_FILE:
+                       i = cols [MONO_MANIFEST_IMPLEMENTATION] >> MONO_IMPLEMENTATION_BITS;
                        table = &assembly->assembly->image->tables [MONO_TABLE_FILE];
                        mono_metadata_decode_row (table, i - 1, file_cols, MONO_FILE_SIZE);
                        val = mono_metadata_string_heap (assembly->assembly->image, file_cols [MONO_FILE_NAME]);
@@ -3375,8 +3429,8 @@ ves_icall_System_Reflection_Assembly_GetManifestResourceInfoInternal (MonoReflec
                                info->location = RESOURCE_LOCATION_EMBEDDED;
                        break;
 
-               case IMPLEMENTATION_ASSEMBLYREF:
-                       i = cols [MONO_MANIFEST_IMPLEMENTATION] >> IMPLEMENTATION_BITS;
+               case MONO_IMPLEMENTATION_ASSEMBLYREF:
+                       i = cols [MONO_MANIFEST_IMPLEMENTATION] >> MONO_IMPLEMENTATION_BITS;
                        info->assembly = mono_assembly_get_object (mono_domain_get (), assembly->assembly->image->references [i - 1]);
 
                        /* Obtain info recursively */
@@ -3384,7 +3438,7 @@ ves_icall_System_Reflection_Assembly_GetManifestResourceInfoInternal (MonoReflec
                        info->location |= RESOURCE_LOCATION_ANOTHER_ASSEMBLY;
                        break;
 
-               case IMPLEMENTATION_EXP_TYPE:
+               case MONO_IMPLEMENTATION_EXP_TYPE:
                        g_assert_not_reached ();
                        break;
                }
@@ -3515,7 +3569,7 @@ ves_icall_System_Reflection_Assembly_GetEntryAssembly (void)
        MONO_ARCH_SAVE_REGS;
 
        if (!domain->entry_assembly)
-               domain = mono_root_domain;
+               domain = mono_get_root_domain ();
 
        return mono_assembly_get_object (domain, domain->entry_assembly);
 }
@@ -4061,7 +4115,7 @@ ves_icall_System_CurrentTimeZone_GetTimeZoneData (guint32 year, MonoArray **data
                                t1 += 60;
                                tt1 = *localtime (&t1);
                        } while (gmt_offset (&tt1, t1) == gmtoff);
-                       
+                       t1+=gmtoff;
                        strftime (tzone, sizeof (tzone), "%Z", &tt);
                        
                        /* Write data, if we're already in daylight saving, we're done. */
@@ -4696,7 +4750,7 @@ ves_icall_System_Configuration_DefaultConfig_get_machine_config_path (void)
 
        MONO_ARCH_SAVE_REGS;
 
-       path = g_build_path (G_DIR_SEPARATOR_S, mono_get_config_dir (), "mono", "machine.config", NULL);
+       path = g_build_path (G_DIR_SEPARATOR_S, mono_get_config_dir (), "mono", mono_get_framework_version (), "machine.config", NULL);
 
 #if defined (PLATFORM_WIN32)
        /* Avoid mixing '/' and '\\' */
@@ -4880,7 +4934,7 @@ mono_ArgIterator_IntGetNextArg (MonoArgIterator *iter)
        iter->args = (char*)iter->args + arg_size;
        iter->next_arg++;
 
-       //g_print ("returning arg %d, type 0x%02x of size %d at %p\n", i, res.type->type, arg_size, res.value);
+       /* g_print ("returning arg %d, type 0x%02x of size %d at %p\n", i, res.type->type, arg_size, res.value); */
 
        return res;
 }
@@ -4906,10 +4960,10 @@ mono_ArgIterator_IntGetNextArgT (MonoArgIterator *iter, MonoType *type)
                arg_size = mono_type_stack_size (res.type, &align);
                iter->args = (char*)iter->args + arg_size;
                iter->next_arg++;
-               //g_print ("returning arg %d, type 0x%02x of size %d at %p\n", i, res.type->type, arg_size, res.value);
+               /* g_print ("returning arg %d, type 0x%02x of size %d at %p\n", i, res.type->type, arg_size, res.value); */
                return res;
        }
-       //g_print ("arg type 0x%02x not found\n", res.type->type);
+       /* g_print ("arg type 0x%02x not found\n", res.type->type); */
 
        res.type = NULL;
        res.value = NULL;
@@ -5026,6 +5080,7 @@ static const IcallEntry appdomain_icalls [] = {
        {"SetData", ves_icall_System_AppDomain_SetData},
        {"createDomain", ves_icall_System_AppDomain_createDomain},
        {"getCurDomain", ves_icall_System_AppDomain_getCurDomain},
+       {"getDomainByID", ves_icall_System_AppDomain_getDomainByID},
        {"getFriendlyName", ves_icall_System_AppDomain_getFriendlyName},
        {"getSetup", ves_icall_System_AppDomain_getSetup}
 };
@@ -5485,11 +5540,17 @@ static const IcallEntry typebuilder_icalls [] = {
        {"setup_internal_class", mono_reflection_setup_internal_class}
 };
 
+static const IcallEntry enumbuilder_icalls [] = {
+       {"setup_enum_type", ves_icall_EnumBuilder_setup_enum_type}
+};
+
 static const IcallEntry runtimehelpers_icalls [] = {
        {"GetObjectValue", ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_GetObjectValue},
+        /* REMOVEME: no longer needed, just so we dont break things when not needed */
        {"GetOffsetToStringData", ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_GetOffsetToStringData},
        {"InitializeArray", ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_InitializeArray},
-       {"RunClassConstructor", ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_RunClassConstructor}
+       {"RunClassConstructor", ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_RunClassConstructor},
+       {"get_OffsetToStringData", ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_GetOffsetToStringData}
 };
 
 static const IcallEntry gchandle_icalls [] = {
@@ -5630,8 +5691,8 @@ static const IcallEntry interlocked_icalls [] = {
 };
 
 static const IcallEntry mutex_icalls [] = {
-       {"CreateMutex_internal", ves_icall_System_Threading_Mutex_CreateMutex_internal},
-       {"ReleaseMutex_internal", ves_icall_System_Threading_Mutex_ReleaseMutex_internal}
+       {"CreateMutex_internal(bool,string,bool&)", ves_icall_System_Threading_Mutex_CreateMutex_internal},
+       {"ReleaseMutex_internal(intptr)", ves_icall_System_Threading_Mutex_ReleaseMutex_internal}
 };
 
 static const IcallEntry nativeevents_icalls [] = {
@@ -5805,6 +5866,7 @@ static const IcallMap icall_entries [] = {
        {"System.Reflection.Emit.AssemblyBuilder", assemblybuilder_icalls, G_N_ELEMENTS (assemblybuilder_icalls)},
        {"System.Reflection.Emit.CustomAttributeBuilder", customattrbuilder_icalls, G_N_ELEMENTS (customattrbuilder_icalls)},
        {"System.Reflection.Emit.DynamicMethod", dynamicmethod_icalls, G_N_ELEMENTS (dynamicmethod_icalls)},
+       {"System.Reflection.Emit.EnumBuilder", enumbuilder_icalls, G_N_ELEMENTS (enumbuilder_icalls)},
        {"System.Reflection.Emit.GenericTypeParameterBuilder", generictypeparambuilder_icalls, G_N_ELEMENTS (generictypeparambuilder_icalls)},
        {"System.Reflection.Emit.MethodBuilder", methodbuilder_icalls, G_N_ELEMENTS (methodbuilder_icalls)},
        {"System.Reflection.Emit.ModuleBuilder", modulebuilder_icalls, G_N_ELEMENTS (modulebuilder_icalls)},
@@ -5848,6 +5910,8 @@ static const IcallMap icall_entries [] = {
 };
 
 static GHashTable *icall_hash = NULL;
+static GHashTable *jit_icall_hash_name = NULL;
+static GHashTable *jit_icall_hash_addr = NULL;
 
 void
 mono_init_icall (void)
@@ -6022,3 +6086,157 @@ mono_lookup_internal_call (MonoMethod *method)
        return NULL;
 }
 
+static MonoType*
+type_from_typename (char *typename)
+{
+       MonoClass *klass;
+
+       if (!strcmp (typename, "int"))
+               klass = mono_defaults.int_class;
+       else if (!strcmp (typename, "ptr"))
+               klass = mono_defaults.int_class;
+       else if (!strcmp (typename, "void"))
+               klass = mono_defaults.void_class;
+       else if (!strcmp (typename, "int32"))
+               klass = mono_defaults.int32_class;
+       else if (!strcmp (typename, "uint32"))
+               klass = mono_defaults.uint32_class;
+       else if (!strcmp (typename, "long"))
+               klass = mono_defaults.int64_class;
+       else if (!strcmp (typename, "ulong"))
+               klass = mono_defaults.uint64_class;
+       else if (!strcmp (typename, "float"))
+               klass = mono_defaults.single_class;
+       else if (!strcmp (typename, "double"))
+               klass = mono_defaults.double_class;
+       else if (!strcmp (typename, "object"))
+               klass = mono_defaults.object_class;
+       else if (!strcmp (typename, "obj"))
+               klass = mono_defaults.object_class;
+       else {
+               g_error (typename);
+               g_assert_not_reached ();
+       }
+       return &klass->byval_arg;
+}
+
+MonoMethodSignature*
+mono_create_icall_signature (const char *sigstr)
+{
+       gchar **parts;
+       int i, len;
+       gchar **tmp;
+       MonoMethodSignature *res;
+
+       mono_loader_lock ();
+       res = g_hash_table_lookup (mono_defaults.corlib->helper_signatures, sigstr);
+       if (res) {
+               mono_loader_unlock ();
+               return res;
+       }
+
+       parts = g_strsplit (sigstr, " ", 256);
+
+       tmp = parts;
+       len = 0;
+       while (*tmp) {
+               len ++;
+               tmp ++;
+       }
+
+       res = mono_metadata_signature_alloc (mono_defaults.corlib, len - 1);
+       res->pinvoke = 1;
+
+#ifdef PLATFORM_WIN32
+       /* 
+        * Under windows, the default pinvoke calling convention is STDCALL but
+        * we need CDECL.
+        */
+       res->call_convention = MONO_CALL_C;
+#endif
+
+       res->ret = type_from_typename (parts [0]);
+       for (i = 1; i < len; ++i) {
+               res->params [i - 1] = type_from_typename (parts [i]);
+       }
+
+       g_strfreev (parts);
+
+       g_hash_table_insert (mono_defaults.corlib->helper_signatures, sigstr, res);
+
+       mono_loader_unlock ();
+
+       return res;
+}
+
+MonoJitICallInfo *
+mono_find_jit_icall_by_name (const char *name)
+{
+       MonoJitICallInfo *info;
+       g_assert (jit_icall_hash_name);
+
+       mono_loader_lock ();
+       info = g_hash_table_lookup (jit_icall_hash_name, name);
+       mono_loader_unlock ();
+       return info;
+}
+
+MonoJitICallInfo *
+mono_find_jit_icall_by_addr (gconstpointer addr)
+{
+       MonoJitICallInfo *info;
+       g_assert (jit_icall_hash_addr);
+
+       mono_loader_lock ();
+       info = g_hash_table_lookup (jit_icall_hash_addr, (gpointer)addr);
+       mono_loader_unlock ();
+
+       return info;
+}
+
+void
+mono_register_jit_icall_wrapper (MonoJitICallInfo *info, gconstpointer wrapper)
+{
+       mono_loader_lock ();
+       g_hash_table_insert (jit_icall_hash_addr, (gpointer)info->wrapper, info);       
+       mono_loader_unlock ();
+}
+
+MonoJitICallInfo *
+mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save)
+{
+       MonoJitICallInfo *info;
+       
+       g_assert (func);
+       g_assert (name);
+
+       mono_loader_lock ();
+
+       if (!jit_icall_hash_name) {
+               jit_icall_hash_name = g_hash_table_new (g_str_hash, g_str_equal);
+               jit_icall_hash_addr = g_hash_table_new (NULL, NULL);
+       }
+
+       if (g_hash_table_lookup (jit_icall_hash_name, name)) {
+               g_warning ("jit icall already defined \"%s\"\n", name);
+               g_assert_not_reached ();
+       }
+
+       info = g_new (MonoJitICallInfo, 1);
+       
+       info->name = name;
+       info->func = func;
+       info->sig = sig;
+
+       if (is_save) {
+               info->wrapper = func;
+       } else {
+               info->wrapper = NULL;
+       }
+
+       g_hash_table_insert (jit_icall_hash_name, (gpointer)info->name, info);
+       g_hash_table_insert (jit_icall_hash_addr, (gpointer)func, info);
+
+       mono_loader_unlock ();
+       return info;
+}