From 5fb8ab10ebda8d85e7dc8cd25a50cb9b72d4efcf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 4 Mar 2021 15:37:02 -0500 Subject: [PATCH] tcg: Restart code generation when we run out of temps Some large translation blocks can generate so many unique constants that we run out of temps to hold them. In this case, longjmp back to the start of code generation and restart with a smaller translation block. Backports ae30e86661b0f48562cd95918d37cbeec5d0226 --- qemu/accel/tcg/translate-all.c | 15 ++++++++++++++- qemu/tcg/tcg.c | 11 ++++++++--- qemu/tcg/tcg.h | 3 +++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/qemu/accel/tcg/translate-all.c b/qemu/accel/tcg/translate-all.c index 82b8f80a..be4664fa 100644 --- a/qemu/accel/tcg/translate-all.c +++ b/qemu/accel/tcg/translate-all.c @@ -1372,11 +1372,17 @@ TranslationBlock *tb_gen_code(CPUState *cpu, ti = profile_getclock(); #endif + gen_code_size = sigsetjmp(tcg_ctx->jmp_trans, 0); + if (unlikely(gen_code_size != 0)) { + goto error_return; + } + tcg_func_start(tcg_ctx); tcg_ctx->cpu = env_cpu(env); gen_intermediate_code(cpu, tb, max_insns); tcg_ctx->cpu = NULL; + max_insns = tb->icount; // Unicorn: FIXME: Needs to be amended to work with new TCG #if 0 @@ -1413,6 +1419,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, gen_code_size = tcg_gen_code(tcg_ctx, tb); if (unlikely(gen_code_size < 0)) { + error_return: switch (gen_code_size) { case -1: /* @@ -1424,6 +1431,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu, * flush the TBs, allocate a new TB, re-initialize it per * above, and re-do the actual code generation. */ + qemu_log_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT, + "Restarting code generation for " + "code_gen_buffer overflow\n"); goto buffer_overflow; case -2: @@ -1436,9 +1446,12 @@ TranslationBlock *tb_gen_code(CPUState *cpu, * Try again with half as many insns as we attempted this time. * If a single insn overflows, there's a bug somewhere... */ - max_insns = tb->icount; assert(max_insns > 1); max_insns /= 2; + qemu_log_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT, + "Restarting code generation with " + "smaller translation block (max %d insns)\n", + max_insns); goto tb_overflow; default: diff --git a/qemu/tcg/tcg.c b/qemu/tcg/tcg.c index d6766e18..39aea3e7 100644 --- a/qemu/tcg/tcg.c +++ b/qemu/tcg/tcg.c @@ -543,18 +543,23 @@ void tcg_func_start(TCGContext *s) QSIMPLEQ_INIT(&s->labels); } -static inline TCGTemp *tcg_temp_alloc(TCGContext *s) +static TCGTemp *tcg_temp_alloc(TCGContext *s) { int n = s->nb_temps++; - tcg_debug_assert(n < TCG_MAX_TEMPS); + + if (n >= TCG_MAX_TEMPS) { + /* Signal overflow, starting over with fewer guest insns. */ + siglongjmp(s->jmp_trans, -2); + } return memset(&s->temps[n], 0, sizeof(TCGTemp)); } -static inline TCGTemp *tcg_global_alloc(TCGContext *s) +static TCGTemp *tcg_global_alloc(TCGContext *s) { TCGTemp *ts; tcg_debug_assert(s->nb_globals == s->nb_temps); + tcg_debug_assert(s->nb_globals < TCG_MAX_TEMPS); s->nb_globals++; ts = tcg_temp_alloc(s); ts->kind = TEMP_GLOBAL; diff --git a/qemu/tcg/tcg.h b/qemu/tcg/tcg.h index 5b22cc2c..24d4688e 100644 --- a/qemu/tcg/tcg.h +++ b/qemu/tcg/tcg.h @@ -755,6 +755,9 @@ struct TCGContext { uint16_t gen_insn_end_off[TCG_MAX_INSNS]; target_ulong gen_insn_data[TCG_MAX_INSNS][TARGET_INSN_START_WORDS]; + /* Exit to translator on overflow. */ + sigjmp_buf jmp_trans; + // Unicorn engine variables struct uc_struct *uc; /* qemu/target-i386/translate.c: global register indexes */