1
Second pull for this week, since this set is large enough by itself.
1
Posting pre-PR because I had to adjust Emilio's QTree patch [1],
2
2
and added a new patch to avoid an assert that can be generated
3
with incorrect -R reserved_va values vs the ARM commpage.
3
4
4
r~
5
r~
5
6
7
[1] https://gitlab.com/rth7680/qemu/-/jobs/3975817279#L92
6
8
7
The following changes since commit 7c9236d6d61f30583d5d860097d88dbf0fe487bf:
9
Emilio Cota (2):
10
util: import GTree as QTree
11
tcg: use QTree instead of GTree
8
12
9
Merge tag 'pull-tcg-20230116' of https://gitlab.com/rth7680/qemu into staging (2023-01-17 10:24:16 +0000)
13
Richard Henderson (9):
14
linux-user: Diagnose misaligned -R size
15
include/exec: Change reserved_va semantics to last byte
16
accel/tcg: Pass last not end to page_set_flags
17
accel/tcg: Pass last not end to page_reset_target_data
18
accel/tcg: Pass last not end to PAGE_FOR_EACH_TB
19
accel/tcg: Pass last not end to page_collection_lock
20
accel/tcg: Pass last not end to tb_invalidate_phys_page_range__locked
21
accel/tcg: Pass last not end to tb_invalidate_phys_range
22
linux-user/arm: Take more care allocating commpage
10
23
11
are available in the Git repository at:
24
configure | 15 +
25
meson.build | 4 +
26
include/exec/cpu-all.h | 15 +-
27
include/exec/exec-all.h | 2 +-
28
include/qemu/qtree.h | 201 +++++
29
linux-user/arm/target_cpu.h | 2 +-
30
accel/tcg/tb-maint.c | 112 +--
31
accel/tcg/translate-all.c | 2 +-
32
accel/tcg/user-exec.c | 25 +-
33
bsd-user/main.c | 10 +-
34
bsd-user/mmap.c | 10 +-
35
linux-user/elfload.c | 67 +-
36
linux-user/main.c | 31 +-
37
linux-user/mmap.c | 22 +-
38
linux-user/syscall.c | 4 +-
39
softmmu/physmem.c | 2 +-
40
tcg/region.c | 19 +-
41
tests/bench/qtree-bench.c | 286 +++++++
42
tests/unit/test-qtree.c | 333 +++++++++
43
util/qtree.c | 1390 +++++++++++++++++++++++++++++++++++
44
tests/bench/meson.build | 4 +
45
tests/unit/meson.build | 1 +
46
util/meson.build | 1 +
47
23 files changed, 2412 insertions(+), 146 deletions(-)
48
create mode 100644 include/qemu/qtree.h
49
create mode 100644 tests/bench/qtree-bench.c
50
create mode 100644 tests/unit/test-qtree.c
51
create mode 100644 util/qtree.c
12
52
13
https://gitlab.com/rth7680/qemu.git tags/pull-tcg-20230117
53
--
14
54
2.34.1
15
for you to fetch changes up to 493c9b19a7fb7f387c4fcf57d3836504d5242bf5:
16
17
tcg/riscv: Implement direct branch for goto_tb (2023-01-17 22:36:17 +0000)
18
19
----------------------------------------------------------------
20
tcg: Fix race conditions in (most) goto_tb implementations
21
22
----------------------------------------------------------------
23
Richard Henderson (22):
24
tcg: Split out tcg_out_exit_tb
25
tcg/i386: Remove unused goto_tb code for indirect jump
26
tcg/ppc: Remove unused goto_tb code for indirect jump
27
tcg/sparc64: Remove unused goto_tb code for indirect jump
28
tcg: Replace asserts on tcg_jmp_insn_offset
29
tcg: Introduce set_jmp_insn_offset
30
tcg: Introduce get_jmp_target_addr
31
tcg: Split out tcg_out_goto_tb
32
tcg: Rename TB_JMP_RESET_OFFSET_INVALID to TB_JMP_OFFSET_INVALID
33
tcg: Add gen_tb to TCGContext
34
tcg: Add TranslationBlock.jmp_insn_offset
35
tcg: Change tb_target_set_jmp_target arguments
36
tcg: Move tb_target_set_jmp_target declaration to tcg.h
37
tcg: Always define tb_target_set_jmp_target
38
tcg: Remove TCG_TARGET_HAS_direct_jump
39
tcg/aarch64: Reorg goto_tb implementation
40
tcg/ppc: Reorg goto_tb implementation
41
tcg/sparc64: Remove USE_REG_TB
42
tcg/sparc64: Reorg goto_tb implementation
43
tcg/arm: Implement direct branch for goto_tb
44
tcg/riscv: Introduce OPC_NOP
45
tcg/riscv: Implement direct branch for goto_tb
46
47
include/exec/exec-all.h | 5 +-
48
include/tcg/tcg.h | 14 ++-
49
tcg/aarch64/tcg-target.h | 6 +-
50
tcg/arm/tcg-target.h | 5 -
51
tcg/i386/tcg-target.h | 9 --
52
tcg/loongarch64/tcg-target.h | 3 -
53
tcg/mips/tcg-target.h | 5 -
54
tcg/ppc/tcg-target.h | 7 +-
55
tcg/riscv/tcg-target.h | 4 -
56
tcg/s390x/tcg-target.h | 11 ---
57
tcg/sparc64/tcg-target.h | 4 -
58
tcg/tci/tcg-target.h | 4 -
59
accel/tcg/cpu-exec.c | 21 ++--
60
accel/tcg/translate-all.c | 10 +-
61
tcg/tcg-op.c | 14 +--
62
tcg/tcg.c | 42 +++++---
63
tcg/aarch64/tcg-target.c.inc | 106 ++++++++++-----------
64
tcg/arm/tcg-target.c.inc | 89 +++++++++++------
65
tcg/i386/tcg-target.c.inc | 68 +++++++------
66
tcg/loongarch64/tcg-target.c.inc | 66 +++++++------
67
tcg/mips/tcg-target.c.inc | 59 +++++++-----
68
tcg/ppc/tcg-target.c.inc | 193 ++++++++++++-------------------------
69
tcg/riscv/tcg-target.c.inc | 65 +++++++++----
70
tcg/s390x/tcg-target.c.inc | 67 ++++++++-----
71
tcg/sparc64/tcg-target.c.inc | 201 +++++++++++++++------------------------
72
tcg/tci/tcg-target.c.inc | 31 +++---
73
26 files changed, 528 insertions(+), 581 deletions(-)
diff view generated by jsdifflib
1
Now that tcg can handle direct and indirect goto_tb simultaneously,
1
From: Emilio Cota <cota@braap.org>
2
we can optimistically leave space for a direct branch and fall back
3
to loading the pointer from the TB for an indirect branch.
4
2
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
3
The only reason to add this implementation is to control the memory allocator
4
used. Some users (e.g. TCG) cannot work reliably in multi-threaded
5
environments (e.g. forking in user-mode) with GTree's allocator, GSlice.
6
See https://gitlab.com/qemu-project/qemu/-/issues/285 for details.
7
8
Importing GTree is a temporary workaround until GTree migrates away
9
from GSlice.
10
11
This implementation is identical to that in glib v2.75.0, except that
12
we don't import recent additions to the API nor deprecated API calls,
13
none of which are used in QEMU.
14
15
I've imported tests from glib and added a benchmark just to
16
make sure that performance is similar. Note: it cannot be identical
17
because (1) we are not using GSlice, (2) we use different compilation flags
18
(e.g. -fPIC) and (3) we're linking statically.
19
20
$ cat /proc/cpuinfo| grep 'model name' | head -1
21
model name : AMD Ryzen 7 PRO 5850U with Radeon Graphics
22
$ echo '0' | sudo tee /sys/devices/system/cpu/cpufreq/boost
23
$ tests/bench/qtree-bench
24
25
Tree Op 32 1024 4096 131072 1048576
26
------------------------------------------------------------------------------------------------
27
GTree Lookup 83.23 43.08 25.31 19.40 16.22
28
QTree Lookup 113.42 (1.36x) 53.83 (1.25x) 28.38 (1.12x) 17.64 (0.91x) 13.04 (0.80x)
29
GTree Insert 44.23 29.37 25.83 19.49 17.03
30
QTree Insert 46.87 (1.06x) 25.62 (0.87x) 24.29 (0.94x) 16.83 (0.86x) 12.97 (0.76x)
31
GTree Remove 53.27 35.15 31.43 24.64 16.70
32
QTree Remove 57.32 (1.08x) 41.76 (1.19x) 38.37 (1.22x) 29.30 (1.19x) 15.07 (0.90x)
33
GTree RemoveAll 135.44 127.52 126.72 120.11 64.34
34
QTree RemoveAll 127.15 (0.94x) 110.37 (0.87x) 107.97 (0.85x) 97.13 (0.81x) 55.10 (0.86x)
35
GTree Traverse 277.71 276.09 272.78 246.72 98.47
36
QTree Traverse 370.33 (1.33x) 411.97 (1.49x) 400.23 (1.47x) 262.82 (1.07x) 78.52 (0.80x)
37
------------------------------------------------------------------------------------------------
38
39
As a sanity check, the same benchmark when Glib's version
40
is >= $glib_dropped_gslice_version (i.e. QTree == GTree):
41
42
Tree Op 32 1024 4096 131072 1048576
43
------------------------------------------------------------------------------------------------
44
GTree Lookup 82.72 43.09 24.18 19.73 16.09
45
QTree Lookup 81.82 (0.99x) 43.10 (1.00x) 24.20 (1.00x) 19.76 (1.00x) 16.26 (1.01x)
46
GTree Insert 45.07 29.62 26.34 19.90 17.18
47
QTree Insert 45.72 (1.01x) 29.60 (1.00x) 26.38 (1.00x) 19.71 (0.99x) 17.20 (1.00x)
48
GTree Remove 54.48 35.36 31.77 24.97 16.95
49
QTree Remove 54.46 (1.00x) 35.32 (1.00x) 31.77 (1.00x) 24.91 (1.00x) 17.15 (1.01x)
50
GTree RemoveAll 140.68 127.36 125.43 121.45 68.20
51
QTree RemoveAll 140.65 (1.00x) 127.64 (1.00x) 125.01 (1.00x) 121.73 (1.00x) 67.06 (0.98x)
52
GTree Traverse 278.68 276.05 266.75 251.65 104.93
53
QTree Traverse 278.31 (1.00x) 275.78 (1.00x) 266.42 (1.00x) 247.89 (0.99x) 104.58 (1.00x)
54
------------------------------------------------------------------------------------------------
55
56
Signed-off-by: Emilio Cota <cota@braap.org>
57
Message-Id: <20230205163758.416992-2-cota@braap.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
58
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
---
59
---
8
tcg/riscv/tcg-target.c.inc | 19 +++++++++++++++++--
60
configure | 15 +
9
1 file changed, 17 insertions(+), 2 deletions(-)
61
meson.build | 4 +
62
include/qemu/qtree.h | 201 ++++++
63
tests/bench/qtree-bench.c | 286 ++++++++
64
tests/unit/test-qtree.c | 333 +++++++++
65
util/qtree.c | 1390 +++++++++++++++++++++++++++++++++++++
66
tests/bench/meson.build | 4 +
67
tests/unit/meson.build | 1 +
68
util/meson.build | 1 +
69
9 files changed, 2235 insertions(+)
70
create mode 100644 include/qemu/qtree.h
71
create mode 100644 tests/bench/qtree-bench.c
72
create mode 100644 tests/unit/test-qtree.c
73
create mode 100644 util/qtree.c
10
74
11
diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
75
diff --git a/configure b/configure
76
index XXXXXXX..XXXXXXX 100755
77
--- a/configure
78
+++ b/configure
79
@@ -XXX,XX +XXX,XX @@ safe_stack=""
80
use_containers="yes"
81
gdb_bin=$(command -v "gdb-multiarch" || command -v "gdb")
82
gdb_arches=""
83
+glib_has_gslice="no"
84
85
if test -e "$source_path/.git"
86
then
87
@@ -XXX,XX +XXX,XX @@ for i in $glib_modules; do
88
fi
89
done
90
91
+# Check whether glib has gslice, which we have to avoid for correctness.
92
+# TODO: remove this check and the corresponding workaround (qtree) when
93
+# the minimum supported glib is >= $glib_dropped_gslice_version.
94
+glib_dropped_gslice_version=2.75.3
95
+for i in $glib_modules; do
96
+ if ! $pkg_config --atleast-version=$glib_dropped_gslice_version $i; then
97
+ glib_has_gslice="yes"
98
+    break
99
+ fi
100
+done
101
+
102
glib_bindir="$($pkg_config --variable=bindir glib-2.0)"
103
if test -z "$glib_bindir" ; then
104
    glib_bindir="$($pkg_config --variable=prefix glib-2.0)"/bin
