1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#![allow(clippy::mutex_atomic)] // Avoid clippy warning about JITS_MADE
#![allow(clippy::new_without_default)] // Avoid clippy warning about Jit::new

use std::os::raw;
use std::ptr;
use std::sync::Mutex;

use crate::bindings;
use crate::JitState;

use std::marker::PhantomData;

#[derive(Debug)]
pub struct Jit<'a>(PhantomData<&'a ()>);

lazy_static! {
    static ref JITS_MADE: Mutex<usize> = Mutex::new(0);
}

impl<'a> Jit<'a> {
    pub fn new() -> Jit<'a> {
        let mut m = JITS_MADE.lock().unwrap();

        if *m == 0 {
            unsafe {
                //TODO: figure out how to get ptr to argv[0]
                bindings::init_jit(ptr::null::<raw::c_char>());
            }
        }

        *m += 1;
        Jit(PhantomData)
    }

    // This takes &mut self instead of &self because the unsafe operations wrapped herein are
    // inherently mutating.
    pub fn new_state(&mut self) -> JitState {
        JitState {
            state: unsafe {
                bindings::jit_new_state()
            },
            phantom: PhantomData,
        }
    }

    pub fn r_num(&self) -> bindings::jit_gpr_t {
        unsafe {
            bindings::lgsys_JIT_R_NUM()
        }
    }

    pub fn v_num(&self) -> bindings::jit_gpr_t {
        unsafe {
            bindings::lgsys_JIT_V_NUM()
        }
    }

    pub fn f_num(&self) -> bindings::jit_gpr_t {
        unsafe {
            bindings::lgsys_JIT_F_NUM()
        }
    }

}

impl<'a> Drop for Jit<'a> {
    fn drop(&mut self) {
        let mut m = JITS_MADE.lock().unwrap();
        *m -= 1;

        if *m == 0 {
            unsafe {
                bindings::finish_jit();
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::Jit;
    use crate::Reg;
    use crate::types::ToFFI;

    #[test]
    fn test_jit() {
        {
            let _jit = Jit::new();
            Jit::new();
        }

        {
            let _jit = Jit::new();
            Jit::new();
        }

    }

    #[test]
    fn test_reg_num() {
        let jit = Jit::new();
        assert!(jit.r_num() >= 3);
        assert!(jit.v_num() >= 3);
        assert!(jit.f_num() >= 6);
    }

    #[test]
    fn test_to_ffi() {
        let jit = Jit::new();

        assert!(std::panic::catch_unwind(|| Reg::R(jit.r_num()).to_ffi()).is_err());
        Reg::R(jit.r_num()-1).to_ffi();
        Reg::R(0).to_ffi();

        assert!(std::panic::catch_unwind(|| Reg::V(jit.v_num()).to_ffi()).is_err());
        Reg::V(jit.v_num()-1).to_ffi();
        Reg::V(0).to_ffi();

        assert!(std::panic::catch_unwind(|| Reg::F(jit.f_num()).to_ffi()).is_err());
        Reg::F(jit.f_num()-1).to_ffi();
        Reg::F(0).to_ffi();
    }
}