Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/zjit-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,25 @@ permissions:
contents: read

jobs:
lint:
name: cargo clippy

runs-on: ubuntu-22.04

if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
|| (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
)}}

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- run: cargo clippy --all-targets --all-features
working-directory: zjit

make:
strategy:
fail-fast: false
Expand Down
4 changes: 4 additions & 0 deletions doc/zjit.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ To run code snippets with ZJIT:
You can also try https://www.rubyexplorer.xyz/ to view Ruby YARV disasm output with syntax highlighting
in a way that can be easily shared with other team members.

## Documentation

You can generate and open the source level documentation in your browser using `cargo doc --open --document-private-items`.

## Testing

Make sure you have a `--enable-zjit=dev` build, and install the following tools:
Expand Down
3 changes: 2 additions & 1 deletion test/ruby/test_gc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -742,12 +742,13 @@ def test_exception_in_finalizer
end

def test_interrupt_in_finalizer
omit 'randomly hangs on many platforms' if ENV.key?('GITHUB_ACTIONS')
bug10595 = '[ruby-core:66825] [Bug #10595]'
src = <<-'end;'
Signal.trap(:INT, 'DEFAULT')
pid = $$
Thread.start do
1000.times {
10.times {
sleep 0.1
Process.kill("INT", pid) rescue break
}
Expand Down
21 changes: 19 additions & 2 deletions vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ jit_compile(rb_execution_context_t *ec)

// At call-threshold, compile the ISEQ with ZJIT.
if (body->jit_entry_calls == rb_zjit_call_threshold) {
rb_zjit_compile_iseq(iseq, ec, false);
rb_zjit_compile_iseq(iseq, false);
}
}
#endif
Expand Down Expand Up @@ -493,8 +493,25 @@ jit_compile_exception(rb_execution_context_t *ec)
const rb_iseq_t *iseq = ec->cfp->iseq;
struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);

// Increment the ISEQ's call counter and trigger JIT compilation if not compiled
#if USE_ZJIT
if (body->jit_exception == NULL && rb_zjit_enabled_p) {
body->jit_exception_calls++;

// At profile-threshold, rewrite some of the YARV instructions
// to zjit_* instructions to profile these instructions.
if (body->jit_exception_calls == rb_zjit_profile_threshold) {
rb_zjit_profile_enable(iseq);
}

// At call-threshold, compile the ISEQ with ZJIT.
if (body->jit_exception_calls == rb_zjit_call_threshold) {
rb_zjit_compile_iseq(iseq, true);
}
}
#endif

#if USE_YJIT
// Increment the ISEQ's call counter and trigger JIT compilation if not compiled
if (body->jit_exception == NULL && rb_yjit_enabled_p) {
body->jit_exception_calls++;
if (body->jit_exception_calls == rb_yjit_call_threshold) {
Expand Down
2 changes: 1 addition & 1 deletion yjit.c
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit
else {
iseq->body->jit_entry = (rb_jit_func_t)code_ptr;
}
}
}
}

// GC root for interacting with the GC
Expand Down
16 changes: 10 additions & 6 deletions zjit.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,18 +159,22 @@ rb_zjit_reserve_addr_space(uint32_t mem_size)
void rb_zjit_profile_disable(const rb_iseq_t *iseq);

void
rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception)
rb_zjit_compile_iseq(const rb_iseq_t *iseq, bool jit_exception)
{
RB_VM_LOCKING() {
rb_vm_barrier();

// Compile a block version starting at the current instruction
uint8_t *rb_zjit_iseq_gen_entry_point(const rb_iseq_t *iseq, rb_execution_context_t *ec); // defined in Rust
uintptr_t code_ptr = (uintptr_t)rb_zjit_iseq_gen_entry_point(iseq, ec);
uint8_t *rb_zjit_iseq_gen_entry_point(const rb_iseq_t *iseq, bool jit_exception); // defined in Rust
uintptr_t code_ptr = (uintptr_t)rb_zjit_iseq_gen_entry_point(iseq, jit_exception);

// TODO: support jit_exception
iseq->body->jit_entry = (rb_jit_func_t)code_ptr;
}
if (jit_exception) {
iseq->body->jit_exception = (rb_jit_func_t)code_ptr;
}
else {
iseq->body->jit_entry = (rb_jit_func_t)code_ptr;
}
}
}

