/* * The per-CPU TranslationBlock jump cache. * * Copyright (c) 2003 Fabrice Bellard * * SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef ACCEL_TCG_TB_JMP_CACHE_H #define ACCEL_TCG_TB_JMP_CACHE_H #define TB_JMP_CACHE_BITS 12 #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS) /* * Accessed in parallel; all accesses to 'tb' must be atomic. * For TARGET_TB_PCREL, accesses to 'pc' must be protected by * a load_acquire/store_release to 'tb'. */ struct CPUJumpCache { struct rcu_head rcu; struct { TranslationBlock *tb; #if TARGET_TB_PCREL target_ulong pc; #endif } array[TB_JMP_CACHE_SIZE]; }; static inline TranslationBlock * tb_jmp_cache_get_tb(CPUJumpCache *jc, uint32_t hash) { #if TARGET_TB_PCREL /* Use acquire to ensure current load of pc from jc. */ return qatomic_load_acquire(&jc->array[hash].tb); #else /* Use rcu_read to ensure current load of pc from *tb. */ return qatomic_rcu_read(&jc->array[hash].tb); #endif } static inline target_ulong tb_jmp_cache_get_pc(CPUJumpCache *jc, uint32_t hash, TranslationBlock *tb) { #if TARGET_TB_PCREL return jc->array[hash].pc; #else return tb_pc(tb); #endif } static inline void tb_jmp_cache_set(CPUJumpCache *jc, uint32_t hash, TranslationBlock *tb, target_ulong pc) { #if TARGET_TB_PCREL jc->array[hash].pc = pc; /* Use store_release on tb to ensure pc is written first. */ qatomic_store_release(&jc->array[hash].tb, tb); #else /* Use the pc value already stored in tb->pc. */ qatomic_set(&jc->array[hash].tb, tb); #endif } #endif /* ACCEL_TCG_TB_JMP_CACHE_H */