mono_set_pending_exception (mono_get_exception_arithmetic ());
return d;
}
+
+void
+mono_llvmonly_set_calling_assembly (MonoImage *image)
+{
+ MonoJitTlsData *jit_tls = NULL;
+
+ jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+ g_assert (jit_tls);
+ jit_tls->calling_image = image;
+}
+
+MonoObject*
+mono_llvmonly_get_calling_assembly (void)
+{
+ MonoJitTlsData *jit_tls = NULL;
+
+ jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+ g_assert (jit_tls);
+ if (!jit_tls->calling_image)
+ mono_raise_exception (mono_get_exception_not_supported ("Stack walks are not supported on this platform."));
+ return (MonoObject*)mono_assembly_get_object (mono_domain_get (), jit_tls->calling_image->assembly);
+}
return FALSE;
}
+/* Return whenever METHOD calls Assembly.GetCallingAssembly () */
+// FIXME: It would be better to generalize this using some kind of method attribute
+// or automatic detection
+static gboolean
+method_needs_calling_assembly (MonoMethod *method)
+{
+ MonoClass *klass = method->klass;
+
+ if (klass->image != mono_defaults.corlib)
+ return FALSE;
+ if (!strcmp (klass->name_space, "System") && !strcmp (klass->name, "Activator") &&
+ !strcmp (method->name, "CreateInstance"))
+ return TRUE;
+ return FALSE;
+}
+
#define is_complex_isinst(klass) ((klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
static MonoInst*
ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
return ins;
}
+ if (cfg->llvm_only && !strcmp (cmethod->name, "GetCallingAssembly")) {
+ /* No stack walks are currently available, so implement this as an intrinsic */
+ ins = mono_emit_jit_icall (cfg, mono_llvmonly_get_calling_assembly, NULL);
+ return ins;
+ }
} else if (cmethod->klass == mono_defaults.math_class) {
/*
* There is general branchless code for Min/Max, but it does not work for
gboolean delegate_invoke = FALSE;
gboolean direct_icall = FALSE;
gboolean constrained_partial_call = FALSE;
+ gboolean needs_calling_assembly = FALSE;
MonoMethod *cil_method;
CHECK_OPSIZE (5);
}
}
+ /*
+ * Stack walks are not supported in llvmonly mode, so
+ * when calling methods which call GetCallingAssembly (), save the
+ * current assembly in the caller. The call to GetCallingAssembly ()
+ * will be turned into an icall which will retrieve the value.
+ */
+ if (cfg->llvm_only && cmethod && method_needs_calling_assembly (cmethod)) {
+ needs_calling_assembly = TRUE;
+
+ MonoInst *assembly_ins;
+
+ EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
+ ins = mono_emit_jit_icall (cfg, mono_llvmonly_set_calling_assembly, &assembly_ins);
+ }
+
mono_save_token_info (cfg, image, token, cil_method);
if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
}
+ if (needs_calling_assembly) {
+ /*
+ * Clear the calling assembly.
+ * This is not EH safe, but this is not a problem in practice, since
+ * the null value is only used for error checking.
+ */
+ MonoInst *assembly_ins;
+
+ EMIT_NEW_PCONST (cfg, assembly_ins, NULL);
+ ins = mono_emit_jit_icall (cfg, mono_llvmonly_set_calling_assembly, &assembly_ins);
+ }
+
CHECK_CFG_EXCEPTION;
ip += 5;
register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
+ register_icall_no_wrapper (mono_llvmonly_set_calling_assembly, "mono_llvmonly_set_calling_assembly", "void ptr");
+ register_icall_no_wrapper (mono_llvmonly_get_calling_assembly, "mono_llvmonly_get_calling_assembly", "object");
/* This needs a wrapper so it can have a preserveall cconv */
register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
register_icall (mono_init_delegate, "mono_init_delegate", "void object object ptr", TRUE);