+/*
+ * is_jit_optimizer_disabled:
+ *
+ * Determine whenever M's assembly has a DebuggableAttribute with the
+ * IsJITOptimizerDisabled flag set.
+ */
+static gboolean
+is_jit_optimizer_disabled (MonoMethod *m)
+{
+ MonoAssembly *ass = m->klass->image->assembly;
+ MonoCustomAttrInfo* attrs;
+ static MonoClass *klass;
+ int i;
+ gboolean val = FALSE;
+
+ g_assert (ass);
+ if (ass->jit_optimizer_disabled_inited)
+ return ass->jit_optimizer_disabled;
+
+ if (!klass)
+ klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
+ if (!klass) {
+ /* Linked away */
+ ass->jit_optimizer_disabled = FALSE;
+ mono_memory_barrier ();
+ ass->jit_optimizer_disabled_inited = TRUE;
+ return FALSE;
+ }
+
+ attrs = mono_custom_attrs_from_assembly (ass);
+ if (attrs) {
+ for (i = 0; i < attrs->num_attrs; ++i) {
+ MonoCustomAttrEntry *attr = &attrs->attrs [i];
+ const gchar *p;
+ int len;
+ MonoMethodSignature *sig;
+
+ if (!attr->ctor || attr->ctor->klass != klass)
+ continue;
+ /* Decode the attribute. See reflection.c */
+ len = attr->data_size;
+ p = (const char*)attr->data;
+ g_assert (read16 (p) == 0x0001);
+ p += 2;
+
+ // FIXME: Support named parameters
+ sig = mono_method_signature (attr->ctor);
+ if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
+ continue;
+ /* Two boolean arguments */
+ p ++;
+ val = *p;
+ }
+ mono_custom_attrs_free (attrs);
+ }
+
+ ass->jit_optimizer_disabled = val;
+ mono_memory_barrier ();
+ ass->jit_optimizer_disabled_inited = TRUE;
+
+ return val;
+}
+
+static gboolean
+is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig)
+{
+ gboolean supported_tail_call;
+ int i;
+
+#ifdef MONO_ARCH_USE_OP_TAIL_CALL
+ supported_tail_call = MONO_ARCH_USE_OP_TAIL_CALL (mono_method_signature (method), mono_method_signature (cmethod));
+#else
+ supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
+#endif
+
+ for (i = 0; i < fsig->param_count; ++i) {
+ if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
+ /* These can point to the current method's stack */
+ supported_tail_call = FALSE;
+ }
+ if (fsig->hasthis && cmethod->klass->valuetype)
+ /* this might point to the current method's stack */
+ supported_tail_call = FALSE;
+ if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
+ supported_tail_call = FALSE;
+ if (cfg->method->save_lmf)
+ supported_tail_call = FALSE;
+ if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
+ supported_tail_call = FALSE;
+
+ /* Debugging support */
+#if 0
+ if (supported_tail_call) {
+ static int count = 0;
+ count ++;
+ if (getenv ("COUNT")) {
+ if (count == atoi (getenv ("COUNT")))
+ printf ("LAST: %s\n", mono_method_full_name (cmethod, TRUE));
+ if (count > atoi (getenv ("COUNT")))
+ supported_tail_call = FALSE;
+ }
+ }
+#endif
+
+ return supported_tail_call;
+}
+