Skip to content

[mono][aot] Deferred failures code cleanup #86998

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions src/mono/mono/metadata/class-init.c
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,12 @@ mono_class_setup_fields (MonoClass *klass)
instance_size = MONO_ABI_SIZEOF (MonoObject);
}

if (m_class_is_inlinearray (klass) && m_class_inlinearray_value (klass) <= 0)
mono_class_set_deferred_type_load_failure_callback (klass, "Inline array length property must be positive.");
if (m_class_is_inlinearray (klass) && m_class_inlinearray_value (klass) <= 0) {
if (mono_get_runtime_callbacks ()->mono_class_set_deferred_type_load_failure_callback)
mono_get_runtime_callbacks ()->mono_class_set_deferred_type_load_failure_callback (klass, "Inline array length property must be positive.");
else
mono_class_set_type_load_failure (klass, "Inline array length property must be positive.");
}

/* Get the real size */
explicit_size = mono_metadata_packing_from_typedef (klass->image, klass->type_token, &packing_size, &real_size);
Expand Down Expand Up @@ -376,8 +380,15 @@ mono_class_setup_fields (MonoClass *klass)
break;
}
if (m_class_is_inlinearray (klass)) {
if (mono_class_set_deferred_type_load_failure_callback (klass, "Inline array struct must not have explicit layout."))
if (mono_get_runtime_callbacks ()->mono_class_set_deferred_type_load_failure_callback) {
if (mono_get_runtime_callbacks ()->mono_class_set_deferred_type_load_failure_callback (klass, "Inline array struct must not have explicit layout."))
break;
else
; // failure occured during AOT compilation, continue execution
} else {
mono_class_set_type_load_failure (klass, "Inline array struct must not have explicit layout.");
break;
}
}
}
if (mono_type_has_exceptions (field->type)) {
Expand Down Expand Up @@ -2281,10 +2292,15 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_
size *= m_class_inlinearray_value (klass);
inlined_fields++;
if(size == 0 || size > struct_max_size) {
if (mono_class_set_deferred_type_load_failure_callback (klass, "Inline array struct size out of bounds, abnormally large."))
if (mono_get_runtime_callbacks ()->mono_class_set_deferred_type_load_failure_callback) {
if (mono_get_runtime_callbacks ()->mono_class_set_deferred_type_load_failure_callback (klass, "Inline array struct size out of bounds, abnormally large."))
break;
else
size = initial_size; // failure occured during AOT compilation, continue execution
} else {
mono_class_set_type_load_failure (klass, "Inline array struct size out of bounds, abnormally large.");
break;
else
size = initial_size;
}
}
}

Expand Down Expand Up @@ -2314,8 +2330,12 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_
instance_size &= ~(min_align - 1);
}
}
if (m_class_is_inlinearray (klass) && inlined_fields != 1)
mono_class_set_deferred_type_load_failure_callback (klass, "Inline array struct must have a single field.");
if (m_class_is_inlinearray (klass) && inlined_fields != 1) {
if (mono_get_runtime_callbacks ()->mono_class_set_deferred_type_load_failure_callback)
mono_get_runtime_callbacks ()->mono_class_set_deferred_type_load_failure_callback (klass, "Inline array struct must have a single field.");
else
mono_class_set_type_load_failure (klass, "Inline array struct must have a single field.");
}
break;
case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: {
real_size = 0;
Expand Down
74 changes: 74 additions & 0 deletions src/mono/mono/metadata/class.c
Original file line number Diff line number Diff line change
Expand Up @@ -6886,3 +6886,77 @@ mono_class_has_default_constructor (MonoClass *klass, gboolean public_only)
}
return FALSE;
}

/**
* mono_class_set_deferred_type_load_failure:
* \param klass class in which the failure was detected
* \param fmt \c printf -style error message string.
*
* Sets a deferred failure in the class and prints a warning message.
* The deferred failure allows the runtime to attempt setting up the class layout at runtime.
*
* LOCKING: Acquires the loader lock.
*
* \returns FALSE
*/
gboolean
mono_class_set_deferred_type_load_failure (MonoClass *klass, const char * fmt, ...)
{
if (!mono_class_has_deferred_failure (klass)) {
va_list args;

va_start (args, fmt);
g_warning ("Warning: %s", fmt, args);
va_end (args);

mono_class_set_deferred_failure (klass);
}

return FALSE;
}

