42
42
#include "decode.h"
43
43
#include "io.h"
44
44
#include "jit.h"
45
+ #include "log.h"
45
46
#include "riscv.h"
46
47
#include "riscv_private.h"
47
48
#include "utils.h"
@@ -593,24 +594,30 @@ static void update_branch_imm(struct jit_state *state,
593
594
assert ((imm & 3 ) == 0 );
594
595
uint32_t insn ;
595
596
imm >>= 2 ;
597
+ rv_log_debug ("JIT: Patching branch at offset=%u, imm=%d" , offset , imm * 4 );
598
+ /* Read instruction while in execute mode (MAP_JIT requirement) */
596
599
memcpy (& insn , state -> buf + offset , sizeof (uint32_t ));
597
600
if ((insn & 0xfe000000U ) == 0x54000000U /* Conditional branch immediate. */
598
601
|| (insn & 0x7e000000U ) ==
599
602
0x34000000U ) { /* Compare and branch immediate. */
600
603
assert ((imm >> 19 ) == INT64_C (-1 ) || (imm >> 19 ) == 0 );
604
+ insn &= ~(0x7ffffU << 5 ); /* Clear old offset bits */
601
605
insn |= (imm & 0x7ffff ) << 5 ;
602
606
} else if ((insn & 0x7c000000U ) == 0x14000000U ) {
603
607
/* Unconditional branch immediate. */
604
608
assert ((imm >> 26 ) == INT64_C (-1 ) || (imm >> 26 ) == 0 );
609
+ insn &= ~0x03ffffffU ; /* Clear old offset bits */
605
610
insn |= (imm & 0x03ffffffU ) << 0 ;
606
611
} else {
607
612
assert (false);
608
613
insn = BAD_OPCODE ;
609
614
}
610
615
#if defined(__APPLE__ ) && defined(__aarch64__ )
616
+ /* Switch to write mode only for writing */
611
617
pthread_jit_write_protect_np (false);
612
618
#endif
613
619
memcpy (state -> buf + offset , & insn , sizeof (uint32_t ));
620
+ sys_icache_invalidate (state -> buf + offset , sizeof (uint32_t ));
614
621
#if defined(__APPLE__ ) && defined(__aarch64__ )
615
622
pthread_jit_write_protect_np (true);
616
623
#endif
@@ -2164,9 +2171,12 @@ void clear_hot(block_t *block)
2164
2171
2165
2172
static void code_cache_flush (struct jit_state * state , riscv_t * rv )
2166
2173
{
2174
+ rv_log_info ("JIT: Flushing code cache (n_blocks=%d, n_jumps=%d, offset=%u)" ,
2175
+ state -> n_blocks , state -> n_jumps , state -> offset );
2167
2176
should_flush = false;
2168
2177
state -> offset = state -> org_size ;
2169
2178
state -> n_blocks = 0 ;
2179
+ state -> n_jumps = 0 ; /* Reset jump count when flushing */
2170
2180
set_reset (& state -> set );
2171
2181
clear_cache_hot (rv -> block_cache , (clear_func_t ) clear_hot );
2172
2182
#if RV32_HAS (T2C )
@@ -2196,6 +2206,7 @@ static void translate(struct jit_state *state, riscv_t *rv, block_t *block)
2196
2206
2197
2207
static void resolve_jumps (struct jit_state * state )
2198
2208
{
2209
+ rv_log_debug ("JIT: Resolving %d jumps" , state -> n_jumps );
2199
2210
for (int i = 0 ; i < state -> n_jumps ; i ++ ) {
2200
2211
struct jump jump = state -> jumps [i ];
2201
2212
int target_loc ;
@@ -2218,6 +2229,10 @@ static void resolve_jumps(struct jit_state *state)
2218
2229
(if (jump .target_satp == state -> offset_map [i ].satp ), )
2219
2230
{
2220
2231
target_loc = state -> offset_map [i ].offset ;
2232
+ rv_log_debug (
2233
+ "JIT: Jump %d resolved to block pc=0x%08x, "
2234
+ "offset=%d" ,
2235
+ i , jump .target_pc , target_loc );
2221
2236
break ;
2222
2237
}
2223
2238
}
@@ -2229,6 +2244,7 @@ static void resolve_jumps(struct jit_state *state)
2229
2244
2230
2245
uint8_t * offset_ptr = & state -> buf [jump .offset_loc ];
2231
2246
memcpy (offset_ptr , & rel , sizeof (uint32_t ));
2247
+ sys_icache_invalidate (offset_ptr , sizeof (uint32_t ));
2232
2248
#elif defined(__aarch64__)
2233
2249
int32_t rel = target_loc - jump .offset_loc ;
2234
2250
update_branch_imm (state , jump .offset_loc , rel );
@@ -2308,23 +2324,35 @@ void jit_translate(riscv_t *rv, block_t *block)
2308
2324
) {
2309
2325
block -> offset = state -> offset_map [i ].offset ;
2310
2326
block -> hot = true;
2327
+ rv_log_debug ("JIT: Cache hit for block pc=0x%08x, offset=%u" ,
2328
+ block -> pc_start , block -> offset );
2311
2329
return ;
2312
2330
}
2313
2331
}
2314
2332
assert (NULL );
2315
2333
__UNREACHABLE ;
2316
2334
}
2335
+ rv_log_debug ("JIT: Starting translation for block pc=0x%08x" ,
2336
+ block -> pc_start );
2317
2337
restart :
2318
2338
memset (state -> jumps , 0 , MAX_JUMPS * sizeof (struct jump ));
2319
2339
state -> n_jumps = 0 ;
2320
2340
block -> offset = state -> offset ;
2321
2341
translate_chained_block (state , rv , block );
2322
2342
if (unlikely (should_flush )) {
2343
+ /* Mark block as not translated since translation was incomplete */
2344
+ block -> hot = false;
2345
+ /* Don't reset offset - it will be set correctly on restart */
2346
+ rv_log_debug ("JIT: Translation triggered flush for block pc=0x%08x" ,
2347
+ block -> pc_start );
2323
2348
code_cache_flush (state , rv );
2324
2349
goto restart ;
2325
2350
}
2326
2351
resolve_jumps (state );
2327
2352
block -> hot = true;
2353
+ rv_log_debug (
2354
+ "JIT: Translation completed for block pc=0x%08x, offset=%u, size=%u" ,
2355
+ block -> pc_start , block -> offset , state -> offset - block -> offset );
2328
2356
}
2329
2357
2330
2358
struct jit_state * jit_state_init (size_t size )
@@ -2336,10 +2364,12 @@ struct jit_state *jit_state_init(size_t size)
2336
2364
2337
2365
state -> offset = 0 ;
2338
2366
state -> size = size ;
2339
- #if defined(TSAN_ENABLED ) && defined( __x86_64__ )
2367
+ #if defined(TSAN_ENABLED )
2340
2368
/* ThreadSanitizer compatibility: Allocate JIT code buffer at a fixed
2341
2369
* address above the main memory region to avoid conflicts.
2342
- *
2370
+ */
2371
+ #if defined(__x86_64__ )
2372
+ /* x86_64 memory layout:
2343
2373
* Main memory: 0x7d0000000000 - 0x7d0100000000 (4GB for FULL4G)
2344
2374
* JIT buffer: 0x7d1000000000 + size
2345
2375
*
@@ -2348,7 +2378,32 @@ struct jit_state *jit_state_init(size_t size)
2348
2378
*/
2349
2379
void * jit_addr = (void * ) 0x7d1000000000UL ;
2350
2380
state -> buf = mmap (jit_addr , size , PROT_READ | PROT_WRITE | PROT_EXEC ,
2351
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED , -1 , 0 );
2381
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED
2382
+ #if defined(__APPLE__ )
2383
+ | MAP_JIT
2384
+ #endif
2385
+ ,
2386
+ -1 , 0 );
2387
+ #elif defined(__aarch64__ )
2388
+ /* ARM64 memory layout (macOS/Apple Silicon):
2389
+ * Main memory: 0x150000000000 - 0x150100000000 (4GB for FULL4G)
2390
+ * JIT buffer: 0x151000000000 + size
2391
+ *
2392
+ * Apple Silicon requires MAP_JIT for executable memory. The fixed
2393
+ * address is chosen to avoid TSAN's shadow memory and typical process
2394
+ * allocations. Requires ASLR disabled via: setarch $(uname -m) -R
2395
+ */
2396
+ void * jit_addr = (void * ) 0x151000000000UL ;
2397
+ state -> buf = mmap (jit_addr , size , PROT_READ | PROT_WRITE | PROT_EXEC ,
2398
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED
2399
+ #if defined(__APPLE__ )
2400
+ | MAP_JIT
2401
+ #endif
2402
+ ,
2403
+ -1 , 0 );
2404
+ #else
2405
+ #error "TSAN is only supported on x86_64 and aarch64"
2406
+ #endif
2352
2407
if (state -> buf == MAP_FAILED ) {
2353
2408
free (state );
2354
2409
return NULL ;
0 commit comments