extern VALUE *rb_vm_base_ptr(struct rb_control_frame_struct *cfp);
Expand Down
4 changes: 2 additions & 2 deletions zjit.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
extern bool rb_zjit_enabled_p;
extern uint64_t rb_zjit_call_threshold;
extern uint64_t rb_zjit_profile_threshold;
void rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception);
void rb_zjit_compile_iseq(const rb_iseq_t *iseq, bool jit_exception);
void rb_zjit_profile_insn(uint32_t insn, rb_execution_context_t *ec);
void rb_zjit_profile_enable(const rb_iseq_t *iseq);
void rb_zjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop);
Expand All @@ -26,7 +26,7 @@ void rb_zjit_before_ractor_spawn(void);
void rb_zjit_tracing_invalidate_all(void);
#else
#define rb_zjit_enabled_p false
static inline void rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception) {}
static inline void rb_zjit_compile_iseq(const rb_iseq_t *iseq, bool jit_exception) {}
static inline void rb_zjit_profile_insn(uint32_t insn, rb_execution_context_t *ec) {}
static inline void rb_zjit_profile_enable(const rb_iseq_t *iseq) {}
static inline void rb_zjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop) {}
Expand Down
2 changes: 1 addition & 1 deletion zjit/src/asm/arm64/inst/branch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ mod tests {
#[test]
fn test_ret() {
let result: u32 = Branch::ret(30).into();
assert_eq!(0xd65f03C0, result);
assert_eq!(0xd65f03c0, result);
}

#[test]
Expand Down
2 changes: 2 additions & 0 deletions zjit/src/asm/arm64/inst/load_literal.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::identity_op)]

use super::super::arg::{InstructionOffset, truncate_imm};

