2525#include "pycore_template.h"
2626#include "pycore_tuple.h"
2727#include "pycore_unicodeobject.h"
28+ #include "pycore_uop_metadata.h"
2829
2930#include "pycore_jit.h"
3031
@@ -124,6 +125,26 @@ mark_executable(unsigned char *memory, size_t size)
124125 return 0 ;
125126}
126127
128+ static int
129+ mark_read_writeable (unsigned char * memory , size_t size )
130+ {
131+ if (size == 0 ) {
132+ return 0 ;
133+ }
134+ assert (size % get_page_size () == 0 );
135+ #ifdef MS_WINDOWS
136+ int old ;
137+ int failed = !VirtualProtect (memory , size , PAGE_READWRITE , & old );
138+ #else
139+ int failed = mprotect (memory , size , PROT_WRITE | PROT_READ );
140+ #endif
141+ if (failed ) {
142+ jit_error ("unable to protect executable memory" );
143+ return -1 ;
144+ }
145+ return 0 ;
146+ }
147+
127148// JIT compiler stuff: /////////////////////////////////////////////////////////
128149
129150#define SYMBOL_MASK_WORDS 4
@@ -138,6 +159,7 @@ typedef struct {
138159
139160typedef struct {
140161 trampoline_state trampolines ;
162+ _PyExecutorObject * executor ;
141163 uintptr_t instruction_starts [UOP_MAX_TRACE_LENGTH ];
142164} jit_state ;
143165
@@ -443,6 +465,22 @@ patch_x86_64_32rx(unsigned char *location, uint64_t value)
443465 patch_32r (location , value );
444466}
445467
468+ static void
469+ register_side_exit (const _PyUOpInstruction * instruction , unsigned char * loc , const _PyUOpInstruction * exit_trace )
470+ {
471+ if (!(_PyUop_Flags [instruction -> opcode ] & HAS_EXIT_FLAG )) {
472+ return ;
473+ }
474+ assert (exit_trace -> opcode == _EXIT_TRACE );
475+ _PyExitData * exit = (_PyExitData * )exit_trace -> operand0 ;
476+ if (exit -> num_side_locations_used >= UOP_MAX_SIDE_EXITS_PER_UOP ) {
477+ return ;
478+ }
479+ exit -> exiting_uop_side_exit_locations [exit -> num_side_locations_used ] = (uintptr_t )loc ;
480+ exit -> num_side_locations_used ++ ;
481+ }
482+
483+
446484void patch_aarch64_trampoline (unsigned char * location , int ordinal , jit_state * state );
447485
448486#include "jit_stencils.h"
@@ -519,6 +557,7 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction trace[], siz
519557 size_t code_size = 0 ;
520558 size_t data_size = 0 ;
521559 jit_state state = {0 };
560+ state .executor = executor ;
522561 for (size_t i = 0 ; i < length ; i ++ ) {
523562 const _PyUOpInstruction * instruction = & trace [i ];
524563 group = & stencil_groups [instruction -> opcode ];
@@ -664,4 +703,47 @@ _PyJIT_Free(_PyExecutorObject *executor)
664703 }
665704}
666705
706+ #ifdef __x86_64__
707+ static void
708+ patch_side_exit (unsigned char * location , uint64_t value )
709+ {
710+ uint64_t distance = (value - 0x4 ) - (uintptr_t )location ;
711+ // Cannot fit in a 32-bit PC-relative address.
712+ if ((int64_t )distance < - (1LL << 31 ) || (int64_t )distance >= (1LL << 31 )) {
713+ return ;
714+ }
715+ patch_32r (location , value - 0x4 );
716+ }
717+ #else
718+ // TODO AArch64
719+ static void
720+ patch_side_exit (unsigned char * location , uint64_t value )
721+ {
722+ (void )location ;
723+ (void )value ;
724+ return ;
725+ }
726+ #endif
727+
728+ int
729+ _PyJit_PatchSideExit (_PyExecutorObject * trunk_executor , _PyExitData * exit_p , _PyExecutorObject * side_exit )
730+ {
731+ if (exit_p -> num_side_locations_used > 0 ) {
732+ if (mark_read_writeable (trunk_executor -> jit_code , trunk_executor -> jit_size ) < 0 ) {
733+ return -1 ;
734+ }
735+ uintptr_t new_target = (uintptr_t )side_exit -> jit_code ;
736+ for (int i = 0 ; i < exit_p -> num_side_locations_used ; i ++ ) {
737+ uintptr_t loc = exit_p -> exiting_uop_side_exit_locations [i ];
738+ assert (loc >= (uintptr_t )trunk_executor -> jit_code );
739+ assert (loc < (uintptr_t )((unsigned char * )trunk_executor -> jit_code + trunk_executor -> jit_size ));
740+ patch_side_exit ((unsigned char * )loc , new_target );
741+ }
742+ if (mark_executable (trunk_executor -> jit_code , trunk_executor -> jit_size ) < 0 ) {
743+ return -1 ;
744+ }
745+ }
746+ return 0 ;
747+ }
748+
667749#endif // _Py_JIT
0 commit comments