Skip to main content

low_luajit/lua/
jit.rs

1use core::ops::BitOr;
2use crate::{LuaState, ffi};
3
4/// Mode flags used to toggle/flush JIT compilation.
5///
6/// This enum is used by the following functions:
7/// - [`LuaState::jit_set_mode`].
8/// - [`LuaState::jit_set_engine`].
9/// - [`LuaState::jit_set_function`].
10///
11/// Functions using `JITMode` directly usually allow passing `true`/`false` as an alternative to [`JITMode::On`]/[`JITMode::Off`].
12#[repr(i32)]
13#[derive(Debug, PartialEq, Eq)]
14pub enum JITMode {
15	Off = ffi::LUAJIT_MODE_OFF,
16	On = ffi::LUAJIT_MODE_ON,
17	Flush = ffi::LUAJIT_MODE_FLUSH,
18}
19
20impl From<bool> for JITMode {
21	/// Converts `true` into [`JITMode::On`] and `false` into [`JITMode::Off`].
22	#[inline]
23	fn from(value: bool) -> Self {
24		if value { Self::On } else { Self::Off }
25	}
26}
27
28impl BitOr<JITMode> for i32 {
29	type Output = i32;
30
31	#[inline]
32	fn bitor(self, rhs: JITMode) -> Self::Output {
33		rhs as i32 | self
34	}
35}
36
37/// JIT compiler engine handling functions.
38impl LuaState {
39	/// Generic JIT compiler engine mode controller function.
40	///
41	/// `mode` should be a `LUAJIT_MODE_*` constant (see the [`ffi`] module) or'd with a [`JITMode`] flag.
42	///
43	/// Returns `true` on success, `false` otherwise.
44	///
45	/// # Panics
46	///
47	/// Panics if `mode` uses `LUAJIT_MODE_FUNC`, `LUAJIT_MODE_ALLFUNC`, or `LUAJIT_MODE_ALLSUBFUNC` and `index` is out of bounds.
48	///
49	/// Additionally, this function will always panic if `mode` uses `LUAJIT_MODE_WRAPCFUNC`.
50	// Use `LuaState::wrap_cfunctions` instead. (TODO)
51	#[inline]
52	pub fn jit_set_mode(&self, index: i32, mode: i32) -> bool {
53		let masked_mode = mode & ffi::LUAJIT_MODE_MASK;
54		assert!(masked_mode != ffi::LUAJIT_MODE_WRAPCFUNC, "cannot set `LUAJIT_MODE_WRAPCFUNC` by calling `LuaState::jit_set_mode`");
55		assert!(
56			(masked_mode != ffi::LUAJIT_MODE_FUNC && masked_mode != ffi::LUAJIT_MODE_ALLFUNC && masked_mode != ffi::LUAJIT_MODE_ALLSUBFUNC) ||
57			self.is_index_ok(index),
58			"cannot set the JIT compilation mode of the function at index {index}, as there are only {} elements", self.get_top()
59		);
60
61		// SAFETY: self.0 is always valid and mode is not LUAJIT_MODE_WRAPCFUNC.
62		unsafe { ffi::luaJIT_setmode(self.0, index, mode) != 0 }
63	}
64
65	/// Sets the entire JIT compiler on or off or flushes the cached compiled code.
66	///
67	/// This function always returns `true` unless the version of LuaJIT being used was compiled without the JIT compiler.
68	#[inline]
69	pub fn jit_set_engine(&self, mode: impl Into<JITMode>) -> bool {
70		self.jit_set_mode(0, ffi::LUAJIT_MODE_ENGINE | mode.into())
71	}
72
73	/// Sets JIT compilation on or off, or flushes already compiled code, for the specified functions.
74	///
75	/// If `to_self` is `true`, the function at the given `index` will be affected.
76	/// If `to_subs` is `true`, the *sub-functions* of the function at the given `index` will be affected.
77	///
78	/// If `index` is `0`, the function that called the currently running [`CFunction`] will be used in the above cases.
79	///
80	/// *(This function only applies to Lua functions, as [`CFunction`]s cannot be JIT compiled.)*
81	///
82	/// This function will return `true` if at least one function was affected, `false` otherwise.
83	/// If the version of LuaJIT being used was compiled without the JIT compiler no function can be affected.
84	///
85	/// # Panics
86	///
87	/// Panics if `index` is out of bounds.
88	///
89	/// [`CFunction`]: ./type.CFunction.html
90	#[inline]
91	pub fn jit_set_function(&self, index: i32, mode: impl Into<JITMode>, to_self: bool, to_subs: bool) -> bool {
92		self.jit_set_mode(index, match (to_self, to_subs) {
93			(true, false) => ffi::LUAJIT_MODE_FUNC,
94			(true, true) => ffi::LUAJIT_MODE_ALLFUNC,
95			(false, true) => ffi::LUAJIT_MODE_ALLSUBFUNC,
96			(false, false) => return false,
97		} | mode.into())
98	}
99
100	/// Flushes the given root `trace` and all of its side traces from the cache.
101	///
102	/// The code for the trace will be retained as long as there are any other traces which link to it.
103	#[inline]
104	pub fn jit_flush_trace(&self, trace: u32) {
105		self.jit_set_mode(trace.cast_signed(), ffi::LUAJIT_MODE_TRACE | JITMode::Flush);
106	}
107}