PageRenderTime 73ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 1ms

/mono/mini/mini.c

https://bitbucket.org/danipen/mono
C | 7546 lines | 5653 code | 1106 blank | 787 comment | 1283 complexity | f31ed2aa6d9086644678b23f82b25e3f MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * mini.c: The new Mono code generator.
  3. *
  4. * Authors:
  5. * Paolo Molaro (lupus@ximian.com)
  6. * Dietmar Maurer (dietmar@ximian.com)
  7. *
  8. * Copyright 2002-2003 Ximian, Inc.
  9. * Copyright 2003-2010 Novell, Inc.
  10. * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
  11. */
  12. #define MONO_LLVM_IN_MINI 1
  13. #include <config.h>
  14. #include <signal.h>
  15. #ifdef HAVE_ALLOCA_H
  16. #include <alloca.h>
  17. #endif
  18. #ifdef HAVE_UNISTD_H
  19. #include <unistd.h>
  20. #endif
  21. #include <math.h>
  22. #ifdef HAVE_SYS_TIME_H
  23. #include <sys/time.h>
  24. #endif
  25. #include <mono/utils/memcheck.h>
  26. #include <mono/metadata/assembly.h>
  27. #include <mono/metadata/loader.h>
  28. #include <mono/metadata/tabledefs.h>
  29. #include <mono/metadata/class.h>
  30. #include <mono/metadata/object.h>
  31. #include <mono/metadata/tokentype.h>
  32. #include <mono/metadata/tabledefs.h>
  33. #include <mono/metadata/threads.h>
  34. #include <mono/metadata/appdomain.h>
  35. #include <mono/metadata/debug-helpers.h>
  36. #include <mono/io-layer/io-layer.h>
  37. #include "mono/metadata/profiler.h"
  38. #include <mono/metadata/profiler-private.h>
  39. #include <mono/metadata/mono-config.h>
  40. #include <mono/metadata/environment.h>
  41. #include <mono/metadata/mono-debug.h>
  42. #include <mono/metadata/gc-internal.h>
  43. #include <mono/metadata/threads-types.h>
  44. #include <mono/metadata/verify.h>
  45. #include <mono/metadata/verify-internals.h>
  46. #include <mono/metadata/mempool-internals.h>
  47. #include <mono/metadata/attach.h>
  48. #include <mono/metadata/runtime.h>
  49. #include <mono/utils/mono-math.h>
  50. #include <mono/utils/mono-compiler.h>
  51. #include <mono/utils/mono-counters.h>
  52. #include <mono/utils/mono-logger-internal.h>
  53. #include <mono/utils/mono-mmap.h>
  54. #include <mono/utils/mono-tls.h>
  55. #include <mono/utils/dtrace.h>
  56. #include "mini.h"
  57. #include "mini-llvm.h"
  58. #include "tasklets.h"
  59. #include <string.h>
  60. #include <ctype.h>
  61. #include "trace.h"
  62. #include "version.h"
  63. #include "jit-icalls.h"
  64. #include "debug-mini.h"
  65. #include "mini-gc.h"
  66. #include "debugger-agent.h"
  67. static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex);
  68. static guint32 default_opt = 0;
  69. static gboolean default_opt_set = FALSE;
  70. MonoNativeTlsKey mono_jit_tls_id;
  71. #ifdef MONO_HAVE_FAST_TLS
  72. MONO_FAST_TLS_DECLARE(mono_jit_tls);
  73. #endif
  74. #ifndef MONO_ARCH_MONITOR_ENTER_ADJUSTMENT
  75. #define MONO_ARCH_MONITOR_ENTER_ADJUSTMENT 1
  76. #endif
  77. MonoTraceSpec *mono_jit_trace_calls = NULL;
  78. gboolean mono_compile_aot = FALSE;
  79. /* If this is set, no code is generated dynamically, everything is taken from AOT files */
  80. gboolean mono_aot_only = FALSE;
  81. /* Whenever to use IMT */
  82. #ifdef MONO_ARCH_HAVE_IMT
  83. gboolean mono_use_imt = TRUE;
  84. #else
  85. gboolean mono_use_imt = FALSE;
  86. #endif
  87. MonoMethodDesc *mono_inject_async_exc_method = NULL;
  88. int mono_inject_async_exc_pos;
  89. MonoMethodDesc *mono_break_at_bb_method = NULL;
  90. int mono_break_at_bb_bb_num;
  91. gboolean mono_do_x86_stack_align = TRUE;
  92. const char *mono_build_date;
  93. gboolean mono_do_signal_chaining;
  94. static gboolean mono_using_xdebug;
  95. static int mini_verbose = 0;
  96. /*
  97. * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
  98. * it can load AOT code compiled by LLVM.
  99. */
  100. gboolean mono_use_llvm = FALSE;
  101. #define mono_jit_lock() EnterCriticalSection (&jit_mutex)
  102. #define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
  103. static CRITICAL_SECTION jit_mutex;
  104. static MonoCodeManager *global_codeman = NULL;
  105. static GHashTable *jit_icall_name_hash = NULL;
  106. static MonoDebugOptions debug_options;
  107. #ifdef VALGRIND_JIT_REGISTER_MAP
  108. static int valgrind_register = 0;
  109. #endif
  110. /*
  111. * Table written to by the debugger with a 1-based index into the
  112. * mono_breakpoint_info table, which contains changes made to
  113. * the JIT instructions by the debugger.
  114. */
  115. gssize
  116. mono_breakpoint_info_index [MONO_BREAKPOINT_ARRAY_SIZE];
  117. /* Whenever to check for pending exceptions in managed-to-native wrappers */
  118. gboolean check_for_pending_exc = TRUE;
  119. /* Whenever to disable passing/returning small valuetypes in registers for managed methods */
  120. gboolean disable_vtypes_in_regs = FALSE;
  121. gboolean mono_dont_free_global_codeman;
  122. gpointer
  123. mono_realloc_native_code (MonoCompile *cfg)
  124. {
  125. #if defined(__default_codegen__)
  126. return g_realloc (cfg->native_code, cfg->code_size);
  127. #elif defined(__native_client_codegen__)
  128. guint old_padding;
  129. gpointer native_code;
  130. guint alignment_check;
  131. /* Save the old alignment offset so we can re-align after the realloc. */
  132. old_padding = (guint)(cfg->native_code - cfg->native_code_alloc);
  133. cfg->native_code_alloc = g_realloc ( cfg->native_code_alloc,
  134. cfg->code_size + kNaClAlignment );
  135. /* Align native_code to next nearest kNaClAlignment byte. */
  136. native_code = (guint)cfg->native_code_alloc + kNaClAlignment;
  137. native_code = (guint)native_code & ~kNaClAlignmentMask;
  138. /* Shift the data to be 32-byte aligned again. */
  139. memmove (native_code, cfg->native_code_alloc + old_padding, cfg->code_size);
  140. alignment_check = (guint)native_code & kNaClAlignmentMask;
  141. g_assert (alignment_check == 0);
  142. return native_code;
  143. #else
  144. g_assert_not_reached ();
  145. return cfg->native_code;
  146. #endif
  147. }
  148. #ifdef __native_client_codegen__
  149. /* Prevent instructions from straddling a 32-byte alignment boundary. */
  150. /* Instructions longer than 32 bytes must be aligned internally. */
  151. /* IN: pcode, instlen */
  152. /* OUT: pcode */
  153. void mono_nacl_align_inst(guint8 **pcode, int instlen) {
  154. int space_in_block;
  155. space_in_block = kNaClAlignment - ((uintptr_t)(*pcode) & kNaClAlignmentMask);
  156. if (G_UNLIKELY (instlen >= kNaClAlignment)) {
  157. g_assert_not_reached();
  158. } else if (instlen > space_in_block) {
  159. *pcode = mono_arch_nacl_pad(*pcode, space_in_block);
  160. }
  161. }
  162. /* Move emitted call sequence to the end of a kNaClAlignment-byte block. */
  163. /* IN: start pointer to start of call sequence */
  164. /* IN: pcode pointer to end of call sequence (current "IP") */
  165. /* OUT: start pointer to the start of the call sequence after padding */
  166. /* OUT: pcode pointer to the end of the call sequence after padding */
  167. void mono_nacl_align_call(guint8 **start, guint8 **pcode) {
  168. const size_t MAX_NACL_CALL_LENGTH = kNaClAlignment;
  169. guint8 copy_of_call[MAX_NACL_CALL_LENGTH];
  170. guint8 *temp;
  171. const size_t length = (size_t)((*pcode)-(*start));
  172. g_assert(length < MAX_NACL_CALL_LENGTH);
  173. memcpy(copy_of_call, *start, length);
  174. temp = mono_nacl_pad_call(*start, (guint8)length);
  175. memcpy(temp, copy_of_call, length);
  176. (*start) = temp;
  177. (*pcode) = temp + length;
  178. }
  179. /* mono_nacl_pad_call(): Insert padding for Native Client call instructions */
  180. /* code pointer to buffer for emitting code */
  181. /* ilength length of call instruction */
  182. guint8 *mono_nacl_pad_call(guint8 *code, guint8 ilength) {
  183. int freeSpaceInBlock = kNaClAlignment - ((uintptr_t)code & kNaClAlignmentMask);
  184. int padding = freeSpaceInBlock - ilength;
  185. if (padding < 0) {
  186. /* There isn't enough space in this block for the instruction. */
  187. /* Fill this block and start a new one. */
  188. code = mono_arch_nacl_pad(code, freeSpaceInBlock);
  189. freeSpaceInBlock = kNaClAlignment;
  190. padding = freeSpaceInBlock - ilength;
  191. }
  192. g_assert(ilength > 0);
  193. g_assert(padding >= 0);
  194. g_assert(padding < kNaClAlignment);
  195. if (0 == padding) return code;
  196. return mono_arch_nacl_pad(code, padding);
  197. }
  198. guint8 *mono_nacl_align(guint8 *code) {
  199. int padding = kNaClAlignment - ((uintptr_t)code & kNaClAlignmentMask);
  200. if (padding != kNaClAlignment) code = mono_arch_nacl_pad(code, padding);
  201. return code;
  202. }
  203. void mono_nacl_fix_patches(const guint8 *code, MonoJumpInfo *ji)
  204. {
  205. MonoJumpInfo *patch_info;
  206. for (patch_info = ji; patch_info; patch_info = patch_info->next) {
  207. unsigned char *ip = patch_info->ip.i + code;
  208. ip = mono_arch_nacl_skip_nops(ip);
  209. patch_info->ip.i = ip - code;
  210. }
  211. }
  212. #endif /* __native_client_codegen__ */
  213. gboolean
  214. mono_running_on_valgrind (void)
  215. {
  216. if (RUNNING_ON_VALGRIND){
  217. #ifdef VALGRIND_JIT_REGISTER_MAP
  218. valgrind_register = TRUE;
  219. #endif
  220. return TRUE;
  221. } else
  222. return FALSE;
  223. }
  224. typedef struct {
  225. MonoExceptionClause *clause;
  226. MonoBasicBlock *basic_block;
  227. int start_offset;
  228. } TryBlockHole;
  229. typedef struct {
  230. void *ip;
  231. MonoMethod *method;
  232. } FindTrampUserData;
  233. static void
  234. find_tramp (gpointer key, gpointer value, gpointer user_data)
  235. {
  236. FindTrampUserData *ud = (FindTrampUserData*)user_data;
  237. if (value == ud->ip)
  238. ud->method = (MonoMethod*)key;
  239. }
  240. /* debug function */
  241. G_GNUC_UNUSED static char*
  242. get_method_from_ip (void *ip)
  243. {
  244. MonoJitInfo *ji;
  245. char *method;
  246. char *res;
  247. MonoDomain *domain = mono_domain_get ();
  248. MonoDebugSourceLocation *location;
  249. FindTrampUserData user_data;
  250. if (!domain)
  251. domain = mono_get_root_domain ();
  252. ji = mono_jit_info_table_find (domain, ip);
  253. if (!ji) {
  254. user_data.ip = ip;
  255. user_data.method = NULL;
  256. mono_domain_lock (domain);
  257. g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
  258. mono_domain_unlock (domain);
  259. if (user_data.method) {
  260. char *mname = mono_method_full_name (user_data.method, TRUE);
  261. res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
  262. g_free (mname);
  263. return res;
  264. }
  265. else
  266. return NULL;
  267. }
  268. method = mono_method_full_name (ji->method, TRUE);
  269. /* FIXME: unused ? */
  270. location = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
  271. res = g_strdup_printf (" %s + 0x%x (%p %p) [%p - %s]", method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
  272. mono_debug_free_source_location (location);
  273. g_free (method);
  274. return res;
  275. }
  276. /**
  277. * mono_pmip:
  278. * @ip: an instruction pointer address
  279. *
  280. * This method is used from a debugger to get the name of the
  281. * method at address @ip. This routine is typically invoked from
  282. * a debugger like this:
  283. *
  284. * (gdb) print mono_pmip ($pc)
  285. *
  286. * Returns: the name of the method at address @ip.
  287. */
  288. G_GNUC_UNUSED char *
  289. mono_pmip (void *ip)
  290. {
  291. return get_method_from_ip (ip);
  292. }
  293. /**
  294. * mono_print_method_from_ip
  295. * @ip: an instruction pointer address
  296. *
  297. * This method is used from a debugger to get the name of the
  298. * method at address @ip.
  299. *
  300. * This prints the name of the method at address @ip in the standard
  301. * output. Unlike mono_pmip which returns a string, this routine
  302. * prints the value on the standard output.
  303. */
  304. #ifdef __GNUC__
  305. /* Prevent the linker from optimizing this away in embedding setups to help debugging */
  306. __attribute__((used))
  307. #endif
  308. void
  309. mono_print_method_from_ip (void *ip)
  310. {
  311. MonoJitInfo *ji;
  312. char *method;
  313. MonoDebugSourceLocation *source;
  314. MonoDomain *domain = mono_domain_get ();
  315. MonoDomain *target_domain = mono_domain_get ();
  316. FindTrampUserData user_data;
  317. MonoGenericSharingContext*gsctx;
  318. const char *shared_type;
  319. ji = mini_jit_info_table_find (domain, ip, &target_domain);
  320. if (!ji) {
  321. user_data.ip = ip;
  322. user_data.method = NULL;
  323. mono_domain_lock (domain);
  324. g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
  325. mono_domain_unlock (domain);
  326. if (user_data.method) {
  327. char *mname = mono_method_full_name (user_data.method, TRUE);
  328. printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
  329. g_free (mname);
  330. }
  331. else
  332. g_print ("No method at %p\n", ip);
  333. fflush (stdout);
  334. return;
  335. }
  336. method = mono_method_full_name (ji->method, TRUE);
  337. source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain);
  338. gsctx = mono_jit_info_get_generic_sharing_context (ji);
  339. shared_type = "";
  340. if (gsctx) {
  341. if (gsctx->var_is_vt || gsctx->mvar_is_vt)
  342. shared_type = "gsharedvt ";
  343. else
  344. shared_type = "gshared ";
  345. }
  346. g_print ("IP %p at offset 0x%x of %smethod %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), shared_type, method, ji->code_start, (char*)ji->code_start + ji->code_size, target_domain, target_domain->friendly_name);
  347. if (source)
  348. g_print ("%s:%d\n", source->source_file, source->row);
  349. fflush (stdout);
  350. mono_debug_free_source_location (source);
  351. g_free (method);
  352. }
  353. /*
  354. * mono_method_same_domain:
  355. *
  356. * Determine whenever two compiled methods are in the same domain, thus
  357. * the address of the callee can be embedded in the caller.
  358. */
  359. gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee)
  360. {
  361. if (!caller || !callee)
  362. return FALSE;
  363. /*
  364. * If the call was made from domain-neutral to domain-specific
  365. * code, we can't patch the call site.
  366. */
  367. if (caller->domain_neutral && !callee->domain_neutral)
  368. return FALSE;
  369. if ((caller->method->klass == mono_defaults.appdomain_class) &&
  370. (strstr (caller->method->name, "InvokeInDomain"))) {
  371. /* The InvokeInDomain methods change the current appdomain */
  372. return FALSE;
  373. }
  374. return TRUE;
  375. }
  376. /*
  377. * mono_global_codeman_reserve:
  378. *
  379. * Allocate code memory from the global code manager.
  380. */
  381. void *mono_global_codeman_reserve (int size)
  382. {
  383. void *ptr;
  384. if (mono_aot_only)
  385. g_error ("Attempting to allocate from the global code manager while running with --aot-only.\n");
  386. if (!global_codeman) {
  387. /* This can happen during startup */
  388. global_codeman = mono_code_manager_new ();
  389. return mono_code_manager_reserve (global_codeman, size);
  390. }
  391. else {
  392. mono_jit_lock ();
  393. ptr = mono_code_manager_reserve (global_codeman, size);
  394. mono_jit_unlock ();
  395. return ptr;
  396. }
  397. }
  398. #if defined(__native_client_codegen__) && defined(__native_client__)
  399. /* Given the temporary buffer (allocated by mono_global_codeman_reserve) into
  400. * which we are generating code, return a pointer to the destination in the
  401. * dynamic code segment into which the code will be copied when
  402. * mono_global_codeman_commit is called.
  403. * LOCKING: Acquires the jit lock.
  404. */
  405. void*
  406. nacl_global_codeman_get_dest (void *data)
  407. {
  408. void *dest;
  409. mono_jit_lock ();
  410. dest = nacl_code_manager_get_code_dest (global_codeman, data);
  411. mono_jit_unlock ();
  412. return dest;
  413. }
  414. void
  415. mono_global_codeman_commit (void *data, int size, int newsize)
  416. {
  417. mono_jit_lock ();
  418. mono_code_manager_commit (global_codeman, data, size, newsize);
  419. mono_jit_unlock ();
  420. }
  421. /*
  422. * Convenience function which calls mono_global_codeman_commit to validate and
  423. * copy the code. The caller sets *buf_base and *buf_size to the start and size
  424. * of the buffer (allocated by mono_global_codeman_reserve), and *code_end to
  425. * the byte after the last instruction byte. On return, *buf_base will point to
  426. * the start of the copied in the code segment, and *code_end will point after
  427. * the end of the copied code.
  428. */
  429. void
  430. nacl_global_codeman_validate (guint8 **buf_base, int buf_size, guint8 **code_end)
  431. {
  432. guint8 *tmp = nacl_global_codeman_get_dest (*buf_base);
  433. mono_global_codeman_commit (*buf_base, buf_size, *code_end - *buf_base);
  434. *code_end = tmp + (*code_end - *buf_base);
  435. *buf_base = tmp;
  436. }
  437. #else
  438. /* no-op versions of Native Client functions */
  439. void*
  440. nacl_global_codeman_get_dest (void *data)
  441. {
  442. return data;
  443. }
  444. void
  445. mono_global_codeman_commit (void *data, int size, int newsize)
  446. {
  447. }
  448. void
  449. nacl_global_codeman_validate (guint8 **buf_base, int buf_size, guint8 **code_end)
  450. {
  451. }
  452. #endif /* __native_client__ */
  453. /**
  454. * mono_create_unwind_op:
  455. *
  456. * Create an unwind op with the given parameters.
  457. */
  458. MonoUnwindOp*
  459. mono_create_unwind_op (int when, int tag, int reg, int val)
  460. {
  461. MonoUnwindOp *op = g_new0 (MonoUnwindOp, 1);
  462. op->op = tag;
  463. op->reg = reg;
  464. op->val = val;
  465. op->when = when;
  466. return op;
  467. }
  468. /**
  469. * mono_emit_unwind_op:
  470. *
  471. * Add an unwind op with the given parameters for the list of unwind ops stored in
  472. * cfg->unwind_ops.
  473. */
  474. void
  475. mono_emit_unwind_op (MonoCompile *cfg, int when, int tag, int reg, int val)
  476. {
  477. MonoUnwindOp *op = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoUnwindOp));
  478. op->op = tag;
  479. op->reg = reg;
  480. op->val = val;
  481. op->when = when;
  482. cfg->unwind_ops = g_slist_append_mempool (cfg->mempool, cfg->unwind_ops, op);
  483. }
  484. MonoJumpInfoToken *
  485. mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
  486. {
  487. MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
  488. res->image = image;
  489. res->token = token;
  490. res->has_context = context != NULL;
  491. if (context)
  492. memcpy (&res->context, context, sizeof (MonoGenericContext));
  493. return res;
  494. }
  495. MonoJumpInfoToken *
  496. mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
  497. {
  498. return mono_jump_info_token_new2 (mp, image, token, NULL);
  499. }
  500. /*
  501. * mono_tramp_info_create:
  502. *
  503. * Create a MonoTrampInfo structure from the arguments. This function assumes ownership
  504. * of NAME, JI, and UNWIND_OPS.
  505. */
  506. MonoTrampInfo*
  507. mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
  508. {
  509. MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
  510. info->name = (char*)name;
  511. info->code = code;
  512. info->code_size = code_size;
  513. info->ji = ji;
  514. info->unwind_ops = unwind_ops;
  515. return info;
  516. }
  517. void
  518. mono_tramp_info_free (MonoTrampInfo *info)
  519. {
  520. GSList *l;
  521. g_free (info->name);
  522. // FIXME: ji
  523. for (l = info->unwind_ops; l; l = l->next)
  524. g_free (l->data);
  525. g_slist_free (info->unwind_ops);
  526. g_free (info);
  527. }
  528. G_GNUC_UNUSED static void
  529. break_count (void)
  530. {
  531. }
  532. /*
  533. * Runtime debugging tool, use if (debug_count ()) <x> else <y> to do <x> the first COUNT times, then do <y> afterwards.
  534. * Set a breakpoint in break_count () to break the last time <x> is done.
  535. */
  536. G_GNUC_UNUSED gboolean
  537. mono_debug_count (void)
  538. {
  539. static int count = 0;
  540. count ++;
  541. if (!getenv ("COUNT"))
  542. return TRUE;
  543. if (count == atoi (getenv ("COUNT"))) {
  544. break_count ();
  545. }
  546. if (count > atoi (getenv ("COUNT"))) {
  547. return FALSE;
  548. }
  549. return TRUE;
  550. }
  551. #define MONO_INIT_VARINFO(vi,id) do { \
  552. (vi)->range.first_use.pos.bid = 0xffff; \
  553. (vi)->reg = -1; \
  554. (vi)->idx = (id); \
  555. } while (0)
  556. /**
  557. * mono_unlink_bblock:
  558. *
  559. * Unlink two basic blocks.
  560. */
  561. void
  562. mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
  563. {
  564. int i, pos;
  565. gboolean found;
  566. found = FALSE;
  567. for (i = 0; i < from->out_count; ++i) {
  568. if (to == from->out_bb [i]) {
  569. found = TRUE;
  570. break;
  571. }
  572. }
  573. if (found) {
  574. pos = 0;
  575. for (i = 0; i < from->out_count; ++i) {
  576. if (from->out_bb [i] != to)
  577. from->out_bb [pos ++] = from->out_bb [i];
  578. }
  579. g_assert (pos == from->out_count - 1);
  580. from->out_count--;
  581. }
  582. found = FALSE;
  583. for (i = 0; i < to->in_count; ++i) {
  584. if (from == to->in_bb [i]) {
  585. found = TRUE;
  586. break;
  587. }
  588. }
  589. if (found) {
  590. pos = 0;
  591. for (i = 0; i < to->in_count; ++i) {
  592. if (to->in_bb [i] != from)
  593. to->in_bb [pos ++] = to->in_bb [i];
  594. }
  595. g_assert (pos == to->in_count - 1);
  596. to->in_count--;
  597. }
  598. }
  599. /*
  600. * mono_bblocks_linked:
  601. *
  602. * Return whenever BB1 and BB2 are linked in the CFG.
  603. */
  604. gboolean
  605. mono_bblocks_linked (MonoBasicBlock *bb1, MonoBasicBlock *bb2)
  606. {
  607. int i;
  608. for (i = 0; i < bb1->out_count; ++i) {
  609. if (bb1->out_bb [i] == bb2)
  610. return TRUE;
  611. }
  612. return FALSE;
  613. }
  614. static int
  615. mono_find_block_region_notry (MonoCompile *cfg, int offset)
  616. {
  617. MonoMethodHeader *header = cfg->header;
  618. MonoExceptionClause *clause;
  619. int i;
  620. for (i = 0; i < header->num_clauses; ++i) {
  621. clause = &header->clauses [i];
  622. if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
  623. (offset < (clause->handler_offset)))
  624. return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
  625. if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
  626. if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
  627. return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
  628. else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
  629. return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
  630. else
  631. return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
  632. }
  633. }
  634. return -1;
  635. }
  636. /*
  637. * mono_get_block_region_notry:
  638. *
  639. * Return the region corresponding to REGION, ignoring try clauses nested inside
  640. * finally clauses.
  641. */
  642. int
  643. mono_get_block_region_notry (MonoCompile *cfg, int region)
  644. {
  645. if ((region & (0xf << 4)) == MONO_REGION_TRY) {
  646. MonoMethodHeader *header = cfg->header;
  647. /*
  648. * This can happen if a try clause is nested inside a finally clause.
  649. */
  650. int clause_index = (region >> 8) - 1;
  651. g_assert (clause_index >= 0 && clause_index < header->num_clauses);
  652. region = mono_find_block_region_notry (cfg, header->clauses [clause_index].try_offset);
  653. }
  654. return region;
  655. }
  656. MonoInst *
  657. mono_find_spvar_for_region (MonoCompile *cfg, int region)
  658. {
  659. region = mono_get_block_region_notry (cfg, region);
  660. return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
  661. }
  662. static void
  663. df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
  664. {
  665. int i;
  666. array [*dfn] = start;
  667. /* g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num); */
  668. for (i = 0; i < start->out_count; ++i) {
  669. if (start->out_bb [i]->dfn)
  670. continue;
  671. (*dfn)++;
  672. start->out_bb [i]->dfn = *dfn;
  673. start->out_bb [i]->df_parent = start;
  674. array [*dfn] = start->out_bb [i];
  675. df_visit (start->out_bb [i], dfn, array);
  676. }
  677. }
  678. guint32
  679. mono_reverse_branch_op (guint32 opcode)
  680. {
  681. static const int reverse_map [] = {
  682. CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
  683. CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
  684. };
  685. static const int reverse_fmap [] = {
  686. OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
  687. OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
  688. };
  689. static const int reverse_lmap [] = {
  690. OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
  691. OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
  692. };
  693. static const int reverse_imap [] = {
  694. OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
  695. OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
  696. };
  697. if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) {
  698. opcode = reverse_map [opcode - CEE_BEQ];
  699. } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) {
  700. opcode = reverse_fmap [opcode - OP_FBEQ];
  701. } else if (opcode >= OP_LBEQ && opcode <= OP_LBLT_UN) {
  702. opcode = reverse_lmap [opcode - OP_LBEQ];
  703. } else if (opcode >= OP_IBEQ && opcode <= OP_IBLT_UN) {
  704. opcode = reverse_imap [opcode - OP_IBEQ];
  705. } else
  706. g_assert_not_reached ();
  707. return opcode;
  708. }
  709. guint
  710. mono_type_to_store_membase (MonoCompile *cfg, MonoType *type)
  711. {
  712. if (type->byref)
  713. return OP_STORE_MEMBASE_REG;
  714. handle_enum:
  715. switch (type->type) {
  716. case MONO_TYPE_I1:
  717. case MONO_TYPE_U1:
  718. case MONO_TYPE_BOOLEAN:
  719. return OP_STOREI1_MEMBASE_REG;
  720. case MONO_TYPE_I2:
  721. case MONO_TYPE_U2:
  722. case MONO_TYPE_CHAR:
  723. return OP_STOREI2_MEMBASE_REG;
  724. case MONO_TYPE_I4:
  725. case MONO_TYPE_U4:
  726. return OP_STOREI4_MEMBASE_REG;
  727. case MONO_TYPE_I:
  728. case MONO_TYPE_U:
  729. case MONO_TYPE_PTR:
  730. case MONO_TYPE_FNPTR:
  731. return OP_STORE_MEMBASE_REG;
  732. case MONO_TYPE_CLASS:
  733. case MONO_TYPE_STRING:
  734. case MONO_TYPE_OBJECT:
  735. case MONO_TYPE_SZARRAY:
  736. case MONO_TYPE_ARRAY:
  737. return OP_STORE_MEMBASE_REG;
  738. case MONO_TYPE_I8:
  739. case MONO_TYPE_U8:
  740. return OP_STOREI8_MEMBASE_REG;
  741. case MONO_TYPE_R4:
  742. return OP_STORER4_MEMBASE_REG;
  743. case MONO_TYPE_R8:
  744. return OP_STORER8_MEMBASE_REG;
  745. case MONO_TYPE_VALUETYPE:
  746. if (type->data.klass->enumtype) {
  747. type = mono_class_enum_basetype (type->data.klass);
  748. goto handle_enum;
  749. }
  750. if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
  751. return OP_STOREX_MEMBASE;
  752. return OP_STOREV_MEMBASE;
  753. case MONO_TYPE_TYPEDBYREF:
  754. return OP_STOREV_MEMBASE;
  755. case MONO_TYPE_GENERICINST:
  756. type = &type->data.generic_class->container_class->byval_arg;
  757. goto handle_enum;
  758. case MONO_TYPE_VAR:
  759. case MONO_TYPE_MVAR:
  760. if (mini_type_var_is_vt (cfg, type))
  761. return OP_STOREV_MEMBASE;
  762. else
  763. return OP_STORE_MEMBASE_REG;
  764. default:
  765. g_error ("unknown type 0x%02x in type_to_store_membase", type->type);
  766. }
  767. return -1;
  768. }
  769. guint
  770. mono_type_to_load_membase (MonoCompile *cfg, MonoType *type)
  771. {
  772. if (type->byref)
  773. return OP_LOAD_MEMBASE;
  774. type = mono_type_get_underlying_type (type);
  775. switch (type->type) {
  776. case MONO_TYPE_I1:
  777. return OP_LOADI1_MEMBASE;
  778. case MONO_TYPE_U1:
  779. case MONO_TYPE_BOOLEAN:
  780. return OP_LOADU1_MEMBASE;
  781. case MONO_TYPE_I2:
  782. return OP_LOADI2_MEMBASE;
  783. case MONO_TYPE_U2:
  784. case MONO_TYPE_CHAR:
  785. return OP_LOADU2_MEMBASE;
  786. case MONO_TYPE_I4:
  787. return OP_LOADI4_MEMBASE;
  788. case MONO_TYPE_U4:
  789. return OP_LOADU4_MEMBASE;
  790. case MONO_TYPE_I:
  791. case MONO_TYPE_U:
  792. case MONO_TYPE_PTR:
  793. case MONO_TYPE_FNPTR:
  794. return OP_LOAD_MEMBASE;
  795. case MONO_TYPE_CLASS:
  796. case MONO_TYPE_STRING:
  797. case MONO_TYPE_OBJECT:
  798. case MONO_TYPE_SZARRAY:
  799. case MONO_TYPE_ARRAY:
  800. return OP_LOAD_MEMBASE;
  801. case MONO_TYPE_I8:
  802. case MONO_TYPE_U8:
  803. return OP_LOADI8_MEMBASE;
  804. case MONO_TYPE_R4:
  805. return OP_LOADR4_MEMBASE;
  806. case MONO_TYPE_R8:
  807. return OP_LOADR8_MEMBASE;
  808. case MONO_TYPE_VALUETYPE:
  809. if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
  810. return OP_LOADX_MEMBASE;
  811. case MONO_TYPE_TYPEDBYREF:
  812. return OP_LOADV_MEMBASE;
  813. case MONO_TYPE_GENERICINST:
  814. if (mono_type_generic_inst_is_valuetype (type))
  815. return OP_LOADV_MEMBASE;
  816. else
  817. return OP_LOAD_MEMBASE;
  818. break;
  819. case MONO_TYPE_VAR:
  820. case MONO_TYPE_MVAR:
  821. g_assert (cfg->generic_sharing_context);
  822. if (mini_type_var_is_vt (cfg, type))
  823. return OP_LOADV_MEMBASE;
  824. else
  825. return OP_LOAD_MEMBASE;
  826. default:
  827. g_error ("unknown type 0x%02x in type_to_load_membase", type->type);
  828. }
  829. return -1;
  830. }
  831. static guint
  832. mini_type_to_ldind (MonoCompile* cfg, MonoType *type)
  833. {
  834. if (cfg->generic_sharing_context && !type->byref) {
  835. if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
  836. if (mini_type_var_is_vt (cfg, type))
  837. return CEE_LDOBJ;
  838. else
  839. return CEE_LDIND_REF;
  840. }
  841. }
  842. return mono_type_to_ldind (type);
  843. }
  844. #ifndef DISABLE_JIT
  845. guint
  846. mini_type_to_stind (MonoCompile* cfg, MonoType *type)
  847. {
  848. if (cfg->generic_sharing_context && !type->byref) {
  849. if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
  850. if (mini_type_var_is_vt (cfg, type))
  851. return CEE_STOBJ;
  852. else
  853. return CEE_STIND_REF;
  854. }
  855. }
  856. return mono_type_to_stind (type);
  857. }
  858. int
  859. mono_op_imm_to_op (int opcode)
  860. {
  861. switch (opcode) {
  862. case OP_ADD_IMM:
  863. #if SIZEOF_REGISTER == 4
  864. return OP_IADD;
  865. #else
  866. return OP_LADD;
  867. #endif
  868. case OP_IADD_IMM:
  869. return OP_IADD;
  870. case OP_LADD_IMM:
  871. return OP_LADD;
  872. case OP_ISUB_IMM:
  873. return OP_ISUB;
  874. case OP_LSUB_IMM:
  875. return OP_LSUB;
  876. case OP_IMUL_IMM:
  877. return OP_IMUL;
  878. case OP_AND_IMM:
  879. #if SIZEOF_REGISTER == 4
  880. return OP_IAND;
  881. #else
  882. return OP_LAND;
  883. #endif
  884. case OP_OR_IMM:
  885. #if SIZEOF_REGISTER == 4
  886. return OP_IOR;
  887. #else
  888. return OP_LOR;
  889. #endif
  890. case OP_XOR_IMM:
  891. #if SIZEOF_REGISTER == 4
  892. return OP_IXOR;
  893. #else
  894. return OP_LXOR;
  895. #endif
  896. case OP_IAND_IMM:
  897. return OP_IAND;
  898. case OP_LAND_IMM:
  899. return OP_LAND;
  900. case OP_IOR_IMM:
  901. return OP_IOR;
  902. case OP_LOR_IMM:
  903. return OP_LOR;
  904. case OP_IXOR_IMM:
  905. return OP_IXOR;
  906. case OP_LXOR_IMM:
  907. return OP_LXOR;
  908. case OP_ISHL_IMM:
  909. return OP_ISHL;
  910. case OP_LSHL_IMM:
  911. return OP_LSHL;
  912. case OP_ISHR_IMM:
  913. return OP_ISHR;
  914. case OP_LSHR_IMM:
  915. return OP_LSHR;
  916. case OP_ISHR_UN_IMM:
  917. return OP_ISHR_UN;
  918. case OP_LSHR_UN_IMM:
  919. return OP_LSHR_UN;
  920. case OP_IDIV_IMM:
  921. return OP_IDIV;
  922. case OP_IDIV_UN_IMM:
  923. return OP_IDIV_UN;
  924. case OP_IREM_UN_IMM:
  925. return OP_IREM_UN;
  926. case OP_IREM_IMM:
  927. return OP_IREM;
  928. case OP_DIV_IMM:
  929. #if SIZEOF_REGISTER == 4
  930. return OP_IDIV;
  931. #else
  932. return OP_LDIV;
  933. #endif
  934. case OP_REM_IMM:
  935. #if SIZEOF_REGISTER == 4
  936. return OP_IREM;
  937. #else
  938. return OP_LREM;
  939. #endif
  940. case OP_ADDCC_IMM:
  941. return OP_ADDCC;
  942. case OP_ADC_IMM:
  943. return OP_ADC;
  944. case OP_SUBCC_IMM:
  945. return OP_SUBCC;
  946. case OP_SBB_IMM:
  947. return OP_SBB;
  948. case OP_IADC_IMM:
  949. return OP_IADC;
  950. case OP_ISBB_IMM:
  951. return OP_ISBB;
  952. case OP_COMPARE_IMM:
  953. return OP_COMPARE;
  954. case OP_ICOMPARE_IMM:
  955. return OP_ICOMPARE;
  956. case OP_LOCALLOC_IMM:
  957. return OP_LOCALLOC;
  958. default:
  959. printf ("%s\n", mono_inst_name (opcode));
  960. g_assert_not_reached ();
  961. return -1;
  962. }
  963. }
  964. /*
  965. * mono_decompose_op_imm:
  966. *
  967. * Replace the OP_.._IMM INS with its non IMM variant.
  968. */
  969. void
  970. mono_decompose_op_imm (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
  971. {
  972. MonoInst *temp;
  973. MONO_INST_NEW (cfg, temp, OP_ICONST);
  974. temp->inst_c0 = ins->inst_imm;
  975. temp->dreg = mono_alloc_ireg (cfg);
  976. mono_bblock_insert_before_ins (bb, ins, temp);
  977. ins->opcode = mono_op_imm_to_op (ins->opcode);
  978. if (ins->opcode == OP_LOCALLOC)
  979. ins->sreg1 = temp->dreg;
  980. else
  981. ins->sreg2 = temp->dreg;
  982. bb->max_vreg = MAX (bb->max_vreg, cfg->next_vreg);
  983. }
  984. #endif
  985. static void
  986. set_vreg_to_inst (MonoCompile *cfg, int vreg, MonoInst *inst)
  987. {
  988. if (vreg >= cfg->vreg_to_inst_len) {
  989. MonoInst **tmp = cfg->vreg_to_inst;
  990. int size = cfg->vreg_to_inst_len;
  991. while (vreg >= cfg->vreg_to_inst_len)
  992. cfg->vreg_to_inst_len = cfg->vreg_to_inst_len ? cfg->vreg_to_inst_len * 2 : 32;
  993. cfg->vreg_to_inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * cfg->vreg_to_inst_len);
  994. if (size)
  995. memcpy (cfg->vreg_to_inst, tmp, size * sizeof (MonoInst*));
  996. }
  997. cfg->vreg_to_inst [vreg] = inst;
  998. }
  999. #define mono_type_is_long(type) (!(type)->byref && ((mono_type_get_underlying_type (type)->type == MONO_TYPE_I8) || (mono_type_get_underlying_type (type)->type == MONO_TYPE_U8)))
  1000. #define mono_type_is_float(type) (!(type)->byref && (((type)->type == MONO_TYPE_R8) || ((type)->type == MONO_TYPE_R4)))
  1001. #ifdef DISABLE_JIT
  1002. MonoInst*
  1003. mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
  1004. {
  1005. return NULL;
  1006. }
  1007. #else
  1008. MonoInst*
  1009. mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode, int vreg)
  1010. {
  1011. MonoInst *inst;
  1012. int num = cfg->num_varinfo;
  1013. gboolean regpair;
  1014. if ((num + 1) >= cfg->varinfo_count) {
  1015. int orig_count = cfg->varinfo_count;
  1016. cfg->varinfo_count = cfg->varinfo_count ? (cfg->varinfo_count * 2) : 64;
  1017. cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
  1018. cfg->vars = (MonoMethodVar *)g_realloc (cfg->vars, sizeof (MonoMethodVar) * cfg->varinfo_count);
  1019. memset (&cfg->vars [orig_count], 0, (cfg->varinfo_count - orig_count) * sizeof (MonoMethodVar));
  1020. }
  1021. cfg->stat_allocate_var++;
  1022. MONO_INST_NEW (cfg, inst, opcode);
  1023. inst->inst_c0 = num;
  1024. inst->inst_vtype = type;
  1025. inst->klass = mono_class_from_mono_type (type);
  1026. type_to_eval_stack_type (cfg, type, inst);
  1027. /* if set to 1 the variable is native */
  1028. inst->backend.is_pinvoke = 0;
  1029. inst->dreg = vreg;
  1030. if (inst->klass->exception_type)
  1031. mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
  1032. if (cfg->compute_gc_maps) {
  1033. if (type->byref) {
  1034. mono_mark_vreg_as_mp (cfg, vreg);
  1035. } else {
  1036. MonoType *t = mini_type_get_underlying_type (NULL, type);
  1037. if ((MONO_TYPE_ISSTRUCT (t) && inst->klass->has_references) || mini_type_is_reference (cfg, t)) {
  1038. inst->flags |= MONO_INST_GC_TRACK;
  1039. mono_mark_vreg_as_ref (cfg, vreg);
  1040. }
  1041. }
  1042. }
  1043. cfg->varinfo [num] = inst;
  1044. MONO_INIT_VARINFO (&cfg->vars [num], num);
  1045. MONO_VARINFO (cfg, num)->vreg = vreg;
  1046. if (vreg != -1)
  1047. set_vreg_to_inst (cfg, vreg, inst);
  1048. #if SIZEOF_REGISTER == 4
  1049. #ifdef MONO_ARCH_SOFT_FLOAT
  1050. regpair = mono_type_is_long (type) || mono_type_is_float (type);
  1051. #else
  1052. regpair = mono_type_is_long (type);
  1053. #endif
  1054. #else
  1055. regpair = FALSE;
  1056. #endif
  1057. if (regpair) {
  1058. MonoInst *tree;
  1059. /*
  1060. * These two cannot be allocated using create_var_for_vreg since that would
  1061. * put it into the cfg->varinfo array, confusing many parts of the JIT.
  1062. */
  1063. /*
  1064. * Set flags to VOLATILE so SSA skips it.
  1065. */
  1066. if (cfg->verbose_level >= 4) {
  1067. printf (" Create LVAR R%d (R%d, R%d)\n", inst->dreg, inst->dreg + 1, inst->dreg + 2);
  1068. }
  1069. #ifdef MONO_ARCH_SOFT_FLOAT
  1070. if (cfg->opt & MONO_OPT_SSA) {
  1071. if (mono_type_is_float (type))
  1072. inst->flags = MONO_INST_VOLATILE;
  1073. }
  1074. #endif
  1075. /* Allocate a dummy MonoInst for the first vreg */
  1076. MONO_INST_NEW (cfg, tree, OP_LOCAL);
  1077. tree->dreg = inst->dreg + 1;
  1078. if (cfg->opt & MONO_OPT_SSA)
  1079. tree->flags = MONO_INST_VOLATILE;
  1080. tree->inst_c0 = num;
  1081. tree->type = STACK_I4;
  1082. tree->inst_vtype = &mono_defaults.int32_class->byval_arg;
  1083. tree->klass = mono_class_from_mono_type (tree->inst_vtype);
  1084. set_vreg_to_inst (cfg, inst->dreg + 1, tree);
  1085. /* Allocate a dummy MonoInst for the second vreg */
  1086. MONO_INST_NEW (cfg, tree, OP_LOCAL);
  1087. tree->dreg = inst->dreg + 2;
  1088. if (cfg->opt & MONO_OPT_SSA)
  1089. tree->flags = MONO_INST_VOLATILE;
  1090. tree->inst_c0 = num;
  1091. tree->type = STACK_I4;
  1092. tree->inst_vtype = &mono_defaults.int32_class->byval_arg;
  1093. tree->klass = mono_class_from_mono_type (tree->inst_vtype);
  1094. set_vreg_to_inst (cfg, inst->dreg + 2, tree);
  1095. }
  1096. cfg->num_varinfo++;
  1097. if (cfg->verbose_level > 2)
  1098. g_print ("created temp %d (R%d) of type %s\n", num, vreg, mono_type_get_name (type));
  1099. return inst;
  1100. }
  1101. MonoInst*
  1102. mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
  1103. {
  1104. int dreg;
  1105. if (mono_type_is_long (type))
  1106. dreg = mono_alloc_dreg (cfg, STACK_I8);
  1107. #ifdef MONO_ARCH_SOFT_FLOAT
  1108. else if (mono_type_is_float (type))
  1109. dreg = mono_alloc_dreg (cfg, STACK_R8);
  1110. #endif
  1111. else
  1112. /* All the others are unified */
  1113. dreg = mono_alloc_preg (cfg);
  1114. return mono_compile_create_var_for_vreg (cfg, type, opcode, dreg);
  1115. }
  1116. /*
  1117. * Transform a MonoInst into a load from the variable of index var_index.
  1118. */
  1119. void
  1120. mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) {
  1121. memset (dest, 0, sizeof (MonoInst));
  1122. dest->inst_i0 = cfg->varinfo [var_index];
  1123. dest->opcode = mini_type_to_ldind (cfg, dest->inst_i0->inst_vtype);
  1124. type_to_eval_stack_type (cfg, dest->inst_i0->inst_vtype, dest);
  1125. dest->klass = dest->inst_i0->klass;
  1126. }
  1127. #endif
  1128. void
  1129. mono_mark_vreg_as_ref (MonoCompile *cfg, int vreg)
  1130. {
  1131. if (vreg >= cfg->vreg_is_ref_len) {
  1132. gboolean *tmp = cfg->vreg_is_ref;
  1133. int size = cfg->vreg_is_ref_len;
  1134. while (vreg >= cfg->vreg_is_ref_len)
  1135. cfg->vreg_is_ref_len = cfg->vreg_is_ref_len ? cfg->vreg_is_ref_len * 2 : 32;
  1136. cfg->vreg_is_ref = mono_mempool_alloc0 (cfg->mempool, sizeof (gboolean) * cfg->vreg_is_ref_len);
  1137. if (size)
  1138. memcpy (cfg->vreg_is_ref, tmp, size * sizeof (gboolean));
  1139. }
  1140. cfg->vreg_is_ref [vreg] = TRUE;
  1141. }
  1142. void
  1143. mono_mark_vreg_as_mp (MonoCompile *cfg, int vreg)
  1144. {
  1145. if (vreg >= cfg->vreg_is_mp_len) {
  1146. gboolean *tmp = cfg->vreg_is_mp;
  1147. int size = cfg->vreg_is_mp_len;
  1148. while (vreg >= cfg->vreg_is_mp_len)
  1149. cfg->vreg_is_mp_len = cfg->vreg_is_mp_len ? cfg->vreg_is_mp_len * 2 : 32;
  1150. cfg->vreg_is_mp = mono_mempool_alloc0 (cfg->mempool, sizeof (gboolean) * cfg->vreg_is_mp_len);
  1151. if (size)
  1152. memcpy (cfg->vreg_is_mp, tmp, size * sizeof (gboolean));
  1153. }
  1154. cfg->vreg_is_mp [vreg] = TRUE;
  1155. }
  1156. static MonoType*
  1157. type_from_stack_type (MonoInst *ins) {
  1158. switch (ins->type) {
  1159. case STACK_I4: return &mono_defaults.int32_class->byval_arg;
  1160. case STACK_I8: return &mono_defaults.int64_class->byval_arg;
  1161. case STACK_PTR: return &mono_defaults.int_class->byval_arg;
  1162. case STACK_R8: return &mono_defaults.double_class->byval_arg;
  1163. case STACK_MP:
  1164. /*
  1165. * this if used to be commented without any specific reason, but
  1166. * it breaks #80235 when commented
  1167. */
  1168. if (ins->klass)
  1169. return &ins->klass->this_arg;
  1170. else
  1171. return &mono_defaults.object_class->this_arg;
  1172. case STACK_OBJ:
  1173. /* ins->klass may not be set for ldnull.
  1174. * Also, if we have a boxed valuetype, we want an object lass,
  1175. * not the valuetype class
  1176. */
  1177. if (ins->klass && !ins->klass->valuetype)
  1178. return &ins->klass->byval_arg;
  1179. return &mono_defaults.object_class->byval_arg;
  1180. case STACK_VTYPE: return &ins->klass->byval_arg;
  1181. default:
  1182. g_error ("stack type %d to montype not handled\n", ins->type);
  1183. }
  1184. return NULL;
  1185. }
  1186. MonoType*
  1187. mono_type_from_stack_type (MonoInst *ins) {
  1188. return type_from_stack_type (ins);
  1189. }
  1190. /*
  1191. * mono_add_ins_to_end:
  1192. *
  1193. * Same as MONO_ADD_INS, but add INST before any branches at the end of BB.
  1194. */
  1195. void
  1196. mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
  1197. {
  1198. int opcode;
  1199. if (!bb->code) {
  1200. MONO_ADD_INS (bb, inst);
  1201. return;
  1202. }
  1203. switch (bb->last_ins->opcode) {
  1204. case OP_BR:
  1205. case OP_BR_REG:
  1206. case CEE_BEQ:
  1207. case CEE_BGE:
  1208. case CEE_BGT:
  1209. case CEE_BLE:
  1210. case CEE_BLT:
  1211. case CEE_BNE_UN:
  1212. case CEE_BGE_UN:
  1213. case CEE_BGT_UN:
  1214. case CEE_BLE_UN:
  1215. case CEE_BLT_UN:
  1216. case OP_SWITCH:
  1217. mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
  1218. break;
  1219. default:
  1220. if (MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
  1221. /* Need to insert the ins before the compare */
  1222. if (bb->code == bb->last_ins) {
  1223. mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
  1224. return;
  1225. }
  1226. if (bb->code->next == bb->last_ins) {
  1227. /* Only two instructions */
  1228. opcode = bb->code->opcode;
  1229. if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM)) {
  1230. /* NEW IR */
  1231. mono_bblock_insert_before_ins (bb, bb->code, inst);
  1232. } else {
  1233. mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
  1234. }
  1235. } else {
  1236. opcode = bb->last_ins->prev->opcode;
  1237. if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM)) {
  1238. /* NEW IR */
  1239. mono_bblock_insert_before_ins (bb, bb->last_ins->prev, inst);
  1240. } else {
  1241. mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
  1242. }
  1243. }
  1244. }
  1245. else
  1246. MONO_ADD_INS (bb, inst);
  1247. break;
  1248. }
  1249. }
  1250. void
  1251. mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
  1252. {
  1253. MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
  1254. MonoJumpInfoBBTable *table;
  1255. table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
  1256. table->table = bbs;
  1257. table->table_size = num_blocks;
  1258. ji->ip.label = label;
  1259. ji->type = MONO_PATCH_INFO_SWITCH;
  1260. ji->data.table = table;
  1261. ji->next = cfg->patch_info;
  1262. cfg->patch_info = ji;
  1263. }
  1264. static MonoMethodSignature *
  1265. mono_get_array_new_va_signature (int arity)
  1266. {
  1267. static GHashTable *sighash = NULL;
  1268. MonoMethodSignature *res;
  1269. int i;
  1270. mono_jit_lock ();
  1271. if (!sighash) {
  1272. sighash = g_hash_table_new (NULL, NULL);
  1273. }
  1274. else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
  1275. mono_jit_unlock ();
  1276. return res;
  1277. }
  1278. res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
  1279. res->pinvoke = 1;
  1280. #ifdef MONO_ARCH_VARARG_ICALLS
  1281. /* Only set this only some archs since not all backends can handle varargs+pinvoke */
  1282. res->call_convention = MONO_CALL_VARARG;
  1283. #endif
  1284. #ifdef TARGET_WIN32
  1285. res->call_convention = MONO_CALL_C;
  1286. #endif
  1287. res->params [0] = &mono_defaults.int_class->byval_arg;
  1288. for (i = 0; i < arity; i++)
  1289. res->params [i + 1] = &mono_defaults.int_class->byval_arg;
  1290. res->ret = &mono_defaults.object_class->byval_arg;
  1291. g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
  1292. mono_jit_unlock ();
  1293. return res;
  1294. }
  1295. MonoJitICallInfo *
  1296. mono_get_array_new_va_icall (int rank)
  1297. {
  1298. MonoMethodSignature *esig;
  1299. char icall_name [256];
  1300. char *name;
  1301. MonoJitICallInfo *info;
  1302. /* Need to register the icall so it gets an icall wrapper */
  1303. sprintf (icall_name, "ves_array_new_va_%d", rank);
  1304. mono_jit_lock ();
  1305. info = mono_find_jit_icall_by_name (icall_name);
  1306. if (info == NULL) {
  1307. esig = mono_get_array_new_va_signature (rank);
  1308. name = g_strdup (icall_name);
  1309. info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
  1310. g_hash_table_insert (jit_icall_name_hash, name, name);
  1311. }
  1312. mono_jit_unlock ();
  1313. return info;
  1314. }
  1315. gboolean
  1316. mini_class_is_system_array (MonoClass *klass)
  1317. {
  1318. if (klass->parent == mono_defaults.array_class)
  1319. return TRUE;
  1320. else
  1321. return FALSE;
  1322. }
  1323. gboolean
  1324. mini_assembly_can_skip_verification (MonoDomain *domain, MonoMethod *method)
  1325. {
  1326. MonoAssembly *assembly = method->klass->image->assembly;
  1327. if (method->wrapper_type != MONO_WRAPPER_NONE && method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
  1328. return FALSE;
  1329. if (assembly->in_gac || assembly->image == mono_defaults.corlib)
  1330. return FALSE;
  1331. if (mono_security_get_mode () != MONO_SECURITY_MODE_NONE)
  1332. return FALSE;
  1333. return mono_assembly_has_skip_verification (assembly);
  1334. }
  1335. /*
  1336. * mini_method_verify:
  1337. *
  1338. * Verify the method using the new verfier.
  1339. *
  1340. * Returns true if the method is invalid.
  1341. */
  1342. static gboolean
  1343. mini_method_verify (MonoCompile *cfg, MonoMethod *method, gboolean fail_compile)
  1344. {
  1345. GSList *tmp, *res;
  1346. gboolean is_fulltrust;
  1347. MonoLoaderError *error;
  1348. if (method->verification_success)
  1349. return FALSE;
  1350. if (!mono_verifier_is_enabled_for_method (method))
  1351. return FALSE;
  1352. /*skip verification implies the assembly must be */
  1353. is_fulltrust = mono_verifier_is_method_full_trust (method) || mini_assembly_can_skip_verification (cfg->domain, method);
  1354. res = mono_method_verify_with_current_settings (method, cfg->skip_visibility, is_fulltrust);
  1355. if ((error = mono_loader_get_last_error ())) {
  1356. if (fail_compile)
  1357. cfg->exception_type = error->exception_type;
  1358. else
  1359. mono_loader_clear_error ();
  1360. if (res)
  1361. mono_free_verify_list (res);
  1362. return TRUE;
  1363. }
  1364. if (res) {
  1365. for (tmp = res; tmp; tmp = tmp->next) {
  1366. MonoVerifyInfoExtended *info = (MonoVerifyInfoExtended *)tmp->data;
  1367. if (info->info.status == MONO_VERIFY_ERROR) {
  1368. if (fail_compile) {
  1369. char *method_name = mono_method_full_name (method, TRUE);
  1370. cfg->exception_type = info->exception_type;
  1371. cfg->exception_message = g_strdup_printf ("Error verifying %s: %s", method_name, info->info.message);
  1372. g_free (method_name);
  1373. }
  1374. mono_free_verify_list (res);
  1375. return TRUE;
  1376. }
  1377. if (info->info.status == MONO_VERIFY_NOT_VERIFIABLE && (!is_fulltrust || info->exception_type == MONO_EXCEPTION_METHOD_ACCESS || info->exception_type == MONO_EXCEPTION_FIELD_ACCESS)) {
  1378. if (fail_compile) {
  1379. char *method_name = mono_method_full_name (method, TRUE);
  1380. cfg->exception_type = info->exception_type;
  1381. cfg->exception_message = g_strdup_printf ("Error verifying %s: %s", method_name, info->info.message);
  1382. g_free (method_name);
  1383. }
  1384. mono_free_verify_list (res);
  1385. return TRUE;
  1386. }
  1387. }
  1388. mono_free_verify_list (res);
  1389. }
  1390. method->verification_success = 1;
  1391. return FALSE;
  1392. }
  1393. /*Returns true if something went wrong*/
  1394. gboolean
  1395. mono_compile_is_broken (MonoCompile *cfg, MonoMethod *method, gboolean fail_compile)
  1396. {
  1397. MonoMethod *method_definition = method;
  1398. gboolean dont_verify = method->klass->image->assembly->corlib_internal;
  1399. while (method_definition->is_inflated) {
  1400. MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
  1401. method_definition = imethod->declaring;
  1402. }
  1403. return !dont_verify && mini_method_verify (cfg, method_definition, fail_compile);
  1404. }
  1405. static gconstpointer
  1406. mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
  1407. {
  1408. char *name;
  1409. MonoMethod *wrapper;
  1410. gconstpointer trampoline;
  1411. MonoDomain *domain = mono_get_root_domain ();
  1412. if (callinfo->wrapper) {
  1413. return callinfo->wrapper;
  1414. }
  1415. if (callinfo->trampoline)
  1416. return callinfo->trampoline;
  1417. /*
  1418. * We use the lock on the root domain instead of the JIT lock to protect
  1419. * callinfo->trampoline, since we do a lot of stuff inside the critical section.
  1420. */
  1421. mono_loader_lock (); /*FIXME mono_compile_method requires the loader lock, by large.*/
  1422. mono_domain_lock (domain);
  1423. if (callinfo->trampoline) {
  1424. mono_domain_unlock (domain);
  1425. mono_loader_unlock ();
  1426. return callinfo->trampoline;
  1427. }
  1428. name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
  1429. wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_for_pending_exc);
  1430. g_free (name);
  1431. if (do_compile)
  1432. trampoline = mono_compile_method (wrapper);
  1433. else
  1434. trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
  1435. mono_register_jit_icall_wrapper (callinfo, trampoline);
  1436. callinfo->trampoline = trampoline;
  1437. mono_domain_unlock (domain);
  1438. mono_loader_unlock ();
  1439. return callinfo->trampoline;
  1440. }
  1441. gconstpointer
  1442. mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
  1443. {
  1444. return mono_icall_get_wrapper_full (callinfo, FALSE);
  1445. }
  1446. static void
  1447. mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
  1448. {
  1449. if (!domain_jit_info (domain)->dynamic_code_hash)
  1450. domain_jit_info (domain)->dynamic_code_hash = g_hash_table_new (NULL, NULL);
  1451. g_hash_table_insert (domain_jit_info (domain)->dynamic_code_hash, method, ji);
  1452. }
  1453. static MonoJitDynamicMethodInfo*
  1454. mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
  1455. {
  1456. MonoJitDynamicMethodInfo *res;
  1457. if (domain_jit_info (domain)->dynamic_code_hash)
  1458. res = g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
  1459. else
  1460. res = NULL;
  1461. return res;
  1462. }
  1463. typedef struct {
  1464. MonoClass *vtype;
  1465. GList *active, *inactive;
  1466. GSList *slots;
  1467. } StackSlotInfo;
  1468. static gint
  1469. compare_by_interval_start_pos_func (gconstpointer a, gconstpointer b)
  1470. {
  1471. MonoMethodVar *v1 = (MonoMethodVar*)a;
  1472. MonoMethodVar *v2 = (MonoMethodVar*)b;
  1473. if (v1 == v2)
  1474. return 0;
  1475. else if (v1->interval->range && v2->interval->range)
  1476. return v1->interval->range->from - v2->interval->range->from;
  1477. else if (v1->interval->range)
  1478. return -1;
  1479. else
  1480. return 1;
  1481. }
  1482. #ifndef DISABLE_JIT
  1483. #if 0
  1484. #define LSCAN_DEBUG(a) do { a; } while (0)
  1485. #else
  1486. #define LSCAN_DEBUG(a)
  1487. #endif
  1488. static gint32*
  1489. mono_allocate_stack_slots2 (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
  1490. {
  1491. int i, slot, offset, size;
  1492. guint32 align;
  1493. MonoMethodVar *vmv;
  1494. MonoInst *inst;
  1495. gint32 *offsets;
  1496. GList *vars = NULL, *l, *unhandled;
  1497. StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
  1498. MonoType *t;
  1499. int nvtypes;
  1500. gboolean reuse_slot;
  1501. LSCAN_DEBUG (printf ("Allocate Stack Slots 2 for %s:\n", mono_method_full_name (cfg->method, TRUE)));
  1502. scalar_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
  1503. vtype_stack_slots = NULL;
  1504. nvtypes = 0;
  1505. offsets = mono_mempool_alloc (cfg->mempool, sizeof (gint32) * cfg->num_varinfo);
  1506. for (i = 0; i < cfg->num_varinfo; ++i)
  1507. offsets [i] = -1;
  1508. for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
  1509. inst = cfg->varinfo [i];
  1510. vmv = MONO_VARINFO (cfg, i);
  1511. if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
  1512. continue;
  1513. vars = g_list_prepend (vars, vmv);
  1514. }
  1515. vars = g_list_sort (g_list_copy (vars), compare_by_interval_start_pos_func);
  1516. /* Sanity check */
  1517. /*
  1518. i = 0;
  1519. for (unhandled = vars; unhandled; unhandled = unhandled->next) {
  1520. MonoMethodVar *current = unhandled->data;
  1521. if (current->interval->range) {
  1522. g_assert (current->interval->range->from >= i);
  1523. i = current->interval->range->from;
  1524. }
  1525. }
  1526. */
  1527. offset = 0;
  1528. *stack_align = 0;
  1529. for (unhandled = vars; unhandled; unhandled = unhandled->next) {
  1530. MonoMethodVar *current = unhandled->data;
  1531. vmv = current;
  1532. inst = cfg->varinfo [vmv->idx];
  1533. t = mono_type_get_underlying_type (inst->inst_vtype);
  1534. if (cfg->gsharedvt && mini_is_gsharedvt_variable_type (cfg, t))
  1535. t = mini_get_gsharedvt_alloc_type_for_type (cfg, t);
  1536. /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
  1537. * pinvoke wrappers when they call functions returning structures */
  1538. if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (t) && t->type != MONO_TYPE_TYPEDBYREF) {
  1539. size = mono_class_native_size (mono_class_from_mono_type (t), &align);
  1540. }
  1541. else {
  1542. int ialign;
  1543. size = mono_type_size (t, &ialign);
  1544. align = ialign;
  1545. if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (t)))
  1546. align = 16;
  1547. }
  1548. reuse_slot = TRUE;
  1549. if (cfg->disable_reuse_stack_slots)
  1550. reuse_slot = FALSE;
  1551. switch (t->type) {
  1552. case MONO_TYPE_GENERICINST:
  1553. if (!mono_type_generic_inst_is_valuetype (t)) {
  1554. slot_info = &scalar_stack_slots [t->type];
  1555. break;
  1556. }
  1557. /* Fall through */
  1558. case MONO_TYPE_VALUETYPE:
  1559. if (!vtype_stack_slots)
  1560. vtype_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * 256);
  1561. for (i = 0; i < nvtypes; ++i)
  1562. if (t->data.klass == vtype_stack_slots [i].vtype)
  1563. break;
  1564. if (i < nvtypes)
  1565. slot_info = &vtype_stack_slots [i];
  1566. else {
  1567. g_assert (nvtypes < 256);
  1568. vtype_stack_slots [nvtypes].vtype = t->data.klass;
  1569. slot_info = &vtype_stack_slots [nvtypes];
  1570. nvtypes ++;
  1571. }
  1572. if (cfg->disable_reuse_ref_stack_slots)
  1573. reuse_slot = FALSE;
  1574. break;
  1575. case MONO_TYPE_PTR:
  1576. case MONO_TYPE_I:
  1577. case MONO_TYPE_U:
  1578. #if SIZEOF_VOID_P == 4
  1579. case MONO_TYPE_I4:
  1580. #else
  1581. case MONO_TYPE_I8:
  1582. #endif
  1583. if (cfg->disable_ref_noref_stack_slot_share) {
  1584. slot_info = &scalar_stack_slots [MONO_TYPE_I];
  1585. break;
  1586. }
  1587. /* Fall through */
  1588. case MONO_TYPE_CLASS:
  1589. case MONO_TYPE_OBJECT:
  1590. case MONO_TYPE_ARRAY:
  1591. case MONO_TYPE_SZARRAY:
  1592. case MONO_TYPE_STRING:
  1593. /* Share non-float stack slots of the same size */
  1594. slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
  1595. if (cfg->disable_reuse_ref_stack_slots)
  1596. reuse_slot = FALSE;
  1597. break;
  1598. default:
  1599. slot_info = &scalar_stack_slots [t->type];
  1600. }
  1601. slot = 0xffffff;
  1602. if (cfg->comp_done & MONO_COMP_LIVENESS) {
  1603. int pos;
  1604. gboolean changed;
  1605. //printf ("START %2d %08x %08x\n", vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
  1606. if (!current->interval->range) {
  1607. if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
  1608. pos = ~0;
  1609. else {
  1610. /* Dead */
  1611. inst->flags |= MONO_INST_IS_DEAD;
  1612. continue;
  1613. }
  1614. }
  1615. else
  1616. pos = current->interval->range->from;
  1617. LSCAN_DEBUG (printf ("process R%d ", inst->dreg));
  1618. if (current->interval->range)
  1619. LSCAN_DEBUG (mono_linterval_print (current->interval));
  1620. LSCAN_DEBUG (printf ("\n"));
  1621. /* Check for intervals in active which expired or inactive */
  1622. changed = TRUE;
  1623. /* FIXME: Optimize this */
  1624. while (changed) {
  1625. changed = FALSE;
  1626. for (l = slot_info->active; l != NULL; l = l->next) {
  1627. MonoMethodVar *v = (MonoMethodVar*)l->data;
  1628. if (v->interval->last_range->to < pos) {
  1629. slot_info->active = g_list_delete_link (slot_info->active, l);
  1630. slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [v->id

Large files files are truncated, but you can click here to view the full file