static inline void dynamic_image_lock (MonoDynamicImage *image) { MONO_ENTER_GC_SAFE; mono_image_lock ((MonoImage*)image); MONO_EXIT_GC_SAFE; }
static MonoMethod * create_method_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *signature, int max_stack) { MonoMethodHeader *header; MonoMethodWrapper *mw; MonoImage *image; MonoMethod *method; GList *l; int i; g_assert (mb != NULL); image = m_class_get_image (mb->method->klass); if (mb->dynamic) { method = mb->method; mw = (MonoMethodWrapper*)method; method->name = mb->name; method->dynamic = TRUE; mw->header = header = (MonoMethodHeader *) g_malloc0 (MONO_SIZEOF_METHOD_HEADER + mb->locals * sizeof (MonoType *)); header->code = mb->code; for (i = 0, l = mb->locals_list; l; l = l->next, i++) { header->locals [i] = (MonoType*)l->data; } } else { /* Realloc the method info into a mempool */ method = (MonoMethod *)mono_image_alloc0 (image, sizeof (MonoMethodWrapper)); memcpy (method, mb->method, sizeof (MonoMethodWrapper)); mw = (MonoMethodWrapper*) method; if (mb->no_dup_name) method->name = mb->name; else method->name = mono_image_strdup (image, mb->name); mw->header = header = (MonoMethodHeader *) mono_image_alloc0 (image, MONO_SIZEOF_METHOD_HEADER + mb->locals * sizeof (MonoType *)); header->code = (const unsigned char *)mono_image_alloc (image, mb->pos); memcpy ((char*)header->code, mb->code, mb->pos); for (i = 0, l = mb->locals_list; l; l = l->next, i++) { header->locals [i] = (MonoType*)l->data; } } /* Free the locals list so mono_mb_free () doesn't free the types twice */ g_list_free (mb->locals_list); mb->locals_list = NULL; method->signature = signature; if (!signature->hasthis) method->flags |= METHOD_ATTRIBUTE_STATIC; if (max_stack < 8) max_stack = 8; header->max_stack = max_stack; header->code_size = mb->pos; header->num_locals = mb->locals; header->init_locals = mb->init_locals; header->volatile_args = mb->volatile_args; header->volatile_locals = mb->volatile_locals; mb->volatile_args = NULL; mb->volatile_locals = NULL; header->num_clauses = mb->num_clauses; header->clauses = mb->clauses; method->skip_visibility = mb->skip_visibility; i = g_list_length ((GList *)mw->method_data); if (i) { GList *tmp; void **data; l = g_list_reverse ((GList *)mw->method_data); if (method_is_dynamic (method)) data = (void **)g_malloc (sizeof (gpointer) * (i + 1)); else data = (void **)mono_image_alloc (image, sizeof (gpointer) * (i + 1)); /* store the size in the first element */ data [0] = GUINT_TO_POINTER (i); i = 1; for (tmp = l; tmp; tmp = tmp->next) { data [i++] = tmp->data; } g_list_free (l); mw->method_data = data; } /*{ static int total_code = 0; static int total_alloc = 0; total_code += mb->pos; total_alloc += mb->code_size; g_print ("code size: %d of %d (allocated: %d)\n", mb->pos, total_code, total_alloc); }*/ #ifdef DEBUG_RUNTIME_CODE printf ("RUNTIME CODE FOR %s\n", mono_method_full_name (method, TRUE)); printf ("%s\n", mono_disasm_code (&marshal_dh, method, mb->code, mb->code + mb->pos)); #endif if (mb->param_names) { char **param_names = (char **)mono_image_alloc0 (image, signature->param_count * sizeof (gpointer)); for (i = 0; i < signature->param_count; ++i) param_names [i] = mono_image_strdup (image, mb->param_names [i]); mono_image_lock (image); if (!image->wrapper_param_names) image->wrapper_param_names = g_hash_table_new (NULL, NULL); g_hash_table_insert (image->wrapper_param_names, method, param_names); mono_image_unlock (image); } return method; }
static gboolean check_image_may_reference_image(MonoImage *from, MonoImage *to) { if (to == from) // Shortcut return TRUE; // Corlib is never unloaded, and all images implicitly reference it. // Some images avoid explicitly referencing it as an optimization, so special-case it here. if (to == mono_defaults.corlib) return TRUE; // Non-dynamic images may NEVER reference dynamic images if (to->dynamic && !from->dynamic) return FALSE; // FIXME: We currently give a dynamic images a pass on the reference rules. // Dynamic images may ALWAYS reference non-dynamic images. // We allow this because the dynamic image code is known "messy", and in theory it is already // protected because dynamic images can only reference classes their assembly has retained. // However, long term, we should make this rigorous. if (from->dynamic && !to->dynamic) return TRUE; gboolean success = FALSE; // Images to inspect on this pass, images to inspect on the next pass GPtrArray *current = g_ptr_array_sized_new (1), *next = g_ptr_array_new (); // Because in practice the image graph contains cycles, we must track which images we've visited GHashTable *visited = g_hash_table_new (NULL, NULL); #define CHECK_IMAGE_VISIT(i) check_image_search (visited, next, (i), to, &success) CHECK_IMAGE_VISIT (from); // Initially "next" contains only from node // For each pass exhaust the "to check" queue while filling up the "check next" queue while (!success && next->len > 0) // Halt on success or when out of nodes to process { // Swap "current" and "next" and clear next GPtrArray *temp = current; current = next; next = temp; g_ptr_array_set_size (next, 0); int current_idx; for(current_idx = 0; current_idx < current->len; current_idx++) { MonoImage *checking = g_ptr_array_index (current, current_idx); // CAST? mono_image_lock (checking); // For each queued image visit all directly referenced images int inner_idx; for (inner_idx = 0; !success && inner_idx < checking->module_count; inner_idx++) { CHECK_IMAGE_VISIT (checking->modules[inner_idx]); } for (inner_idx = 0; !success && inner_idx < checking->nreferences; inner_idx++) { // References are lazy-loaded and thus allowed to be NULL. // If they are NULL, we don't care about them for this search, because they haven't impacted ref_count yet. if (checking->references[inner_idx]) { CHECK_IMAGE_VISIT (checking->references[inner_idx]->image); } } mono_image_unlock (checking); } } g_ptr_array_free (current, TRUE); g_ptr_array_free (next, TRUE); g_hash_table_destroy (visited); return success; }