From 539d04e07c2dcd8087864f0ca66fdb0569a34e6a Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Sun, 5 Nov 2023 13:32:52 +0200 Subject: [PATCH] [mono][interp] When local space overflows, retry compilation with optimization enabled The unoptimized version of a method allocates all vars outside of the execution stack as global. Some operations, like `array[,].Set`, need to reorder values on the execution stack and they do this by allocating temporary vars. These vars would be logically dead after the operation, but since we don't do any optimization they occupy the stack space for the entire method execution. Patterns where thousands of such calls are inlined in a single method by code generators can be quite common, in EFCore for example. When the local space overflows, in addition to disabling inlining, we also try to compile with optimizations enabled. --- src/mono/mono/mini/interp/transform.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index e8b967827ddd1..136021722f5d4 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -11157,11 +11157,16 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoG td->seq_points = g_ptr_array_new (); td->verbose_level = mono_interp_traceopt; td->prof_coverage = mono_profiler_coverage_instrumentation_enabled (method); - td->disable_inlining = !rtm->optimized; - if (retry_compilation) + if (retry_compilation) { + // Optimizing the method can lead to deadce and better var offset allocation + // reducing the likelihood of local space overflow. + td->optimized = rtm->optimized = TRUE; td->disable_inlining = TRUE; + } else { + td->optimized = rtm->optimized; + td->disable_inlining = !td->optimized; + } rtm->data_items = td->data_items; - td->optimized = rtm->optimized; if (td->prof_coverage) td->coverage_info = mono_profiler_coverage_alloc (method, header->code_size); @@ -11221,7 +11226,7 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoG generate_compacted_code (rtm, td); if (td->total_locals_size >= G_MAXUINT16) { - if (td->disable_inlining) { + if (td->disable_inlining && td->optimized) { char *name = mono_method_get_full_name (method); char *msg = g_strdup_printf ("Unable to run method '%s': locals size too big.", name); g_free (name); @@ -11230,7 +11235,9 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoG retry_compilation = FALSE; goto exit; } else { - // We give the method another chance to compile with inlining disabled + // We give the method another chance to compile with inlining disabled and optimization enabled + if (td->verbose_level) + g_print ("Local space overflow. Retrying compilation\n"); retry_compilation = TRUE; goto exit; }