/**
* mono_class_set_type_load_failure:
* \param klass class in which the failure was detected
* \param fmt \c printf -style error message string.
*
* Collect detected failure informaion in the class for later processing.
* The error is stored as a MonoErrorBoxed as with mono_error_set_type_load_class()
* Note that only the first failure is kept.
*
* LOCKING: Acquires the loader lock.
*
* \returns TRUE
*/
gboolean
mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
{
if (!mono_class_has_failure (klass)) {
ERROR_DECL (prepare_error);
va_list args;

va_start (args, fmt);
mono_error_vset_type_load_class (prepare_error, klass, fmt, args);
va_end (args);

MonoErrorBoxed *box = mono_error_box (prepare_error, m_class_get_image (klass));
mono_error_cleanup (prepare_error);
mono_class_set_failure (klass, box);
}

return TRUE;
}

void mono_set_failure_type (MonoFailureType failure_type) {
switch (failure_type) {
case MONO_CLASS_LOADER_IMMEDIATE_FAILURE:
mono_get_runtime_callbacks ()->mono_class_set_deferred_type_load_failure_callback = mono_class_set_type_load_failure;
break;
case MONO_CLASS_LOADER_DEFERRED_FAILURE:
mono_get_runtime_callbacks ()->mono_class_set_deferred_type_load_failure_callback = mono_class_set_deferred_type_load_failure;
break;
default:
g_assert_not_reached();
break;
}
}
14 changes: 14 additions & 0 deletions src/mono/mono/metadata/metadata-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,11 @@ typedef struct {

#define MONO_SIZEOF_METHOD_SIGNATURE (sizeof (struct _MonoMethodSignature) - MONO_ZERO_LEN_ARRAY * SIZEOF_VOID_P)

typedef enum {
MONO_CLASS_LOADER_IMMEDIATE_FAILURE, // Used during runtime to indicate that the failure should be reported
MONO_CLASS_LOADER_DEFERRED_FAILURE // Used during AOT compilation to defer failure for execution
} MonoFailureType;

static inline gboolean
image_is_dynamic (MonoImage *image)
{
Expand Down Expand Up @@ -1257,4 +1262,13 @@ mono_metadata_table_to_ptr_table (int table_num)
uint32_t
mono_metadata_get_method_params (MonoImage *image, uint32_t method_idx, uint32_t *last_param_out);

void
mono_set_failure_type (MonoFailureType failure_type);

gboolean
mono_class_set_deferred_type_load_failure (MonoClass *klass, const char * fmt, ...);

gboolean
mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...);

#endif /* __MONO_METADATA_INTERNALS_H__ */
13 changes: 13 additions & 0 deletions src/mono/mono/metadata/object-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,19 @@ typedef struct {
gboolean (*get_class_from_name) (MonoImage *image, const char *name_space, const char *name, MonoClass **res);
gpointer (*build_imt_trampoline) (MonoVTable *vtable, MonoIMTCheckItem **imt_entries, int count, gpointer fail_trunk);
MonoJitInfo *(*find_jit_info_in_aot) (MonoImage *image, gpointer addr);
/**
* mono_class_set_deferred_type_load_failure_callback:
* @param klass: Class in which the failure was detected.
* @param fmt: printf-style error message string.
*
* The callback is responsible for processing the failure information provided by the @klass parameter and the error message format string @fmt.
* If a deferred failure occurs, the callback should return FALSE to let the AOT compiler proceed with the class layout setup.
* Otherwise, if the callback returns TRUE, it indicates that the failure should be reported.
*
* @returns: TRUE if the failure is handled and the runtime should not proceed with class setup, FALSE if the failure should be deferred for runtime class setup.
*
*/
gboolean (*mono_class_set_deferred_type_load_failure_callback) (MonoClass *klass, const char * fmt, ...) MONO_ATTR_FORMAT_PRINTF(2,3);
} MonoRuntimeCallbacks;

typedef gboolean (*MonoInternalStackWalk) (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data);
Expand Down
3 changes: 1 addition & 2 deletions src/mono/mono/mini/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -1400,7 +1400,7 @@ main_thread_handler (gpointer user_data)
MonoAssembly **assemblies;

assemblies = g_new0 (MonoAssembly*, main_args->argc);
set_failure_type (DEFERRED_FAILURE);
mono_set_failure_type (MONO_CLASS_LOADER_DEFERRED_FAILURE);
/* Treat the other arguments as assemblies to compile too */
for (i = 0; i < main_args->argc; ++i) {
assembly = mono_domain_assembly_open_internal (mono_alc_get_default (), main_args->argv [i]);
Expand Down Expand Up @@ -1428,7 +1428,6 @@ main_thread_handler (gpointer user_data)
return;
}

set_failure_type (IMMEDIATE_FAILURE);
assembly = mono_domain_assembly_open_internal (mono_alc_get_default (), main_args->file);
if (!assembly){
fprintf (stderr, "Can not open image %s\n", main_args->file);
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/mini/mini-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -4658,6 +4658,7 @@ mini_init (const char *filename)
callbacks.get_frame_info = mono_get_frame_info;
callbacks.get_cached_class_info = mono_aot_get_cached_class_info;
callbacks.get_class_from_name = mono_aot_get_class_from_name;
callbacks.mono_class_set_deferred_type_load_failure_callback = mono_class_set_type_load_failure;

if (mono_llvm_only) {
callbacks.build_imt_trampoline = mini_llvmonly_get_imt_trampoline;
Expand Down
30 changes: 0 additions & 30 deletions src/mono/mono/utils/mono-error-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,36 +319,6 @@ mono_error_set_specific (MonoError *error, int error_code, const char *missing_m
void
mono_error_set_first_argument (MonoError *oerror, const char *first_argument);

typedef enum {
DEFERRED_FAILURE, // Used during AOT compilation to defer failure for execution
IMMEDIATE_FAILURE // Used during runtime to indicate that the failure should be reported
} FailureType;

void
set_failure_type (FailureType failure_type);

/**
* TypeLoadFailureCallback:
* @param klass: Class in which the failure was detected.
* @param fmt: printf-style error message string.
*
* The callback is responsible for processing the failure information provided by the @klass parameter and the error message format string @fmt.
* If a deferred failure occurs, the callback should return FALSE to let the AOT compiler proceed with the class layout setup.
* Otherwise, if the callback returns TRUE, it indicates that the failure should be reported.
*
* @returns: TRUE if the failure is handled and the runtime should not proceed with class setup, FALSE if the failure should be deferred for runtime class setup.
*
*/
typedef gboolean (*TypeLoadFailureCallback)(MonoClass *klass, const char * fmt, ...) MONO_ATTR_FORMAT_PRINTF(2,3);

extern TypeLoadFailureCallback mono_class_set_deferred_type_load_failure_callback;

gboolean
mono_class_set_deferred_type_load_failure (MonoClass *klass, const char * fmt, ...);

gboolean
mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...);

#if HOST_WIN32
#if HOST_X86 || HOST_AMD64

Expand Down
72 changes: 0 additions & 72 deletions src/mono/mono/utils/mono-error.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@
va_end (args); \
} while (0)

TypeLoadFailureCallback mono_class_set_deferred_type_load_failure_callback = mono_class_set_type_load_failure;

static void
mono_error_set_generic_errorv (MonoError *oerror, const char *name_space, const char *name, const char *msg_format, va_list args);

Expand Down Expand Up @@ -910,73 +908,3 @@ mono_error_set_first_argument (MonoError *oerror, const char *first_argument)
to->first_argument = g_strdup (first_argument);
to->flags |= MONO_ERROR_FREE_STRINGS;
}

/**
* mono_class_set_deferred_type_load_failure:
* \param klass class in which the failure was detected
* \param fmt \c printf -style error message string.
*
* Sets a deferred failure in the class and prints a warning message.
* The deferred failure allows the runtime to attempt setting up the class layout at runtime.
*
* LOCKING: Acquires the loader lock.
*
* \returns FALSE
*/
gboolean
mono_class_set_deferred_type_load_failure (MonoClass *klass, const char * fmt, ...)
{
if (!mono_class_has_deferred_failure (klass)) {
va_list args;

va_start (args, fmt);
g_warning ("Warning: %s", fmt, args);
va_end (args);

mono_class_set_deferred_failure (klass);
}

return FALSE;
}

/**
* mono_class_set_type_load_failure:
* \param klass class in which the failure was detected
* \param fmt \c printf -style error message string.
*
* Collect detected failure informaion in the class for later processing.
* The error is stored as a MonoErrorBoxed as with mono_error_set_type_load_class()
* Note that only the first failure is kept.
*
* LOCKING: Acquires the loader lock.
*
* \returns TRUE
*/
gboolean
mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
{
if (!mono_class_has_failure (klass)) {
ERROR_DECL (prepare_error);
va_list args;

va_start (args, fmt);
mono_error_vset_type_load_class (prepare_error, klass, fmt, args);
va_end (args);

MonoErrorBoxed *box = mono_error_box (prepare_error, m_class_get_image (klass));
mono_error_cleanup (prepare_error);
mono_class_set_failure (klass, box);
}

return TRUE;
}

void set_failure_type(FailureType failure_type) {
if (failure_type == DEFERRED_FAILURE) {
mono_class_set_deferred_type_load_failure_callback = mono_class_set_deferred_type_load_failure;
} else if (failure_type == IMMEDIATE_FAILURE) {
mono_class_set_deferred_type_load_failure_callback = mono_class_set_type_load_failure;
} else {
g_assert_not_reached ();
}
}