1 /**
2  * \file
3  * mono Ahead of Time compiler
4  *
5  * Author:
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *   Zoltan Varga (vargaz@gmail.com)
8  *
9  * (C) 2002 Ximian, Inc.
10  * Copyright 2003-2011 Novell, Inc.
11  * Copyright 2011 Xamarin, Inc.
12  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13  */
14 
15 #include "config.h"
16 #include <sys/types.h>
17 #ifdef HAVE_UNISTD_H
18 #include <unistd.h>
19 #endif
20 #include <fcntl.h>
21 #include <string.h>
22 #ifdef HAVE_SYS_MMAN_H
23 #include <sys/mman.h>
24 #endif
25 
26 #if HOST_WIN32
27 #include <winsock2.h>
28 #include <windows.h>
29 #endif
30 
31 #ifdef HAVE_EXECINFO_H
32 #include <execinfo.h>
33 #endif
34 
35 #include <errno.h>
36 #include <sys/stat.h>
37 
38 #ifdef HAVE_SYS_WAIT_H
39 #include <sys/wait.h>  /* for WIFEXITED, WEXITSTATUS */
40 #endif
41 
42 #include <mono/metadata/abi-details.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/class.h>
45 #include <mono/metadata/object.h>
46 #include <mono/metadata/tokentype.h>
47 #include <mono/metadata/appdomain.h>
48 #include <mono/metadata/debug-helpers.h>
49 #include <mono/metadata/assembly.h>
50 #include <mono/metadata/assembly-internals.h>
51 #include <mono/metadata/metadata-internals.h>
52 #include <mono/metadata/marshal.h>
53 #include <mono/metadata/gc-internals.h>
54 #include <mono/metadata/threads-types.h>
55 #include <mono/metadata/mono-endian.h>
56 #include <mono/utils/mono-logger-internals.h>
57 #include <mono/utils/mono-mmap.h>
58 #include <mono/utils/mono-compiler.h>
59 #include <mono/utils/mono-counters.h>
60 #include <mono/utils/mono-digest.h>
61 #include <mono/utils/mono-threads-coop.h>
62 
63 #include "mini.h"
64 #include "seq-points.h"
65 #include "version.h"
66 #include "debugger-agent.h"
67 #include "aot-compiler.h"
68 #include "aot-runtime.h"
69 #include "jit-icalls.h"
70 #include "mini-runtime.h"
71 
72 #ifndef DISABLE_AOT
73 
74 #ifdef TARGET_OSX
75 #define ENABLE_AOT_CACHE
76 #endif
77 
78 /* Number of got entries shared between the JIT and LLVM GOT */
79 #define N_COMMON_GOT_ENTRIES 10
80 
81 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
82 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
83 #define ROUND_DOWN(VALUE,SIZE)	((VALUE) & ~((SIZE) - 1))
84 
85 typedef struct {
86 	int method_index;
87 	MonoJitInfo *jinfo;
88 } JitInfoMap;
89 
90 typedef struct MonoAotModule {
91 	char *aot_name;
92 	/* Pointer to the Global Offset Table */
93 	gpointer *got;
94 	gpointer *llvm_got;
95 	gpointer *shared_got;
96 	GHashTable *name_cache;
97 	GHashTable *extra_methods;
98 	/* Maps methods to their code */
99 	GHashTable *method_to_code;
100 	/* Maps pointers into the method info to the methods themselves */
101 	GHashTable *method_ref_to_method;
102 	MonoAssemblyName *image_names;
103 	char **image_guids;
104 	MonoAssembly *assembly;
105 	MonoImage **image_table;
106 	guint32 image_table_len;
107 	gboolean out_of_date;
108 	gboolean plt_inited;
109 	gboolean got_initializing;
110 	guint8 *mem_begin;
111 	guint8 *mem_end;
112 	guint8 *jit_code_start;
113 	guint8 *jit_code_end;
114 	guint8 *llvm_code_start;
115 	guint8 *llvm_code_end;
116 	guint8 *plt;
117 	guint8 *plt_end;
118 	guint8 *blob;
119 	gpointer weak_field_indexes;
120 	/* Maps method indexes to their code */
121 	gpointer *methods;
122 	/* Sorted array of method addresses */
123 	gpointer *sorted_methods;
124 	/* Method indexes for each method in sorted_methods */
125 	int *sorted_method_indexes;
126 	/* The length of the two tables above */
127 	int sorted_methods_len;
128 	guint32 *method_info_offsets;
129 	guint32 *ex_info_offsets;
130 	guint32 *class_info_offsets;
131 	guint32 *got_info_offsets;
132 	guint32 *llvm_got_info_offsets;
133 	guint32 *methods_loaded;
134 	guint16 *class_name_table;
135 	guint32 *extra_method_table;
136 	guint32 *extra_method_info_offsets;
137 	guint32 *unbox_trampolines;
138 	guint32 *unbox_trampolines_end;
139 	guint32 *unbox_trampoline_addresses;
140 	guint8 *unwind_info;
141 
142 	/* Points to the mono EH data created by LLVM */
143 	guint8 *mono_eh_frame;
144 
145 	/* Points to the data tables if MONO_AOT_FILE_FLAG_SEPARATE_DATA is set */
146 	gpointer tables [MONO_AOT_TABLE_NUM];
147 	/* Points to the trampolines */
148 	guint8 *trampolines [MONO_AOT_TRAMP_NUM];
149 	/* The first unused trampoline of each kind */
150 	guint32 trampoline_index [MONO_AOT_TRAMP_NUM];
151 
152 	gboolean use_page_trampolines;
153 
154 	MonoAotFileInfo info;
155 
156 	gpointer *globals;
157 	MonoDl *sofile;
158 
159 	JitInfoMap *async_jit_info_table;
160 	mono_mutex_t mutex;
161 } MonoAotModule;
162 
163 typedef struct {
164 	void *next;
165 	unsigned char *trampolines;
166 	unsigned char *trampolines_end;
167 } TrampolinePage;
168 
169 static GHashTable *aot_modules;
170 #define mono_aot_lock() mono_os_mutex_lock (&aot_mutex)
171 #define mono_aot_unlock() mono_os_mutex_unlock (&aot_mutex)
172 static mono_mutex_t aot_mutex;
173 
174 /*
175  * Maps assembly names to the mono_aot_module_<NAME>_info symbols in the
176  * AOT modules registered by mono_aot_register_module ().
177  */
178 static GHashTable *static_aot_modules;
179 /*
180  * Same as above, but tracks module that must be loaded before others are
181  * This allows us to have a "container" module which contains resources for
182  * other modules. Since it doesn't provide methods for a managed assembly,
183  * and it needs to be fully loaded by the time the other code needs it, it
184  * must be eagerly loaded before other modules.
185  */
186 static char *container_assm_name = NULL;
187 static MonoAotModule *container_amodule = NULL;
188 
189 /*
190  * Maps MonoJitInfo* to the aot module they belong to, this can be different
191  * from ji->method->klass->image's aot module for generic instances.
192  */
193 static GHashTable *ji_to_amodule;
194 
195 /*
196  * Whenever to AOT compile loaded assemblies on demand and store them in
197  * a cache.
198  */
199 static gboolean enable_aot_cache = FALSE;
200 
201 static gboolean mscorlib_aot_loaded;
202 
203 /* For debugging */
204 static gint32 mono_last_aot_method = -1;
205 
206 static gboolean make_unreadable = FALSE;
207 static guint32 name_table_accesses = 0;
208 static guint32 n_pagefaults = 0;
209 
210 /* Used to speed-up find_aot_module () */
211 static gsize aot_code_low_addr = (gssize)-1;
212 static gsize aot_code_high_addr = 0;
213 
214 /* Stats */
215 static gint32 async_jit_info_size;
216 
217 static GHashTable *aot_jit_icall_hash;
218 
219 #ifdef MONOTOUCH
220 #define USE_PAGE_TRAMPOLINES ((MonoAotModule*)mono_defaults.corlib->aot_module)->use_page_trampolines
221 #else
222 #define USE_PAGE_TRAMPOLINES 0
223 #endif
224 
225 #define mono_aot_page_lock() mono_os_mutex_lock (&aot_page_mutex)
226 #define mono_aot_page_unlock() mono_os_mutex_unlock (&aot_page_mutex)
227 static mono_mutex_t aot_page_mutex;
228 
229 static MonoAotModule *mscorlib_aot_module;
230 
231 /* Embedding API hooks to load the AOT data for AOT images compiled with MONO_AOT_FILE_FLAG_SEPARATE_DATA */
232 static MonoLoadAotDataFunc aot_data_load_func;
233 static MonoFreeAotDataFunc aot_data_free_func;
234 static gpointer aot_data_func_user_data;
235 
236 static void
237 init_plt (MonoAotModule *info);
238 
239 static void
240 compute_llvm_code_range (MonoAotModule *amodule, guint8 **code_start, guint8 **code_end);
241 
242 static gboolean
243 init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, MonoClass *init_class, MonoGenericContext *context, MonoError *error);
244 
245 static MonoJumpInfo*
246 decode_patches (MonoAotModule *amodule, MonoMemPool *mp, int n_patches, gboolean llvm, guint32 *got_offsets);
247 
248 static inline void
amodule_lock(MonoAotModule * amodule)249 amodule_lock (MonoAotModule *amodule)
250 {
251 	mono_os_mutex_lock (&amodule->mutex);
252 }
253 
254 static inline void
amodule_unlock(MonoAotModule * amodule)255 amodule_unlock (MonoAotModule *amodule)
256 {
257 	mono_os_mutex_unlock (&amodule->mutex);
258 }
259 
260 /*
261  * load_image:
262  *
263  *   Load one of the images referenced by AMODULE. Returns NULL if the image is not
264  * found, and sets @error for what happened
265  */
266 static MonoImage *
load_image(MonoAotModule * amodule,int index,MonoError * error)267 load_image (MonoAotModule *amodule, int index, MonoError *error)
268 {
269 	MonoAssembly *assembly;
270 	MonoImageOpenStatus status;
271 
272 	g_assert (index < amodule->image_table_len);
273 
274 	error_init (error);
275 
276 	if (amodule->image_table [index])
277 		return amodule->image_table [index];
278 	if (amodule->out_of_date) {
279 		mono_error_set_bad_image_name (error, amodule->aot_name, "Image out of date");
280 		return NULL;
281 	}
282 
283 	assembly = mono_assembly_load (&amodule->image_names [index], amodule->assembly->basedir, &status);
284 	if (!assembly) {
285 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: module %s is unusable because dependency %s is not found.", amodule->aot_name, amodule->image_names [index].name);
286 		mono_error_set_bad_image_name (error, amodule->aot_name, "module is unusable because dependency %s is not found (error %d).\n", amodule->image_names [index].name, status);
287 		amodule->out_of_date = TRUE;
288 		return NULL;
289 	}
290 
291 	if (strcmp (assembly->image->guid, amodule->image_guids [index])) {
292 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: module %s is unusable (GUID of dependent assembly %s doesn't match (expected '%s', got '%s').", amodule->aot_name, amodule->image_names [index].name, amodule->image_guids [index], assembly->image->guid);
293 		mono_error_set_bad_image_name (error, amodule->aot_name, "module is unusable (GUID of dependent assembly %s doesn't match (expected '%s', got '%s').", amodule->image_names [index].name, amodule->image_guids [index], assembly->image->guid);
294 		amodule->out_of_date = TRUE;
295 		return NULL;
296 	}
297 
298 	amodule->image_table [index] = assembly->image;
299 	return assembly->image;
300 }
301 
302 static inline gint32
decode_value(guint8 * ptr,guint8 ** rptr)303 decode_value (guint8 *ptr, guint8 **rptr)
304 {
305 	guint8 b = *ptr;
306 	gint32 len;
307 
308 	if ((b & 0x80) == 0){
309 		len = b;
310 		++ptr;
311 	} else if ((b & 0x40) == 0){
312 		len = ((b & 0x3f) << 8 | ptr [1]);
313 		ptr += 2;
314 	} else if (b != 0xff) {
315 		len = ((b & 0x1f) << 24) |
316 			(ptr [1] << 16) |
317 			(ptr [2] << 8) |
318 			ptr [3];
319 		ptr += 4;
320 	}
321 	else {
322 		len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4];
323 		ptr += 5;
324 	}
325 	if (rptr)
326 		*rptr = ptr;
327 
328 	//printf ("DECODE: %d.\n", len);
329 	return len;
330 }
331 
332 /*
333  * mono_aot_get_offset:
334  *
335  *   Decode an offset table emitted by emit_offset_table (), returning the INDEXth
336  * entry.
337  */
338 static guint32
mono_aot_get_offset(guint32 * table,int index)339 mono_aot_get_offset (guint32 *table, int index)
340 {
341 	int i, group, ngroups, index_entry_size;
342 	int start_offset, offset, group_size;
343 	guint8 *data_start, *p;
344 	guint32 *index32 = NULL;
345 	guint16 *index16 = NULL;
346 
347 	/* noffsets = table [0]; */
348 	group_size = table [1];
349 	ngroups = table [2];
350 	index_entry_size = table [3];
351 	group = index / group_size;
352 
353 	if (index_entry_size == 2) {
354 		index16 = (guint16*)&table [4];
355 		data_start = (guint8*)&index16 [ngroups];
356 		p = data_start + index16 [group];
357 	} else {
358 		index32 = (guint32*)&table [4];
359 		data_start = (guint8*)&index32 [ngroups];
360 		p = data_start + index32 [group];
361 	}
362 
363 	/* offset will contain the value of offsets [group * group_size] */
364 	offset = start_offset = decode_value (p, &p);
365 	for (i = group * group_size + 1; i <= index; ++i) {
366 		offset += decode_value (p, &p);
367 	}
368 
369 	//printf ("Offset lookup: %d -> %d, start=%d, p=%d\n", index, offset, start_offset, table [3 + group]);
370 
371 	return offset;
372 }
373 
374 static MonoMethod*
375 decode_resolve_method_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf, MonoError *error);
376 
377 static MonoClass*
378 decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf, MonoError *error);
379 
380 static MonoType*
381 decode_type (MonoAotModule *module, guint8 *buf, guint8 **endbuf, MonoError *error);
382 
383 static MonoGenericInst*
decode_generic_inst(MonoAotModule * module,guint8 * buf,guint8 ** endbuf,MonoError * error)384 decode_generic_inst (MonoAotModule *module, guint8 *buf, guint8 **endbuf, MonoError *error)
385 {
386 	int type_argc, i;
387 	MonoType **type_argv;
388 	MonoGenericInst *inst;
389 	guint8 *p = buf;
390 
391 	error_init (error);
392 	type_argc = decode_value (p, &p);
393 	type_argv = g_new0 (MonoType*, type_argc);
394 
395 	for (i = 0; i < type_argc; ++i) {
396 		MonoClass *pclass = decode_klass_ref (module, p, &p, error);
397 		if (!pclass) {
398 			g_free (type_argv);
399 			return NULL;
400 		}
401 		type_argv [i] = &pclass->byval_arg;
402 	}
403 
404 	inst = mono_metadata_get_generic_inst (type_argc, type_argv);
405 	g_free (type_argv);
406 
407 	*endbuf = p;
408 
409 	return inst;
410 }
411 
412 static gboolean
decode_generic_context(MonoAotModule * module,MonoGenericContext * ctx,guint8 * buf,guint8 ** endbuf,MonoError * error)413 decode_generic_context (MonoAotModule *module, MonoGenericContext *ctx, guint8 *buf, guint8 **endbuf, MonoError *error)
414 {
415 	guint8 *p = buf;
416 	guint8 *p2;
417 	int argc;
418 	error_init (error);
419 
420 	p2 = p;
421 	argc = decode_value (p, &p);
422 	if (argc) {
423 		p = p2;
424 		ctx->class_inst = decode_generic_inst (module, p, &p, error);
425 		if (!ctx->class_inst)
426 			return FALSE;
427 	}
428 	p2 = p;
429 	argc = decode_value (p, &p);
430 	if (argc) {
431 		p = p2;
432 		ctx->method_inst = decode_generic_inst (module, p, &p, error);
433 		if (!ctx->method_inst)
434 			return FALSE;
435 	}
436 
437 	*endbuf = p;
438 	return TRUE;
439 }
440 
441 static MonoClass*
decode_klass_ref(MonoAotModule * module,guint8 * buf,guint8 ** endbuf,MonoError * error)442 decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf, MonoError *error)
443 {
444 	MonoImage *image;
445 	MonoClass *klass = NULL, *eklass;
446 	guint32 token, rank, idx;
447 	guint8 *p = buf;
448 	int reftype;
449 
450 	error_init (error);
451 	reftype = decode_value (p, &p);
452 	if (reftype == 0) {
453 		*endbuf = p;
454 		mono_error_set_bad_image_name (error, module->aot_name, "Decoding a null class ref");
455 		return NULL;
456 	}
457 
458 	switch (reftype) {
459 	case MONO_AOT_TYPEREF_TYPEDEF_INDEX:
460 		idx = decode_value (p, &p);
461 		image = load_image (module, 0, error);
462 		if (!image)
463 			return NULL;
464 		klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF + idx, error);
465 		break;
466 	case MONO_AOT_TYPEREF_TYPEDEF_INDEX_IMAGE:
467 		idx = decode_value (p, &p);
468 		image = load_image (module, decode_value (p, &p), error);
469 		if (!image)
470 			return NULL;
471 		klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF + idx, error);
472 		break;
473 	case MONO_AOT_TYPEREF_TYPESPEC_TOKEN:
474 		token = decode_value (p, &p);
475 		image = module->assembly->image;
476 		if (!image) {
477 			mono_error_set_bad_image_name (error, module->aot_name, "No image associated with the aot module");
478 			return NULL;
479 		}
480 		klass = mono_class_get_checked (image, token, error);
481 		break;
482 	case MONO_AOT_TYPEREF_GINST: {
483 		MonoClass *gclass;
484 		MonoGenericContext ctx;
485 		MonoType *type;
486 
487 		gclass = decode_klass_ref (module, p, &p, error);
488 		if (!gclass)
489 			return NULL;
490 		g_assert (mono_class_is_gtd (gclass));
491 
492 		memset (&ctx, 0, sizeof (ctx));
493 		ctx.class_inst = decode_generic_inst (module, p, &p, error);
494 		if (!ctx.class_inst)
495 			return NULL;
496 		type = mono_class_inflate_generic_type_checked (&gclass->byval_arg, &ctx, error);
497 		if (!type)
498 			return NULL;
499 		klass = mono_class_from_mono_type (type);
500 		mono_metadata_free_type (type);
501 		break;
502 	}
503 	case MONO_AOT_TYPEREF_VAR: {
504 		MonoType *t = NULL;
505 		MonoGenericContainer *container = NULL;
506 		gboolean has_constraint = decode_value (p, &p);
507 
508 		if (has_constraint) {
509 			MonoClass *par_klass;
510 			MonoType *gshared_constraint;
511 
512 			gshared_constraint = decode_type (module, p, &p, error);
513 			if (!gshared_constraint)
514 				return NULL;
515 
516 			par_klass = decode_klass_ref (module, p, &p, error);
517 			if (!par_klass)
518 				return NULL;
519 
520 			t = mini_get_shared_gparam (&par_klass->byval_arg, gshared_constraint);
521 			mono_metadata_free_type (gshared_constraint);
522 			klass = mono_class_from_mono_type (t);
523 		} else {
524 			int type = decode_value (p, &p);
525 			int num = decode_value (p, &p);
526 			gboolean is_not_anonymous = decode_value (p, &p);
527 
528 			if (is_not_anonymous) {
529 				gboolean is_method = decode_value (p, &p);
530 
531 				if (is_method) {
532 					MonoMethod *method_def;
533 					g_assert (type == MONO_TYPE_MVAR);
534 					method_def = decode_resolve_method_ref (module, p, &p, error);
535 					if (!method_def)
536 						return NULL;
537 
538 					container = mono_method_get_generic_container (method_def);
539 				} else {
540 					MonoClass *class_def;
541 					g_assert (type == MONO_TYPE_VAR);
542 					class_def = decode_klass_ref (module, p, &p, error);
543 					if (!class_def)
544 						return NULL;
545 
546 					container = mono_class_try_get_generic_container (class_def); //FIXME is this a case for a try_get?
547 				}
548 			} else {
549 				// We didn't decode is_method, so we have to infer it from type enum.
550 				container = get_anonymous_container_for_image (module->assembly->image, type == MONO_TYPE_MVAR);
551 			}
552 
553 			t = g_new0 (MonoType, 1);
554 			t->type = (MonoTypeEnum)type;
555 			if (is_not_anonymous) {
556 				t->data.generic_param = mono_generic_container_get_param (container, num);
557 			} else {
558 				/* Anonymous */
559 				MonoGenericParam *par = (MonoGenericParam*)mono_image_alloc0 (module->assembly->image, sizeof (MonoGenericParamFull));
560 				par->owner = container;
561 				par->num = num;
562 				t->data.generic_param = par;
563 				((MonoGenericParamFull*)par)->info.name = make_generic_name_string (module->assembly->image, num);
564 			}
565 			// FIXME: Maybe use types directly to avoid
566 			// the overhead of creating MonoClass-es
567 			klass = mono_class_from_mono_type (t);
568 
569 			g_free (t);
570 		}
571 		break;
572 	}
573 	case MONO_AOT_TYPEREF_ARRAY:
574 		/* Array */
575 		rank = decode_value (p, &p);
576 		eklass = decode_klass_ref (module, p, &p, error);
577 		if (!eklass)
578 			return NULL;
579 		klass = mono_array_class_get (eklass, rank);
580 		break;
581 	case MONO_AOT_TYPEREF_PTR: {
582 		MonoType *t;
583 
584 		t = decode_type (module, p, &p, error);
585 		if (!t)
586 			return NULL;
587 		klass = mono_class_from_mono_type (t);
588 		g_free (t);
589 		break;
590 	}
591 	case MONO_AOT_TYPEREF_BLOB_INDEX: {
592 		guint32 offset = decode_value (p, &p);
593 		guint8 *p2;
594 
595 		p2 = module->blob + offset;
596 		klass = decode_klass_ref (module, p2, &p2, error);
597 		break;
598 	}
599 	default:
600 		mono_error_set_bad_image_name (error, module->aot_name, "Invalid klass reftype %d", reftype);
601 	}
602 	//g_assert (klass);
603 	//printf ("BLA: %s\n", mono_type_full_name (&klass->byval_arg));
604 	*endbuf = p;
605 	return klass;
606 }
607 
608 static MonoClassField*
decode_field_info(MonoAotModule * module,guint8 * buf,guint8 ** endbuf)609 decode_field_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
610 {
611 	MonoError error;
612 	MonoClass *klass = decode_klass_ref (module, buf, &buf, &error);
613 	guint32 token;
614 	guint8 *p = buf;
615 
616 	if (!klass) {
617 		mono_error_cleanup (&error); /* FIXME don't swallow the error */
618 		return NULL;
619 	}
620 
621 	token = MONO_TOKEN_FIELD_DEF + decode_value (p, &p);
622 
623 	*endbuf = p;
624 
625 	return mono_class_get_field (klass, token);
626 }
627 
628 /*
629  * Parse a MonoType encoded by encode_type () in aot-compiler.c. Return malloc-ed
630  * memory.
631  */
632 static MonoType*
decode_type(MonoAotModule * module,guint8 * buf,guint8 ** endbuf,MonoError * error)633 decode_type (MonoAotModule *module, guint8 *buf, guint8 **endbuf, MonoError *error)
634 {
635 	guint8 *p = buf;
636 	MonoType *t;
637 
638 	t = (MonoType *)g_malloc0 (sizeof (MonoType));
639 	error_init (error);
640 
641 	while (TRUE) {
642 		if (*p == MONO_TYPE_PINNED) {
643 			t->pinned = TRUE;
644 			++p;
645 		} else if (*p == MONO_TYPE_BYREF) {
646 			t->byref = TRUE;
647 			++p;
648 		} else {
649 			break;
650 		}
651 	}
652 
653 	t->type = (MonoTypeEnum)*p;
654 	++p;
655 
656 	switch (t->type) {
657 	case MONO_TYPE_VOID:
658 	case MONO_TYPE_BOOLEAN:
659 	case MONO_TYPE_CHAR:
660 	case MONO_TYPE_I1:
661 	case MONO_TYPE_U1:
662 	case MONO_TYPE_I2:
663 	case MONO_TYPE_U2:
664 	case MONO_TYPE_I4:
665 	case MONO_TYPE_U4:
666 	case MONO_TYPE_I8:
667 	case MONO_TYPE_U8:
668 	case MONO_TYPE_R4:
669 	case MONO_TYPE_R8:
670 	case MONO_TYPE_I:
671 	case MONO_TYPE_U:
672 	case MONO_TYPE_STRING:
673 	case MONO_TYPE_OBJECT:
674 	case MONO_TYPE_TYPEDBYREF:
675 		break;
676 	case MONO_TYPE_VALUETYPE:
677 	case MONO_TYPE_CLASS:
678 		t->data.klass = decode_klass_ref (module, p, &p, error);
679 		if (!t->data.klass)
680 			goto fail;
681 		break;
682 	case MONO_TYPE_SZARRAY:
683 		t->data.klass = decode_klass_ref (module, p, &p, error);
684 
685 		if (!t->data.klass)
686 			goto fail;
687 		break;
688 	case MONO_TYPE_PTR:
689 		t->data.type = decode_type (module, p, &p, error);
690 		if (!t->data.type)
691 			goto fail;
692 		break;
693 	case MONO_TYPE_GENERICINST: {
694 		MonoClass *gclass;
695 		MonoGenericContext ctx;
696 		MonoType *type;
697 		MonoClass *klass;
698 
699 		gclass = decode_klass_ref (module, p, &p, error);
700 		if (!gclass)
701 			goto fail;
702 		g_assert (mono_class_is_gtd (gclass));
703 
704 		memset (&ctx, 0, sizeof (ctx));
705 		ctx.class_inst = decode_generic_inst (module, p, &p, error);
706 		if (!ctx.class_inst)
707 			goto fail;
708 		type = mono_class_inflate_generic_type_checked (&gclass->byval_arg, &ctx, error);
709 		if (!type)
710 			goto fail;
711 		klass = mono_class_from_mono_type (type);
712 		t->data.generic_class = mono_class_get_generic_class (klass);
713 		break;
714 	}
715 	case MONO_TYPE_ARRAY: {
716 		MonoArrayType *array;
717 		int i;
718 
719 		// FIXME: memory management
720 		array = g_new0 (MonoArrayType, 1);
721 		array->eklass = decode_klass_ref (module, p, &p, error);
722 		if (!array->eklass)
723 			goto fail;
724 		array->rank = decode_value (p, &p);
725 		array->numsizes = decode_value (p, &p);
726 
727 		if (array->numsizes)
728 			array->sizes = (int *)g_malloc0 (sizeof (int) * array->numsizes);
729 		for (i = 0; i < array->numsizes; ++i)
730 			array->sizes [i] = decode_value (p, &p);
731 
732 		array->numlobounds = decode_value (p, &p);
733 		if (array->numlobounds)
734 			array->lobounds = (int *)g_malloc0 (sizeof (int) * array->numlobounds);
735 		for (i = 0; i < array->numlobounds; ++i)
736 			array->lobounds [i] = decode_value (p, &p);
737 		t->data.array = array;
738 		break;
739 	}
740 	case MONO_TYPE_VAR:
741 	case MONO_TYPE_MVAR: {
742 		MonoClass *klass = decode_klass_ref (module, p, &p, error);
743 		if (!klass)
744 			goto fail;
745 		t->data.generic_param = klass->byval_arg.data.generic_param;
746 		break;
747 	}
748 	default:
749 		mono_error_set_bad_image_name (error, module->aot_name, "Invalid encoded type %d", t->type);
750 		goto fail;
751 	}
752 
753 	*endbuf = p;
754 
755 	return t;
756 fail:
757 	g_free (t);
758 	return NULL;
759 }
760 
761 // FIXME: Error handling, memory management
762 
763 static MonoMethodSignature*
decode_signature_with_target(MonoAotModule * module,MonoMethodSignature * target,guint8 * buf,guint8 ** endbuf)764 decode_signature_with_target (MonoAotModule *module, MonoMethodSignature *target, guint8 *buf, guint8 **endbuf)
765 {
766 	MonoError error;
767 	MonoMethodSignature *sig;
768 	guint32 flags;
769 	int i, gen_param_count = 0, param_count, call_conv;
770 	guint8 *p = buf;
771 	gboolean hasthis, explicit_this, has_gen_params;
772 
773 	flags = *p;
774 	p ++;
775 	has_gen_params = (flags & 0x10) != 0;
776 	hasthis = (flags & 0x20) != 0;
777 	explicit_this = (flags & 0x40) != 0;
778 	call_conv = flags & 0x0F;
779 
780 	if (has_gen_params)
781 		gen_param_count = decode_value (p, &p);
782 	param_count = decode_value (p, &p);
783 	if (target && param_count != target->param_count)
784 		return NULL;
785 	sig = (MonoMethodSignature *)g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + param_count * sizeof (MonoType *));
786 	sig->param_count = param_count;
787 	sig->sentinelpos = -1;
788 	sig->hasthis = hasthis;
789 	sig->explicit_this = explicit_this;
790 	sig->call_convention = call_conv;
791 	sig->generic_param_count = gen_param_count;
792 	sig->ret = decode_type (module, p, &p, &error);
793 	if (!sig->ret)
794 		goto fail;
795 	for (i = 0; i < param_count; ++i) {
796 		if (*p == MONO_TYPE_SENTINEL) {
797 			g_assert (sig->call_convention == MONO_CALL_VARARG);
798 			sig->sentinelpos = i;
799 			p ++;
800 		}
801 		sig->params [i] = decode_type (module, p, &p, &error);
802 		if (!sig->params [i])
803 			goto fail;
804 	}
805 
806 	if (sig->call_convention == MONO_CALL_VARARG && sig->sentinelpos == -1)
807 		sig->sentinelpos = sig->param_count;
808 
809 	*endbuf = p;
810 
811 	return sig;
812 fail:
813 	mono_error_cleanup (&error); /* FIXME don't swallow the error */
814 	g_free (sig);
815 	return NULL;
816 }
817 
818 static MonoMethodSignature*
decode_signature(MonoAotModule * module,guint8 * buf,guint8 ** endbuf)819 decode_signature (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
820 {
821 	return decode_signature_with_target (module, NULL, buf, endbuf);
822 }
823 
824 static gboolean
sig_matches_target(MonoAotModule * module,MonoMethod * target,guint8 * buf,guint8 ** endbuf)825 sig_matches_target (MonoAotModule *module, MonoMethod *target, guint8 *buf, guint8 **endbuf)
826 {
827 	MonoMethodSignature *sig;
828 	gboolean res;
829 	guint8 *p = buf;
830 
831 	sig = decode_signature_with_target (module, mono_method_signature (target), p, &p);
832 	res = sig && mono_metadata_signature_equal (mono_method_signature (target), sig);
833 	g_free (sig);
834 	*endbuf = p;
835 	return res;
836 }
837 
838 /* Stores information returned by decode_method_ref () */
839 typedef struct {
840 	MonoImage *image;
841 	guint32 token;
842 	MonoMethod *method;
843 	gboolean no_aot_trampoline;
844 } MethodRef;
845 
846 /*
847  * decode_method_ref_with_target:
848  *
849  *   Decode a method reference, storing the image/token into a MethodRef structure.
850  * This avoids loading metadata for the method if the caller does not need it. If the method has
851  * no token, then it is loaded from metadata and ref->method is set to the method instance.
852  * If TARGET is non-NULL, abort decoding if it can be determined that the decoded method
853  *  couldn't resolve to TARGET, and return FALSE.
854  * There are some kinds of method references which only support a non-null TARGET.
855  * This means that its not possible to decode this into a method, only to check
856  * that the method reference matches a given method. This is normally not a problem
857  * as these wrappers only occur in the extra_methods table, where we already have
858  * a method we want to lookup.
859  *
860  * If there was a decoding error, we return FALSE and set @error
861  */
862 static gboolean
decode_method_ref_with_target(MonoAotModule * module,MethodRef * ref,MonoMethod * target,guint8 * buf,guint8 ** endbuf,MonoError * error)863 decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod *target, guint8 *buf, guint8 **endbuf, MonoError *error)
864 {
865 	guint32 image_index, value;
866 	MonoImage *image = NULL;
867 	guint8 *p = buf;
868 
869 	memset (ref, 0, sizeof (MethodRef));
870 	error_init (error);
871 
872 	value = decode_value (p, &p);
873 	image_index = value >> 24;
874 
875 	if (image_index == MONO_AOT_METHODREF_NO_AOT_TRAMPOLINE) {
876 		ref->no_aot_trampoline = TRUE;
877 		value = decode_value (p, &p);
878 		image_index = value >> 24;
879 	}
880 
881 	if (image_index < MONO_AOT_METHODREF_MIN || image_index == MONO_AOT_METHODREF_METHODSPEC || image_index == MONO_AOT_METHODREF_GINST) {
882 		if (target && target->wrapper_type) {
883 			return FALSE;
884 		}
885 	}
886 
887 	if (image_index == MONO_AOT_METHODREF_WRAPPER) {
888 		WrapperInfo *info;
889 		guint32 wrapper_type;
890 
891 		wrapper_type = decode_value (p, &p);
892 
893 		if (target && target->wrapper_type != wrapper_type)
894 			return FALSE;
895 
896 		/* Doesn't matter */
897 		image = mono_defaults.corlib;
898 
899 		switch (wrapper_type) {
900 #ifndef DISABLE_REMOTING
901 		case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
902 			MonoMethod *m = decode_resolve_method_ref (module, p, &p, error);
903 			if (!m)
904 				return FALSE;
905 			mono_class_init (m->klass);
906 			if (mono_aot_only)
907 				ref->method = m;
908 			else
909 				ref->method = mono_marshal_get_remoting_invoke_with_check (m);
910 			break;
911 		}
912 		case MONO_WRAPPER_PROXY_ISINST: {
913 			MonoClass *klass = decode_klass_ref (module, p, &p, error);
914 			if (!klass)
915 				return FALSE;
916 			ref->method = mono_marshal_get_proxy_cancast (klass);
917 			break;
918 		}
919 		case MONO_WRAPPER_LDFLD:
920 		case MONO_WRAPPER_LDFLDA:
921 		case MONO_WRAPPER_STFLD: {
922 			MonoClass *klass = decode_klass_ref (module, p, &p, error);
923 			if (!klass)
924 				return FALSE;
925 			if (wrapper_type == MONO_WRAPPER_LDFLD)
926 				ref->method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
927 			else if (wrapper_type == MONO_WRAPPER_LDFLDA)
928 				ref->method = mono_marshal_get_ldflda_wrapper (&klass->byval_arg);
929 			else if (wrapper_type == MONO_WRAPPER_STFLD)
930 				ref->method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
931 			else {
932 				mono_error_set_bad_image_name (error, module->aot_name, "Unknown AOT wrapper type %d", wrapper_type);
933 				return FALSE;
934 			}
935 			break;
936 		}
937 #endif
938 		case MONO_WRAPPER_ALLOC: {
939 			int atype = decode_value (p, &p);
940 			ManagedAllocatorVariant variant =
941 				mono_profiler_allocations_enabled () ?
942 				MANAGED_ALLOCATOR_PROFILER : MANAGED_ALLOCATOR_REGULAR;
943 
944 			ref->method = mono_gc_get_managed_allocator_by_type (atype, variant);
945 			/* Try to fallback to the slow path version */
946 			if (!ref->method)
947 				ref->method = mono_gc_get_managed_allocator_by_type (atype, MANAGED_ALLOCATOR_SLOW_PATH);
948 			if (!ref->method) {
949 				mono_error_set_bad_image_name (error, module->aot_name, "Error: No managed allocator, but we need one for AOT.\nAre you using non-standard GC options?\n");
950 				return FALSE;
951 			}
952 			break;
953 		}
954 		case MONO_WRAPPER_WRITE_BARRIER: {
955 			ref->method = mono_gc_get_write_barrier ();
956 			break;
957 		}
958 		case MONO_WRAPPER_STELEMREF: {
959 			int subtype = decode_value (p, &p);
960 
961 			if (subtype == WRAPPER_SUBTYPE_NONE) {
962 				ref->method = mono_marshal_get_stelemref ();
963 			} else if (subtype == WRAPPER_SUBTYPE_VIRTUAL_STELEMREF) {
964 				int kind;
965 
966 				kind = decode_value (p, &p);
967 
968 				/* Can't decode this */
969 				if (!target)
970 					return FALSE;
971 				if (target->wrapper_type == MONO_WRAPPER_STELEMREF) {
972 					info = mono_marshal_get_wrapper_info (target);
973 
974 					g_assert (info);
975 					if (info->subtype == subtype && info->d.virtual_stelemref.kind == kind)
976 						ref->method = target;
977 					else
978 						return FALSE;
979 				} else {
980 					return FALSE;
981 				}
982 			} else {
983 				mono_error_set_bad_image_name (error, module->aot_name, "Invalid STELEMREF subtype %d", subtype);
984 				return FALSE;
985 			}
986 			break;
987 		}
988 		case MONO_WRAPPER_SYNCHRONIZED: {
989 			MonoMethod *m = decode_resolve_method_ref (module, p, &p, error);
990 			if (!m)
991 				return FALSE;
992 			ref->method = mono_marshal_get_synchronized_wrapper (m);
993 			break;
994 		}
995 		case MONO_WRAPPER_UNKNOWN: {
996 			int subtype = decode_value (p, &p);
997 
998 			if (subtype == WRAPPER_SUBTYPE_PTR_TO_STRUCTURE || subtype == WRAPPER_SUBTYPE_STRUCTURE_TO_PTR) {
999 				MonoClass *klass = decode_klass_ref (module, p, &p, error);
1000 				if (!klass)
1001 					return FALSE;
1002 
1003 				if (!target)
1004 					return FALSE;
1005 				if (klass != target->klass)
1006 					return FALSE;
1007 
1008 				if (subtype == WRAPPER_SUBTYPE_PTR_TO_STRUCTURE) {
1009 					if (strcmp (target->name, "PtrToStructure"))
1010 						return FALSE;
1011 					ref->method = mono_marshal_get_ptr_to_struct (klass);
1012 				} else {
1013 					if (strcmp (target->name, "StructureToPtr"))
1014 						return FALSE;
1015 					ref->method = mono_marshal_get_struct_to_ptr (klass);
1016 				}
1017 			} else if (subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
1018 				MonoMethod *m = decode_resolve_method_ref (module, p, &p, error);
1019 				if (!m)
1020 					return FALSE;
1021 				ref->method = mono_marshal_get_synchronized_inner_wrapper (m);
1022 			} else if (subtype == WRAPPER_SUBTYPE_ARRAY_ACCESSOR) {
1023 				MonoMethod *m = decode_resolve_method_ref (module, p, &p, error);
1024 				if (!m)
1025 					return FALSE;
1026 				ref->method = mono_marshal_get_array_accessor_wrapper (m);
1027 			} else if (subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN) {
1028 				ref->method = mono_marshal_get_gsharedvt_in_wrapper ();
1029 			} else if (subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) {
1030 				ref->method = mono_marshal_get_gsharedvt_out_wrapper ();
1031 			} else if (subtype == WRAPPER_SUBTYPE_INTERP_IN) {
1032 				MonoMethodSignature *sig = decode_signature (module, p, &p);
1033 				if (!sig)
1034 					return FALSE;
1035 				ref->method = mini_get_interp_in_wrapper (sig);
1036 			} else if (subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
1037 				MonoMethodSignature *sig = decode_signature (module, p, &p);
1038 				if (!sig)
1039 					return FALSE;
1040 				ref->method = mini_get_gsharedvt_in_sig_wrapper (sig);
1041 			} else if (subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG) {
1042 				MonoMethodSignature *sig = decode_signature (module, p, &p);
1043 				if (!sig)
1044 					return FALSE;
1045 				ref->method = mini_get_gsharedvt_out_sig_wrapper (sig);
1046 			} else {
1047 				mono_error_set_bad_image_name (error, module->aot_name, "Invalid UNKNOWN wrapper subtype %d", subtype);
1048 				return FALSE;
1049 			}
1050 			break;
1051 		}
1052 		case MONO_WRAPPER_MANAGED_TO_MANAGED: {
1053 			int subtype = decode_value (p, &p);
1054 
1055 			if (subtype == WRAPPER_SUBTYPE_ELEMENT_ADDR) {
1056 				int rank = decode_value (p, &p);
1057 				int elem_size = decode_value (p, &p);
1058 
1059 				ref->method = mono_marshal_get_array_address (rank, elem_size);
1060 			} else if (subtype == WRAPPER_SUBTYPE_STRING_CTOR) {
1061 				MonoMethod *m;
1062 
1063 				m = decode_resolve_method_ref (module, p, &p, error);
1064 				if (!m)
1065 					return FALSE;
1066 
1067 				if (!target)
1068 					return FALSE;
1069 				g_assert (target->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED);
1070 
1071 				info = mono_marshal_get_wrapper_info (target);
1072 				if (info && info->subtype == subtype && info->d.string_ctor.method == m)
1073 					ref->method = target;
1074 				else
1075 					return FALSE;
1076 			}
1077 			break;
1078 		}
1079 		case MONO_WRAPPER_MANAGED_TO_NATIVE: {
1080 			MonoMethod *m;
1081 			int subtype = decode_value (p, &p);
1082 			char *name;
1083 
1084 			if (subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) {
1085 				if (!target)
1086 					return FALSE;
1087 
1088 				name = (char*)p;
1089 				if (strcmp (target->name, name) != 0)
1090 					return FALSE;
1091 				ref->method = target;
1092 			} else {
1093 				m = decode_resolve_method_ref (module, p, &p, error);
1094 				if (!m)
1095 					return FALSE;
1096 
1097 				/* This should only happen when looking for an extra method */
1098 				if (!target)
1099 					return FALSE;
1100 				if (mono_marshal_method_from_wrapper (target) == m)
1101 					ref->method = target;
1102 				else
1103 					return FALSE;
1104 			}
1105 			break;
1106 		}
1107 		case MONO_WRAPPER_CASTCLASS: {
1108 			int subtype = decode_value (p, &p);
1109 
1110 			if (subtype == WRAPPER_SUBTYPE_CASTCLASS_WITH_CACHE)
1111 				ref->method = mono_marshal_get_castclass_with_cache ();
1112 			else if (subtype == WRAPPER_SUBTYPE_ISINST_WITH_CACHE)
1113 				ref->method = mono_marshal_get_isinst_with_cache ();
1114 			else {
1115 				mono_error_set_bad_image_name (error, module->aot_name, "Invalid CASTCLASS wrapper subtype %d", subtype);
1116 				return FALSE;
1117 			}
1118 			break;
1119 		}
1120 		case MONO_WRAPPER_RUNTIME_INVOKE: {
1121 			int subtype = decode_value (p, &p);
1122 
1123 			if (!target)
1124 				return FALSE;
1125 
1126 			if (subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC) {
1127 				if (strcmp (target->name, "runtime_invoke_dynamic") != 0)
1128 					return FALSE;
1129 				ref->method = target;
1130 			} else if (subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT) {
1131 				/* Direct wrapper */
1132 				MonoMethod *m = decode_resolve_method_ref (module, p, &p, error);
1133 				if (!m)
1134 					return FALSE;
1135 				ref->method = mono_marshal_get_runtime_invoke (m, FALSE);
1136 			} else if (subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL) {
1137 				/* Virtual direct wrapper */
1138 				MonoMethod *m = decode_resolve_method_ref (module, p, &p, error);
1139 				if (!m)
1140 					return FALSE;
1141 				ref->method = mono_marshal_get_runtime_invoke (m, TRUE);
1142 			} else {
1143 				MonoMethodSignature *sig;
1144 
1145 				sig = decode_signature_with_target (module, NULL, p, &p);
1146 				info = mono_marshal_get_wrapper_info (target);
1147 				g_assert (info);
1148 
1149 				if (info->subtype != subtype)
1150 					return FALSE;
1151 				g_assert (info->d.runtime_invoke.sig);
1152 				if (mono_metadata_signature_equal (sig, info->d.runtime_invoke.sig))
1153 					ref->method = target;
1154 				else
1155 					return FALSE;
1156 			}
1157 			break;
1158 		}
1159 		case MONO_WRAPPER_DELEGATE_INVOKE:
1160 		case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
1161 		case MONO_WRAPPER_DELEGATE_END_INVOKE: {
1162 			gboolean is_inflated = decode_value (p, &p);
1163 			WrapperSubtype subtype;
1164 
1165 			if (is_inflated) {
1166 				MonoClass *klass;
1167 				MonoMethod *invoke, *wrapper;
1168 
1169 				klass = decode_klass_ref (module, p, &p, error);
1170 				if (!klass)
1171 					return FALSE;
1172 
1173 				switch (wrapper_type) {
1174 				case MONO_WRAPPER_DELEGATE_INVOKE:
1175 					invoke = mono_get_delegate_invoke (klass);
1176 					wrapper = mono_marshal_get_delegate_invoke (invoke, NULL);
1177 					break;
1178 				case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE:
1179 					invoke = mono_get_delegate_begin_invoke (klass);
1180 					wrapper = mono_marshal_get_delegate_begin_invoke (invoke);
1181 					break;
1182 				case MONO_WRAPPER_DELEGATE_END_INVOKE:
1183 					invoke = mono_get_delegate_end_invoke (klass);
1184 					wrapper = mono_marshal_get_delegate_end_invoke (invoke);
1185 					break;
1186 				default:
1187 					g_assert_not_reached ();
1188 					break;
1189 				}
1190 				if (target) {
1191 					/*
1192 					 * Due to the way mini_get_shared_method () works, we could end up with
1193 					 * multiple copies of the same wrapper.
1194 					 */
1195 					if (wrapper->klass != target->klass)
1196 						return FALSE;
1197 					ref->method = target;
1198 				} else {
1199 					ref->method = wrapper;
1200 				}
1201 			} else {
1202 				/*
1203 				 * These wrappers are associated with a signature, not with a method.
1204 				 * Since we can't decode them into methods, they need a target method.
1205 				 */
1206 				if (!target)
1207 					return FALSE;
1208 
1209 				if (wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) {
1210 					subtype = (WrapperSubtype)decode_value (p, &p);
1211 					info = mono_marshal_get_wrapper_info (target);
1212 					if (info) {
1213 						if (info->subtype != subtype)
1214 							return FALSE;
1215 					} else {
1216 						if (subtype != WRAPPER_SUBTYPE_NONE)
1217 							return FALSE;
1218 					}
1219 				}
1220 				if (sig_matches_target (module, target, p, &p))
1221 					ref->method = target;
1222 				else
1223 					return FALSE;
1224 			}
1225 			break;
1226 		}
1227 		case MONO_WRAPPER_NATIVE_TO_MANAGED: {
1228 			MonoMethod *m;
1229 			MonoClass *klass;
1230 
1231 			m = decode_resolve_method_ref (module, p, &p, error);
1232 			if (!m)
1233 				return FALSE;
1234 			klass = decode_klass_ref (module, p, &p, error);
1235 			if (!klass)
1236 				return FALSE;
1237 			ref->method = mono_marshal_get_managed_wrapper (m, klass, 0, error);
1238 			if (!mono_error_ok (error))
1239 				return FALSE;
1240 			break;
1241 		}
1242 		default:
1243 			g_assert_not_reached ();
1244 		}
1245 	} else if (image_index == MONO_AOT_METHODREF_METHODSPEC) {
1246 		image_index = decode_value (p, &p);
1247 		ref->token = decode_value (p, &p);
1248 
1249 		image = load_image (module, image_index, error);
1250 		if (!image)
1251 			return FALSE;
1252 	} else if (image_index == MONO_AOT_METHODREF_GINST) {
1253 		MonoClass *klass;
1254 		MonoGenericContext ctx;
1255 
1256 		/*
1257 		 * These methods do not have a token which resolves them, so we
1258 		 * resolve them immediately.
1259 		 */
1260 		klass = decode_klass_ref (module, p, &p, error);
1261 		if (!klass)
1262 			return FALSE;
1263 
1264 		if (target && target->klass != klass)
1265 			return FALSE;
1266 
1267 		image_index = decode_value (p, &p);
1268 		ref->token = decode_value (p, &p);
1269 
1270 		image = load_image (module, image_index, error);
1271 		if (!image)
1272 			return FALSE;
1273 
1274 		ref->method = mono_get_method_checked (image, ref->token, NULL, NULL, error);
1275 		if (!ref->method)
1276 			return FALSE;
1277 
1278 
1279 		memset (&ctx, 0, sizeof (ctx));
1280 
1281 		if (FALSE && mono_class_is_ginst (klass)) {
1282 			ctx.class_inst = mono_class_get_generic_class (klass)->context.class_inst;
1283 			ctx.method_inst = NULL;
1284 
1285 			ref->method = mono_class_inflate_generic_method_full_checked (ref->method, klass, &ctx, error);
1286 			if (!ref->method)
1287 				return FALSE;
1288 		}
1289 
1290 		memset (&ctx, 0, sizeof (ctx));
1291 
1292 		if (!decode_generic_context (module, &ctx, p, &p, error))
1293 			return FALSE;
1294 
1295 		ref->method = mono_class_inflate_generic_method_full_checked (ref->method, klass, &ctx, error);
1296 		if (!ref->method)
1297 			return FALSE;
1298 
1299 	} else if (image_index == MONO_AOT_METHODREF_ARRAY) {
1300 		MonoClass *klass;
1301 		int method_type;
1302 
1303 		klass = decode_klass_ref (module, p, &p, error);
1304 		if (!klass)
1305 			return FALSE;
1306 		method_type = decode_value (p, &p);
1307 		switch (method_type) {
1308 		case 0:
1309 			ref->method = mono_class_get_method_from_name (klass, ".ctor", klass->rank);
1310 			break;
1311 		case 1:
1312 			ref->method = mono_class_get_method_from_name (klass, ".ctor", klass->rank * 2);
1313 			break;
1314 		case 2:
1315 			ref->method = mono_class_get_method_from_name (klass, "Get", -1);
1316 			break;
1317 		case 3:
1318 			ref->method = mono_class_get_method_from_name (klass, "Address", -1);
1319 			break;
1320 		case 4:
1321 			ref->method = mono_class_get_method_from_name (klass, "Set", -1);
1322 			break;
1323 		default:
1324 			mono_error_set_bad_image_name (error, module->aot_name, "Invalid METHODREF_ARRAY method type %d", method_type);
1325 			return FALSE;
1326 		}
1327 	} else {
1328 		if (image_index == MONO_AOT_METHODREF_LARGE_IMAGE_INDEX) {
1329 			image_index = decode_value (p, &p);
1330 			value = decode_value (p, &p);
1331 		}
1332 
1333 		ref->token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
1334 
1335 		image = load_image (module, image_index, error);
1336 		if (!image)
1337 			return FALSE;
1338 	}
1339 
1340 	*endbuf = p;
1341 
1342 	ref->image = image;
1343 
1344 	return TRUE;
1345 }
1346 
1347 static gboolean
decode_method_ref(MonoAotModule * module,MethodRef * ref,guint8 * buf,guint8 ** endbuf,MonoError * error)1348 decode_method_ref (MonoAotModule *module, MethodRef *ref, guint8 *buf, guint8 **endbuf, MonoError *error)
1349 {
1350 	return decode_method_ref_with_target (module, ref, NULL, buf, endbuf, error);
1351 }
1352 
1353 /*
1354  * decode_resolve_method_ref_with_target:
1355  *
1356  *   Similar to decode_method_ref, but resolve and return the method itself.
1357  */
1358 static MonoMethod*
decode_resolve_method_ref_with_target(MonoAotModule * module,MonoMethod * target,guint8 * buf,guint8 ** endbuf,MonoError * error)1359 decode_resolve_method_ref_with_target (MonoAotModule *module, MonoMethod *target, guint8 *buf, guint8 **endbuf, MonoError *error)
1360 {
1361 	MethodRef ref;
1362 
1363 	error_init (error);
1364 
1365 	if (!decode_method_ref_with_target (module, &ref, target, buf, endbuf, error))
1366 		return NULL;
1367 	if (ref.method)
1368 		return ref.method;
1369 	if (!ref.image) {
1370 		mono_error_set_bad_image_name (error, module->aot_name, "No image found for methodref with target");
1371 		return NULL;
1372 	}
1373 	return mono_get_method_checked (ref.image, ref.token, NULL, NULL, error);
1374 }
1375 
1376 static MonoMethod*
decode_resolve_method_ref(MonoAotModule * module,guint8 * buf,guint8 ** endbuf,MonoError * error)1377 decode_resolve_method_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf, MonoError *error)
1378 {
1379 	return decode_resolve_method_ref_with_target (module, NULL, buf, endbuf, error);
1380 }
1381 
1382 #ifdef ENABLE_AOT_CACHE
1383 
1384 /* AOT CACHE */
1385 
1386 /*
1387  * FIXME:
1388  * - Add options for controlling the cache size
1389  * - Handle full cache by deleting old assemblies lru style
1390  * - Maybe add a threshold after an assembly is AOT compiled
1391  * - Add options for enabling this for specific main assemblies
1392  */
1393 
1394 /* The cache directory */
1395 static char *cache_dir;
1396 
1397 /* The number of assemblies AOTed in this run */
1398 static int cache_count;
1399 
1400 /* Whenever to AOT in-process */
1401 static gboolean in_process;
1402 
1403 static void
collect_assemblies(gpointer data,gpointer user_data)1404 collect_assemblies (gpointer data, gpointer user_data)
1405 {
1406 	MonoAssembly *ass = data;
1407 	GSList **l = user_data;
1408 
1409 	*l = g_slist_prepend (*l, ass);
1410 }
1411 
1412 #define SHA1_DIGEST_LENGTH 20
1413 
1414 /*
1415  * get_aot_config_hash:
1416  *
1417  *   Return a hash for all the version information an AOT module depends on.
1418  */
1419 static G_GNUC_UNUSED char*
get_aot_config_hash(MonoAssembly * assembly)1420 get_aot_config_hash (MonoAssembly *assembly)
1421 {
1422 	char *build_info;
1423 	GSList *l, *assembly_list = NULL;
1424 	GString *s;
1425 	int i;
1426 	guint8 digest [SHA1_DIGEST_LENGTH];
1427 	char *digest_str;
1428 
1429 	build_info = mono_get_runtime_build_info ();
1430 
1431 	s = g_string_new (build_info);
1432 
1433 	mono_assembly_foreach (collect_assemblies, &assembly_list);
1434 
1435 	/*
1436 	 * The assembly list includes the current assembly as well, no need
1437 	 * to add it.
1438 	 */
1439 	for (l = assembly_list; l; l = l->next) {
1440 		MonoAssembly *ass = l->data;
1441 
1442 		g_string_append (s, "_");
1443 		g_string_append (s, ass->aname.name);
1444 		g_string_append (s, "_");
1445 		g_string_append (s, ass->image->guid);
1446 	}
1447 
1448 	for (i = 0; i < s->len; ++i) {
1449 		if (!isalnum (s->str [i]) && s->str [i] != '-')
1450 			s->str [i] = '_';
1451 	}
1452 
1453 	mono_sha1_get_digest ((guint8*)s->str, s->len, digest);
1454 
1455 	digest_str = g_malloc0 ((SHA1_DIGEST_LENGTH * 2) + 1);
1456 	for (i = 0; i < SHA1_DIGEST_LENGTH; ++i)
1457 		sprintf (digest_str + (i * 2), "%02x", digest [i]);
1458 
1459 	mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: file dependencies: %s, hash %s", s->str, digest_str);
1460 
1461 	g_string_free (s, TRUE);
1462 
1463 	return digest_str;
1464 }
1465 
1466 static void
aot_cache_init(void)1467 aot_cache_init (void)
1468 {
1469 	if (mono_aot_only)
1470 		return;
1471 	enable_aot_cache = TRUE;
1472 	in_process = TRUE;
1473 }
1474 
1475 /*
1476  * aot_cache_load_module:
1477  *
1478  *   Load the AOT image corresponding to ASSEMBLY from the aot cache, AOTing it if neccessary.
1479  */
1480 static MonoDl*
aot_cache_load_module(MonoAssembly * assembly,char ** aot_name)1481 aot_cache_load_module (MonoAssembly *assembly, char **aot_name)
1482 {
1483 	MonoAotCacheConfig *config;
1484 	GSList *l;
1485 	char *fname, *tmp2, *aot_options, *failure_fname;
1486 	const char *home;
1487 	MonoDl *module;
1488 	gboolean res;
1489 	gint exit_status;
1490 	char *hash;
1491 	int pid;
1492 	gboolean enabled;
1493 	FILE *failure_file;
1494 
1495 	*aot_name = NULL;
1496 
1497 	if (image_is_dynamic (assembly->image))
1498 		return NULL;
1499 
1500 	/* Check in the list of assemblies enabled for aot caching */
1501 	config = mono_get_aot_cache_config ();
1502 
1503 	enabled = FALSE;
1504 	if (config->apps) {
1505 		MonoDomain *domain = mono_domain_get ();
1506 		MonoAssembly *entry_assembly = domain->entry_assembly;
1507 
1508 		// FIXME: This cannot be used for mscorlib during startup, since entry_assembly is not set yet
1509 		for (l = config->apps; l; l = l->next) {
1510 			char *n = l->data;
1511 
1512 			if ((entry_assembly && !strcmp (entry_assembly->aname.name, n)) || (!entry_assembly && !strcmp (assembly->aname.name, n)))
1513 				break;
1514 		}
1515 		if (l)
1516 			enabled = TRUE;
1517 	}
1518 
1519 	if (!enabled) {
1520 		for (l = config->assemblies; l; l = l->next) {
1521 			char *n = l->data;
1522 
1523 			if (!strcmp (assembly->aname.name, n))
1524 				break;
1525 		}
1526 		if (l)
1527 			enabled = TRUE;
1528 	}
1529 	if (!enabled)
1530 		return NULL;
1531 
1532 	if (!cache_dir) {
1533 		home = g_get_home_dir ();
1534 		if (!home)
1535 			return NULL;
1536 		cache_dir = g_strdup_printf ("%s/Library/Caches/mono/aot-cache", home);
1537 		if (!g_file_test (cache_dir, G_FILE_TEST_EXISTS|G_FILE_TEST_IS_DIR))
1538 			g_mkdir_with_parents (cache_dir, 0777);
1539 	}
1540 
1541 	/*
1542 	 * The same assembly can be used in multiple configurations, i.e. multiple
1543      * versions of the runtime, with multiple versions of dependent assemblies etc.
1544 	 * To handle this, we compute a version string containing all this information, hash it,
1545 	 * and use the hash as a filename suffix.
1546 	 */
1547 	hash = get_aot_config_hash (assembly);
1548 
1549 	tmp2 = g_strdup_printf ("%s-%s%s", assembly->image->assembly_name, hash, MONO_SOLIB_EXT);
1550 	fname = g_build_filename (cache_dir, tmp2, NULL);
1551 	*aot_name = fname;
1552 	g_free (tmp2);
1553 
1554 	mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: loading from cache: '%s'.", fname);
1555 	module = mono_dl_open (fname, MONO_DL_LAZY, NULL);
1556 
1557 	if (module) {
1558 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: found in cache: '%s'.", fname);
1559 		return module;
1560 	}
1561 
1562 	if (!strcmp (assembly->aname.name, "mscorlib") && !mscorlib_aot_loaded)
1563 		/*
1564 		 * Can't AOT this during startup, so we AOT it when called later from
1565 		 * mono_aot_get_method ().
1566 		 */
1567 		return NULL;
1568 
1569 	mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: not found.");
1570 
1571 	/* Only AOT one assembly per run to avoid slowing down execution too much */
1572 	if (cache_count > 0)
1573 		return NULL;
1574 	cache_count ++;
1575 
1576 	/* Check for previous failure */
1577 	failure_fname = g_strdup_printf ("%s.failure", fname);
1578 	failure_file = fopen (failure_fname, "r");
1579 	if (failure_file) {
1580 		mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: assembly '%s' previously failed to compile '%s' ('%s')... ", assembly->image->name, fname, failure_fname);
1581 		g_free (failure_fname);
1582 		return NULL;
1583 	} else {
1584 		g_free (failure_fname);
1585 		fclose (failure_file);
1586 	}
1587 
1588 	mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: compiling assembly '%s', logfile: '%s.log'... ", assembly->image->name, fname);
1589 
1590 	/*
1591 	 * We need to invoke the AOT compiler here. There are multiple approaches:
1592 	 * - spawn a new runtime process. This can be hard when running with mkbundle, and
1593 	 * its hard to make the new process load the same set of assemblies.
1594 	 * - doing it in-process. This exposes the current process to bugs/leaks/side effects of
1595 	 * the AOT compiler.
1596 	 * - fork a new process and do the work there.
1597 	 */
1598 	if (in_process) {
1599 		aot_options = g_strdup_printf ("outfile=%s,internal-logfile=%s.log%s%s", fname, fname, config->aot_options ? "," : "", config->aot_options ? config->aot_options : "");
1600 		/* Maybe due this in another thread ? */
1601 		res = mono_compile_assembly (assembly, mono_parse_default_optimizations (NULL), aot_options, NULL);
1602 		if (res) {
1603 			mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: compilation failed.");
1604 			failure_fname = g_strdup_printf ("%s.failure", fname);
1605 			failure_file = fopen (failure_fname, "a+");
1606 			fclose (failure_file);
1607 			g_free (failure_fname);
1608 		} else {
1609 			mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: compilation succeeded.");
1610 		}
1611 	} else {
1612 		/*
1613 		 * - Avoid waiting for the aot process to finish ?
1614 		 *   (less overhead, but multiple processes could aot the same assembly at the same time)
1615 		 */
1616 		pid = fork ();
1617 		if (pid == 0) {
1618 			FILE *logfile;
1619 			char *logfile_name;
1620 
1621 			/* Child */
1622 
1623 			logfile_name = g_strdup_printf ("%s/aot.log", cache_dir);
1624 			logfile = fopen (logfile_name, "a+");
1625 			g_free (logfile_name);
1626 
1627 			dup2 (fileno (logfile), 1);
1628 			dup2 (fileno (logfile), 2);
1629 
1630 			aot_options = g_strdup_printf ("outfile=%s", fname);
1631 			res = mono_compile_assembly (assembly, mono_parse_default_optimizations (NULL), aot_options, NULL);
1632 			if (!res) {
1633 				exit (1);
1634 			} else {
1635 				exit (0);
1636 			}
1637 		} else {
1638 			/* Parent */
1639 			waitpid (pid, &exit_status, 0);
1640 			if (!WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) == 0))
1641 				mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: failed.");
1642 			else
1643 				mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: succeeded.");
1644 		}
1645 	}
1646 
1647 	module = mono_dl_open (fname, MONO_DL_LAZY, NULL);
1648 
1649 	return module;
1650 }
1651 
1652 #else
1653 
1654 static void
aot_cache_init(void)1655 aot_cache_init (void)
1656 {
1657 }
1658 
1659 static MonoDl*
aot_cache_load_module(MonoAssembly * assembly,char ** aot_name)1660 aot_cache_load_module (MonoAssembly *assembly, char **aot_name)
1661 {
1662 	return NULL;
1663 }
1664 
1665 #endif
1666 
1667 static void
find_symbol(MonoDl * module,gpointer * globals,const char * name,gpointer * value)1668 find_symbol (MonoDl *module, gpointer *globals, const char *name, gpointer *value)
1669 {
1670 	if (globals) {
1671 		int global_index;
1672 		guint16 *table, *entry;
1673 		guint16 table_size;
1674 		guint32 hash;
1675 		char *symbol = (char*)name;
1676 
1677 #ifdef TARGET_MACH
1678 		symbol = g_strdup_printf ("_%s", name);
1679 #endif
1680 
1681 		/* The first entry points to the hash */
1682 		table = (guint16 *)globals [0];
1683 		globals ++;
1684 
1685 		table_size = table [0];
1686 		table ++;
1687 
1688 		hash = mono_metadata_str_hash (symbol) % table_size;
1689 
1690 		entry = &table [hash * 2];
1691 
1692 		/* Search the hash for the index into the globals table */
1693 		global_index = -1;
1694 		while (entry [0] != 0) {
1695 			guint32 index = entry [0] - 1;
1696 			guint32 next = entry [1];
1697 
1698 			//printf ("X: %s %s\n", (char*)globals [index * 2], name);
1699 
1700 			if (!strcmp (globals [index * 2], symbol)) {
1701 				global_index = index;
1702 				break;
1703 			}
1704 
1705 			if (next != 0) {
1706 				entry = &table [next * 2];
1707 			} else {
1708 				break;
1709 			}
1710 		}
1711 
1712 		if (global_index != -1)
1713 			*value = globals [global_index * 2 + 1];
1714 		else
1715 			*value = NULL;
1716 
1717 		if (symbol != name)
1718 			g_free (symbol);
1719 	} else {
1720 		char *err = mono_dl_symbol (module, name, value);
1721 
1722 		if (err)
1723 			g_free (err);
1724 	}
1725 }
1726 
1727 static void
find_amodule_symbol(MonoAotModule * amodule,const char * name,gpointer * value)1728 find_amodule_symbol (MonoAotModule *amodule, const char *name, gpointer *value)
1729 {
1730 	g_assert (!(amodule->info.flags & MONO_AOT_FILE_FLAG_LLVM_ONLY));
1731 
1732 	find_symbol (amodule->sofile, amodule->globals, name, value);
1733 }
1734 
1735 void
mono_install_load_aot_data_hook(MonoLoadAotDataFunc load_func,MonoFreeAotDataFunc free_func,gpointer user_data)1736 mono_install_load_aot_data_hook (MonoLoadAotDataFunc load_func, MonoFreeAotDataFunc free_func, gpointer user_data)
1737 {
1738 	aot_data_load_func = load_func;
1739 	aot_data_free_func = free_func;
1740 	aot_data_func_user_data = user_data;
1741 }
1742 
1743 /* Load the separate aot data file for ASSEMBLY */
1744 static guint8*
open_aot_data(MonoAssembly * assembly,MonoAotFileInfo * info,void ** ret_handle)1745 open_aot_data (MonoAssembly *assembly, MonoAotFileInfo *info, void **ret_handle)
1746 {
1747 	MonoFileMap *map;
1748 	char *filename;
1749 	guint8 *data;
1750 
1751 	if (aot_data_load_func) {
1752 		data = aot_data_load_func (assembly, info->datafile_size, aot_data_func_user_data, ret_handle);
1753 		g_assert (data);
1754 		return data;
1755 	}
1756 
1757 	/*
1758 	 * Use <assembly name>.aotdata as the default implementation if no callback is given
1759 	 */
1760 	filename = g_strdup_printf ("%s.aotdata", assembly->image->name);
1761 	map = mono_file_map_open (filename);
1762 	g_assert (map);
1763 	data = mono_file_map (info->datafile_size, MONO_MMAP_READ, mono_file_map_fd (map), 0, ret_handle);
1764 	g_assert (data);
1765 
1766 	return data;
1767 }
1768 
1769 static gboolean
check_usable(MonoAssembly * assembly,MonoAotFileInfo * info,guint8 * blob,char ** out_msg)1770 check_usable (MonoAssembly *assembly, MonoAotFileInfo *info, guint8 *blob, char **out_msg)
1771 {
1772 	char *build_info;
1773 	char *msg = NULL;
1774 	gboolean usable = TRUE;
1775 	gboolean full_aot, safepoints;
1776 	guint32 excluded_cpu_optimizations;
1777 
1778 	if (strcmp (assembly->image->guid, info->assembly_guid)) {
1779 		msg = g_strdup_printf ("doesn't match assembly");
1780 		usable = FALSE;
1781 	}
1782 
1783 	build_info = mono_get_runtime_build_info ();
1784 	if (strlen ((const char *)info->runtime_version) > 0 && strcmp (info->runtime_version, build_info)) {
1785 		msg = g_strdup_printf ("compiled against runtime version '%s' while this runtime has version '%s'", info->runtime_version, build_info);
1786 		usable = FALSE;
1787 	}
1788 	g_free (build_info);
1789 
1790 	full_aot = info->flags & MONO_AOT_FILE_FLAG_FULL_AOT;
1791 
1792 	if (mono_aot_only && !full_aot) {
1793 		msg = g_strdup_printf ("not compiled with --aot=full");
1794 		usable = FALSE;
1795 	}
1796 	if (!mono_aot_only && full_aot) {
1797 		msg = g_strdup_printf ("compiled with --aot=full");
1798 		usable = FALSE;
1799 	}
1800 	if (mono_llvm_only && !(info->flags & MONO_AOT_FILE_FLAG_LLVM_ONLY)) {
1801 		msg = g_strdup_printf ("not compiled with --aot=llvmonly");
1802 		usable = FALSE;
1803 	}
1804 	if (mini_get_debug_options ()->mdb_optimizations && !(info->flags & MONO_AOT_FILE_FLAG_DEBUG) && !full_aot) {
1805 		msg = g_strdup_printf ("not compiled for debugging");
1806 		usable = FALSE;
1807 	}
1808 
1809 	mono_arch_cpu_optimizations (&excluded_cpu_optimizations);
1810 	if (info->opts & excluded_cpu_optimizations) {
1811 		msg = g_strdup_printf ("compiled with unsupported CPU optimizations");
1812 		usable = FALSE;
1813 	}
1814 
1815 	if (!mono_aot_only && (info->simd_opts & ~mono_arch_cpu_enumerate_simd_versions ())) {
1816 		msg = g_strdup_printf ("compiled with unsupported SIMD extensions");
1817 		usable = FALSE;
1818 	}
1819 
1820 	if (info->gc_name_index != -1) {
1821 		char *gc_name = (char*)&blob [info->gc_name_index];
1822 		const char *current_gc_name = mono_gc_get_gc_name ();
1823 
1824 		if (strcmp (current_gc_name, gc_name) != 0) {
1825 			msg = g_strdup_printf ("compiled against GC %s, while the current runtime uses GC %s.\n", gc_name, current_gc_name);
1826 			usable = FALSE;
1827 		}
1828 	}
1829 
1830 	safepoints = info->flags & MONO_AOT_FILE_FLAG_SAFEPOINTS;
1831 
1832 	if (!safepoints && mono_threads_is_coop_enabled ()) {
1833 		msg = g_strdup_printf ("not compiled with safepoints");
1834 		usable = FALSE;
1835 	}
1836 
1837 	*out_msg = msg;
1838 	return usable;
1839 }
1840 
1841 /*
1842  * TABLE should point to a table of call instructions. Return the address called by the INDEXth entry.
1843  */
1844 static void*
get_call_table_entry(void * table,int index)1845 get_call_table_entry (void *table, int index)
1846 {
1847 #if defined(TARGET_ARM)
1848 	guint32 *ins_addr;
1849 	guint32 ins;
1850 	gint32 offset;
1851 
1852 	ins_addr = (guint32*)table + index;
1853 	ins = *ins_addr;
1854 	if ((ins >> ARMCOND_SHIFT) == ARMCOND_NV) {
1855 		/* blx */
1856 		offset = (((int)(((ins & 0xffffff) << 1) | ((ins >> 24) & 0x1))) << 7) >> 7;
1857 		return (char*)ins_addr + (offset * 2) + 8 + 1;
1858 	} else {
1859 		offset = (((int)ins & 0xffffff) << 8) >> 8;
1860 		return (char*)ins_addr + (offset * 4) + 8;
1861 	}
1862 #elif defined(TARGET_ARM64)
1863 	return mono_arch_get_call_target ((guint8*)table + (index * 4) + 4);
1864 #elif defined(TARGET_X86) || defined(TARGET_AMD64)
1865 	/* The callee expects an ip which points after the call */
1866 	return mono_arch_get_call_target ((guint8*)table + (index * 5) + 5);
1867 #else
1868 	g_assert_not_reached ();
1869 	return NULL;
1870 #endif
1871 }
1872 
1873 /*
1874  * init_amodule_got:
1875  *
1876  *   Initialize the shared got entries for AMODULE.
1877  */
1878 static void
init_amodule_got(MonoAotModule * amodule)1879 init_amodule_got (MonoAotModule *amodule)
1880 {
1881 	MonoJumpInfo *ji;
1882 	MonoMemPool *mp;
1883 	MonoJumpInfo *patches;
1884 	guint32 got_offsets [128];
1885 	MonoError error;
1886 	int i, npatches;
1887 
1888 	/* These can't be initialized in load_aot_module () */
1889 	if (amodule->shared_got [0] || amodule->got_initializing)
1890 		return;
1891 
1892 	amodule->got_initializing = TRUE;
1893 
1894 	mp = mono_mempool_new ();
1895 	npatches = amodule->info.nshared_got_entries;
1896 	for (i = 0; i < npatches; ++i)
1897 		got_offsets [i] = i;
1898 	patches = decode_patches (amodule, mp, npatches, FALSE, got_offsets);
1899 	g_assert (patches);
1900 	for (i = 0; i < npatches; ++i) {
1901 		ji = &patches [i];
1902 
1903 		if (ji->type == MONO_PATCH_INFO_GC_CARD_TABLE_ADDR && !mono_gc_is_moving ()) {
1904 			amodule->shared_got [i] = NULL;
1905 		} else if (ji->type == MONO_PATCH_INFO_GC_NURSERY_START && !mono_gc_is_moving ()) {
1906 			amodule->shared_got [i] = NULL;
1907 		} else if (ji->type == MONO_PATCH_INFO_GC_NURSERY_BITS && !mono_gc_is_moving ()) {
1908 			amodule->shared_got [i] = NULL;
1909 		} else if (ji->type == MONO_PATCH_INFO_IMAGE) {
1910 			amodule->shared_got [i] = amodule->assembly->image;
1911 		} else if (ji->type == MONO_PATCH_INFO_MSCORLIB_GOT_ADDR) {
1912 			if (mono_defaults.corlib) {
1913 				MonoAotModule *mscorlib_amodule = (MonoAotModule *)mono_defaults.corlib->aot_module;
1914 
1915 				if (mscorlib_amodule)
1916 					amodule->shared_got [i] = mscorlib_amodule->got;
1917 			} else {
1918 				amodule->shared_got [i] = amodule->got;
1919 			}
1920 		} else if (ji->type == MONO_PATCH_INFO_AOT_MODULE) {
1921 			amodule->shared_got [i] = amodule;
1922 		} else {
1923 			amodule->shared_got [i] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, ji, FALSE, &error);
1924 			mono_error_assert_ok (&error);
1925 		}
1926 	}
1927 
1928 	if (amodule->got) {
1929 		for (i = 0; i < npatches; ++i)
1930 			amodule->got [i] = amodule->shared_got [i];
1931 	}
1932 	if (amodule->llvm_got) {
1933 		for (i = 0; i < npatches; ++i)
1934 			amodule->llvm_got [i] = amodule->shared_got [i];
1935 	}
1936 
1937 	mono_mempool_destroy (mp);
1938 }
1939 
1940 static void
load_aot_module(MonoAssembly * assembly,gpointer user_data)1941 load_aot_module (MonoAssembly *assembly, gpointer user_data)
1942 {
1943 	char *aot_name, *found_aot_name;
1944 	MonoAotModule *amodule;
1945 	MonoDl *sofile;
1946 	gboolean usable = TRUE;
1947 	char *version_symbol = NULL;
1948 	char *msg = NULL;
1949 	gpointer *globals = NULL;
1950 	MonoAotFileInfo *info = NULL;
1951 	int i, version;
1952 	gboolean do_load_image = TRUE;
1953 	int align_double, align_int64;
1954 	guint8 *aot_data = NULL;
1955 
1956 	if (mono_compile_aot)
1957 		return;
1958 
1959 	if (assembly->image->aot_module)
1960 		/*
1961 		 * Already loaded. This can happen because the assembly loading code might invoke
1962 		 * the assembly load hooks multiple times for the same assembly.
1963 		 */
1964 		return;
1965 
1966 	if (image_is_dynamic (assembly->image) || assembly->ref_only || mono_domain_get () != mono_get_root_domain ())
1967 		return;
1968 
1969 	mono_aot_lock ();
1970 
1971 if (container_assm_name && !container_amodule) {
1972 	char *local_ref = container_assm_name;
1973 	container_assm_name = NULL;
1974 	MonoImageOpenStatus status = MONO_IMAGE_OK;
1975 	gchar *dll = g_strdup_printf (		"%s.dll", local_ref);
1976 	MonoAssembly *assm = mono_assembly_open_a_lot (dll, &status, FALSE, FALSE);
1977 	if (!assm) {
1978 		gchar *exe = g_strdup_printf ("%s.exe", local_ref);
1979 		assm = mono_assembly_open_a_lot (exe, &status, FALSE, FALSE);
1980 	}
1981 	g_assert (assm);
1982 	load_aot_module (assm, NULL);
1983 	container_amodule = assm->image->aot_module;
1984 }
1985 
1986 	if (static_aot_modules)
1987 		info = (MonoAotFileInfo *)g_hash_table_lookup (static_aot_modules, assembly->aname.name);
1988 
1989 	mono_aot_unlock ();
1990 
1991 	sofile = NULL;
1992 
1993 	found_aot_name = NULL;
1994 
1995 	if (info) {
1996 		/* Statically linked AOT module */
1997 		aot_name = g_strdup_printf ("%s", assembly->aname.name);
1998 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "Found statically linked AOT module '%s'.", aot_name);
1999 		if (!(info->flags & MONO_AOT_FILE_FLAG_LLVM_ONLY)) {
2000 			globals = (void **)info->globals;
2001 			g_assert (globals);
2002 		}
2003 		found_aot_name = g_strdup (aot_name);
2004 	} else {
2005 		char *err;
2006 
2007 		if (enable_aot_cache)
2008 			sofile = aot_cache_load_module (assembly, &aot_name);
2009 		if (!sofile) {
2010 			aot_name = g_strdup_printf ("%s%s", assembly->image->name, MONO_SOLIB_EXT);
2011 
2012 			sofile = mono_dl_open (aot_name, MONO_DL_LAZY, &err);
2013 			if (sofile) {
2014 				found_aot_name = g_strdup (aot_name);
2015 			} else {
2016 				mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: image '%s' not found: %s", aot_name, err);
2017 				g_free (err);
2018 			}
2019 			g_free (aot_name);
2020 		}
2021 		if (!sofile) {
2022 			char *basename = g_path_get_basename (assembly->image->name);
2023 			aot_name = g_strdup_printf ("%s/mono/aot-cache/%s/%s%s", mono_assembly_getrootdir(), MONO_ARCHITECTURE, basename, MONO_SOLIB_EXT);
2024 			g_free (basename);
2025 			sofile = mono_dl_open (aot_name, MONO_DL_LAZY, &err);
2026 			if (!sofile) {
2027 				mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: image '%s' not found: %s", aot_name, err);
2028 				g_free (err);
2029 			}
2030 			g_free (aot_name);
2031 		}
2032 		if (!sofile) {
2033 			GList *l;
2034 
2035 			for (l = mono_aot_paths; l; l = l->next) {
2036 				char *path = l->data;
2037 
2038 				char *basename = g_path_get_basename (assembly->image->name);
2039 				aot_name = g_strdup_printf ("%s/%s%s", path, basename, MONO_SOLIB_EXT);
2040 				sofile = mono_dl_open (aot_name, MONO_DL_LAZY, &err);
2041 				if (sofile) {
2042 					found_aot_name = g_strdup (aot_name);
2043 				} else {
2044 					mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: image '%s' not found: %s", aot_name, err);
2045 					g_free (err);
2046 				}
2047 				g_free (basename);
2048 				g_free (aot_name);
2049 				if (sofile)
2050 					break;
2051 			}
2052 		}
2053 		if (!sofile) {
2054 			if (mono_aot_only && !mono_use_interpreter && assembly->image->tables [MONO_TABLE_METHOD].rows) {
2055 				aot_name = g_strdup_printf ("%s%s", assembly->image->name, MONO_SOLIB_EXT);
2056 				g_error ("Failed to load AOT module '%s' in aot-only mode.\n", aot_name);
2057 				g_free (aot_name);
2058 			}
2059 			return;
2060 		}
2061 	}
2062 
2063 	if (!info) {
2064 		find_symbol (sofile, globals, "mono_aot_version", (gpointer *) &version_symbol);
2065 		find_symbol (sofile, globals, "mono_aot_file_info", (gpointer*)&info);
2066 	}
2067 
2068 	// Copy aotid to MonoImage
2069 	memcpy(&assembly->image->aotid, info->aotid, 16);
2070 
2071 	if (version_symbol) {
2072 		/* Old file format */
2073 		version = atoi (version_symbol);
2074 	} else {
2075 		g_assert (info);
2076 		version = info->version;
2077 	}
2078 
2079 	if (version != MONO_AOT_FILE_VERSION) {
2080 		msg = g_strdup_printf ("wrong file format version (expected %d got %d)", MONO_AOT_FILE_VERSION, version);
2081 		usable = FALSE;
2082 	} else {
2083 		guint8 *blob;
2084 		void *handle;
2085 
2086 		if (info->flags & MONO_AOT_FILE_FLAG_SEPARATE_DATA) {
2087 			aot_data = open_aot_data (assembly, info, &handle);
2088 
2089 			blob = aot_data + info->table_offsets [MONO_AOT_TABLE_BLOB];
2090 		} else {
2091 			blob = (guint8 *)info->blob;
2092 		}
2093 
2094 		usable = check_usable (assembly, info, blob, &msg);
2095 	}
2096 
2097 	if (!usable) {
2098 		if (mono_aot_only && !mono_use_interpreter) {
2099 			g_error ("Failed to load AOT module '%s' while running in aot-only mode: %s.\n", found_aot_name, msg);
2100 		} else {
2101 			mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: module %s is unusable: %s.", found_aot_name, msg);
2102 		}
2103 		g_free (msg);
2104 		g_free (found_aot_name);
2105 		if (sofile)
2106 			mono_dl_close (sofile);
2107 		assembly->image->aot_module = NULL;
2108 		return;
2109 	}
2110 
2111 	/* Sanity check */
2112 	align_double = MONO_ABI_ALIGNOF (double);
2113 	align_int64 = MONO_ABI_ALIGNOF (gint64);
2114 	g_assert (info->double_align == align_double);
2115 	g_assert (info->long_align == align_int64);
2116 	g_assert (info->generic_tramp_num == MONO_TRAMPOLINE_NUM);
2117 
2118 	amodule = g_new0 (MonoAotModule, 1);
2119 	amodule->aot_name = found_aot_name;
2120 	amodule->assembly = assembly;
2121 
2122 	memcpy (&amodule->info, info, sizeof (*info));
2123 
2124 	amodule->got = (void **)amodule->info.jit_got;
2125 	amodule->llvm_got = (void **)amodule->info.llvm_got;
2126 	amodule->globals = globals;
2127 	amodule->sofile = sofile;
2128 	amodule->method_to_code = g_hash_table_new (mono_aligned_addr_hash, NULL);
2129 	amodule->extra_methods = g_hash_table_new (NULL, NULL);
2130 	amodule->shared_got = g_new0 (gpointer, info->nshared_got_entries);
2131 
2132 	if (info->flags & MONO_AOT_FILE_FLAG_SEPARATE_DATA) {
2133 		for (i = 0; i < MONO_AOT_TABLE_NUM; ++i)
2134 			amodule->tables [i] = aot_data + info->table_offsets [i];
2135 	}
2136 
2137 	mono_os_mutex_init_recursive (&amodule->mutex);
2138 
2139 	/* Read image table */
2140 	{
2141 		guint32 table_len, i;
2142 		char *table = NULL;
2143 
2144 		if (info->flags & MONO_AOT_FILE_FLAG_SEPARATE_DATA)
2145 			table = amodule->tables [MONO_AOT_TABLE_IMAGE_TABLE];
2146 		else
2147 			table = (char *)info->image_table;
2148 		g_assert (table);
2149 
2150 		table_len = *(guint32*)table;
2151 		table += sizeof (guint32);
2152 		amodule->image_table = g_new0 (MonoImage*, table_len);
2153 		amodule->image_names = g_new0 (MonoAssemblyName, table_len);
2154 		amodule->image_guids = g_new0 (char*, table_len);
2155 		amodule->image_table_len = table_len;
2156 		for (i = 0; i < table_len; ++i) {
2157 			MonoAssemblyName *aname = &(amodule->image_names [i]);
2158 
2159 			aname->name = g_strdup (table);
2160 			table += strlen (table) + 1;
2161 			amodule->image_guids [i] = g_strdup (table);
2162 			table += strlen (table) + 1;
2163 			if (table [0] != 0)
2164 				aname->culture = g_strdup (table);
2165 			table += strlen (table) + 1;
2166 			memcpy (aname->public_key_token, table, strlen (table) + 1);
2167 			table += strlen (table) + 1;
2168 
2169 			table = (char *)ALIGN_PTR_TO (table, 8);
2170 			aname->flags = *(guint32*)table;
2171 			table += 4;
2172 			aname->major = *(guint32*)table;
2173 			table += 4;
2174 			aname->minor = *(guint32*)table;
2175 			table += 4;
2176 			aname->build = *(guint32*)table;
2177 			table += 4;
2178 			aname->revision = *(guint32*)table;
2179 			table += 4;
2180 		}
2181 	}
2182 
2183 	amodule->jit_code_start = (guint8 *)info->jit_code_start;
2184 	amodule->jit_code_end = (guint8 *)info->jit_code_end;
2185 	if (info->flags & MONO_AOT_FILE_FLAG_SEPARATE_DATA) {
2186 		amodule->blob = amodule->tables [MONO_AOT_TABLE_BLOB];
2187 		amodule->method_info_offsets = amodule->tables [MONO_AOT_TABLE_METHOD_INFO_OFFSETS];
2188 		amodule->ex_info_offsets = amodule->tables [MONO_AOT_TABLE_EX_INFO_OFFSETS];
2189 		amodule->class_info_offsets = amodule->tables [MONO_AOT_TABLE_CLASS_INFO_OFFSETS];
2190 		amodule->class_name_table = amodule->tables [MONO_AOT_TABLE_CLASS_NAME];
2191 		amodule->extra_method_table = amodule->tables [MONO_AOT_TABLE_EXTRA_METHOD_TABLE];
2192 		amodule->extra_method_info_offsets = amodule->tables [MONO_AOT_TABLE_EXTRA_METHOD_INFO_OFFSETS];
2193 		amodule->got_info_offsets = amodule->tables [MONO_AOT_TABLE_GOT_INFO_OFFSETS];
2194 		amodule->llvm_got_info_offsets = amodule->tables [MONO_AOT_TABLE_LLVM_GOT_INFO_OFFSETS];
2195 		amodule->weak_field_indexes = amodule->tables [MONO_AOT_TABLE_WEAK_FIELD_INDEXES];
2196 	} else {
2197 		amodule->blob = info->blob;
2198 		amodule->method_info_offsets = (guint32 *)info->method_info_offsets;
2199 		amodule->ex_info_offsets = (guint32 *)info->ex_info_offsets;
2200 		amodule->class_info_offsets = (guint32 *)info->class_info_offsets;
2201 		amodule->class_name_table = (guint16 *)info->class_name_table;
2202 		amodule->extra_method_table = (guint32 *)info->extra_method_table;
2203 		amodule->extra_method_info_offsets = (guint32 *)info->extra_method_info_offsets;
2204 		amodule->got_info_offsets = info->got_info_offsets;
2205 		amodule->llvm_got_info_offsets = info->llvm_got_info_offsets;
2206 		amodule->weak_field_indexes = info->weak_field_indexes;
2207 	}
2208 	amodule->unbox_trampolines = (guint32 *)info->unbox_trampolines;
2209 	amodule->unbox_trampolines_end = (guint32 *)info->unbox_trampolines_end;
2210 	amodule->unbox_trampoline_addresses = (guint32 *)info->unbox_trampoline_addresses;
2211 	amodule->unwind_info = (guint8 *)info->unwind_info;
2212 	amodule->mem_begin = amodule->jit_code_start;
2213 	amodule->mem_end = (guint8 *)info->mem_end;
2214 	amodule->plt = (guint8 *)info->plt;
2215 	amodule->plt_end = (guint8 *)info->plt_end;
2216 	amodule->mono_eh_frame = (guint8 *)info->mono_eh_frame;
2217 	amodule->trampolines [MONO_AOT_TRAMP_SPECIFIC] = (guint8 *)info->specific_trampolines;
2218 	amodule->trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = (guint8 *)info->static_rgctx_trampolines;
2219 	amodule->trampolines [MONO_AOT_TRAMP_IMT] = (guint8 *)info->imt_trampolines;
2220 	amodule->trampolines [MONO_AOT_TRAMP_GSHAREDVT_ARG] = (guint8 *)info->gsharedvt_arg_trampolines;
2221 
2222 	if (!strcmp (assembly->aname.name, "mscorlib"))
2223 		mscorlib_aot_module = amodule;
2224 
2225 	/* Compute method addresses */
2226 	amodule->methods = (void **)g_malloc0 (amodule->info.nmethods * sizeof (gpointer));
2227 	for (i = 0; i < amodule->info.nmethods; ++i) {
2228 		void *addr = NULL;
2229 
2230 		if (amodule->info.llvm_get_method) {
2231 			gpointer (*get_method) (int) = (gpointer (*)(int))amodule->info.llvm_get_method;
2232 
2233 			addr = get_method (i);
2234 		}
2235 
2236 		/* method_addresses () contains a table of branches, since the ios linker can update those correctly */
2237 		if (!addr && amodule->info.method_addresses) {
2238 			addr = get_call_table_entry (amodule->info.method_addresses, i);
2239 			g_assert (addr);
2240 			if (addr == amodule->info.method_addresses)
2241 				addr = NULL;
2242 		}
2243 		if (addr == NULL)
2244 			amodule->methods [i] = GINT_TO_POINTER (-1);
2245 		else
2246 			amodule->methods [i] = addr;
2247 	}
2248 
2249 	if (make_unreadable) {
2250 #ifndef TARGET_WIN32
2251 		guint8 *addr;
2252 		guint8 *page_start, *page_end;
2253 		int err, len;
2254 
2255 		addr = amodule->mem_begin;
2256 		g_assert (addr);
2257 		len = amodule->mem_end - amodule->mem_begin;
2258 
2259 		/* Round down in both directions to avoid modifying data which is not ours */
2260 		page_start = (guint8 *) (((gssize) (addr)) & ~ (mono_pagesize () - 1)) + mono_pagesize ();
2261 		page_end = (guint8 *) (((gssize) (addr + len)) & ~ (mono_pagesize () - 1));
2262 		if (page_end > page_start) {
2263 			err = mono_mprotect (page_start, (page_end - page_start), MONO_MMAP_NONE);
2264 			g_assert (err == 0);
2265 		}
2266 #endif
2267 	}
2268 
2269 	/* Compute the boundaries of LLVM code */
2270 	if (info->flags & MONO_AOT_FILE_FLAG_WITH_LLVM)
2271 		compute_llvm_code_range (amodule, &amodule->llvm_code_start, &amodule->llvm_code_end);
2272 
2273 	mono_aot_lock ();
2274 
2275 	if (amodule->jit_code_start) {
2276 		aot_code_low_addr = MIN (aot_code_low_addr, (gsize)amodule->jit_code_start);
2277 		aot_code_high_addr = MAX (aot_code_high_addr, (gsize)amodule->jit_code_end);
2278 	}
2279 	if (amodule->llvm_code_start) {
2280 		aot_code_low_addr = MIN (aot_code_low_addr, (gsize)amodule->llvm_code_start);
2281 		aot_code_high_addr = MAX (aot_code_high_addr, (gsize)amodule->llvm_code_end);
2282 	}
2283 
2284 	g_hash_table_insert (aot_modules, assembly, amodule);
2285 	mono_aot_unlock ();
2286 
2287 	if (amodule->jit_code_start)
2288 		mono_jit_info_add_aot_module (assembly->image, amodule->jit_code_start, amodule->jit_code_end);
2289 	if (amodule->llvm_code_start)
2290 		mono_jit_info_add_aot_module (assembly->image, amodule->llvm_code_start, amodule->llvm_code_end);
2291 
2292 	assembly->image->aot_module = amodule;
2293 
2294 	if (mono_aot_only && !mono_llvm_only) {
2295 		char *code;
2296 		find_amodule_symbol (amodule, "specific_trampolines_page", (gpointer *)&code);
2297 		amodule->use_page_trampolines = code != NULL;
2298 		/*g_warning ("using page trampolines: %d", amodule->use_page_trampolines);*/
2299 	}
2300 
2301 	/*
2302 	 * Register the plt region as a single trampoline so we can unwind from this code
2303 	 */
2304 	mono_aot_tramp_info_register (
2305 		mono_tramp_info_create (
2306 			NULL,
2307 			amodule->plt,
2308 			amodule->plt_end - amodule->plt,
2309 			NULL,
2310 			mono_unwind_get_cie_program ()
2311 			),
2312 		NULL
2313 		);
2314 
2315 	/*
2316 	 * Since we store methoddef and classdef tokens when referring to methods/classes in
2317 	 * referenced assemblies, we depend on the exact versions of the referenced assemblies.
2318 	 * MS calls this 'hard binding'. This means we have to load all referenced assemblies
2319 	 * non-lazily, since we can't handle out-of-date errors later.
2320 	 * The cached class info also depends on the exact assemblies.
2321 	 */
2322 	if (do_load_image) {
2323 		for (i = 0; i < amodule->image_table_len; ++i) {
2324 			MonoError error;
2325 			load_image (amodule, i, &error);
2326 			mono_error_cleanup (&error); /* FIXME don't swallow the error */
2327 		}
2328 	}
2329 
2330 	if (amodule->out_of_date) {
2331 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: Module %s is unusable because a dependency is out-of-date.", assembly->image->name);
2332 		if (mono_aot_only)
2333 			g_error ("Failed to load AOT module '%s' while running in aot-only mode because a dependency cannot be found or it is out of date.\n", found_aot_name);
2334 	} else {
2335 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: image '%s' found.", found_aot_name);
2336 	}
2337 }
2338 
2339 /*
2340  * mono_aot_register_module:
2341  *
2342  * This should be called by embedding code to register normal AOT modules statically linked
2343  * into the executable.
2344  *
2345  * \param aot_info the value of the 'mono_aot_module_<ASSEMBLY_NAME>_info' global symbol from the AOT module.
2346  */
2347 void
mono_aot_register_module(gpointer * aot_info)2348 mono_aot_register_module (gpointer *aot_info)
2349 {
2350 	gpointer *globals;
2351 	char *aname;
2352 	MonoAotFileInfo *info = (MonoAotFileInfo *)aot_info;
2353 
2354 	g_assert (info->version == MONO_AOT_FILE_VERSION);
2355 
2356 	if (!(info->flags & MONO_AOT_FILE_FLAG_LLVM_ONLY)) {
2357 		globals = (void **)info->globals;
2358 		g_assert (globals);
2359 	}
2360 
2361 	aname = (char *)info->assembly_name;
2362 
2363 	/* This could be called before startup */
2364 	if (aot_modules)
2365 		mono_aot_lock ();
2366 
2367 	if (!static_aot_modules)
2368 		static_aot_modules = g_hash_table_new (g_str_hash, g_str_equal);
2369 
2370 	g_hash_table_insert (static_aot_modules, aname, info);
2371 
2372 	if (info->flags & MONO_AOT_FILE_FLAG_EAGER_LOAD) {
2373 		g_assert (!container_assm_name);
2374 		container_assm_name = aname;
2375 	}
2376 
2377 	if (aot_modules)
2378 		mono_aot_unlock ();
2379 }
2380 
2381 void
mono_aot_init(void)2382 mono_aot_init (void)
2383 {
2384 	mono_os_mutex_init_recursive (&aot_mutex);
2385 	mono_os_mutex_init_recursive (&aot_page_mutex);
2386 	aot_modules = g_hash_table_new (NULL, NULL);
2387 
2388 	mono_install_assembly_load_hook (load_aot_module, NULL);
2389 	mono_counters_register ("Async JIT info size", MONO_COUNTER_INT|MONO_COUNTER_JIT, &async_jit_info_size);
2390 
2391 	char *lastaot = g_getenv ("MONO_LASTAOT");
2392 	if (lastaot) {
2393 		mono_last_aot_method = atoi (lastaot);
2394 		g_free (lastaot);
2395 	}
2396 	aot_cache_init ();
2397 }
2398 
2399 void
mono_aot_cleanup(void)2400 mono_aot_cleanup (void)
2401 {
2402 	if (aot_jit_icall_hash)
2403 		g_hash_table_destroy (aot_jit_icall_hash);
2404 	if (aot_modules)
2405 		g_hash_table_destroy (aot_modules);
2406 }
2407 
2408 static gboolean
decode_cached_class_info(MonoAotModule * module,MonoCachedClassInfo * info,guint8 * buf,guint8 ** endbuf)2409 decode_cached_class_info (MonoAotModule *module, MonoCachedClassInfo *info, guint8 *buf, guint8 **endbuf)
2410 {
2411 	MonoError error;
2412 	guint32 flags;
2413 	MethodRef ref;
2414 	gboolean res;
2415 
2416 	info->vtable_size = decode_value (buf, &buf);
2417 	if (info->vtable_size == -1)
2418 		/* Generic type */
2419 		return FALSE;
2420 	flags = decode_value (buf, &buf);
2421 	info->ghcimpl = (flags >> 0) & 0x1;
2422 	info->has_finalize = (flags >> 1) & 0x1;
2423 	info->has_cctor = (flags >> 2) & 0x1;
2424 	info->has_nested_classes = (flags >> 3) & 0x1;
2425 	info->blittable = (flags >> 4) & 0x1;
2426 	info->has_references = (flags >> 5) & 0x1;
2427 	info->has_static_refs = (flags >> 6) & 0x1;
2428 	info->no_special_static_fields = (flags >> 7) & 0x1;
2429 	info->is_generic_container = (flags >> 8) & 0x1;
2430 	info->has_weak_fields = (flags >> 9) & 0x1;
2431 
2432 	if (info->has_cctor) {
2433 		res = decode_method_ref (module, &ref, buf, &buf, &error);
2434 		mono_error_assert_ok (&error); /* FIXME don't swallow the error */
2435 		if (!res)
2436 			return FALSE;
2437 		info->cctor_token = ref.token;
2438 	}
2439 	if (info->has_finalize) {
2440 		res = decode_method_ref (module, &ref, buf, &buf, &error);
2441 		mono_error_assert_ok (&error); /* FIXME don't swallow the error */
2442 		if (!res)
2443 			return FALSE;
2444 		info->finalize_image = ref.image;
2445 		info->finalize_token = ref.token;
2446 	}
2447 
2448 	info->instance_size = decode_value (buf, &buf);
2449 	info->class_size = decode_value (buf, &buf);
2450 	info->packing_size = decode_value (buf, &buf);
2451 	info->min_align = decode_value (buf, &buf);
2452 
2453 	*endbuf = buf;
2454 
2455 	return TRUE;
2456 }
2457 
2458 gpointer
mono_aot_get_method_from_vt_slot(MonoDomain * domain,MonoVTable * vtable,int slot,MonoError * error)2459 mono_aot_get_method_from_vt_slot (MonoDomain *domain, MonoVTable *vtable, int slot, MonoError *error)
2460 {
2461 	int i;
2462 	MonoClass *klass = vtable->klass;
2463 	MonoAotModule *amodule = (MonoAotModule *)klass->image->aot_module;
2464 	guint8 *info, *p;
2465 	MonoCachedClassInfo class_info;
2466 	gboolean err;
2467 	MethodRef ref;
2468 	gboolean res;
2469 	gpointer addr;
2470 	MonoError inner_error;
2471 
2472 	error_init (error);
2473 
2474 	if (MONO_CLASS_IS_INTERFACE (klass) || klass->rank || !amodule)
2475 		return NULL;
2476 
2477 	info = &amodule->blob [mono_aot_get_offset (amodule->class_info_offsets, mono_metadata_token_index (klass->type_token) - 1)];
2478 	p = info;
2479 
2480 	err = decode_cached_class_info (amodule, &class_info, p, &p);
2481 	if (!err)
2482 		return NULL;
2483 
2484 	for (i = 0; i < slot; ++i) {
2485 		decode_method_ref (amodule, &ref, p, &p, &inner_error);
2486 		mono_error_cleanup (&inner_error); /* FIXME don't swallow the error */
2487 	}
2488 
2489 	res = decode_method_ref (amodule, &ref, p, &p, &inner_error);
2490 	mono_error_cleanup (&inner_error); /* FIXME don't swallow the error */
2491 	if (!res)
2492 		return NULL;
2493 	if (ref.no_aot_trampoline)
2494 		return NULL;
2495 
2496 	if (mono_metadata_token_index (ref.token) == 0 || mono_metadata_token_table (ref.token) != MONO_TABLE_METHOD)
2497 		return NULL;
2498 
2499 	addr = mono_aot_get_method_from_token (domain, ref.image, ref.token, error);
2500 	return addr;
2501 }
2502 
2503 gboolean
mono_aot_get_cached_class_info(MonoClass * klass,MonoCachedClassInfo * res)2504 mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
2505 {
2506 	MonoAotModule *amodule = (MonoAotModule *)klass->image->aot_module;
2507 	guint8 *p;
2508 	gboolean err;
2509 
2510 	if (klass->rank || !klass->type_token || !amodule)
2511 		return FALSE;
2512 
2513 	p = (guint8*)&amodule->blob [mono_aot_get_offset (amodule->class_info_offsets, mono_metadata_token_index (klass->type_token) - 1)];
2514 
2515 	err = decode_cached_class_info (amodule, res, p, &p);
2516 	if (!err)
2517 		return FALSE;
2518 
2519 	return TRUE;
2520 }
2521 
2522 /**
2523  * mono_aot_get_class_from_name:
2524  *
2525  *  Obtains a MonoClass with a given namespace and a given name which is located in IMAGE,
2526  * using a cache stored in the AOT file.
2527  * Stores the resulting class in *KLASS if found, stores NULL otherwise.
2528  *
2529  * Returns: TRUE if the klass was found/not found in the cache, FALSE if no aot file was
2530  * found.
2531  */
2532 gboolean
mono_aot_get_class_from_name(MonoImage * image,const char * name_space,const char * name,MonoClass ** klass)2533 mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const char *name, MonoClass **klass)
2534 {
2535 	MonoAotModule *amodule = (MonoAotModule *)image->aot_module;
2536 	guint16 *table, *entry;
2537 	guint16 table_size;
2538 	guint32 hash;
2539 	char full_name_buf [1024];
2540 	char *full_name;
2541 	const char *name2, *name_space2;
2542 	MonoTableInfo  *t;
2543 	guint32 cols [MONO_TYPEDEF_SIZE];
2544 	GHashTable *nspace_table;
2545 
2546 	if (!amodule || !amodule->class_name_table)
2547 		return FALSE;
2548 
2549 	amodule_lock (amodule);
2550 
2551 	*klass = NULL;
2552 
2553 	/* First look in the cache */
2554 	if (!amodule->name_cache)
2555 		amodule->name_cache = g_hash_table_new (g_str_hash, g_str_equal);
2556 	nspace_table = (GHashTable *)g_hash_table_lookup (amodule->name_cache, name_space);
2557 	if (nspace_table) {
2558 		*klass = (MonoClass *)g_hash_table_lookup (nspace_table, name);
2559 		if (*klass) {
2560 			amodule_unlock (amodule);
2561 			return TRUE;
2562 		}
2563 	}
2564 
2565 	table_size = amodule->class_name_table [0];
2566 	table = amodule->class_name_table + 1;
2567 
2568 	if (name_space [0] == '\0')
2569 		full_name = g_strdup_printf ("%s", name);
2570 	else {
2571 		if (strlen (name_space) + strlen (name) < 1000) {
2572 			sprintf (full_name_buf, "%s.%s", name_space, name);
2573 			full_name = full_name_buf;
2574 		} else {
2575 			full_name = g_strdup_printf ("%s.%s", name_space, name);
2576 		}
2577 	}
2578 	hash = mono_metadata_str_hash (full_name) % table_size;
2579 	if (full_name != full_name_buf)
2580 		g_free (full_name);
2581 
2582 	entry = &table [hash * 2];
2583 
2584 	if (entry [0] != 0) {
2585 		t = &image->tables [MONO_TABLE_TYPEDEF];
2586 
2587 		while (TRUE) {
2588 			guint32 index = entry [0];
2589 			guint32 next = entry [1];
2590 			guint32 token = mono_metadata_make_token (MONO_TABLE_TYPEDEF, index);
2591 
2592 			name_table_accesses ++;
2593 
2594 			mono_metadata_decode_row (t, index - 1, cols, MONO_TYPEDEF_SIZE);
2595 
2596 			name2 = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
2597 			name_space2 = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
2598 
2599 			if (!strcmp (name, name2) && !strcmp (name_space, name_space2)) {
2600 				MonoError error;
2601 				amodule_unlock (amodule);
2602 				*klass = mono_class_get_checked (image, token, &error);
2603 				if (!mono_error_ok (&error))
2604 					mono_error_cleanup (&error); /* FIXME don't swallow the error */
2605 
2606 				/* Add to cache */
2607 				if (*klass) {
2608 					amodule_lock (amodule);
2609 					nspace_table = (GHashTable *)g_hash_table_lookup (amodule->name_cache, name_space);
2610 					if (!nspace_table) {
2611 						nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
2612 						g_hash_table_insert (amodule->name_cache, (char*)name_space2, nspace_table);
2613 					}
2614 					g_hash_table_insert (nspace_table, (char*)name2, *klass);
2615 					amodule_unlock (amodule);
2616 				}
2617 				return TRUE;
2618 			}
2619 
2620 			if (next != 0) {
2621 				entry = &table [next * 2];
2622 			} else {
2623 				break;
2624 			}
2625 		}
2626 	}
2627 
2628 	amodule_unlock (amodule);
2629 
2630 	return TRUE;
2631 }
2632 
2633 GHashTable *
mono_aot_get_weak_field_indexes(MonoImage * image)2634 mono_aot_get_weak_field_indexes (MonoImage *image)
2635 {
2636 	MonoAotModule *amodule = (MonoAotModule *)image->aot_module;
2637 
2638 	if (!amodule)
2639 		return NULL;
2640 
2641 	/* Initialize weak field indexes from the cached copy */
2642 	guint32 *indexes = amodule->weak_field_indexes;
2643 	int len  = indexes [0];
2644 	GHashTable *indexes_hash = g_hash_table_new (NULL, NULL);
2645 	for (int i = 0; i < len; ++i)
2646 		g_hash_table_insert (indexes_hash, GUINT_TO_POINTER (indexes [i + 1]), GUINT_TO_POINTER (1));
2647 	return indexes_hash;
2648 }
2649 
2650 /* Compute the boundaries of the LLVM code for AMODULE. */
2651 static void
compute_llvm_code_range(MonoAotModule * amodule,guint8 ** code_start,guint8 ** code_end)2652 compute_llvm_code_range (MonoAotModule *amodule, guint8 **code_start, guint8 **code_end)
2653 {
2654 	guint8 *p;
2655 	int version, fde_count;
2656 	gint32 *table;
2657 
2658 	if (amodule->info.llvm_get_method) {
2659 		gpointer (*get_method) (int) = (gpointer (*)(int))amodule->info.llvm_get_method;
2660 
2661 		*code_start = (guint8 *)get_method (-1);
2662 		*code_end = (guint8 *)get_method (-2);
2663 
2664 		g_assert (*code_end > *code_start);
2665 		return;
2666 	}
2667 
2668 	g_assert (amodule->mono_eh_frame);
2669 
2670 	p = amodule->mono_eh_frame;
2671 
2672 	/* p points to data emitted by LLVM in DwarfException::EmitMonoEHFrame () */
2673 
2674 	/* Header */
2675 	version = *p;
2676 	g_assert (version == 3);
2677 	p ++;
2678 	p ++;
2679 	p = (guint8 *)ALIGN_PTR_TO (p, 4);
2680 
2681 	fde_count = *(guint32*)p;
2682 	p += 4;
2683 	table = (gint32*)p;
2684 
2685 	if (fde_count > 0) {
2686 		*code_start = (guint8 *)amodule->methods [table [0]];
2687 		*code_end = (guint8*)amodule->methods [table [(fde_count - 1) * 2]] + table [fde_count * 2];
2688 	} else {
2689 		*code_start = NULL;
2690 		*code_end = NULL;
2691 	}
2692 }
2693 
2694 static gboolean
is_llvm_code(MonoAotModule * amodule,guint8 * code)2695 is_llvm_code (MonoAotModule *amodule, guint8 *code)
2696 {
2697 	if ((guint8*)code >= amodule->llvm_code_start && (guint8*)code < amodule->llvm_code_end)
2698 		return TRUE;
2699 	else
2700 		return FALSE;
2701 }
2702 
2703 static gboolean
is_thumb_code(MonoAotModule * amodule,guint8 * code)2704 is_thumb_code (MonoAotModule *amodule, guint8 *code)
2705 {
2706 	if (is_llvm_code (amodule, code) && (amodule->info.flags & MONO_AOT_FILE_FLAG_LLVM_THUMB))
2707 		return TRUE;
2708 	else
2709 		return FALSE;
2710 }
2711 
2712 /*
2713  * decode_llvm_mono_eh_frame:
2714  *
2715  *   Decode the EH information emitted by our modified LLVM compiler and construct a
2716  * MonoJitInfo structure from it.
2717  * If JINFO is NULL, set OUT_LLVM_CLAUSES to the number of llvm level clauses.
2718  * This function is async safe when called in async context.
2719  */
2720 static void
decode_llvm_mono_eh_frame(MonoAotModule * amodule,MonoDomain * domain,MonoJitInfo * jinfo,guint8 * code,guint32 code_len,MonoJitExceptionInfo * clauses,int num_clauses,GSList ** nesting,int * this_reg,int * this_offset,int * out_llvm_clauses)2721 decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, MonoJitInfo *jinfo,
2722 						   guint8 *code, guint32 code_len,
2723 						   MonoJitExceptionInfo *clauses, int num_clauses,
2724 						   GSList **nesting,
2725 						   int *this_reg, int *this_offset, int *out_llvm_clauses)
2726 {
2727 	guint8 *p, *code1, *code2;
2728 	guint8 *fde, *cie, *code_start, *code_end;
2729 	int version, fde_count;
2730 	gint32 *table;
2731 	int i, pos, left, right;
2732 	MonoJitExceptionInfo *ei;
2733 	guint32 fde_len, ei_len, nested_len, nindex;
2734 	gpointer *type_info;
2735 	MonoLLVMFDEInfo info;
2736 	guint8 *unw_info;
2737 	gboolean async;
2738 
2739 	async = mono_thread_info_is_async_context ();
2740 
2741 	if (!amodule->mono_eh_frame) {
2742 		if (!jinfo) {
2743 			*out_llvm_clauses = num_clauses;
2744 			return;
2745 		}
2746 		memcpy (jinfo->clauses, clauses, num_clauses * sizeof (MonoJitExceptionInfo));
2747 		return;
2748 	}
2749 
2750 	g_assert (amodule->mono_eh_frame && code);
2751 
2752 	p = amodule->mono_eh_frame;
2753 
2754 	/* p points to data emitted by LLVM in DwarfMonoException::EmitMonoEHFrame () */
2755 
2756 	/* Header */
2757 	version = *p;
2758 	g_assert (version == 3);
2759 	p ++;
2760 	/* func_encoding = *p; */
2761 	p ++;
2762 	p = (guint8 *)ALIGN_PTR_TO (p, 4);
2763 
2764 	fde_count = *(guint32*)p;
2765 	p += 4;
2766 	table = (gint32*)p;
2767 
2768 	/* There is +1 entry in the table */
2769 	cie = p + ((fde_count + 1) * 8);
2770 
2771 	/* Binary search in the table to find the entry for code */
2772 	left = 0;
2773 	right = fde_count;
2774 	while (TRUE) {
2775 		pos = (left + right) / 2;
2776 
2777 		/* The table contains method index/fde offset pairs */
2778 		g_assert (table [(pos * 2)] != -1);
2779 		code1 = (guint8 *)amodule->methods [table [(pos * 2)]];
2780 		if (pos + 1 == fde_count) {
2781 			code2 = amodule->llvm_code_end;
2782 		} else {
2783 			g_assert (table [(pos + 1) * 2] != -1);
2784 			code2 = (guint8 *)amodule->methods [table [(pos + 1) * 2]];
2785 		}
2786 
2787 		if (code < code1)
2788 			right = pos;
2789 		else if (code >= code2)
2790 			left = pos + 1;
2791 		else
2792 			break;
2793 	}
2794 
2795 	code_start = (guint8 *)amodule->methods [table [(pos * 2)]];
2796 	if (pos + 1 == fde_count) {
2797 		/* The +1 entry in the table contains the length of the last method */
2798 		int len = table [(pos + 1) * 2];
2799 		code_end = code_start + len;
2800 	} else {
2801 		code_end = (guint8 *)amodule->methods [table [(pos + 1) * 2]];
2802 	}
2803 	if (!code_len)
2804 		code_len = code_end - code_start;
2805 
2806 	g_assert (code >= code_start && code < code_end);
2807 
2808 	if (is_thumb_code (amodule, code_start))
2809 		/* Clear thumb flag */
2810 		code_start = (guint8*)(((mgreg_t)code_start) & ~1);
2811 
2812 	fde = amodule->mono_eh_frame + table [(pos * 2) + 1];
2813 	/* This won't overflow because there is +1 entry in the table */
2814 	fde_len = table [(pos * 2) + 2 + 1] - table [(pos * 2) + 1];
2815 
2816 	/* Compute lengths */
2817 	mono_unwind_decode_llvm_mono_fde (fde, fde_len, cie, code_start, &info, NULL, NULL, NULL);
2818 
2819 	if (async) {
2820 		/* These are leaked, but the leak is bounded */
2821 		ei = mono_domain_alloc0_lock_free (domain, info.ex_info_len * sizeof (MonoJitExceptionInfo));
2822 		type_info = mono_domain_alloc0_lock_free (domain, info.ex_info_len * sizeof (gpointer));
2823 		unw_info = mono_domain_alloc0_lock_free (domain, info.unw_info_len);
2824 	} else {
2825 		ei = (MonoJitExceptionInfo *)g_malloc0 (info.ex_info_len * sizeof (MonoJitExceptionInfo));
2826 		type_info = (gpointer *)g_malloc0 (info.ex_info_len * sizeof (gpointer));
2827 		unw_info = (guint8*)g_malloc0 (info.unw_info_len);
2828 	}
2829 	mono_unwind_decode_llvm_mono_fde (fde, fde_len, cie, code_start, &info, ei, type_info, unw_info);
2830 
2831 	ei_len = info.ex_info_len;
2832 	*this_reg = info.this_reg;
2833 	*this_offset = info.this_offset;
2834 
2835 	/*
2836 	 * LLVM might represent one IL region with multiple regions.
2837 	 */
2838 
2839 	/* Count number of nested clauses */
2840 	nested_len = 0;
2841 	for (i = 0; i < ei_len; ++i) {
2842 		/* This might be unaligned */
2843 		gint32 cindex1 = read32 (type_info [i]);
2844 		GSList *l;
2845 
2846 		for (l = nesting [cindex1]; l; l = l->next)
2847 			nested_len ++;
2848 	}
2849 
2850 	if (!jinfo) {
2851 		*out_llvm_clauses = ei_len + nested_len;
2852 		return;
2853 	}
2854 
2855 	/* Store the unwind info addr/length in the MonoJitInfo structure itself so its async safe */
2856 	MonoUnwindJitInfo *jinfo_unwind = mono_jit_info_get_unwind_info (jinfo);
2857 	g_assert (jinfo_unwind);
2858 	jinfo_unwind->unw_info = unw_info;
2859 	jinfo_unwind->unw_info_len = info.unw_info_len;
2860 
2861 	for (i = 0; i < ei_len; ++i) {
2862 		/*
2863 		 * clauses contains the original IL exception info saved by the AOT
2864 		 * compiler, we have to combine that with the information produced by LLVM
2865 		 */
2866 		/* The type_info entries contain IL clause indexes */
2867 		int clause_index = read32 (type_info [i]);
2868 		MonoJitExceptionInfo *jei = &jinfo->clauses [i];
2869 		MonoJitExceptionInfo *orig_jei = &clauses [clause_index];
2870 
2871 		g_assert (clause_index < num_clauses);
2872 		jei->flags = orig_jei->flags;
2873 		jei->data.catch_class = orig_jei->data.catch_class;
2874 
2875 		jei->try_start = ei [i].try_start;
2876 		jei->try_end = ei [i].try_end;
2877 		jei->handler_start = ei [i].handler_start;
2878 		jei->clause_index = clause_index;
2879 
2880 		if (is_thumb_code (amodule, (guint8 *)jei->try_start)) {
2881 			jei->try_start = (void*)((mgreg_t)jei->try_start & ~1);
2882 			jei->try_end = (void*)((mgreg_t)jei->try_end & ~1);
2883 			/* Make sure we transition to thumb when a handler starts */
2884 			jei->handler_start = (void*)((mgreg_t)jei->handler_start + 1);
2885 		}
2886 	}
2887 
2888 	/* See exception_cb () in mini-llvm.c as to why this is needed */
2889 	nindex = ei_len;
2890 	for (i = 0; i < ei_len; ++i) {
2891 		gint32 cindex1 = read32 (type_info [i]);
2892 		GSList *l;
2893 
2894 		for (l = nesting [cindex1]; l; l = l->next) {
2895 			gint32 nesting_cindex = GPOINTER_TO_INT (l->data);
2896 			MonoJitExceptionInfo *nesting_ei;
2897 			MonoJitExceptionInfo *nesting_clause = &clauses [nesting_cindex];
2898 
2899 			nesting_ei = &jinfo->clauses [nindex];
2900 			nindex ++;
2901 
2902 			memcpy (nesting_ei, &jinfo->clauses [i], sizeof (MonoJitExceptionInfo));
2903 			nesting_ei->flags = nesting_clause->flags;
2904 			nesting_ei->data.catch_class = nesting_clause->data.catch_class;
2905 			nesting_ei->clause_index = nesting_cindex;
2906 		}
2907 	}
2908 	g_assert (nindex == ei_len + nested_len);
2909 }
2910 
2911 static gpointer
alloc0_jit_info_data(MonoDomain * domain,int size,gboolean async_context)2912 alloc0_jit_info_data (MonoDomain *domain, int size, gboolean async_context)
2913 {
2914 	gpointer res;
2915 
2916 	if (async_context) {
2917 		res = mono_domain_alloc0_lock_free (domain, size);
2918 		mono_atomic_fetch_add_i32 (&async_jit_info_size, size);
2919 	} else {
2920 		res = mono_domain_alloc0 (domain, size);
2921 	}
2922 	return res;
2923 }
2924 
2925 /*
2926  * LOCKING: Acquires the domain lock.
2927  * In async context, this is async safe.
2928  */
2929 static MonoJitInfo*
decode_exception_debug_info(MonoAotModule * amodule,MonoDomain * domain,MonoMethod * method,guint8 * ex_info,guint8 * code,guint32 code_len)2930 decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
2931 							 MonoMethod *method, guint8* ex_info,
2932 							 guint8 *code, guint32 code_len)
2933 {
2934 	MonoError error;
2935 	int i, buf_len, num_clauses, len;
2936 	MonoJitInfo *jinfo;
2937 	MonoJitInfoFlags flags = JIT_INFO_NONE;
2938 	guint unwind_info, eflags;
2939 	gboolean has_generic_jit_info, has_dwarf_unwind_info, has_clauses, has_seq_points, has_try_block_holes, has_arch_eh_jit_info;
2940 	gboolean from_llvm, has_gc_map;
2941 	guint8 *p;
2942 	int try_holes_info_size, num_holes;
2943 	int this_reg = 0, this_offset = 0;
2944 	gboolean async;
2945 
2946 	/* Load the method info from the AOT file */
2947 	async = mono_thread_info_is_async_context ();
2948 
2949 	p = ex_info;
2950 	eflags = decode_value (p, &p);
2951 	has_generic_jit_info = (eflags & 1) != 0;
2952 	has_dwarf_unwind_info = (eflags & 2) != 0;
2953 	has_clauses = (eflags & 4) != 0;
2954 	has_seq_points = (eflags & 8) != 0;
2955 	from_llvm = (eflags & 16) != 0;
2956 	has_try_block_holes = (eflags & 32) != 0;
2957 	has_gc_map = (eflags & 64) != 0;
2958 	has_arch_eh_jit_info = (eflags & 128) != 0;
2959 
2960 	if (has_dwarf_unwind_info) {
2961 		unwind_info = decode_value (p, &p);
2962 		g_assert (unwind_info < (1 << 30));
2963 	} else {
2964 		unwind_info = decode_value (p, &p);
2965 	}
2966 	if (has_generic_jit_info)
2967 		flags = (MonoJitInfoFlags)(flags | JIT_INFO_HAS_GENERIC_JIT_INFO);
2968 
2969 	if (has_try_block_holes) {
2970 		num_holes = decode_value (p, &p);
2971 		flags = (MonoJitInfoFlags)(flags | JIT_INFO_HAS_TRY_BLOCK_HOLES);
2972 		try_holes_info_size = sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
2973 	} else {
2974 		num_holes = try_holes_info_size = 0;
2975 	}
2976 
2977 	if (has_arch_eh_jit_info) {
2978 		flags = (MonoJitInfoFlags)(flags | JIT_INFO_HAS_ARCH_EH_INFO);
2979 		/* Overwrite the original code_len which includes alignment padding */
2980 		code_len = decode_value (p, &p);
2981 	}
2982 
2983 	/* Exception table */
2984 	if (has_clauses)
2985 		num_clauses = decode_value (p, &p);
2986 	else
2987 		num_clauses = 0;
2988 
2989 	if (from_llvm) {
2990 		MonoJitExceptionInfo *clauses;
2991 		GSList **nesting;
2992 
2993 		/*
2994 		 * Part of the info is encoded by the AOT compiler, the rest is in the .eh_frame
2995 		 * section.
2996 		 */
2997 		if (async) {
2998 			if (num_clauses < 16) {
2999 				clauses = g_newa (MonoJitExceptionInfo, num_clauses);
3000 				nesting = g_newa (GSList*, num_clauses);
3001 			} else {
3002 				clauses = alloc0_jit_info_data (domain, sizeof (MonoJitExceptionInfo) * num_clauses, TRUE);
3003 				nesting = alloc0_jit_info_data (domain, sizeof (GSList*) * num_clauses, TRUE);
3004 			}
3005 			memset (clauses, 0, sizeof (MonoJitExceptionInfo) * num_clauses);
3006 			memset (nesting, 0, sizeof (GSList*) * num_clauses);
3007 		} else {
3008 			clauses = g_new0 (MonoJitExceptionInfo, num_clauses);
3009 			nesting = g_new0 (GSList*, num_clauses);
3010 		}
3011 
3012 		for (i = 0; i < num_clauses; ++i) {
3013 			MonoJitExceptionInfo *ei = &clauses [i];
3014 
3015 			ei->flags = decode_value (p, &p);
3016 
3017 			if (!(ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
3018 				int len = decode_value (p, &p);
3019 
3020 				if (len > 0) {
3021 					if (async) {
3022 						p += len;
3023 					} else {
3024 						ei->data.catch_class = decode_klass_ref (amodule, p, &p, &error);
3025 						mono_error_cleanup (&error); /* FIXME don't swallow the error */
3026 					}
3027 				}
3028 			}
3029 
3030 			ei->clause_index = i;
3031 
3032 			ei->try_offset = decode_value (p, &p);
3033 			ei->try_len = decode_value (p, &p);
3034 			ei->handler_offset = decode_value (p, &p);
3035 			ei->handler_len = decode_value (p, &p);
3036 
3037 			/* Read the list of nesting clauses */
3038 			while (TRUE) {
3039 				int nesting_index = decode_value (p, &p);
3040 				if (nesting_index == -1)
3041 					break;
3042 				// FIXME: async
3043 				g_assert (!async);
3044 				nesting [i] = g_slist_prepend (nesting [i], GINT_TO_POINTER (nesting_index));
3045 			}
3046 		}
3047 
3048 		flags |= JIT_INFO_HAS_UNWIND_INFO;
3049 
3050 		int num_llvm_clauses;
3051 		/* Get the length first */
3052 		decode_llvm_mono_eh_frame (amodule, domain, NULL, code, code_len, clauses, num_clauses, nesting, &this_reg, &this_offset, &num_llvm_clauses);
3053 		len = mono_jit_info_size (flags, num_llvm_clauses, num_holes);
3054 		jinfo = (MonoJitInfo *)alloc0_jit_info_data (domain, len, async);
3055 		mono_jit_info_init (jinfo, method, code, code_len, flags, num_llvm_clauses, num_holes);
3056 
3057 		decode_llvm_mono_eh_frame (amodule, domain, jinfo, code, code_len, clauses, num_clauses, nesting, &this_reg, &this_offset, NULL);
3058 
3059 		if (!async) {
3060 			g_free (clauses);
3061 			for (i = 0; i < num_clauses; ++i)
3062 				g_slist_free (nesting [i]);
3063 			g_free (nesting);
3064 		}
3065 		jinfo->from_llvm = 1;
3066 	} else {
3067 		len = mono_jit_info_size (flags, num_clauses, num_holes);
3068 		jinfo = (MonoJitInfo *)alloc0_jit_info_data (domain, len, async);
3069 		mono_jit_info_init (jinfo, method, code, code_len, flags, num_clauses, num_holes);
3070 
3071 		for (i = 0; i < jinfo->num_clauses; ++i) {
3072 			MonoJitExceptionInfo *ei = &jinfo->clauses [i];
3073 
3074 			ei->flags = decode_value (p, &p);
3075 
3076 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
3077 			/* Not used for catch clauses */
3078 			if (ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
3079 				ei->exvar_offset = decode_value (p, &p);
3080 #else
3081 			ei->exvar_offset = decode_value (p, &p);
3082 #endif
3083 
3084 			if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
3085 				ei->data.filter = code + decode_value (p, &p);
3086 			else {
3087 				int len = decode_value (p, &p);
3088 
3089 				if (len > 0) {
3090 					if (async) {
3091 						p += len;
3092 					} else {
3093 						ei->data.catch_class = decode_klass_ref (amodule, p, &p, &error);
3094 						mono_error_cleanup (&error); /* FIXME don't swallow the error */
3095 					}
3096 				}
3097 			}
3098 
3099 			ei->try_start = code + decode_value (p, &p);
3100 			ei->try_end = code + decode_value (p, &p);
3101 			ei->handler_start = code + decode_value (p, &p);
3102 		}
3103 
3104 		jinfo->unwind_info = unwind_info;
3105 		jinfo->domain_neutral = 0;
3106 		jinfo->from_aot = 1;
3107 	}
3108 
3109 	if (has_try_block_holes) {
3110 		MonoTryBlockHoleTableJitInfo *table;
3111 
3112 		g_assert (jinfo->has_try_block_holes);
3113 
3114 		table = mono_jit_info_get_try_block_hole_table_info (jinfo);
3115 		g_assert (table);
3116 
3117 		table->num_holes = (guint16)num_holes;
3118 		for (i = 0; i < num_holes; ++i) {
3119 			MonoTryBlockHoleJitInfo *hole = &table->holes [i];
3120 			hole->clause = decode_value (p, &p);
3121 			hole->length = decode_value (p, &p);
3122 			hole->offset = decode_value (p, &p);
3123 		}
3124 	}
3125 
3126 	if (has_arch_eh_jit_info) {
3127 		MonoArchEHJitInfo *eh_info;
3128 
3129 		g_assert (jinfo->has_arch_eh_info);
3130 
3131 		eh_info = mono_jit_info_get_arch_eh_info (jinfo);
3132 		eh_info->stack_size = decode_value (p, &p);
3133 		eh_info->epilog_size = decode_value (p, &p);
3134 	}
3135 
3136 	if (async) {
3137 		/* The rest is not needed in async mode */
3138 		jinfo->async = TRUE;
3139 		jinfo->d.aot_info = amodule;
3140 		// FIXME: Cache
3141 		return jinfo;
3142 	}
3143 
3144 	if (has_generic_jit_info) {
3145 		MonoGenericJitInfo *gi;
3146 		int len;
3147 
3148 		g_assert (jinfo->has_generic_jit_info);
3149 
3150 		gi = mono_jit_info_get_generic_jit_info (jinfo);
3151 		g_assert (gi);
3152 
3153 		gi->nlocs = decode_value (p, &p);
3154 		if (gi->nlocs) {
3155 			gi->locations = (MonoDwarfLocListEntry *)alloc0_jit_info_data (domain, gi->nlocs * sizeof (MonoDwarfLocListEntry), async);
3156 			for (i = 0; i < gi->nlocs; ++i) {
3157 				MonoDwarfLocListEntry *entry = &gi->locations [i];
3158 
3159 				entry->is_reg = decode_value (p, &p);
3160 				entry->reg = decode_value (p, &p);
3161 				if (!entry->is_reg)
3162 					entry->offset = decode_value (p, &p);
3163 				if (i > 0)
3164 					entry->from = decode_value (p, &p);
3165 				entry->to = decode_value (p, &p);
3166 			}
3167 			gi->has_this = 1;
3168 		} else {
3169 			if (from_llvm) {
3170 				gi->has_this = this_reg != -1;
3171 				gi->this_reg = this_reg;
3172 				gi->this_offset = this_offset;
3173 			} else {
3174 				gi->has_this = decode_value (p, &p);
3175 				gi->this_reg = decode_value (p, &p);
3176 				gi->this_offset = decode_value (p, &p);
3177 			}
3178 		}
3179 
3180 		len = decode_value (p, &p);
3181 		if (async) {
3182 			p += len;
3183 		} else {
3184 			jinfo->d.method = decode_resolve_method_ref (amodule, p, &p, &error);
3185 			mono_error_cleanup (&error); /* FIXME don't swallow the error */
3186 		}
3187 
3188 		gi->generic_sharing_context = alloc0_jit_info_data (domain, sizeof (MonoGenericSharingContext), async);
3189 		if (decode_value (p, &p)) {
3190 			/* gsharedvt */
3191 			MonoGenericSharingContext *gsctx = gi->generic_sharing_context;
3192 
3193 			gsctx->is_gsharedvt = TRUE;
3194 		}
3195 	}
3196 
3197 	if (method && has_seq_points) {
3198 		MonoSeqPointInfo *seq_points;
3199 
3200 		p += mono_seq_point_info_read (&seq_points, p, FALSE);
3201 
3202 		mono_domain_lock (domain);
3203 		/* This could be set already since this function can be called more than once for the same method */
3204 		if (!g_hash_table_lookup (domain_jit_info (domain)->seq_points, method))
3205 			g_hash_table_insert (domain_jit_info (domain)->seq_points, method, seq_points);
3206 		else
3207 			mono_seq_point_info_free (seq_points);
3208 		mono_domain_unlock (domain);
3209 	}
3210 
3211 	/* Load debug info */
3212 	buf_len = decode_value (p, &p);
3213 	if (!async)
3214 		mono_debug_add_aot_method (domain, method, code, p, buf_len);
3215 	p += buf_len;
3216 
3217 	if (has_gc_map) {
3218 		int map_size = decode_value (p, &p);
3219 		/* The GC map requires 4 bytes of alignment */
3220 		while ((guint64)(gsize)p % 4)
3221 			p ++;
3222 		jinfo->gc_info = p;
3223 		p += map_size;
3224 	}
3225 
3226 	if (amodule != jinfo->d.method->klass->image->aot_module) {
3227 		mono_aot_lock ();
3228 		if (!ji_to_amodule)
3229 			ji_to_amodule = g_hash_table_new (NULL, NULL);
3230 		g_hash_table_insert (ji_to_amodule, jinfo, amodule);
3231 		mono_aot_unlock ();
3232 	}
3233 
3234 	return jinfo;
3235 }
3236 
3237 static gboolean
amodule_contains_code_addr(MonoAotModule * amodule,guint8 * code)3238 amodule_contains_code_addr (MonoAotModule *amodule, guint8 *code)
3239 {
3240 	return (code >= amodule->jit_code_start && code <= amodule->jit_code_end) ||
3241 		(code >= amodule->llvm_code_start && code <= amodule->llvm_code_end);
3242 }
3243 
3244 /*
3245  * mono_aot_get_unwind_info:
3246  *
3247  *   Return a pointer to the DWARF unwind info belonging to JI.
3248  */
3249 guint8*
mono_aot_get_unwind_info(MonoJitInfo * ji,guint32 * unwind_info_len)3250 mono_aot_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len)
3251 {
3252 	MonoAotModule *amodule;
3253 	guint8 *p;
3254 	guint8 *code = (guint8 *)ji->code_start;
3255 
3256 	if (ji->async)
3257 		amodule = (MonoAotModule *)ji->d.aot_info;
3258 	else
3259 		amodule = (MonoAotModule *)jinfo_get_method (ji)->klass->image->aot_module;
3260 	g_assert (amodule);
3261 	g_assert (ji->from_aot);
3262 
3263 	if (!amodule_contains_code_addr (amodule, code)) {
3264 		/* ji belongs to a different aot module than amodule */
3265 		mono_aot_lock ();
3266 		g_assert (ji_to_amodule);
3267 		amodule = (MonoAotModule *)g_hash_table_lookup (ji_to_amodule, ji);
3268 		g_assert (amodule);
3269 		g_assert (amodule_contains_code_addr (amodule, code));
3270 		mono_aot_unlock ();
3271 	}
3272 
3273 	p = amodule->unwind_info + ji->unwind_info;
3274 	*unwind_info_len = decode_value (p, &p);
3275 	return p;
3276 }
3277 
3278 static void
msort_method_addresses_internal(gpointer * array,int * indexes,int lo,int hi,gpointer * scratch,int * scratch_indexes)3279 msort_method_addresses_internal (gpointer *array, int *indexes, int lo, int hi, gpointer *scratch, int *scratch_indexes)
3280 {
3281 	int mid = (lo + hi) / 2;
3282 	int i, t_lo, t_hi;
3283 
3284 	if (lo >= hi)
3285 		return;
3286 
3287 	if (hi - lo < 32) {
3288 		for (i = lo; i < hi; ++i)
3289 			if (array [i] > array [i + 1])
3290 				break;
3291 		if (i == hi)
3292 			/* Already sorted */
3293 			return;
3294 	}
3295 
3296 	msort_method_addresses_internal (array, indexes, lo, mid, scratch, scratch_indexes);
3297 	msort_method_addresses_internal (array, indexes, mid + 1, hi, scratch, scratch_indexes);
3298 
3299 	if (array [mid] < array [mid + 1])
3300 		return;
3301 
3302 	/* Merge */
3303 	t_lo = lo;
3304 	t_hi = mid + 1;
3305 	for (i = lo; i <= hi; i ++) {
3306 		if (t_lo <= mid && ((t_hi > hi) || array [t_lo] < array [t_hi])) {
3307 			scratch [i] = array [t_lo];
3308 			scratch_indexes [i] = indexes [t_lo];
3309 			t_lo ++;
3310 		} else {
3311 			scratch [i] = array [t_hi];
3312 			scratch_indexes [i] = indexes [t_hi];
3313 			t_hi ++;
3314 		}
3315 	}
3316 	for (i = lo; i <= hi; ++i) {
3317 		array [i] = scratch [i];
3318 		indexes [i] = scratch_indexes [i];
3319 	}
3320 }
3321 
3322 static void
msort_method_addresses(gpointer * array,int * indexes,int len)3323 msort_method_addresses (gpointer *array, int *indexes, int len)
3324 {
3325 	gpointer *scratch;
3326 	int *scratch_indexes;
3327 
3328 	scratch = g_new (gpointer, len);
3329 	scratch_indexes = g_new (int, len);
3330 	msort_method_addresses_internal (array, indexes, 0, len - 1, scratch, scratch_indexes);
3331 	g_free (scratch);
3332 	g_free (scratch_indexes);
3333 }
3334 
3335 /*
3336  * mono_aot_find_jit_info:
3337  *
3338  *   In async context, the resulting MonoJitInfo will not have its method field set, and it will not be added
3339  * to the jit info tables.
3340  * FIXME: Large sizes in the lock free allocator
3341  */
3342 MonoJitInfo *
mono_aot_find_jit_info(MonoDomain * domain,MonoImage * image,gpointer addr)3343 mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
3344 {
3345 	MonoError error;
3346 	int pos, left, right, code_len;
3347 	int method_index, table_len;
3348 	guint32 token;
3349 	MonoAotModule *amodule = (MonoAotModule *)image->aot_module;
3350 	MonoMethod *method = NULL;
3351 	MonoJitInfo *jinfo;
3352 	guint8 *code, *ex_info, *p;
3353 	guint32 *table;
3354 	int nmethods;
3355 	gpointer *methods;
3356 	guint8 *code1, *code2;
3357 	int methods_len, i;
3358 	gboolean async;
3359 
3360 	if (!amodule)
3361 		return NULL;
3362 
3363 	nmethods = amodule->info.nmethods;
3364 
3365 	if (domain != mono_get_root_domain ())
3366 		/* FIXME: */
3367 		return NULL;
3368 
3369 	if (!amodule_contains_code_addr (amodule, (guint8 *)addr))
3370 		return NULL;
3371 
3372 	async = mono_thread_info_is_async_context ();
3373 
3374 	/* Compute a sorted table mapping code to method indexes. */
3375 	if (!amodule->sorted_methods) {
3376 		// FIXME: async
3377 		gpointer *methods = g_new0 (gpointer, nmethods);
3378 		int *method_indexes = g_new0 (int, nmethods);
3379 		int methods_len = 0;
3380 
3381 		for (i = 0; i < nmethods; ++i) {
3382 			/* Skip the -1 entries to speed up sorting */
3383 			if (amodule->methods [i] == GINT_TO_POINTER (-1))
3384 				continue;
3385 			methods [methods_len] = amodule->methods [i];
3386 			method_indexes [methods_len] = i;
3387 			methods_len ++;
3388 		}
3389 		/* Use a merge sort as this is mostly sorted */
3390 		msort_method_addresses (methods, method_indexes, methods_len);
3391 		for (i = 0; i < methods_len -1; ++i)
3392 			g_assert (methods [i] <= methods [i + 1]);
3393 		amodule->sorted_methods_len = methods_len;
3394 		if (mono_atomic_cas_ptr ((gpointer*)&amodule->sorted_methods, methods, NULL) != NULL)
3395 			/* Somebody got in before us */
3396 			g_free (methods);
3397 		if (mono_atomic_cas_ptr ((gpointer*)&amodule->sorted_method_indexes, method_indexes, NULL) != NULL)
3398 			/* Somebody got in before us */
3399 			g_free (method_indexes);
3400 	}
3401 
3402 	/* Binary search in the sorted_methods table */
3403 	methods = amodule->sorted_methods;
3404 	methods_len = amodule->sorted_methods_len;
3405 	code = (guint8 *)addr;
3406 	left = 0;
3407 	right = methods_len;
3408 	while (TRUE) {
3409 		pos = (left + right) / 2;
3410 
3411 		code1 = (guint8 *)methods [pos];
3412 		if (pos + 1 == methods_len) {
3413 			if (code1 >= amodule->jit_code_start && code1 < amodule->jit_code_end)
3414 				code2 = amodule->jit_code_end;
3415 			else
3416 				code2 = amodule->llvm_code_end;
3417 		} else {
3418 			code2 = (guint8 *)methods [pos + 1];
3419 		}
3420 
3421 		if (code < code1)
3422 			right = pos;
3423 		else if (code >= code2)
3424 			left = pos + 1;
3425 		else
3426 			break;
3427 	}
3428 
3429 	g_assert (addr >= methods [pos]);
3430 	if (pos + 1 < methods_len)
3431 		g_assert (addr < methods [pos + 1]);
3432 	method_index = amodule->sorted_method_indexes [pos];
3433 
3434 	/* In async mode, jinfo is not added to the normal jit info table, so have to cache it ourselves */
3435 	if (async) {
3436 		JitInfoMap *table = amodule->async_jit_info_table;
3437 		int len;
3438 
3439 		if (table) {
3440 			len = table [0].method_index;
3441 			for (i = 1; i < len; ++i) {
3442 				if (table [i].method_index == method_index)
3443 					return table [i].jinfo;
3444 			}
3445 		}
3446 	}
3447 
3448 	code = (guint8 *)amodule->methods [method_index];
3449 	ex_info = &amodule->blob [mono_aot_get_offset (amodule->ex_info_offsets, method_index)];
3450 
3451 	if (pos == methods_len - 1) {
3452 		if (code >= amodule->jit_code_start && code < amodule->jit_code_end)
3453 			code_len = amodule->jit_code_end - code;
3454 		else
3455 			code_len = amodule->llvm_code_end - code;
3456 	} else {
3457 		code_len = (guint8*)methods [pos + 1] - (guint8*)methods [pos];
3458 	}
3459 
3460 	g_assert ((guint8*)code <= (guint8*)addr && (guint8*)addr < (guint8*)code + code_len);
3461 
3462 	/* Might be a wrapper/extra method */
3463 	if (!async) {
3464 		if (amodule->extra_methods) {
3465 			amodule_lock (amodule);
3466 			method = (MonoMethod *)g_hash_table_lookup (amodule->extra_methods, GUINT_TO_POINTER (method_index));
3467 			amodule_unlock (amodule);
3468 		} else {
3469 			method = NULL;
3470 		}
3471 
3472 		if (!method) {
3473 			if (method_index >= image->tables [MONO_TABLE_METHOD].rows) {
3474 				/*
3475 				 * This is hit for extra methods which are called directly, so they are
3476 				 * not in amodule->extra_methods.
3477 				 */
3478 				table_len = amodule->extra_method_info_offsets [0];
3479 				table = amodule->extra_method_info_offsets + 1;
3480 				left = 0;
3481 				right = table_len;
3482 				pos = 0;
3483 
3484 				/* Binary search */
3485 				while (TRUE) {
3486 					pos = ((left + right) / 2);
3487 
3488 					g_assert (pos < table_len);
3489 
3490 					if (table [pos * 2] < method_index)
3491 						left = pos + 1;
3492 					else if (table [pos * 2] > method_index)
3493 						right = pos;
3494 					else
3495 						break;
3496 				}
3497 
3498 				p = amodule->blob + table [(pos * 2) + 1];
3499 				method = decode_resolve_method_ref (amodule, p, &p, &error);
3500 				mono_error_cleanup (&error); /* FIXME don't swallow the error */
3501 				if (!method)
3502 					/* Happens when a random address is passed in which matches a not-yey called wrapper encoded using its name */
3503 					return NULL;
3504 			} else {
3505 				MonoError error;
3506 				token = mono_metadata_make_token (MONO_TABLE_METHOD, method_index + 1);
3507 				method = mono_get_method_checked (image, token, NULL, NULL, &error);
3508 				if (!method)
3509 					g_error ("AOT runtime could not load method due to %s", mono_error_get_message (&error)); /* FIXME don't swallow the error */
3510 			}
3511 		}
3512 		/* FIXME: */
3513 		g_assert (method);
3514 	}
3515 
3516 	//printf ("F: %s\n", mono_method_full_name (method, TRUE));
3517 
3518 	jinfo = decode_exception_debug_info (amodule, domain, method, ex_info, code, code_len);
3519 
3520 	g_assert ((guint8*)addr >= (guint8*)jinfo->code_start);
3521 
3522 	/* Add it to the normal JitInfo tables */
3523 	if (async) {
3524 		JitInfoMap *old_table, *new_table;
3525 		int len;
3526 
3527 		/*
3528 		 * Use a simple inmutable table with linear search to cache async jit info entries.
3529 		 * This assumes that the number of entries is small.
3530 		 */
3531 		while (TRUE) {
3532 			/* Copy the table, adding a new entry at the end */
3533 			old_table = amodule->async_jit_info_table;
3534 			if (old_table)
3535 				len = old_table[0].method_index;
3536 			else
3537 				len = 1;
3538 			new_table = (JitInfoMap *)alloc0_jit_info_data (domain, (len + 1) * sizeof (JitInfoMap), async);
3539 			if (old_table)
3540 				memcpy (new_table, old_table, len * sizeof (JitInfoMap));
3541 			new_table [0].method_index = len + 1;
3542 			new_table [len].method_index = method_index;
3543 			new_table [len].jinfo = jinfo;
3544 			/* Publish it */
3545 			mono_memory_barrier ();
3546 			if (mono_atomic_cas_ptr ((volatile gpointer *)&amodule->async_jit_info_table, new_table, old_table) == old_table)
3547 				break;
3548 		}
3549 	} else {
3550 		mono_jit_info_table_add (domain, jinfo);
3551 	}
3552 
3553 	if ((guint8*)addr >= (guint8*)jinfo->code_start + jinfo->code_size)
3554 		/* addr is in the padding between methods, see the adjustment of code_size in decode_exception_debug_info () */
3555 		return NULL;
3556 
3557 	return jinfo;
3558 }
3559 
3560 static gboolean
decode_patch(MonoAotModule * aot_module,MonoMemPool * mp,MonoJumpInfo * ji,guint8 * buf,guint8 ** endbuf)3561 decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guint8 *buf, guint8 **endbuf)
3562 {
3563 	MonoError error;
3564 	guint8 *p = buf;
3565 	gpointer *table;
3566 	MonoImage *image;
3567 	int i;
3568 
3569 	switch (ji->type) {
3570 	case MONO_PATCH_INFO_METHOD:
3571 	case MONO_PATCH_INFO_METHOD_JUMP:
3572 	case MONO_PATCH_INFO_ICALL_ADDR:
3573 	case MONO_PATCH_INFO_ICALL_ADDR_CALL:
3574 	case MONO_PATCH_INFO_METHOD_RGCTX:
3575 	case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
3576 		MethodRef ref;
3577 		gboolean res;
3578 
3579 		res = decode_method_ref (aot_module, &ref, p, &p, &error);
3580 		mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3581 		if (!res)
3582 			goto cleanup;
3583 
3584 		if (!ref.method && !mono_aot_only && !ref.no_aot_trampoline && (ji->type == MONO_PATCH_INFO_METHOD) && (mono_metadata_token_table (ref.token) == MONO_TABLE_METHOD)) {
3585 			ji->data.target = mono_create_ftnptr (mono_domain_get (), mono_create_jit_trampoline_from_token (ref.image, ref.token));
3586 			ji->type = MONO_PATCH_INFO_ABS;
3587 		}
3588 		else {
3589 			if (ref.method) {
3590 				ji->data.method = ref.method;
3591 			}else {
3592 				MonoError error;
3593 				ji->data.method = mono_get_method_checked (ref.image, ref.token, NULL, NULL, &error);
3594 				if (!ji->data.method)
3595 					g_error ("AOT Runtime could not load method due to %s", mono_error_get_message (&error)); /* FIXME don't swallow the error */
3596 			}
3597 			g_assert (ji->data.method);
3598 			mono_class_init (ji->data.method->klass);
3599 		}
3600 		break;
3601 	}
3602 	case MONO_PATCH_INFO_INTERNAL_METHOD:
3603 	case MONO_PATCH_INFO_JIT_ICALL_ADDR:
3604 	case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
3605 		guint32 len = decode_value (p, &p);
3606 
3607 		ji->data.name = (char*)p;
3608 		p += len + 1;
3609 		break;
3610 	}
3611 	case MONO_PATCH_INFO_METHODCONST:
3612 		/* Shared */
3613 		ji->data.method = decode_resolve_method_ref (aot_module, p, &p, &error);
3614 		mono_error_cleanup (&error); /* FIXME don't swallow the error */
3615 		if (!ji->data.method)
3616 			goto cleanup;
3617 		break;
3618 	case MONO_PATCH_INFO_VTABLE:
3619 	case MONO_PATCH_INFO_CLASS:
3620 	case MONO_PATCH_INFO_IID:
3621 	case MONO_PATCH_INFO_ADJUSTED_IID:
3622 		/* Shared */
3623 		ji->data.klass = decode_klass_ref (aot_module, p, &p, &error);
3624 		mono_error_cleanup (&error); /* FIXME don't swallow the error */
3625 		if (!ji->data.klass)
3626 			goto cleanup;
3627 		break;
3628 	case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
3629 		ji->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
3630 		ji->data.del_tramp->klass = decode_klass_ref (aot_module, p, &p, &error);
3631 		mono_error_cleanup (&error); /* FIXME don't swallow the error */
3632 		if (!ji->data.del_tramp->klass)
3633 			goto cleanup;
3634 		if (decode_value (p, &p)) {
3635 			ji->data.del_tramp->method = decode_resolve_method_ref (aot_module, p, &p, &error);
3636 			mono_error_cleanup (&error); /* FIXME don't swallow the error */
3637 			if (!ji->data.del_tramp->method)
3638 				goto cleanup;
3639 		}
3640 		ji->data.del_tramp->is_virtual = decode_value (p, &p) ? TRUE : FALSE;
3641 		break;
3642 	case MONO_PATCH_INFO_IMAGE:
3643 		ji->data.image = load_image (aot_module, decode_value (p, &p), &error);
3644 		mono_error_cleanup (&error); /* FIXME don't swallow the error */
3645 		if (!ji->data.image)
3646 			goto cleanup;
3647 		break;
3648 	case MONO_PATCH_INFO_FIELD:
3649 	case MONO_PATCH_INFO_SFLDA:
3650 		/* Shared */
3651 		ji->data.field = decode_field_info (aot_module, p, &p);
3652 		if (!ji->data.field)
3653 			goto cleanup;
3654 		break;
3655 	case MONO_PATCH_INFO_SWITCH:
3656 		ji->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable));
3657 		ji->data.table->table_size = decode_value (p, &p);
3658 		table = (void **)mono_domain_alloc (mono_domain_get (), sizeof (gpointer) * ji->data.table->table_size);
3659 		ji->data.table->table = (MonoBasicBlock**)table;
3660 		for (i = 0; i < ji->data.table->table_size; i++)
3661 			table [i] = (gpointer)(gssize)decode_value (p, &p);
3662 		break;
3663 	case MONO_PATCH_INFO_R4: {
3664 		guint32 val;
3665 
3666 		ji->data.target = mono_domain_alloc0 (mono_domain_get (), sizeof (float));
3667 		val = decode_value (p, &p);
3668 		*(float*)ji->data.target = *(float*)&val;
3669 		break;
3670 	}
3671 	case MONO_PATCH_INFO_R8: {
3672 		guint32 val [2];
3673 		guint64 v;
3674 
3675 		ji->data.target = mono_domain_alloc0 (mono_domain_get (), sizeof (double));
3676 
3677 		val [0] = decode_value (p, &p);
3678 		val [1] = decode_value (p, &p);
3679 		v = ((guint64)val [1] << 32) | ((guint64)val [0]);
3680 		*(double*)ji->data.target = *(double*)&v;
3681 		break;
3682 	}
3683 	case MONO_PATCH_INFO_LDSTR:
3684 		image = load_image (aot_module, decode_value (p, &p), &error);
3685 		mono_error_cleanup (&error); /* FIXME don't swallow the error */
3686 		if (!image)
3687 			goto cleanup;
3688 		ji->data.token = mono_jump_info_token_new (mp, image, MONO_TOKEN_STRING + decode_value (p, &p));
3689 		break;
3690 	case MONO_PATCH_INFO_RVA:
3691 	case MONO_PATCH_INFO_DECLSEC:
3692 	case MONO_PATCH_INFO_LDTOKEN:
3693 	case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3694 		/* Shared */
3695 		image = load_image (aot_module, decode_value (p, &p), &error);
3696 		mono_error_cleanup (&error); /* FIXME don't swallow the error */
3697 		if (!image)
3698 			goto cleanup;
3699 		ji->data.token = mono_jump_info_token_new (mp, image, decode_value (p, &p));
3700 
3701 		ji->data.token->has_context = decode_value (p, &p);
3702 		if (ji->data.token->has_context) {
3703 			gboolean res = decode_generic_context (aot_module, &ji->data.token->context, p, &p, &error);
3704 			mono_error_cleanup (&error); /* FIXME don't swallow the error */
3705 			if (!res)
3706 				goto cleanup;
3707 		}
3708 		break;
3709 	case MONO_PATCH_INFO_EXC_NAME:
3710 		ji->data.klass = decode_klass_ref (aot_module, p, &p, &error);
3711 		mono_error_cleanup (&error); /* FIXME don't swallow the error */
3712 		if (!ji->data.klass)
3713 			goto cleanup;
3714 		ji->data.name = ji->data.klass->name;
3715 		break;
3716 	case MONO_PATCH_INFO_METHOD_REL:
3717 		ji->data.offset = decode_value (p, &p);
3718 		break;
3719 	case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
3720 	case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
3721 	case MONO_PATCH_INFO_GC_NURSERY_START:
3722 	case MONO_PATCH_INFO_GC_NURSERY_BITS:
3723 	case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
3724 		break;
3725 	case MONO_PATCH_INFO_CASTCLASS_CACHE:
3726 		ji->data.index = decode_value (p, &p);
3727 		break;
3728 	case MONO_PATCH_INFO_RGCTX_FETCH:
3729 	case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
3730 		gboolean res;
3731 		MonoJumpInfoRgctxEntry *entry;
3732 		guint32 offset, val;
3733 		guint8 *p2;
3734 
3735 		offset = decode_value (p, &p);
3736 		val = decode_value (p, &p);
3737 
3738 		entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3739 		p2 = aot_module->blob + offset;
3740 		entry->method = decode_resolve_method_ref (aot_module, p2, &p2, &error);
3741 		entry->in_mrgctx = ((val & 1) > 0) ? TRUE : FALSE;
3742 		entry->info_type = (MonoRgctxInfoType)((val >> 1) & 0xff);
3743 		entry->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3744 		entry->data->type = (MonoJumpInfoType)((val >> 9) & 0xff);
3745 		mono_error_cleanup (&error); /* FIXME don't swallow the error */
3746 
3747 		res = decode_patch (aot_module, mp, entry->data, p, &p);
3748 		if (!res)
3749 			goto cleanup;
3750 		ji->data.rgctx_entry = entry;
3751 		break;
3752 	}
3753 	case MONO_PATCH_INFO_SEQ_POINT_INFO:
3754 	case MONO_PATCH_INFO_AOT_MODULE:
3755 	case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
3756 		break;
3757 	case MONO_PATCH_INFO_SIGNATURE:
3758 	case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
3759 		ji->data.target = decode_signature (aot_module, p, &p);
3760 		break;
3761 	case MONO_PATCH_INFO_GSHAREDVT_CALL: {
3762 		MonoJumpInfoGSharedVtCall *info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoGSharedVtCall));
3763 		info->sig = decode_signature (aot_module, p, &p);
3764 		g_assert (info->sig);
3765 		info->method = decode_resolve_method_ref (aot_module, p, &p, &error);
3766 		mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3767 
3768 		ji->data.target = info;
3769 		break;
3770 	}
3771 	case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
3772 		MonoGSharedVtMethodInfo *info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (mp, sizeof (MonoGSharedVtMethodInfo));
3773 		int i;
3774 
3775 		info->method = decode_resolve_method_ref (aot_module, p, &p, &error);
3776 		mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3777 
3778 		info->num_entries = decode_value (p, &p);
3779 		info->count_entries = info->num_entries;
3780 		info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
3781 		for (i = 0; i < info->num_entries; ++i) {
3782 			MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
3783 
3784 			template_->info_type = (MonoRgctxInfoType)decode_value (p, &p);
3785 			switch (mini_rgctx_info_type_to_patch_info_type (template_->info_type)) {
3786 			case MONO_PATCH_INFO_CLASS: {
3787 				MonoClass *klass = decode_klass_ref (aot_module, p, &p, &error);
3788 				mono_error_cleanup (&error); /* FIXME don't swallow the error */
3789 				if (!klass)
3790 					goto cleanup;
3791 				template_->data = &klass->byval_arg;
3792 				break;
3793 			}
3794 			case MONO_PATCH_INFO_FIELD:
3795 				template_->data = decode_field_info (aot_module, p, &p);
3796 				if (!template_->data)
3797 					goto cleanup;
3798 				break;
3799 			default:
3800 				g_assert_not_reached ();
3801 				break;
3802 			}
3803 		}
3804 		ji->data.target = info;
3805 		break;
3806 	}
3807 	case MONO_PATCH_INFO_LDSTR_LIT: {
3808 		int len = decode_value (p, &p);
3809 		char *s;
3810 
3811 		s = (char *)mono_mempool_alloc0 (mp, len + 1);
3812 		memcpy (s, p, len + 1);
3813 		p += len + 1;
3814 
3815 		ji->data.target = s;
3816 		break;
3817 	}
3818 	case MONO_PATCH_INFO_VIRT_METHOD: {
3819 		MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
3820 
3821 		info->klass = decode_klass_ref (aot_module, p, &p, &error);
3822 		mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3823 
3824 		info->method = decode_resolve_method_ref (aot_module, p, &p, &error);
3825 		mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3826 
3827 		ji->data.target = info;
3828 		break;
3829 	}
3830 	case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
3831 	case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
3832 		break;
3833 	case MONO_PATCH_INFO_GET_TLS_TRAMP:
3834 	case MONO_PATCH_INFO_SET_TLS_TRAMP:
3835 	case MONO_PATCH_INFO_AOT_JIT_INFO:
3836 		ji->data.index = decode_value (p, &p);
3837 		break;
3838 	default:
3839 		g_warning ("unhandled type %d", ji->type);
3840 		g_assert_not_reached ();
3841 	}
3842 
3843 	*endbuf = p;
3844 
3845 	return TRUE;
3846 
3847  cleanup:
3848 	return FALSE;
3849 }
3850 
3851 /*
3852  * decode_patches:
3853  *
3854  *    Decode a list of patches identified by the got offsets in GOT_OFFSETS. Return an array of
3855  * MonoJumpInfo structures allocated from MP.
3856  */
3857 static MonoJumpInfo*
decode_patches(MonoAotModule * amodule,MonoMemPool * mp,int n_patches,gboolean llvm,guint32 * got_offsets)3858 decode_patches (MonoAotModule *amodule, MonoMemPool *mp, int n_patches, gboolean llvm, guint32 *got_offsets)
3859 {
3860 	MonoJumpInfo *patches;
3861 	MonoJumpInfo *ji;
3862 	gpointer *got;
3863 	guint32 *got_info_offsets;
3864 	int i;
3865 	gboolean res;
3866 
3867 	if (llvm) {
3868 		got = amodule->llvm_got;
3869 		got_info_offsets = (guint32 *)amodule->llvm_got_info_offsets;
3870 	} else {
3871 		got = amodule->got;
3872 		got_info_offsets = (guint32 *)amodule->got_info_offsets;
3873 	}
3874 
3875 	patches = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo) * n_patches);
3876 	for (i = 0; i < n_patches; ++i) {
3877 		guint8 *p = amodule->blob + mono_aot_get_offset (got_info_offsets, got_offsets [i]);
3878 
3879 		ji = &patches [i];
3880 		ji->type = (MonoJumpInfoType)decode_value (p, &p);
3881 
3882 		/* See load_method () for SFLDA */
3883 		if (got && got [got_offsets [i]] && ji->type != MONO_PATCH_INFO_SFLDA) {
3884 			/* Already loaded */
3885 		} else {
3886 			res = decode_patch (amodule, mp, ji, p, &p);
3887 			if (!res)
3888 				return NULL;
3889 		}
3890 	}
3891 
3892 	return patches;
3893 }
3894 
3895 static MonoJumpInfo*
load_patch_info(MonoAotModule * amodule,MonoMemPool * mp,int n_patches,gboolean llvm,guint32 ** got_slots,guint8 * buf,guint8 ** endbuf)3896 load_patch_info (MonoAotModule *amodule, MonoMemPool *mp, int n_patches,
3897 				 gboolean llvm, guint32 **got_slots,
3898 				 guint8 *buf, guint8 **endbuf)
3899 {
3900 	MonoJumpInfo *patches;
3901 	int pindex;
3902 	guint8 *p;
3903 
3904 	p = buf;
3905 
3906 	*got_slots = (guint32 *)g_malloc (sizeof (guint32) * n_patches);
3907 	for (pindex = 0; pindex < n_patches; ++pindex) {
3908 		(*got_slots)[pindex] = decode_value (p, &p);
3909 	}
3910 
3911 	patches = decode_patches (amodule, mp, n_patches, llvm, *got_slots);
3912 	if (!patches) {
3913 		g_free (*got_slots);
3914 		*got_slots = NULL;
3915 		return NULL;
3916 	}
3917 
3918 	*endbuf = p;
3919 	return patches;
3920 }
3921 
3922 static void
register_jump_target_got_slot(MonoDomain * domain,MonoMethod * method,gpointer * got_slot)3923 register_jump_target_got_slot (MonoDomain *domain, MonoMethod *method, gpointer *got_slot)
3924 {
3925 	/*
3926 	 * Jump addresses cannot be patched by the trampoline code since it
3927 	 * does not have access to the caller's address. Instead, we collect
3928 	 * the addresses of the GOT slots pointing to a method, and patch
3929 	 * them after the method has been compiled.
3930 	 */
3931 	MonoJitDomainInfo *info = domain_jit_info (domain);
3932 	GSList *list;
3933 
3934 	mono_domain_lock (domain);
3935 	if (!info->jump_target_got_slot_hash)
3936 		info->jump_target_got_slot_hash = g_hash_table_new (NULL, NULL);
3937 	list = (GSList *)g_hash_table_lookup (info->jump_target_got_slot_hash, method);
3938 	list = g_slist_prepend (list, got_slot);
3939 	g_hash_table_insert (info->jump_target_got_slot_hash, method, list);
3940 	mono_domain_unlock (domain);
3941 }
3942 
3943 /*
3944  * load_method:
3945  *
3946  *   Load the method identified by METHOD_INDEX from the AOT image. Return a
3947  * pointer to the native code of the method, or NULL if not found.
3948  * METHOD might not be set if the caller only has the image/token info.
3949  */
3950 static gpointer
load_method(MonoDomain * domain,MonoAotModule * amodule,MonoImage * image,MonoMethod * method,guint32 token,int method_index,MonoError * error)3951 load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoMethod *method, guint32 token, int method_index,
3952 			 MonoError *error)
3953 {
3954 	MonoJitInfo *jinfo = NULL;
3955 	guint8 *code = NULL, *info;
3956 	gboolean res;
3957 
3958 	error_init (error);
3959 
3960 	init_amodule_got (amodule);
3961 
3962 	if (domain != mono_get_root_domain ())
3963 		/* Non shared AOT code can't be used in other appdomains */
3964 		return NULL;
3965 
3966 	if (amodule->out_of_date)
3967 		return NULL;
3968 
3969 	if (amodule->info.llvm_get_method) {
3970 		/*
3971 		 * Obtain the method address by calling a generated function in the LLVM module.
3972 		 */
3973 		gpointer (*get_method) (int) = (gpointer (*)(int))amodule->info.llvm_get_method;
3974 		code = (guint8 *)get_method (method_index);
3975 	}
3976 
3977 	if (!code) {
3978 		/* JITted method */
3979 		if (amodule->methods [method_index] == GINT_TO_POINTER (-1)) {
3980 			if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
3981 				char *full_name;
3982 
3983 				if (!method) {
3984 					method = mono_get_method_checked (image, token, NULL, NULL, error);
3985 					if (!method)
3986 						return NULL;
3987 				}
3988 				if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
3989 					full_name = mono_method_full_name (method, TRUE);
3990 					mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT: NOT FOUND: %s.", full_name);
3991 					g_free (full_name);
3992 				}
3993 			}
3994 			return NULL;
3995 		}
3996 		code = (guint8 *)amodule->methods [method_index];
3997 	}
3998 
3999 	info = &amodule->blob [mono_aot_get_offset (amodule->method_info_offsets, method_index)];
4000 
4001 	if (!amodule->methods_loaded) {
4002 		amodule_lock (amodule);
4003 		if (!amodule->methods_loaded) {
4004 			guint32 *loaded;
4005 
4006 			loaded = g_new0 (guint32, amodule->info.nmethods / 32 + 1);
4007 			mono_memory_barrier ();
4008 			amodule->methods_loaded = loaded;
4009 		}
4010 		amodule_unlock (amodule);
4011 	}
4012 
4013 	if ((amodule->methods_loaded [method_index / 32] >> (method_index % 32)) & 0x1)
4014 		return code;
4015 
4016 	if (mono_last_aot_method != -1) {
4017 		gint32 methods_aot = mono_atomic_load_i32 (&mono_jit_stats.methods_aot);
4018 		if (methods_aot >= mono_last_aot_method)
4019 			return NULL;
4020 		else if (methods_aot == mono_last_aot_method - 1) {
4021 			if (!method) {
4022 				method = mono_get_method_checked (image, token, NULL, NULL, error);
4023 				if (!method)
4024 					return NULL;
4025 			}
4026 			if (method) {
4027 				char *name = mono_method_full_name (method, TRUE);
4028 				g_print ("LAST AOT METHOD: %s.\n", name);
4029 				g_free (name);
4030 			} else {
4031 				g_print ("LAST AOT METHOD: %p %d\n", code, method_index);
4032 			}
4033 		}
4034 	}
4035 
4036 	if (!(is_llvm_code (amodule, code) && (amodule->info.flags & MONO_AOT_FILE_FLAG_LLVM_ONLY)) ||
4037 		(mono_llvm_only && method && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)) {
4038 		res = init_method (amodule, method_index, method, NULL, NULL, error);
4039 		if (!res)
4040 			goto cleanup;
4041 	}
4042 
4043 	if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
4044 		char *full_name;
4045 
4046 		if (!method) {
4047 			method = mono_get_method_checked (image, token, NULL, NULL, error);
4048 			if (!method)
4049 				return NULL;
4050 		}
4051 
4052 		full_name = mono_method_full_name (method, TRUE);
4053 
4054 		if (!jinfo)
4055 			jinfo = mono_aot_find_jit_info (domain, amodule->assembly->image, code);
4056 
4057 		mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT: FOUND method %s [%p - %p %p]", full_name, code, code + jinfo->code_size, info);
4058 		g_free (full_name);
4059 	}
4060 
4061 	amodule_lock (amodule);
4062 
4063 	init_plt (amodule);
4064 
4065 	mono_atomic_inc_i32 (&mono_jit_stats.methods_aot);
4066 
4067 	if (method && method->wrapper_type)
4068 		g_hash_table_insert (amodule->method_to_code, method, code);
4069 
4070 	/* Commit changes since methods_loaded is accessed outside the lock */
4071 	mono_memory_barrier ();
4072 
4073 	amodule->methods_loaded [method_index / 32] |= 1 << (method_index % 32);
4074 
4075 	amodule_unlock (amodule);
4076 
4077 	if (MONO_PROFILER_ENABLED (jit_begin) || MONO_PROFILER_ENABLED (jit_done)) {
4078 		MonoJitInfo *jinfo;
4079 
4080 		if (!method) {
4081 			method = mono_get_method_checked (amodule->assembly->image, token, NULL, NULL, error);
4082 			if (!method)
4083 				return NULL;
4084 		}
4085 		MONO_PROFILER_RAISE (jit_begin, (method));
4086 		jinfo = mono_jit_info_table_find (domain, (char*)code);
4087 		g_assert (jinfo);
4088 		MONO_PROFILER_RAISE (jit_done, (method, jinfo));
4089 	}
4090 
4091 	return code;
4092 
4093  cleanup:
4094 	if (jinfo)
4095 		g_free (jinfo);
4096 
4097 	return NULL;
4098 }
4099 
4100 /** find_aot_method_in_amodule
4101 	*
4102 	* \param code_amodule The AOT module containing the code pointer
4103 	* \param method The method to find the code index for
4104 	* \param hash_full The hash for the method
4105 	*/
4106 static guint32
find_aot_method_in_amodule(MonoAotModule * code_amodule,MonoMethod * method,guint32 hash_full)4107 find_aot_method_in_amodule (MonoAotModule *code_amodule, MonoMethod *method, guint32 hash_full)
4108 {
4109 	MonoError error;
4110 	guint32 table_size, entry_size, hash;
4111 	guint32 *table, *entry;
4112 	guint32 index;
4113 	static guint32 n_extra_decodes;
4114 
4115 	// The AOT module containing the MonoMethod
4116 	// The reference to the metadata amodule will differ among multiple dedup methods
4117 	// which mangle to the same name but live in different assemblies. This leads to
4118 	// the caching breaking. The solution seems to be to cache using the "metadata" amodule.
4119 	MonoAotModule *metadata_amodule = (MonoAotModule *)method->klass->image->aot_module;
4120 
4121 	if (!metadata_amodule || metadata_amodule->out_of_date || !code_amodule || code_amodule->out_of_date)
4122 		return 0xffffff;
4123 
4124 	table_size = code_amodule->extra_method_table [0];
4125 	hash = hash_full % table_size;
4126 	table = code_amodule->extra_method_table + 1;
4127 	entry_size = 3;
4128 
4129 	entry = &table [hash * entry_size];
4130 
4131 	if (entry [0] == 0)
4132 		return 0xffffff;
4133 
4134 	index = 0xffffff;
4135 	while (TRUE) {
4136 		guint32 key = entry [0];
4137 		guint32 value = entry [1];
4138 		guint32 next = entry [entry_size - 1];
4139 		MonoMethod *m;
4140 		guint8 *p, *orig_p;
4141 
4142 		p = code_amodule->blob + key;
4143 		orig_p = p;
4144 
4145 		amodule_lock (metadata_amodule);
4146 		if (!metadata_amodule->method_ref_to_method)
4147 			metadata_amodule->method_ref_to_method = g_hash_table_new (NULL, NULL);
4148 		m = (MonoMethod *)g_hash_table_lookup (metadata_amodule->method_ref_to_method, p);
4149 		amodule_unlock (metadata_amodule);
4150 		if (!m) {
4151 			m = decode_resolve_method_ref_with_target (code_amodule, method, p, &p, &error);
4152 			mono_error_cleanup (&error); /* FIXME don't swallow the error */
4153 			/*
4154 			 * Can't catche runtime invoke wrappers since it would break
4155 			 * the check in decode_method_ref_with_target ().
4156 			 */
4157 			if (m && m->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
4158 				amodule_lock (metadata_amodule);
4159 				g_hash_table_insert (metadata_amodule->method_ref_to_method, orig_p, m);
4160 				amodule_unlock (metadata_amodule);
4161 			}
4162 		}
4163 		if (m == method) {
4164 			index = value;
4165 			break;
4166 		}
4167 
4168 		/* Methods decoded needlessly */
4169 		if (m) {
4170 			//printf ("%d %s %s %p\n", n_extra_decodes, mono_method_full_name (method, TRUE), mono_method_full_name (m, TRUE), orig_p);
4171 			n_extra_decodes ++;
4172 		}
4173 
4174 		if (next != 0)
4175 			entry = &table [next * entry_size];
4176 		else
4177 			break;
4178 	}
4179 
4180 	if (index != 0xffffff)
4181 		g_assert (index < code_amodule->info.nmethods);
4182 
4183 	return index;
4184 }
4185 
4186 static void
add_module_cb(gpointer key,gpointer value,gpointer user_data)4187 add_module_cb (gpointer key, gpointer value, gpointer user_data)
4188 {
4189 	g_ptr_array_add ((GPtrArray*)user_data, value);
4190 }
4191 
4192 gboolean
mono_aot_can_dedup(MonoMethod * method)4193 mono_aot_can_dedup (MonoMethod *method)
4194 {
4195 	gboolean not_normal_gshared = method->is_inflated && !mono_method_is_generic_sharable_full (method, TRUE, FALSE, FALSE);
4196 	gboolean extra_method = (method->wrapper_type != MONO_WRAPPER_NONE) || not_normal_gshared;
4197 
4198 	return extra_method;
4199 }
4200 
4201 
4202 /*
4203  * find_aot_method:
4204  *
4205  *   Try finding METHOD in the extra_method table in all AOT images.
4206  * Return its method index, or 0xffffff if not found. Set OUT_AMODULE to the AOT
4207  * module where the method was found.
4208  */
4209 static guint32
find_aot_method(MonoMethod * method,MonoAotModule ** out_amodule)4210 find_aot_method (MonoMethod *method, MonoAotModule **out_amodule)
4211 {
4212 	guint32 index;
4213 	GPtrArray *modules;
4214 	int i;
4215 	guint32 hash = mono_aot_method_hash (method);
4216 
4217 	/* Try the place we expect to have moved the method only
4218 	 * We don't probe, as that causes hard-to-debug issues when we fail
4219 	 * to find the method */
4220 	if (container_amodule && mono_aot_can_dedup (method)) {
4221 		*out_amodule = container_amodule;
4222 		index = find_aot_method_in_amodule (container_amodule, method, hash);
4223 		return index;
4224 	}
4225 
4226 	/* Try the method's module first */
4227 	*out_amodule = (MonoAotModule *)method->klass->image->aot_module;
4228 	index = find_aot_method_in_amodule ((MonoAotModule *)method->klass->image->aot_module, method, hash);
4229 	if (index != 0xffffff)
4230 		return index;
4231 
4232 	/*
4233 	 * Try all other modules.
4234 	 * This is needed because generic instances klass->image points to the image
4235 	 * containing the generic definition, but the native code is generated to the
4236 	 * AOT image which contains the reference.
4237 	 */
4238 
4239 	/* Make a copy to avoid doing the search inside the aot lock */
4240 	modules = g_ptr_array_new ();
4241 	mono_aot_lock ();
4242 	g_hash_table_foreach (aot_modules, add_module_cb, modules);
4243 	mono_aot_unlock ();
4244 
4245 	index = 0xffffff;
4246 	for (i = 0; i < modules->len; ++i) {
4247 		MonoAotModule *amodule = (MonoAotModule *)g_ptr_array_index (modules, i);
4248 
4249 		if (amodule != method->klass->image->aot_module)
4250 			index = find_aot_method_in_amodule (amodule, method, hash);
4251 		if (index != 0xffffff) {
4252 			*out_amodule = amodule;
4253 			break;
4254 		}
4255 	}
4256 
4257 	g_ptr_array_free (modules, TRUE);
4258 
4259 	return index;
4260 }
4261 
4262 guint32
mono_aot_find_method_index(MonoMethod * method)4263 mono_aot_find_method_index (MonoMethod *method)
4264 {
4265 	MonoAotModule *out_amodule;
4266 	return find_aot_method (method, &out_amodule);
4267 }
4268 
4269 static gboolean
init_method(MonoAotModule * amodule,guint32 method_index,MonoMethod * method,MonoClass * init_class,MonoGenericContext * context,MonoError * error)4270 init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, MonoClass *init_class, MonoGenericContext *context, MonoError *error)
4271 {
4272 	MonoDomain *domain = mono_domain_get ();
4273 	MonoMemPool *mp;
4274 	MonoClass *klass_to_run_ctor = NULL;
4275 	gboolean from_plt = method == NULL;
4276 	int pindex, n_patches;
4277 	guint8 *p;
4278 	MonoJitInfo *jinfo = NULL;
4279 	guint8 *code, *info;
4280 
4281 	error_init (error);
4282 
4283 	code = (guint8 *)amodule->methods [method_index];
4284 	info = &amodule->blob [mono_aot_get_offset (amodule->method_info_offsets, method_index)];
4285 
4286 	p = info;
4287 
4288 	//does the method's class has a cctor?
4289 	if (decode_value (p, &p) == 1)
4290 		klass_to_run_ctor = decode_klass_ref (amodule, p, &p, error);
4291 	if (!is_ok (error))
4292 		return FALSE;
4293 
4294 	//FIXME old code would use the class from @method if not null and ignore the one encoded. I don't know if we need to honor that -- @kumpera
4295 	if (method)
4296 		klass_to_run_ctor = method->klass;
4297 
4298 	n_patches = decode_value (p, &p);
4299 
4300 	if (n_patches) {
4301 		MonoJumpInfo *patches;
4302 		guint32 *got_slots;
4303 		gboolean llvm;
4304 		gpointer *got;
4305 
4306 		mp = mono_mempool_new ();
4307 
4308 		if ((gpointer)code >= amodule->info.jit_code_start && (gpointer)code <= amodule->info.jit_code_end) {
4309 			llvm = FALSE;
4310 			got = amodule->got;
4311 		} else {
4312 			llvm = TRUE;
4313 			got = amodule->llvm_got;
4314 			g_assert (got);
4315 		}
4316 
4317 		patches = load_patch_info (amodule, mp, n_patches, llvm, &got_slots, p, &p);
4318 		if (patches == NULL) {
4319 			mono_mempool_destroy (mp);
4320 			goto cleanup;
4321 		}
4322 
4323 		for (pindex = 0; pindex < n_patches; ++pindex) {
4324 			MonoJumpInfo *ji = &patches [pindex];
4325 			gpointer addr;
4326 
4327 			/*
4328 			 * For SFLDA, we need to call resolve_patch_target () since the GOT slot could have
4329 			 * been initialized by load_method () for a static cctor before the cctor has
4330 			 * finished executing (#23242).
4331 			 */
4332 			if (!got [got_slots [pindex]] || ji->type == MONO_PATCH_INFO_SFLDA) {
4333 				/* In llvm-only made, we might encounter shared methods */
4334 				if (mono_llvm_only && ji->type == MONO_PATCH_INFO_METHOD && mono_method_check_context_used (ji->data.method)) {
4335 					g_assert (context);
4336 					ji->data.method = mono_class_inflate_generic_method_checked (ji->data.method, context, error);
4337 					if (!mono_error_ok (error)) {
4338 						g_free (got_slots);
4339 						mono_mempool_destroy (mp);
4340 						return FALSE;
4341 					}
4342 				}
4343 				/* This cannot be resolved in mono_resolve_patch_target () */
4344 				if (ji->type == MONO_PATCH_INFO_AOT_JIT_INFO) {
4345 					// FIXME: Lookup using the index
4346 					jinfo = mono_aot_find_jit_info (domain, amodule->assembly->image, code);
4347 					ji->type = MONO_PATCH_INFO_ABS;
4348 					ji->data.target = jinfo;
4349 				}
4350 				addr = mono_resolve_patch_target (method, domain, code, ji, TRUE, error);
4351 				if (!mono_error_ok (error)) {
4352 					g_free (got_slots);
4353 					mono_mempool_destroy (mp);
4354 					return FALSE;
4355 				}
4356 				if (ji->type == MONO_PATCH_INFO_METHOD_JUMP)
4357 					addr = mono_create_ftnptr (domain, addr);
4358 				mono_memory_barrier ();
4359 				got [got_slots [pindex]] = addr;
4360 				if (ji->type == MONO_PATCH_INFO_METHOD_JUMP)
4361 					register_jump_target_got_slot (domain, ji->data.method, &(got [got_slots [pindex]]));
4362 			}
4363 			ji->type = MONO_PATCH_INFO_NONE;
4364 		}
4365 
4366 		g_free (got_slots);
4367 
4368 		mono_mempool_destroy (mp);
4369 	}
4370 
4371 	if (mini_get_debug_options ()->load_aot_jit_info_eagerly)
4372 		jinfo = mono_aot_find_jit_info (domain, amodule->assembly->image, code);
4373 
4374 	gboolean inited_ok = TRUE;
4375 	if (init_class)
4376 		inited_ok = mono_runtime_class_init_full (mono_class_vtable (domain, init_class), error);
4377 	else if (from_plt && klass_to_run_ctor && !mono_class_is_gtd (klass_to_run_ctor))
4378 		inited_ok = mono_runtime_class_init_full (mono_class_vtable (domain, klass_to_run_ctor), error);
4379 	if (!inited_ok)
4380 		return FALSE;
4381 
4382 	return TRUE;
4383 
4384  cleanup:
4385 	if (jinfo)
4386 		g_free (jinfo);
4387 
4388 	return FALSE;
4389 }
4390 
4391 static void
init_llvmonly_method(MonoAotModule * amodule,guint32 method_index,MonoMethod * method,MonoClass * init_class,MonoGenericContext * context)4392 init_llvmonly_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, MonoClass *init_class, MonoGenericContext *context)
4393 {
4394 	gboolean res;
4395 	MonoError error;
4396 
4397 	res = init_method (amodule, method_index, method, init_class, context, &error);
4398 	if (!is_ok (&error)) {
4399 		MonoException *ex = mono_error_convert_to_exception (&error);
4400 		/* Its okay to raise in llvmonly mode */
4401 		if (ex)
4402 			mono_llvm_throw_exception ((MonoObject*)ex);
4403 	}
4404 }
4405 
4406 void
mono_aot_init_llvm_method(gpointer aot_module,guint32 method_index)4407 mono_aot_init_llvm_method (gpointer aot_module, guint32 method_index)
4408 {
4409 	MonoAotModule *amodule = (MonoAotModule *)aot_module;
4410 
4411 	init_llvmonly_method (amodule, method_index, NULL, NULL, NULL);
4412 }
4413 
4414 void
mono_aot_init_gshared_method_this(gpointer aot_module,guint32 method_index,MonoObject * this_obj)4415 mono_aot_init_gshared_method_this (gpointer aot_module, guint32 method_index, MonoObject *this_obj)
4416 {
4417 	MonoAotModule *amodule = (MonoAotModule *)aot_module;
4418 	MonoClass *klass;
4419 	MonoGenericContext *context;
4420 	MonoMethod *method;
4421 
4422 	// FIXME:
4423 	g_assert (this_obj);
4424 	klass = this_obj->vtable->klass;
4425 
4426 	amodule_lock (amodule);
4427 	method = (MonoMethod *)g_hash_table_lookup (amodule->extra_methods, GUINT_TO_POINTER (method_index));
4428 	amodule_unlock (amodule);
4429 
4430 	g_assert (method);
4431 	context = mono_method_get_context (method);
4432 	g_assert (context);
4433 
4434 	init_llvmonly_method (amodule, method_index, NULL, klass, context);
4435 }
4436 
4437 void
mono_aot_init_gshared_method_mrgctx(gpointer aot_module,guint32 method_index,MonoMethodRuntimeGenericContext * rgctx)4438 mono_aot_init_gshared_method_mrgctx (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx)
4439 {
4440 	MonoAotModule *amodule = (MonoAotModule *)aot_module;
4441 	MonoGenericContext context = { NULL, NULL };
4442 	MonoClass *klass = rgctx->class_vtable->klass;
4443 
4444 	if (mono_class_is_ginst (klass))
4445 		context.class_inst = mono_class_get_generic_class (klass)->context.class_inst;
4446 	else if (mono_class_is_gtd (klass))
4447 		context.class_inst = mono_class_get_generic_container (klass)->context.class_inst;
4448 	context.method_inst = rgctx->method_inst;
4449 
4450 	init_llvmonly_method (amodule, method_index, NULL, rgctx->class_vtable->klass, &context);
4451 }
4452 
4453 void
mono_aot_init_gshared_method_vtable(gpointer aot_module,guint32 method_index,MonoVTable * vtable)4454 mono_aot_init_gshared_method_vtable (gpointer aot_module, guint32 method_index, MonoVTable *vtable)
4455 {
4456 	MonoAotModule *amodule = (MonoAotModule *)aot_module;
4457 	MonoClass *klass;
4458 	MonoGenericContext *context;
4459 	MonoMethod *method;
4460 
4461 	klass = vtable->klass;
4462 
4463 	amodule_lock (amodule);
4464 	method = (MonoMethod *)g_hash_table_lookup (amodule->extra_methods, GUINT_TO_POINTER (method_index));
4465 	amodule_unlock (amodule);
4466 
4467 	g_assert (method);
4468 	context = mono_method_get_context (method);
4469 	g_assert (context);
4470 
4471 	init_llvmonly_method (amodule, method_index, NULL, klass, context);
4472 }
4473 
4474 /*
4475  * mono_aot_get_method_checked:
4476  *
4477  *   Return a pointer to the AOTed native code for METHOD if it can be found,
4478  * NULL otherwise.
4479  * On platforms with function pointers, this doesn't return a function pointer.
4480  */
4481 gpointer
mono_aot_get_method_checked(MonoDomain * domain,MonoMethod * method,MonoError * error)4482 mono_aot_get_method_checked (MonoDomain *domain, MonoMethod *method, MonoError *error)
4483 {
4484 	MonoClass *klass = method->klass;
4485 	MonoMethod *orig_method = method;
4486 	guint32 method_index;
4487 	MonoAotModule *amodule = (MonoAotModule *)klass->image->aot_module;
4488 	guint8 *code;
4489 	gboolean cache_result = FALSE;
4490 	MonoError inner_error;
4491 
4492 	error_init (error);
4493 
4494 	if (domain != mono_get_root_domain ())
4495 		/* Non shared AOT code can't be used in other appdomains */
4496 		return NULL;
4497 
4498 	if (enable_aot_cache && !amodule && domain->entry_assembly && klass->image == mono_defaults.corlib) {
4499 		/* This cannot be AOTed during startup, so do it now */
4500 		if (!mscorlib_aot_loaded) {
4501 			mscorlib_aot_loaded = TRUE;
4502 			load_aot_module (klass->image->assembly, NULL);
4503 			amodule = (MonoAotModule *)klass->image->aot_module;
4504 		}
4505 	}
4506 
4507 	if (!amodule)
4508 		return NULL;
4509 
4510 	if (amodule->out_of_date)
4511 		return NULL;
4512 
4513 	if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
4514 		(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
4515 		(method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
4516 		(method->flags & METHOD_ATTRIBUTE_ABSTRACT))
4517 		return NULL;
4518 
4519 	/*
4520 	 * Use the original method instead of its invoke-with-check wrapper.
4521 	 * This is not a problem when using full-aot, since it doesn't support
4522 	 * remoting.
4523 	 */
4524 	if (mono_aot_only && method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
4525 		return mono_aot_get_method_checked (domain, mono_marshal_method_from_wrapper (method), error);
4526 
4527 	g_assert (klass->inited);
4528 
4529 	/* Find method index */
4530 	method_index = 0xffffff;
4531 
4532 	gboolean dedupable = mono_aot_can_dedup (method);
4533 
4534 	if (method->is_inflated && !method->wrapper_type && mono_method_is_generic_sharable_full (method, TRUE, FALSE, FALSE) && !dedupable) {
4535 		MonoMethod *orig_method = method;
4536 		/*
4537 		 * For generic methods, we store the fully shared instance in place of the
4538 		 * original method.
4539 		 */
4540 		method = mono_method_get_declaring_generic_method (method);
4541 		method_index = mono_metadata_token_index (method->token) - 1;
4542 
4543 		if (mono_llvm_only) {
4544 			/* Needed by mono_aot_init_gshared_method_this () */
4545 			/* orig_method is a random instance but it is enough to make init_method () work */
4546 			amodule_lock (amodule);
4547 			g_hash_table_insert (amodule->extra_methods, GUINT_TO_POINTER (method_index), orig_method);
4548 			amodule_unlock (amodule);
4549 		}
4550 	}
4551 
4552 	if (method_index == 0xffffff && (method->is_inflated || !method->token)) {
4553 		/* This hash table is used to avoid the slower search in the extra_method_table in the AOT image */
4554 		amodule_lock (amodule);
4555 		code = (guint8 *)g_hash_table_lookup (amodule->method_to_code, method);
4556 		amodule_unlock (amodule);
4557 		if (code)
4558 			return code;
4559 
4560 		cache_result = TRUE;
4561 		if (method_index == 0xffffff)
4562 			method_index = find_aot_method (method, &amodule);
4563 
4564 		/*
4565 		 * Special case the ICollection<T> wrappers for arrays, as they cannot
4566 		 * be statically enumerated, and each wrapper ends up calling the same
4567 		 * method in Array.
4568 		 */
4569 		if (method_index == 0xffffff && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED && method->klass->rank && strstr (method->name, "System.Collections.Generic")) {
4570 			MonoMethod *m = mono_aot_get_array_helper_from_wrapper (method);
4571 
4572 			code = (guint8 *)mono_aot_get_method_checked (domain, m, &inner_error);
4573 			mono_error_cleanup (&inner_error);
4574 			if (code)
4575 				return code;
4576 		}
4577 
4578 		/*
4579 		 * Special case Array.GetGenericValueImpl which is a generic icall.
4580 		 * Generic sharing currently can't handle it, but the icall returns data using
4581 		 * an out parameter, so the managed-to-native wrappers can share the same code.
4582 		 */
4583 		if (method_index == 0xffffff && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE && method->klass == mono_defaults.array_class && !strcmp (method->name, "GetGenericValueImpl")) {
4584 			MonoMethod *m;
4585 			MonoGenericContext ctx;
4586 			MonoType *args [16];
4587 
4588 			if (mono_method_signature (method)->params [1]->type == MONO_TYPE_OBJECT)
4589 				/* Avoid recursion */
4590 				return NULL;
4591 
4592 			m = mono_class_get_method_from_name (mono_defaults.array_class, "GetGenericValueImpl", 2);
4593 			g_assert (m);
4594 
4595 			memset (&ctx, 0, sizeof (ctx));
4596 			args [0] = &mono_defaults.object_class->byval_arg;
4597 			ctx.method_inst = mono_metadata_get_generic_inst (1, args);
4598 
4599 			m = mono_marshal_get_native_wrapper (mono_class_inflate_generic_method_checked (m, &ctx, error), TRUE, TRUE);
4600 			if (!m)
4601 				g_error ("AOT runtime could not load method due to %s", mono_error_get_message (error)); /* FIXME don't swallow the error */
4602 
4603 			/*
4604 			 * Get the code for the <object> instantiation which should be emitted into
4605 			 * the mscorlib aot image by the AOT compiler.
4606 			 */
4607 			code = (guint8 *)mono_aot_get_method_checked (domain, m, &inner_error);
4608 			mono_error_cleanup (&inner_error);
4609 			if (code)
4610 				return code;
4611 		}
4612 
4613 		/* Same for CompareExchange<T> and Exchange<T> */
4614 		/* Same for Volatile.Read<T>/Write<T> */
4615 		if (method_index == 0xffffff && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE && method->klass->image == mono_defaults.corlib &&
4616 			((!strcmp (method->klass->name_space, "System.Threading") && !strcmp (method->klass->name, "Interlocked") && (!strcmp (method->name, "CompareExchange") || !strcmp (method->name, "Exchange")) && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (mono_method_signature (method)->params [1]))) ||
4617 			 (!strcmp (method->klass->name_space, "System.Threading") && !strcmp (method->klass->name, "Volatile") && (!strcmp (method->name, "Read") && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (mono_method_signature (method)->ret)))) ||
4618 			 (!strcmp (method->klass->name_space, "System.Threading") && !strcmp (method->klass->name, "Volatile") && (!strcmp (method->name, "Write") && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (mono_method_signature (method)->params [1])))))) {
4619 			MonoMethod *m;
4620 			MonoGenericContext ctx;
4621 			MonoType *args [16];
4622 			gpointer iter = NULL;
4623 
4624 			while ((m = mono_class_get_methods (method->klass, &iter))) {
4625 				if (mono_method_signature (m)->generic_param_count && !strcmp (m->name, method->name))
4626 					break;
4627 			}
4628 			g_assert (m);
4629 
4630 			memset (&ctx, 0, sizeof (ctx));
4631 			args [0] = &mono_defaults.object_class->byval_arg;
4632 			ctx.method_inst = mono_metadata_get_generic_inst (1, args);
4633 
4634 			m = mono_marshal_get_native_wrapper (mono_class_inflate_generic_method_checked (m, &ctx, error), TRUE, TRUE);
4635 			if (!m)
4636 				g_error ("AOT runtime could not load method due to %s", mono_error_get_message (error)); /* FIXME don't swallow the error */
4637 
4638 			/* Avoid recursion */
4639 			if (method == m)
4640 				return NULL;
4641 
4642 			/*
4643 			 * Get the code for the <object> instantiation which should be emitted into
4644 			 * the mscorlib aot image by the AOT compiler.
4645 			 */
4646 			code = (guint8 *)mono_aot_get_method_checked (domain, m, &inner_error);
4647 			mono_error_cleanup (&inner_error);
4648 			if (code)
4649 				return code;
4650 		}
4651 
4652 		/* For ARRAY_ACCESSOR wrappers with reference types, use the <object> instantiation saved in corlib */
4653 		if (method_index == 0xffffff && method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
4654 			WrapperInfo *info = mono_marshal_get_wrapper_info (method);
4655 
4656 			if (info->subtype == WRAPPER_SUBTYPE_ARRAY_ACCESSOR) {
4657 				MonoMethod *array_method = info->d.array_accessor.method;
4658 				if (MONO_TYPE_IS_REFERENCE (&array_method->klass->element_class->byval_arg)) {
4659 					int rank;
4660 
4661 					if (!strcmp (array_method->name, "Set"))
4662 						rank = mono_method_signature (array_method)->param_count - 1;
4663 					else if (!strcmp (array_method->name, "Get") || !strcmp (array_method->name, "Address"))
4664 						rank = mono_method_signature (array_method)->param_count;
4665 					else
4666 						g_assert_not_reached ();
4667 					MonoClass *obj_array_class = mono_array_class_get (mono_defaults.object_class, rank);
4668 					MonoMethod *m = mono_class_get_method_from_name (obj_array_class, array_method->name, mono_method_signature (array_method)->param_count);
4669 					g_assert (m);
4670 
4671 					m = mono_marshal_get_array_accessor_wrapper (m);
4672 					if (m != method) {
4673 						code = (guint8 *)mono_aot_get_method_checked (domain, m, &inner_error);
4674 						mono_error_cleanup (&inner_error);
4675 						if (code)
4676 							return code;
4677 					}
4678 				}
4679 			}
4680 		}
4681 
4682 		if (method_index == 0xffffff && method->is_inflated && mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE)) {
4683 			/* Partial sharing */
4684 			MonoMethod *shared;
4685 
4686 			shared = mini_get_shared_method (method);
4687 			method_index = find_aot_method (shared, &amodule);
4688 			if (method_index != 0xffffff)
4689 				method = shared;
4690 		}
4691 
4692 		if (method_index == 0xffffff && method->is_inflated && mono_method_is_generic_sharable_full (method, FALSE, FALSE, TRUE)) {
4693 			MonoMethod *shared;
4694 			/* gsharedvt */
4695 			/* Use the all-vt shared method since this is what was AOTed */
4696 			shared = mini_get_shared_method_full (method, TRUE, TRUE);
4697 			method_index = find_aot_method (shared, &amodule);
4698 			if (method_index != 0xffffff)
4699 				method = mini_get_shared_method_full (method, TRUE, FALSE);
4700 		}
4701 
4702 		if (method_index == 0xffffff) {
4703 			if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
4704 				char *full_name;
4705 
4706 				full_name = mono_method_full_name (method, TRUE);
4707 				mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.", full_name);
4708 				g_free (full_name);
4709 			}
4710 			return NULL;
4711 		}
4712 
4713 		if (method_index == 0xffffff)
4714 			return NULL;
4715 
4716 		/* Needed by find_jit_info */
4717 		amodule_lock (amodule);
4718 		g_hash_table_insert (amodule->extra_methods, GUINT_TO_POINTER (method_index), method);
4719 		amodule_unlock (amodule);
4720 	} else {
4721 		/* Common case */
4722 		method_index = mono_metadata_token_index (method->token) - 1;
4723 	}
4724 
4725 	code = (guint8 *)load_method (domain, amodule, klass->image, method, method->token, method_index, error);
4726 	if (!is_ok (error))
4727 		return NULL;
4728 	if (code && cache_result) {
4729 		amodule_lock (amodule);
4730 		g_hash_table_insert (amodule->method_to_code, orig_method, code);
4731 		amodule_unlock (amodule);
4732 	}
4733 	return code;
4734 }
4735 
4736 /**
4737  * Same as mono_aot_get_method, but we try to avoid loading any metadata from the
4738  * method.
4739  */
4740 gpointer
mono_aot_get_method_from_token(MonoDomain * domain,MonoImage * image,guint32 token,MonoError * error)4741 mono_aot_get_method_from_token (MonoDomain *domain, MonoImage *image, guint32 token, MonoError *error)
4742 {
4743 	MonoAotModule *aot_module = (MonoAotModule *)image->aot_module;
4744 	int method_index;
4745 	gpointer res;
4746 
4747 	error_init (error);
4748 
4749 	if (!aot_module)
4750 		return NULL;
4751 
4752 	method_index = mono_metadata_token_index (token) - 1;
4753 
4754 	res = load_method (domain, aot_module, image, NULL, token, method_index, error);
4755 	return res;
4756 }
4757 
4758 typedef struct {
4759 	guint8 *addr;
4760 	gboolean res;
4761 } IsGotEntryUserData;
4762 
4763 static void
check_is_got_entry(gpointer key,gpointer value,gpointer user_data)4764 check_is_got_entry (gpointer key, gpointer value, gpointer user_data)
4765 {
4766 	IsGotEntryUserData *data = (IsGotEntryUserData*)user_data;
4767 	MonoAotModule *aot_module = (MonoAotModule*)value;
4768 
4769 	if (aot_module->got && (data->addr >= (guint8*)(aot_module->got)) && (data->addr < (guint8*)(aot_module->got + aot_module->info.got_size)))
4770 		data->res = TRUE;
4771 }
4772 
4773 gboolean
mono_aot_is_got_entry(guint8 * code,guint8 * addr)4774 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
4775 {
4776 	IsGotEntryUserData user_data;
4777 
4778 	if (!aot_modules)
4779 		return FALSE;
4780 
4781 	user_data.addr = addr;
4782 	user_data.res = FALSE;
4783 	mono_aot_lock ();
4784 	g_hash_table_foreach (aot_modules, check_is_got_entry, &user_data);
4785 	mono_aot_unlock ();
4786 
4787 	return user_data.res;
4788 }
4789 
4790 typedef struct {
4791 	guint8 *addr;
4792 	MonoAotModule *module;
4793 } FindAotModuleUserData;
4794 
4795 static void
find_aot_module_cb(gpointer key,gpointer value,gpointer user_data)4796 find_aot_module_cb (gpointer key, gpointer value, gpointer user_data)
4797 {
4798 	FindAotModuleUserData *data = (FindAotModuleUserData*)user_data;
4799 	MonoAotModule *aot_module = (MonoAotModule*)value;
4800 
4801 	if (amodule_contains_code_addr (aot_module, data->addr))
4802 		data->module = aot_module;
4803 }
4804 
4805 static inline MonoAotModule*
find_aot_module(guint8 * code)4806 find_aot_module (guint8 *code)
4807 {
4808 	FindAotModuleUserData user_data;
4809 
4810 	if (!aot_modules)
4811 		return NULL;
4812 
4813 	/* Reading these need no locking */
4814 	if (((gsize)code < aot_code_low_addr) || ((gsize)code > aot_code_high_addr))
4815 		return NULL;
4816 
4817 	user_data.addr = code;
4818 	user_data.module = NULL;
4819 
4820 	mono_aot_lock ();
4821 	g_hash_table_foreach (aot_modules, find_aot_module_cb, &user_data);
4822 	mono_aot_unlock ();
4823 
4824 	return user_data.module;
4825 }
4826 
4827 void
mono_aot_patch_plt_entry(guint8 * code,guint8 * plt_entry,gpointer * got,mgreg_t * regs,guint8 * addr)4828 mono_aot_patch_plt_entry (guint8 *code, guint8 *plt_entry, gpointer *got, mgreg_t *regs, guint8 *addr)
4829 {
4830 	MonoAotModule *amodule;
4831 
4832 	/*
4833 	 * Since AOT code is only used in the root domain,
4834 	 * mono_domain_get () != mono_get_root_domain () means the calling method
4835 	 * is AppDomain:InvokeInDomain, so this is the same check as in
4836 	 * mono_method_same_domain () but without loading the metadata for the method.
4837 	 */
4838 	if (mono_domain_get () == mono_get_root_domain ()) {
4839 		if (!got) {
4840 			amodule = find_aot_module (code);
4841 			if (amodule)
4842 				got = amodule->got;
4843 		}
4844 		mono_arch_patch_plt_entry (plt_entry, got, regs, addr);
4845 	}
4846 }
4847 
4848 /*
4849  * mono_aot_plt_resolve:
4850  *
4851  *   This function is called by the entries in the PLT to resolve the actual method that
4852  * needs to be called. It returns a trampoline to the method and patches the PLT entry.
4853  * Returns NULL if the something cannot be loaded.
4854  */
4855 gpointer
mono_aot_plt_resolve(gpointer aot_module,guint32 plt_info_offset,guint8 * code,MonoError * error)4856 mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code, MonoError *error)
4857 {
4858 #ifdef MONO_ARCH_AOT_SUPPORTED
4859 	guint8 *p, *target, *plt_entry;
4860 	MonoJumpInfo ji;
4861 	MonoAotModule *module = (MonoAotModule*)aot_module;
4862 	gboolean res, no_ftnptr = FALSE;
4863 	MonoMemPool *mp;
4864 	gboolean using_gsharedvt = FALSE;
4865 
4866 	error_init (error);
4867 
4868 	//printf ("DYN: %p %d\n", aot_module, plt_info_offset);
4869 
4870 	p = &module->blob [plt_info_offset];
4871 
4872 	ji.type = (MonoJumpInfoType)decode_value (p, &p);
4873 
4874 	mp = mono_mempool_new ();
4875 	res = decode_patch (module, mp, &ji, p, &p);
4876 
4877 	if (!res) {
4878 		mono_mempool_destroy (mp);
4879 		return NULL;
4880 	}
4881 
4882 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
4883 	using_gsharedvt = TRUE;
4884 #endif
4885 
4886 	/*
4887 	 * Avoid calling resolve_patch_target in the full-aot case if possible, since
4888 	 * it would create a trampoline, and we don't need that.
4889 	 * We could do this only if the method does not need the special handling
4890 	 * in mono_magic_trampoline ().
4891 	 */
4892 	if (mono_aot_only && ji.type == MONO_PATCH_INFO_METHOD && !ji.data.method->is_generic && !mono_method_check_context_used (ji.data.method) && !(ji.data.method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) &&
4893 		!mono_method_needs_static_rgctx_invoke (ji.data.method, FALSE) && !using_gsharedvt) {
4894 		target = (guint8 *)mono_jit_compile_method (ji.data.method, error);
4895 		if (!mono_error_ok (error)) {
4896 			mono_mempool_destroy (mp);
4897 			return NULL;
4898 		}
4899 		no_ftnptr = TRUE;
4900 	} else {
4901 		target = (guint8 *)mono_resolve_patch_target (NULL, mono_domain_get (), NULL, &ji, TRUE, error);
4902 		if (!mono_error_ok (error)) {
4903 			mono_mempool_destroy (mp);
4904 			return NULL;
4905 		}
4906 	}
4907 
4908 	/*
4909 	 * The trampoline expects us to return a function descriptor on platforms which use
4910 	 * it, but resolve_patch_target returns a direct function pointer for some type of
4911 	 * patches, so have to translate between the two.
4912 	 * FIXME: Clean this up, but how ?
4913 	 */
4914 	if (ji.type == MONO_PATCH_INFO_ABS || ji.type == MONO_PATCH_INFO_INTERNAL_METHOD || ji.type == MONO_PATCH_INFO_ICALL_ADDR || ji.type == MONO_PATCH_INFO_JIT_ICALL_ADDR || ji.type == MONO_PATCH_INFO_RGCTX_FETCH) {
4915 		/* These should already have a function descriptor */
4916 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4917 		/* Our function descriptors have a 0 environment, gcc created ones don't */
4918 		if (ji.type != MONO_PATCH_INFO_INTERNAL_METHOD && ji.type != MONO_PATCH_INFO_JIT_ICALL_ADDR && ji.type != MONO_PATCH_INFO_ICALL_ADDR)
4919 			g_assert (((gpointer*)target) [2] == 0);
4920 #endif
4921 		/* Empty */
4922 	} else if (!no_ftnptr) {
4923 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4924 		g_assert (((gpointer*)target) [2] != 0);
4925 #endif
4926 		target = (guint8 *)mono_create_ftnptr (mono_domain_get (), target);
4927 	}
4928 
4929 	mono_mempool_destroy (mp);
4930 
4931 	/* Patch the PLT entry with target which might be the actual method not a trampoline */
4932 	plt_entry = mono_aot_get_plt_entry (code);
4933 	g_assert (plt_entry);
4934 	mono_aot_patch_plt_entry (code, plt_entry, module->got, NULL, target);
4935 
4936 	return target;
4937 #else
4938 	g_assert_not_reached ();
4939 	return NULL;
4940 #endif
4941 }
4942 
4943 /**
4944  * init_plt:
4945  *
4946  *   Initialize the PLT table of the AOT module. Called lazily when the first AOT
4947  * method in the module is loaded to avoid committing memory by writing to it.
4948  * LOCKING: Assumes the AMODULE lock is held.
4949  */
4950 static void
init_plt(MonoAotModule * amodule)4951 init_plt (MonoAotModule *amodule)
4952 {
4953 	int i;
4954 	gpointer tramp;
4955 
4956 	if (amodule->plt_inited)
4957 		return;
4958 
4959 	if (amodule->info.plt_size <= 1) {
4960 		amodule->plt_inited = TRUE;
4961 		return;
4962 	}
4963 
4964 	tramp = mono_create_specific_trampoline (amodule, MONO_TRAMPOLINE_AOT_PLT, mono_get_root_domain (), NULL);
4965 
4966 	/*
4967 	 * Initialize the PLT entries in the GOT to point to the default targets.
4968 	 */
4969 
4970 	tramp = mono_create_ftnptr (mono_domain_get (), tramp);
4971 	 for (i = 1; i < amodule->info.plt_size; ++i)
4972 		 /* All the default entries point to the AOT trampoline */
4973 		 ((gpointer*)amodule->got)[amodule->info.plt_got_offset_base + i] = tramp;
4974 
4975 	amodule->plt_inited = TRUE;
4976 }
4977 
4978 /*
4979  * mono_aot_get_plt_entry:
4980  *
4981  *   Return the address of the PLT entry called by the code at CODE if exists.
4982  */
4983 guint8*
mono_aot_get_plt_entry(guint8 * code)4984 mono_aot_get_plt_entry (guint8 *code)
4985 {
4986 	MonoAotModule *amodule = find_aot_module (code);
4987 	guint8 *target = NULL;
4988 
4989 	if (!amodule)
4990 		return NULL;
4991 
4992 #ifdef TARGET_ARM
4993 	if (is_thumb_code (amodule, code - 4))
4994 		return mono_arm_get_thumb_plt_entry (code);
4995 #endif
4996 
4997 #ifdef MONO_ARCH_AOT_SUPPORTED
4998 	target = mono_arch_get_call_target (code);
4999 #else
5000 	g_assert_not_reached ();
5001 #endif
5002 
5003 #ifdef MONOTOUCH
5004 	while (target != NULL) {
5005 		if ((target >= (guint8*)(amodule->plt)) && (target < (guint8*)(amodule->plt_end)))
5006 			return target;
5007 
5008 		// Add 4 since mono_arch_get_call_target assumes we're passing
5009 		// the instruction after the actual branch instruction.
5010 		target = mono_arch_get_call_target (target + 4);
5011 	}
5012 
5013 	return NULL;
5014 #else
5015 	if ((target >= (guint8*)(amodule->plt)) && (target < (guint8*)(amodule->plt_end)))
5016 		return target;
5017 	else
5018 		return NULL;
5019 #endif
5020 }
5021 
5022 /*
5023  * mono_aot_get_plt_info_offset:
5024  *
5025  *   Return the PLT info offset belonging to the plt entry called by CODE.
5026  */
5027 guint32
mono_aot_get_plt_info_offset(mgreg_t * regs,guint8 * code)5028 mono_aot_get_plt_info_offset (mgreg_t *regs, guint8 *code)
5029 {
5030 	guint8 *plt_entry = mono_aot_get_plt_entry (code);
5031 
5032 	g_assert (plt_entry);
5033 
5034 	/* The offset is embedded inside the code after the plt entry */
5035 #ifdef MONO_ARCH_AOT_SUPPORTED
5036 	return mono_arch_get_plt_info_offset (plt_entry, regs, code);
5037 #else
5038 	g_assert_not_reached ();
5039 	return 0;
5040 #endif
5041 }
5042 
5043 static gpointer
mono_create_ftnptr_malloc(guint8 * code)5044 mono_create_ftnptr_malloc (guint8 *code)
5045 {
5046 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
5047 	MonoPPCFunctionDescriptor *ftnptr = g_malloc0 (sizeof (MonoPPCFunctionDescriptor));
5048 
5049 	ftnptr->code = code;
5050 	ftnptr->toc = NULL;
5051 	ftnptr->env = NULL;
5052 
5053 	return ftnptr;
5054 #else
5055 	return code;
5056 #endif
5057 }
5058 
5059 /*
5060  * mono_aot_register_jit_icall:
5061  *
5062  *   Register a JIT icall which is called by trampolines in full-aot mode. This should
5063  * be called from mono_arch_init () during startup.
5064  */
5065 void
mono_aot_register_jit_icall(const char * name,gpointer addr)5066 mono_aot_register_jit_icall (const char *name, gpointer addr)
5067 {
5068 	/* No need for locking */
5069 	if (!aot_jit_icall_hash)
5070 		aot_jit_icall_hash = g_hash_table_new (g_str_hash, g_str_equal);
5071 	g_hash_table_insert (aot_jit_icall_hash, (char*)name, addr);
5072 }
5073 
5074 /*
5075  * load_function_full:
5076  *
5077  *   Load the function named NAME from the aot image.
5078  */
5079 static gpointer
load_function_full(MonoAotModule * amodule,const char * name,MonoTrampInfo ** out_tinfo)5080 load_function_full (MonoAotModule *amodule, const char *name, MonoTrampInfo **out_tinfo)
5081 {
5082 	char *symbol;
5083 	guint8 *p;
5084 	int n_patches, pindex;
5085 	MonoMemPool *mp;
5086 	gpointer code;
5087 	guint32 info_offset;
5088 
5089 	/* Load the code */
5090 
5091 	symbol = g_strdup_printf ("%s", name);
5092 	find_amodule_symbol (amodule, symbol, (gpointer *)&code);
5093 	g_free (symbol);
5094 	if (!code)
5095 		g_error ("Symbol '%s' not found in AOT file '%s'.\n", name, amodule->aot_name);
5096 
5097 	mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT: FOUND function '%s' in AOT file '%s'.", name, amodule->aot_name);
5098 
5099 	/* Load info */
5100 
5101 	symbol = g_strdup_printf ("%s_p", name);
5102 	find_amodule_symbol (amodule, symbol, (gpointer *)&p);
5103 	g_free (symbol);
5104 	if (!p)
5105 		/* Nothing to patch */
5106 		return code;
5107 
5108 	info_offset = *(guint32*)p;
5109 	if (out_tinfo) {
5110 		MonoTrampInfo *tinfo;
5111 		guint32 code_size, uw_info_len, uw_offset;
5112 		guint8 *uw_info;
5113 		/* Construct a MonoTrampInfo from the data in the AOT image */
5114 
5115 		p += sizeof (guint32);
5116 		code_size = *(guint32*)p;
5117 		p += sizeof (guint32);
5118 		uw_offset = *(guint32*)p;
5119 		uw_info = amodule->unwind_info + uw_offset;
5120 		uw_info_len = decode_value (uw_info, &uw_info);
5121 
5122 		tinfo = g_new0 (MonoTrampInfo, 1);
5123 		tinfo->code = (guint8 *)code;
5124 		tinfo->code_size = code_size;
5125 		tinfo->uw_info_len = uw_info_len;
5126 		if (uw_info_len)
5127 			tinfo->uw_info = uw_info;
5128 
5129 		*out_tinfo = tinfo;
5130 	}
5131 
5132 	p = amodule->blob + info_offset;
5133 
5134 	/* Similar to mono_aot_load_method () */
5135 
5136 	n_patches = decode_value (p, &p);
5137 
5138 	if (n_patches) {
5139 		MonoJumpInfo *patches;
5140 		guint32 *got_slots;
5141 
5142 		mp = mono_mempool_new ();
5143 
5144 		patches = load_patch_info (amodule, mp, n_patches, FALSE, &got_slots, p, &p);
5145 		g_assert (patches);
5146 
5147 		for (pindex = 0; pindex < n_patches; ++pindex) {
5148 			MonoJumpInfo *ji = &patches [pindex];
5149 			MonoError error;
5150 			gpointer target;
5151 
5152 			if (amodule->got [got_slots [pindex]])
5153 				continue;
5154 
5155 			/*
5156 			 * When this code is executed, the runtime may not be initalized yet, so
5157 			 * resolve the patch info by hand.
5158 			 */
5159 			if (ji->type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
5160 				if (!strcmp (ji->data.name, "mono_get_lmf_addr")) {
5161 					target = mono_get_lmf_addr;
5162 				} else if (!strcmp (ji->data.name, "mono_thread_force_interruption_checkpoint_noraise")) {
5163 					target = mono_thread_force_interruption_checkpoint_noraise;
5164 				} else if (!strcmp (ji->data.name, "mono_exception_from_token")) {
5165 					target = mono_exception_from_token;
5166 				} else if (!strcmp (ji->data.name, "mono_throw_exception")) {
5167 					target = mono_get_throw_exception ();
5168 				} else if (strstr (ji->data.name, "trampoline_func_") == ji->data.name) {
5169 					MonoTrampolineType tramp_type2 = (MonoTrampolineType)atoi (ji->data.name + strlen ("trampoline_func_"));
5170 					target = (gpointer)mono_get_trampoline_func (tramp_type2);
5171 				} else if (strstr (ji->data.name, "specific_trampoline_lazy_fetch_") == ji->data.name) {
5172 					/* atoll is needed because the the offset is unsigned */
5173 					guint32 slot;
5174 					int res;
5175 
5176 					res = sscanf (ji->data.name, "specific_trampoline_lazy_fetch_%u", &slot);
5177 					g_assert (res == 1);
5178 					target = mono_create_specific_trampoline (GUINT_TO_POINTER (slot), MONO_TRAMPOLINE_RGCTX_LAZY_FETCH, mono_get_root_domain (), NULL);
5179 					target = mono_create_ftnptr_malloc ((guint8 *)target);
5180 				} else if (!strcmp (ji->data.name, "debugger_agent_single_step_from_context")) {
5181 					target = debugger_agent_single_step_from_context;
5182 				} else if (!strcmp (ji->data.name, "debugger_agent_breakpoint_from_context")) {
5183 					target = debugger_agent_breakpoint_from_context;
5184 				} else if (!strcmp (ji->data.name, "throw_exception_addr")) {
5185 					target = mono_get_throw_exception_addr ();
5186 				} else if (strstr (ji->data.name, "generic_trampoline_")) {
5187 					target = mono_aot_get_trampoline (ji->data.name);
5188 				} else if (aot_jit_icall_hash && g_hash_table_lookup (aot_jit_icall_hash, ji->data.name)) {
5189 					/* Registered by mono_arch_init () */
5190 					target = g_hash_table_lookup (aot_jit_icall_hash, ji->data.name);
5191 				} else {
5192 					fprintf (stderr, "Unknown relocation '%s'\n", ji->data.name);
5193 					g_assert_not_reached ();
5194 					target = NULL;
5195 				}
5196 			} else {
5197 				/* Hopefully the code doesn't have patches which need method or
5198 				 * domain to be set.
5199 				 */
5200 				target = mono_resolve_patch_target (NULL, NULL, (guint8 *)code, ji, FALSE, &error);
5201 				mono_error_assert_ok (&error);
5202 				g_assert (target);
5203 			}
5204 
5205 			amodule->got [got_slots [pindex]] = target;
5206 		}
5207 
5208 		g_free (got_slots);
5209 
5210 		mono_mempool_destroy (mp);
5211 	}
5212 
5213 	return code;
5214 }
5215 
5216 static gpointer
load_function(MonoAotModule * amodule,const char * name)5217 load_function (MonoAotModule *amodule, const char *name)
5218 {
5219 	return load_function_full (amodule, name, NULL);
5220 }
5221 
5222 static MonoAotModule*
get_mscorlib_aot_module(void)5223 get_mscorlib_aot_module (void)
5224 {
5225 	MonoImage *image;
5226 	MonoAotModule *amodule;
5227 
5228 	image = mono_defaults.corlib;
5229 	if (image)
5230 		amodule = (MonoAotModule *)image->aot_module;
5231 	else
5232 		amodule = mscorlib_aot_module;
5233 	g_assert (amodule);
5234 	return amodule;
5235 }
5236 
5237 static void
no_trampolines(void)5238 no_trampolines (void)
5239 {
5240 	g_assert_not_reached ();
5241 }
5242 
5243 
5244 #ifndef TARGET_WASM
5245 /*
5246  * Return the trampoline identified by NAME from the mscorlib AOT file.
5247  * On ppc64, this returns a function descriptor.
5248  */
5249 gpointer
mono_aot_get_trampoline_full(const char * name,MonoTrampInfo ** out_tinfo)5250 mono_aot_get_trampoline_full (const char *name, MonoTrampInfo **out_tinfo)
5251 {
5252 	MonoAotModule *amodule = get_mscorlib_aot_module ();
5253 
5254 	if (mono_llvm_only) {
5255 		*out_tinfo = NULL;
5256 		return no_trampolines;
5257 	}
5258 
5259 	return mono_create_ftnptr_malloc ((guint8 *)load_function_full (amodule, name, out_tinfo));
5260 }
5261 #endif
5262 
5263 
5264 gpointer
mono_aot_get_trampoline(const char * name)5265 mono_aot_get_trampoline (const char *name)
5266 {
5267 	MonoTrampInfo *out_tinfo;
5268 	gpointer code;
5269 
5270 	code =  mono_aot_get_trampoline_full (name, &out_tinfo);
5271 	mono_aot_tramp_info_register (out_tinfo, NULL);
5272 
5273 	return code;
5274 }
5275 
5276 static gpointer
read_unwind_info(MonoAotModule * amodule,MonoTrampInfo * info,const char * symbol_name)5277 read_unwind_info (MonoAotModule *amodule, MonoTrampInfo *info, const char *symbol_name)
5278 {
5279 	gpointer symbol_addr;
5280 	guint32 uw_offset, uw_info_len;
5281 	guint8 *uw_info;
5282 
5283 	find_amodule_symbol (amodule, symbol_name, &symbol_addr);
5284 
5285 	if (!symbol_addr)
5286 		return NULL;
5287 
5288 	uw_offset = *(guint32*)symbol_addr;
5289 	uw_info = amodule->unwind_info + uw_offset;
5290 	uw_info_len = decode_value (uw_info, &uw_info);
5291 
5292 	info->uw_info_len = uw_info_len;
5293 	if (uw_info_len)
5294 		info->uw_info = uw_info;
5295 	else
5296 		info->uw_info = NULL;
5297 
5298 	/* If successful return the address of the following data */
5299 	return (guint32*)symbol_addr + 1;
5300 }
5301 
5302 #ifdef MONOTOUCH
5303 #include <mach/mach.h>
5304 
5305 static TrampolinePage* trampoline_pages [MONO_AOT_TRAMP_NUM];
5306 
5307 static void
read_page_trampoline_uwinfo(MonoTrampInfo * info,int tramp_type,gboolean is_generic)5308 read_page_trampoline_uwinfo (MonoTrampInfo *info, int tramp_type, gboolean is_generic)
5309 {
5310 	char symbol_name [128];
5311 
5312 	if (tramp_type == MONO_AOT_TRAMP_SPECIFIC)
5313 		sprintf (symbol_name, "specific_trampolines_page_%s_p", is_generic ? "gen" : "sp");
5314 	else if (tramp_type == MONO_AOT_TRAMP_STATIC_RGCTX)
5315 		sprintf (symbol_name, "rgctx_trampolines_page_%s_p", is_generic ? "gen" : "sp");
5316 	else if (tramp_type == MONO_AOT_TRAMP_IMT)
5317 		sprintf (symbol_name, "imt_trampolines_page_%s_p", is_generic ? "gen" : "sp");
5318 	else if (tramp_type == MONO_AOT_TRAMP_GSHAREDVT_ARG)
5319 		sprintf (symbol_name, "gsharedvt_trampolines_page_%s_p", is_generic ? "gen" : "sp");
5320 	else
5321 		g_assert_not_reached ();
5322 
5323 	read_unwind_info (mono_defaults.corlib->aot_module, info, symbol_name);
5324 }
5325 
5326 static unsigned char*
get_new_trampoline_from_page(int tramp_type)5327 get_new_trampoline_from_page (int tramp_type)
5328 {
5329 	MonoAotModule *amodule;
5330 	MonoImage *image;
5331 	TrampolinePage *page;
5332 	int count;
5333 	void *tpage;
5334 	vm_address_t addr, taddr;
5335 	kern_return_t ret;
5336 	vm_prot_t prot, max_prot;
5337 	int psize, specific_trampoline_size;
5338 	unsigned char *code;
5339 
5340 	specific_trampoline_size = 2 * sizeof (gpointer);
5341 
5342 	mono_aot_page_lock ();
5343 	page = trampoline_pages [tramp_type];
5344 	if (page && page->trampolines < page->trampolines_end) {
5345 		code = page->trampolines;
5346 		page->trampolines += specific_trampoline_size;
5347 		mono_aot_page_unlock ();
5348 		return code;
5349 	}
5350 	mono_aot_page_unlock ();
5351 	/* the trampoline template page is in the mscorlib module */
5352 	image = mono_defaults.corlib;
5353 	g_assert (image);
5354 
5355 	psize = MONO_AOT_TRAMP_PAGE_SIZE;
5356 
5357 	amodule = image->aot_module;
5358 	g_assert (amodule);
5359 
5360 	if (tramp_type == MONO_AOT_TRAMP_SPECIFIC)
5361 		tpage = load_function (amodule, "specific_trampolines_page");
5362 	else if (tramp_type == MONO_AOT_TRAMP_STATIC_RGCTX)
5363 		tpage = load_function (amodule, "rgctx_trampolines_page");
5364 	else if (tramp_type == MONO_AOT_TRAMP_IMT)
5365 		tpage = load_function (amodule, "imt_trampolines_page");
5366 	else if (tramp_type == MONO_AOT_TRAMP_GSHAREDVT_ARG)
5367 		tpage = load_function (amodule, "gsharedvt_arg_trampolines_page");
5368 	else
5369 		g_error ("Incorrect tramp type for trampolines page");
5370 	g_assert (tpage);
5371 	/*g_warning ("loaded trampolines page at %x", tpage);*/
5372 
5373 	/* avoid the unlikely case of looping forever */
5374 	count = 40;
5375 	page = NULL;
5376 	while (page == NULL && count-- > 0) {
5377 		MonoTrampInfo *gen_info, *sp_info;
5378 
5379 		addr = 0;
5380 		/* allocate two contiguous pages of memory: the first page will contain the data (like a local constant pool)
5381 		 * while the second will contain the trampolines.
5382 		 */
5383 		do {
5384 			ret = vm_allocate (mach_task_self (), &addr, psize * 2, VM_FLAGS_ANYWHERE);
5385 		} while (ret == KERN_ABORTED);
5386 		if (ret != KERN_SUCCESS) {
5387 			g_error ("Cannot allocate memory for trampolines: %d", ret);
5388 			break;
5389 		}
5390 		/*g_warning ("allocated trampoline double page at %x", addr);*/
5391 		/* replace the second page with a remapped trampoline page */
5392 		taddr = addr + psize;
5393 		vm_deallocate (mach_task_self (), taddr, psize);
5394 		ret = vm_remap (mach_task_self (), &taddr, psize, 0, FALSE, mach_task_self(), (vm_address_t)tpage, FALSE, &prot, &max_prot, VM_INHERIT_SHARE);
5395 		if (ret != KERN_SUCCESS) {
5396 			/* someone else got the page, try again  */
5397 			vm_deallocate (mach_task_self (), addr, psize);
5398 			continue;
5399 		}
5400 		/*g_warning ("remapped trampoline page at %x", taddr);*/
5401 
5402 		mono_aot_page_lock ();
5403 		page = trampoline_pages [tramp_type];
5404 		/* some other thread already allocated, so use that to avoid wasting memory */
5405 		if (page && page->trampolines < page->trampolines_end) {
5406 			code = page->trampolines;
5407 			page->trampolines += specific_trampoline_size;
5408 			mono_aot_page_unlock ();
5409 			vm_deallocate (mach_task_self (), addr, psize);
5410 			vm_deallocate (mach_task_self (), taddr, psize);
5411 			return code;
5412 		}
5413 		page = (TrampolinePage*)addr;
5414 		page->next = trampoline_pages [tramp_type];
5415 		trampoline_pages [tramp_type] = page;
5416 		page->trampolines = (void*)(taddr + amodule->info.tramp_page_code_offsets [tramp_type]);
5417 		page->trampolines_end = (void*)(taddr + psize - 64);
5418 		code = page->trampolines;
5419 		page->trampolines += specific_trampoline_size;
5420 		mono_aot_page_unlock ();
5421 
5422 		/* Register the generic part at the beggining of the trampoline page */
5423 		gen_info = mono_tramp_info_create (NULL, (guint8*)taddr, amodule->info.tramp_page_code_offsets [tramp_type], NULL, NULL);
5424 		read_page_trampoline_uwinfo (gen_info, tramp_type, TRUE);
5425 		mono_aot_tramp_info_register (gen_info, NULL);
5426 		/*
5427 		 * FIXME
5428 		 * Registering each specific trampoline produces a lot of
5429 		 * MonoJitInfo structures. Jump trampolines are also registered
5430 		 * separately.
5431 		 */
5432 		if (tramp_type != MONO_AOT_TRAMP_SPECIFIC) {
5433 			/* Register the rest of the page as a single trampoline */
5434 			sp_info = mono_tramp_info_create (NULL, code, page->trampolines_end - code, NULL, NULL);
5435 			read_page_trampoline_uwinfo (sp_info, tramp_type, FALSE);
5436 			mono_aot_tramp_info_register (sp_info, NULL);
5437 		}
5438 		return code;
5439 	}
5440 	g_error ("Cannot allocate more trampoline pages: %d", ret);
5441 	return NULL;
5442 }
5443 
5444 #else
5445 static unsigned char*
get_new_trampoline_from_page(int tramp_type)5446 get_new_trampoline_from_page (int tramp_type)
5447 {
5448 	g_error ("Page trampolines not supported.");
5449 	return NULL;
5450 }
5451 #endif
5452 
5453 
5454 static gpointer
get_new_specific_trampoline_from_page(gpointer tramp,gpointer arg)5455 get_new_specific_trampoline_from_page (gpointer tramp, gpointer arg)
5456 {
5457 	void *code;
5458 	gpointer *data;
5459 
5460 	code = get_new_trampoline_from_page (MONO_AOT_TRAMP_SPECIFIC);
5461 
5462 	data = (gpointer*)((char*)code - MONO_AOT_TRAMP_PAGE_SIZE);
5463 	data [0] = arg;
5464 	data [1] = tramp;
5465 	/*g_warning ("new trampoline at %p for data %p, tramp %p (stored at %p)", code, arg, tramp, data);*/
5466 	return code;
5467 
5468 }
5469 
5470 static gpointer
get_new_rgctx_trampoline_from_page(gpointer tramp,gpointer arg)5471 get_new_rgctx_trampoline_from_page (gpointer tramp, gpointer arg)
5472 {
5473 	void *code;
5474 	gpointer *data;
5475 
5476 	code = get_new_trampoline_from_page (MONO_AOT_TRAMP_STATIC_RGCTX);
5477 
5478 	data = (gpointer*)((char*)code - MONO_AOT_TRAMP_PAGE_SIZE);
5479 	data [0] = arg;
5480 	data [1] = tramp;
5481 	/*g_warning ("new rgctx trampoline at %p for data %p, tramp %p (stored at %p)", code, arg, tramp, data);*/
5482 	return code;
5483 
5484 }
5485 
5486 static gpointer
get_new_imt_trampoline_from_page(gpointer arg)5487 get_new_imt_trampoline_from_page (gpointer arg)
5488 {
5489 	void *code;
5490 	gpointer *data;
5491 
5492 	code = get_new_trampoline_from_page (MONO_AOT_TRAMP_IMT);
5493 
5494 	data = (gpointer*)((char*)code - MONO_AOT_TRAMP_PAGE_SIZE);
5495 	data [0] = arg;
5496 	/*g_warning ("new imt trampoline at %p for data %p, (stored at %p)", code, arg, data);*/
5497 	return code;
5498 
5499 }
5500 
5501 static gpointer
get_new_gsharedvt_arg_trampoline_from_page(gpointer tramp,gpointer arg)5502 get_new_gsharedvt_arg_trampoline_from_page (gpointer tramp, gpointer arg)
5503 {
5504 	void *code;
5505 	gpointer *data;
5506 
5507 	code = get_new_trampoline_from_page (MONO_AOT_TRAMP_GSHAREDVT_ARG);
5508 
5509 	data = (gpointer*)((char*)code - MONO_AOT_TRAMP_PAGE_SIZE);
5510 	data [0] = arg;
5511 	data [1] = tramp;
5512 	/*g_warning ("new rgctx trampoline at %p for data %p, tramp %p (stored at %p)", code, arg, tramp, data);*/
5513 	return code;
5514 }
5515 
5516 /* Return a given kind of trampoline */
5517 /* FIXME set unwind info for these trampolines */
5518 static gpointer
get_numerous_trampoline(MonoAotTrampoline tramp_type,int n_got_slots,MonoAotModule ** out_amodule,guint32 * got_offset,guint32 * out_tramp_size)5519 get_numerous_trampoline (MonoAotTrampoline tramp_type, int n_got_slots, MonoAotModule **out_amodule, guint32 *got_offset, guint32 *out_tramp_size)
5520 {
5521 	MonoImage *image;
5522 	MonoAotModule *amodule = get_mscorlib_aot_module ();
5523 	int index, tramp_size;
5524 
5525 	/* Currently, we keep all trampolines in the mscorlib AOT image */
5526 	image = mono_defaults.corlib;
5527 
5528 	*out_amodule = amodule;
5529 
5530 	mono_aot_lock ();
5531 
5532 #ifdef MONOTOUCH
5533 #define	MONOTOUCH_TRAMPOLINES_ERROR ". See http://docs.xamarin.com/ios/troubleshooting for instructions on how to fix this condition."
5534 #else
5535 #define	MONOTOUCH_TRAMPOLINES_ERROR ""
5536 #endif
5537 	if (amodule->trampoline_index [tramp_type] == amodule->info.num_trampolines [tramp_type]) {
5538 		g_error ("Ran out of trampolines of type %d in '%s' (limit %d)%s\n",
5539 				 tramp_type, image ? image->name : "mscorlib", amodule->info.num_trampolines [tramp_type], MONOTOUCH_TRAMPOLINES_ERROR);
5540 	}
5541 	index = amodule->trampoline_index [tramp_type] ++;
5542 
5543 	mono_aot_unlock ();
5544 
5545 	*got_offset = amodule->info.trampoline_got_offset_base [tramp_type] + (index * n_got_slots);
5546 
5547 	tramp_size = amodule->info.trampoline_size [tramp_type];
5548 
5549 	if (out_tramp_size)
5550 		*out_tramp_size = tramp_size;
5551 
5552 	return amodule->trampolines [tramp_type] + (index * tramp_size);
5553 }
5554 
5555 static void
no_specific_trampoline(void)5556 no_specific_trampoline (void)
5557 {
5558 	g_assert_not_reached ();
5559 }
5560 
5561 /*
5562  * Return a specific trampoline from the AOT file.
5563  */
5564 gpointer
mono_aot_create_specific_trampoline(MonoImage * image,gpointer arg1,MonoTrampolineType tramp_type,MonoDomain * domain,guint32 * code_len)5565 mono_aot_create_specific_trampoline (MonoImage *image, gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
5566 {
5567 	MonoAotModule *amodule;
5568 	guint32 got_offset, tramp_size;
5569 	guint8 *code, *tramp;
5570 	static gpointer generic_trampolines [MONO_TRAMPOLINE_NUM];
5571 	static gboolean inited;
5572 	static guint32 num_trampolines;
5573 
5574 	if (mono_llvm_only) {
5575 		*code_len = 1;
5576 		return no_specific_trampoline;
5577 	}
5578 
5579 	if (!inited) {
5580 		mono_aot_lock ();
5581 
5582 		if (!inited) {
5583 			mono_counters_register ("Specific trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &num_trampolines);
5584 			inited = TRUE;
5585 		}
5586 
5587 		mono_aot_unlock ();
5588 	}
5589 
5590 	num_trampolines ++;
5591 
5592 	if (!generic_trampolines [tramp_type]) {
5593 		char *symbol;
5594 
5595 		symbol = mono_get_generic_trampoline_name (tramp_type);
5596 		generic_trampolines [tramp_type] = mono_aot_get_trampoline (symbol);
5597 		g_free (symbol);
5598 	}
5599 
5600 	tramp = (guint8 *)generic_trampolines [tramp_type];
5601 	g_assert (tramp);
5602 
5603 	if (USE_PAGE_TRAMPOLINES) {
5604 		code = (guint8 *)get_new_specific_trampoline_from_page (tramp, arg1);
5605 		tramp_size = 8;
5606 	} else {
5607 		code = (guint8 *)get_numerous_trampoline (MONO_AOT_TRAMP_SPECIFIC, 2, &amodule, &got_offset, &tramp_size);
5608 
5609 		amodule->got [got_offset] = tramp;
5610 		amodule->got [got_offset + 1] = arg1;
5611 	}
5612 
5613 	if (code_len)
5614 		*code_len = tramp_size;
5615 
5616 	return code;
5617 }
5618 
5619 gpointer
mono_aot_get_static_rgctx_trampoline(gpointer ctx,gpointer addr)5620 mono_aot_get_static_rgctx_trampoline (gpointer ctx, gpointer addr)
5621 {
5622 	MonoAotModule *amodule;
5623 	guint8 *code;
5624 	guint32 got_offset;
5625 
5626 	if (USE_PAGE_TRAMPOLINES) {
5627 		code = (guint8 *)get_new_rgctx_trampoline_from_page (addr, ctx);
5628 	} else {
5629 		code = (guint8 *)get_numerous_trampoline (MONO_AOT_TRAMP_STATIC_RGCTX, 2, &amodule, &got_offset, NULL);
5630 
5631 		amodule->got [got_offset] = ctx;
5632 		amodule->got [got_offset + 1] = addr;
5633 	}
5634 
5635 	/* The caller expects an ftnptr */
5636 	return mono_create_ftnptr (mono_domain_get (), code);
5637 }
5638 
5639 gpointer
mono_aot_get_unbox_trampoline(MonoMethod * method)5640 mono_aot_get_unbox_trampoline (MonoMethod *method)
5641 {
5642 	guint32 method_index = mono_metadata_token_index (method->token) - 1;
5643 	MonoAotModule *amodule;
5644 	gpointer code;
5645 	guint32 *ut, *ut_end, *entry;
5646 	int low, high, entry_index = 0;
5647 	gpointer symbol_addr;
5648 	MonoTrampInfo *tinfo;
5649 
5650 	if (method->is_inflated && !mono_method_is_generic_sharable_full (method, FALSE, FALSE, FALSE)) {
5651 		method_index = find_aot_method (method, &amodule);
5652 		if (method_index == 0xffffff && mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE)) {
5653 			MonoMethod *shared = mini_get_shared_method_full (method, FALSE, FALSE);
5654 			method_index = find_aot_method (shared, &amodule);
5655 		}
5656 		if (method_index == 0xffffff && mono_method_is_generic_sharable_full (method, FALSE, TRUE, TRUE)) {
5657 			MonoMethod *shared = mini_get_shared_method_full (method, TRUE, TRUE);
5658 			method_index = find_aot_method (shared, &amodule);
5659 		}
5660 		g_assert (method_index != 0xffffff);
5661 	} else {
5662 		amodule = (MonoAotModule *)method->klass->image->aot_module;
5663 		g_assert (amodule);
5664 	}
5665 
5666 	if (amodule->info.llvm_get_unbox_tramp) {
5667 		gpointer (*get_tramp) (int) = (gpointer (*)(int))amodule->info.llvm_get_unbox_tramp;
5668 		code = get_tramp (method_index);
5669 
5670 		if (code)
5671 			return code;
5672 	}
5673 
5674 	ut = amodule->unbox_trampolines;
5675 	ut_end = amodule->unbox_trampolines_end;
5676 
5677 	/* Do a binary search in the sorted table */
5678 	code = NULL;
5679 	low = 0;
5680 	high = (ut_end - ut);
5681 	while (low < high) {
5682 		entry_index = (low + high) / 2;
5683 		entry = &ut [entry_index];
5684 		if (entry [0] < method_index) {
5685 			low = entry_index + 1;
5686 		} else if (entry [0] > method_index) {
5687 			high = entry_index;
5688 		} else {
5689 			break;
5690 		}
5691 	}
5692 
5693 	code = get_call_table_entry (amodule->unbox_trampoline_addresses, entry_index);
5694 	g_assert (code);
5695 
5696 	tinfo = mono_tramp_info_create (NULL, (guint8 *)code, 0, NULL, NULL);
5697 
5698 	symbol_addr = read_unwind_info (amodule, tinfo, "unbox_trampoline_p");
5699 	if (!symbol_addr) {
5700 		mono_tramp_info_free (tinfo);
5701 		return FALSE;
5702 	}
5703 
5704 	tinfo->code_size = *(guint32*)symbol_addr;
5705 	mono_aot_tramp_info_register (tinfo, NULL);
5706 
5707 	/* The caller expects an ftnptr */
5708 	return mono_create_ftnptr (mono_domain_get (), code);
5709 }
5710 
5711 gpointer
mono_aot_get_lazy_fetch_trampoline(guint32 slot)5712 mono_aot_get_lazy_fetch_trampoline (guint32 slot)
5713 {
5714 	char *symbol;
5715 	gpointer code;
5716 	MonoAotModule *amodule = (MonoAotModule *)mono_defaults.corlib->aot_module;
5717 	guint32 index = MONO_RGCTX_SLOT_INDEX (slot);
5718 	static int count = 0;
5719 
5720 	count ++;
5721 	if (index >= amodule->info.num_rgctx_fetch_trampolines) {
5722 		static gpointer addr;
5723 		gpointer *info;
5724 
5725 		/*
5726 		 * Use the general version of the rgctx fetch trampoline. It receives a pair of <slot, trampoline> in the rgctx arg reg.
5727 		 */
5728 		if (!addr)
5729 			addr = load_function (amodule, "rgctx_fetch_trampoline_general");
5730 		info = (void **)mono_domain_alloc0 (mono_get_root_domain (), sizeof (gpointer) * 2);
5731 		info [0] = GUINT_TO_POINTER (slot);
5732 		info [1] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot), MONO_TRAMPOLINE_RGCTX_LAZY_FETCH, mono_get_root_domain (), NULL);
5733 		code = mono_aot_get_static_rgctx_trampoline (info, addr);
5734 		return mono_create_ftnptr (mono_domain_get (), code);
5735 	}
5736 
5737 	symbol = mono_get_rgctx_fetch_trampoline_name (slot);
5738 	code = load_function ((MonoAotModule *)mono_defaults.corlib->aot_module, symbol);
5739 	g_free (symbol);
5740 	/* The caller expects an ftnptr */
5741 	return mono_create_ftnptr (mono_domain_get (), code);
5742 }
5743 
5744 static void
no_imt_trampoline(void)5745 no_imt_trampoline (void)
5746 {
5747 	g_assert_not_reached ();
5748 }
5749 
5750 gpointer
mono_aot_get_imt_trampoline(MonoVTable * vtable,MonoDomain * domain,MonoIMTCheckItem ** imt_entries,int count,gpointer fail_tramp)5751 mono_aot_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
5752 {
5753 	guint32 got_offset;
5754 	gpointer code;
5755 	gpointer *buf;
5756 	int i, index, real_count;
5757 	MonoAotModule *amodule;
5758 
5759 	if (mono_llvm_only)
5760 		return no_imt_trampoline;
5761 
5762 	real_count = 0;
5763 	for (i = 0; i < count; ++i) {
5764 		MonoIMTCheckItem *item = imt_entries [i];
5765 
5766 		if (item->is_equals)
5767 			real_count ++;
5768 	}
5769 
5770 	/* Save the entries into an array */
5771 	buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
5772 	index = 0;
5773 	for (i = 0; i < count; ++i) {
5774 		MonoIMTCheckItem *item = imt_entries [i];
5775 
5776 		if (!item->is_equals)
5777 			continue;
5778 
5779 		g_assert (item->key);
5780 
5781 		buf [(index * 2)] = item->key;
5782 		if (item->has_target_code) {
5783 			gpointer *p = (gpointer *)mono_domain_alloc (domain, sizeof (gpointer));
5784 			*p = item->value.target_code;
5785 			buf [(index * 2) + 1] = p;
5786 		} else {
5787 			buf [(index * 2) + 1] = &(vtable->vtable [item->value.vtable_slot]);
5788 		}
5789 		index ++;
5790 	}
5791 	buf [(index * 2)] = NULL;
5792 	buf [(index * 2) + 1] = fail_tramp;
5793 
5794 	if (USE_PAGE_TRAMPOLINES) {
5795 		code = get_new_imt_trampoline_from_page (buf);
5796 	} else {
5797 		code = get_numerous_trampoline (MONO_AOT_TRAMP_IMT, 1, &amodule, &got_offset, NULL);
5798 
5799 		amodule->got [got_offset] = buf;
5800 	}
5801 
5802 	return code;
5803 }
5804 
5805 gpointer
mono_aot_get_gsharedvt_arg_trampoline(gpointer arg,gpointer addr)5806 mono_aot_get_gsharedvt_arg_trampoline (gpointer arg, gpointer addr)
5807 {
5808 	MonoAotModule *amodule;
5809 	guint8 *code;
5810 	guint32 got_offset;
5811 
5812 	if (USE_PAGE_TRAMPOLINES) {
5813 		code = (guint8 *)get_new_gsharedvt_arg_trampoline_from_page (addr, arg);
5814 	} else {
5815 		code = (guint8 *)get_numerous_trampoline (MONO_AOT_TRAMP_GSHAREDVT_ARG, 2, &amodule, &got_offset, NULL);
5816 
5817 		amodule->got [got_offset] = arg;
5818 		amodule->got [got_offset + 1] = addr;
5819 	}
5820 
5821 	/* The caller expects an ftnptr */
5822 	return mono_create_ftnptr (mono_domain_get (), code);
5823 }
5824 
5825 /*
5826  * mono_aot_set_make_unreadable:
5827  *
5828  *   Set whenever to make all mmaped memory unreadable. In conjuction with a
5829  * SIGSEGV handler, this is useful to find out which pages the runtime tries to read.
5830  */
5831 void
mono_aot_set_make_unreadable(gboolean unreadable)5832 mono_aot_set_make_unreadable (gboolean unreadable)
5833 {
5834 	static int inited;
5835 
5836 	make_unreadable = unreadable;
5837 
5838 	if (make_unreadable && !inited) {
5839 		mono_counters_register ("AOT: pagefaults", MONO_COUNTER_JIT | MONO_COUNTER_INT, &n_pagefaults);
5840 	}
5841 }
5842 
5843 typedef struct {
5844 	MonoAotModule *module;
5845 	guint8 *ptr;
5846 } FindMapUserData;
5847 
5848 static void
find_map(gpointer key,gpointer value,gpointer user_data)5849 find_map (gpointer key, gpointer value, gpointer user_data)
5850 {
5851 	MonoAotModule *module = (MonoAotModule*)value;
5852 	FindMapUserData *data = (FindMapUserData*)user_data;
5853 
5854 	if (!data->module)
5855 		if ((data->ptr >= module->mem_begin) && (data->ptr < module->mem_end))
5856 			data->module = module;
5857 }
5858 
5859 static MonoAotModule*
find_module_for_addr(void * ptr)5860 find_module_for_addr (void *ptr)
5861 {
5862 	FindMapUserData data;
5863 
5864 	if (!make_unreadable)
5865 		return NULL;
5866 
5867 	data.module = NULL;
5868 	data.ptr = (guint8*)ptr;
5869 
5870 	mono_aot_lock ();
5871 	g_hash_table_foreach (aot_modules, (GHFunc)find_map, &data);
5872 	mono_aot_unlock ();
5873 
5874 	return data.module;
5875 }
5876 
5877 /*
5878  * mono_aot_is_pagefault:
5879  *
5880  *   Should be called from a SIGSEGV signal handler to find out whenever @ptr is
5881  * within memory allocated by this module.
5882  */
5883 gboolean
mono_aot_is_pagefault(void * ptr)5884 mono_aot_is_pagefault (void *ptr)
5885 {
5886 	if (!make_unreadable)
5887 		return FALSE;
5888 
5889 	/*
5890 	 * Not signal safe, but SIGSEGV's are synchronous, and
5891 	 * this is only turned on by a MONO_DEBUG option.
5892 	 */
5893 	return find_module_for_addr (ptr) != NULL;
5894 }
5895 
5896 /*
5897  * mono_aot_handle_pagefault:
5898  *
5899  *   Handle a pagefault caused by an unreadable page by making it readable again.
5900  */
5901 void
mono_aot_handle_pagefault(void * ptr)5902 mono_aot_handle_pagefault (void *ptr)
5903 {
5904 #ifndef HOST_WIN32
5905 	guint8* start = (guint8*)ROUND_DOWN (((gssize)ptr), mono_pagesize ());
5906 	int res;
5907 
5908 	mono_aot_lock ();
5909 	res = mono_mprotect (start, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
5910 	g_assert (res == 0);
5911 
5912 	n_pagefaults ++;
5913 	mono_aot_unlock ();
5914 #endif
5915 }
5916 
5917 #else
5918 /* AOT disabled */
5919 
5920 void
mono_aot_init(void)5921 mono_aot_init (void)
5922 {
5923 }
5924 
5925 void
mono_aot_cleanup(void)5926 mono_aot_cleanup (void)
5927 {
5928 }
5929 
5930 guint32
mono_aot_find_method_index(MonoMethod * method)5931 mono_aot_find_method_index (MonoMethod *method)
5932 {
5933 	g_assert_not_reached ();
5934 	return 0;
5935 }
5936 
5937 void
mono_aot_init_llvm_method(gpointer aot_module,guint32 method_index)5938 mono_aot_init_llvm_method (gpointer aot_module, guint32 method_index)
5939 {
5940 }
5941 
5942 void
mono_aot_init_gshared_method_this(gpointer aot_module,guint32 method_index,MonoObject * this)5943 mono_aot_init_gshared_method_this (gpointer aot_module, guint32 method_index, MonoObject *this)
5944 {
5945 }
5946 
5947 void
mono_aot_init_gshared_method_mrgctx(gpointer aot_module,guint32 method_index,MonoMethodRuntimeGenericContext * rgctx)5948 mono_aot_init_gshared_method_mrgctx (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx)
5949 {
5950 }
5951 
5952 void
mono_aot_init_gshared_method_vtable(gpointer aot_module,guint32 method_index,MonoVTable * vtable)5953 mono_aot_init_gshared_method_vtable (gpointer aot_module, guint32 method_index, MonoVTable *vtable)
5954 {
5955 }
5956 
5957 gpointer
mono_aot_get_method(MonoDomain * domain,MonoMethod * method)5958 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
5959 {
5960 	return NULL;
5961 }
5962 
5963 gpointer
mono_aot_get_method_checked(MonoDomain * domain,MonoMethod * method,MonoError * error)5964 mono_aot_get_method_checked (MonoDomain *domain,
5965 							 MonoMethod *method, MonoError *error)
5966 {
5967 	error_init (error);
5968 	return NULL;
5969 }
5970 
5971 gboolean
mono_aot_is_got_entry(guint8 * code,guint8 * addr)5972 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
5973 {
5974 	return FALSE;
5975 }
5976 
5977 gboolean
mono_aot_get_cached_class_info(MonoClass * klass,MonoCachedClassInfo * res)5978 mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
5979 {
5980 	return FALSE;
5981 }
5982 
5983 gboolean
mono_aot_get_class_from_name(MonoImage * image,const char * name_space,const char * name,MonoClass ** klass)5984 mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const char *name, MonoClass **klass)
5985 {
5986 	return FALSE;
5987 }
5988 
5989 MonoJitInfo *
mono_aot_find_jit_info(MonoDomain * domain,MonoImage * image,gpointer addr)5990 mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
5991 {
5992 	return NULL;
5993 }
5994 
5995 gpointer
mono_aot_get_method_from_token(MonoDomain * domain,MonoImage * image,guint32 token,MonoError * error)5996 mono_aot_get_method_from_token (MonoDomain *domain, MonoImage *image, guint32 token, MonoError *error)
5997 {
5998 	error_init (error);
5999 	return NULL;
6000 }
6001 
6002 guint8*
mono_aot_get_plt_entry(guint8 * code)6003 mono_aot_get_plt_entry (guint8 *code)
6004 {
6005 	return NULL;
6006 }
6007 
6008 gpointer
mono_aot_plt_resolve(gpointer aot_module,guint32 plt_info_offset,guint8 * code,MonoError * error)6009 mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code, MonoError *error)
6010 {
6011 	return NULL;
6012 }
6013 
6014 void
mono_aot_patch_plt_entry(guint8 * code,guint8 * plt_entry,gpointer * got,mgreg_t * regs,guint8 * addr)6015 mono_aot_patch_plt_entry (guint8 *code, guint8 *plt_entry, gpointer *got, mgreg_t *regs, guint8 *addr)
6016 {
6017 }
6018 
6019 gpointer
mono_aot_get_method_from_vt_slot(MonoDomain * domain,MonoVTable * vtable,int slot,MonoError * error)6020 mono_aot_get_method_from_vt_slot (MonoDomain *domain, MonoVTable *vtable, int slot, MonoError *error)
6021 {
6022 	error_init (error);
6023 
6024 	return NULL;
6025 }
6026 
6027 guint32
mono_aot_get_plt_info_offset(mgreg_t * regs,guint8 * code)6028 mono_aot_get_plt_info_offset (mgreg_t *regs, guint8 *code)
6029 {
6030 	g_assert_not_reached ();
6031 
6032 	return 0;
6033 }
6034 
6035 gpointer
mono_aot_create_specific_trampoline(MonoImage * image,gpointer arg1,MonoTrampolineType tramp_type,MonoDomain * domain,guint32 * code_len)6036 mono_aot_create_specific_trampoline (MonoImage *image, gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
6037 {
6038 	g_assert_not_reached ();
6039 	return NULL;
6040 }
6041 
6042 gpointer
mono_aot_get_static_rgctx_trampoline(gpointer ctx,gpointer addr)6043 mono_aot_get_static_rgctx_trampoline (gpointer ctx, gpointer addr)
6044 {
6045 	g_assert_not_reached ();
6046 	return NULL;
6047 }
6048 
6049 gpointer
mono_aot_get_trampoline_full(const char * name,MonoTrampInfo ** out_tinfo)6050 mono_aot_get_trampoline_full (const char *name, MonoTrampInfo **out_tinfo)
6051 {
6052 	g_assert_not_reached ();
6053 	return NULL;
6054 }
6055 
6056 gpointer
mono_aot_get_trampoline(const char * name)6057 mono_aot_get_trampoline (const char *name)
6058 {
6059 	g_assert_not_reached ();
6060 	return NULL;
6061 }
6062 
6063 gpointer
mono_aot_get_unbox_trampoline(MonoMethod * method)6064 mono_aot_get_unbox_trampoline (MonoMethod *method)
6065 {
6066 	g_assert_not_reached ();
6067 	return NULL;
6068 }
6069 
6070 gpointer
mono_aot_get_lazy_fetch_trampoline(guint32 slot)6071 mono_aot_get_lazy_fetch_trampoline (guint32 slot)
6072 {
6073 	g_assert_not_reached ();
6074 	return NULL;
6075 }
6076 
6077 gpointer
mono_aot_get_imt_trampoline(MonoVTable * vtable,MonoDomain * domain,MonoIMTCheckItem ** imt_entries,int count,gpointer fail_tramp)6078 mono_aot_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
6079 {
6080 	g_assert_not_reached ();
6081 	return NULL;
6082 }
6083 
6084 gpointer
mono_aot_get_gsharedvt_arg_trampoline(gpointer arg,gpointer addr)6085 mono_aot_get_gsharedvt_arg_trampoline (gpointer arg, gpointer addr)
6086 {
6087 	g_assert_not_reached ();
6088 	return NULL;
6089 }
6090 
6091 void
mono_aot_set_make_unreadable(gboolean unreadable)6092 mono_aot_set_make_unreadable (gboolean unreadable)
6093 {
6094 }
6095 
6096 gboolean
mono_aot_is_pagefault(void * ptr)6097 mono_aot_is_pagefault (void *ptr)
6098 {
6099 	return FALSE;
6100 }
6101 
6102 void
mono_aot_handle_pagefault(void * ptr)6103 mono_aot_handle_pagefault (void *ptr)
6104 {
6105 }
6106 
6107 guint8*
mono_aot_get_unwind_info(MonoJitInfo * ji,guint32 * unwind_info_len)6108 mono_aot_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len)
6109 {
6110 	g_assert_not_reached ();
6111 	return NULL;
6112 }
6113 
6114 void
mono_aot_register_jit_icall(const char * name,gpointer addr)6115 mono_aot_register_jit_icall (const char *name, gpointer addr)
6116 {
6117 }
6118 
6119 #endif
6120