Skip to content

Commit e000d0e

Browse files
committed
pythongh-96143: Clear instruction cache after mprotect call
1 parent 894cafd commit e000d0e

1 file changed

Lines changed: 18 additions & 4 deletions

File tree

‎Objects/perf_trampoline.c‎

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,18 @@ struct trampoline_api_st {
185185

186186
typedef struct trampoline_api_st trampoline_api_t;
187187

188+
#if defined(__clang__) || defined(__GNUC__)
189+
extern void __clear_cache(void *, void*);
190+
#endif
191+
192+
static void invalidate_icache(char* begin, char*end) {
193+
#if defined(__clang__) || defined(__GNUC__)
194+
return __clear_cache(begin, end);
195+
#else
196+
return;
197+
#endif
198+
}
199+
188200
static perf_status_t perf_status = PERF_STATUS_NO_INIT;
189201
static Py_ssize_t extra_code_index = -1;
190202
static code_arena_t *code_arena;
@@ -297,10 +309,6 @@ new_code_arena(void)
297309
memcpy(memory + i * code_size, start, code_size * sizeof(char));
298310
}
299311
// Some systems may prevent us from creating executable code on the fly.
300-
// TODO: Call icache invalidation intrinsics if available:
301-
// __builtin___clear_cache/__clear_cache (depending if clang/gcc). This is
302-
// technically not necessary but we could be missing something so better be
303-
// safe.
304312
int res = mprotect(memory, mem_size, PROT_READ | PROT_EXEC);
305313
if (res == -1) {
306314
PyErr_SetFromErrno(PyExc_OSError);
@@ -311,6 +319,12 @@ new_code_arena(void)
311319
return -1;
312320
}
313321

322+
#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
323+
// Before the JIT can run a block of code that has been emitted it must invalidate
324+
// the instruction cache on some platforms like arm and aarch64.
325+
invalidate_icache(memory, memory + mem_size);
326+
#endif
327+
314328
code_arena_t *new_arena = PyMem_RawCalloc(1, sizeof(code_arena_t));
315329
if (new_arena == NULL) {
316330
PyErr_NoMemory();

0 commit comments

Comments
 (0)