summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accel/tcg/translate-all.c38
-rw-r--r--tcg/tcg.c4
2 files changed, 36 insertions, 6 deletions
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 39532fd44c..20b59f93f4 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -1722,6 +1722,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
tb->cflags = cflags;
tb->trace_vcpu_dstate = *cpu->trace_dstate;
tcg_ctx->tb_cflags = cflags;
+ tb_overflow:
#ifdef CONFIG_PROFILER
/* includes aborted translations because of exceptions */
@@ -1755,14 +1756,39 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
ti = profile_getclock();
#endif
- /* ??? Overflow could be handled better here. In particular, we
- don't need to re-do gen_intermediate_code, nor should we re-do
- the tcg optimization currently hidden inside tcg_gen_code. All
- that should be required is to flush the TBs, allocate a new TB,
- re-initialize it per above, and re-do the actual code generation. */
gen_code_size = tcg_gen_code(tcg_ctx, tb);
if (unlikely(gen_code_size < 0)) {
- goto buffer_overflow;
+ switch (gen_code_size) {
+ case -1:
+ /*
+ * Overflow of code_gen_buffer, or the current slice of it.
+ *
+ * TODO: We don't need to re-do gen_intermediate_code, nor
+ * should we re-do the tcg optimization currently hidden
+ * inside tcg_gen_code. All that should be required is to
+ * flush the TBs, allocate a new TB, re-initialize it per
+ * above, and re-do the actual code generation.
+ */
+ goto buffer_overflow;
+
+ case -2:
+ /*
+ * The code generated for the TranslationBlock is too large.
+ * The maximum size allowed by the unwind info is 64k.
+ * There may be stricter constraints from relocations
+ * in the tcg backend.
+ *
+ * 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;
+ goto tb_overflow;
+
+ default:
+ g_assert_not_reached();
+ }
}
search_size = encode_search(tb, (void *)gen_code_buf + gen_code_size);
if (unlikely(search_size < 0)) {
diff --git a/tcg/tcg.c b/tcg/tcg.c
index c0730f119f..5d255166c0 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -3996,6 +3996,10 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
return -1;
}
+ /* Test for TB overflow, as seen by gen_insn_end_off. */
+ if (unlikely(tcg_current_code_size(s) > UINT16_MAX)) {
+ return -2;
+ }
}
tcg_debug_assert(num_insns >= 0);
s->gen_insn_end_off[num_insns] = tcg_current_code_size(s);