/// The size of the operands being operated on.
Expand Down
4 changes: 2 additions & 2 deletions zjit/src/asm/arm64/inst/mov.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,14 @@ mod tests {
fn test_movk_shifted_16() {
let inst = Mov::movk(0, 123, 16, 64);
let result: u32 = inst.into();
assert_eq!(0xf2A00f60, result);
assert_eq!(0xf2a00f60, result);
}

#[test]
fn test_movk_shifted_32() {
let inst = Mov::movk(0, 123, 32, 64);
let result: u32 = inst.into();
assert_eq!(0xf2C00f60, result);
assert_eq!(0xf2c00f60, result);
}

#[test]
Expand Down
6 changes: 5 additions & 1 deletion zjit/src/asm/arm64/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#![allow(dead_code)] // For instructions and operands we're not currently using.
#![allow(clippy::upper_case_acronyms)]
#![allow(clippy::identity_op)]
#![allow(clippy::self_named_constructors)]
#![allow(clippy::unusual_byte_groupings)]

use crate::asm::CodeBlock;

Expand Down Expand Up @@ -1590,7 +1594,7 @@ mod tests {

#[test]
fn test_nop() {
check_bytes("1f2003d5", |cb| nop(cb));
check_bytes("1f2003d5", nop);
}

#[test]
Expand Down
5 changes: 1 addition & 4 deletions zjit/src/asm/arm64/opnd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,7 @@ impl A64Opnd {

/// Convenience function to check if this operand is a register.
pub fn is_reg(&self) -> bool {
match self {
A64Opnd::Reg(_) => true,
_ => false
}
matches!(self, A64Opnd::Reg(_))
}

/// Unwrap a register from an operand.
Expand Down
2 changes: 2 additions & 0 deletions zjit/src/asm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Model for creating generating textual assembler code.

use std::collections::BTreeMap;
use std::fmt;
use std::ops::Range;
Expand Down
9 changes: 3 additions & 6 deletions zjit/src/asm/x86_64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,7 @@ impl X86Opnd {
}

pub fn is_some(&self) -> bool {
match self {
X86Opnd::None => false,
_ => true
}
!matches!(self, X86Opnd::None)
}

}
Expand Down Expand Up @@ -284,11 +281,11 @@ pub fn mem_opnd(num_bits: u8, base_reg: X86Opnd, disp: i32) -> X86Opnd
} else {
X86Opnd::Mem(
X86Mem {
num_bits: num_bits,
num_bits,
base_reg_no: base_reg.reg_no,
idx_reg_no: None,
scale_exp: 0,
disp: disp,
disp,
}
)
}
Expand Down
6 changes: 3 additions & 3 deletions zjit/src/asm/x86_64/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn test_add() {
fn test_add_unsigned() {
// ADD r/m8, imm8
check_bytes("4180c001", |cb| add(cb, R8B, uimm_opnd(1)));
check_bytes("4180c07f", |cb| add(cb, R8B, imm_opnd(i8::MAX.try_into().unwrap())));
check_bytes("4180c07f", |cb| add(cb, R8B, imm_opnd(i8::MAX.into())));

// ADD r/m16, imm16
check_bytes("664183c001", |cb| add(cb, R8W, uimm_opnd(1)));
Expand Down Expand Up @@ -102,7 +102,7 @@ fn test_cmp() {

#[test]
fn test_cqo() {
check_bytes("4899", |cb| cqo(cb));
check_bytes("4899", cqo);
}

#[test]
Expand Down Expand Up @@ -341,7 +341,7 @@ fn test_push() {

#[test]
fn test_ret() {
check_bytes("c3", |cb| ret(cb));
check_bytes("c3", ret);
}

#[test]
Expand Down
25 changes: 11 additions & 14 deletions zjit/src/backend/arm64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ fn emit_load_value(cb: &mut CodeBlock, rd: A64Opnd, value: u64) -> usize {
/// List of registers that can be used for register allocation.
/// This has the same number of registers for x86_64 and arm64.
/// SCRATCH0 and SCRATCH1 are excluded.
pub const ALLOC_REGS: &'static [Reg] = &[
pub const ALLOC_REGS: &[Reg] = &[
X0_REG,
X1_REG,
X2_REG,
Expand Down Expand Up @@ -386,15 +386,12 @@ impl Assembler
let mut opnd_iter = insn.opnd_iter_mut();

while let Some(opnd) = opnd_iter.next() {
match opnd {
Opnd::Value(value) => {
if value.special_const_p() {
*opnd = Opnd::UImm(value.as_u64());
} else if !is_load {
*opnd = asm.load(*opnd);
}
},
_ => {}
if let Opnd::Value(value) = opnd {
if value.special_const_p() {
*opnd = Opnd::UImm(value.as_u64());
} else if !is_load {
*opnd = asm.load(*opnd);
}
};
}

Expand Down Expand Up @@ -481,7 +478,7 @@ impl Assembler
// which is both the return value and first argument register
if !opnds.is_empty() {
let mut args: Vec<(Reg, Opnd)> = vec![];
for (idx, opnd) in opnds.into_iter().enumerate().rev() {
for (idx, opnd) in opnds.iter_mut().enumerate().rev() {
// If the value that we're sending is 0, then we can use
// the zero register, so in this case we'll just send
// a UImm of 0 along as the argument to the move.
Expand Down Expand Up @@ -1411,7 +1408,7 @@ impl Assembler
///
/// If a, b, and c are all registers.
fn merge_three_reg_mov(
live_ranges: &Vec<LiveRange>,
live_ranges: &[LiveRange],
iterator: &mut std::iter::Peekable<impl Iterator<Item = (usize, Insn)>>,
left: &Opnd,
right: &Opnd,
Expand Down Expand Up @@ -1566,7 +1563,7 @@ mod tests {

#[test]
fn frame_setup_and_teardown() {
const THREE_REGS: &'static [Opnd] = &[Opnd::Reg(X19_REG), Opnd::Reg(X20_REG), Opnd::Reg(X21_REG)];
const THREE_REGS: &[Opnd] = &[Opnd::Reg(X19_REG), Opnd::Reg(X20_REG), Opnd::Reg(X21_REG)];
// Test 3 preserved regs (odd), odd slot_count
{
let (mut asm, mut cb) = setup_asm();
Expand Down Expand Up @@ -1607,7 +1604,7 @@ mod tests {

// Test 4 preserved regs (even), odd slot_count
{
static FOUR_REGS: &'static [Opnd] = &[Opnd::Reg(X19_REG), Opnd::Reg(X20_REG), Opnd::Reg(X21_REG), Opnd::Reg(X22_REG)];
static FOUR_REGS: &[Opnd] = &[Opnd::Reg(X19_REG), Opnd::Reg(X20_REG), Opnd::Reg(X21_REG), Opnd::Reg(X22_REG)];
let (mut asm, mut cb) = setup_asm();
asm.frame_setup(FOUR_REGS, 3);
asm.frame_teardown(FOUR_REGS);
Expand Down
Loading