105
@@ -XXX,XX +XXX,XX @@ echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
106
echo "GLIB_LIBS=$glib_libs" >> $config_host_mak
107
echo "GLIB_BINDIR=$glib_bindir" >> $config_host_mak
108
echo "GLIB_VERSION=$($pkg_config --modversion glib-2.0)" >> $config_host_mak
109
+if test "$glib_has_gslice" = "yes" ; then
110
+ echo "HAVE_GLIB_WITH_SLICE_ALLOCATOR=y" >> $config_host_mak
111
+fi
112
echo "QEMU_LDFLAGS=$QEMU_LDFLAGS" >> $config_host_mak
113
echo "EXESUF=$EXESUF" >> $config_host_mak
114
115
diff --git a/meson.build b/meson.build
12
index XXXXXXX..XXXXXXX 100644
116
index XXXXXXX..XXXXXXX 100644
13
--- a/tcg/riscv/tcg-target.c.inc
117
--- a/meson.build
14
+++ b/tcg/riscv/tcg-target.c.inc
118
+++ b/meson.build
15
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
119
@@ -XXX,XX +XXX,XX @@ glib = declare_dependency(compile_args: config_host['GLIB_CFLAGS'].split(),
16
120
})
17
static void tcg_out_goto_tb(TCGContext *s, int which)
121
# override glib dep with the configure results (for subprojects)
18
{
122
meson.override_dependency('glib-2.0', glib)
19
- /* indirect jump method */
123
+# pass down whether Glib has the slice allocator
20
+ /* Direct branch will be patched by tb_target_set_jmp_target. */
124
+if config_host.has_key('HAVE_GLIB_WITH_SLICE_ALLOCATOR')
21
+ set_jmp_insn_offset(s, which);
125
+ config_host_data.set('HAVE_GLIB_WITH_SLICE_ALLOCATOR', true)
22
+ tcg_out32(s, OPC_JAL);
126
+endif
23
+
127
24
+ /* When branch is out of range, fall through to indirect. */
128
gio = not_found
25
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO,
129
gdbus_codegen = not_found
26
get_jmp_target_addr(s, which));
130
diff --git a/include/qemu/qtree.h b/include/qemu/qtree.h
27
tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, TCG_REG_TMP0, 0);
131
new file mode 100644
28
@@ -XXX,XX +XXX,XX @@ static void tcg_out_goto_tb(TCGContext *s, int which)
132
index XXXXXXX..XXXXXXX
29
void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
133
--- /dev/null
30
uintptr_t jmp_rx, uintptr_t jmp_rw)
134
+++ b/include/qemu/qtree.h
31
{
135
@@ -XXX,XX +XXX,XX @@
32
- /* Always indirect, nothing to do */
136
+/*
33
+ uintptr_t addr = tb->jmp_target_addr[n];
137
+ * GLIB - Library of useful routines for C programming
34
+ ptrdiff_t offset = addr - jmp_rx;
138
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
35
+ tcg_insn_unit insn;
139
+ *
36
+
140
+ * SPDX-License-Identifier: LGPL-2.1-or-later
37
+ /* Either directly branch, or fall through to indirect branch. */
141
+ *
38
+ if (offset == sextreg(offset, 0, 20)) {
142
+ * This library is free software; you can redistribute it and/or
39
+ insn = encode_uj(OPC_JAL, TCG_REG_ZERO, offset);
143
+ * modify it under the terms of the GNU Lesser General Public
144
+ * License as published by the Free Software Foundation; either
145
+ * version 2.1 of the License, or (at your option) any later version.
146
+ *
147
+ * This library is distributed in the hope that it will be useful,
148
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
149
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
150
+ * Lesser General Public License for more details.
151
+ *
152
+ * You should have received a copy of the GNU Lesser General Public
153
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
154
+ */
155
+
156
+/*
157
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
158
+ * file for a list of people on the GLib Team. See the ChangeLog
159
+ * files for a list of changes. These files are distributed with
160
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
161
+ */
162
+
163
+/*
164
+ * QTree is a partial import of Glib's GTree. The parts excluded correspond
165
+ * to API calls either deprecated (e.g. g_tree_traverse) or recently added
166
+ * (e.g. g_tree_search_node, added in 2.68); neither have callers in QEMU.
167
+ *
168
+ * The reason for this import is to allow us to control the memory allocator
169
+ * used by the tree implementation. Until Glib 2.75.3, GTree uses Glib's
170
+ * slice allocator, which causes problems when forking in user-mode;
171
+ * see https://gitlab.com/qemu-project/qemu/-/issues/285 and glib's
172
+ * "45b5a6c1e gslice: Remove slice allocator and use malloc() instead".
173
+ *
174
+ * TODO: remove QTree when QEMU's minimum Glib version is >= 2.75.3.
175
+ */
176
+
177
+#ifndef QEMU_QTREE_H
178
+#define QEMU_QTREE_H
179
+
180
+#include "qemu/osdep.h"
181
+
182
+#ifdef HAVE_GLIB_WITH_SLICE_ALLOCATOR
183
+
184
+typedef struct _QTree QTree;
185
+
186
+typedef struct _QTreeNode QTreeNode;
187
+
188
+typedef gboolean (*QTraverseNodeFunc)(QTreeNode *node,
189
+ gpointer user_data);
190
+
191
+/*
192
+ * Balanced binary trees
193
+ */
194
+QTree *q_tree_new(GCompareFunc key_compare_func);
195
+QTree *q_tree_new_with_data(GCompareDataFunc key_compare_func,
196
+ gpointer key_compare_data);
197
+QTree *q_tree_new_full(GCompareDataFunc key_compare_func,
198
+ gpointer key_compare_data,
199
+ GDestroyNotify key_destroy_func,
200
+ GDestroyNotify value_destroy_func);
201
+QTree *q_tree_ref(QTree *tree);
202
+void q_tree_unref(QTree *tree);
203
+void q_tree_destroy(QTree *tree);
204
+void q_tree_insert(QTree *tree,
205
+ gpointer key,
206
+ gpointer value);
207
+void q_tree_replace(QTree *tree,
208
+ gpointer key,
209
+ gpointer value);
210
+gboolean q_tree_remove(QTree *tree,
211
+ gconstpointer key);
212
+gboolean q_tree_steal(QTree *tree,
213
+ gconstpointer key);
214
+gpointer q_tree_lookup(QTree *tree,
215
+ gconstpointer key);
216
+gboolean q_tree_lookup_extended(QTree *tree,
217
+ gconstpointer lookup_key,
218
+ gpointer *orig_key,
219
+ gpointer *value);
220
+void q_tree_foreach(QTree *tree,
221
+ GTraverseFunc func,
222
+ gpointer user_data);
223
+gpointer q_tree_search(QTree *tree,
224
+ GCompareFunc search_func,
225
+ gconstpointer user_data);
226
+gint q_tree_height(QTree *tree);
227
+gint q_tree_nnodes(QTree *tree);
228
+
229
+#else /* !HAVE_GLIB_WITH_SLICE_ALLOCATOR */
230
+
231
+typedef GTree QTree;
232
+typedef GTreeNode QTreeNode;
233
+typedef GTraverseNodeFunc QTraverseNodeFunc;
234
+
235
+static inline QTree *q_tree_new(GCompareFunc key_compare_func)
236
+{
237
+ return g_tree_new(key_compare_func);
238
+}
239
+
240
+static inline QTree *q_tree_new_with_data(GCompareDataFunc key_compare_func,
241
+ gpointer key_compare_data)
242
+{
243
+ return g_tree_new_with_data(key_compare_func, key_compare_data);
244
+}
245
+
246
+static inline QTree *q_tree_new_full(GCompareDataFunc key_compare_func,
247
+ gpointer key_compare_data,
248
+ GDestroyNotify key_destroy_func,
249
+ GDestroyNotify value_destroy_func)
250
+{
251
+ return g_tree_new_full(key_compare_func, key_compare_data,
252
+ key_destroy_func, value_destroy_func);
253
+}
254
+
255
+static inline QTree *q_tree_ref(QTree *tree)
256
+{
257
+ return g_tree_ref(tree);
258
+}
259
+
260
+static inline void q_tree_unref(QTree *tree)
261
+{
262
+ g_tree_unref(tree);
263
+}
264
+
265
+static inline void q_tree_destroy(QTree *tree)
266
+{
267
+ g_tree_destroy(tree);
268
+}
269
+
270
+static inline void q_tree_insert(QTree *tree,
271
+ gpointer key,
272
+ gpointer value)
273
+{
274
+ g_tree_insert(tree, key, value);
275
+}
276
+
277
+static inline void q_tree_replace(QTree *tree,
278
+ gpointer key,
279
+ gpointer value)
280
+{
281
+ g_tree_replace(tree, key, value);
282
+}
283
+
284
+static inline gboolean q_tree_remove(QTree *tree,
285
+ gconstpointer key)
286
+{
287
+ return g_tree_remove(tree, key);
288
+}
289
+
290
+static inline gboolean q_tree_steal(QTree *tree,
291
+ gconstpointer key)
292
+{
293
+ return g_tree_steal(tree, key);
294
+}
295
+
296
+static inline gpointer q_tree_lookup(QTree *tree,
297
+ gconstpointer key)
298
+{
299
+ return g_tree_lookup(tree, key);
300
+}
301
+
302
+static inline gboolean q_tree_lookup_extended(QTree *tree,
303
+ gconstpointer lookup_key,
304
+ gpointer *orig_key,
305
+ gpointer *value)
306
+{
307
+ return g_tree_lookup_extended(tree, lookup_key, orig_key, value);
308
+}
309
+
310
+static inline void q_tree_foreach(QTree *tree,
311
+ GTraverseFunc func,
312
+ gpointer user_data)
313
+{
314
+ return g_tree_foreach(tree, func, user_data);
315
+}
316
+
317
+static inline gpointer q_tree_search(QTree *tree,
318
+ GCompareFunc search_func,
319
+ gconstpointer user_data)
320
+{
321
+ return g_tree_search(tree, search_func, user_data);
322
+}
323
+
324
+static inline gint q_tree_height(QTree *tree)
325
+{
326
+ return g_tree_height(tree);
327
+}
328
+
329
+static inline gint q_tree_nnodes(QTree *tree)
330
+{
331
+ return g_tree_nnodes(tree);
332
+}
333
+
334
+#endif /* HAVE_GLIB_WITH_SLICE_ALLOCATOR */
335
+
336
+#endif /* QEMU_QTREE_H */
337
diff --git a/tests/bench/qtree-bench.c b/tests/bench/qtree-bench.c
338
new file mode 100644
339
index XXXXXXX..XXXXXXX
340
--- /dev/null
341
+++ b/tests/bench/qtree-bench.c
342
@@ -XXX,XX +XXX,XX @@
343
+/* SPDX-License-Identifier: GPL-2.0-or-later */
344
+#include "qemu/osdep.h"
345
+#include "qemu/qtree.h"
346
+#include "qemu/timer.h"
347
+
348
+enum tree_op {
349
+ OP_LOOKUP,
350
+ OP_INSERT,
351
+ OP_REMOVE,
352
+ OP_REMOVE_ALL,
353
+ OP_TRAVERSE,
354
+};
355
+
356
+struct benchmark {
357
+ const char * const name;
358
+ enum tree_op op;
359
+ bool fill_on_init;
360
+};
361
+
362
+enum impl_type {
363
+ IMPL_GTREE,
364
+ IMPL_QTREE,
365
+};
366
+
367
+struct tree_implementation {
368
+ const char * const name;
369
+ enum impl_type type;
370
+};
371
+
372
+static const struct benchmark benchmarks[] = {
373
+ {
374
+ .name = "Lookup",
375
+ .op = OP_LOOKUP,
376
+ .fill_on_init = true,
377
+ },
378
+ {
379
+ .name = "Insert",
380
+ .op = OP_INSERT,
381
+ .fill_on_init = false,
382
+ },
383
+ {
384
+ .name = "Remove",
385
+ .op = OP_REMOVE,
386
+ .fill_on_init = true,
387
+ },
388
+ {
389
+ .name = "RemoveAll",
390
+ .op = OP_REMOVE_ALL,
391
+ .fill_on_init = true,
392
+ },
393
+ {
394
+ .name = "Traverse",
395
+ .op = OP_TRAVERSE,
396
+ .fill_on_init = true,
397
+ },
398
+};
399
+
400
+static const struct tree_implementation impls[] = {
401
+ {
402
+ .name = "GTree",
403
+ .type = IMPL_GTREE,
404
+ },
405
+ {
406
+ .name = "QTree",
407
+ .type = IMPL_QTREE,
408
+ },
409
+};
410
+
411
+static int compare_func(const void *ap, const void *bp)
412
+{
413
+ const size_t *a = ap;
414
+ const size_t *b = bp;
415
+
416
+ return *a - *b;
417
+}
418
+
419
+static void init_empty_tree_and_keys(enum impl_type impl,
420
+ void **ret_tree, size_t **ret_keys,
421
+ size_t n_elems)
422
+{
423
+ size_t *keys = g_malloc_n(n_elems, sizeof(*keys));
424
+ for (size_t i = 0; i < n_elems; i++) {
425
+ keys[i] = i;
426
+ }
427
+
428
+ void *tree;
429
+ switch (impl) {
430
+ case IMPL_GTREE:
431
+ tree = g_tree_new(compare_func);
432
+ break;
433
+ case IMPL_QTREE:
434
+ tree = q_tree_new(compare_func);
435
+ break;
436
+ default:
437
+ g_assert_not_reached();
438
+ }
439
+
440
+ *ret_tree = tree;
441
+ *ret_keys = keys;
442
+}
443
+
444
+static gboolean traverse_func(gpointer key, gpointer value, gpointer data)
445
+{
446
+ return FALSE;
447
+}
448
+
449
+static inline void remove_all(void *tree, enum impl_type impl)
450
+{
451
+ switch (impl) {
452
+ case IMPL_GTREE:
453
+ g_tree_destroy(tree);
454
+ break;
455
+ case IMPL_QTREE:
456
+ q_tree_destroy(tree);
457
+ break;
458
+ default:
459
+ g_assert_not_reached();
460
+ }
461
+}
462
+
463
+static int64_t run_benchmark(const struct benchmark *bench,
464
+ enum impl_type impl,
465
+ size_t n_elems)
466
+{
467
+ void *tree;
468
+ size_t *keys;
469
+
470
+ init_empty_tree_and_keys(impl, &tree, &keys, n_elems);
471
+ if (bench->fill_on_init) {
472
+ for (size_t i = 0; i < n_elems; i++) {
473
+ switch (impl) {
474
+ case IMPL_GTREE:
475
+ g_tree_insert(tree, &keys[i], &keys[i]);
476
+ break;
477
+ case IMPL_QTREE:
478
+ q_tree_insert(tree, &keys[i], &keys[i]);
479
+ break;
480
+ default:
481
+ g_assert_not_reached();
482
+ }
483
+ }
484
+ }
485
+
486
+ int64_t start_ns = get_clock();
487
+ switch (bench->op) {
488
+ case OP_LOOKUP:
489
+ for (size_t i = 0; i < n_elems; i++) {
490
+ void *value;
491
+ switch (impl) {
492
+ case IMPL_GTREE:
493
+ value = g_tree_lookup(tree, &keys[i]);
494
+ break;
495
+ case IMPL_QTREE:
496
+ value = q_tree_lookup(tree, &keys[i]);
497
+ break;
498
+ default:
499
+ g_assert_not_reached();
500
+ }
501
+ (void)value;
502
+ }
503
+ break;
504
+ case OP_INSERT:
505
+ for (size_t i = 0; i < n_elems; i++) {
506
+ switch (impl) {
507
+ case IMPL_GTREE:
508
+ g_tree_insert(tree, &keys[i], &keys[i]);
509
+ break;
510
+ case IMPL_QTREE:
511
+ q_tree_insert(tree, &keys[i], &keys[i]);
512
+ break;
513
+ default:
514
+ g_assert_not_reached();
515
+ }
516
+ }
517
+ break;
518
+ case OP_REMOVE:
519
+ for (size_t i = 0; i < n_elems; i++) {
520
+ switch (impl) {
521
+ case IMPL_GTREE:
522
+ g_tree_remove(tree, &keys[i]);
523
+ break;
524
+ case IMPL_QTREE:
525
+ q_tree_remove(tree, &keys[i]);
526
+ break;
527
+ default:
528
+ g_assert_not_reached();
529
+ }
530
+ }
531
+ break;
532
+ case OP_REMOVE_ALL:
533
+ remove_all(tree, impl);
534
+ break;
535
+ case OP_TRAVERSE:
536
+ switch (impl) {
537
+ case IMPL_GTREE:
538
+ g_tree_foreach(tree, traverse_func, NULL);
539
+ break;
540
+ case IMPL_QTREE:
541
+ q_tree_foreach(tree, traverse_func, NULL);
542
+ break;
543
+ default:
544
+ g_assert_not_reached();
545
+ }
546
+ break;
547
+ default:
548
+ g_assert_not_reached();
549
+ }
550
+ int64_t ns = get_clock() - start_ns;
551
+
552
+ if (bench->op != OP_REMOVE_ALL) {
553
+ remove_all(tree, impl);
554
+ }
555
+ g_free(keys);
556
+
557
+ return ns;
558
+}
559
+
560
+int main(int argc, char *argv[])
561
+{
562
+ size_t sizes[] = {
563
+ 32,
564
+ 1024,
565
+ 1024 * 4,
566
+ 1024 * 128,
567
+ 1024 * 1024,
568
+ };
569
+
570
+ double res[ARRAY_SIZE(benchmarks)][ARRAY_SIZE(impls)][ARRAY_SIZE(sizes)];
571
+ for (int i = 0; i < ARRAY_SIZE(sizes); i++) {
572
+ size_t size = sizes[i];
573
+ for (int j = 0; j < ARRAY_SIZE(impls); j++) {
574
+ const struct tree_implementation *impl = &impls[j];
575
+ for (int k = 0; k < ARRAY_SIZE(benchmarks); k++) {
576
+ const struct benchmark *bench = &benchmarks[k];
577
+
578
+ /* warm-up run */
579
+ run_benchmark(bench, impl->type, size);
580
+
581
+ int64_t total_ns = 0;
582
+ int64_t n_runs = 0;
583
+ while (total_ns < 2e8 || n_runs < 5) {
584
+ total_ns += run_benchmark(bench, impl->type, size);
585
+ n_runs++;
586
+ }
587
+ double ns_per_run = (double)total_ns / n_runs;
588
+
589
+ /* Throughput, in Mops/s */
590
+ res[k][j][i] = size / ns_per_run * 1e3;
591
+ }
592
+ }
593
+ }
594
+
595
+ printf("# Results' breakdown: Tree, Op and #Elements. Units: Mops/s\n");
596
+ printf("%5s %10s ", "Tree", "Op");
597
+ for (int i = 0; i < ARRAY_SIZE(sizes); i++) {
598
+ printf("%7zu ", sizes[i]);
599
+ }
600
+ printf("\n");
601
+ char separator[97];
602
+ for (int i = 0; i < ARRAY_SIZE(separator) - 1; i++) {
603
+ separator[i] = '-';
604
+ }
605
+ separator[ARRAY_SIZE(separator) - 1] = '\0';
606
+ printf("%s\n", separator);
607
+ for (int i = 0; i < ARRAY_SIZE(benchmarks); i++) {
608
+ for (int j = 0; j < ARRAY_SIZE(impls); j++) {
609
+ printf("%5s %10s ", impls[j].name, benchmarks[i].name);
610
+ for (int k = 0; k < ARRAY_SIZE(sizes); k++) {
611
+ printf("%7.2f ", res[i][j][k]);
612
+ if (j == 0) {
613
+ printf(" ");
614
+ } else {
615
+ if (res[i][0][k] != 0) {
616
+ double speedup = res[i][j][k] / res[i][0][k];
617
+ printf("(%4.2fx) ", speedup);
618
+ } else {
619
+ printf("( ) ");
620
+ }
621
+ }
622
+ }
623
+ printf("\n");
624
+ }
625
+ }
626
+ printf("%s\n", separator);
627
+ return 0;
628
+}
629
diff --git a/tests/unit/test-qtree.c b/tests/unit/test-qtree.c
630
new file mode 100644
631
index XXXXXXX..XXXXXXX
632
--- /dev/null
633
+++ b/tests/unit/test-qtree.c
634
@@ -XXX,XX +XXX,XX @@
635
+/*
636
+ * SPDX-License-Identifier: LGPL-2.1-or-later
637
+ *
638
+ * Tests for QTree.
639
+ * Original source: glib
640
+ * https://gitlab.gnome.org/GNOME/glib/-/blob/main/glib/tests/tree.c
641
+ * LGPL license.
642
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
643
+ */
644
+
645
+#include "qemu/osdep.h"
646
+#include "qemu/qtree.h"
647
+
648
+static gint my_compare(gconstpointer a, gconstpointer b)
649
+{
650
+ const char *cha = a;
651
+ const char *chb = b;
652
+
653
+ return *cha - *chb;
654
+}
655
+
656
+static gint my_compare_with_data(gconstpointer a,
657
+ gconstpointer b,
658
+ gpointer user_data)
659
+{
660
+ const char *cha = a;
661
+ const char *chb = b;
662
+
663
+ /* just check that we got the right data */
664
+ g_assert(GPOINTER_TO_INT(user_data) == 123);
665
+
666
+ return *cha - *chb;
667
+}
668
+
669
+static gint my_search(gconstpointer a, gconstpointer b)
670
+{
671
+ return my_compare(b, a);
672
+}
673
+
674
+static gpointer destroyed_key;
675
+static gpointer destroyed_value;
676
+static guint destroyed_key_count;
677
+static guint destroyed_value_count;
678
+
679
+static void my_key_destroy(gpointer key)
680
+{
681
+ destroyed_key = key;
682
+ destroyed_key_count++;
683
+}
684
+
685
+static void my_value_destroy(gpointer value)
686
+{
687
+ destroyed_value = value;
688
+ destroyed_value_count++;
689
+}
690
+
691
+static gint my_traverse(gpointer key, gpointer value, gpointer data)
692
+{
693
+ char *ch = key;
694
+
695
+ g_assert((*ch) > 0);
696
+
697
+ if (*ch == 'd') {
698
+ return TRUE;
699
+ }
700
+
701
+ return FALSE;
702
+}
703
+
704
+char chars[] =
705
+ "0123456789"
706
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
707
+ "abcdefghijklmnopqrstuvwxyz";
708
+
709
+char chars2[] =
710
+ "0123456789"
711
+ "abcdefghijklmnopqrstuvwxyz";
712
+
713
+static gint check_order(gpointer key, gpointer value, gpointer data)
714
+{
715
+ char **p = data;
716
+ char *ch = key;
717
+
718
+ g_assert(**p == *ch);
719
+
720
+ (*p)++;
721
+
722
+ return FALSE;
723
+}
724
+
725
+static void test_tree_search(void)
726
+{
727
+ gint i;
728
+ QTree *tree;
729
+ gboolean removed;
730
+ gchar c;
731
+ gchar *p, *d;
732
+
733
+ tree = q_tree_new_with_data(my_compare_with_data, GINT_TO_POINTER(123));
734
+
735
+ for (i = 0; chars[i]; i++) {
736
+ q_tree_insert(tree, &chars[i], &chars[i]);
737
+ }
738
+
739
+ q_tree_foreach(tree, my_traverse, NULL);
740
+
741
+ g_assert(q_tree_nnodes(tree) == strlen(chars));
742
+ g_assert(q_tree_height(tree) == 6);
743
+
744
+ p = chars;
745
+ q_tree_foreach(tree, check_order, &p);
746
+
747
+ for (i = 0; i < 26; i++) {
748
+ removed = q_tree_remove(tree, &chars[i + 10]);
749
+ g_assert(removed);
750
+ }
751
+
752
+ c = '\0';
753
+ removed = q_tree_remove(tree, &c);
754
+ g_assert(!removed);
755
+
756
+ q_tree_foreach(tree, my_traverse, NULL);
757
+
758
+ g_assert(q_tree_nnodes(tree) == strlen(chars2));
759
+ g_assert(q_tree_height(tree) == 6);
760
+
761
+ p = chars2;
762
+ q_tree_foreach(tree, check_order, &p);
763
+
764
+ for (i = 25; i >= 0; i--) {
765
+ q_tree_insert(tree, &chars[i + 10], &chars[i + 10]);
766
+ }
767
+
768
+ p = chars;
769
+ q_tree_foreach(tree, check_order, &p);
770
+
771
+ c = '0';
772
+ p = q_tree_lookup(tree, &c);
773
+ g_assert(p && *p == c);
774
+ g_assert(q_tree_lookup_extended(tree, &c, (gpointer *)&d, (gpointer *)&p));
775
+ g_assert(c == *d && c == *p);
776
+
777
+ c = 'A';
778
+ p = q_tree_lookup(tree, &c);
779
+ g_assert(p && *p == c);
780
+
781
+ c = 'a';
782
+ p = q_tree_lookup(tree, &c);
783
+ g_assert(p && *p == c);
784
+
785
+ c = 'z';
786
+ p = q_tree_lookup(tree, &c);
787
+ g_assert(p && *p == c);
788
+
789
+ c = '!';
790
+ p = q_tree_lookup(tree, &c);
791
+ g_assert(p == NULL);
792
+
793
+ c = '=';
794
+ p = q_tree_lookup(tree, &c);
795
+ g_assert(p == NULL);
796
+
797
+ c = '|';
798
+ p = q_tree_lookup(tree, &c);
799
+ g_assert(p == NULL);
800
+
801
+ c = '0';
802
+ p = q_tree_search(tree, my_search, &c);
803
+ g_assert(p && *p == c);
804
+
805
+ c = 'A';
806
+ p = q_tree_search(tree, my_search, &c);
807
+ g_assert(p && *p == c);
808
+
809
+ c = 'a';
810
+ p = q_tree_search(tree, my_search, &c);
811
+ g_assert(p && *p == c);
812
+
813
+ c = 'z';
814
+ p = q_tree_search(tree, my_search, &c);
815
+ g_assert(p && *p == c);
816
+
817
+ c = '!';
818
+ p = q_tree_search(tree, my_search, &c);
819
+ g_assert(p == NULL);
820
+
821
+ c = '=';
822
+ p = q_tree_search(tree, my_search, &c);
823
+ g_assert(p == NULL);
824
+
825
+ c = '|';
826
+ p = q_tree_search(tree, my_search, &c);
827
+ g_assert(p == NULL);
828
+
829
+ q_tree_destroy(tree);
830
+}
831
+
832
+static void test_tree_remove(void)
833
+{
834
+ QTree *tree;
835
+ char c, d;
836
+ gint i;
837
+ gboolean removed;
838
+
839
+ tree = q_tree_new_full((GCompareDataFunc)my_compare, NULL,
840
+ my_key_destroy,
841
+ my_value_destroy);
842
+
843
+ for (i = 0; chars[i]; i++) {
844
+ q_tree_insert(tree, &chars[i], &chars[i]);
845
+ }
846
+
847
+ c = '0';
848
+ q_tree_insert(tree, &c, &c);
849
+ g_assert(destroyed_key == &c);
850
+ g_assert(destroyed_value == &chars[0]);
851
+ destroyed_key = NULL;
852
+ destroyed_value = NULL;
853
+
854
+ d = '1';
855
+ q_tree_replace(tree, &d, &d);
856
+ g_assert(destroyed_key == &chars[1]);
857
+ g_assert(destroyed_value == &chars[1]);
858
+ destroyed_key = NULL;
859
+ destroyed_value = NULL;
860
+
861
+ c = '2';
862
+ removed = q_tree_remove(tree, &c);
863
+ g_assert(removed);
864
+ g_assert(destroyed_key == &chars[2]);
865
+ g_assert(destroyed_value == &chars[2]);
866
+ destroyed_key = NULL;
867
+ destroyed_value = NULL;
868
+
869
+ c = '3';
870
+ removed = q_tree_steal(tree, &c);
871
+ g_assert(removed);
872
+ g_assert(destroyed_key == NULL);
873
+ g_assert(destroyed_value == NULL);
874
+
875
+ const gchar *remove = "omkjigfedba";
876
+ for (i = 0; remove[i]; i++) {
877
+ removed = q_tree_remove(tree, &remove[i]);
878
+ g_assert(removed);
879
+ }
880
+
881
+ q_tree_destroy(tree);
882
+}
883
+
884
+static void test_tree_destroy(void)
885
+{
886
+ QTree *tree;
887
+ gint i;
888
+
889
+ tree = q_tree_new(my_compare);
890
+
891
+ for (i = 0; chars[i]; i++) {
892
+ q_tree_insert(tree, &chars[i], &chars[i]);
893
+ }
894
+
895
+ g_assert(q_tree_nnodes(tree) == strlen(chars));
896
+
897
+ g_test_message("nnodes: %d", q_tree_nnodes(tree));
898
+ q_tree_ref(tree);
899
+ q_tree_destroy(tree);
900
+
901
+ g_test_message("nnodes: %d", q_tree_nnodes(tree));
902
+ g_assert(q_tree_nnodes(tree) == 0);
903
+
904
+ q_tree_unref(tree);
905
+}
906
+
907
+static void test_tree_insert(void)
908
+{
909
+ QTree *tree;
910
+ gchar *p;
911
+ gint i;
912
+ gchar *scrambled;
913
+
914
+ tree = q_tree_new(my_compare);
915
+
916
+ for (i = 0; chars[i]; i++) {
917
+ q_tree_insert(tree, &chars[i], &chars[i]);
918
+ }
919
+ p = chars;
920
+ q_tree_foreach(tree, check_order, &p);
921
+
922
+ q_tree_unref(tree);
923
+ tree = q_tree_new(my_compare);
924
+
925
+ for (i = strlen(chars) - 1; i >= 0; i--) {
926
+ q_tree_insert(tree, &chars[i], &chars[i]);
927
+ }
928
+ p = chars;
929
+ q_tree_foreach(tree, check_order, &p);
930
+
931
+ q_tree_unref(tree);
932
+ tree = q_tree_new(my_compare);
933
+
934
+ scrambled = g_strdup(chars);
935
+
936
+ for (i = 0; i < 30; i++) {
937
+ gchar tmp;
938
+ gint a, b;
939
+
940
+ a = g_random_int_range(0, strlen(scrambled));
941
+ b = g_random_int_range(0, strlen(scrambled));
942
+ tmp = scrambled[a];
943
+ scrambled[a] = scrambled[b];
944
+ scrambled[b] = tmp;
945
+ }
946
+
947
+ for (i = 0; scrambled[i]; i++) {
948
+ q_tree_insert(tree, &scrambled[i], &scrambled[i]);
949
+ }
950
+ p = chars;
951
+ q_tree_foreach(tree, check_order, &p);
952
+
953
+ g_free(scrambled);
954
+ q_tree_unref(tree);
955
+}
956
+
957
+int main(int argc, char *argv[])
958
+{
959
+ g_test_init(&argc, &argv, NULL);
960
+
961
+ g_test_add_func("/qtree/search", test_tree_search);
962
+ g_test_add_func("/qtree/remove", test_tree_remove);
963
+ g_test_add_func("/qtree/destroy", test_tree_destroy);
964
+ g_test_add_func("/qtree/insert", test_tree_insert);
965
+
966
+ return g_test_run();
967
+}
968
diff --git a/util/qtree.c b/util/qtree.c
969
new file mode 100644
970
index XXXXXXX..XXXXXXX
971
--- /dev/null
972
+++ b/util/qtree.c
973
@@ -XXX,XX +XXX,XX @@
974
+/*
975
+ * GLIB - Library of useful routines for C programming
976
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
977
+ *
978
+ * SPDX-License-Identifier: LGPL-2.1-or-later
979
+ *
980
+ * This library is free software; you can redistribute it and/or
981
+ * modify it under the terms of the GNU Lesser General Public
982
+ * License as published by the Free Software Foundation; either
983
+ * version 2.1 of the License, or (at your option) any later version.
984
+ *
985
+ * This library is distributed in the hope that it will be useful,
986
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
987
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
988
+ * Lesser General Public License for more details.
989
+ *
990
+ * You should have received a copy of the GNU Lesser General Public
991
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
992
+ */
993
+
994
+/*
995
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
996
+ * file for a list of people on the GLib Team. See the ChangeLog
997
+ * files for a list of changes. These files are distributed with
998
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
999
+ */
1000
+
1001
+/*
1002
+ * MT safe
1003
+ */
1004
+
1005
+#include "qemu/osdep.h"
1006
+#include "qemu/qtree.h"
1007
+
1008
+/**
1009
+ * SECTION:trees-binary
1010
+ * @title: Balanced Binary Trees
1011
+ * @short_description: a sorted collection of key/value pairs optimized
1012
+ * for searching and traversing in order
1013
+ *
1014
+ * The #QTree structure and its associated functions provide a sorted
1015
+ * collection of key/value pairs optimized for searching and traversing
1016
+ * in order. This means that most of the operations (access, search,
1017
+ * insertion, deletion, ...) on #QTree are O(log(n)) in average and O(n)
1018
+ * in worst case for time complexity. But, note that maintaining a
1019
+ * balanced sorted #QTree of n elements is done in time O(n log(n)).
1020
+ *
1021
+ * To create a new #QTree use q_tree_new().
1022
+ *
1023
+ * To insert a key/value pair into a #QTree use q_tree_insert()
1024
+ * (O(n log(n))).
1025
+ *
1026
+ * To remove a key/value pair use q_tree_remove() (O(n log(n))).
1027
+ *
1028
+ * To look up the value corresponding to a given key, use
1029
+ * q_tree_lookup() and q_tree_lookup_extended().
1030
+ *
1031
+ * To find out the number of nodes in a #QTree, use q_tree_nnodes(). To
1032
+ * get the height of a #QTree, use q_tree_height().
1033
+ *
1034
+ * To traverse a #QTree, calling a function for each node visited in
1035
+ * the traversal, use q_tree_foreach().
1036
+ *
1037
+ * To destroy a #QTree, use q_tree_destroy().
1038
+ **/
1039
+
1040
+#define MAX_GTREE_HEIGHT 40
1041
+
1042
+/**
1043
+ * QTree:
1044
+ *
1045
+ * The QTree struct is an opaque data structure representing a
1046
+ * [balanced binary tree][glib-Balanced-Binary-Trees]. It should be
1047
+ * accessed only by using the following functions.
1048
+ */
1049
+struct _QTree {
1050
+ QTreeNode *root;
1051
+ GCompareDataFunc key_compare;
1052
+ GDestroyNotify key_destroy_func;
1053
+ GDestroyNotify value_destroy_func;
1054
+ gpointer key_compare_data;
1055
+ guint nnodes;
1056
+ gint ref_count;
1057
+};
1058
+
1059
+struct _QTreeNode {
1060
+ gpointer key; /* key for this node */
1061
+ gpointer value; /* value stored at this node */
1062
+ QTreeNode *left; /* left subtree */
1063
+ QTreeNode *right; /* right subtree */
1064
+ gint8 balance; /* height (right) - height (left) */
1065
+ guint8 left_child;
1066
+ guint8 right_child;
1067
+};
1068
+
1069
+
1070
+static QTreeNode *q_tree_node_new(gpointer key,
1071
+ gpointer value);
1072
+static QTreeNode *q_tree_insert_internal(QTree *tree,
1073
+ gpointer key,
1074
+ gpointer value,
1075
+ gboolean replace);
1076
+static gboolean q_tree_remove_internal(QTree *tree,
1077
+ gconstpointer key,
1078
+ gboolean steal);
1079
+static QTreeNode *q_tree_node_balance(QTreeNode *node);
1080
+static QTreeNode *q_tree_find_node(QTree *tree,
1081
+ gconstpointer key);
1082
+static QTreeNode *q_tree_node_search(QTreeNode *node,
1083
+ GCompareFunc search_func,
1084
+ gconstpointer data);
1085
+static QTreeNode *q_tree_node_rotate_left(QTreeNode *node);
1086
+static QTreeNode *q_tree_node_rotate_right(QTreeNode *node);
1087
+#ifdef Q_TREE_DEBUG
1088
+static void q_tree_node_check(QTreeNode *node);
1089
+#endif
1090
+
1091
+static QTreeNode*
1092
+q_tree_node_new(gpointer key,
1093
+ gpointer value)
1094
+{
1095
+ QTreeNode *node = g_new(QTreeNode, 1);
1096
+
1097
+ node->balance = 0;
1098
+ node->left = NULL;
1099
+ node->right = NULL;
1100
+ node->left_child = FALSE;
1101
+ node->right_child = FALSE;
1102
+ node->key = key;
1103
+ node->value = value;
1104
+
1105
+ return node;
1106
+}
1107
+
1108
+/**
1109
+ * q_tree_new:
1110
+ * @key_compare_func: the function used to order the nodes in the #QTree.
1111
+ * It should return values similar to the standard strcmp() function -
1112
+ * 0 if the two arguments are equal, a negative value if the first argument
1113
+ * comes before the second, or a positive value if the first argument comes
1114
+ * after the second.
1115
+ *
1116
+ * Creates a new #QTree.
1117
+ *
1118
+ * Returns: a newly allocated #QTree
1119
+ */
1120
+QTree *
1121
+q_tree_new(GCompareFunc key_compare_func)
1122
+{
1123
+ g_return_val_if_fail(key_compare_func != NULL, NULL);
1124
+
1125
+ return q_tree_new_full((GCompareDataFunc) key_compare_func, NULL,
1126
+ NULL, NULL);
1127
+}
1128
+
1129
+/**
1130
+ * q_tree_new_with_data:
1131
+ * @key_compare_func: qsort()-style comparison function
1132
+ * @key_compare_data: data to pass to comparison function
1133
+ *
1134
+ * Creates a new #QTree with a comparison function that accepts user data.
1135
+ * See q_tree_new() for more details.
1136
+ *
1137
+ * Returns: a newly allocated #QTree
1138
+ */
1139
+QTree *
1140
+q_tree_new_with_data(GCompareDataFunc key_compare_func,
1141
+ gpointer key_compare_data)
1142
+{
1143
+ g_return_val_if_fail(key_compare_func != NULL, NULL);
1144
+
1145
+ return q_tree_new_full(key_compare_func, key_compare_data,
1146
+ NULL, NULL);
1147
+}
1148
+
1149
+/**
1150
+ * q_tree_new_full:
1151
+ * @key_compare_func: qsort()-style comparison function
1152
+ * @key_compare_data: data to pass to comparison function
1153
+ * @key_destroy_func: a function to free the memory allocated for the key
1154
+ * used when removing the entry from the #QTree or %NULL if you don't
1155
+ * want to supply such a function
1156
+ * @value_destroy_func: a function to free the memory allocated for the
1157
+ * value used when removing the entry from the #QTree or %NULL if you
1158
+ * don't want to supply such a function
1159
+ *
1160
+ * Creates a new #QTree like q_tree_new() and allows to specify functions
1161
+ * to free the memory allocated for the key and value that get called when
1162
+ * removing the entry from the #QTree.
1163
+ *
1164
+ * Returns: a newly allocated #QTree
1165
+ */
1166
+QTree *
1167
+q_tree_new_full(GCompareDataFunc key_compare_func,
1168
+ gpointer key_compare_data,
1169
+ GDestroyNotify key_destroy_func,
1170
+ GDestroyNotify value_destroy_func)
1171
+{
1172
+ QTree *tree;
1173
+
1174
+ g_return_val_if_fail(key_compare_func != NULL, NULL);
1175
+
1176
+ tree = g_new(QTree, 1);
1177
+ tree->root = NULL;
1178
+ tree->key_compare = key_compare_func;
1179
+ tree->key_destroy_func = key_destroy_func;
1180
+ tree->value_destroy_func = value_destroy_func;
1181
+ tree->key_compare_data = key_compare_data;
1182
+ tree->nnodes = 0;
1183
+ tree->ref_count = 1;
1184
+
1185
+ return tree;
1186
+}
1187
+
1188
+/**
1189
+ * q_tree_node_first:
1190
+ * @tree: a #QTree
1191
+ *
1192
+ * Returns the first in-order node of the tree, or %NULL
1193
+ * for an empty tree.
1194
+ *
1195
+ * Returns: (nullable) (transfer none): the first node in the tree
1196
+ *
1197
+ * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
1198
+ */
1199
+static QTreeNode *
1200
+q_tree_node_first(QTree *tree)
1201
+{
1202
+ QTreeNode *tmp;
1203
+
1204
+ g_return_val_if_fail(tree != NULL, NULL);
1205
+
1206
+ if (!tree->root) {
1207
+ return NULL;
1208
+ }
1209
+
1210
+ tmp = tree->root;
1211
+
1212
+ while (tmp->left_child) {
1213
+ tmp = tmp->left;
1214
+ }
1215
+
1216
+ return tmp;
1217
+}
1218
+
1219
+/**
1220
+ * q_tree_node_previous
1221
+ * @node: a #QTree node
1222
+ *
1223
+ * Returns the previous in-order node of the tree, or %NULL
1224
+ * if the passed node was already the first one.
1225
+ *
1226
+ * Returns: (nullable) (transfer none): the previous node in the tree
1227
+ *
1228
+ * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
1229
+ */
1230
+static QTreeNode *
1231
+q_tree_node_previous(QTreeNode *node)
1232
+{
1233
+ QTreeNode *tmp;
1234
+
1235
+ g_return_val_if_fail(node != NULL, NULL);
1236
+
1237
+ tmp = node->left;
1238
+
1239
+ if (node->left_child) {
1240
+ while (tmp->right_child) {
1241
+ tmp = tmp->right;
1242
+ }
1243
+ }
1244
+
1245
+ return tmp;
1246
+}
1247
+
1248
+/**
1249
+ * q_tree_node_next
1250
+ * @node: a #QTree node
1251
+ *
1252
+ * Returns the next in-order node of the tree, or %NULL
1253
+ * if the passed node was already the last one.
1254
+ *
1255
+ * Returns: (nullable) (transfer none): the next node in the tree
1256
+ *
1257
+ * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
1258
+ */
1259
+static QTreeNode *
1260
+q_tree_node_next(QTreeNode *node)
1261
+{
1262
+ QTreeNode *tmp;
1263
+
1264
+ g_return_val_if_fail(node != NULL, NULL);
1265
+
1266
+ tmp = node->right;
1267
+
1268
+ if (node->right_child) {
1269
+ while (tmp->left_child) {
1270
+ tmp = tmp->left;
1271
+ }
1272
+ }
1273
+
1274
+ return tmp;
1275
+}
1276
+
1277
+/**
1278
+ * q_tree_remove_all:
1279
+ * @tree: a #QTree
1280
+ *
1281
+ * Removes all nodes from a #QTree and destroys their keys and values,
1282
+ * then resets the #QTree’s root to %NULL.
1283
+ *
1284
+ * Since: 2.70 in GLib. Internal in Qtree, i.e. not in the public API.
1285
+ */
1286
+static void
1287
+q_tree_remove_all(QTree *tree)
1288
+{
1289
+ QTreeNode *node;
1290
+ QTreeNode *next;
1291
+
1292
+ g_return_if_fail(tree != NULL);
1293
+
1294
+ node = q_tree_node_first(tree);
1295
+
1296
+ while (node) {
1297
+ next = q_tree_node_next(node);
1298
+
1299
+ if (tree->key_destroy_func) {
1300
+ tree->key_destroy_func(node->key);
1301
+ }
1302
+ if (tree->value_destroy_func) {
1303
+ tree->value_destroy_func(node->value);
1304
+ }
1305
+ g_free(node);
1306
+
1307
+#ifdef Q_TREE_DEBUG
1308
+ g_assert(tree->nnodes > 0);
1309
+ tree->nnodes--;
1310
+#endif
1311
+
1312
+ node = next;
1313
+ }
1314
+
1315
+#ifdef Q_TREE_DEBUG
1316
+ g_assert(tree->nnodes == 0);
1317
+#endif
1318
+
1319
+ tree->root = NULL;
1320
+#ifndef Q_TREE_DEBUG
1321
+ tree->nnodes = 0;
1322
+#endif
1323
+}
1324
+
1325
+/**
1326
+ * q_tree_ref:
1327
+ * @tree: a #QTree
1328
+ *
1329
+ * Increments the reference count of @tree by one.
1330
+ *
1331
+ * It is safe to call this function from any thread.
1332
+ *
1333
+ * Returns: the passed in #QTree
1334
+ *
1335
+ * Since: 2.22
1336
+ */
1337
+QTree *
1338
+q_tree_ref(QTree *tree)
1339
+{
1340
+ g_return_val_if_fail(tree != NULL, NULL);
1341
+
1342
+ g_atomic_int_inc(&tree->ref_count);
1343
+
1344
+ return tree;
1345
+}
1346
+
1347
+/**
1348
+ * q_tree_unref:
1349
+ * @tree: a #QTree
1350
+ *
1351
+ * Decrements the reference count of @tree by one.
1352
+ * If the reference count drops to 0, all keys and values will
1353
+ * be destroyed (if destroy functions were specified) and all
1354
+ * memory allocated by @tree will be released.
1355
+ *
1356
+ * It is safe to call this function from any thread.
1357
+ *
1358
+ * Since: 2.22
1359
+ */
1360
+void
1361
+q_tree_unref(QTree *tree)
1362
+{
1363
+ g_return_if_fail(tree != NULL);
1364
+
1365
+ if (g_atomic_int_dec_and_test(&tree->ref_count)) {
1366
+ q_tree_remove_all(tree);
1367
+ g_free(tree);
1368
+ }
1369
+}
1370
+
1371
+/**
1372
+ * q_tree_destroy:
1373
+ * @tree: a #QTree
1374
+ *
1375
+ * Removes all keys and values from the #QTree and decreases its
1376
+ * reference count by one. If keys and/or values are dynamically
1377
+ * allocated, you should either free them first or create the #QTree
1378
+ * using q_tree_new_full(). In the latter case the destroy functions
1379
+ * you supplied will be called on all keys and values before destroying
1380
+ * the #QTree.
1381
+ */
1382
+void
1383
+q_tree_destroy(QTree *tree)
1384
+{
1385
+ g_return_if_fail(tree != NULL);
1386
+
1387
+ q_tree_remove_all(tree);
1388
+ q_tree_unref(tree);
1389
+}
1390
+
1391
+/**
1392
+ * q_tree_insert_node:
1393
+ * @tree: a #QTree
1394
+ * @key: the key to insert
1395
+ * @value: the value corresponding to the key
1396
+ *
1397
+ * Inserts a key/value pair into a #QTree.
1398
+ *
1399
+ * If the given key already exists in the #QTree its corresponding value
1400
+ * is set to the new value. If you supplied a @value_destroy_func when
1401
+ * creating the #QTree, the old value is freed using that function. If
1402
+ * you supplied a @key_destroy_func when creating the #QTree, the passed
1403
+ * key is freed using that function.
1404
+ *
1405
+ * The tree is automatically 'balanced' as new key/value pairs are added,
1406
+ * so that the distance from the root to every leaf is as small as possible.
1407
+ * The cost of maintaining a balanced tree while inserting new key/value
1408
+ * result in a O(n log(n)) operation where most of the other operations
1409
+ * are O(log(n)).
1410
+ *
1411
+ * Returns: (transfer none): the inserted (or set) node.
1412
+ *
1413
+ * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
1414
+ */
1415
+static QTreeNode *
1416
+q_tree_insert_node(QTree *tree,
1417
+ gpointer key,
1418
+ gpointer value)
1419
+{
1420
+ QTreeNode *node;
1421
+
1422
+ g_return_val_if_fail(tree != NULL, NULL);
1423
+
1424
+ node = q_tree_insert_internal(tree, key, value, FALSE);
1425
+
1426
+#ifdef Q_TREE_DEBUG
1427
+ q_tree_node_check(tree->root);
1428
+#endif
1429
+
1430
+ return node;
1431
+}
1432
+
1433
+/**
1434
+ * q_tree_insert:
1435
+ * @tree: a #QTree
1436
+ * @key: the key to insert
1437
+ * @value: the value corresponding to the key
1438
+ *
1439
+ * Inserts a key/value pair into a #QTree.
1440
+ *
1441
+ * Inserts a new key and value into a #QTree as q_tree_insert_node() does,
1442
+ * only this function does not return the inserted or set node.
1443
+ */
1444
+void
1445
+q_tree_insert(QTree *tree,
1446
+ gpointer key,
1447
+ gpointer value)
1448
+{
1449
+ q_tree_insert_node(tree, key, value);
1450
+}
1451
+
1452
+/**
1453
+ * q_tree_replace_node:
1454
+ * @tree: a #QTree
1455
+ * @key: the key to insert
1456
+ * @value: the value corresponding to the key
1457
+ *
1458
+ * Inserts a new key and value into a #QTree similar to q_tree_insert_node().
1459
+ * The difference is that if the key already exists in the #QTree, it gets
1460
+ * replaced by the new key. If you supplied a @value_destroy_func when
1461
+ * creating the #QTree, the old value is freed using that function. If you
1462
+ * supplied a @key_destroy_func when creating the #QTree, the old key is
1463
+ * freed using that function.
1464
+ *
1465
+ * The tree is automatically 'balanced' as new key/value pairs are added,
1466
+ * so that the distance from the root to every leaf is as small as possible.
1467
+ *
1468
+ * Returns: (transfer none): the inserted (or set) node.
1469
+ *
1470
+ * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
1471
+ */
1472
+static QTreeNode *
1473
+q_tree_replace_node(QTree *tree,
1474
+ gpointer key,
1475
+ gpointer value)
1476
+{
1477
+ QTreeNode *node;
1478
+
1479
+ g_return_val_if_fail(tree != NULL, NULL);
1480
+
1481
+ node = q_tree_insert_internal(tree, key, value, TRUE);
1482
+
1483
+#ifdef Q_TREE_DEBUG
1484
+ q_tree_node_check(tree->root);
1485
+#endif
1486
+
1487
+ return node;
1488
+}
1489
+
1490
+/**
1491
+ * q_tree_replace:
1492
+ * @tree: a #QTree
1493
+ * @key: the key to insert
1494
+ * @value: the value corresponding to the key
1495
+ *
1496
+ * Inserts a new key and value into a #QTree as q_tree_replace_node() does,
1497
+ * only this function does not return the inserted or set node.
1498
+ */
1499
+void
1500
+q_tree_replace(QTree *tree,
1501
+ gpointer key,
1502
+ gpointer value)
1503
+{
1504
+ q_tree_replace_node(tree, key, value);
1505
+}
1506
+
1507
+/* internal insert routine */
1508
+static QTreeNode *
1509
+q_tree_insert_internal(QTree *tree,
1510
+ gpointer key,
1511
+ gpointer value,
1512
+ gboolean replace)
1513
+{
1514
+ QTreeNode *node, *retnode;
1515
+ QTreeNode *path[MAX_GTREE_HEIGHT];
1516
+ int idx;
1517
+
1518
+ g_return_val_if_fail(tree != NULL, NULL);
1519
+
1520
+ if (!tree->root) {
1521
+ tree->root = q_tree_node_new(key, value);
1522
+ tree->nnodes++;
1523
+ return tree->root;
1524
+ }
1525
+
1526
+ idx = 0;
1527
+ path[idx++] = NULL;
1528
+ node = tree->root;
1529
+
1530
+ while (1) {
1531
+ int cmp = tree->key_compare(key, node->key, tree->key_compare_data);
1532
+
1533
+ if (cmp == 0) {
1534
+ if (tree->value_destroy_func) {
1535
+ tree->value_destroy_func(node->value);
1536
+ }
1537
+
1538
+ node->value = value;
1539
+
1540
+ if (replace) {
1541
+ if (tree->key_destroy_func) {
1542
+ tree->key_destroy_func(node->key);
1543
+ }
1544
+
1545
+ node->key = key;
1546
+ } else {
1547
+ /* free the passed key */
1548
+ if (tree->key_destroy_func) {
1549
+ tree->key_destroy_func(key);
1550
+ }
1551
+ }
1552
+
1553
+ return node;
1554
+ } else if (cmp < 0) {
1555
+ if (node->left_child) {
1556
+ path[idx++] = node;
1557
+ node = node->left;
1558
+ } else {
1559
+ QTreeNode *child = q_tree_node_new(key, value);
1560
+
1561
+ child->left = node->left;
1562
+ child->right = node;
1563
+ node->left = child;
1564
+ node->left_child = TRUE;
1565
+ node->balance -= 1;
1566
+
1567
+ tree->nnodes++;
1568
+
1569
+ retnode = child;
1570
+ break;
1571
+ }
1572
+ } else {
1573
+ if (node->right_child) {
1574
+ path[idx++] = node;
1575
+ node = node->right;
1576
+ } else {
1577
+ QTreeNode *child = q_tree_node_new(key, value);
1578
+
1579
+ child->right = node->right;
1580
+ child->left = node;
1581
+ node->right = child;
1582
+ node->right_child = TRUE;
1583
+ node->balance += 1;
1584
+
1585
+ tree->nnodes++;
1586
+
1587
+ retnode = child;
1588
+ break;
1589
+ }
1590
+ }
1591
+ }
1592
+
1593
+ /*
1594
+ * Restore balance. This is the goodness of a non-recursive
1595
+ * implementation, when we are done with balancing we 'break'
1596
+ * the loop and we are done.
1597
+ */
1598
+ while (1) {
1599
+ QTreeNode *bparent = path[--idx];
1600
+ gboolean left_node = (bparent && node == bparent->left);
1601
+ g_assert(!bparent || bparent->left == node || bparent->right == node);
1602
+
1603
+ if (node->balance < -1 || node->balance > 1) {
1604
+ node = q_tree_node_balance(node);
1605
+ if (bparent == NULL) {
1606
+ tree->root = node;
1607
+ } else if (left_node) {
1608
+ bparent->left = node;
1609
+ } else {
1610
+ bparent->right = node;
1611
+ }
1612
+ }
1613
+
1614
+ if (node->balance == 0 || bparent == NULL) {
1615
+ break;
1616
+ }
1617
+
1618
+ if (left_node) {
1619
+ bparent->balance -= 1;
1620
+ } else {
1621
+ bparent->balance += 1;
1622
+ }
1623
+
1624
+ node = bparent;
1625
+ }
1626
+
1627
+ return retnode;
1628
+}
1629
+
1630
+/**
1631
+ * q_tree_remove:
1632
+ * @tree: a #QTree
1633
+ * @key: the key to remove
1634
+ *
1635
+ * Removes a key/value pair from a #QTree.
1636
+ *
1637
+ * If the #QTree was created using q_tree_new_full(), the key and value
1638
+ * are freed using the supplied destroy functions, otherwise you have to
1639
+ * make sure that any dynamically allocated values are freed yourself.
1640
+ * If the key does not exist in the #QTree, the function does nothing.
1641
+ *
1642
+ * The cost of maintaining a balanced tree while removing a key/value
1643
+ * result in a O(n log(n)) operation where most of the other operations
1644
+ * are O(log(n)).
1645
+ *
1646
+ * Returns: %TRUE if the key was found (prior to 2.8, this function
1647
+ * returned nothing)
1648
+ */
1649
+gboolean
1650
+q_tree_remove(QTree *tree,
1651
+ gconstpointer key)
1652
+{
1653
+ gboolean removed;
1654
+
1655
+ g_return_val_if_fail(tree != NULL, FALSE);
1656
+
1657
+ removed = q_tree_remove_internal(tree, key, FALSE);
1658
+
1659
+#ifdef Q_TREE_DEBUG
1660
+ q_tree_node_check(tree->root);
1661
+#endif
1662
+
1663
+ return removed;
1664
+}
1665
+
1666
+/**
1667
+ * q_tree_steal:
1668
+ * @tree: a #QTree
1669
+ * @key: the key to remove
1670
+ *
1671
+ * Removes a key and its associated value from a #QTree without calling
1672
+ * the key and value destroy functions.
1673
+ *
1674
+ * If the key does not exist in the #QTree, the function does nothing.
1675
+ *
1676
+ * Returns: %TRUE if the key was found (prior to 2.8, this function
1677
+ * returned nothing)
1678
+ */
1679
+gboolean
1680
+q_tree_steal(QTree *tree,
1681
+ gconstpointer key)
1682
+{
1683
+ gboolean removed;
1684
+
1685
+ g_return_val_if_fail(tree != NULL, FALSE);
1686
+
1687
+ removed = q_tree_remove_internal(tree, key, TRUE);
1688
+
1689
+#ifdef Q_TREE_DEBUG
1690
+ q_tree_node_check(tree->root);
1691
+#endif
1692
+
1693
+ return removed;
1694
+}
1695
+
1696
+/* internal remove routine */
1697
+static gboolean
1698
+q_tree_remove_internal(QTree *tree,
1699
+ gconstpointer key,
1700
+ gboolean steal)
1701
+{
1702
+ QTreeNode *node, *parent, *balance;
1703
+ QTreeNode *path[MAX_GTREE_HEIGHT];
1704
+ int idx;
1705
+ gboolean left_node;
1706
+
1707
+ g_return_val_if_fail(tree != NULL, FALSE);
1708
+
1709
+ if (!tree->root) {
1710
+ return FALSE;
1711
+ }
1712
+
1713
+ idx = 0;
1714
+ path[idx++] = NULL;
1715
+ node = tree->root;
1716
+
1717
+ while (1) {
1718
+ int cmp = tree->key_compare(key, node->key, tree->key_compare_data);
1719
+
1720
+ if (cmp == 0) {
1721
+ break;
1722
+ } else if (cmp < 0) {
1723
+ if (!node->left_child) {
1724
+ return FALSE;
1725
+ }
1726
+
1727
+ path[idx++] = node;
1728
+ node = node->left;
1729
+ } else {
1730
+ if (!node->right_child) {
1731
+ return FALSE;
1732
+ }
1733
+
1734
+ path[idx++] = node;
1735
+ node = node->right;
1736
+ }
1737
+ }
1738
+
1739
+ /*
1740
+ * The following code is almost equal to q_tree_remove_node,
1741
+ * except that we do not have to call q_tree_node_parent.
1742
+ */
1743
+ balance = parent = path[--idx];
1744
+ g_assert(!parent || parent->left == node || parent->right == node);
1745
+ left_node = (parent && node == parent->left);
1746
+
1747
+ if (!node->left_child) {
1748
+ if (!node->right_child) {
1749
+ if (!parent) {
1750
+ tree->root = NULL;
1751
+ } else if (left_node) {
1752
+ parent->left_child = FALSE;
1753
+ parent->left = node->left;
1754
+ parent->balance += 1;
1755
+ } else {
1756
+ parent->right_child = FALSE;
1757
+ parent->right = node->right;
1758
+ parent->balance -= 1;
1759
+ }
1760
+ } else {
1761
+ /* node has a right child */
1762
+ QTreeNode *tmp = q_tree_node_next(node);
1763
+ tmp->left = node->left;
1764
+
1765
+ if (!parent) {
1766
+ tree->root = node->right;
1767
+ } else if (left_node) {
1768
+ parent->left = node->right;
1769
+ parent->balance += 1;
1770
+ } else {
1771
+ parent->right = node->right;
1772
+ parent->balance -= 1;
1773
+ }
1774
+ }
40
+ } else {
1775
+ } else {
41
+ insn = OPC_NOP;
1776
+ /* node has a left child */
42
+ }
1777
+ if (!node->right_child) {
43
+ qatomic_set((uint32_t *)jmp_rw, insn);
1778
+ QTreeNode *tmp = q_tree_node_previous(node);
44
+ flush_idcache_range(jmp_rx, jmp_rw, 4);
1779
+ tmp->right = node->right;
45
}
1780
+
46
1781
+ if (parent == NULL) {
47
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
1782
+ tree->root = node->left;
1783
+ } else if (left_node) {
1784
+ parent->left = node->left;
1785
+ parent->balance += 1;
1786
+ } else {
1787
+ parent->right = node->left;
1788
+ parent->balance -= 1;
1789
+ }
1790
+ } else {
1791
+ /* node has a both children (pant, pant!) */
1792
+ QTreeNode *prev = node->left;
1793
+ QTreeNode *next = node->right;
1794
+ QTreeNode *nextp = node;
1795
+ int old_idx = idx + 1;
1796
+ idx++;
1797
+
1798
+ /* path[idx] == parent */
1799
+ /* find the immediately next node (and its parent) */
1800
+ while (next->left_child) {
1801
+ path[++idx] = nextp = next;
1802
+ next = next->left;
1803
+ }
1804
+
1805
+ path[old_idx] = next;
1806
+ balance = path[idx];
1807
+
1808
+ /* remove 'next' from the tree */
1809
+ if (nextp != node) {
1810
+ if (next->right_child) {
1811
+ nextp->left = next->right;
1812
+ } else {
1813
+ nextp->left_child = FALSE;
1814
+ }
1815
+ nextp->balance += 1;
1816
+
1817
+ next->right_child = TRUE;
1818
+ next->right = node->right;
1819
+ } else {
1820
+ node->balance -= 1;
1821
+ }
1822
+
1823
+ /* set the prev to point to the right place */
1824
+ while (prev->right_child) {
1825
+ prev = prev->right;
1826
+ }
1827
+ prev->right = next;
1828
+
1829
+ /* prepare 'next' to replace 'node' */
1830
+ next->left_child = TRUE;
1831
+ next->left = node->left;
1832
+ next->balance = node->balance;
1833
+
1834
+ if (!parent) {
1835
+ tree->root = next;
1836
+ } else if (left_node) {
1837
+ parent->left = next;
1838
+ } else {
1839
+ parent->right = next;
1840
+ }
1841
+ }
1842
+ }
1843
+
1844
+ /* restore balance */
1845
+ if (balance) {
1846
+ while (1) {
1847
+ QTreeNode *bparent = path[--idx];
1848
+ g_assert(!bparent ||
1849
+ bparent->left == balance ||
1850
+ bparent->right == balance);
1851
+ left_node = (bparent && balance == bparent->left);
1852
+
1853
+ if (balance->balance < -1 || balance->balance > 1) {
1854
+ balance = q_tree_node_balance(balance);
1855
+ if (!bparent) {
1856
+ tree->root = balance;
1857
+ } else if (left_node) {
1858
+ bparent->left = balance;
1859
+ } else {
1860
+ bparent->right = balance;
1861
+ }
1862
+ }
1863
+
1864
+ if (balance->balance != 0 || !bparent) {
1865
+ break;
1866
+ }
1867
+
1868
+ if (left_node) {
1869
+ bparent->balance += 1;
1870
+ } else {
1871
+ bparent->balance -= 1;
1872
+ }
1873
+
1874
+ balance = bparent;
1875
+ }
1876
+ }
1877
+
1878
+ if (!steal) {
1879
+ if (tree->key_destroy_func) {
1880
+ tree->key_destroy_func(node->key);
1881
+ }
1882
+ if (tree->value_destroy_func) {
1883
+ tree->value_destroy_func(node->value);
1884
+ }
1885
+ }
1886
+
1887
+ g_free(node);
1888
+
1889
+ tree->nnodes--;
1890
+
1891
+ return TRUE;
1892
+}
1893
+
1894
+/**
1895
+ * q_tree_lookup_node:
1896
+ * @tree: a #QTree
1897
+ * @key: the key to look up
1898
+ *
1899
+ * Gets the tree node corresponding to the given key. Since a #QTree is
1900
+ * automatically balanced as key/value pairs are added, key lookup
1901
+ * is O(log n) (where n is the number of key/value pairs in the tree).
1902
+ *
1903
+ * Returns: (nullable) (transfer none): the tree node corresponding to
1904
+ * the key, or %NULL if the key was not found
1905
+ *
1906
+ * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
1907
+ */
1908
+static QTreeNode *
1909
+q_tree_lookup_node(QTree *tree,
1910
+ gconstpointer key)
1911
+{
1912
+ g_return_val_if_fail(tree != NULL, NULL);
1913
+
1914
+ return q_tree_find_node(tree, key);
1915
+}
1916
+
1917
+/**
1918
+ * q_tree_lookup:
1919
+ * @tree: a #QTree
1920
+ * @key: the key to look up
1921
+ *
1922
+ * Gets the value corresponding to the given key. Since a #QTree is
1923
+ * automatically balanced as key/value pairs are added, key lookup
1924
+ * is O(log n) (where n is the number of key/value pairs in the tree).
1925
+ *
1926
+ * Returns: the value corresponding to the key, or %NULL
1927
+ * if the key was not found
1928
+ */
1929
+gpointer
1930
+q_tree_lookup(QTree *tree,
1931
+ gconstpointer key)
1932
+{
1933
+ QTreeNode *node;
1934
+
1935
+ node = q_tree_lookup_node(tree, key);
1936
+
1937
+ return node ? node->value : NULL;
1938
+}
1939
+
1940
+/**
1941
+ * q_tree_lookup_extended:
1942
+ * @tree: a #QTree
1943
+ * @lookup_key: the key to look up
1944
+ * @orig_key: (out) (optional) (nullable): returns the original key
1945
+ * @value: (out) (optional) (nullable): returns the value associated with
1946
+ * the key
1947
+ *
1948
+ * Looks up a key in the #QTree, returning the original key and the
1949
+ * associated value. This is useful if you need to free the memory
1950
+ * allocated for the original key, for example before calling
1951
+ * q_tree_remove().
1952
+ *
1953
+ * Returns: %TRUE if the key was found in the #QTree
1954
+ */
1955
+gboolean
1956
+q_tree_lookup_extended(QTree *tree,
1957
+ gconstpointer lookup_key,
1958
+ gpointer *orig_key,
1959
+ gpointer *value)
1960
+{
1961
+ QTreeNode *node;
1962
+
1963
+ g_return_val_if_fail(tree != NULL, FALSE);
1964
+
1965
+ node = q_tree_find_node(tree, lookup_key);
1966
+
1967
+ if (node) {
1968
+ if (orig_key) {
1969
+ *orig_key = node->key;
1970
+ }
1971
+ if (value) {
1972
+ *value = node->value;
1973
+ }
1974
+ return TRUE;
1975
+ } else {
1976
+ return FALSE;
1977
+ }
1978
+}
1979
+
1980
+/**
1981
+ * q_tree_foreach:
1982
+ * @tree: a #QTree
1983
+ * @func: the function to call for each node visited.
1984
+ * If this function returns %TRUE, the traversal is stopped.
1985
+ * @user_data: user data to pass to the function
1986
+ *
1987
+ * Calls the given function for each of the key/value pairs in the #QTree.
1988
+ * The function is passed the key and value of each pair, and the given
1989
+ * @data parameter. The tree is traversed in sorted order.
1990
+ *
1991
+ * The tree may not be modified while iterating over it (you can't
1992
+ * add/remove items). To remove all items matching a predicate, you need
1993
+ * to add each item to a list in your #GTraverseFunc as you walk over
1994
+ * the tree, then walk the list and remove each item.
1995
+ */
1996
+void
1997
+q_tree_foreach(QTree *tree,
1998
+ GTraverseFunc func,
1999
+ gpointer user_data)
2000
+{
2001
+ QTreeNode *node;
2002
+
2003
+ g_return_if_fail(tree != NULL);
2004
+
2005
+ if (!tree->root) {
2006
+ return;
2007
+ }
2008
+
2009
+ node = q_tree_node_first(tree);
2010
+
2011
+ while (node) {
2012
+ if ((*func)(node->key, node->value, user_data)) {
2013
+ break;
2014
+ }
2015
+
2016
+ node = q_tree_node_next(node);
2017
+ }
2018
+}
2019
+
2020
+/**
2021
+ * q_tree_search_node:
2022
+ * @tree: a #QTree
2023
+ * @search_func: a function used to search the #QTree
2024
+ * @user_data: the data passed as the second argument to @search_func
2025
+ *
2026
+ * Searches a #QTree using @search_func.
2027
+ *
2028
+ * The @search_func is called with a pointer to the key of a key/value
2029
+ * pair in the tree, and the passed in @user_data. If @search_func returns
2030
+ * 0 for a key/value pair, then the corresponding node is returned as
2031
+ * the result of q_tree_search(). If @search_func returns -1, searching
2032
+ * will proceed among the key/value pairs that have a smaller key; if
2033
+ * @search_func returns 1, searching will proceed among the key/value
2034
+ * pairs that have a larger key.
2035
+ *
2036
+ * Returns: (nullable) (transfer none): the node corresponding to the
2037
+ * found key, or %NULL if the key was not found
2038
+ *
2039
+ * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
2040
+ */
2041
+static QTreeNode *
2042
+q_tree_search_node(QTree *tree,
2043
+ GCompareFunc search_func,
2044
+ gconstpointer user_data)
2045
+{
2046
+ g_return_val_if_fail(tree != NULL, NULL);
2047
+
2048
+ if (!tree->root) {
2049
+ return NULL;
2050
+ }
2051
+
2052
+ return q_tree_node_search(tree->root, search_func, user_data);
2053
+}
2054
+
2055
+/**
2056
+ * q_tree_search:
2057
+ * @tree: a #QTree
2058
+ * @search_func: a function used to search the #QTree
2059
+ * @user_data: the data passed as the second argument to @search_func
2060
+ *
2061
+ * Searches a #QTree using @search_func.
2062
+ *
2063
+ * The @search_func is called with a pointer to the key of a key/value
2064
+ * pair in the tree, and the passed in @user_data. If @search_func returns
2065
+ * 0 for a key/value pair, then the corresponding value is returned as
2066
+ * the result of q_tree_search(). If @search_func returns -1, searching
2067
+ * will proceed among the key/value pairs that have a smaller key; if
2068
+ * @search_func returns 1, searching will proceed among the key/value
2069
+ * pairs that have a larger key.
2070
+ *
2071
+ * Returns: the value corresponding to the found key, or %NULL
2072
+ * if the key was not found
2073
+ */
2074
+gpointer
2075
+q_tree_search(QTree *tree,
2076
+ GCompareFunc search_func,
2077
+ gconstpointer user_data)
2078
+{
2079
+ QTreeNode *node;
2080
+
2081
+ node = q_tree_search_node(tree, search_func, user_data);
2082
+
2083
+ return node ? node->value : NULL;
2084
+}
2085
+
2086
+/**
2087
+ * q_tree_height:
2088
+ * @tree: a #QTree
2089
+ *
2090
+ * Gets the height of a #QTree.
2091
+ *
2092
+ * If the #QTree contains no nodes, the height is 0.
2093
+ * If the #QTree contains only one root node the height is 1.
2094
+ * If the root node has children the height is 2, etc.
2095
+ *
2096
+ * Returns: the height of @tree
2097
+ */
2098
+gint
2099
+q_tree_height(QTree *tree)
2100
+{
2101
+ QTreeNode *node;
2102
+ gint height;
2103
+
2104
+ g_return_val_if_fail(tree != NULL, 0);
2105
+
2106
+ if (!tree->root) {
2107
+ return 0;
2108
+ }
2109
+
2110
+ height = 0;
2111
+ node = tree->root;
2112
+
2113
+ while (1) {
2114
+ height += 1 + MAX(node->balance, 0);
2115
+
2116
+ if (!node->left_child) {
2117
+ return height;
2118
+ }
2119
+
2120
+ node = node->left;
2121
+ }
2122
+}
2123
+
2124
+/**
2125
+ * q_tree_nnodes:
2126
+ * @tree: a #QTree
2127
+ *
2128
+ * Gets the number of nodes in a #QTree.
2129
+ *
2130
+ * Returns: the number of nodes in @tree
2131
+ */
2132
+gint
2133
+q_tree_nnodes(QTree *tree)
2134
+{
2135
+ g_return_val_if_fail(tree != NULL, 0);
2136
+
2137
+ return tree->nnodes;
2138
+}
2139
+
2140
+static QTreeNode *
2141
+q_tree_node_balance(QTreeNode *node)
2142
+{
2143
+ if (node->balance < -1) {
2144
+ if (node->left->balance > 0) {
2145
+ node->left = q_tree_node_rotate_left(node->left);
2146
+ }
2147
+ node = q_tree_node_rotate_right(node);
2148
+ } else if (node->balance > 1) {
2149
+ if (node->right->balance < 0) {
2150
+ node->right = q_tree_node_rotate_right(node->right);
2151
+ }
2152
+ node = q_tree_node_rotate_left(node);
2153
+ }
2154
+
2155
+ return node;
2156
+}
2157
+
2158
+static QTreeNode *
2159
+q_tree_find_node(QTree *tree,
2160
+ gconstpointer key)
2161
+{
2162
+ QTreeNode *node;
2163
+ gint cmp;
2164
+
2165
+ node = tree->root;
2166
+ if (!node) {
2167
+ return NULL;
2168
+ }
2169
+
2170
+ while (1) {
2171
+ cmp = tree->key_compare(key, node->key, tree->key_compare_data);
2172
+ if (cmp == 0) {
2173
+ return node;
2174
+ } else if (cmp < 0) {
2175
+ if (!node->left_child) {
2176
+ return NULL;
2177
+ }
2178
+
2179
+ node = node->left;
2180
+ } else {
2181
+ if (!node->right_child) {
2182
+ return NULL;
2183
+ }
2184
+
2185
+ node = node->right;
2186
+ }
2187
+ }
2188
+}
2189
+
2190
+static QTreeNode *
2191
+q_tree_node_search(QTreeNode *node,
2192
+ GCompareFunc search_func,
2193
+ gconstpointer data)
2194
+{
2195
+ gint dir;
2196
+
2197
+ if (!node) {
2198
+ return NULL;
2199
+ }
2200
+
2201
+ while (1) {
2202
+ dir = (*search_func)(node->key, data);
2203
+ if (dir == 0) {
2204
+ return node;
2205
+ } else if (dir < 0) {
2206
+ if (!node->left_child) {
2207
+ return NULL;
2208
+ }
2209
+
2210
+ node = node->left;
2211
+ } else {
2212
+ if (!node->right_child) {
2213
+ return NULL;
2214
+ }
2215
+
2216
+ node = node->right;
2217
+ }
2218
+ }
2219
+}
2220
+
2221
+static QTreeNode *
2222
+q_tree_node_rotate_left(QTreeNode *node)
2223
+{
2224
+ QTreeNode *right;
2225
+ gint a_bal;
2226
+ gint b_bal;
2227
+
2228
+ right = node->right;
2229
+
2230
+ if (right->left_child) {
2231
+ node->right = right->left;
2232
+ } else {
2233
+ node->right_child = FALSE;
2234
+ right->left_child = TRUE;
2235
+ }
2236
+ right->left = node;
2237
+
2238
+ a_bal = node->balance;
2239
+ b_bal = right->balance;
2240
+
2241
+ if (b_bal <= 0) {
2242
+ if (a_bal >= 1) {
2243
+ right->balance = b_bal - 1;
2244
+ } else {
2245
+ right->balance = a_bal + b_bal - 2;
2246
+ }
2247
+ node->balance = a_bal - 1;
2248
+ } else {
2249
+ if (a_bal <= b_bal) {
2250
+ right->balance = a_bal - 2;
2251
+ } else {
2252
+ right->balance = b_bal - 1;
2253
+ }
2254
+ node->balance = a_bal - b_bal - 1;
2255
+ }
2256
+
2257
+ return right;
2258
+}
2259
+
2260
+static QTreeNode *
2261
+q_tree_node_rotate_right(QTreeNode *node)
2262
+{
2263
+ QTreeNode *left;
2264
+ gint a_bal;
2265
+ gint b_bal;
2266
+
2267
+ left = node->left;
2268
+
2269
+ if (left->right_child) {
2270
+ node->left = left->right;
2271
+ } else {
2272
+ node->left_child = FALSE;
2273
+ left->right_child = TRUE;
2274
+ }
2275
+ left->right = node;
2276
+
2277
+ a_bal = node->balance;
2278
+ b_bal = left->balance;
2279
+
2280
+ if (b_bal <= 0) {
2281
+ if (b_bal > a_bal) {
2282
+ left->balance = b_bal + 1;
2283
+ } else {
2284
+ left->balance = a_bal + 2;
2285
+ }
2286
+ node->balance = a_bal - b_bal + 1;
2287
+ } else {
2288
+ if (a_bal <= -1) {
2289
+ left->balance = b_bal + 1;
2290
+ } else {
2291
+ left->balance = a_bal + b_bal + 2;
2292
+ }
2293
+ node->balance = a_bal + 1;
2294
+ }
2295
+
2296
+ return left;
2297
+}
2298
+
2299
+#ifdef Q_TREE_DEBUG
2300
+static gint
2301
+q_tree_node_height(QTreeNode *node)
2302
+{
2303
+ gint left_height;
2304
+ gint right_height;
2305
+
2306
+ if (node) {
2307
+ left_height = 0;
2308
+ right_height = 0;
2309
+
2310
+ if (node->left_child) {
2311
+ left_height = q_tree_node_height(node->left);
2312
+ }
2313
+
2314
+ if (node->right_child) {
2315
+ right_height = q_tree_node_height(node->right);
2316
+ }
2317
+
2318
+ return MAX(left_height, right_height) + 1;
2319
+ }
2320
+
2321
+ return 0;
2322
+}
2323
+
2324
+static void q_tree_node_check(QTreeNode *node)
2325
+{
2326
+ gint left_height;
2327
+ gint right_height;
2328
+ gint balance;
2329
+ QTreeNode *tmp;
2330
+
2331
+ if (node) {
2332
+ if (node->left_child) {
2333
+ tmp = q_tree_node_previous(node);
2334
+ g_assert(tmp->right == node);
2335
+ }
2336
+
2337
+ if (node->right_child) {
2338
+ tmp = q_tree_node_next(node);
2339
+ g_assert(tmp->left == node);
2340
+ }
2341
+
2342
+ left_height = 0;
2343
+ right_height = 0;
2344
+
2345
+ if (node->left_child) {
2346
+ left_height = q_tree_node_height(node->left);
2347
+ }
2348
+ if (node->right_child) {
2349
+ right_height = q_tree_node_height(node->right);
2350
+ }
2351
+
2352
+ balance = right_height - left_height;
2353
+ g_assert(balance == node->balance);
2354
+
2355
+ if (node->left_child) {
2356
+ q_tree_node_check(node->left);
2357
+ }
2358
+ if (node->right_child) {
2359
+ q_tree_node_check(node->right);
2360
+ }
2361
+ }
2362
+}
2363
+#endif
2364
diff --git a/tests/bench/meson.build b/tests/bench/meson.build
2365
index XXXXXXX..XXXXXXX 100644
2366
--- a/tests/bench/meson.build
2367
+++ b/tests/bench/meson.build
2368
@@ -XXX,XX +XXX,XX @@ xbzrle_bench = executable('xbzrle-bench',
2369
dependencies: [qemuutil,migration])
2370
endif
2371
2372
+qtree_bench = executable('qtree-bench',
2373
+ sources: 'qtree-bench.c',
2374
+ dependencies: [qemuutil])
2375
+
2376
executable('atomic_add-bench',
2377
sources: files('atomic_add-bench.c'),
2378
dependencies: [qemuutil],
2379
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
2380
index XXXXXXX..XXXXXXX 100644
2381
--- a/tests/unit/meson.build
2382
+++ b/tests/unit/meson.build
2383
@@ -XXX,XX +XXX,XX @@ tests = {
2384
'test-rcu-slist': [],
2385
'test-qdist': [],
2386
'test-qht': [],
2387
+ 'test-qtree': [],
2388
'test-bitops': [],
2389
'test-bitcnt': [],
2390
'test-qgraph': ['../qtest/libqos/qgraph.c'],
2391
diff --git a/util/meson.build b/util/meson.build
2392
index XXXXXXX..XXXXXXX 100644
2393
--- a/util/meson.build
2394
+++ b/util/meson.build
2395
@@ -XXX,XX +XXX,XX @@ util_ss.add(when: 'CONFIG_WIN32', if_true: files('oslib-win32.c'))
2396
util_ss.add(when: 'CONFIG_WIN32', if_true: files('qemu-thread-win32.c'))
2397
util_ss.add(when: 'CONFIG_WIN32', if_true: winmm)
2398
util_ss.add(when: 'CONFIG_WIN32', if_true: pathcch)
2399
+util_ss.add(when: 'HAVE_GLIB_WITH_SLICE_ALLOCATOR', if_true: files('qtree.c'))
2400
util_ss.add(files('envlist.c', 'path.c', 'module.c'))
2401
util_ss.add(files('host-utils.c'))
2402
util_ss.add(files('bitmap.c', 'bitops.c'))
48
--
2403
--
49
2.34.1
2404
2.34.1
50
2405
51
2406
diff view generated by jsdifflib
1
The old ppc64 implementation replaces 2 or 4 insns, which leaves a race
1
From: Emilio Cota <cota@braap.org>
2
condition in which a thread could be stopped at a PC in the middle of
2
3
the sequence, and when restarted does not see the complete address
3
qemu-user can hang in a multi-threaded fork. One common
4
computation and branches to nowhere.
4
reason is that when creating a TB, between fork and exec
5
5
we manipulate a GTree whose memory allocator (GSlice) is
6
The new implemetation replaces only one insn, swapping between
6
not fork-safe.
7
7
8
    b <dest>
8
Although POSIX does not mandate it, the system's allocator
9
and
9
(e.g. tcmalloc, libc malloc) is probably fork-safe.
10
    mtctr    r31
10
11
11
Fix some of these hangs by using QTree, which uses the system's
12
falling through to a general-case indirect branch.
12
allocator regardless of the Glib version that we used at
13
13
configuration time.
14
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
14
15
Tested with the test program in the original bug report, i.e.:
16
```
17
18
void garble() {
19
int pid = fork();
20
if (pid == 0) {
21
exit(0);
22
} else {
23
int wstatus;
24
waitpid(pid, &wstatus, 0);
25
}
26
}
27
28
void supragarble(unsigned depth) {
29
if (depth == 0)
30
return ;
31
32
std::thread a(supragarble, depth-1);
33
std::thread b(supragarble, depth-1);
34
garble();
35
a.join();
36
b.join();
37
}
38
39
int main() {
40
supragarble(10);
41
}
42
```
43
44
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/285
45
Reported-by: Valentin David <me@valentindavid.com>
46
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
47
Signed-off-by: Emilio Cota <cota@braap.org>
48
Message-Id: <20230205163758.416992-3-cota@braap.org>
49
[rth: Add QEMU_DISABLE_CFI for all callback using functions.]
15
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
50
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
16
---
51
---
17
tcg/ppc/tcg-target.h | 3 +-
52
accel/tcg/tb-maint.c | 17 +++++++++--------
18
tcg/ppc/tcg-target.c.inc | 158 +++++++++++----------------------------
53
tcg/region.c | 19 ++++++++++---------
19
2 files changed, 44 insertions(+), 117 deletions(-)
54
util/qtree.c | 8 ++++----
20
55
3 files changed, 23 insertions(+), 21 deletions(-)
21
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
56
57
diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c
22
index XXXXXXX..XXXXXXX 100644
58
index XXXXXXX..XXXXXXX 100644
23
--- a/tcg/ppc/tcg-target.h
59
--- a/accel/tcg/tb-maint.c
24
+++ b/tcg/ppc/tcg-target.h
60
+++ b/accel/tcg/tb-maint.c
25
@@ -XXX,XX +XXX,XX @@
61
@@ -XXX,XX +XXX,XX @@
26
62
27
#ifdef _ARCH_PPC64
63
#include "qemu/osdep.h"
28
# define TCG_TARGET_REG_BITS 64
64
#include "qemu/interval-tree.h"
29
-# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
65
+#include "qemu/qtree.h"
30
#else
66
#include "exec/cputlb.h"
31
# define TCG_TARGET_REG_BITS 32
67
#include "exec/log.h"
32
-# define MAX_CODE_GEN_BUFFER_SIZE (32 * MiB)
68
#include "exec/exec-all.h"
33
#endif
69
@@ -XXX,XX +XXX,XX @@ struct page_entry {
34
+#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
70
* See also: page_collection_lock().
35
71
*/
36
#define TCG_TARGET_NB_REGS 64
72
struct page_collection {
37
#define TCG_TARGET_INSN_UNIT_SIZE 4
73
- GTree *tree;
38
diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
74
+ QTree *tree;
75
struct page_entry *max;
76
};
77
78
@@ -XXX,XX +XXX,XX @@ static bool page_trylock_add(struct page_collection *set, tb_page_addr_t addr)
79
struct page_entry *pe;
80
PageDesc *pd;
81
82
- pe = g_tree_lookup(set->tree, &index);
83
+ pe = q_tree_lookup(set->tree, &index);
84
if (pe) {
85
return false;
86
}
87
@@ -XXX,XX +XXX,XX @@ static bool page_trylock_add(struct page_collection *set, tb_page_addr_t addr)
88
}
89
90
pe = page_entry_new(pd, index);
91
- g_tree_insert(set->tree, &pe->index, pe);
92
+ q_tree_insert(set->tree, &pe->index, pe);
93
94
/*
95
* If this is either (1) the first insertion or (2) a page whose index
96
@@ -XXX,XX +XXX,XX @@ static struct page_collection *page_collection_lock(tb_page_addr_t start,
97
end >>= TARGET_PAGE_BITS;
98
g_assert(start <= end);
99
100
- set->tree = g_tree_new_full(tb_page_addr_cmp, NULL, NULL,
101
+ set->tree = q_tree_new_full(tb_page_addr_cmp, NULL, NULL,
102
page_entry_destroy);
103
set->max = NULL;
104
assert_no_pages_locked();
105
106
retry:
107
- g_tree_foreach(set->tree, page_entry_lock, NULL);
108
+ q_tree_foreach(set->tree, page_entry_lock, NULL);
109
110
for (index = start; index <= end; index++) {
111
TranslationBlock *tb;
112
@@ -XXX,XX +XXX,XX @@ static struct page_collection *page_collection_lock(tb_page_addr_t start,
113
continue;
114
}
115
if (page_trylock_add(set, index << TARGET_PAGE_BITS)) {
116
- g_tree_foreach(set->tree, page_entry_unlock, NULL);
117
+ q_tree_foreach(set->tree, page_entry_unlock, NULL);
118
goto retry;
119
}
120
assert_page_locked(pd);
121
@@ -XXX,XX +XXX,XX @@ static struct page_collection *page_collection_lock(tb_page_addr_t start,
122
(tb_page_addr1(tb) != -1 &&
123
page_trylock_add(set, tb_page_addr1(tb)))) {
124
/* drop all locks, and reacquire in order */
125
- g_tree_foreach(set->tree, page_entry_unlock, NULL);
126
+ q_tree_foreach(set->tree, page_entry_unlock, NULL);
127
goto retry;
128
}
129
}
130
@@ -XXX,XX +XXX,XX @@ static struct page_collection *page_collection_lock(tb_page_addr_t start,
131
static void page_collection_unlock(struct page_collection *set)
132
{
133
/* entries are unlocked and freed via page_entry_destroy */
134
- g_tree_destroy(set->tree);
135
+ q_tree_destroy(set->tree);
136
g_free(set);
137
}
138
139
diff --git a/tcg/region.c b/tcg/region.c
39
index XXXXXXX..XXXXXXX 100644
140
index XXXXXXX..XXXXXXX 100644
40
--- a/tcg/ppc/tcg-target.c.inc
141
--- a/tcg/region.c
41
+++ b/tcg/ppc/tcg-target.c.inc
142
+++ b/tcg/region.c
42
@@ -XXX,XX +XXX,XX @@ static void tcg_out_mb(TCGContext *s, TCGArg a0)
143
@@ -XXX,XX +XXX,XX @@
43
tcg_out32(s, insn);
144
#include "qemu/mprotect.h"
44
}
145
#include "qemu/memalign.h"
45
146
#include "qemu/cacheinfo.h"
46
-static inline uint64_t make_pair(tcg_insn_unit i1, tcg_insn_unit i2)
147
+#include "qemu/qtree.h"
47
-{
148
#include "qapi/error.h"
48
- if (HOST_BIG_ENDIAN) {
149
#include "exec/exec-all.h"
49
- return (uint64_t)i1 << 32 | i2;
150
#include "tcg/tcg.h"
50
- }
151
@@ -XXX,XX +XXX,XX @@
51
- return (uint64_t)i2 << 32 | i1;
152
52
-}
153
struct tcg_region_tree {
53
-
154
QemuMutex lock;
54
-static inline void ppc64_replace2(uintptr_t rx, uintptr_t rw,
155
- GTree *tree;
55
- tcg_insn_unit i0, tcg_insn_unit i1)
156
+ QTree *tree;
56
-{
157
/* padding to avoid false sharing is computed at run-time */
57
-#if TCG_TARGET_REG_BITS == 64
158
};
58
- qatomic_set((uint64_t *)rw, make_pair(i0, i1));
159
59
- flush_idcache_range(rx, rw, 8);
160
@@ -XXX,XX +XXX,XX @@ static void tcg_region_trees_init(void)
60
-#else
161
struct tcg_region_tree *rt = region_trees + i * tree_size;
61
- qemu_build_not_reached();
162
62
-#endif
163
qemu_mutex_init(&rt->lock);
63
-}
164
- rt->tree = g_tree_new_full(tb_tc_cmp, NULL, NULL, tb_destroy);
64
-
165
+ rt->tree = q_tree_new_full(tb_tc_cmp, NULL, NULL, tb_destroy);
65
-static inline void ppc64_replace4(uintptr_t rx, uintptr_t rw,
166
}
66
- tcg_insn_unit i0, tcg_insn_unit i1,
167
}
67
- tcg_insn_unit i2, tcg_insn_unit i3)
168
68
-{
169
@@ -XXX,XX +XXX,XX @@ void tcg_tb_insert(TranslationBlock *tb)
69
- uint64_t p[2];
170
70
-
171
g_assert(rt != NULL);
71
- p[!HOST_BIG_ENDIAN] = make_pair(i0, i1);
172
qemu_mutex_lock(&rt->lock);
72
- p[HOST_BIG_ENDIAN] = make_pair(i2, i3);
173
- g_tree_insert(rt->tree, &tb->tc, tb);
73
-
174
+ q_tree_insert(rt->tree, &tb->tc, tb);
74
- /*
175
qemu_mutex_unlock(&rt->lock);
75
- * There's no convenient way to get the compiler to allocate a pair
176
}
76
- * of registers at an even index, so copy into r6/r7 and clobber.
177
77
- */
178
@@ -XXX,XX +XXX,XX @@ void tcg_tb_remove(TranslationBlock *tb)
78
- asm("mr %%r6, %1\n\t"
179
79
- "mr %%r7, %2\n\t"
180
g_assert(rt != NULL);
80
- "stq %%r6, %0"
181
qemu_mutex_lock(&rt->lock);
81
- : "=Q"(*(__int128 *)rw) : "r"(p[0]), "r"(p[1]) : "r6", "r7");
182
- g_tree_remove(rt->tree, &tb->tc);
82
- flush_idcache_range(rx, rw, 16);
183
+ q_tree_remove(rt->tree, &tb->tc);
83
-}
184
qemu_mutex_unlock(&rt->lock);
84
-
185
}
85
-void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
186
86
- uintptr_t jmp_rx, uintptr_t jmp_rw)
187
@@ -XXX,XX +XXX,XX @@ TranslationBlock *tcg_tb_lookup(uintptr_t tc_ptr)
87
-{
188
}
88
- tcg_insn_unit i0, i1, i2, i3;
189
89
- uintptr_t addr = tb->jmp_target_addr[n];
190
qemu_mutex_lock(&rt->lock);
90
- intptr_t tb_diff = addr - (uintptr_t)tb->tc.ptr;
191
- tb = g_tree_lookup(rt->tree, &s);
91
- intptr_t br_diff = addr - (jmp_rx + 4);
192
+ tb = q_tree_lookup(rt->tree, &s);
92
- intptr_t lo, hi;
193
qemu_mutex_unlock(&rt->lock);
93
-
194
return tb;
94
- if (TCG_TARGET_REG_BITS == 32) {
195
}
95
- intptr_t diff = addr - jmp_rx;
196
@@ -XXX,XX +XXX,XX @@ void tcg_tb_foreach(GTraverseFunc func, gpointer user_data)
96
- tcg_debug_assert(in_range_b(diff));
197
for (i = 0; i < region.n; i++) {
97
- qatomic_set((uint32_t *)jmp_rw, B | (diff & 0x3fffffc));
198
struct tcg_region_tree *rt = region_trees + i * tree_size;
98
- flush_idcache_range(jmp_rx, jmp_rw, 4);
199
99
- return;
200
- g_tree_foreach(rt->tree, func, user_data);
100
- }
201
+ q_tree_foreach(rt->tree, func, user_data);
101
-
202
}
102
- /*
203
tcg_region_tree_unlock_all();
103
- * For 16-bit displacements, we can use a single add + branch.
204
}
104
- * This happens quite often.
205
@@ -XXX,XX +XXX,XX @@ size_t tcg_nb_tbs(void)
105
- */
206
for (i = 0; i < region.n; i++) {
106
- if (tb_diff == (int16_t)tb_diff) {
207
struct tcg_region_tree *rt = region_trees + i * tree_size;
107
- i0 = ADDI | TAI(TCG_REG_TB, TCG_REG_TB, tb_diff);
208
108
- i1 = B | (br_diff & 0x3fffffc);
209
- nb_tbs += g_tree_nnodes(rt->tree);
109
- ppc64_replace2(jmp_rx, jmp_rw, i0, i1);
210
+ nb_tbs += q_tree_nnodes(rt->tree);
110
- return;
211
}
111
- }
212
tcg_region_tree_unlock_all();
112
-
213
return nb_tbs;
113
- lo = (int16_t)tb_diff;
214
@@ -XXX,XX +XXX,XX @@ static void tcg_region_tree_reset_all(void)
114
- hi = (int32_t)(tb_diff - lo);
215
struct tcg_region_tree *rt = region_trees + i * tree_size;
115
- assert(tb_diff == hi + lo);
216
116
- i0 = ADDIS | TAI(TCG_REG_TB, TCG_REG_TB, hi >> 16);
217
/* Increment the refcount first so that destroy acts as a reset */
117
- i1 = ADDI | TAI(TCG_REG_TB, TCG_REG_TB, lo);
218
- g_tree_ref(rt->tree);
118
-
219
- g_tree_destroy(rt->tree);
119
- /*
220
+ q_tree_ref(rt->tree);
120
- * Without stq from 2.07, we can only update two insns,
221
+ q_tree_destroy(rt->tree);
121
- * and those must be the ones that load the target address.
222
}
122
- */
223
tcg_region_tree_unlock_all();
123
- if (!have_isa_2_07) {
224
}
124
- ppc64_replace2(jmp_rx, jmp_rw, i0, i1);
225
diff --git a/util/qtree.c b/util/qtree.c
125
- return;
226
index XXXXXXX..XXXXXXX 100644
126
- }
227
--- a/util/qtree.c
127
-
228
+++ b/util/qtree.c
128
- /*
229
@@ -XXX,XX +XXX,XX @@ q_tree_node_next(QTreeNode *node)
129
- * For 26-bit displacements, we can use a direct branch.
230
*
130
- * Otherwise we still need the indirect branch, which we
231
* Since: 2.70 in GLib. Internal in Qtree, i.e. not in the public API.
131
- * must restore after a potential direct branch write.
232
*/
132
- */
233
-static void
133
- br_diff -= 4;
234
+static void QEMU_DISABLE_CFI
134
- if (in_range_b(br_diff)) {
235
q_tree_remove_all(QTree *tree)
135
- i2 = B | (br_diff & 0x3fffffc);
136
- i3 = NOP;
137
- } else {
138
- i2 = MTSPR | RS(TCG_REG_TB) | CTR;
139
- i3 = BCCTR | BO_ALWAYS;
140
- }
141
- ppc64_replace4(jmp_rx, jmp_rw, i0, i1, i2, i3);
142
-}
143
-
144
static void tcg_out_call_int(TCGContext *s, int lk,
145
const tcg_insn_unit *target)
146
{
236
{
147
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg)
237
QTreeNode *node;
148
238
@@ -XXX,XX +XXX,XX @@ q_tree_replace(QTree *tree,
149
static void tcg_out_goto_tb(TCGContext *s, int which)
239
}
240
241
/* internal insert routine */
242
-static QTreeNode *
243
+static QTreeNode * QEMU_DISABLE_CFI
244
q_tree_insert_internal(QTree *tree,
245
gpointer key,
246
gpointer value,
247
@@ -XXX,XX +XXX,XX @@ q_tree_steal(QTree *tree,
248
}
249
250
/* internal remove routine */
251
-static gboolean
252
+static gboolean QEMU_DISABLE_CFI
253
q_tree_remove_internal(QTree *tree,
254
gconstpointer key,
255
gboolean steal)
256
@@ -XXX,XX +XXX,XX @@ q_tree_node_balance(QTreeNode *node)
257
return node;
258
}
259
260
-static QTreeNode *
261
+static QTreeNode * QEMU_DISABLE_CFI
262
q_tree_find_node(QTree *tree,
263
gconstpointer key)
150
{
264
{
151
- /* Direct jump. */
152
- if (TCG_TARGET_REG_BITS == 64) {
153
- /* Ensure the next insns are 8 or 16-byte aligned. */
154
- while ((uintptr_t)s->code_ptr & (have_isa_2_07 ? 15 : 7)) {
155
- tcg_out32(s, NOP);
156
- }
157
+ uintptr_t ptr = get_jmp_target_addr(s, which);
158
+
159
+ if (USE_REG_TB) {
160
+ ptrdiff_t offset = tcg_tbrel_diff(s, (void *)ptr);
161
+ tcg_out_mem_long(s, LD, LDX, TCG_REG_TB, TCG_REG_TB, offset);
162
+
163
+ /* Direct branch will be patched by tb_target_set_jmp_target. */
164
set_jmp_insn_offset(s, which);
165
- tcg_out32(s, ADDIS | TAI(TCG_REG_TB, TCG_REG_TB, 0));
166
- tcg_out32(s, ADDI | TAI(TCG_REG_TB, TCG_REG_TB, 0));
167
tcg_out32(s, MTSPR | RS(TCG_REG_TB) | CTR);
168
+
169
+ /* When branch is out of range, fall through to indirect. */
170
+ tcg_out32(s, BCCTR | BO_ALWAYS);
171
+
172
+ /* For the unlinked case, need to reset TCG_REG_TB. */
173
+ set_jmp_reset_offset(s, which);
174
+ tcg_out_mem_long(s, ADDI, ADD, TCG_REG_TB, TCG_REG_TB,
175
+ -tcg_current_code_size(s));
176
+ } else {
177
+ /* Direct branch will be patched by tb_target_set_jmp_target. */
178
+ set_jmp_insn_offset(s, which);
179
+ tcg_out32(s, NOP);
180
+
181
+ /* When branch is out of range, fall through to indirect. */
182
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP1, ptr - (int16_t)ptr);
183
+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_REG_TMP1, (int16_t)ptr);
184
+ tcg_out32(s, MTSPR | RS(TCG_REG_TMP1) | CTR);
185
tcg_out32(s, BCCTR | BO_ALWAYS);
186
set_jmp_reset_offset(s, which);
187
- if (USE_REG_TB) {
188
- /* For the unlinked case, need to reset TCG_REG_TB. */
189
- tcg_out_mem_long(s, ADDI, ADD, TCG_REG_TB, TCG_REG_TB,
190
- -tcg_current_code_size(s));
191
- }
192
- } else {
193
- set_jmp_insn_offset(s, which);
194
- tcg_out32(s, B);
195
- set_jmp_reset_offset(s, which);
196
}
197
}
198
199
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
200
+ uintptr_t jmp_rx, uintptr_t jmp_rw)
201
+{
202
+ uintptr_t addr = tb->jmp_target_addr[n];
203
+ intptr_t diff = addr - jmp_rx;
204
+ tcg_insn_unit insn;
205
+
206
+ if (in_range_b(diff)) {
207
+ insn = B | (diff & 0x3fffffc);
208
+ } else if (USE_REG_TB) {
209
+ insn = MTSPR | RS(TCG_REG_TB) | CTR;
210
+ } else {
211
+ insn = NOP;
212
+ }
213
+
214
+ qatomic_set((uint32_t *)jmp_rw, insn);
215
+ flush_idcache_range(jmp_rx, jmp_rw, 4);
216
+}
217
+
218
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
219
const TCGArg args[TCG_MAX_OP_ARGS],
220
const int const_args[TCG_MAX_OP_ARGS])
221
--
265
--
222
2.34.1
266
2.34.1
223
267
224
268
diff view generated by jsdifflib
1
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
1
We have been enforcing host page alignment for the non-R
2
fallback of MAX_RESERVED_VA, but failing to enforce for -R.
3
2
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
4
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
3
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
---
6
---
5
include/tcg/tcg.h | 3 +++
7
linux-user/main.c | 6 ++++++
6
tcg/aarch64/tcg-target.h | 4 ----
8
1 file changed, 6 insertions(+)
7
tcg/arm/tcg-target.h | 5 -----
8
tcg/i386/tcg-target.h | 3 ---
9
tcg/loongarch64/tcg-target.h | 3 ---
10
tcg/mips/tcg-target.h | 5 -----
11
tcg/ppc/tcg-target.h | 4 ----
12
tcg/riscv/tcg-target.h | 4 ----
13
tcg/s390x/tcg-target.h | 4 ----
14
tcg/sparc64/tcg-target.h | 4 ----
15
tcg/tci/tcg-target.h | 4 ----
16
11 files changed, 3 insertions(+), 40 deletions(-)
17
9
18
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
10
diff --git a/linux-user/main.c b/linux-user/main.c
19
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
20
--- a/include/tcg/tcg.h
12
--- a/linux-user/main.c
21
+++ b/include/tcg/tcg.h
13
+++ b/linux-user/main.c
22
@@ -XXX,XX +XXX,XX @@ void tcg_func_start(TCGContext *s);
14
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
23
15
*/
24
int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start);
16
max_reserved_va = MAX_RESERVED_VA(cpu);
25
17
if (reserved_va != 0) {
26
+void tb_target_set_jmp_target(const TranslationBlock *, int,
18
+ if (reserved_va % qemu_host_page_size) {
27
+ uintptr_t, uintptr_t);
19
+ char *s = size_to_str(qemu_host_page_size);
28
+
20
+ fprintf(stderr, "Reserved virtual address not aligned mod %s\n", s);
29
void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size);
21
+ g_free(s);
30
22
+ exit(EXIT_FAILURE);
31
TCGTemp *tcg_global_mem_new_internal(TCGType, TCGv_ptr,
23
+ }
32
diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
24
if (max_reserved_va && reserved_va > max_reserved_va) {
33
index XXXXXXX..XXXXXXX 100644
25
fprintf(stderr, "Reserved virtual address too big\n");
34
--- a/tcg/aarch64/tcg-target.h
26
exit(EXIT_FAILURE);
35
+++ b/tcg/aarch64/tcg-target.h
36
@@ -XXX,XX +XXX,XX @@ typedef enum {
37
38
#define TCG_TARGET_DEFAULT_MO (0)
39
#define TCG_TARGET_HAS_MEMORY_BSWAP 0
40
-
41
-void tb_target_set_jmp_target(const TranslationBlock *, int,
42
- uintptr_t, uintptr_t);
43
-
44
#define TCG_TARGET_NEED_LDST_LABELS
45
#define TCG_TARGET_NEED_POOL_LABELS
46
47
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
48
index XXXXXXX..XXXXXXX 100644
49
--- a/tcg/arm/tcg-target.h
50
+++ b/tcg/arm/tcg-target.h
51
@@ -XXX,XX +XXX,XX @@ extern bool use_neon_instructions;
52
53
#define TCG_TARGET_DEFAULT_MO (0)
54
#define TCG_TARGET_HAS_MEMORY_BSWAP 0
55
-
56
-/* not defined -- call should be eliminated at compile time */
57
-void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
58
- uintptr_t, uintptr_t);
59
-
60
#define TCG_TARGET_NEED_LDST_LABELS
61
#define TCG_TARGET_NEED_POOL_LABELS
62
63
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
64
index XXXXXXX..XXXXXXX 100644
65
--- a/tcg/i386/tcg-target.h
66
+++ b/tcg/i386/tcg-target.h
67
@@ -XXX,XX +XXX,XX @@ extern bool have_movbe;
68
#define TCG_TARGET_extract_i64_valid(ofs, len) \
69
(((ofs) == 8 && (len) == 8) || ((ofs) + (len)) == 32)
70
71
-void tb_target_set_jmp_target(const TranslationBlock *, int,
72
- uintptr_t, uintptr_t);
73
-
74
/* This defines the natural memory order supported by this
75
* architecture before guarantees made by various barrier
76
* instructions.
77
diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h
78
index XXXXXXX..XXXXXXX 100644
79
--- a/tcg/loongarch64/tcg-target.h
80
+++ b/tcg/loongarch64/tcg-target.h
81
@@ -XXX,XX +XXX,XX @@ typedef enum {
82
#define TCG_TARGET_HAS_muluh_i64 1
83
#define TCG_TARGET_HAS_mulsh_i64 1
84
85
-void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
86
- uintptr_t, uintptr_t);
87
-
88
#define TCG_TARGET_DEFAULT_MO (0)
89
90
#define TCG_TARGET_NEED_LDST_LABELS
91
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
92
index XXXXXXX..XXXXXXX 100644
93
--- a/tcg/mips/tcg-target.h
94
+++ b/tcg/mips/tcg-target.h
95
@@ -XXX,XX +XXX,XX @@ extern bool use_mips32r2_instructions;
96
#define TCG_TARGET_DEFAULT_MO (0)
97
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
98
99
-/* not defined -- call should be eliminated at compile time */
100
-void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
101
- uintptr_t, uintptr_t)
102
- QEMU_ERROR("code path is reachable");
103
-
104
#define TCG_TARGET_NEED_LDST_LABELS
105
106
#endif
107
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
108
index XXXXXXX..XXXXXXX 100644
109
--- a/tcg/ppc/tcg-target.h
110
+++ b/tcg/ppc/tcg-target.h
111
@@ -XXX,XX +XXX,XX @@ extern bool have_vsx;
112
#define TCG_TARGET_HAS_bitsel_vec have_vsx
113
#define TCG_TARGET_HAS_cmpsel_vec 0
114
115
-void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
116
- uintptr_t, uintptr_t);
117
-
118
#define TCG_TARGET_DEFAULT_MO (0)
119
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
120
-
121
#define TCG_TARGET_NEED_LDST_LABELS
122
#define TCG_TARGET_NEED_POOL_LABELS
123
124
diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h
125
index XXXXXXX..XXXXXXX 100644
126
--- a/tcg/riscv/tcg-target.h
127
+++ b/tcg/riscv/tcg-target.h
128
@@ -XXX,XX +XXX,XX @@ typedef enum {
129
#define TCG_TARGET_HAS_mulsh_i64 1
130
#endif
131
132
-/* not defined -- call should be eliminated at compile time */
133
-void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
134
- uintptr_t, uintptr_t);
135
-
136
#define TCG_TARGET_DEFAULT_MO (0)
137
138
#define TCG_TARGET_NEED_LDST_LABELS
139
diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h
140
index XXXXXXX..XXXXXXX 100644
141
--- a/tcg/s390x/tcg-target.h
142
+++ b/tcg/s390x/tcg-target.h
143
@@ -XXX,XX +XXX,XX @@ extern uint64_t s390_facilities[3];
144
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
145
146
#define TCG_TARGET_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD)
147
-
148
-void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
149
- uintptr_t jmp_rx, uintptr_t jmp_rw);
150
-
151
#define TCG_TARGET_NEED_LDST_LABELS
152
#define TCG_TARGET_NEED_POOL_LABELS
153
154
diff --git a/tcg/sparc64/tcg-target.h b/tcg/sparc64/tcg-target.h
155
index XXXXXXX..XXXXXXX 100644
156
--- a/tcg/sparc64/tcg-target.h
157
+++ b/tcg/sparc64/tcg-target.h
158
@@ -XXX,XX +XXX,XX @@ extern bool use_vis3_instructions;
159
160
#define TCG_TARGET_DEFAULT_MO (0)
161
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
162
-
163
-void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
164
- uintptr_t, uintptr_t);
165
-
166
#define TCG_TARGET_NEED_POOL_LABELS
167
168
#endif
169
diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
170
index XXXXXXX..XXXXXXX 100644
171
--- a/tcg/tci/tcg-target.h
172
+++ b/tcg/tci/tcg-target.h
173
@@ -XXX,XX +XXX,XX @@ typedef enum {
174
175
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
176
177
-/* not defined -- call should be eliminated at compile time */
178
-void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
179
- uintptr_t, uintptr_t);
180
-
181
#endif /* TCG_TARGET_H */
182
--
27
--
183
2.34.1
28
2.34.1
184
29
185
30
diff view generated by jsdifflib
1
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
1
Change the semantics to be the last byte of the guest va, rather
2
than the following byte. This avoids some overflow conditions.
3
2
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
4
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
3
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
---
6
---
5
tcg/riscv/tcg-target.c.inc | 3 ++-
7
include/exec/cpu-all.h | 11 ++++++++++-
6
1 file changed, 2 insertions(+), 1 deletion(-)
8
linux-user/arm/target_cpu.h | 2 +-
7
9
bsd-user/main.c | 10 +++-------
8
diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
10
bsd-user/mmap.c | 4 ++--
9
index XXXXXXX..XXXXXXX 100644
11
linux-user/elfload.c | 21 +++++++++++----------
10
--- a/tcg/riscv/tcg-target.c.inc
12
linux-user/main.c | 27 +++++++++++++--------------
11
+++ b/tcg/riscv/tcg-target.c.inc
13
linux-user/mmap.c | 4 ++--
12
@@ -XXX,XX +XXX,XX @@ typedef enum {
14
7 files changed, 42 insertions(+), 37 deletions(-)
13
#endif
15
14
16
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
15
OPC_FENCE = 0x0000000f,
17
index XXXXXXX..XXXXXXX 100644
16
+ OPC_NOP = OPC_ADDI, /* nop = addi r0,r0,0 */
18
--- a/include/exec/cpu-all.h
17
} RISCVInsn;
19
+++ b/include/exec/cpu-all.h
20
@@ -XXX,XX +XXX,XX @@ static inline void tswap64s(uint64_t *s)
21
*/
22
extern uintptr_t guest_base;
23
extern bool have_guest_base;
24
+
25
+/*
26
+ * If non-zero, the guest virtual address space is a contiguous subset
27
+ * of the host virtual address space, i.e. '-R reserved_va' is in effect
28
+ * either from the command-line or by default. The value is the last
29
+ * byte of the guest address space e.g. UINT32_MAX.
30
+ *
31
+ * If zero, the host and guest virtual address spaces are intermingled.
32
+ */
33
extern unsigned long reserved_va;
18
34
19
/*
35
/*
20
@@ -XXX,XX +XXX,XX @@ static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
36
@@ -XXX,XX +XXX,XX @@ extern unsigned long reserved_va;
37
#define GUEST_ADDR_MAX_ \
38
((MIN_CONST(TARGET_VIRT_ADDR_SPACE_BITS, TARGET_ABI_BITS) <= 32) ? \
39
UINT32_MAX : ~0ul)
40
-#define GUEST_ADDR_MAX (reserved_va ? reserved_va - 1 : GUEST_ADDR_MAX_)
41
+#define GUEST_ADDR_MAX (reserved_va ? : GUEST_ADDR_MAX_)
42
43
#else
44
45
diff --git a/linux-user/arm/target_cpu.h b/linux-user/arm/target_cpu.h
46
index XXXXXXX..XXXXXXX 100644
47
--- a/linux-user/arm/target_cpu.h
48
+++ b/linux-user/arm/target_cpu.h
49
@@ -XXX,XX +XXX,XX @@ static inline unsigned long arm_max_reserved_va(CPUState *cs)
50
* the high addresses. Restrict linux-user to the
51
* cached write-back RAM in the system map.
52
*/
53
- return 0x80000000ul;
54
+ return 0x7ffffffful;
55
} else {
56
/*
57
* We need to be able to map the commpage.
58
diff --git a/bsd-user/main.c b/bsd-user/main.c
59
index XXXXXXX..XXXXXXX 100644
60
--- a/bsd-user/main.c
61
+++ b/bsd-user/main.c
62
@@ -XXX,XX +XXX,XX @@ bool have_guest_base;
63
# if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
64
# if TARGET_VIRT_ADDR_SPACE_BITS == 32 && \
65
(TARGET_LONG_BITS == 32 || defined(TARGET_ABI32))
66
-/*
67
- * There are a number of places where we assign reserved_va to a variable
68
- * of type abi_ulong and expect it to fit. Avoid the last page.
69
- */
70
-# define MAX_RESERVED_VA (0xfffffffful & TARGET_PAGE_MASK)
71
+# define MAX_RESERVED_VA 0xfffffffful
72
# else
73
-# define MAX_RESERVED_VA (1ul << TARGET_VIRT_ADDR_SPACE_BITS)
74
+# define MAX_RESERVED_VA ((1ul << TARGET_VIRT_ADDR_SPACE_BITS) - 1)
75
# endif
76
# else
77
# define MAX_RESERVED_VA 0
78
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
79
envlist_free(envlist);
80
81
if (reserved_va) {
82
- mmap_next_start = reserved_va;
83
+ mmap_next_start = reserved_va + 1;
84
}
85
86
{
87
diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
88
index XXXXXXX..XXXXXXX 100644
89
--- a/bsd-user/mmap.c
90
+++ b/bsd-user/mmap.c
91
@@ -XXX,XX +XXX,XX @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size,
92
size = HOST_PAGE_ALIGN(size) + alignment;
93
end_addr = start + size;
94
if (end_addr > reserved_va) {
95
- end_addr = reserved_va;
96
+ end_addr = reserved_va + 1;
97
}
98
addr = end_addr - qemu_host_page_size;
99
100
@@ -XXX,XX +XXX,XX @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size,
101
if (looped) {
102
return (abi_ulong)-1;
103
}
104
- end_addr = reserved_va;
105
+ end_addr = reserved_va + 1;
106
addr = end_addr - qemu_host_page_size;
107
looped = 1;
108
continue;
109
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
110
index XXXXXXX..XXXXXXX 100644
111
--- a/linux-user/elfload.c
112
+++ b/linux-user/elfload.c
113
@@ -XXX,XX +XXX,XX @@ static bool init_guest_commpage(void)
114
* has specified -R reserved_va, which would trigger an assert().
115
*/
116
if (reserved_va != 0 &&
117
- TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE >= reserved_va) {
118
+ TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE - 1 > reserved_va) {
119
error_report("Cannot allocate vsyscall page");
120
exit(EXIT_FAILURE);
121
}
122
@@ -XXX,XX +XXX,XX @@ static void pgb_have_guest_base(const char *image_name, abi_ulong guest_loaddr,
123
124
/* Sanity check the guest binary. */
125
if (reserved_va) {
126
- if (guest_hiaddr > reserved_va) {
127
+ if (guest_hiaddr - 1 > reserved_va) {
128
error_report("%s: requires more than reserved virtual "
129
"address space (0x%" PRIx64 " > 0x%lx)",
130
- image_name, (uint64_t)guest_hiaddr, reserved_va);
131
+ image_name, (uint64_t)guest_hiaddr - 1,
132
+ reserved_va);
133
exit(EXIT_FAILURE);
134
}
135
} else {
136
@@ -XXX,XX +XXX,XX @@ static void pgb_have_guest_base(const char *image_name, abi_ulong guest_loaddr,
137
if (reserved_va) {
138
guest_loaddr = (guest_base >= mmap_min_addr ? 0
139
: mmap_min_addr - guest_base);
140
- guest_hiaddr = reserved_va;
141
+ guest_hiaddr = reserved_va + 1;
142
}
143
144
/* Reserve the address space for the binary, or reserved_va. */
145
@@ -XXX,XX +XXX,XX @@ static void pgb_reserved_va(const char *image_name, abi_ulong guest_loaddr,
146
int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
147
void *addr, *test;
148
149
- if (guest_hiaddr > reserved_va) {
150
+ if (guest_hiaddr - 1 > reserved_va) {
151
error_report("%s: requires more than reserved virtual "
152
"address space (0x%" PRIx64 " > 0x%lx)",
153
- image_name, (uint64_t)guest_hiaddr, reserved_va);
154
+ image_name, (uint64_t)guest_hiaddr - 1, reserved_va);
155
exit(EXIT_FAILURE);
156
}
157
158
/* Widen the "image" to the entire reserved address space. */
159
- pgb_static(image_name, 0, reserved_va, align);
160
+ pgb_static(image_name, 0, reserved_va + 1, align);
161
162
/* osdep.h defines this as 0 if it's missing */
163
flags |= MAP_FIXED_NOREPLACE;
164
@@ -XXX,XX +XXX,XX @@ static void pgb_reserved_va(const char *image_name, abi_ulong guest_loaddr,
165
/* Reserve the memory on the host. */
166
assert(guest_base != 0);
167
test = g2h_untagged(0);
168
- addr = mmap(test, reserved_va, PROT_NONE, flags, -1, 0);
169
+ addr = mmap(test, reserved_va + 1, PROT_NONE, flags, -1, 0);
170
if (addr == MAP_FAILED || addr != test) {
171
error_report("Unable to reserve 0x%lx bytes of virtual address "
172
"space at %p (%s) for use as guest address space (check your "
173
"virtual memory ulimit setting, min_mmap_addr or reserve less "
174
- "using -R option)", reserved_va, test, strerror(errno));
175
+ "using -R option)", reserved_va + 1, test, strerror(errno));
176
exit(EXIT_FAILURE);
177
}
178
179
qemu_log_mask(CPU_LOG_PAGE, "%s: base @ %p for %lu bytes\n",
180
- __func__, addr, reserved_va);
181
+ __func__, addr, reserved_va + 1);
182
}
183
184
void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
185
diff --git a/linux-user/main.c b/linux-user/main.c
186
index XXXXXXX..XXXXXXX 100644
187
--- a/linux-user/main.c
188
+++ b/linux-user/main.c
189
@@ -XXX,XX +XXX,XX @@ static const char *last_log_filename;
190
# if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
191
# if TARGET_VIRT_ADDR_SPACE_BITS == 32 && \
192
(TARGET_LONG_BITS == 32 || defined(TARGET_ABI32))
193
-/* There are a number of places where we assign reserved_va to a variable
194
- of type abi_ulong and expect it to fit. Avoid the last page. */
195
-# define MAX_RESERVED_VA(CPU) (0xfffffffful & TARGET_PAGE_MASK)
196
+# define MAX_RESERVED_VA(CPU) 0xfffffffful
197
# else
198
-# define MAX_RESERVED_VA(CPU) (1ul << TARGET_VIRT_ADDR_SPACE_BITS)
199
+# define MAX_RESERVED_VA(CPU) ((1ul << TARGET_VIRT_ADDR_SPACE_BITS) - 1)
200
# endif
201
# else
202
# define MAX_RESERVED_VA(CPU) 0
203
@@ -XXX,XX +XXX,XX @@ static void handle_arg_reserved_va(const char *arg)
21
{
204
{
22
int i;
205
char *p;
23
for (i = 0; i < count; ++i) {
206
int shift = 0;
24
- p[i] = encode_i(OPC_ADDI, TCG_REG_ZERO, TCG_REG_ZERO, 0);
207
- reserved_va = strtoul(arg, &p, 0);
25
+ p[i] = OPC_NOP;
208
+ unsigned long val;
26
}
209
+
210
+ val = strtoul(arg, &p, 0);
211
switch (*p) {
212
case 'k':
213
case 'K':
214
@@ -XXX,XX +XXX,XX @@ static void handle_arg_reserved_va(const char *arg)
215
break;
216
}
217
if (shift) {
218
- unsigned long unshifted = reserved_va;
219
+ unsigned long unshifted = val;
220
p++;
221
- reserved_va <<= shift;
222
- if (reserved_va >> shift != unshifted) {
223
+ val <<= shift;
224
+ if (val >> shift != unshifted) {
225
fprintf(stderr, "Reserved virtual address too big\n");
226
exit(EXIT_FAILURE);
227
}
228
@@ -XXX,XX +XXX,XX @@ static void handle_arg_reserved_va(const char *arg)
229
fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
230
exit(EXIT_FAILURE);
231
}
232
+ /* The representation is size - 1, with 0 remaining "default". */
233
+ reserved_va = val ? val - 1 : 0;
27
}
234
}
28
235
236
static void handle_arg_singlestep(const char *arg)
237
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
238
*/
239
max_reserved_va = MAX_RESERVED_VA(cpu);
240
if (reserved_va != 0) {
241
- if (reserved_va % qemu_host_page_size) {
242
+ if ((reserved_va + 1) % qemu_host_page_size) {
243
char *s = size_to_str(qemu_host_page_size);
244
fprintf(stderr, "Reserved virtual address not aligned mod %s\n", s);
245
g_free(s);
246
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
247
exit(EXIT_FAILURE);
248
}
249
} else if (HOST_LONG_BITS == 64 && TARGET_VIRT_ADDR_SPACE_BITS <= 32) {
250
- /*
251
- * reserved_va must be aligned with the host page size
252
- * as it is used with mmap()
253
- */
254
- reserved_va = max_reserved_va & qemu_host_page_mask;
255
+ /* MAX_RESERVED_VA + 1 is a large power of 2, so is aligned. */
256
+ reserved_va = max_reserved_va;
257
}
258
259
{
260
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
261
index XXXXXXX..XXXXXXX 100644
262
--- a/linux-user/mmap.c
263
+++ b/linux-user/mmap.c
264
@@ -XXX,XX +XXX,XX @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size,
265
end_addr = start + size;
266
if (start > reserved_va - size) {
267
/* Start at the top of the address space. */
268
- end_addr = ((reserved_va - size) & -align) + size;
269
+ end_addr = ((reserved_va + 1 - size) & -align) + size;
270
looped = true;
271
}
272
273
@@ -XXX,XX +XXX,XX @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size,
274
return (abi_ulong)-1;
275
}
276
/* Re-start at the top of the address space. */
277
- addr = end_addr = ((reserved_va - size) & -align) + size;
278
+ addr = end_addr = ((reserved_va + 1 - size) & -align) + size;
279
looped = true;
280
} else {
281
prot = page_get_flags(addr);
29
--
282
--
30
2.34.1
283
2.34.1
31
284
32
285
diff view generated by jsdifflib
1
The INDEX_op_exit_tb opcode needs no register allocation.
1
Pass the address of the last byte to be changed, rather than
2
Split out a dedicated helper function for it.
2
the first address past the last byte. This avoids overflow
3
3
when the last page of the address space is involved.
4
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
4
5
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1528
5
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
---
8
---
8
tcg/tcg.c | 4 ++++
9
include/exec/cpu-all.h | 2 +-
9
tcg/aarch64/tcg-target.c.inc | 22 ++++++++++--------
10
accel/tcg/user-exec.c | 16 +++++++---------
10
tcg/arm/tcg-target.c.inc | 11 +++++----
11
bsd-user/mmap.c | 6 +++---
11
tcg/i386/tcg-target.c.inc | 21 +++++++++--------
12
linux-user/elfload.c | 11 ++++++-----
12
tcg/loongarch64/tcg-target.c.inc | 22 ++++++++++--------
13
linux-user/mmap.c | 16 ++++++++--------
13
tcg/mips/tcg-target.c.inc | 33 +++++++++++++--------------
14
linux-user/syscall.c | 4 ++--
14
tcg/ppc/tcg-target.c.inc | 11 +++++----
15
6 files changed, 27 insertions(+), 28 deletions(-)
15
tcg/riscv/tcg-target.c.inc | 22 ++++++++++--------
16
16
tcg/s390x/tcg-target.c.inc | 23 ++++++++++---------
17
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
17
tcg/sparc64/tcg-target.c.inc | 39 +++++++++++++++++---------------
18
index XXXXXXX..XXXXXXX 100644
18
tcg/tci/tcg-target.c.inc | 10 ++++----
19
--- a/include/exec/cpu-all.h
19
11 files changed, 121 insertions(+), 97 deletions(-)
20
+++ b/include/exec/cpu-all.h
20
21
@@ -XXX,XX +XXX,XX @@ typedef int (*walk_memory_regions_fn)(void *, target_ulong,
21
diff --git a/tcg/tcg.c b/tcg/tcg.c
22
int walk_memory_regions(void *, walk_memory_regions_fn);
22
index XXXXXXX..XXXXXXX 100644
23
23
--- a/tcg/tcg.c
24
int page_get_flags(target_ulong address);
24
+++ b/tcg/tcg.c
25
-void page_set_flags(target_ulong start, target_ulong end, int flags);
25
@@ -XXX,XX +XXX,XX @@ static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
26
+void page_set_flags(target_ulong start, target_ulong last, int flags);
26
static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
27
void page_reset_target_data(target_ulong start, target_ulong end);
27
static void tcg_out_movi(TCGContext *s, TCGType type,
28
int page_check_range(target_ulong start, target_ulong len, int flags);
28
TCGReg ret, tcg_target_long arg);
29
29
+static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg);
30
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
30
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
31
index XXXXXXX..XXXXXXX 100644
31
const TCGArg args[TCG_MAX_OP_ARGS],
32
--- a/accel/tcg/user-exec.c
32
const int const_args[TCG_MAX_OP_ARGS]);
33
+++ b/accel/tcg/user-exec.c
33
@@ -XXX,XX +XXX,XX @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start)
34
@@ -XXX,XX +XXX,XX @@ static bool pageflags_set_clear(target_ulong start, target_ulong last,
34
case INDEX_op_call:
35
* The flag PAGE_WRITE_ORG is positioned automatically depending
35
tcg_reg_alloc_call(s, op);
36
* on PAGE_WRITE. The mmap_lock should already be held.
37
*/
38
-void page_set_flags(target_ulong start, target_ulong end, int flags)
39
+void page_set_flags(target_ulong start, target_ulong last, int flags)
40
{
41
- target_ulong last;
42
bool reset = false;
43
bool inval_tb = false;
44
45
/* This function should never be called with addresses outside the
46
guest address space. If this assert fires, it probably indicates
47
a missing call to h2g_valid. */
48
- assert(start < end);
49
- assert(end - 1 <= GUEST_ADDR_MAX);
50
+ assert(start <= last);
51
+ assert(last <= GUEST_ADDR_MAX);
52
/* Only set PAGE_ANON with new mappings. */
53
assert(!(flags & PAGE_ANON) || (flags & PAGE_RESET));
54
assert_memory_lock();
55
56
- start = start & TARGET_PAGE_MASK;
57
- end = TARGET_PAGE_ALIGN(end);
58
- last = end - 1;
59
+ start &= TARGET_PAGE_MASK;
60
+ last |= ~TARGET_PAGE_MASK;
61
62
if (!(flags & PAGE_VALID)) {
63
flags = 0;
64
@@ -XXX,XX +XXX,XX @@ void page_set_flags(target_ulong start, target_ulong end, int flags)
65
}
66
67
if (!flags || reset) {
68
- page_reset_target_data(start, end);
69
+ page_reset_target_data(start, last + 1);
70
inval_tb |= pageflags_unset(start, last);
71
}
72
if (flags) {
73
@@ -XXX,XX +XXX,XX @@ void page_set_flags(target_ulong start, target_ulong end, int flags)
74
~(reset ? 0 : PAGE_STICKY));
75
}
76
if (inval_tb) {
77
- tb_invalidate_phys_range(start, end);
78
+ tb_invalidate_phys_range(start, last + 1);
79
}
80
}
81
82
diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
83
index XXXXXXX..XXXXXXX 100644
84
--- a/bsd-user/mmap.c
85
+++ b/bsd-user/mmap.c
86
@@ -XXX,XX +XXX,XX @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot)
87
if (ret != 0)
88
goto error;
89
}
90
- page_set_flags(start, start + len, prot | PAGE_VALID);
91
+ page_set_flags(start, start + len - 1, prot | PAGE_VALID);
92
mmap_unlock();
93
return 0;
94
error:
95
@@ -XXX,XX +XXX,XX @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
96
}
97
}
98
the_end1:
99
- page_set_flags(start, start + len, prot | PAGE_VALID);
100
+ page_set_flags(start, start + len - 1, prot | PAGE_VALID);
101
the_end:
102
#ifdef DEBUG_MMAP
103
printf("ret=0x" TARGET_ABI_FMT_lx "\n", start);
104
@@ -XXX,XX +XXX,XX @@ int target_munmap(abi_ulong start, abi_ulong len)
105
}
106
107
if (ret == 0) {
108
- page_set_flags(start, start + len, 0);
109
+ page_set_flags(start, start + len - 1, 0);
110
}
111
mmap_unlock();
112
return ret;
113
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
114
index XXXXXXX..XXXXXXX 100644
115
--- a/linux-user/elfload.c
116
+++ b/linux-user/elfload.c
117
@@ -XXX,XX +XXX,XX @@ static bool init_guest_commpage(void)
118
exit(EXIT_FAILURE);
119
}
120
page_set_flags(TARGET_VSYSCALL_PAGE,
121
- TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE,
122
+ TARGET_VSYSCALL_PAGE | ~TARGET_PAGE_MASK,
123
PAGE_EXEC | PAGE_VALID);
124
return true;
125
}
126
@@ -XXX,XX +XXX,XX @@ static bool init_guest_commpage(void)
127
exit(EXIT_FAILURE);
128
}
129
130
- page_set_flags(commpage, commpage + qemu_host_page_size,
131
+ page_set_flags(commpage, commpage | ~qemu_host_page_mask,
132
PAGE_READ | PAGE_EXEC | PAGE_VALID);
133
return true;
134
}
135
@@ -XXX,XX +XXX,XX @@ static bool init_guest_commpage(void)
136
exit(EXIT_FAILURE);
137
}
138
139
- page_set_flags(LO_COMMPAGE, LO_COMMPAGE + TARGET_PAGE_SIZE,
140
+ page_set_flags(LO_COMMPAGE, LO_COMMPAGE | ~TARGET_PAGE_MASK,
141
PAGE_READ | PAGE_EXEC | PAGE_VALID);
142
return true;
143
}
144
@@ -XXX,XX +XXX,XX @@ static bool init_guest_commpage(void)
145
* and implement syscalls. Here, simply mark the page executable.
146
* Special case the entry points during translation (see do_page_zero).
147
*/
148
- page_set_flags(LO_COMMPAGE, LO_COMMPAGE + TARGET_PAGE_SIZE,
149
+ page_set_flags(LO_COMMPAGE, LO_COMMPAGE | ~TARGET_PAGE_MASK,
150
PAGE_EXEC | PAGE_VALID);
151
return true;
152
}
153
@@ -XXX,XX +XXX,XX @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
154
155
/* Ensure that the bss page(s) are valid */
156
if ((page_get_flags(last_bss-1) & prot) != prot) {
157
- page_set_flags(elf_bss & TARGET_PAGE_MASK, last_bss, prot | PAGE_VALID);
158
+ page_set_flags(elf_bss & TARGET_PAGE_MASK, last_bss - 1,
159
+ prot | PAGE_VALID);
160
}
161
162
if (host_start < host_map_start) {
163
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
164
index XXXXXXX..XXXXXXX 100644
165
--- a/linux-user/mmap.c
166
+++ b/linux-user/mmap.c
167
@@ -XXX,XX +XXX,XX @@ int target_mprotect(abi_ulong start, abi_ulong len, int target_prot)
168
}
169
}
170
171
- page_set_flags(start, start + len, page_flags);
172
+ page_set_flags(start, start + len - 1, page_flags);
173
ret = 0;
174
175
error:
176
@@ -XXX,XX +XXX,XX @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
177
}
178
page_flags |= PAGE_RESET;
179
if (passthrough_start == passthrough_end) {
180
- page_set_flags(start, start + len, page_flags);
181
+ page_set_flags(start, start + len - 1, page_flags);
182
} else {
183
if (start < passthrough_start) {
184
- page_set_flags(start, passthrough_start, page_flags);
185
+ page_set_flags(start, passthrough_start - 1, page_flags);
186
}
187
- page_set_flags(passthrough_start, passthrough_end,
188
+ page_set_flags(passthrough_start, passthrough_end - 1,
189
page_flags | PAGE_PASSTHROUGH);
190
if (passthrough_end < start + len) {
191
- page_set_flags(passthrough_end, start + len, page_flags);
192
+ page_set_flags(passthrough_end, start + len - 1, page_flags);
193
}
194
}
195
the_end:
196
@@ -XXX,XX +XXX,XX @@ int target_munmap(abi_ulong start, abi_ulong len)
197
}
198
199
if (ret == 0) {
200
- page_set_flags(start, start + len, 0);
201
+ page_set_flags(start, start + len - 1, 0);
202
}
203
mmap_unlock();
204
return ret;
205
@@ -XXX,XX +XXX,XX @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
206
} else {
207
new_addr = h2g(host_addr);
208
prot = page_get_flags(old_addr);
209
- page_set_flags(old_addr, old_addr + old_size, 0);
210
- page_set_flags(new_addr, new_addr + new_size,
211
+ page_set_flags(old_addr, old_addr + old_size - 1, 0);
212
+ page_set_flags(new_addr, new_addr + new_size - 1,
213
prot | PAGE_VALID | PAGE_RESET);
214
}
215
mmap_unlock();
216
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
217
index XXXXXXX..XXXXXXX 100644
218
--- a/linux-user/syscall.c
219
+++ b/linux-user/syscall.c
220
@@ -XXX,XX +XXX,XX @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
221
}
222
raddr=h2g((unsigned long)host_raddr);
223
224
- page_set_flags(raddr, raddr + shm_info.shm_segsz,
225
+ page_set_flags(raddr, raddr + shm_info.shm_segsz - 1,
226
PAGE_VALID | PAGE_RESET | PAGE_READ |
227
(shmflg & SHM_RDONLY ? 0 : PAGE_WRITE));
228
229
@@ -XXX,XX +XXX,XX @@ static inline abi_long do_shmdt(abi_ulong shmaddr)
230
for (i = 0; i < N_SHM_REGIONS; ++i) {
231
if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
232
shm_regions[i].in_use = false;
233
- page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
234
+ page_set_flags(shmaddr, shmaddr + shm_regions[i].size - 1, 0);
36
break;
235
break;
37
+ case INDEX_op_exit_tb:
236
}
38
+ tcg_out_exit_tb(s, op->args[0]);
39
+ break;
40
case INDEX_op_dup2_vec:
41
if (tcg_reg_alloc_dup2(s, op)) {
42
break;
43
diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
44
index XXXXXXX..XXXXXXX 100644
45
--- a/tcg/aarch64/tcg-target.c.inc
46
+++ b/tcg/aarch64/tcg-target.c.inc
47
@@ -XXX,XX +XXX,XX @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
48
49
static const tcg_insn_unit *tb_ret_addr;
50
51
+static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
52
+{
53
+ /* Reuse the zeroing that exists for goto_ptr. */
54
+ if (a0 == 0) {
55
+ tcg_out_goto_long(s, tcg_code_gen_epilogue);
56
+ } else {
57
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, a0);
58
+ tcg_out_goto_long(s, tb_ret_addr);
59
+ }
60
+}
61
+
62
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
63
const TCGArg args[TCG_MAX_OP_ARGS],
64
const int const_args[TCG_MAX_OP_ARGS])
65
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
66
#define REG0(I) (const_args[I] ? TCG_REG_XZR : (TCGReg)args[I])
67
68
switch (opc) {
69
- case INDEX_op_exit_tb:
70
- /* Reuse the zeroing that exists for goto_ptr. */
71
- if (a0 == 0) {
72
- tcg_out_goto_long(s, tcg_code_gen_epilogue);
73
- } else {
74
- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, a0);
75
- tcg_out_goto_long(s, tb_ret_addr);
76
- }
77
- break;
78
-
79
case INDEX_op_goto_tb:
80
tcg_debug_assert(s->tb_jmp_insn_offset != NULL);
81
/*
82
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
83
case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
84
case INDEX_op_mov_i64:
85
case INDEX_op_call: /* Always emitted via tcg_out_call. */
86
+ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
87
default:
88
g_assert_not_reached();
89
}
90
diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
91
index XXXXXXX..XXXXXXX 100644
92
--- a/tcg/arm/tcg-target.c.inc
93
+++ b/tcg/arm/tcg-target.c.inc
94
@@ -XXX,XX +XXX,XX @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
95
96
static void tcg_out_epilogue(TCGContext *s);
97
98
+static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg)
99
+{
100
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R0, arg);
101
+ tcg_out_epilogue(s);
102
+}
103
+
104
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
105
const TCGArg args[TCG_MAX_OP_ARGS],
106
const int const_args[TCG_MAX_OP_ARGS])
107
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
108
int c;
109
110
switch (opc) {
111
- case INDEX_op_exit_tb:
112
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R0, args[0]);
113
- tcg_out_epilogue(s);
114
- break;
115
case INDEX_op_goto_tb:
116
{
117
/* Indirect jump method */
118
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
119
120
case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
121
case INDEX_op_call: /* Always emitted via tcg_out_call. */
122
+ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
123
default:
124
tcg_abort();
125
}
126
diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
127
index XXXXXXX..XXXXXXX 100644
128
--- a/tcg/i386/tcg-target.c.inc
129
+++ b/tcg/i386/tcg-target.c.inc
130
@@ -XXX,XX +XXX,XX @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
131
#endif
132
}
133
134
+static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
135
+{
136
+ /* Reuse the zeroing that exists for goto_ptr. */
137
+ if (a0 == 0) {
138
+ tcg_out_jmp(s, tcg_code_gen_epilogue);
139
+ } else {
140
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_EAX, a0);
141
+ tcg_out_jmp(s, tb_ret_addr);
142
+ }
143
+}
144
+
145
static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
146
const TCGArg args[TCG_MAX_OP_ARGS],
147
const int const_args[TCG_MAX_OP_ARGS])
148
@@ -XXX,XX +XXX,XX @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
149
const_a2 = const_args[2];
150
151
switch (opc) {
152
- case INDEX_op_exit_tb:
153
- /* Reuse the zeroing that exists for goto_ptr. */
154
- if (a0 == 0) {
155
- tcg_out_jmp(s, tcg_code_gen_epilogue);
156
- } else {
157
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_EAX, a0);
158
- tcg_out_jmp(s, tb_ret_addr);
159
- }
160
- break;
161
case INDEX_op_goto_tb:
162
if (s->tb_jmp_insn_offset) {
163
/* direct jump method */
164
@@ -XXX,XX +XXX,XX @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
165
case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
166
case INDEX_op_mov_i64:
167
case INDEX_op_call: /* Always emitted via tcg_out_call. */
168
+ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
169
default:
170
tcg_abort();
171
}
172
diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc
173
index XXXXXXX..XXXXXXX 100644
174
--- a/tcg/loongarch64/tcg-target.c.inc
175
+++ b/tcg/loongarch64/tcg-target.c.inc
176
@@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx,
177
178
static const tcg_insn_unit *tb_ret_addr;
179
180
+static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
181
+{
182
+ /* Reuse the zeroing that exists for goto_ptr. */
183
+ if (a0 == 0) {
184
+ tcg_out_call_int(s, tcg_code_gen_epilogue, true);
185
+ } else {
186
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A0, a0);
187
+ tcg_out_call_int(s, tb_ret_addr, true);
188
+ }
189
+}
190
+
191
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
192
const TCGArg args[TCG_MAX_OP_ARGS],
193
const int const_args[TCG_MAX_OP_ARGS])
194
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
195
int c2 = const_args[2];
196
197
switch (opc) {
198
- case INDEX_op_exit_tb:
199
- /* Reuse the zeroing that exists for goto_ptr. */
200
- if (a0 == 0) {
201
- tcg_out_call_int(s, tcg_code_gen_epilogue, true);
202
- } else {
203
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A0, a0);
204
- tcg_out_call_int(s, tb_ret_addr, true);
205
- }
206
- break;
207
-
208
case INDEX_op_goto_tb:
209
tcg_debug_assert(s->tb_jmp_insn_offset != NULL);
210
/*
211
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
212
case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
213
case INDEX_op_mov_i64:
214
case INDEX_op_call: /* Always emitted via tcg_out_call. */
215
+ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
216
default:
217
g_assert_not_reached();
218
}
219
diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc
220
index XXXXXXX..XXXXXXX 100644
221
--- a/tcg/mips/tcg-target.c.inc
222
+++ b/tcg/mips/tcg-target.c.inc
223
@@ -XXX,XX +XXX,XX @@ static void tcg_out_clz(TCGContext *s, MIPSInsn opcv2, MIPSInsn opcv6,
224
}
225
}
226
227
+static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
228
+{
229
+ TCGReg b0 = TCG_REG_ZERO;
230
+
231
+ if (a0 & ~0xffff) {
232
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_V0, a0 & ~0xffff);
233
+ b0 = TCG_REG_V0;
234
+ }
235
+ if (!tcg_out_opc_jmp(s, OPC_J, tb_ret_addr)) {
236
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, (uintptr_t)tb_ret_addr);
237
+ tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0);
238
+ }
239
+ tcg_out_opc_imm(s, OPC_ORI, TCG_REG_V0, b0, a0 & 0xffff);
240
+}
241
+
242
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
243
const TCGArg args[TCG_MAX_OP_ARGS],
244
const int const_args[TCG_MAX_OP_ARGS])
245
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
246
c2 = const_args[2];
247
248
switch (opc) {
249
- case INDEX_op_exit_tb:
250
- {
251
- TCGReg b0 = TCG_REG_ZERO;
252
-
253
- a0 = (intptr_t)a0;
254
- if (a0 & ~0xffff) {
255
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_V0, a0 & ~0xffff);
256
- b0 = TCG_REG_V0;
257
- }
258
- if (!tcg_out_opc_jmp(s, OPC_J, tb_ret_addr)) {
259
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0,
260
- (uintptr_t)tb_ret_addr);
261
- tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0);
262
- }
263
- tcg_out_opc_imm(s, OPC_ORI, TCG_REG_V0, b0, a0 & 0xffff);
264
- }
265
- break;
266
case INDEX_op_goto_tb:
267
/* indirect jump method */
268
tcg_debug_assert(s->tb_jmp_insn_offset == 0);
269
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
270
case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
271
case INDEX_op_mov_i64:
272
case INDEX_op_call: /* Always emitted via tcg_out_call. */
273
+ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
274
default:
275
tcg_abort();
276
}
277
diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
278
index XXXXXXX..XXXXXXX 100644
279
--- a/tcg/ppc/tcg-target.c.inc
280
+++ b/tcg/ppc/tcg-target.c.inc
281
@@ -XXX,XX +XXX,XX @@ static void tcg_target_qemu_prologue(TCGContext *s)
282
tcg_out32(s, BCLR | BO_ALWAYS);
283
}
284
285
+static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg)
286
+{
287
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R3, arg);
288
+ tcg_out_b(s, 0, tcg_code_gen_epilogue);
289
+}
290
+
291
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
292
const TCGArg args[TCG_MAX_OP_ARGS],
293
const int const_args[TCG_MAX_OP_ARGS])
294
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
295
TCGArg a0, a1, a2;
296
297
switch (opc) {
298
- case INDEX_op_exit_tb:
299
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R3, args[0]);
300
- tcg_out_b(s, 0, tcg_code_gen_epilogue);
301
- break;
302
case INDEX_op_goto_tb:
303
if (s->tb_jmp_insn_offset) {
304
/* Direct jump. */
305
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
306
case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
307
case INDEX_op_mov_i64:
308
case INDEX_op_call: /* Always emitted via tcg_out_call. */
309
+ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
310
default:
311
tcg_abort();
312
}
313
diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
314
index XXXXXXX..XXXXXXX 100644
315
--- a/tcg/riscv/tcg-target.c.inc
316
+++ b/tcg/riscv/tcg-target.c.inc
317
@@ -XXX,XX +XXX,XX @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
318
319
static const tcg_insn_unit *tb_ret_addr;
320
321
+static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
322
+{
323
+ /* Reuse the zeroing that exists for goto_ptr. */
324
+ if (a0 == 0) {
325
+ tcg_out_call_int(s, tcg_code_gen_epilogue, true);
326
+ } else {
327
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A0, a0);
328
+ tcg_out_call_int(s, tb_ret_addr, true);
329
+ }
330
+}
331
+
332
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
333
const TCGArg args[TCG_MAX_OP_ARGS],
334
const int const_args[TCG_MAX_OP_ARGS])
335
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
336
int c2 = const_args[2];
337
338
switch (opc) {
339
- case INDEX_op_exit_tb:
340
- /* Reuse the zeroing that exists for goto_ptr. */
341
- if (a0 == 0) {
342
- tcg_out_call_int(s, tcg_code_gen_epilogue, true);
343
- } else {
344
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A0, a0);
345
- tcg_out_call_int(s, tb_ret_addr, true);
346
- }
347
- break;
348
-
349
case INDEX_op_goto_tb:
350
assert(s->tb_jmp_insn_offset == 0);
351
/* indirect jump method */
352
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
353
case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
354
case INDEX_op_mov_i64:
355
case INDEX_op_call: /* Always emitted via tcg_out_call. */
356
+ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
357
default:
358
g_assert_not_reached();
359
}
360
diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc
361
index XXXXXXX..XXXXXXX 100644
362
--- a/tcg/s390x/tcg-target.c.inc
363
+++ b/tcg/s390x/tcg-target.c.inc
364
@@ -XXX,XX +XXX,XX @@ static void tcg_out_qemu_st(TCGContext* s, TCGReg data_reg, TCGReg addr_reg,
365
#endif
366
}
367
368
+static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
369
+{
370
+ /* Reuse the zeroing that exists for goto_ptr. */
371
+ if (a0 == 0) {
372
+ tgen_gotoi(s, S390_CC_ALWAYS, tcg_code_gen_epilogue);
373
+ } else {
374
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, a0);
375
+ tgen_gotoi(s, S390_CC_ALWAYS, tb_ret_addr);
376
+ }
377
+}
378
+
379
# define OP_32_64(x) \
380
case glue(glue(INDEX_op_,x),_i32): \
381
case glue(glue(INDEX_op_,x),_i64)
382
@@ -XXX,XX +XXX,XX @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
383
TCGArg a0, a1, a2;
384
385
switch (opc) {
386
- case INDEX_op_exit_tb:
387
- /* Reuse the zeroing that exists for goto_ptr. */
388
- a0 = args[0];
389
- if (a0 == 0) {
390
- tgen_gotoi(s, S390_CC_ALWAYS, tcg_code_gen_epilogue);
391
- } else {
392
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, a0);
393
- tgen_gotoi(s, S390_CC_ALWAYS, tb_ret_addr);
394
- }
395
- break;
396
-
397
case INDEX_op_goto_tb:
398
a0 = args[0];
399
/*
400
@@ -XXX,XX +XXX,XX @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
401
case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
402
case INDEX_op_mov_i64:
403
case INDEX_op_call: /* Always emitted via tcg_out_call. */
404
+ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
405
default:
406
tcg_abort();
407
}
408
diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc
409
index XXXXXXX..XXXXXXX 100644
410
--- a/tcg/sparc64/tcg-target.c.inc
411
+++ b/tcg/sparc64/tcg-target.c.inc
412
@@ -XXX,XX +XXX,XX @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr,
413
#endif /* CONFIG_SOFTMMU */
414
}
415
416
+static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
417
+{
418
+ if (check_fit_ptr(a0, 13)) {
419
+ tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN);
420
+ tcg_out_movi_imm13(s, TCG_REG_O0, a0);
421
+ return;
422
+ } else if (USE_REG_TB) {
423
+ intptr_t tb_diff = tcg_tbrel_diff(s, (void *)a0);
424
+ if (check_fit_ptr(tb_diff, 13)) {
425
+ tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN);
426
+ /* Note that TCG_REG_TB has been unwound to O1. */
427
+ tcg_out_arithi(s, TCG_REG_O0, TCG_REG_O1, tb_diff, ARITH_ADD);
428
+ return;
429
+ }
430
+ }
431
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I0, a0 & ~0x3ff);
432
+ tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN);
433
+ tcg_out_arithi(s, TCG_REG_O0, TCG_REG_O0, a0 & 0x3ff, ARITH_OR);
434
+}
435
+
436
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
437
const TCGArg args[TCG_MAX_OP_ARGS],
438
const int const_args[TCG_MAX_OP_ARGS])
439
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
440
c2 = const_args[2];
441
442
switch (opc) {
443
- case INDEX_op_exit_tb:
444
- if (check_fit_ptr(a0, 13)) {
445
- tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN);
446
- tcg_out_movi_imm13(s, TCG_REG_O0, a0);
447
- break;
448
- } else if (USE_REG_TB) {
449
- intptr_t tb_diff = tcg_tbrel_diff(s, (void *)a0);
450
- if (check_fit_ptr(tb_diff, 13)) {
451
- tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN);
452
- /* Note that TCG_REG_TB has been unwound to O1. */
453
- tcg_out_arithi(s, TCG_REG_O0, TCG_REG_O1, tb_diff, ARITH_ADD);
454
- break;
455
- }
456
- }
457
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I0, a0 & ~0x3ff);
458
- tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN);
459
- tcg_out_arithi(s, TCG_REG_O0, TCG_REG_O0, a0 & 0x3ff, ARITH_OR);
460
- break;
461
case INDEX_op_goto_tb:
462
if (s->tb_jmp_insn_offset) {
463
/* direct jump method */
464
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
465
case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
466
case INDEX_op_mov_i64:
467
case INDEX_op_call: /* Always emitted via tcg_out_call. */
468
+ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
469
default:
470
tcg_abort();
471
}
472
diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc
473
index XXXXXXX..XXXXXXX 100644
474
--- a/tcg/tci/tcg-target.c.inc
475
+++ b/tcg/tci/tcg-target.c.inc
476
@@ -XXX,XX +XXX,XX @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *func,
477
# define CASE_64(x)
478
#endif
479
480
+static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg)
481
+{
482
+ tcg_out_op_p(s, INDEX_op_exit_tb, (void *)arg);
483
+}
484
+
485
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
486
const TCGArg args[TCG_MAX_OP_ARGS],
487
const int const_args[TCG_MAX_OP_ARGS])
488
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
489
TCGOpcode exts;
490
491
switch (opc) {
492
- case INDEX_op_exit_tb:
493
- tcg_out_op_p(s, opc, (void *)args[0]);
494
- break;
495
-
496
case INDEX_op_goto_tb:
497
tcg_debug_assert(s->tb_jmp_insn_offset == 0);
498
/* indirect jump method. */
499
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
500
case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
501
case INDEX_op_mov_i64:
502
case INDEX_op_call: /* Always emitted via tcg_out_call. */
503
+ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
504
default:
505
tcg_abort();
506
}
237
}
507
--
238
--
508
2.34.1
239
2.34.1
509
240
510
241
diff view generated by jsdifflib
Deleted patch
1
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
2
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
3
---
4
tcg/i386/tcg-target.c.inc | 14 +++++---------
5
1 file changed, 5 insertions(+), 9 deletions(-)
6
1
7
diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
8
index XXXXXXX..XXXXXXX 100644
9
--- a/tcg/i386/tcg-target.c.inc
10
+++ b/tcg/i386/tcg-target.c.inc
11
@@ -XXX,XX +XXX,XX @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
12
13
switch (opc) {
14
case INDEX_op_goto_tb:
15
- if (s->tb_jmp_insn_offset) {
16
- /* direct jump method */
17
- int gap;
18
- /* jump displacement must be aligned for atomic patching;
19
+ qemu_build_assert(TCG_TARGET_HAS_direct_jump);
20
+ {
21
+ /*
22
+ * Jump displacement must be aligned for atomic patching;
23
* see if we need to add extra nops before jump
24
*/
25
- gap = QEMU_ALIGN_PTR_UP(s->code_ptr + 1, 4) - s->code_ptr;
26
+ int gap = QEMU_ALIGN_PTR_UP(s->code_ptr + 1, 4) - s->code_ptr;
27
if (gap != 1) {
28
tcg_out_nopn(s, gap - 1);
29
}
30
tcg_out8(s, OPC_JMP_long); /* jmp im */
31
s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
32
tcg_out32(s, 0);
33
- } else {
34
- /* indirect jump method */
35
- tcg_out_modrm_offset(s, OPC_GRP5, EXT5_JMPN_Ev, -1,
36
- (intptr_t)(s->tb_jmp_target_addr + a0));
37
}
38
set_jmp_reset_offset(s, a0);
39
break;
40
--
41
2.34.1
42
43
diff view generated by jsdifflib
Deleted patch
1
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
2
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
3
---
4
tcg/ppc/tcg-target.c.inc | 32 +++++++++++++-------------------
5
1 file changed, 13 insertions(+), 19 deletions(-)
6
1
7
diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
8
index XXXXXXX..XXXXXXX 100644
9
--- a/tcg/ppc/tcg-target.c.inc
10
+++ b/tcg/ppc/tcg-target.c.inc
11
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
12
13
switch (opc) {
14
case INDEX_op_goto_tb:
15
- if (s->tb_jmp_insn_offset) {
16
- /* Direct jump. */
17
- if (TCG_TARGET_REG_BITS == 64) {
18
- /* Ensure the next insns are 8 or 16-byte aligned. */
19
- while ((uintptr_t)s->code_ptr & (have_isa_2_07 ? 15 : 7)) {
20
- tcg_out32(s, NOP);
21
- }
22
- s->tb_jmp_insn_offset[args[0]] = tcg_current_code_size(s);
23
- tcg_out32(s, ADDIS | TAI(TCG_REG_TB, TCG_REG_TB, 0));
24
- tcg_out32(s, ADDI | TAI(TCG_REG_TB, TCG_REG_TB, 0));
25
- } else {
26
- s->tb_jmp_insn_offset[args[0]] = tcg_current_code_size(s);
27
- tcg_out32(s, B);
28
- s->tb_jmp_reset_offset[args[0]] = tcg_current_code_size(s);
29
- break;
30
+ qemu_build_assert(TCG_TARGET_HAS_direct_jump);
31
+ /* Direct jump. */
32
+ if (TCG_TARGET_REG_BITS == 64) {
33
+ /* Ensure the next insns are 8 or 16-byte aligned. */
34
+ while ((uintptr_t)s->code_ptr & (have_isa_2_07 ? 15 : 7)) {
35
+ tcg_out32(s, NOP);
36
}
37
+ s->tb_jmp_insn_offset[args[0]] = tcg_current_code_size(s);
38
+ tcg_out32(s, ADDIS | TAI(TCG_REG_TB, TCG_REG_TB, 0));
39
+ tcg_out32(s, ADDI | TAI(TCG_REG_TB, TCG_REG_TB, 0));
40
} else {
41
- /* Indirect jump. */
42
- tcg_debug_assert(s->tb_jmp_insn_offset == NULL);
43
- tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TB, 0,
44
- (intptr_t)(s->tb_jmp_insn_offset + args[0]));
45
+ s->tb_jmp_insn_offset[args[0]] = tcg_current_code_size(s);
46
+ tcg_out32(s, B);
47
+ s->tb_jmp_reset_offset[args[0]] = tcg_current_code_size(s);
48
+ break;
49
}
50
tcg_out32(s, MTSPR | RS(TCG_REG_TB) | CTR);
51
tcg_out32(s, BCCTR | BO_ALWAYS);
52
--
53
2.34.1
54
55
diff view generated by jsdifflib
Deleted patch
1
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
2
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
3
---
4
tcg/sparc64/tcg-target.c.inc | 41 +++++++++++-------------------------
5
1 file changed, 12 insertions(+), 29 deletions(-)
6
1
7
diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc
8
index XXXXXXX..XXXXXXX 100644
9
--- a/tcg/sparc64/tcg-target.c.inc
10
+++ b/tcg/sparc64/tcg-target.c.inc
11
@@ -XXX,XX +XXX,XX @@ static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
12
return false;
13
}
14
15
-static void tcg_out_ld_ptr(TCGContext *s, TCGReg ret, const void *arg)
16
-{
17
- intptr_t diff = tcg_tbrel_diff(s, arg);
18
- if (USE_REG_TB && check_fit_ptr(diff, 13)) {
19
- tcg_out_ld(s, TCG_TYPE_PTR, ret, TCG_REG_TB, diff);
20
- return;
21
- }
22
- tcg_out_movi(s, TCG_TYPE_PTR, ret, (uintptr_t)arg & ~0x3ff);
23
- tcg_out_ld(s, TCG_TYPE_PTR, ret, ret, (uintptr_t)arg & 0x3ff);
24
-}
25
-
26
static void tcg_out_sety(TCGContext *s, TCGReg rs)
27
{
28
tcg_out32(s, WRY | INSN_RS1(TCG_REG_G0) | INSN_RS2(rs));
29
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
30
31
switch (opc) {
32
case INDEX_op_goto_tb:
33
- if (s->tb_jmp_insn_offset) {
34
- /* direct jump method */
35
- if (USE_REG_TB) {
36
- /* make sure the patch is 8-byte aligned. */
37
- if ((intptr_t)s->code_ptr & 4) {
38
- tcg_out_nop(s);
39
- }
40
- s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
41
- tcg_out_sethi(s, TCG_REG_T1, 0);
42
- tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, 0, ARITH_OR);
43
- tcg_out_arith(s, TCG_REG_G0, TCG_REG_TB, TCG_REG_T1, JMPL);
44
- tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD);
45
- } else {
46
- s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
47
- tcg_out32(s, CALL);
48
+ qemu_build_assert(TCG_TARGET_HAS_direct_jump);
49
+ /* Direct jump. */
50
+ if (USE_REG_TB) {
51
+ /* make sure the patch is 8-byte aligned. */
52
+ if ((intptr_t)s->code_ptr & 4) {
53
tcg_out_nop(s);
54
}
55
+ s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
56
+ tcg_out_sethi(s, TCG_REG_T1, 0);
57
+ tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, 0, ARITH_OR);
58
+ tcg_out_arith(s, TCG_REG_G0, TCG_REG_TB, TCG_REG_T1, JMPL);
59
+ tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD);
60
} else {
61
- /* indirect jump method */
62
- tcg_out_ld_ptr(s, TCG_REG_TB, s->tb_jmp_target_addr + a0);
63
- tcg_out_arithi(s, TCG_REG_G0, TCG_REG_TB, 0, JMPL);
64
+ s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
65
+ tcg_out32(s, CALL);
66
tcg_out_nop(s);
67
}
68
set_jmp_reset_offset(s, a0);
69
--
70
2.34.1
71
72
diff view generated by jsdifflib
Deleted patch
1
Test TCG_TARGET_HAS_direct_jump instead of testing an
2
implementation pointer.
3
1
4
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
5
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
---
8
tcg/aarch64/tcg-target.c.inc | 2 +-
9
tcg/arm/tcg-target.c.inc | 2 +-
10
tcg/loongarch64/tcg-target.c.inc | 2 +-
11
tcg/mips/tcg-target.c.inc | 2 +-
12
tcg/riscv/tcg-target.c.inc | 2 +-
13
tcg/tci/tcg-target.c.inc | 2 +-
14
6 files changed, 6 insertions(+), 6 deletions(-)
15
16
diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
17
index XXXXXXX..XXXXXXX 100644
18
--- a/tcg/aarch64/tcg-target.c.inc
19
+++ b/tcg/aarch64/tcg-target.c.inc
20
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
21
22
switch (opc) {
23
case INDEX_op_goto_tb:
24
- tcg_debug_assert(s->tb_jmp_insn_offset != NULL);
25
+ qemu_build_assert(TCG_TARGET_HAS_direct_jump);
26
/*
27
* Ensure that ADRP+ADD are 8-byte aligned so that an atomic
28
* write can be used to patch the target address.
29
diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
30
index XXXXXXX..XXXXXXX 100644
31
--- a/tcg/arm/tcg-target.c.inc
32
+++ b/tcg/arm/tcg-target.c.inc
33
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
34
intptr_t ptr, dif, dil;
35
TCGReg base = TCG_REG_PC;
36
37
- tcg_debug_assert(s->tb_jmp_insn_offset == 0);
38
+ qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
39
ptr = (intptr_t)tcg_splitwx_to_rx(s->tb_jmp_target_addr + args[0]);
40
dif = tcg_pcrel_diff(s, (void *)ptr) - 8;
41
dil = sextract32(dif, 0, 12);
42
diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc
43
index XXXXXXX..XXXXXXX 100644
44
--- a/tcg/loongarch64/tcg-target.c.inc
45
+++ b/tcg/loongarch64/tcg-target.c.inc
46
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
47
48
switch (opc) {
49
case INDEX_op_goto_tb:
50
- tcg_debug_assert(s->tb_jmp_insn_offset != NULL);
51
+ qemu_build_assert(TCG_TARGET_HAS_direct_jump);
52
/*
53
* Ensure that patch area is 8-byte aligned so that an
54
* atomic write can be used to patch the target address.
55
diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc
56
index XXXXXXX..XXXXXXX 100644
57
--- a/tcg/mips/tcg-target.c.inc
58
+++ b/tcg/mips/tcg-target.c.inc
59
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
60
switch (opc) {
61
case INDEX_op_goto_tb:
62
/* indirect jump method */
63
- tcg_debug_assert(s->tb_jmp_insn_offset == 0);
64
+ qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
65
tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_REG_ZERO,
66
(uintptr_t)(s->tb_jmp_target_addr + a0));
67
tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0);
68
diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
69
index XXXXXXX..XXXXXXX 100644
70
--- a/tcg/riscv/tcg-target.c.inc
71
+++ b/tcg/riscv/tcg-target.c.inc
72
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
73
74
switch (opc) {
75
case INDEX_op_goto_tb:
76
- assert(s->tb_jmp_insn_offset == 0);
77
+ qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
78
/* indirect jump method */
79
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO,
80
(uintptr_t)(s->tb_jmp_target_addr + a0));
81
diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc
82
index XXXXXXX..XXXXXXX 100644
83
--- a/tcg/tci/tcg-target.c.inc
84
+++ b/tcg/tci/tcg-target.c.inc
85
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
86
87
switch (opc) {
88
case INDEX_op_goto_tb:
89
- tcg_debug_assert(s->tb_jmp_insn_offset == 0);
90
+ qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
91
/* indirect jump method. */
92
tcg_out_op_p(s, opc, s->tb_jmp_target_addr + args[0]);
93
set_jmp_reset_offset(s, args[0]);
94
--
95
2.34.1
96
97
diff view generated by jsdifflib
Deleted patch
1
Similar to the existing set_jmp_reset_offset. Move any assert for
2
TCG_TARGET_HAS_direct_jump into the new function (which now cannot
3
be build-time). Will be unused if TCG_TARGET_HAS_direct_jump is
4
constant 0, but we can't test for constant in the preprocessor,
5
so just mark it G_GNUC_UNUSED.
6
1
7
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
---
10
tcg/tcg.c | 10 ++++++++++
11
tcg/aarch64/tcg-target.c.inc | 3 +--
12
tcg/i386/tcg-target.c.inc | 3 +--
13
tcg/loongarch64/tcg-target.c.inc | 3 +--
14
tcg/ppc/tcg-target.c.inc | 7 +++----
15
tcg/s390x/tcg-target.c.inc | 2 +-
16
tcg/sparc64/tcg-target.c.inc | 5 ++---
17
7 files changed, 19 insertions(+), 14 deletions(-)
18
19
diff --git a/tcg/tcg.c b/tcg/tcg.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/tcg/tcg.c
22
+++ b/tcg/tcg.c
23
@@ -XXX,XX +XXX,XX @@ static void set_jmp_reset_offset(TCGContext *s, int which)
24
s->tb_jmp_reset_offset[which] = tcg_current_code_size(s);
25
}
26
27
+static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which)
28
+{
29
+ /*
30
+ * We will check for overflow at the end of the opcode loop in
31
+ * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
32
+ */
33
+ tcg_debug_assert(TCG_TARGET_HAS_direct_jump);
34
+ s->tb_jmp_insn_offset[which] = tcg_current_code_size(s);
35
+}
36
+
37
/* Signal overflow, starting over with fewer guest insns. */
38
static G_NORETURN
39
void tcg_raise_tb_overflow(TCGContext *s)
40
diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
41
index XXXXXXX..XXXXXXX 100644
42
--- a/tcg/aarch64/tcg-target.c.inc
43
+++ b/tcg/aarch64/tcg-target.c.inc
44
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
45
46
switch (opc) {
47
case INDEX_op_goto_tb:
48
- qemu_build_assert(TCG_TARGET_HAS_direct_jump);
49
/*
50
* Ensure that ADRP+ADD are 8-byte aligned so that an atomic
51
* write can be used to patch the target address.
52
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
53
if ((uintptr_t)s->code_ptr & 7) {
54
tcg_out32(s, NOP);
55
}
56
- s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
57
+ set_jmp_insn_offset(s, a0);
58
/*
59
* actual branch destination will be patched by
60
* tb_target_set_jmp_target later
61
diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
62
index XXXXXXX..XXXXXXX 100644
63
--- a/tcg/i386/tcg-target.c.inc
64
+++ b/tcg/i386/tcg-target.c.inc
65
@@ -XXX,XX +XXX,XX @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
66
67
switch (opc) {
68
case INDEX_op_goto_tb:
69
- qemu_build_assert(TCG_TARGET_HAS_direct_jump);
70
{
71
/*
72
* Jump displacement must be aligned for atomic patching;
73
@@ -XXX,XX +XXX,XX @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
74
tcg_out_nopn(s, gap - 1);
75
}
76
tcg_out8(s, OPC_JMP_long); /* jmp im */
77
- s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
78
+ set_jmp_insn_offset(s, a0);
79
tcg_out32(s, 0);
80
}
81
set_jmp_reset_offset(s, a0);
82
diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc
83
index XXXXXXX..XXXXXXX 100644
84
--- a/tcg/loongarch64/tcg-target.c.inc
85
+++ b/tcg/loongarch64/tcg-target.c.inc
86
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
87
88
switch (opc) {
89
case INDEX_op_goto_tb:
90
- qemu_build_assert(TCG_TARGET_HAS_direct_jump);
91
/*
92
* Ensure that patch area is 8-byte aligned so that an
93
* atomic write can be used to patch the target address.
94
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
95
if ((uintptr_t)s->code_ptr & 7) {
96
tcg_out_nop(s);
97
}
98
- s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
99
+ set_jmp_insn_offset(s, a0);
100
/*
101
* actual branch destination will be patched by
102
* tb_target_set_jmp_target later
103
diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
104
index XXXXXXX..XXXXXXX 100644
105
--- a/tcg/ppc/tcg-target.c.inc
106
+++ b/tcg/ppc/tcg-target.c.inc
107
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
108
109
switch (opc) {
110
case INDEX_op_goto_tb:
111
- qemu_build_assert(TCG_TARGET_HAS_direct_jump);
112
/* Direct jump. */
113
if (TCG_TARGET_REG_BITS == 64) {
114
/* Ensure the next insns are 8 or 16-byte aligned. */
115
while ((uintptr_t)s->code_ptr & (have_isa_2_07 ? 15 : 7)) {
116
tcg_out32(s, NOP);
117
}
118
- s->tb_jmp_insn_offset[args[0]] = tcg_current_code_size(s);
119
+ set_jmp_insn_offset(s, args[0]);
120
tcg_out32(s, ADDIS | TAI(TCG_REG_TB, TCG_REG_TB, 0));
121
tcg_out32(s, ADDI | TAI(TCG_REG_TB, TCG_REG_TB, 0));
122
} else {
123
- s->tb_jmp_insn_offset[args[0]] = tcg_current_code_size(s);
124
+ set_jmp_insn_offset(s, args[0]);
125
tcg_out32(s, B);
126
- s->tb_jmp_reset_offset[args[0]] = tcg_current_code_size(s);
127
+ set_jmp_reset_offset(s, args[0]);
128
break;
129
}
130
tcg_out32(s, MTSPR | RS(TCG_REG_TB) | CTR);
131
diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc
132
index XXXXXXX..XXXXXXX 100644
133
--- a/tcg/s390x/tcg-target.c.inc
134
+++ b/tcg/s390x/tcg-target.c.inc
135
@@ -XXX,XX +XXX,XX @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
136
tcg_out16(s, NOP);
137
}
138
tcg_out16(s, RIL_BRCL | (S390_CC_ALWAYS << 4));
139
- s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
140
+ set_jmp_insn_offset(s, a0);
141
s->code_ptr += 2;
142
set_jmp_reset_offset(s, a0);
143
break;
144
diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc
145
index XXXXXXX..XXXXXXX 100644
146
--- a/tcg/sparc64/tcg-target.c.inc
147
+++ b/tcg/sparc64/tcg-target.c.inc
148
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
149
150
switch (opc) {
151
case INDEX_op_goto_tb:
152
- qemu_build_assert(TCG_TARGET_HAS_direct_jump);
153
/* Direct jump. */
154
if (USE_REG_TB) {
155
/* make sure the patch is 8-byte aligned. */
156
if ((intptr_t)s->code_ptr & 4) {
157
tcg_out_nop(s);
158
}
159
- s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
160
+ set_jmp_insn_offset(s, a0);
161
tcg_out_sethi(s, TCG_REG_T1, 0);
162
tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, 0, ARITH_OR);
163
tcg_out_arith(s, TCG_REG_G0, TCG_REG_TB, TCG_REG_T1, JMPL);
164
tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD);
165
} else {
166
- s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
167
+ set_jmp_insn_offset(s, a0);
168
tcg_out32(s, CALL);
169
tcg_out_nop(s);
170
}
171
--
172
2.34.1
173
174
diff view generated by jsdifflib
Deleted patch
1
Similar to the existing set_jmp_reset_offset. Include the
2
rw->rx address space conversion done by arm and s390x, and
3
forgotten by mips and riscv.
4
1
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
---
9
tcg/tcg.c | 9 +++++++++
10
tcg/arm/tcg-target.c.inc | 2 +-
11
tcg/mips/tcg-target.c.inc | 2 +-
12
tcg/riscv/tcg-target.c.inc | 2 +-
13
tcg/tci/tcg-target.c.inc | 2 +-
14
5 files changed, 13 insertions(+), 4 deletions(-)
15
16
diff --git a/tcg/tcg.c b/tcg/tcg.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/tcg/tcg.c
19
+++ b/tcg/tcg.c
20
@@ -XXX,XX +XXX,XX @@ static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which)
21
s->tb_jmp_insn_offset[which] = tcg_current_code_size(s);
22
}
23
24
+static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which)
25
+{
26
+ /*
27
+ * Return the read-execute version of the pointer, for the benefit
28
+ * of any pc-relative addressing mode.
29
+ */
30
+ return (uintptr_t)tcg_splitwx_to_rx(&s->tb_jmp_target_addr[which]);
31
+}
32
+
33
/* Signal overflow, starting over with fewer guest insns. */
34
static G_NORETURN
35
void tcg_raise_tb_overflow(TCGContext *s)
36
diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
37
index XXXXXXX..XXXXXXX 100644
38
--- a/tcg/arm/tcg-target.c.inc
39
+++ b/tcg/arm/tcg-target.c.inc
40
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
41
TCGReg base = TCG_REG_PC;
42
43
qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
44
- ptr = (intptr_t)tcg_splitwx_to_rx(s->tb_jmp_target_addr + args[0]);
45
+ ptr = get_jmp_target_addr(s, args[0]);
46
dif = tcg_pcrel_diff(s, (void *)ptr) - 8;
47
dil = sextract32(dif, 0, 12);
48
if (dif != dil) {
49
diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc
50
index XXXXXXX..XXXXXXX 100644
51
--- a/tcg/mips/tcg-target.c.inc
52
+++ b/tcg/mips/tcg-target.c.inc
53
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
54
/* indirect jump method */
55
qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
56
tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_REG_ZERO,
57
- (uintptr_t)(s->tb_jmp_target_addr + a0));
58
+ get_jmp_target_addr(s, a0));
59
tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0);
60
tcg_out_nop(s);
61
set_jmp_reset_offset(s, a0);
62
diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
63
index XXXXXXX..XXXXXXX 100644
64
--- a/tcg/riscv/tcg-target.c.inc
65
+++ b/tcg/riscv/tcg-target.c.inc
66
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
67
qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
68
/* indirect jump method */
69
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO,
70
- (uintptr_t)(s->tb_jmp_target_addr + a0));
71
+ get_jmp_target_addr(s, a0));
72
tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, TCG_REG_TMP0, 0);
73
set_jmp_reset_offset(s, a0);
74
break;
75
diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc
76
index XXXXXXX..XXXXXXX 100644
77
--- a/tcg/tci/tcg-target.c.inc
78
+++ b/tcg/tci/tcg-target.c.inc
79
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
80
case INDEX_op_goto_tb:
81
qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
82
/* indirect jump method. */
83
- tcg_out_op_p(s, opc, s->tb_jmp_target_addr + args[0]);
84
+ tcg_out_op_p(s, opc, (void *)get_jmp_target_addr(s, args[0]));
85
set_jmp_reset_offset(s, args[0]);
86
break;
87
88
--
89
2.34.1
90
91
diff view generated by jsdifflib
1
The INDEX_op_goto_tb opcode needs no register allocation.
1
Pass the address of the last byte to be changed, rather than
2
Split out a dedicated helper function for it.
2
the first address past the last byte. This avoids overflow
3
when the last page of the address space is involved.
3
4
4
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
5
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
5
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
---
7
---
8
tcg/tcg.c | 4 ++
8
include/exec/cpu-all.h | 2 +-
9
tcg/aarch64/tcg-target.c.inc | 40 ++++++++++---------
9
accel/tcg/user-exec.c | 11 +++++------
10
tcg/arm/tcg-target.c.inc | 49 ++++++++++++-----------
10
linux-user/mmap.c | 2 +-
11
tcg/i386/tcg-target.c.inc | 33 ++++++++--------
11
3 files changed, 7 insertions(+), 8 deletions(-)
12
tcg/loongarch64/tcg-target.c.inc | 38 +++++++++---------
13
tcg/mips/tcg-target.c.inc | 21 +++++-----
14
tcg/ppc/tcg-target.c.inc | 52 ++++++++++++------------
15
tcg/riscv/tcg-target.c.inc | 20 +++++-----
16
tcg/s390x/tcg-target.c.inc | 31 ++++++++-------
17
tcg/sparc64/tcg-target.c.inc | 68 +++++++++++++++++---------------
18
tcg/tci/tcg-target.c.inc | 16 ++++----
19
11 files changed, 199 insertions(+), 173 deletions(-)
20
12
21
diff --git a/tcg/tcg.c b/tcg/tcg.c
13
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
22
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
23
--- a/tcg/tcg.c
15
--- a/include/exec/cpu-all.h
24
+++ b/tcg/tcg.c
16
+++ b/include/exec/cpu-all.h
25
@@ -XXX,XX +XXX,XX @@ static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
17
@@ -XXX,XX +XXX,XX @@ int walk_memory_regions(void *, walk_memory_regions_fn);
26
static void tcg_out_movi(TCGContext *s, TCGType type,
18
27
TCGReg ret, tcg_target_long arg);
19
int page_get_flags(target_ulong address);
28
static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg);
20
void page_set_flags(target_ulong start, target_ulong last, int flags);
29
+static void tcg_out_goto_tb(TCGContext *s, int which);
21
-void page_reset_target_data(target_ulong start, target_ulong end);
30
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
22
+void page_reset_target_data(target_ulong start, target_ulong last);
31
const TCGArg args[TCG_MAX_OP_ARGS],
23
int page_check_range(target_ulong start, target_ulong len, int flags);
32
const int const_args[TCG_MAX_OP_ARGS]);
24
33
@@ -XXX,XX +XXX,XX @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start)
25
/**
34
case INDEX_op_exit_tb:
26
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
35
tcg_out_exit_tb(s, op->args[0]);
36
break;
37
+ case INDEX_op_goto_tb:
38
+ tcg_out_goto_tb(s, op->args[0]);
39
+ break;
40
case INDEX_op_dup2_vec:
41
if (tcg_reg_alloc_dup2(s, op)) {
42
break;
43
diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
44
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
45
--- a/tcg/aarch64/tcg-target.c.inc
28
--- a/accel/tcg/user-exec.c
46
+++ b/tcg/aarch64/tcg-target.c.inc
29
+++ b/accel/tcg/user-exec.c
47
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
30
@@ -XXX,XX +XXX,XX @@ void page_set_flags(target_ulong start, target_ulong last, int flags)
48
}
31
}
32
33
if (!flags || reset) {
34
- page_reset_target_data(start, last + 1);
35
+ page_reset_target_data(start, last);
36
inval_tb |= pageflags_unset(start, last);
37
}
38
if (flags) {
39
@@ -XXX,XX +XXX,XX @@ typedef struct TargetPageDataNode {
40
41
static IntervalTreeRoot targetdata_root;
42
43
-void page_reset_target_data(target_ulong start, target_ulong end)
44
+void page_reset_target_data(target_ulong start, target_ulong last)
45
{
46
IntervalTreeNode *n, *next;
47
- target_ulong last;
48
49
assert_memory_lock();
50
51
- start = start & TARGET_PAGE_MASK;
52
- last = TARGET_PAGE_ALIGN(end) - 1;
53
+ start &= TARGET_PAGE_MASK;
54
+ last |= ~TARGET_PAGE_MASK;
55
56
for (n = interval_tree_iter_first(&targetdata_root, start, last),
57
next = n ? interval_tree_iter_next(n, start, last) : NULL;
58
@@ -XXX,XX +XXX,XX @@ void *page_get_target_data(target_ulong address)
59
return t->data[(page - region) >> TARGET_PAGE_BITS];
49
}
60
}
50
61
#else
51
+static void tcg_out_goto_tb(TCGContext *s, int which)
62
-void page_reset_target_data(target_ulong start, target_ulong end) { }
52
+{
63
+void page_reset_target_data(target_ulong start, target_ulong last) { }
53
+ /*
64
#endif /* TARGET_PAGE_DATA_SIZE */
54
+ * Ensure that ADRP+ADD are 8-byte aligned so that an atomic
65
55
+ * write can be used to patch the target address.
66
/* The softmmu versions of these helpers are in cputlb.c. */
56
+ */
67
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
57
+ if ((uintptr_t)s->code_ptr & 7) {
58
+ tcg_out32(s, NOP);
59
+ }
60
+ set_jmp_insn_offset(s, which);
61
+ /*
62
+ * actual branch destination will be patched by
63
+ * tb_target_set_jmp_target later
64
+ */
65
+ tcg_out_insn(s, 3406, ADRP, TCG_REG_TMP, 0);
66
+ tcg_out_insn(s, 3401, ADDI, TCG_TYPE_I64, TCG_REG_TMP, TCG_REG_TMP, 0);
67
+ tcg_out_insn(s, 3207, BR, TCG_REG_TMP);
68
+ set_jmp_reset_offset(s, which);
69
+}
70
+
71
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
72
const TCGArg args[TCG_MAX_OP_ARGS],
73
const int const_args[TCG_MAX_OP_ARGS])
74
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
75
#define REG0(I) (const_args[I] ? TCG_REG_XZR : (TCGReg)args[I])
76
77
switch (opc) {
78
- case INDEX_op_goto_tb:
79
- /*
80
- * Ensure that ADRP+ADD are 8-byte aligned so that an atomic
81
- * write can be used to patch the target address.
82
- */
83
- if ((uintptr_t)s->code_ptr & 7) {
84
- tcg_out32(s, NOP);
85
- }
86
- set_jmp_insn_offset(s, a0);
87
- /*
88
- * actual branch destination will be patched by
89
- * tb_target_set_jmp_target later
90
- */
91
- tcg_out_insn(s, 3406, ADRP, TCG_REG_TMP, 0);
92
- tcg_out_insn(s, 3401, ADDI, TCG_TYPE_I64, TCG_REG_TMP, TCG_REG_TMP, 0);
93
- tcg_out_insn(s, 3207, BR, TCG_REG_TMP);
94
- set_jmp_reset_offset(s, a0);
95
- break;
96
-
97
case INDEX_op_goto_ptr:
98
tcg_out_insn(s, 3207, BR, a0);
99
break;
100
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
101
case INDEX_op_mov_i64:
102
case INDEX_op_call: /* Always emitted via tcg_out_call. */
103
case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
104
+ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */
105
default:
106
g_assert_not_reached();
107
}
108
diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
109
index XXXXXXX..XXXXXXX 100644
68
index XXXXXXX..XXXXXXX 100644
110
--- a/tcg/arm/tcg-target.c.inc
69
--- a/linux-user/mmap.c
111
+++ b/tcg/arm/tcg-target.c.inc
70
+++ b/linux-user/mmap.c
112
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg)
71
@@ -XXX,XX +XXX,XX @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice)
113
tcg_out_epilogue(s);
72
if (can_passthrough_madvise(start, end)) {
114
}
73
ret = get_errno(madvise(g2h_untagged(start), len, advice));
115
74
if ((advice == MADV_DONTNEED) && (ret == 0)) {
116
+static void tcg_out_goto_tb(TCGContext *s, int which)
75
- page_reset_target_data(start, start + len);
117
+{
76
+ page_reset_target_data(start, start + len - 1);
118
+ /* Indirect jump method */
77
}
119
+ intptr_t ptr, dif, dil;
78
}
120
+ TCGReg base = TCG_REG_PC;
121
+
122
+ qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
123
+ ptr = get_jmp_target_addr(s, which);
124
+ dif = tcg_pcrel_diff(s, (void *)ptr) - 8;
125
+ dil = sextract32(dif, 0, 12);
126
+ if (dif != dil) {
127
+ /*
128
+ * The TB is close, but outside the 12 bits addressable by
129
+ * the load. We can extend this to 20 bits with a sub of a
130
+ * shifted immediate from pc. In the vastly unlikely event
131
+ * the code requires more than 1MB, we'll use 2 insns and
132
+ * be no worse off.
133
+ */
134
+ base = TCG_REG_R0;
135
+ tcg_out_movi32(s, COND_AL, base, ptr - dil);
136
+ }
137
+ tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, base, dil);
138
+ set_jmp_reset_offset(s, which);
139
+}
140
+
141
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
142
const TCGArg args[TCG_MAX_OP_ARGS],
143
const int const_args[TCG_MAX_OP_ARGS])
144
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
145
int c;
146
147
switch (opc) {
148
- case INDEX_op_goto_tb:
149
- {
150
- /* Indirect jump method */
151
- intptr_t ptr, dif, dil;
152
- TCGReg base = TCG_REG_PC;
153
-
154
- qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
155
- ptr = get_jmp_target_addr(s, args[0]);
156
- dif = tcg_pcrel_diff(s, (void *)ptr) - 8;
157
- dil = sextract32(dif, 0, 12);
158
- if (dif != dil) {
159
- /* The TB is close, but outside the 12 bits addressable by
160
- the load. We can extend this to 20 bits with a sub of a
161
- shifted immediate from pc. In the vastly unlikely event
162
- the code requires more than 1MB, we'll use 2 insns and
163
- be no worse off. */
164
- base = TCG_REG_R0;
165
- tcg_out_movi32(s, COND_AL, base, ptr - dil);
166
- }
167
- tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, base, dil);
168
- set_jmp_reset_offset(s, args[0]);
169
- }
170
- break;
171
case INDEX_op_goto_ptr:
172
tcg_out_b_reg(s, COND_AL, args[0]);
173
break;
174
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
175
case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
176
case INDEX_op_call: /* Always emitted via tcg_out_call. */
177
case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
178
+ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */
179
default:
180
tcg_abort();
181
}
182
diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
183
index XXXXXXX..XXXXXXX 100644
184
--- a/tcg/i386/tcg-target.c.inc
185
+++ b/tcg/i386/tcg-target.c.inc
186
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
187
}
188
}
189
190
+static void tcg_out_goto_tb(TCGContext *s, int which)
191
+{
192
+ /*
193
+ * Jump displacement must be aligned for atomic patching;
194
+ * see if we need to add extra nops before jump
195
+ */
196
+ int gap = QEMU_ALIGN_PTR_UP(s->code_ptr + 1, 4) - s->code_ptr;
197
+ if (gap != 1) {
198
+ tcg_out_nopn(s, gap - 1);
199
+ }
200
+ tcg_out8(s, OPC_JMP_long); /* jmp im */
201
+ set_jmp_insn_offset(s, which);
202
+ tcg_out32(s, 0);
203
+ set_jmp_reset_offset(s, which);
204
+}
205
+
206
static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
207
const TCGArg args[TCG_MAX_OP_ARGS],
208
const int const_args[TCG_MAX_OP_ARGS])
209
@@ -XXX,XX +XXX,XX @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
210
const_a2 = const_args[2];
211
212
switch (opc) {
213
- case INDEX_op_goto_tb:
214
- {
215
- /*
216
- * Jump displacement must be aligned for atomic patching;
217
- * see if we need to add extra nops before jump
218
- */
219
- int gap = QEMU_ALIGN_PTR_UP(s->code_ptr + 1, 4) - s->code_ptr;
220
- if (gap != 1) {
221
- tcg_out_nopn(s, gap - 1);
222
- }
223
- tcg_out8(s, OPC_JMP_long); /* jmp im */
224
- set_jmp_insn_offset(s, a0);
225
- tcg_out32(s, 0);
226
- }
227
- set_jmp_reset_offset(s, a0);
228
- break;
229
case INDEX_op_goto_ptr:
230
/* jmp to the given host address (could be epilogue) */
231
tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, a0);
232
@@ -XXX,XX +XXX,XX @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
233
case INDEX_op_mov_i64:
234
case INDEX_op_call: /* Always emitted via tcg_out_call. */
235
case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
236
+ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */
237
default:
238
tcg_abort();
239
}
240
diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc
241
index XXXXXXX..XXXXXXX 100644
242
--- a/tcg/loongarch64/tcg-target.c.inc
243
+++ b/tcg/loongarch64/tcg-target.c.inc
244
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
245
}
246
}
247
248
+static void tcg_out_goto_tb(TCGContext *s, int which)
249
+{
250
+ /*
251
+ * Ensure that patch area is 8-byte aligned so that an
252
+ * atomic write can be used to patch the target address.
253
+ */
254
+ if ((uintptr_t)s->code_ptr & 7) {
255
+ tcg_out_nop(s);
256
+ }
257
+ set_jmp_insn_offset(s, which);
258
+ /*
259
+ * actual branch destination will be patched by
260
+ * tb_target_set_jmp_target later
261
+ */
262
+ tcg_out_opc_pcaddu18i(s, TCG_REG_TMP0, 0);
263
+ tcg_out_opc_jirl(s, TCG_REG_ZERO, TCG_REG_TMP0, 0);
264
+ set_jmp_reset_offset(s, which);
265
+}
266
+
267
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
268
const TCGArg args[TCG_MAX_OP_ARGS],
269
const int const_args[TCG_MAX_OP_ARGS])
270
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
271
int c2 = const_args[2];
272
273
switch (opc) {
274
- case INDEX_op_goto_tb:
275
- /*
276
- * Ensure that patch area is 8-byte aligned so that an
277
- * atomic write can be used to patch the target address.
278
- */
279
- if ((uintptr_t)s->code_ptr & 7) {
280
- tcg_out_nop(s);
281
- }
282
- set_jmp_insn_offset(s, a0);
283
- /*
284
- * actual branch destination will be patched by
285
- * tb_target_set_jmp_target later
286
- */
287
- tcg_out_opc_pcaddu18i(s, TCG_REG_TMP0, 0);
288
- tcg_out_opc_jirl(s, TCG_REG_ZERO, TCG_REG_TMP0, 0);
289
- set_jmp_reset_offset(s, a0);
290
- break;
291
-
292
case INDEX_op_mb:
293
tcg_out_mb(s, a0);
294
break;
295
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
296
case INDEX_op_mov_i64:
297
case INDEX_op_call: /* Always emitted via tcg_out_call. */
298
case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
299
+ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */
300
default:
301
g_assert_not_reached();
302
}
303
diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc
304
index XXXXXXX..XXXXXXX 100644
305
--- a/tcg/mips/tcg-target.c.inc
306
+++ b/tcg/mips/tcg-target.c.inc
307
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
308
tcg_out_opc_imm(s, OPC_ORI, TCG_REG_V0, b0, a0 & 0xffff);
309
}
310
311
+static void tcg_out_goto_tb(TCGContext *s, int which)
312
+{
313
+ /* indirect jump method */
314
+ qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
315
+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_REG_ZERO,
316
+ get_jmp_target_addr(s, which));
317
+ tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0);
318
+ tcg_out_nop(s);
319
+ set_jmp_reset_offset(s, which);
320
+}
321
+
322
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
323
const TCGArg args[TCG_MAX_OP_ARGS],
324
const int const_args[TCG_MAX_OP_ARGS])
325
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
326
c2 = const_args[2];
327
328
switch (opc) {
329
- case INDEX_op_goto_tb:
330
- /* indirect jump method */
331
- qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
332
- tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_REG_ZERO,
333
- get_jmp_target_addr(s, a0));
334
- tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0);
335
- tcg_out_nop(s);
336
- set_jmp_reset_offset(s, a0);
337
- break;
338
case INDEX_op_goto_ptr:
339
/* jmp to the given host address (could be epilogue) */
340
tcg_out_opc_reg(s, OPC_JR, 0, a0, 0);
341
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
342
case INDEX_op_mov_i64:
343
case INDEX_op_call: /* Always emitted via tcg_out_call. */
344
case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
345
+ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */
346
default:
347
tcg_abort();
348
}
349
diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
350
index XXXXXXX..XXXXXXX 100644
351
--- a/tcg/ppc/tcg-target.c.inc
352
+++ b/tcg/ppc/tcg-target.c.inc
353
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg)
354
tcg_out_b(s, 0, tcg_code_gen_epilogue);
355
}
356
357
+static void tcg_out_goto_tb(TCGContext *s, int which)
358
+{
359
+ /* Direct jump. */
360
+ if (TCG_TARGET_REG_BITS == 64) {
361
+ /* Ensure the next insns are 8 or 16-byte aligned. */
362
+ while ((uintptr_t)s->code_ptr & (have_isa_2_07 ? 15 : 7)) {
363
+ tcg_out32(s, NOP);
364
+ }
365
+ set_jmp_insn_offset(s, which);
366
+ tcg_out32(s, ADDIS | TAI(TCG_REG_TB, TCG_REG_TB, 0));
367
+ tcg_out32(s, ADDI | TAI(TCG_REG_TB, TCG_REG_TB, 0));
368
+ tcg_out32(s, MTSPR | RS(TCG_REG_TB) | CTR);
369
+ tcg_out32(s, BCCTR | BO_ALWAYS);
370
+ set_jmp_reset_offset(s, which);
371
+ if (USE_REG_TB) {
372
+ /* For the unlinked case, need to reset TCG_REG_TB. */
373
+ tcg_out_mem_long(s, ADDI, ADD, TCG_REG_TB, TCG_REG_TB,
374
+ -tcg_current_code_size(s));
375
+ }
376
+ } else {
377
+ set_jmp_insn_offset(s, which);
378
+ tcg_out32(s, B);
379
+ set_jmp_reset_offset(s, which);
380
+ }
381
+}
382
+
383
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
384
const TCGArg args[TCG_MAX_OP_ARGS],
385
const int const_args[TCG_MAX_OP_ARGS])
386
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
387
TCGArg a0, a1, a2;
388
389
switch (opc) {
390
- case INDEX_op_goto_tb:
391
- /* Direct jump. */
392
- if (TCG_TARGET_REG_BITS == 64) {
393
- /* Ensure the next insns are 8 or 16-byte aligned. */
394
- while ((uintptr_t)s->code_ptr & (have_isa_2_07 ? 15 : 7)) {
395
- tcg_out32(s, NOP);
396
- }
397
- set_jmp_insn_offset(s, args[0]);
398
- tcg_out32(s, ADDIS | TAI(TCG_REG_TB, TCG_REG_TB, 0));
399
- tcg_out32(s, ADDI | TAI(TCG_REG_TB, TCG_REG_TB, 0));
400
- } else {
401
- set_jmp_insn_offset(s, args[0]);
402
- tcg_out32(s, B);
403
- set_jmp_reset_offset(s, args[0]);
404
- break;
405
- }
406
- tcg_out32(s, MTSPR | RS(TCG_REG_TB) | CTR);
407
- tcg_out32(s, BCCTR | BO_ALWAYS);
408
- set_jmp_reset_offset(s, args[0]);
409
- if (USE_REG_TB) {
410
- /* For the unlinked case, need to reset TCG_REG_TB. */
411
- tcg_out_mem_long(s, ADDI, ADD, TCG_REG_TB, TCG_REG_TB,
412
- -tcg_current_code_size(s));
413
- }
414
- break;
415
case INDEX_op_goto_ptr:
416
tcg_out32(s, MTSPR | RS(args[0]) | CTR);
417
if (USE_REG_TB) {
418
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
419
case INDEX_op_mov_i64:
420
case INDEX_op_call: /* Always emitted via tcg_out_call. */
421
case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
422
+ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */
423
default:
424
tcg_abort();
425
}
426
diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
427
index XXXXXXX..XXXXXXX 100644
428
--- a/tcg/riscv/tcg-target.c.inc
429
+++ b/tcg/riscv/tcg-target.c.inc
430
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
431
}
432
}
433
434
+static void tcg_out_goto_tb(TCGContext *s, int which)
435
+{
436
+ qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
437
+ /* indirect jump method */
438
+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO,
439
+ get_jmp_target_addr(s, which));
440
+ tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, TCG_REG_TMP0, 0);
441
+ set_jmp_reset_offset(s, which);
442
+}
443
+
444
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
445
const TCGArg args[TCG_MAX_OP_ARGS],
446
const int const_args[TCG_MAX_OP_ARGS])
447
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
448
int c2 = const_args[2];
449
450
switch (opc) {
451
- case INDEX_op_goto_tb:
452
- qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
453
- /* indirect jump method */
454
- tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO,
455
- get_jmp_target_addr(s, a0));
456
- tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, TCG_REG_TMP0, 0);
457
- set_jmp_reset_offset(s, a0);
458
- break;
459
-
460
case INDEX_op_goto_ptr:
461
tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, a0, 0);
462
break;
463
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
464
case INDEX_op_mov_i64:
465
case INDEX_op_call: /* Always emitted via tcg_out_call. */
466
case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
467
+ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */
468
default:
469
g_assert_not_reached();
470
}
471
diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc
472
index XXXXXXX..XXXXXXX 100644
473
--- a/tcg/s390x/tcg-target.c.inc
474
+++ b/tcg/s390x/tcg-target.c.inc
475
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
476
}
477
}
478
479
+static void tcg_out_goto_tb(TCGContext *s, int which)
480
+{
481
+ /*
482
+ * Branch displacement must be aligned for atomic patching;
483
+ * see if we need to add extra nop before branch
484
+ */
485
+ if (!QEMU_PTR_IS_ALIGNED(s->code_ptr + 1, 4)) {
486
+ tcg_out16(s, NOP);
487
+ }
488
+ tcg_out16(s, RIL_BRCL | (S390_CC_ALWAYS << 4));
489
+ set_jmp_insn_offset(s, which);
490
+ s->code_ptr += 2;
491
+ set_jmp_reset_offset(s, which);
492
+}
493
+
494
# define OP_32_64(x) \
495
case glue(glue(INDEX_op_,x),_i32): \
496
case glue(glue(INDEX_op_,x),_i64)
497
@@ -XXX,XX +XXX,XX @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
498
TCGArg a0, a1, a2;
499
500
switch (opc) {
501
- case INDEX_op_goto_tb:
502
- a0 = args[0];
503
- /*
504
- * branch displacement must be aligned for atomic patching;
505
- * see if we need to add extra nop before branch
506
- */
507
- if (!QEMU_PTR_IS_ALIGNED(s->code_ptr + 1, 4)) {
508
- tcg_out16(s, NOP);
509
- }
510
- tcg_out16(s, RIL_BRCL | (S390_CC_ALWAYS << 4));
511
- set_jmp_insn_offset(s, a0);
512
- s->code_ptr += 2;
513
- set_jmp_reset_offset(s, a0);
514
- break;
515
-
516
case INDEX_op_goto_ptr:
517
a0 = args[0];
518
tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, a0);
519
@@ -XXX,XX +XXX,XX @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
520
case INDEX_op_mov_i64:
521
case INDEX_op_call: /* Always emitted via tcg_out_call. */
522
case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
523
+ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */
524
default:
525
tcg_abort();
526
}
527
diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc
528
index XXXXXXX..XXXXXXX 100644
529
--- a/tcg/sparc64/tcg-target.c.inc
530
+++ b/tcg/sparc64/tcg-target.c.inc
531
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
532
tcg_out_arithi(s, TCG_REG_O0, TCG_REG_O0, a0 & 0x3ff, ARITH_OR);
533
}
534
535
+static void tcg_out_goto_tb(TCGContext *s, int which)
536
+{
537
+ /* Direct jump. */
538
+ if (USE_REG_TB) {
539
+ /* make sure the patch is 8-byte aligned. */
540
+ if ((intptr_t)s->code_ptr & 4) {
541
+ tcg_out_nop(s);
542
+ }
543
+ set_jmp_insn_offset(s, which);
544
+ tcg_out_sethi(s, TCG_REG_T1, 0);
545
+ tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, 0, ARITH_OR);
546
+ tcg_out_arith(s, TCG_REG_G0, TCG_REG_TB, TCG_REG_T1, JMPL);
547
+ tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD);
548
+ } else {
549
+ set_jmp_insn_offset(s, which);
550
+ tcg_out32(s, CALL);
551
+ tcg_out_nop(s);
552
+ }
553
+ set_jmp_reset_offset(s, which);
554
+
555
+ /*
556
+ * For the unlinked path of goto_tb, we need to reset TCG_REG_TB
557
+ * to the beginning of this TB.
558
+ */
559
+ if (USE_REG_TB) {
560
+ int c = -tcg_current_code_size(s);
561
+ if (check_fit_i32(c, 13)) {
562
+ tcg_out_arithi(s, TCG_REG_TB, TCG_REG_TB, c, ARITH_ADD);
563
+ } else {
564
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, c);
565
+ tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD);
566
+ }
567
+ }
568
+}
569
+
570
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
571
const TCGArg args[TCG_MAX_OP_ARGS],
572
const int const_args[TCG_MAX_OP_ARGS])
573
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
574
c2 = const_args[2];
575
576
switch (opc) {
577
- case INDEX_op_goto_tb:
578
- /* Direct jump. */
579
- if (USE_REG_TB) {
580
- /* make sure the patch is 8-byte aligned. */
581
- if ((intptr_t)s->code_ptr & 4) {
582
- tcg_out_nop(s);
583
- }
584
- set_jmp_insn_offset(s, a0);
585
- tcg_out_sethi(s, TCG_REG_T1, 0);
586
- tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, 0, ARITH_OR);
587
- tcg_out_arith(s, TCG_REG_G0, TCG_REG_TB, TCG_REG_T1, JMPL);
588
- tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD);
589
- } else {
590
- set_jmp_insn_offset(s, a0);
591
- tcg_out32(s, CALL);
592
- tcg_out_nop(s);
593
- }
594
- set_jmp_reset_offset(s, a0);
595
-
596
- /* For the unlinked path of goto_tb, we need to reset
597
- TCG_REG_TB to the beginning of this TB. */
598
- if (USE_REG_TB) {
599
- c = -tcg_current_code_size(s);
600
- if (check_fit_i32(c, 13)) {
601
- tcg_out_arithi(s, TCG_REG_TB, TCG_REG_TB, c, ARITH_ADD);
602
- } else {
603
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, c);
604
- tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB,
605
- TCG_REG_T1, ARITH_ADD);
606
- }
607
- }
608
- break;
609
case INDEX_op_goto_ptr:
610
tcg_out_arithi(s, TCG_REG_G0, a0, 0, JMPL);
611
if (USE_REG_TB) {
612
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
613
case INDEX_op_mov_i64:
614
case INDEX_op_call: /* Always emitted via tcg_out_call. */
615
case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
616
+ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */
617
default:
618
tcg_abort();
619
}
620
diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc
621
index XXXXXXX..XXXXXXX 100644
622
--- a/tcg/tci/tcg-target.c.inc
623
+++ b/tcg/tci/tcg-target.c.inc
624
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg)
625
tcg_out_op_p(s, INDEX_op_exit_tb, (void *)arg);
626
}
627
628
+static void tcg_out_goto_tb(TCGContext *s, int which)
629
+{
630
+ qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
631
+ /* indirect jump method. */
632
+ tcg_out_op_p(s, INDEX_op_goto_tb, (void *)get_jmp_target_addr(s, which));
633
+ set_jmp_reset_offset(s, which);
634
+}
635
+
636
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
637
const TCGArg args[TCG_MAX_OP_ARGS],
638
const int const_args[TCG_MAX_OP_ARGS])
639
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
640
TCGOpcode exts;
641
642
switch (opc) {
643
- case INDEX_op_goto_tb:
644
- qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
645
- /* indirect jump method. */
646
- tcg_out_op_p(s, opc, (void *)get_jmp_target_addr(s, args[0]));
647
- set_jmp_reset_offset(s, args[0]);
648
- break;
649
-
650
case INDEX_op_goto_ptr:
651
tcg_out_op_r(s, opc, args[0]);
652
break;
653
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
654
case INDEX_op_mov_i64:
655
case INDEX_op_call: /* Always emitted via tcg_out_call. */
656
case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
657
+ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */
658
default:
659
tcg_abort();
660
}
79
}
661
--
80
--
662
2.34.1
81
2.34.1
663
82
664
83
diff view generated by jsdifflib
1
Install empty versions for !TCG_TARGET_HAS_direct_jump hosts.
1
Pass the address of the last byte to be changed, rather than
2
the first address past the last byte. This avoids overflow
3
when the last page of the address space is involved.
2
4
3
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
4
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
5
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
---
7
---
7
tcg/arm/tcg-target.c.inc | 6 ++++++
8
accel/tcg/tb-maint.c | 28 ++++++++++++++++------------
8
tcg/mips/tcg-target.c.inc | 6 ++++++
9
1 file changed, 16 insertions(+), 12 deletions(-)
9
tcg/riscv/tcg-target.c.inc | 6 ++++++
10
tcg/tci/tcg-target.c.inc | 6 ++++++
11
4 files changed, 24 insertions(+)
12
10
13
diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
11
diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c
14
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
15
--- a/tcg/arm/tcg-target.c.inc
13
--- a/accel/tcg/tb-maint.c
16
+++ b/tcg/arm/tcg-target.c.inc
14
+++ b/accel/tcg/tb-maint.c
17
@@ -XXX,XX +XXX,XX @@ static void tcg_out_goto_tb(TCGContext *s, int which)
15
@@ -XXX,XX +XXX,XX @@ static void tb_remove(TranslationBlock *tb)
18
set_jmp_reset_offset(s, which);
19
}
16
}
20
17
21
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
18
/* TODO: For now, still shared with translate-all.c for system mode. */
22
+ uintptr_t jmp_rx, uintptr_t jmp_rw)
19
-#define PAGE_FOR_EACH_TB(start, end, pagedesc, T, N) \
23
+{
20
- for (T = foreach_tb_first(start, end), \
24
+ /* Always indirect, nothing to do */
21
- N = foreach_tb_next(T, start, end); \
25
+}
22
+#define PAGE_FOR_EACH_TB(start, last, pagedesc, T, N) \
26
+
23
+ for (T = foreach_tb_first(start, last), \
27
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
24
+ N = foreach_tb_next(T, start, last); \
28
const TCGArg args[TCG_MAX_OP_ARGS],
25
T != NULL; \
29
const int const_args[TCG_MAX_OP_ARGS])
26
- T = N, N = foreach_tb_next(N, start, end))
30
diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc
27
+ T = N, N = foreach_tb_next(N, start, last))
31
index XXXXXXX..XXXXXXX 100644
28
32
--- a/tcg/mips/tcg-target.c.inc
29
typedef TranslationBlock *PageForEachNext;
33
+++ b/tcg/mips/tcg-target.c.inc
30
34
@@ -XXX,XX +XXX,XX @@ static void tcg_out_goto_tb(TCGContext *s, int which)
31
static PageForEachNext foreach_tb_first(tb_page_addr_t start,
35
set_jmp_reset_offset(s, which);
32
- tb_page_addr_t end)
33
+ tb_page_addr_t last)
34
{
35
- IntervalTreeNode *n = interval_tree_iter_first(&tb_root, start, end - 1);
36
+ IntervalTreeNode *n = interval_tree_iter_first(&tb_root, start, last);
37
return n ? container_of(n, TranslationBlock, itree) : NULL;
36
}
38
}
37
39
38
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
40
static PageForEachNext foreach_tb_next(PageForEachNext tb,
39
+ uintptr_t jmp_rx, uintptr_t jmp_rw)
41
tb_page_addr_t start,
40
+{
42
- tb_page_addr_t end)
41
+ /* Always indirect, nothing to do */
43
+ tb_page_addr_t last)
42
+}
44
{
43
+
45
IntervalTreeNode *n;
44
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
46
45
const TCGArg args[TCG_MAX_OP_ARGS],
47
if (tb) {
46
const int const_args[TCG_MAX_OP_ARGS])
48
- n = interval_tree_iter_next(&tb->itree, start, end - 1);
47
diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
49
+ n = interval_tree_iter_next(&tb->itree, start, last);
48
index XXXXXXX..XXXXXXX 100644
50
if (n) {
49
--- a/tcg/riscv/tcg-target.c.inc
51
return container_of(n, TranslationBlock, itree);
50
+++ b/tcg/riscv/tcg-target.c.inc
52
}
51
@@ -XXX,XX +XXX,XX @@ static void tcg_out_goto_tb(TCGContext *s, int which)
53
@@ -XXX,XX +XXX,XX @@ struct page_collection {
52
set_jmp_reset_offset(s, which);
54
};
55
56
typedef int PageForEachNext;
57
-#define PAGE_FOR_EACH_TB(start, end, pagedesc, tb, n) \
58
+#define PAGE_FOR_EACH_TB(start, last, pagedesc, tb, n) \
59
TB_FOR_EACH_TAGGED((pagedesc)->first_tb, tb, n, page_next)
60
61
#ifdef CONFIG_DEBUG_TCG
62
@@ -XXX,XX +XXX,XX @@ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
63
{
64
TranslationBlock *tb;
65
PageForEachNext n;
66
+ tb_page_addr_t last = end - 1;
67
68
assert_memory_lock();
69
70
- PAGE_FOR_EACH_TB(start, end, unused, tb, n) {
71
+ PAGE_FOR_EACH_TB(start, last, unused, tb, n) {
72
tb_phys_invalidate__locked(tb);
73
}
53
}
74
}
54
75
@@ -XXX,XX +XXX,XX @@ bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc)
55
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
76
bool current_tb_modified;
56
+ uintptr_t jmp_rx, uintptr_t jmp_rw)
77
TranslationBlock *tb;
57
+{
78
PageForEachNext n;
58
+ /* Always indirect, nothing to do */
79
+ tb_page_addr_t last;
59
+}
80
60
+
81
/*
61
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
82
* Without precise smc semantics, or when outside of a TB,
62
const TCGArg args[TCG_MAX_OP_ARGS],
83
@@ -XXX,XX +XXX,XX @@ bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc)
63
const int const_args[TCG_MAX_OP_ARGS])
84
assert_memory_lock();
64
diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc
85
current_tb = tcg_tb_lookup(pc);
65
index XXXXXXX..XXXXXXX 100644
86
66
--- a/tcg/tci/tcg-target.c.inc
87
+ last = addr | ~TARGET_PAGE_MASK;
67
+++ b/tcg/tci/tcg-target.c.inc
88
addr &= TARGET_PAGE_MASK;
68
@@ -XXX,XX +XXX,XX @@ static void tcg_out_goto_tb(TCGContext *s, int which)
89
current_tb_modified = false;
69
set_jmp_reset_offset(s, which);
90
70
}
91
- PAGE_FOR_EACH_TB(addr, addr + TARGET_PAGE_SIZE, unused, tb, n) {
71
92
+ PAGE_FOR_EACH_TB(addr, last, unused, tb, n) {
72
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
93
if (current_tb == tb &&
73
+ uintptr_t jmp_rx, uintptr_t jmp_rw)
94
(tb_cflags(current_tb) & CF_COUNT_MASK) != 1) {
74
+{
95
/*
75
+ /* Always indirect, nothing to do */
96
@@ -XXX,XX +XXX,XX @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages,
76
+}
97
bool current_tb_modified = false;
77
+
98
TranslationBlock *current_tb = retaddr ? tcg_tb_lookup(retaddr) : NULL;
78
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
99
#endif /* TARGET_HAS_PRECISE_SMC */
79
const TCGArg args[TCG_MAX_OP_ARGS],
100
+ tb_page_addr_t last G_GNUC_UNUSED = end - 1;
80
const int const_args[TCG_MAX_OP_ARGS])
101
102
/*
103
* We remove all the TBs in the range [start, end[.
104
* XXX: see if in some cases it could be faster to invalidate all the code
105
*/
106
- PAGE_FOR_EACH_TB(start, end, p, tb, n) {
107
+ PAGE_FOR_EACH_TB(start, last, p, tb, n) {
108
/* NOTE: this is subtle as a TB may span two physical pages */
109
if (n == 0) {
110
/* NOTE: tb_end may be after the end of the page, but
81
--
111
--
82
2.34.1
112
2.34.1
83
113
84
114
diff view generated by jsdifflib
1
The old implementation replaces two insns, swapping between
1
Pass the address of the last byte to be changed, rather than
2
the first address past the last byte. This avoids overflow
3
when the last page of the address space is involved.
2
4
3
    b    <dest>
5
Fixes a bug in the loop comparision where "<= end" would lock
4
    nop
6
one more page than required.
5
    br    x30
6
and
7
    adrp    x30, <dest>
8
    addi    x30, x30, lo12:<dest>
9
    br    x30
10
7
11
There is a race condition in which a thread could be stopped at
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
12
the PC of the second insn, and when restarted does not see the
13
complete address computation and branches to nowhere.
14
15
The new implemetation replaces only one insn, swapping between
16
17
    b    <dest>
18
    br    tmp
19
and
20
    ldr    tmp, <jmp_addr>
21
    br    tmp
22
23
Reported-by: hev <r@hev.cc>
24
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
25
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
26
---
10
---
27
tcg/aarch64/tcg-target.h | 2 +-
11
accel/tcg/tb-maint.c | 22 +++++++++++-----------
28
tcg/aarch64/tcg-target.c.inc | 66 +++++++++++++++---------------------
12
1 file changed, 11 insertions(+), 11 deletions(-)
29
2 files changed, 29 insertions(+), 39 deletions(-)
30
13
31
diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
14
diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c
32
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
33
--- a/tcg/aarch64/tcg-target.h
16
--- a/accel/tcg/tb-maint.c
34
+++ b/tcg/aarch64/tcg-target.h
17
+++ b/accel/tcg/tb-maint.c
35
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ static gint tb_page_addr_cmp(gconstpointer ap, gconstpointer bp, gpointer udata)
36
37
#define TCG_TARGET_INSN_UNIT_SIZE 4
38
#define TCG_TARGET_TLB_DISPLACEMENT_BITS 24
39
-#define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
40
+#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
41
42
typedef enum {
43
TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3,
44
diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
45
index XXXXXXX..XXXXXXX 100644
46
--- a/tcg/aarch64/tcg-target.c.inc
47
+++ b/tcg/aarch64/tcg-target.c.inc
48
@@ -XXX,XX +XXX,XX @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target,
49
tcg_out_call_int(s, target);
50
}
19
}
51
20
52
-void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
21
/*
53
- uintptr_t jmp_rx, uintptr_t jmp_rw)
22
- * Lock a range of pages ([@start,@end[) as well as the pages of all
54
-{
23
+ * Lock a range of pages ([@start,@last]) as well as the pages of all
55
- uintptr_t addr = tb->jmp_target_addr[n];
24
* intersecting TBs.
56
- tcg_insn_unit i1, i2;
25
* Locking order: acquire locks in ascending order of page index.
57
- TCGType rt = TCG_TYPE_I64;
26
*/
58
- TCGReg rd = TCG_REG_TMP;
27
static struct page_collection *page_collection_lock(tb_page_addr_t start,
59
- uint64_t pair;
28
- tb_page_addr_t end)
60
-
29
+ tb_page_addr_t last)
61
- ptrdiff_t offset = addr - jmp_rx;
62
-
63
- if (offset == sextract64(offset, 0, 26)) {
64
- i1 = I3206_B | ((offset >> 2) & 0x3ffffff);
65
- i2 = NOP;
66
- } else {
67
- offset = (addr >> 12) - (jmp_rx >> 12);
68
-
69
- /* patch ADRP */
70
- i1 = I3406_ADRP | (offset & 3) << 29 | (offset & 0x1ffffc) << (5 - 2) | rd;
71
- /* patch ADDI */
72
- i2 = I3401_ADDI | rt << 31 | (addr & 0xfff) << 10 | rd << 5 | rd;
73
- }
74
- pair = (uint64_t)i2 << 32 | i1;
75
- qatomic_set((uint64_t *)jmp_rw, pair);
76
- flush_idcache_range(jmp_rx, jmp_rw, 8);
77
-}
78
-
79
static inline void tcg_out_goto_label(TCGContext *s, TCGLabel *l)
80
{
30
{
81
if (!l->has_value) {
31
struct page_collection *set = g_malloc(sizeof(*set));
82
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
32
tb_page_addr_t index;
83
static void tcg_out_goto_tb(TCGContext *s, int which)
33
PageDesc *pd;
34
35
start >>= TARGET_PAGE_BITS;
36
- end >>= TARGET_PAGE_BITS;
37
- g_assert(start <= end);
38
+ last >>= TARGET_PAGE_BITS;
39
+ g_assert(start <= last);
40
41
set->tree = q_tree_new_full(tb_page_addr_cmp, NULL, NULL,
42
page_entry_destroy);
43
@@ -XXX,XX +XXX,XX @@ static struct page_collection *page_collection_lock(tb_page_addr_t start,
44
retry:
45
q_tree_foreach(set->tree, page_entry_lock, NULL);
46
47
- for (index = start; index <= end; index++) {
48
+ for (index = start; index <= last; index++) {
49
TranslationBlock *tb;
50
PageForEachNext n;
51
52
@@ -XXX,XX +XXX,XX @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages,
53
void tb_invalidate_phys_page(tb_page_addr_t addr)
84
{
54
{
85
/*
55
struct page_collection *pages;
86
- * Ensure that ADRP+ADD are 8-byte aligned so that an atomic
56
- tb_page_addr_t start, end;
87
- * write can be used to patch the target address.
57
+ tb_page_addr_t start, last;
88
+ * Direct branch, or indirect address load, will be patched
58
PageDesc *p;
89
+ * by tb_target_set_jmp_target. Assert indirect load offset
59
90
+ * in range early, regardless of direct branch distance.
60
p = page_find(addr >> TARGET_PAGE_BITS);
91
*/
61
@@ -XXX,XX +XXX,XX @@ void tb_invalidate_phys_page(tb_page_addr_t addr)
92
- if ((uintptr_t)s->code_ptr & 7) {
62
}
93
- tcg_out32(s, NOP);
63
94
- }
64
start = addr & TARGET_PAGE_MASK;
95
+ intptr_t i_off = tcg_pcrel_diff(s, (void *)get_jmp_target_addr(s, which));
65
- end = start + TARGET_PAGE_SIZE;
96
+ tcg_debug_assert(i_off == sextract64(i_off, 0, 21));
66
- pages = page_collection_lock(start, end);
97
+
67
- tb_invalidate_phys_page_range__locked(pages, p, start, end, 0);
98
set_jmp_insn_offset(s, which);
68
+ last = addr | ~TARGET_PAGE_MASK;
99
- /*
69
+ pages = page_collection_lock(start, last);
100
- * actual branch destination will be patched by
70
+ tb_invalidate_phys_page_range__locked(pages, p, start, last + 1, 0);
101
- * tb_target_set_jmp_target later
71
page_collection_unlock(pages);
102
- */
103
- tcg_out_insn(s, 3406, ADRP, TCG_REG_TMP, 0);
104
- tcg_out_insn(s, 3401, ADDI, TCG_TYPE_I64, TCG_REG_TMP, TCG_REG_TMP, 0);
105
+ tcg_out32(s, I3206_B);
106
tcg_out_insn(s, 3207, BR, TCG_REG_TMP);
107
set_jmp_reset_offset(s, which);
108
}
72
}
109
73
110
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
74
@@ -XXX,XX +XXX,XX @@ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
111
+ uintptr_t jmp_rx, uintptr_t jmp_rw)
75
struct page_collection *pages;
112
+{
76
tb_page_addr_t next;
113
+ uintptr_t d_addr = tb->jmp_target_addr[n];
77
114
+ ptrdiff_t d_offset = d_addr - jmp_rx;
78
- pages = page_collection_lock(start, end);
115
+ tcg_insn_unit insn;
79
+ pages = page_collection_lock(start, end - 1);
116
+
80
for (next = (start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
117
+ /* Either directly branch, or indirect branch load. */
81
start < end;
118
+ if (d_offset == sextract64(d_offset, 0, 28)) {
82
start = next, next += TARGET_PAGE_SIZE) {
119
+ insn = deposit32(I3206_B, 0, 26, d_offset >> 2);
83
@@ -XXX,XX +XXX,XX @@ void tb_invalidate_phys_range_fast(ram_addr_t ram_addr,
120
+ } else {
84
{
121
+ uintptr_t i_addr = (uintptr_t)&tb->jmp_target_addr[n];
85
struct page_collection *pages;
122
+ ptrdiff_t i_offset = i_addr - jmp_rx;
86
123
+
87
- pages = page_collection_lock(ram_addr, ram_addr + size);
124
+ /* Note that we asserted this in range in tcg_out_goto_tb. */
88
+ pages = page_collection_lock(ram_addr, ram_addr + size - 1);
125
+ insn = deposit32(I3305_LDR | TCG_REG_TMP, 0, 5, i_offset >> 2);
89
tb_invalidate_phys_page_fast__locked(pages, ram_addr, size, retaddr);
126
+ }
90
page_collection_unlock(pages);
127
+ qatomic_set((uint32_t *)jmp_rw, insn);
91
}
128
+ flush_idcache_range(jmp_rx, jmp_rw, 4);
129
+}
130
+
131
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
132
const TCGArg args[TCG_MAX_OP_ARGS],
133
const int const_args[TCG_MAX_OP_ARGS])
134
--
92
--
135
2.34.1
93
2.34.1
136
94
137
95
diff view generated by jsdifflib
1
This is always true for sparc64, so this is dead since 3a5f6805c7ca.
1
Pass the address of the last byte to be changed, rather than
2
the first address past the last byte. This avoids overflow
3
when the last page of the address space is involved.
2
4
3
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
5
Properly truncate tb_last to the end of the page; the comment about
6
tb_end being past the end of the page being ok is not correct,
7
considering overflow.
8
4
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
---
11
---
7
tcg/sparc64/tcg-target.c.inc | 62 ++++++++++++------------------------
12
accel/tcg/tb-maint.c | 26 ++++++++++++--------------
8
1 file changed, 21 insertions(+), 41 deletions(-)
13
1 file changed, 12 insertions(+), 14 deletions(-)
9
14
10
diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc
15
diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c
11
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
12
--- a/tcg/sparc64/tcg-target.c.inc
17
--- a/accel/tcg/tb-maint.c
13
+++ b/tcg/sparc64/tcg-target.c.inc
18
+++ b/accel/tcg/tb-maint.c
14
@@ -XXX,XX +XXX,XX @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
19
@@ -XXX,XX +XXX,XX @@ bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc)
15
#endif
20
static void
16
21
tb_invalidate_phys_page_range__locked(struct page_collection *pages,
17
#define TCG_REG_TB TCG_REG_I1
22
PageDesc *p, tb_page_addr_t start,
18
-#define USE_REG_TB (sizeof(void *) > 4)
23
- tb_page_addr_t end,
19
24
+ tb_page_addr_t last,
20
static const int tcg_target_reg_alloc_order[] = {
25
uintptr_t retaddr)
21
TCG_REG_L0,
26
{
22
@@ -XXX,XX +XXX,XX @@ static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret,
27
TranslationBlock *tb;
28
- tb_page_addr_t tb_start, tb_end;
29
PageForEachNext n;
30
#ifdef TARGET_HAS_PRECISE_SMC
31
bool current_tb_modified = false;
32
TranslationBlock *current_tb = retaddr ? tcg_tb_lookup(retaddr) : NULL;
33
#endif /* TARGET_HAS_PRECISE_SMC */
34
- tb_page_addr_t last G_GNUC_UNUSED = end - 1;
35
36
/*
37
- * We remove all the TBs in the range [start, end[.
38
+ * We remove all the TBs in the range [start, last].
39
* XXX: see if in some cases it could be faster to invalidate all the code
40
*/
41
PAGE_FOR_EACH_TB(start, last, p, tb, n) {
42
+ tb_page_addr_t tb_start, tb_last;
43
+
44
/* NOTE: this is subtle as a TB may span two physical pages */
45
+ tb_start = tb_page_addr0(tb);
46
+ tb_last = tb_start + tb->size - 1;
47
if (n == 0) {
48
- /* NOTE: tb_end may be after the end of the page, but
49
- it is not a problem */
50
- tb_start = tb_page_addr0(tb);
51
- tb_end = tb_start + tb->size;
52
+ tb_last = MIN(tb_last, tb_start | ~TARGET_PAGE_MASK);
53
} else {
54
tb_start = tb_page_addr1(tb);
55
- tb_end = tb_start + ((tb_page_addr0(tb) + tb->size)
56
- & ~TARGET_PAGE_MASK);
57
+ tb_last = tb_start + (tb_last & ~TARGET_PAGE_MASK);
58
}
59
- if (!(tb_end <= start || tb_start >= end)) {
60
+ if (!(tb_last < start || tb_start > last)) {
61
#ifdef TARGET_HAS_PRECISE_SMC
62
if (current_tb == tb &&
63
(tb_cflags(current_tb) & CF_COUNT_MASK) != 1) {
64
@@ -XXX,XX +XXX,XX @@ void tb_invalidate_phys_page(tb_page_addr_t addr)
65
start = addr & TARGET_PAGE_MASK;
66
last = addr | ~TARGET_PAGE_MASK;
67
pages = page_collection_lock(start, last);
68
- tb_invalidate_phys_page_range__locked(pages, p, start, last + 1, 0);
69
+ tb_invalidate_phys_page_range__locked(pages, p, start, last, 0);
70
page_collection_unlock(pages);
71
}
72
73
@@ -XXX,XX +XXX,XX @@ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
74
continue;
75
}
76
assert_page_locked(pd);
77
- tb_invalidate_phys_page_range__locked(pages, pd, start, bound, 0);
78
+ tb_invalidate_phys_page_range__locked(pages, pd, start, bound - 1, 0);
23
}
79
}
24
80
page_collection_unlock(pages);
25
/* A 13-bit constant relative to the TB. */
81
}
26
- if (!in_prologue && USE_REG_TB) {
82
@@ -XXX,XX +XXX,XX @@ static void tb_invalidate_phys_page_fast__locked(struct page_collection *pages,
27
+ if (!in_prologue) {
28
test = tcg_tbrel_diff(s, (void *)arg);
29
if (check_fit_ptr(test, 13)) {
30
tcg_out_arithi(s, ret, TCG_REG_TB, test, ARITH_ADD);
31
@@ -XXX,XX +XXX,XX @@ static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret,
32
}
83
}
33
84
34
/* Use the constant pool, if possible. */
85
assert_page_locked(p);
35
- if (!in_prologue && USE_REG_TB) {
86
- tb_invalidate_phys_page_range__locked(pages, p, start, start + len, ra);
36
+ if (!in_prologue) {
87
+ tb_invalidate_phys_page_range__locked(pages, p, start, start + len - 1, ra);
37
new_pool_label(s, arg, R_SPARC_13, s->code_ptr,
38
tcg_tbrel_diff(s, NULL));
39
tcg_out32(s, LDX | INSN_RD(ret) | INSN_RS1(TCG_REG_TB));
40
@@ -XXX,XX +XXX,XX @@ static void tcg_target_qemu_prologue(TCGContext *s)
41
#endif
42
43
/* We choose TCG_REG_TB such that no move is required. */
44
- if (USE_REG_TB) {
45
- QEMU_BUILD_BUG_ON(TCG_REG_TB != TCG_REG_I1);
46
- tcg_regset_set_reg(s->reserved_regs, TCG_REG_TB);
47
- }
48
+ QEMU_BUILD_BUG_ON(TCG_REG_TB != TCG_REG_I1);
49
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TB);
50
51
tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I1, 0, JMPL);
52
/* delay slot */
53
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
54
tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN);
55
tcg_out_movi_imm13(s, TCG_REG_O0, a0);
56
return;
57
- } else if (USE_REG_TB) {
58
+ } else {
59
intptr_t tb_diff = tcg_tbrel_diff(s, (void *)a0);
60
if (check_fit_ptr(tb_diff, 13)) {
61
tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN);
62
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
63
64
static void tcg_out_goto_tb(TCGContext *s, int which)
65
{
66
+ int c;
67
+
68
/* Direct jump. */
69
- if (USE_REG_TB) {
70
- /* make sure the patch is 8-byte aligned. */
71
- if ((intptr_t)s->code_ptr & 4) {
72
- tcg_out_nop(s);
73
- }
74
- set_jmp_insn_offset(s, which);
75
- tcg_out_sethi(s, TCG_REG_T1, 0);
76
- tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, 0, ARITH_OR);
77
- tcg_out_arith(s, TCG_REG_G0, TCG_REG_TB, TCG_REG_T1, JMPL);
78
- tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD);
79
- } else {
80
- set_jmp_insn_offset(s, which);
81
- tcg_out32(s, CALL);
82
+ /* make sure the patch is 8-byte aligned. */
83
+ if ((intptr_t)s->code_ptr & 4) {
84
tcg_out_nop(s);
85
}
86
+ set_jmp_insn_offset(s, which);
87
+ tcg_out_sethi(s, TCG_REG_T1, 0);
88
+ tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, 0, ARITH_OR);
89
+ tcg_out_arith(s, TCG_REG_G0, TCG_REG_TB, TCG_REG_T1, JMPL);
90
+ tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD);
91
set_jmp_reset_offset(s, which);
92
93
/*
94
* For the unlinked path of goto_tb, we need to reset TCG_REG_TB
95
* to the beginning of this TB.
96
*/
97
- if (USE_REG_TB) {
98
- int c = -tcg_current_code_size(s);
99
- if (check_fit_i32(c, 13)) {
100
- tcg_out_arithi(s, TCG_REG_TB, TCG_REG_TB, c, ARITH_ADD);
101
- } else {
102
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, c);
103
- tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD);
104
- }
105
+ c = -tcg_current_code_size(s);
106
+ if (check_fit_i32(c, 13)) {
107
+ tcg_out_arithi(s, TCG_REG_TB, TCG_REG_TB, c, ARITH_ADD);
108
+ } else {
109
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, c);
110
+ tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD);
111
}
112
}
88
}
113
89
114
@@ -XXX,XX +XXX,XX @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
90
/*
115
switch (opc) {
116
case INDEX_op_goto_ptr:
117
tcg_out_arithi(s, TCG_REG_G0, a0, 0, JMPL);
118
- if (USE_REG_TB) {
119
- tcg_out_mov_delay(s, TCG_REG_TB, a0);
120
- } else {
121
- tcg_out_nop(s);
122
- }
123
+ tcg_out_mov_delay(s, TCG_REG_TB, a0);
124
break;
125
case INDEX_op_br:
126
tcg_out_bpcc(s, COND_A, BPCC_PT, arg_label(a0));
127
@@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
128
tcg_debug_assert(tb_disp == (int32_t)tb_disp);
129
tcg_debug_assert(br_disp == (int32_t)br_disp);
130
131
- if (!USE_REG_TB) {
132
- qatomic_set((uint32_t *)jmp_rw,
133
-         deposit32(CALL, 0, 30, br_disp >> 2));
134
- flush_idcache_range(jmp_rx, jmp_rw, 4);
135
- return;
136
- }
137
-
138
/* This does not exercise the range of the branch, but we do
139
still need to be able to load the new value of TCG_REG_TB.
140
But this does still happen quite often. */
141
--
91
--
142
2.34.1
92
2.34.1
143
93
144
94
diff view generated by jsdifflib
1
This will shortly be used for more than reset.
1
Pass the address of the last byte to be changed, rather than
2
the first address past the last byte. This avoids overflow
3
when the last page of the address space is involved.
2
4
3
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
4
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
5
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
---
7
---
7
include/exec/exec-all.h | 2 +-
8
include/exec/exec-all.h | 2 +-
8
accel/tcg/translate-all.c | 8 ++++----
9
accel/tcg/tb-maint.c | 31 ++++++++++++++++---------------
9
tcg/tcg.c | 4 ++--
10
accel/tcg/translate-all.c | 2 +-
10
3 files changed, 7 insertions(+), 7 deletions(-)
11
accel/tcg/user-exec.c | 2 +-
12
softmmu/physmem.c | 2 +-
13
5 files changed, 20 insertions(+), 19 deletions(-)
11
14
12
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
15
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
13
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
14
--- a/include/exec/exec-all.h
17
--- a/include/exec/exec-all.h
15
+++ b/include/exec/exec-all.h
18
+++ b/include/exec/exec-all.h
16
@@ -XXX,XX +XXX,XX @@ struct TranslationBlock {
19
@@ -XXX,XX +XXX,XX @@ void tb_invalidate_phys_addr(target_ulong addr);
17
* setting one of the jump targets (or patching the jump instruction). Only
20
void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs);
18
* two of such jumps are supported.
21
#endif
19
*/
22
void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr);
20
+#define TB_JMP_OFFSET_INVALID 0xffff /* indicates no jump generated */
23
-void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end);
21
uint16_t jmp_reset_offset[2]; /* offset of original jump target */
24
+void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t last);
22
-#define TB_JMP_RESET_OFFSET_INVALID 0xffff /* indicates no jump generated */
25
void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr);
23
uintptr_t jmp_target_arg[2]; /* target address or offset */
26
24
27
/* GETPC is the true target of the return instruction that we'll execute. */
25
/*
28
diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c
29
index XXXXXXX..XXXXXXX 100644
30
--- a/accel/tcg/tb-maint.c
31
+++ b/accel/tcg/tb-maint.c
32
@@ -XXX,XX +XXX,XX @@ TranslationBlock *tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
33
* Called with mmap_lock held for user-mode emulation.
34
* NOTE: this function must not be called while a TB is running.
35
*/
36
-void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
37
+void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t last)
38
{
39
TranslationBlock *tb;
40
PageForEachNext n;
41
- tb_page_addr_t last = end - 1;
42
43
assert_memory_lock();
44
45
@@ -XXX,XX +XXX,XX @@ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
46
*/
47
void tb_invalidate_phys_page(tb_page_addr_t addr)
48
{
49
- tb_page_addr_t start, end;
50
+ tb_page_addr_t start, last;
51
52
start = addr & TARGET_PAGE_MASK;
53
- end = start + TARGET_PAGE_SIZE;
54
- tb_invalidate_phys_range(start, end);
55
+ last = addr | ~TARGET_PAGE_MASK;
56
+ tb_invalidate_phys_range(start, last);
57
}
58
59
/*
60
@@ -XXX,XX +XXX,XX @@ void tb_invalidate_phys_page(tb_page_addr_t addr)
61
62
/*
63
* Invalidate all TBs which intersect with the target physical address range
64
- * [start;end[. NOTE: start and end may refer to *different* physical pages.
65
+ * [start;last]. NOTE: start and end may refer to *different* physical pages.
66
* 'is_cpu_write_access' should be true if called from a real cpu write
67
* access: the virtual CPU will exit the current TB if code is modified inside
68
* this TB.
69
*/
70
-void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
71
+void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t last)
72
{
73
struct page_collection *pages;
74
- tb_page_addr_t next;
75
+ tb_page_addr_t index, index_last;
76
77
- pages = page_collection_lock(start, end - 1);
78
- for (next = (start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
79
- start < end;
80
- start = next, next += TARGET_PAGE_SIZE) {
81
- PageDesc *pd = page_find(start >> TARGET_PAGE_BITS);
82
- tb_page_addr_t bound = MIN(next, end);
83
+ pages = page_collection_lock(start, last);
84
+
85
+ index_last = last >> TARGET_PAGE_BITS;
86
+ for (index = start >> TARGET_PAGE_BITS; index <= index_last; index++) {
87
+ PageDesc *pd = page_find(index);
88
+ tb_page_addr_t bound;
89
90
if (pd == NULL) {
91
continue;
92
}
93
assert_page_locked(pd);
94
- tb_invalidate_phys_page_range__locked(pages, pd, start, bound - 1, 0);
95
+ bound = (index << TARGET_PAGE_BITS) | ~TARGET_PAGE_MASK;
96
+ bound = MIN(bound, last);
97
+ tb_invalidate_phys_page_range__locked(pages, pd, start, bound, 0);
98
}
99
page_collection_unlock(pages);
100
}
26
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
101
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
27
index XXXXXXX..XXXXXXX 100644
102
index XXXXXXX..XXXXXXX 100644
28
--- a/accel/tcg/translate-all.c
103
--- a/accel/tcg/translate-all.c
29
+++ b/accel/tcg/translate-all.c
104
+++ b/accel/tcg/translate-all.c
30
@@ -XXX,XX +XXX,XX @@ TranslationBlock *tb_gen_code(CPUState *cpu,
105
@@ -XXX,XX +XXX,XX @@ void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr)
31
tb->jmp_dest[1] = (uintptr_t)NULL;
106
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
32
107
addr = get_page_addr_code(env, pc);
33
/* init original jump addresses which have been set during tcg_gen_code() */
108
if (addr != -1) {
34
- if (tb->jmp_reset_offset[0] != TB_JMP_RESET_OFFSET_INVALID) {
109
- tb_invalidate_phys_range(addr, addr + 1);
35
+ if (tb->jmp_reset_offset[0] != TB_JMP_OFFSET_INVALID) {
110
+ tb_invalidate_phys_range(addr, addr);
36
tb_reset_jump(tb, 0);
37
}
38
- if (tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) {
39
+ if (tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID) {
40
tb_reset_jump(tb, 1);
41
}
42
43
@@ -XXX,XX +XXX,XX @@ static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data)
44
if (tb_page_addr1(tb) != -1) {
45
tst->cross_page++;
46
}
47
- if (tb->jmp_reset_offset[0] != TB_JMP_RESET_OFFSET_INVALID) {
48
+ if (tb->jmp_reset_offset[0] != TB_JMP_OFFSET_INVALID) {
49
tst->direct_jmp_count++;
50
- if (tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) {
51
+ if (tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID) {
52
tst->direct_jmp2_count++;
53
}
111
}
54
}
112
}
55
diff --git a/tcg/tcg.c b/tcg/tcg.c
113
}
114
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
56
index XXXXXXX..XXXXXXX 100644
115
index XXXXXXX..XXXXXXX 100644
57
--- a/tcg/tcg.c
116
--- a/accel/tcg/user-exec.c
58
+++ b/tcg/tcg.c
117
+++ b/accel/tcg/user-exec.c
59
@@ -XXX,XX +XXX,XX @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start)
118
@@ -XXX,XX +XXX,XX @@ void page_set_flags(target_ulong start, target_ulong last, int flags)
60
#endif
119
~(reset ? 0 : PAGE_STICKY));
61
120
}
62
/* Initialize goto_tb jump offsets. */
121
if (inval_tb) {
63
- tb->jmp_reset_offset[0] = TB_JMP_RESET_OFFSET_INVALID;
122
- tb_invalidate_phys_range(start, last + 1);
64
- tb->jmp_reset_offset[1] = TB_JMP_RESET_OFFSET_INVALID;
123
+ tb_invalidate_phys_range(start, last);
65
+ tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID;
124
}
66
+ tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID;
125
}
67
tcg_ctx->tb_jmp_reset_offset = tb->jmp_reset_offset;
126
68
if (TCG_TARGET_HAS_direct_jump) {
127
diff --git a/softmmu/physmem.c b/softmmu/physmem.c
69
tcg_ctx->tb_jmp_insn_offset = tb->jmp_target_arg;
128
index XXXXXXX..XXXXXXX 100644
129
--- a/softmmu/physmem.c
130
+++ b/softmmu/physmem.c
131
@@ -XXX,XX +XXX,XX @@ static void invalidate_and_set_dirty(MemoryRegion *mr, hwaddr addr,
132
}
133
if (dirty_log_mask & (1 << DIRTY_MEMORY_CODE)) {
134
assert(tcg_enabled());
135
- tb_invalidate_phys_range(addr, addr + length);
136
+ tb_invalidate_phys_range(addr, addr + length - 1);
137
dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
138
}
139
cpu_physical_memory_set_dirty_range(addr, length, dirty_log_mask);
70
--
140
--
71
2.34.1
141
2.34.1
72
142
73
143
diff view generated by jsdifflib
Deleted patch
1
This can replace four other variables that are references
2
into the TranslationBlock structure.
3
1
4
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
---
7
include/tcg/tcg.h | 11 +++--------
8
accel/tcg/translate-all.c | 2 +-
9
tcg/tcg-op.c | 14 +++++++-------
10
tcg/tcg.c | 14 +++-----------
11
4 files changed, 14 insertions(+), 27 deletions(-)
12
13
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
14
index XXXXXXX..XXXXXXX 100644
15
--- a/include/tcg/tcg.h
16
+++ b/include/tcg/tcg.h
17
@@ -XXX,XX +XXX,XX @@ struct TCGContext {
18
int nb_indirects;
19
int nb_ops;
20
21
- /* goto_tb support */
22
- tcg_insn_unit *code_buf;
23
- uint16_t *tb_jmp_reset_offset; /* tb->jmp_reset_offset */
24
- uintptr_t *tb_jmp_insn_offset; /* tb->jmp_target_arg if direct_jump */
25
- uintptr_t *tb_jmp_target_addr; /* tb->jmp_target_arg if !direct_jump */
26
-
27
TCGRegSet reserved_regs;
28
- uint32_t tb_cflags; /* cflags of the current TB */
29
intptr_t current_frame_offset;
30
intptr_t frame_start;
31
intptr_t frame_end;
32
TCGTemp *frame_temp;
33
34
- tcg_insn_unit *code_ptr;
35
+ TranslationBlock *gen_tb; /* tb for which code is being generated */
36
+ tcg_insn_unit *code_buf; /* pointer for start of tb */
37
+ tcg_insn_unit *code_ptr; /* pointer for running end of tb */
38
39
#ifdef CONFIG_PROFILER
40
TCGProfile prof;
41
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/accel/tcg/translate-all.c
44
+++ b/accel/tcg/translate-all.c
45
@@ -XXX,XX +XXX,XX @@ TranslationBlock *tb_gen_code(CPUState *cpu,
46
tb->trace_vcpu_dstate = *cpu->trace_dstate;
47
tb_set_page_addr0(tb, phys_pc);
48
tb_set_page_addr1(tb, -1);
49
- tcg_ctx->tb_cflags = cflags;
50
+ tcg_ctx->gen_tb = tb;
51
tb_overflow:
52
53
#ifdef CONFIG_PROFILER
54
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
55
index XXXXXXX..XXXXXXX 100644
56
--- a/tcg/tcg-op.c
57
+++ b/tcg/tcg-op.c
58
@@ -XXX,XX +XXX,XX @@ void tcg_gen_op6(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3,
59
60
void tcg_gen_mb(TCGBar mb_type)
61
{
62
- if (tcg_ctx->tb_cflags & CF_PARALLEL) {
63
+ if (tcg_ctx->gen_tb->cflags & CF_PARALLEL) {
64
tcg_gen_op1(INDEX_op_mb, mb_type);
65
}
66
}
67
@@ -XXX,XX +XXX,XX @@ void tcg_gen_exit_tb(const TranslationBlock *tb, unsigned idx)
68
void tcg_gen_goto_tb(unsigned idx)
69
{
70
/* We tested CF_NO_GOTO_TB in translator_use_goto_tb. */
71
- tcg_debug_assert(!(tcg_ctx->tb_cflags & CF_NO_GOTO_TB));
72
+ tcg_debug_assert(!(tcg_ctx->gen_tb->cflags & CF_NO_GOTO_TB));
73
/* We only support two chained exits. */
74
tcg_debug_assert(idx <= TB_EXIT_IDXMAX);
75
#ifdef CONFIG_DEBUG_TCG
76
@@ -XXX,XX +XXX,XX @@ void tcg_gen_lookup_and_goto_ptr(void)
77
{
78
TCGv_ptr ptr;
79
80
- if (tcg_ctx->tb_cflags & CF_NO_GOTO_PTR) {
81
+ if (tcg_ctx->gen_tb->cflags & CF_NO_GOTO_PTR) {
82
tcg_gen_exit_tb(NULL, 0);
83
return;
84
}
85
@@ -XXX,XX +XXX,XX @@ void tcg_gen_atomic_cmpxchg_i32(TCGv_i32 retv, TCGv addr, TCGv_i32 cmpv,
86
{
87
memop = tcg_canonicalize_memop(memop, 0, 0);
88
89
- if (!(tcg_ctx->tb_cflags & CF_PARALLEL)) {
90
+ if (!(tcg_ctx->gen_tb->cflags & CF_PARALLEL)) {
91
TCGv_i32 t1 = tcg_temp_new_i32();
92
TCGv_i32 t2 = tcg_temp_new_i32();
93
94
@@ -XXX,XX +XXX,XX @@ void tcg_gen_atomic_cmpxchg_i64(TCGv_i64 retv, TCGv addr, TCGv_i64 cmpv,
95
{
96
memop = tcg_canonicalize_memop(memop, 1, 0);
97
98
- if (!(tcg_ctx->tb_cflags & CF_PARALLEL)) {
99
+ if (!(tcg_ctx->gen_tb->cflags & CF_PARALLEL)) {
100
TCGv_i64 t1 = tcg_temp_new_i64();
101
TCGv_i64 t2 = tcg_temp_new_i64();
102
103
@@ -XXX,XX +XXX,XX @@ static void * const table_##NAME[(MO_SIZE | MO_BSWAP) + 1] = { \
104
void tcg_gen_atomic_##NAME##_i32 \
105
(TCGv_i32 ret, TCGv addr, TCGv_i32 val, TCGArg idx, MemOp memop) \
106
{ \
107
- if (tcg_ctx->tb_cflags & CF_PARALLEL) { \
108
+ if (tcg_ctx->gen_tb->cflags & CF_PARALLEL) { \
109
do_atomic_op_i32(ret, addr, val, idx, memop, table_##NAME); \
110
} else { \
111
do_nonatomic_op_i32(ret, addr, val, idx, memop, NEW, \
112
@@ -XXX,XX +XXX,XX @@ void tcg_gen_atomic_##NAME##_i32 \
113
void tcg_gen_atomic_##NAME##_i64 \
114
(TCGv_i64 ret, TCGv addr, TCGv_i64 val, TCGArg idx, MemOp memop) \
115
{ \
116
- if (tcg_ctx->tb_cflags & CF_PARALLEL) { \
117
+ if (tcg_ctx->gen_tb->cflags & CF_PARALLEL) { \
118
do_atomic_op_i64(ret, addr, val, idx, memop, table_##NAME); \
119
} else { \
120
do_nonatomic_op_i64(ret, addr, val, idx, memop, NEW, \
121
diff --git a/tcg/tcg.c b/tcg/tcg.c
122
index XXXXXXX..XXXXXXX 100644
123
--- a/tcg/tcg.c
124
+++ b/tcg/tcg.c
125
@@ -XXX,XX +XXX,XX @@ static void set_jmp_reset_offset(TCGContext *s, int which)
126
* We will check for overflow at the end of the opcode loop in
127
* tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
128
*/
129
- s->tb_jmp_reset_offset[which] = tcg_current_code_size(s);
130
+ s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s);
131
}
132
133
static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which)
134
@@ -XXX,XX +XXX,XX @@ static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which)
135
* tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
136
*/
137
tcg_debug_assert(TCG_TARGET_HAS_direct_jump);
138
- s->tb_jmp_insn_offset[which] = tcg_current_code_size(s);
139
+ s->gen_tb->jmp_target_arg[which] = tcg_current_code_size(s);
140
}
141
142
static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which)
143
@@ -XXX,XX +XXX,XX @@ static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which)
144
* Return the read-execute version of the pointer, for the benefit
145
* of any pc-relative addressing mode.
146
*/
147
- return (uintptr_t)tcg_splitwx_to_rx(&s->tb_jmp_target_addr[which]);
148
+ return (uintptr_t)tcg_splitwx_to_rx(s->gen_tb->jmp_target_arg + which);
149
}
150
151
/* Signal overflow, starting over with fewer guest insns. */
152
@@ -XXX,XX +XXX,XX @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start)
153
/* Initialize goto_tb jump offsets. */
154
tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID;
155
tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID;
156
- tcg_ctx->tb_jmp_reset_offset = tb->jmp_reset_offset;
157
- if (TCG_TARGET_HAS_direct_jump) {
158
- tcg_ctx->tb_jmp_insn_offset = tb->jmp_target_arg;
159
- tcg_ctx->tb_jmp_target_addr = NULL;
160
- } else {
161
- tcg_ctx->tb_jmp_insn_offset = NULL;
162
- tcg_ctx->tb_jmp_target_addr = tb->jmp_target_arg;
163
- }
164
165
tcg_reg_alloc_start(s);
166
167
--
168
2.34.1
169
170
diff view generated by jsdifflib
Deleted patch
1
Stop overloading jmp_target_arg for both offset and address,
2
depending on TCG_TARGET_HAS_direct_jump. Instead, add a new
3
field to hold the jump insn offset and always set the target
4
address in jmp_target_addr[]. This will allow a tcg backend
5
to use either direct or indirect depending on displacement.
6
1
7
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
---
10
include/exec/exec-all.h | 3 ++-
11
accel/tcg/cpu-exec.c | 5 ++---
12
tcg/tcg.c | 6 ++++--
13
3 files changed, 8 insertions(+), 6 deletions(-)
14
15
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
16
index XXXXXXX..XXXXXXX 100644
17
--- a/include/exec/exec-all.h
18
+++ b/include/exec/exec-all.h
19
@@ -XXX,XX +XXX,XX @@ struct TranslationBlock {
20
*/
21
#define TB_JMP_OFFSET_INVALID 0xffff /* indicates no jump generated */
22
uint16_t jmp_reset_offset[2]; /* offset of original jump target */
23
- uintptr_t jmp_target_arg[2]; /* target address or offset */
24
+ uint16_t jmp_insn_offset[2]; /* offset of direct jump insn */
25
+ uintptr_t jmp_target_addr[2]; /* target address */
26
27
/*
28
* Each TB has a NULL-terminated list (jmp_list_head) of incoming jumps.
29
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/accel/tcg/cpu-exec.c
32
+++ b/accel/tcg/cpu-exec.c
33
@@ -XXX,XX +XXX,XX @@ void cpu_exec_step_atomic(CPUState *cpu)
34
35
void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr)
36
{
37
+ tb->jmp_target_addr[n] = addr;
38
if (TCG_TARGET_HAS_direct_jump) {
39
- uintptr_t offset = tb->jmp_target_arg[n];
40
+ uintptr_t offset = tb->jmp_insn_offset[n];
41
uintptr_t tc_ptr = (uintptr_t)tb->tc.ptr;
42
uintptr_t jmp_rx = tc_ptr + offset;
43
uintptr_t jmp_rw = jmp_rx - tcg_splitwx_diff;
44
tb_target_set_jmp_target(tc_ptr, jmp_rx, jmp_rw, addr);
45
- } else {
46
- tb->jmp_target_arg[n] = addr;
47
}
48
}
49
50
diff --git a/tcg/tcg.c b/tcg/tcg.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/tcg/tcg.c
53
+++ b/tcg/tcg.c
54
@@ -XXX,XX +XXX,XX @@ static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which)
55
* tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
56
*/
57
tcg_debug_assert(TCG_TARGET_HAS_direct_jump);
58
- s->gen_tb->jmp_target_arg[which] = tcg_current_code_size(s);
59
+ s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s);
60
}
61
62
static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which)
63
@@ -XXX,XX +XXX,XX @@ static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which)
64
* Return the read-execute version of the pointer, for the benefit
65
* of any pc-relative addressing mode.
66
*/
67
- return (uintptr_t)tcg_splitwx_to_rx(s->gen_tb->jmp_target_arg + which);
68
+ return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]);
69
}
70
71
/* Signal overflow, starting over with fewer guest insns. */
72
@@ -XXX,XX +XXX,XX @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start)
73
/* Initialize goto_tb jump offsets. */
74
tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID;
75
tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID;
76
+ tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID;
77
+ tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID;
78
79
tcg_reg_alloc_start(s);
80
81
--
82
2.34.1
83
84
diff view generated by jsdifflib
Deleted patch
1
Replace 'tc_ptr' and 'addr' with 'tb' and 'n'.
2
1
3
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
5
---
6
tcg/aarch64/tcg-target.h | 3 ++-
7
tcg/arm/tcg-target.h | 3 ++-
8
tcg/i386/tcg-target.h | 9 ++-------
9
tcg/loongarch64/tcg-target.h | 3 ++-
10
tcg/mips/tcg-target.h | 3 ++-
11
tcg/ppc/tcg-target.h | 3 ++-
12
tcg/riscv/tcg-target.h | 3 ++-
13
tcg/s390x/tcg-target.h | 10 ++--------
14
tcg/sparc64/tcg-target.h | 3 ++-
15
tcg/tci/tcg-target.h | 3 ++-
16
accel/tcg/cpu-exec.c | 11 ++++++++---
17
tcg/aarch64/tcg-target.c.inc | 5 +++--
18
tcg/i386/tcg-target.c.inc | 9 +++++++++
19
tcg/loongarch64/tcg-target.c.inc | 5 +++--
20
tcg/ppc/tcg-target.c.inc | 7 ++++---
21
tcg/s390x/tcg-target.c.inc | 10 ++++++++++
22
tcg/sparc64/tcg-target.c.inc | 7 ++++---
23
17 files changed, 61 insertions(+), 36 deletions(-)
24
25
diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
26
index XXXXXXX..XXXXXXX 100644
27
--- a/tcg/aarch64/tcg-target.h
28
+++ b/tcg/aarch64/tcg-target.h
29
@@ -XXX,XX +XXX,XX @@ typedef enum {
30
#define TCG_TARGET_DEFAULT_MO (0)
31
#define TCG_TARGET_HAS_MEMORY_BSWAP 0
32
33
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
34
+void tb_target_set_jmp_target(const TranslationBlock *, int,
35
+ uintptr_t, uintptr_t);
36
37
#define TCG_TARGET_NEED_LDST_LABELS
38
#define TCG_TARGET_NEED_POOL_LABELS
39
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
40
index XXXXXXX..XXXXXXX 100644
41
--- a/tcg/arm/tcg-target.h
42
+++ b/tcg/arm/tcg-target.h
43
@@ -XXX,XX +XXX,XX @@ extern bool use_neon_instructions;
44
#define TCG_TARGET_HAS_MEMORY_BSWAP 0
45
46
/* not defined -- call should be eliminated at compile time */
47
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
48
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
49
+ uintptr_t, uintptr_t);
50
51
#define TCG_TARGET_NEED_LDST_LABELS
52
#define TCG_TARGET_NEED_POOL_LABELS
53
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
54
index XXXXXXX..XXXXXXX 100644
55
--- a/tcg/i386/tcg-target.h
56
+++ b/tcg/i386/tcg-target.h
57
@@ -XXX,XX +XXX,XX @@ extern bool have_movbe;
58
#define TCG_TARGET_extract_i64_valid(ofs, len) \
59
(((ofs) == 8 && (len) == 8) || ((ofs) + (len)) == 32)
60
61
-static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx,
62
- uintptr_t jmp_rw, uintptr_t addr)
63
-{
64
- /* patch the branch destination */
65
- qatomic_set((int32_t *)jmp_rw, addr - (jmp_rx + 4));
66
- /* no need to flush icache explicitly */
67
-}
68
+void tb_target_set_jmp_target(const TranslationBlock *, int,
69
+ uintptr_t, uintptr_t);
70
71
/* This defines the natural memory order supported by this
72
* architecture before guarantees made by various barrier
73
diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h
74
index XXXXXXX..XXXXXXX 100644
75
--- a/tcg/loongarch64/tcg-target.h
76
+++ b/tcg/loongarch64/tcg-target.h
77
@@ -XXX,XX +XXX,XX @@ typedef enum {
78
#define TCG_TARGET_HAS_muluh_i64 1
79
#define TCG_TARGET_HAS_mulsh_i64 1
80
81
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
82
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
83
+ uintptr_t, uintptr_t);
84
85
#define TCG_TARGET_DEFAULT_MO (0)
86
87
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
88
index XXXXXXX..XXXXXXX 100644
89
--- a/tcg/mips/tcg-target.h
90
+++ b/tcg/mips/tcg-target.h
91
@@ -XXX,XX +XXX,XX @@ extern bool use_mips32r2_instructions;
92
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
93
94
/* not defined -- call should be eliminated at compile time */
95
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t)
96
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
97
+ uintptr_t, uintptr_t)
98
QEMU_ERROR("code path is reachable");
99
100
#define TCG_TARGET_NEED_LDST_LABELS
101
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
102
index XXXXXXX..XXXXXXX 100644
103
--- a/tcg/ppc/tcg-target.h
104
+++ b/tcg/ppc/tcg-target.h
105
@@ -XXX,XX +XXX,XX @@ extern bool have_vsx;
106
#define TCG_TARGET_HAS_bitsel_vec have_vsx
107
#define TCG_TARGET_HAS_cmpsel_vec 0
108
109
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
110
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
111
+ uintptr_t, uintptr_t);
112
113
#define TCG_TARGET_DEFAULT_MO (0)
114
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
115
diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h
116
index XXXXXXX..XXXXXXX 100644
117
--- a/tcg/riscv/tcg-target.h
118
+++ b/tcg/riscv/tcg-target.h
119
@@ -XXX,XX +XXX,XX @@ typedef enum {
120
#endif
121
122
/* not defined -- call should be eliminated at compile time */
123
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
124
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
125
+ uintptr_t, uintptr_t);
126
127
#define TCG_TARGET_DEFAULT_MO (0)
128
129
diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h
130
index XXXXXXX..XXXXXXX 100644
131
--- a/tcg/s390x/tcg-target.h
132
+++ b/tcg/s390x/tcg-target.h
133
@@ -XXX,XX +XXX,XX @@ extern uint64_t s390_facilities[3];
134
135
#define TCG_TARGET_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD)
136
137
-static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx,
138
- uintptr_t jmp_rw, uintptr_t addr)
139
-{
140
- /* patch the branch destination */
141
- intptr_t disp = addr - (jmp_rx - 2);
142
- qatomic_set((int32_t *)jmp_rw, disp / 2);
143
- /* no need to flush icache explicitly */
144
-}
145
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
146
+ uintptr_t jmp_rx, uintptr_t jmp_rw);
147
148
#define TCG_TARGET_NEED_LDST_LABELS
149
#define TCG_TARGET_NEED_POOL_LABELS
150
diff --git a/tcg/sparc64/tcg-target.h b/tcg/sparc64/tcg-target.h
151
index XXXXXXX..XXXXXXX 100644
152
--- a/tcg/sparc64/tcg-target.h
153
+++ b/tcg/sparc64/tcg-target.h
154
@@ -XXX,XX +XXX,XX @@ extern bool use_vis3_instructions;
155
#define TCG_TARGET_DEFAULT_MO (0)
156
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
157
158
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
159
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
160
+ uintptr_t, uintptr_t);
161
162
#define TCG_TARGET_NEED_POOL_LABELS
163
164
diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
165
index XXXXXXX..XXXXXXX 100644
166
--- a/tcg/tci/tcg-target.h
167
+++ b/tcg/tci/tcg-target.h
168
@@ -XXX,XX +XXX,XX @@ typedef enum {
169
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
170
171
/* not defined -- call should be eliminated at compile time */
172
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
173
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
174
+ uintptr_t, uintptr_t);
175
176
#endif /* TCG_TARGET_H */
177
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
178
index XXXXXXX..XXXXXXX 100644
179
--- a/accel/tcg/cpu-exec.c
180
+++ b/accel/tcg/cpu-exec.c
181
@@ -XXX,XX +XXX,XX @@ void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr)
182
{
183
tb->jmp_target_addr[n] = addr;
184
if (TCG_TARGET_HAS_direct_jump) {
185
+ /*
186
+ * Get the rx view of the structure, from which we find the
187
+ * executable code address, and tb_target_set_jmp_target can
188
+ * produce a pc-relative displacement to jmp_target_addr[n].
189
+ */
190
+ const TranslationBlock *c_tb = tcg_splitwx_to_rx(tb);
191
uintptr_t offset = tb->jmp_insn_offset[n];
192
- uintptr_t tc_ptr = (uintptr_t)tb->tc.ptr;
193
- uintptr_t jmp_rx = tc_ptr + offset;
194
+ uintptr_t jmp_rx = (uintptr_t)tb->tc.ptr + offset;
195
uintptr_t jmp_rw = jmp_rx - tcg_splitwx_diff;
196
- tb_target_set_jmp_target(tc_ptr, jmp_rx, jmp_rw, addr);
197
+ tb_target_set_jmp_target(c_tb, n, jmp_rx, jmp_rw);
198
}
199
}
200
201
diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
202
index XXXXXXX..XXXXXXX 100644
203
--- a/tcg/aarch64/tcg-target.c.inc
204
+++ b/tcg/aarch64/tcg-target.c.inc
205
@@ -XXX,XX +XXX,XX @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target,
206
tcg_out_call_int(s, target);
207
}
208
209
-void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx,
210
- uintptr_t jmp_rw, uintptr_t addr)
211
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
212
+ uintptr_t jmp_rx, uintptr_t jmp_rw)
213
{
214
+ uintptr_t addr = tb->jmp_target_addr[n];
215
tcg_insn_unit i1, i2;
216
TCGType rt = TCG_TYPE_I64;
217
TCGReg rd = TCG_REG_TMP;
218
diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
219
index XXXXXXX..XXXXXXX 100644
220
--- a/tcg/i386/tcg-target.c.inc
221
+++ b/tcg/i386/tcg-target.c.inc
222
@@ -XXX,XX +XXX,XX @@ static void tcg_out_goto_tb(TCGContext *s, int which)
223
set_jmp_reset_offset(s, which);
224
}
225
226
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
227
+ uintptr_t jmp_rx, uintptr_t jmp_rw)
228
+{
229
+ /* patch the branch destination */
230
+ uintptr_t addr = tb->jmp_target_addr[n];
231
+ qatomic_set((int32_t *)jmp_rw, addr - (jmp_rx + 4));
232
+ /* no need to flush icache explicitly */
233
+}
234
+
235
static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
236
const TCGArg args[TCG_MAX_OP_ARGS],
237
const int const_args[TCG_MAX_OP_ARGS])
238
diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc
239
index XXXXXXX..XXXXXXX 100644
240
--- a/tcg/loongarch64/tcg-target.c.inc
241
+++ b/tcg/loongarch64/tcg-target.c.inc
242
@@ -XXX,XX +XXX,XX @@ static void tcg_out_nop(TCGContext *s)
243
tcg_out32(s, NOP);
244
}
245
246
-void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx,
247
- uintptr_t jmp_rw, uintptr_t addr)
248
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
249
+ uintptr_t jmp_rx, uintptr_t jmp_rw)
250
{
251
tcg_insn_unit i1, i2;
252
ptrdiff_t upper, lower;
253
+ uintptr_t addr = tb->jmp_target_addr[n];
254
ptrdiff_t offset = (ptrdiff_t)(addr - jmp_rx) >> 2;
255
256
if (offset == sextreg(offset, 0, 26)) {
257
diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
258
index XXXXXXX..XXXXXXX 100644
259
--- a/tcg/ppc/tcg-target.c.inc
260
+++ b/tcg/ppc/tcg-target.c.inc
261
@@ -XXX,XX +XXX,XX @@ static inline void ppc64_replace4(uintptr_t rx, uintptr_t rw,
262
flush_idcache_range(rx, rw, 16);
263
}
264
265
-void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx,
266
- uintptr_t jmp_rw, uintptr_t addr)
267
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
268
+ uintptr_t jmp_rx, uintptr_t jmp_rw)
269
{
270
tcg_insn_unit i0, i1, i2, i3;
271
- intptr_t tb_diff = addr - tc_ptr;
272
+ uintptr_t addr = tb->jmp_target_addr[n];
273
+ intptr_t tb_diff = addr - (uintptr_t)tb->tc.ptr;
274
intptr_t br_diff = addr - (jmp_rx + 4);
275
intptr_t lo, hi;
276
277
diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc
278
index XXXXXXX..XXXXXXX 100644
279
--- a/tcg/s390x/tcg-target.c.inc
280
+++ b/tcg/s390x/tcg-target.c.inc
281
@@ -XXX,XX +XXX,XX @@ static void tcg_out_goto_tb(TCGContext *s, int which)
282
set_jmp_reset_offset(s, which);
283
}
284
285
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
286
+ uintptr_t jmp_rx, uintptr_t jmp_rw)
287
+{
288
+ /* patch the branch destination */
289
+ uintptr_t addr = tb->jmp_target_addr[n];
290
+ intptr_t disp = addr - (jmp_rx - 2);
291
+ qatomic_set((int32_t *)jmp_rw, disp / 2);
292
+ /* no need to flush icache explicitly */
293
+}
294
+
295
# define OP_32_64(x) \
296
case glue(glue(INDEX_op_,x),_i32): \
297
case glue(glue(INDEX_op_,x),_i64)
298
diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc
299
index XXXXXXX..XXXXXXX 100644
300
--- a/tcg/sparc64/tcg-target.c.inc
301
+++ b/tcg/sparc64/tcg-target.c.inc
302
@@ -XXX,XX +XXX,XX @@ void tcg_register_jit(const void *buf, size_t buf_size)
303
tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
304
}
305
306
-void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx,
307
- uintptr_t jmp_rw, uintptr_t addr)
308
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
309
+ uintptr_t jmp_rx, uintptr_t jmp_rw)
310
{
311
- intptr_t tb_disp = addr - tc_ptr;
312
+ uintptr_t addr = tb->jmp_target_addr[n];
313
+ intptr_t tb_disp = addr - (uintptr_t)tb->tc.ptr;
314
intptr_t br_disp = addr - jmp_rx;
315
tcg_insn_unit i1, i2;
316
317
--
318
2.34.1
319
320
diff view generated by jsdifflib
Deleted patch
1
We now have the option to generate direct or indirect
2
goto_tb depending on the dynamic displacement, thus
3
the define is no longer necessary or completely accurate.
4
1
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
---
8
tcg/aarch64/tcg-target.h | 1 -
9
tcg/arm/tcg-target.h | 1 -
10
tcg/i386/tcg-target.h | 1 -
11
tcg/loongarch64/tcg-target.h | 1 -
12
tcg/mips/tcg-target.h | 1 -
13
tcg/ppc/tcg-target.h | 1 -
14
tcg/riscv/tcg-target.h | 1 -
15
tcg/s390x/tcg-target.h | 1 -
16
tcg/sparc64/tcg-target.h | 1 -
17
tcg/tci/tcg-target.h | 1 -
18
accel/tcg/cpu-exec.c | 23 +++++++++++------------
19
tcg/tcg.c | 1 -
20
tcg/arm/tcg-target.c.inc | 1 -
21
tcg/mips/tcg-target.c.inc | 1 -
22
tcg/riscv/tcg-target.c.inc | 1 -
23
tcg/s390x/tcg-target.c.inc | 3 +++
24
tcg/tci/tcg-target.c.inc | 1 -
25
17 files changed, 14 insertions(+), 27 deletions(-)
26
27
diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
28
index XXXXXXX..XXXXXXX 100644
29
--- a/tcg/aarch64/tcg-target.h
30
+++ b/tcg/aarch64/tcg-target.h
31
@@ -XXX,XX +XXX,XX @@ typedef enum {
32
#define TCG_TARGET_HAS_muls2_i64 0
33
#define TCG_TARGET_HAS_muluh_i64 1
34
#define TCG_TARGET_HAS_mulsh_i64 1
35
-#define TCG_TARGET_HAS_direct_jump 1
36
37
#define TCG_TARGET_HAS_v64 1
38
#define TCG_TARGET_HAS_v128 1
39
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
40
index XXXXXXX..XXXXXXX 100644
41
--- a/tcg/arm/tcg-target.h
42
+++ b/tcg/arm/tcg-target.h
43
@@ -XXX,XX +XXX,XX @@ extern bool use_neon_instructions;
44
#define TCG_TARGET_HAS_mulsh_i32 0
45
#define TCG_TARGET_HAS_div_i32 use_idiv_instructions
46
#define TCG_TARGET_HAS_rem_i32 0
47
-#define TCG_TARGET_HAS_direct_jump 0
48
#define TCG_TARGET_HAS_qemu_st8_i32 0
49
50
#define TCG_TARGET_HAS_v64 use_neon_instructions
51
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
52
index XXXXXXX..XXXXXXX 100644
53
--- a/tcg/i386/tcg-target.h
54
+++ b/tcg/i386/tcg-target.h
55
@@ -XXX,XX +XXX,XX @@ extern bool have_movbe;
56
#define TCG_TARGET_HAS_muls2_i32 1
57
#define TCG_TARGET_HAS_muluh_i32 0
58
#define TCG_TARGET_HAS_mulsh_i32 0
59
-#define TCG_TARGET_HAS_direct_jump 1
60
61
#if TCG_TARGET_REG_BITS == 64
62
/* Keep target addresses zero-extended in a register. */
63
diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h
64
index XXXXXXX..XXXXXXX 100644
65
--- a/tcg/loongarch64/tcg-target.h
66
+++ b/tcg/loongarch64/tcg-target.h
67
@@ -XXX,XX +XXX,XX @@ typedef enum {
68
#define TCG_TARGET_HAS_clz_i32 1
69
#define TCG_TARGET_HAS_ctz_i32 1
70
#define TCG_TARGET_HAS_ctpop_i32 0
71
-#define TCG_TARGET_HAS_direct_jump 1
72
#define TCG_TARGET_HAS_brcond2 0
73
#define TCG_TARGET_HAS_setcond2 0
74
#define TCG_TARGET_HAS_qemu_st8_i32 0
75
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
76
index XXXXXXX..XXXXXXX 100644
77
--- a/tcg/mips/tcg-target.h
78
+++ b/tcg/mips/tcg-target.h
79
@@ -XXX,XX +XXX,XX @@ extern bool use_mips32r2_instructions;
80
#define TCG_TARGET_HAS_muluh_i32 1
81
#define TCG_TARGET_HAS_mulsh_i32 1
82
#define TCG_TARGET_HAS_bswap32_i32 1
83
-#define TCG_TARGET_HAS_direct_jump 0
84
85
#if TCG_TARGET_REG_BITS == 64
86
#define TCG_TARGET_HAS_add2_i32 0
87
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
88
index XXXXXXX..XXXXXXX 100644
89
--- a/tcg/ppc/tcg-target.h
90
+++ b/tcg/ppc/tcg-target.h
91
@@ -XXX,XX +XXX,XX @@ extern bool have_vsx;
92
#define TCG_TARGET_HAS_muls2_i32 0
93
#define TCG_TARGET_HAS_muluh_i32 1
94
#define TCG_TARGET_HAS_mulsh_i32 1
95
-#define TCG_TARGET_HAS_direct_jump 1
96
#define TCG_TARGET_HAS_qemu_st8_i32 0
97
98
#if TCG_TARGET_REG_BITS == 64
99
diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h
100
index XXXXXXX..XXXXXXX 100644
101
--- a/tcg/riscv/tcg-target.h
102
+++ b/tcg/riscv/tcg-target.h
103
@@ -XXX,XX +XXX,XX @@ typedef enum {
104
#define TCG_TARGET_HAS_clz_i32 0
105
#define TCG_TARGET_HAS_ctz_i32 0
106
#define TCG_TARGET_HAS_ctpop_i32 0
107
-#define TCG_TARGET_HAS_direct_jump 0
108
#define TCG_TARGET_HAS_brcond2 1
109
#define TCG_TARGET_HAS_setcond2 1
110
#define TCG_TARGET_HAS_qemu_st8_i32 0
111
diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h
112
index XXXXXXX..XXXXXXX 100644
113
--- a/tcg/s390x/tcg-target.h
114
+++ b/tcg/s390x/tcg-target.h
115
@@ -XXX,XX +XXX,XX @@ extern uint64_t s390_facilities[3];
116
#define TCG_TARGET_HAS_mulsh_i32 0
117
#define TCG_TARGET_HAS_extrl_i64_i32 0
118
#define TCG_TARGET_HAS_extrh_i64_i32 0
119
-#define TCG_TARGET_HAS_direct_jump 1
120
#define TCG_TARGET_HAS_qemu_st8_i32 0
121
122
#define TCG_TARGET_HAS_div2_i64 1
123
diff --git a/tcg/sparc64/tcg-target.h b/tcg/sparc64/tcg-target.h
124
index XXXXXXX..XXXXXXX 100644
125
--- a/tcg/sparc64/tcg-target.h
126
+++ b/tcg/sparc64/tcg-target.h
127
@@ -XXX,XX +XXX,XX @@ extern bool use_vis3_instructions;
128
#define TCG_TARGET_HAS_muls2_i32 1
129
#define TCG_TARGET_HAS_muluh_i32 0
130
#define TCG_TARGET_HAS_mulsh_i32 0
131
-#define TCG_TARGET_HAS_direct_jump 1
132
#define TCG_TARGET_HAS_qemu_st8_i32 0
133
134
#define TCG_TARGET_HAS_extrl_i64_i32 1
135
diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
136
index XXXXXXX..XXXXXXX 100644
137
--- a/tcg/tci/tcg-target.h
138
+++ b/tcg/tci/tcg-target.h
139
@@ -XXX,XX +XXX,XX @@
140
#define TCG_TARGET_HAS_muls2_i32 1
141
#define TCG_TARGET_HAS_muluh_i32 0
142
#define TCG_TARGET_HAS_mulsh_i32 0
143
-#define TCG_TARGET_HAS_direct_jump 0
144
#define TCG_TARGET_HAS_qemu_st8_i32 0
145
146
#if TCG_TARGET_REG_BITS == 64
147
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
148
index XXXXXXX..XXXXXXX 100644
149
--- a/accel/tcg/cpu-exec.c
150
+++ b/accel/tcg/cpu-exec.c
151
@@ -XXX,XX +XXX,XX @@ void cpu_exec_step_atomic(CPUState *cpu)
152
153
void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr)
154
{
155
+ /*
156
+ * Get the rx view of the structure, from which we find the
157
+ * executable code address, and tb_target_set_jmp_target can
158
+ * produce a pc-relative displacement to jmp_target_addr[n].
159
+ */
160
+ const TranslationBlock *c_tb = tcg_splitwx_to_rx(tb);
161
+ uintptr_t offset = tb->jmp_insn_offset[n];
162
+ uintptr_t jmp_rx = (uintptr_t)tb->tc.ptr + offset;
163
+ uintptr_t jmp_rw = jmp_rx - tcg_splitwx_diff;
164
+
165
tb->jmp_target_addr[n] = addr;
166
- if (TCG_TARGET_HAS_direct_jump) {
167
- /*
168
- * Get the rx view of the structure, from which we find the
169
- * executable code address, and tb_target_set_jmp_target can
170
- * produce a pc-relative displacement to jmp_target_addr[n].
171
- */
172
- const TranslationBlock *c_tb = tcg_splitwx_to_rx(tb);
173
- uintptr_t offset = tb->jmp_insn_offset[n];
174
- uintptr_t jmp_rx = (uintptr_t)tb->tc.ptr + offset;
175
- uintptr_t jmp_rw = jmp_rx - tcg_splitwx_diff;
176
- tb_target_set_jmp_target(c_tb, n, jmp_rx, jmp_rw);
177
- }
178
+ tb_target_set_jmp_target(c_tb, n, jmp_rx, jmp_rw);
179
}
180
181
static inline void tb_add_jump(TranslationBlock *tb, int n,
182
diff --git a/tcg/tcg.c b/tcg/tcg.c
183
index XXXXXXX..XXXXXXX 100644
184
--- a/tcg/tcg.c
185
+++ b/tcg/tcg.c
186
@@ -XXX,XX +XXX,XX @@ static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which)
187
* We will check for overflow at the end of the opcode loop in
188
* tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX.
189
*/
190
- tcg_debug_assert(TCG_TARGET_HAS_direct_jump);
191
s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s);
192
}
193
194
diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
195
index XXXXXXX..XXXXXXX 100644
196
--- a/tcg/arm/tcg-target.c.inc
197
+++ b/tcg/arm/tcg-target.c.inc
198
@@ -XXX,XX +XXX,XX @@ static void tcg_out_goto_tb(TCGContext *s, int which)
199
intptr_t ptr, dif, dil;
200
TCGReg base = TCG_REG_PC;
201
202
- qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
203
ptr = get_jmp_target_addr(s, which);
204
dif = tcg_pcrel_diff(s, (void *)ptr) - 8;
205
dil = sextract32(dif, 0, 12);
206
diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc
207
index XXXXXXX..XXXXXXX 100644
208
--- a/tcg/mips/tcg-target.c.inc
209
+++ b/tcg/mips/tcg-target.c.inc
210
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
211
static void tcg_out_goto_tb(TCGContext *s, int which)
212
{
213
/* indirect jump method */
214
- qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
215
tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_REG_ZERO,
216
get_jmp_target_addr(s, which));
217
tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0);
218
diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
219
index XXXXXXX..XXXXXXX 100644
220
--- a/tcg/riscv/tcg-target.c.inc
221
+++ b/tcg/riscv/tcg-target.c.inc
222
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
223
224
static void tcg_out_goto_tb(TCGContext *s, int which)
225
{
226
- qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
227
/* indirect jump method */
228
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO,
229
get_jmp_target_addr(s, which));
230
diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc
231
index XXXXXXX..XXXXXXX 100644
232
--- a/tcg/s390x/tcg-target.c.inc
233
+++ b/tcg/s390x/tcg-target.c.inc
234
@@ -XXX,XX +XXX,XX @@ static void tcg_out_goto_tb(TCGContext *s, int which)
235
void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
236
uintptr_t jmp_rx, uintptr_t jmp_rw)
237
{
238
+ if (!HAVE_FACILITY(GEN_INST_EXT)) {
239
+ return;
240
+ }
241
/* patch the branch destination */
242
uintptr_t addr = tb->jmp_target_addr[n];
243
intptr_t disp = addr - (jmp_rx - 2);
244
diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc
245
index XXXXXXX..XXXXXXX 100644
246
--- a/tcg/tci/tcg-target.c.inc
247
+++ b/tcg/tci/tcg-target.c.inc
248
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg)
249
250
static void tcg_out_goto_tb(TCGContext *s, int which)
251
{
252
- qemu_build_assert(!TCG_TARGET_HAS_direct_jump);
253
/* indirect jump method. */
254
tcg_out_op_p(s, INDEX_op_goto_tb, (void *)get_jmp_target_addr(s, which));
255
set_jmp_reset_offset(s, which);
256
--
257
2.34.1
258
259
diff view generated by jsdifflib
Deleted patch
1
The old sparc64 implementation may replace two insns, which leaves
2
a race condition in which a thread could be stopped at a PC in the
3
middle of the sequence, and when restarted does not see the complete
4
address computation and branches to nowhere.
5
1
6
The new implemetation replaces only one insn, swapping between a
7
direct branch and a direct call. The TCG_REG_TB register is loaded
8
from tb->jmp_target_addr[] in the delay slot.
9
10
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
11
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
12
---
13
tcg/sparc64/tcg-target.c.inc | 87 +++++++++++++++---------------------
14
1 file changed, 37 insertions(+), 50 deletions(-)
15
16
diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc
17
index XXXXXXX..XXXXXXX 100644
18
--- a/tcg/sparc64/tcg-target.c.inc
19
+++ b/tcg/sparc64/tcg-target.c.inc
20
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
21
22
static void tcg_out_goto_tb(TCGContext *s, int which)
23
{
24
- int c;
25
+ ptrdiff_t off = tcg_tbrel_diff(s, (void *)get_jmp_target_addr(s, which));
26
27
- /* Direct jump. */
28
- /* make sure the patch is 8-byte aligned. */
29
- if ((intptr_t)s->code_ptr & 4) {
30
- tcg_out_nop(s);
31
- }
32
+ /* Direct branch will be patched by tb_target_set_jmp_target. */
33
set_jmp_insn_offset(s, which);
34
- tcg_out_sethi(s, TCG_REG_T1, 0);
35
- tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, 0, ARITH_OR);
36
- tcg_out_arith(s, TCG_REG_G0, TCG_REG_TB, TCG_REG_T1, JMPL);
37
- tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD);
38
+ tcg_out32(s, CALL);
39
+ /* delay slot */
40
+ tcg_debug_assert(check_fit_ptr(off, 13));
41
+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TB, TCG_REG_TB, off);
42
set_jmp_reset_offset(s, which);
43
44
/*
45
* For the unlinked path of goto_tb, we need to reset TCG_REG_TB
46
* to the beginning of this TB.
47
*/
48
- c = -tcg_current_code_size(s);
49
- if (check_fit_i32(c, 13)) {
50
- tcg_out_arithi(s, TCG_REG_TB, TCG_REG_TB, c, ARITH_ADD);
51
+ off = -tcg_current_code_size(s);
52
+ if (check_fit_i32(off, 13)) {
53
+ tcg_out_arithi(s, TCG_REG_TB, TCG_REG_TB, off, ARITH_ADD);
54
} else {
55
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, c);
56
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, off);
57
tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD);
58
}
59
}
60
61
+void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
62
+ uintptr_t jmp_rx, uintptr_t jmp_rw)
63
+{
64
+ uintptr_t addr = tb->jmp_target_addr[n];
65
+ intptr_t br_disp = (intptr_t)(addr - jmp_rx) >> 2;
66
+ tcg_insn_unit insn;
67
+
68
+ br_disp >>= 2;
69
+ if (check_fit_ptr(br_disp, 19)) {
70
+ /* ba,pt %icc, addr */
71
+ insn = deposit32(INSN_OP(0) | INSN_OP2(1) | INSN_COND(COND_A)
72
+ | BPCC_ICC | BPCC_PT, 0, 19, br_disp);
73
+ } else if (check_fit_ptr(br_disp, 22)) {
74
+ /* ba addr */
75
+ insn = deposit32(INSN_OP(0) | INSN_OP2(2) | INSN_COND(COND_A),
76
+ 0, 22, br_disp);
77
+ } else {
78
+ /* The code_gen_buffer can't be larger than 2GB. */
79
+ tcg_debug_assert(check_fit_ptr(br_disp, 30));
80
+ /* call addr */
81
+ insn = deposit32(CALL, 0, 30, br_disp);
82
+ }
83
+
84
+ qatomic_set((uint32_t *)jmp_rw, insn);
85
+ flush_idcache_range(jmp_rx, jmp_rw, 4);
86
+}
87
+
88
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
89
const TCGArg args[TCG_MAX_OP_ARGS],
90
const int const_args[TCG_MAX_OP_ARGS])
91
@@ -XXX,XX +XXX,XX @@ void tcg_register_jit(const void *buf, size_t buf_size)
92
{
93
tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
94
}
95
-
96
-void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
97
- uintptr_t jmp_rx, uintptr_t jmp_rw)
98
-{
99
- uintptr_t addr = tb->jmp_target_addr[n];
100
- intptr_t tb_disp = addr - (uintptr_t)tb->tc.ptr;
101
- intptr_t br_disp = addr - jmp_rx;
102
- tcg_insn_unit i1, i2;
103
-
104
- /* We can reach the entire address space for ILP32.
105
- For LP64, the code_gen_buffer can't be larger than 2GB. */
106
- tcg_debug_assert(tb_disp == (int32_t)tb_disp);
107
- tcg_debug_assert(br_disp == (int32_t)br_disp);
108
-
109
- /* This does not exercise the range of the branch, but we do
110
- still need to be able to load the new value of TCG_REG_TB.
111
- But this does still happen quite often. */
112
- if (check_fit_ptr(tb_disp, 13)) {
113
- /* ba,pt %icc, addr */
114
- i1 = (INSN_OP(0) | INSN_OP2(1) | INSN_COND(COND_A)
115
- | BPCC_ICC | BPCC_PT | INSN_OFF19(br_disp));
116
- i2 = (ARITH_ADD | INSN_RD(TCG_REG_TB) | INSN_RS1(TCG_REG_TB)
117
- | INSN_IMM13(tb_disp));
118
- } else if (tb_disp >= 0) {
119
- i1 = SETHI | INSN_RD(TCG_REG_T1) | ((tb_disp & 0xfffffc00) >> 10);
120
- i2 = (ARITH_OR | INSN_RD(TCG_REG_T1) | INSN_RS1(TCG_REG_T1)
121
- | INSN_IMM13(tb_disp & 0x3ff));
122
- } else {
123
- i1 = SETHI | INSN_RD(TCG_REG_T1) | ((~tb_disp & 0xfffffc00) >> 10);
124
- i2 = (ARITH_XOR | INSN_RD(TCG_REG_T1) | INSN_RS1(TCG_REG_T1)
125
- | INSN_IMM13((tb_disp & 0x3ff) | -0x400));
126
- }
127
-
128
- qatomic_set((uint64_t *)jmp_rw, deposit64(i2, 32, 32, i1));
129
- flush_idcache_range(jmp_rx, jmp_rw, 8);
130
-}
131
--
132
2.34.1
133
134
diff view generated by jsdifflib
1
Now that tcg can handle direct and indirect goto_tb
1
User setting of -R reserved_va can lead to an assertion
2
simultaneously, we can optimistically leave space for
2
failure in page_set_flags. Sanity check the value of
3
a direct branch and fall back to loading the pointer
3
reserved_va and print an error message instead. Do not
4
from the TB for an indirect branch.
4
allocate a commpage at all for m-profile cpus.
5
5
6
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
---
7
---
9
tcg/arm/tcg-target.c.inc | 52 ++++++++++++++++++++++++++++------------
8
linux-user/elfload.c | 37 +++++++++++++++++++++++++++----------
10
1 file changed, 37 insertions(+), 15 deletions(-)
9
1 file changed, 27 insertions(+), 10 deletions(-)
11
10
12
diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
11
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
13
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
14
--- a/tcg/arm/tcg-target.c.inc
13
--- a/linux-user/elfload.c
15
+++ b/tcg/arm/tcg-target.c.inc
14
+++ b/linux-user/elfload.c
16
@@ -XXX,XX +XXX,XX @@ typedef enum {
15
@@ -XXX,XX +XXX,XX @@ enum {
17
ARITH_BIC = 0xe << 21,
16
18
ARITH_MVN = 0xf << 21,
17
static bool init_guest_commpage(void)
19
20
+ INSN_B = 0x0a000000,
21
+
22
INSN_CLZ = 0x016f0f10,
23
INSN_RBIT = 0x06ff0f30,
24
25
@@ -XXX,XX +XXX,XX @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct)
26
27
static void tcg_out_b_imm(TCGContext *s, ARMCond cond, int32_t offset)
28
{
18
{
29
- tcg_out32(s, (cond << 28) | 0x0a000000 |
19
- abi_ptr commpage = HI_COMMPAGE & -qemu_host_page_size;
30
+ tcg_out32(s, (cond << 28) | INSN_B |
20
- void *want = g2h_untagged(commpage);
31
(((offset - 8) >> 2) & 0x00ffffff));
21
- void *addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE,
32
}
22
- MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
33
23
+ ARMCPU *cpu = ARM_CPU(thread_cpu);
34
@@ -XXX,XX +XXX,XX @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg)
24
+ abi_ptr want = HI_COMMPAGE & TARGET_PAGE_MASK;
35
25
+ abi_ptr addr;
36
static void tcg_out_goto_tb(TCGContext *s, int which)
26
37
{
27
- if (addr == MAP_FAILED) {
38
- /* Indirect jump method */
28
+ /*
39
- intptr_t ptr, dif, dil;
29
+ * M-profile allocates maximum of 2GB address space, so can never
40
- TCGReg base = TCG_REG_PC;
30
+ * allocate the commpage. Skip it.
41
+ uintptr_t i_addr;
31
+ */
42
+ intptr_t i_disp;
32
+ if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
43
33
+ return true;
44
- ptr = get_jmp_target_addr(s, which);
45
- dif = tcg_pcrel_diff(s, (void *)ptr) - 8;
46
- dil = sextract32(dif, 0, 12);
47
- if (dif != dil) {
48
+ /* Direct branch will be patched by tb_target_set_jmp_target. */
49
+ set_jmp_insn_offset(s, which);
50
+ tcg_out32(s, INSN_NOP);
51
+
52
+ /* When branch is out of range, fall through to indirect. */
53
+ i_addr = get_jmp_target_addr(s, which);
54
+ i_disp = tcg_pcrel_diff(s, (void *)i_addr) - 8;
55
+ tcg_debug_assert(i_disp < 0);
56
+ if (i_disp >= -0xfff) {
57
+ tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, i_disp);
58
+ } else {
59
/*
60
* The TB is close, but outside the 12 bits addressable by
61
* the load. We can extend this to 20 bits with a sub of a
62
- * shifted immediate from pc. In the vastly unlikely event
63
- * the code requires more than 1MB, we'll use 2 insns and
64
- * be no worse off.
65
+ * shifted immediate from pc.
66
*/
67
- base = TCG_REG_R0;
68
- tcg_out_movi32(s, COND_AL, base, ptr - dil);
69
+ int h = -i_disp;
70
+ int l = h & 0xfff;
71
+
72
+ h = encode_imm_nofail(h - l);
73
+ tcg_out_dat_imm(s, COND_AL, ARITH_SUB, TCG_REG_R0, TCG_REG_PC, h);
74
+ tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_R0, l);
75
}
76
- tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, base, dil);
77
set_jmp_reset_offset(s, which);
78
}
79
80
void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
81
uintptr_t jmp_rx, uintptr_t jmp_rw)
82
{
83
- /* Always indirect, nothing to do */
84
+ uintptr_t addr = tb->jmp_target_addr[n];
85
+ ptrdiff_t offset = addr - (jmp_rx + 8);
86
+ tcg_insn_unit insn;
87
+
88
+ /* Either directly branch, or fall through to indirect branch. */
89
+ if (offset == sextract64(offset, 0, 26)) {
90
+ /* B <addr> */
91
+ insn = deposit32((COND_AL << 28) | INSN_B, 0, 24, offset >> 2);
92
+ } else {
93
+ insn = INSN_NOP;
94
+ }
34
+ }
95
+
35
+
96
+ qatomic_set((uint32_t *)jmp_rw, insn);
36
+ /*
97
+ flush_idcache_range(jmp_rx, jmp_rw, 4);
37
+ * If reserved_va does not cover the commpage, we get an assert
38
+ * in page_set_flags. Produce an intelligent error instead.
39
+ */
40
+ if (reserved_va != 0 && want + TARGET_PAGE_SIZE - 1 > reserved_va) {
41
+ error_report("Allocating guest commpage: -R 0x%" PRIx64 " too small",
42
+ (uint64_t)reserved_va + 1);
43
+ exit(EXIT_FAILURE);
44
+ }
45
+
46
+ addr = target_mmap(want, TARGET_PAGE_SIZE, PROT_READ | PROT_WRITE,
47
+ MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
48
+
49
+ if (addr == -1) {
50
perror("Allocating guest commpage");
51
exit(EXIT_FAILURE);
52
}
53
@@ -XXX,XX +XXX,XX @@ static bool init_guest_commpage(void)
54
}
55
56
/* Set kernel helper versions; rest of page is 0. */
57
- __put_user(5, (uint32_t *)g2h_untagged(0xffff0ffcu));
58
+ put_user_u32(5, 0xffff0ffcu);
59
60
- if (mprotect(addr, qemu_host_page_size, PROT_READ)) {
61
+ if (target_mprotect(addr, qemu_host_page_size, PROT_READ | PROT_EXEC)) {
62
perror("Protecting guest commpage");
63
exit(EXIT_FAILURE);
64
}
65
-
66
- page_set_flags(commpage, commpage | ~qemu_host_page_mask,
67
- PAGE_READ | PAGE_EXEC | PAGE_VALID);
68
return true;
98
}
69
}
99
70
100
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
101
--
71
--
102
2.34.1
72
2.34.1
103
104
diff view generated by jsdifflib