MonoException * mono_get_exception_reflection_type_load_checked (MonoArray *types, MonoArray *exceptions, MonoError *error) { MonoClass *klass; gpointer args [2]; MonoObject *exc; MonoMethod *method; gpointer iter; klass = mono_class_load_from_name (mono_get_corlib (), "System.Reflection", "ReflectionTypeLoadException"); mono_class_init (klass); /* Find the Type[], Exception[] ctor */ iter = NULL; while ((method = mono_class_get_methods (klass, &iter))) { if (!strcmp (".ctor", mono_method_get_name (method))) { MonoMethodSignature *sig = mono_method_signature (method); if (sig->param_count == 2 && sig->params [0]->type == MONO_TYPE_SZARRAY && sig->params [1]->type == MONO_TYPE_SZARRAY) break; } method = NULL; } g_assert (method); args [0] = types; args [1] = exceptions; exc = mono_object_new_checked (mono_domain_get (), klass, error); mono_error_assert_ok (error); mono_runtime_invoke_checked (method, exc, args, error); return_val_if_nok (error, NULL); return (MonoException *) exc; }
/** * mono_get_exception_type_initialization: * @type_name: the name of the type that failed to initialize. * @inner: the inner exception. * * Returns: a new instance of the `System.TypeInitializationException` */ MonoException * mono_get_exception_type_initialization (const gchar *type_name, MonoException *inner) { MonoError error; MonoClass *klass; gpointer args [2]; MonoObject *exc; MonoMethod *method; gpointer iter; klass = mono_class_load_from_name (mono_get_corlib (), "System", "TypeInitializationException"); mono_class_init (klass); iter = NULL; while ((method = mono_class_get_methods (klass, &iter))) { if (!strcmp (".ctor", mono_method_get_name (method))) { MonoMethodSignature *sig = mono_method_signature (method); if (sig->param_count == 2 && sig->params [0]->type == MONO_TYPE_STRING && mono_class_from_mono_type (sig->params [1]) == mono_defaults.exception_class) break; } method = NULL; } g_assert (method); args [0] = mono_string_new (mono_domain_get (), type_name); args [1] = inner; exc = mono_object_new_checked (mono_domain_get (), klass, &error); mono_error_assert_ok (&error); mono_runtime_invoke_checked (method, exc, args, &error); mono_error_raise_exception (&error); /* FIXME don't raise here */ return (MonoException *) exc; }
void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base) { CRASH_COND(!CACHED_CLASS(GodotObject)->is_assignable_from(this)); if (methods_fetched) return; void *iter = NULL; MonoMethod *raw_method = NULL; while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != NULL) { StringName name = mono_method_get_name(raw_method); // get_method implicitly fetches methods and adds them to this->methods GDMonoMethod *method = get_method(raw_method, name); ERR_CONTINUE(!method); if (method->get_name() != name) { #ifdef DEBUG_ENABLED String fullname = method->get_ret_type_full_name() + " " + name + "(" + method->get_signature_desc(true) + ")"; WARN_PRINTS("Method `" + fullname + "` is hidden by Godot API method. Should be `" + method->get_full_name_no_class() + "`. In class `" + namespace_name + "." + class_name + "`."); #endif continue; } #ifdef DEBUG_ENABLED // For debug builds, we also fetched from native base classes as well before if this is not a native base class. // This allows us to warn the user here if he is using snake_case by mistake. if (p_native_base != this) { GDMonoClass *native_top = p_native_base; while (native_top) { GDMonoMethod *m = native_top->get_method(name, method->get_parameters_count()); if (m && m->get_name() != name) { // found String fullname = m->get_ret_type_full_name() + " " + name + "(" + m->get_signature_desc(true) + ")"; WARN_PRINTS("Method `" + fullname + "` should be `" + m->get_full_name_no_class() + "`. In class `" + namespace_name + "." + class_name + "`."); break; } if (native_top == CACHED_CLASS(GodotObject)) break; native_top = native_top->get_parent_class(); } } #endif uint32_t flags = mono_method_get_flags(method->mono_method, NULL); if (!(flags & MONO_METHOD_ATTR_VIRTUAL)) continue; // Virtual method of Godot Object derived type, let's try to find GodotMethod attribute GDMonoClass *top = p_native_base; while (top) { GDMonoMethod *base_method = top->get_method(name, method->get_parameters_count()); if (base_method && base_method->has_attribute(CACHED_CLASS(GodotMethodAttribute))) { // Found base method with GodotMethod attribute. // We get the original API method name from this attribute. // This name must point to the virtual method. MonoObject *attr = base_method->get_attribute(CACHED_CLASS(GodotMethodAttribute)); StringName godot_method_name = CACHED_FIELD(GodotMethodAttribute, methodName)->get_string_value(attr); #ifdef DEBUG_ENABLED CRASH_COND(godot_method_name == StringName()); #endif MethodKey key = MethodKey(godot_method_name, method->get_parameters_count()); GDMonoMethod **existing_method = methods.getptr(key); if (existing_method) memdelete(*existing_method); // Must delete old one methods.set(key, method); break; } if (top == CACHED_CLASS(GodotObject)) break; top = top->get_parent_class(); } } methods_fetched = true; }
void virt_mono_throw_unhandled_exception (MonoObject *exc) { caddr_t err; char *message = (char *) ""; const char *name = (const char *) ""; MonoString *str; MonoMethod *method; MonoClass *klass; gboolean free_message = FALSE; gint i; if (mono_object_isinst (exc, mono_get_exception_class ())) { klass = mono_object_get_class (exc); method = NULL; while (klass && method == NULL) { gpointer m_iter = NULL; for (method = mono_class_get_methods (klass, &m_iter); method != NULL; method = mono_class_get_methods (klass, &m_iter)) { MonoMethodSignature *sig = mono_method_signature (method); guint32 flags = 0; const char *name = mono_method_get_name (method); mono_method_get_flags (method, &flags); if (!strcmp ("ToString", name) && sig->param_count == 0 #ifdef OLD_KIT_1_1_5 && (flags & METHOD_ATTRIBUTE_VIRTUAL) && (flags & METHOD_ATTRIBUTE_PUBLIC) #endif ) { break; } method = NULL; } if (method == NULL) klass = mono_class_get_parent (klass); } g_assert (method); str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL); if (str) { message = mono_string_to_utf8 (str); free_message = TRUE; name = mono_class_get_name (klass); } } /* * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, * exc->vtable->klass->name, message); */ g_printerr ("\nUnhandled Exception: %s\n", message); err = srv_make_new_error ("42000", "MN001", "Unhandled Mono Exception [%.200s]: %.200s", name, message); if (free_message) g_free (message); sqlr_resignal (err); }
IMonoMethod *CScriptClass::GetMethod(const char *name, IMonoArray *pArgs, bool throwOnFail) { MonoMethodSignature *pSignature = nullptr; void *pIterator = 0; MonoClass *pClass = (MonoClass *)m_pObject; MonoType *pClassType = mono_class_get_type(pClass); MonoMethod *pCurMethod = nullptr; int suppliedArgsCount = pArgs ? pArgs->GetSize() : 0; while (pClass != nullptr) { pCurMethod = mono_class_get_methods(pClass, &pIterator); if(pCurMethod == nullptr) { pClass = mono_class_get_parent(pClass); if(pClass == mono_get_object_class()) break; pIterator = 0; continue; } pSignature = mono_method_signature(pCurMethod); int signatureParamCount = mono_signature_get_param_count(pSignature); bool bCorrectName = !strcmp(mono_method_get_name(pCurMethod), name); if(bCorrectName && signatureParamCount == 0 && suppliedArgsCount == 0) return new CScriptMethod(pCurMethod); else if(bCorrectName && signatureParamCount >= suppliedArgsCount && suppliedArgsCount != 0) { //if(bStatic != (mono_method_get_flags(pCurMethod, nullptr) & METHOD_ATTRIBUTE_STATIC) > 0) //continue; void *pIter = nullptr; MonoType *pType = nullptr; for(int i = 0; i < signatureParamCount; i++) { pType = mono_signature_get_params(pSignature, &pIter); if(mono::object item = pArgs->GetItem(i)) { MonoClass *pItemClass = mono_object_get_class((MonoObject *)item); MonoType *pItemType = mono_class_get_type(pItemClass); MonoTypeEnum itemMonoType = (MonoTypeEnum)mono_type_get_type(pItemType); MonoTypeEnum monoType = (MonoTypeEnum)mono_type_get_type(pType); if(itemMonoType != monoType) { // exceptions: // Anything can be treated as object. if(monoType == MONO_TYPE_OBJECT) {} // The runtime confuses things with value types a lot, so ignore parameters that appear with that type. else if(itemMonoType == MONO_TYPE_VALUETYPE || monoType == MONO_TYPE_VALUETYPE) {} else { if(MonoClass *pMethodParameterClass = mono_type_get_class(pType)) { MonoWarning("Parameter mismatch when searching for method %s in class %s.%s, on parameter %i: Provided type %s.%s does not match expected parameter type %s.%s.", name, mono_class_get_namespace(pClass), mono_class_get_name(pClass), i + 1, mono_class_get_namespace(pItemClass), mono_class_get_name(pItemClass), mono_class_get_namespace(pMethodParameterClass), mono_class_get_name(pMethodParameterClass)); } else { MonoWarning("Parameter mismatch when searching for method %s in class %s.%s, on parameter %i: Provided type %s.%s does not match parameter type.", name, mono_class_get_namespace(pClass), mono_class_get_name(pClass), i + 1, mono_class_get_namespace(pItemClass), mono_class_get_name(pItemClass)); } break; } } } if(i + 1 == suppliedArgsCount) return new CScriptMethod(pCurMethod); } } } if(throwOnFail) { if(IMonoException *pException = GetMonoScriptSystem()->GetCorlibAssembly()->GetException("System", "MissingMethodException", "Failed to locate method %s in class %s", name, GetName())) pException->Throw(); } return nullptr; }