#ifndef V8_WASM_JUMP_TABLE_ASSEMBLER_H_
#define V8_WASM_JUMP_TABLE_ASSEMBLER_H_
#if !V8_ENABLE_WEBASSEMBLY
#error This header should only be included if WebAssembly is enabled.
#endif
#include "src/codegen/flush-instruction-cache.h"
#include "src/codegen/macro-assembler.h"
namespace v8 {
namespace internal {
namespace wasm {
class V8_EXPORT_PRIVATE JumpTableAssembler {
public:
static uint32_t SlotOffsetToIndex(uint32_t slot_offset) {
uint32_t line_index = slot_offset / kJumpTableLineSize;
uint32_t line_offset = slot_offset % kJumpTableLineSize;
DCHECK_EQ(0, line_offset % kJumpTableSlotSize);
return line_index * kJumpTableSlotsPerLine +
line_offset / kJumpTableSlotSize;
}
static uint32_t JumpSlotIndexToOffset(uint32_t slot_index) {
uint32_t line_index = slot_index / kJumpTableSlotsPerLine;
uint32_t line_offset =
(slot_index % kJumpTableSlotsPerLine) * kJumpTableSlotSize;
return line_index * kJumpTableLineSize + line_offset;
}
static constexpr uint32_t SizeForNumberOfSlots(uint32_t slot_count) {
return ((slot_count + kJumpTableSlotsPerLine - 1) /
kJumpTableSlotsPerLine) *
kJumpTableLineSize;
}
static uint32_t FarJumpSlotIndexToOffset(uint32_t slot_index) {
return slot_index * kFarJumpTableSlotSize;
}
static uint32_t FarJumpSlotOffsetToIndex(uint32_t offset) {
DCHECK_EQ(0, offset % kFarJumpTableSlotSize);
return offset / kFarJumpTableSlotSize;
}
static constexpr uint32_t SizeForNumberOfFarJumpSlots(
int num_runtime_slots, int num_function_slots) {
int num_entries = num_runtime_slots + num_function_slots;
return num_entries * kFarJumpTableSlotSize;
}
static uint32_t LazyCompileSlotIndexToOffset(uint32_t slot_index) {
return slot_index * kLazyCompileTableSlotSize;
}
static constexpr uint32_t SizeForNumberOfLazyFunctions(uint32_t slot_count) {
return slot_count * kLazyCompileTableSlotSize;
}
static void GenerateLazyCompileTable(Address base, uint32_t num_slots,
uint32_t num_imported_functions,
Address wasm_compile_lazy_target);
static void InitializeJumpsToLazyCompileTable(
Address base, uint32_t num_slots, Address lazy_compile_table_start);
static void GenerateFarJumpTable(WritableJitAllocation& jit_allocation,
Address base, Address* stub_targets,
int num_runtime_slots,
int num_function_slots) {
uint32_t table_size =
SizeForNumberOfFarJumpSlots(num_runtime_slots, num_function_slots);
JumpTableAssembler jtasm(jit_allocation, base);
int offset = 0;
for (int index = 0; index < num_runtime_slots + num_function_slots;
++index) {
DCHECK_EQ(offset, FarJumpSlotIndexToOffset(index));
Address target =
index < num_runtime_slots ? stub_targets[index] : base + offset;
jtasm.EmitFarJumpSlot(target);
offset += kFarJumpTableSlotSize;
DCHECK_EQ(offset, jtasm.pc_offset());
}
FlushInstructionCache(base, table_size);
}
static void PatchJumpTableSlot(WritableJumpTablePair& jump_table_pair,
Address jump_table_slot,
Address far_jump_table_slot, Address target) {
JumpTableAssembler jtasm(jump_table_pair.jump_table(), jump_table_slot);
if (!jtasm.EmitJumpSlot(target)) {
DCHECK_NE(kNullAddress, far_jump_table_slot);
JumpTableAssembler::PatchFarJumpSlot(jump_table_pair.far_jump_table(),
far_jump_table_slot, target);
CHECK(jtasm.EmitJumpSlot(far_jump_table_slot));
}
DCHECK_EQ(kJumpTableSlotSize, jtasm.pc_offset());
FlushInstructionCache(jump_table_slot, kJumpTableSlotSize);
}
private:
explicit JumpTableAssembler(WritableJitAllocation& jit_allocation,
Address slot_addr)
: jit_allocation_(jit_allocation),
buffer_start_(slot_addr),
pc_(slot_addr) {}
WritableJitAllocation& jit_allocation_;
const Address buffer_start_;
Address pc_;
#if V8_TARGET_ARCH_X64
#ifdef V8_ENABLE_CET_IBT
static constexpr int kJumpTableSlotSize = 16;
#else
static constexpr int kJumpTableSlotSize = 8;
#endif
static constexpr int kJumpTableLineSize = kJumpTableSlotSize;
static constexpr int kFarJumpTableSlotSize = 16;
static constexpr int kLazyCompileTableSlotSize = 10;
#elif V8_TARGET_ARCH_IA32
static constexpr int kJumpTableLineSize = 64;
static constexpr int kJumpTableSlotSize = 5;
static constexpr int kFarJumpTableSlotSize = 5;
static constexpr int kLazyCompileTableSlotSize = 10;
#elif V8_TARGET_ARCH_ARM
static constexpr int kJumpTableLineSize = 2 * kInstrSize;
static constexpr int kJumpTableSlotSize = 2 * kInstrSize;
static constexpr int kFarJumpTableSlotSize = 2 * kInstrSize;
static constexpr int kLazyCompileTableSlotSize = 4 * kInstrSize;
#elif V8_TARGET_ARCH_ARM64
#if V8_ENABLE_CONTROL_FLOW_INTEGRITY
static constexpr int kJumpTableLineSize = 2 * kInstrSize;
static constexpr int kJumpTableSlotSize = 2 * kInstrSize;
#else
static constexpr int kJumpTableLineSize = 1 * kInstrSize;
static constexpr int kJumpTableSlotSize = 1 * kInstrSize;
#endif
static constexpr int kFarJumpTableSlotSize = 4 * kInstrSize;
static constexpr int kLazyCompileTableSlotSize = 4 * kInstrSize;
#elif V8_TARGET_ARCH_S390X
static constexpr int kJumpTableLineSize = 128;
static constexpr int kJumpTableSlotSize = 8;
static constexpr int kFarJumpTableSlotSize = 24;
static constexpr int kLazyCompileTableSlotSize = 32;
#elif V8_TARGET_ARCH_PPC64
static constexpr int kJumpTableLineSize = 64;
static constexpr int kJumpTableSlotSize = 1 * kInstrSize;
static constexpr int kFarJumpTableSlotSize = 12 * kInstrSize;
static constexpr int kLazyCompileTableSlotSize = 12 * kInstrSize;
#elif V8_TARGET_ARCH_MIPS64
static constexpr int kJumpTableLineSize = 8 * kInstrSize;
static constexpr int kJumpTableSlotSize = 8 * kInstrSize;
static constexpr int kFarJumpTableSlotSize = 8 * kInstrSize;
static constexpr int kLazyCompileTableSlotSize = 10 * kInstrSize;
#elif V8_TARGET_ARCH_RISCV64
static constexpr int kJumpTableSlotSize = 6 * kInstrSize;
static constexpr int kJumpTableLineSize = kJumpTableSlotSize;
static constexpr int kFarJumpTableSlotSize = 6 * kInstrSize;
static constexpr int kLazyCompileTableSlotSize = 3 * kInstrSize;
#elif V8_TARGET_ARCH_RISCV32
static constexpr int kJumpTableSlotSize = 4 * kInstrSize;
static constexpr int kJumpTableLineSize = kJumpTableSlotSize;
static constexpr int kFarJumpTableSlotSize = kJumpTableSlotSize;
static constexpr int kLazyCompileTableSlotSize = 3 * kInstrSize;
#elif V8_TARGET_ARCH_LOONG64
static constexpr int kJumpTableLineSize = 1 * kInstrSize;
static constexpr int kJumpTableSlotSize = 1 * kInstrSize;
static constexpr int kFarJumpTableSlotSize = 6 * kInstrSize;
static constexpr int kLazyCompileTableSlotSize = 3 * kInstrSize;
#else
#error Unknown architecture.
#endif
static constexpr int kJumpTableSlotsPerLine =
kJumpTableLineSize / kJumpTableSlotSize;
static_assert(kJumpTableSlotsPerLine >= 1);
void EmitLazyCompileJumpSlot(uint32_t func_index,
Address lazy_compile_target);
bool EmitJumpSlot(Address target);
void EmitFarJumpSlot(Address target);
static void PatchFarJumpSlot(WritableJitAllocation& jit_allocation,
Address slot, Address target);
void SkipUntil(int offset);
int pc_offset() const { return static_cast<int>(pc_ - buffer_start_); }
template <typename V>
void emit(V value);
template <typename V>
void emit(V value, RelaxedStoreTag);
};
}
}
}
#endif