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	#[allow(clippy::must_use_candidate)]
53	pub fn jit_set_mode(&self, index: i32, mode: i32) -> bool {
54		let masked_mode = mode & ffi::LUAJIT_MODE_MASK;
55		assert!(masked_mode != ffi::LUAJIT_MODE_WRAPCFUNC, "cannot set `LUAJIT_MODE_WRAPCFUNC` by calling `LuaState::jit_set_mode`");
56		assert!(
57			(masked_mode != ffi::LUAJIT_MODE_FUNC && masked_mode != ffi::LUAJIT_MODE_ALLFUNC && masked_mode != ffi::LUAJIT_MODE_ALLSUBFUNC) ||
58			self.is_index_ok(index),
59			"cannot set the JIT compilation mode of the function at index {index}, as there are only {} elements", self.get_top()
60		);
61
62		// SAFETY: self.as_ptr() is always valid and mode is not LUAJIT_MODE_WRAPCFUNC.
63		unsafe { ffi::luaJIT_setmode(self.as_ptr(), index, mode) != 0 }
64	}
65
66	/// Sets the entire JIT compiler on or off or flushes the cached compiled code.
67	///
68	/// This function always returns `true` unless the version of LuaJIT being used was compiled without the JIT compiler.
69	#[inline]
70	pub fn jit_set_engine(&self, mode: impl Into<JITMode>) -> bool {
71		self.jit_set_mode(0, ffi::LUAJIT_MODE_ENGINE | mode.into())
72	}
73
74	/// Sets JIT compilation on or off, or flushes already compiled code, for the specified functions.
75	///
76	/// If `to_self` is `true`, the function at the given `index` will be affected.
77	/// If `to_subs` is `true`, the *sub-functions* of the function at the given `index` will be affected.
78	///
79	/// If `index` is `0`, the function that called the currently running [`CFunction`] will be used in the above cases.
80	///
81	/// *(This function only applies to Lua functions, as [`CFunction`]s cannot be JIT compiled.)*
82	///
83	/// This function will return `true` if at least one function was affected, `false` otherwise.
84	/// If the version of LuaJIT being used was compiled without the JIT compiler no function can be affected.
85	///
86	/// # Panics
87	///
88	/// Panics if `index` is out of bounds.
89	///
90	/// [`CFunction`]: ./type.CFunction.html
91	#[inline]
92	pub fn jit_set_function(&self, index: i32, mode: impl Into<JITMode>, to_self: bool, to_subs: bool) -> bool {
93		self.jit_set_mode(index, match (to_self, to_subs) {
94			(true, false) => ffi::LUAJIT_MODE_FUNC,
95			(true, true) => ffi::LUAJIT_MODE_ALLFUNC,
96			(false, true) => ffi::LUAJIT_MODE_ALLSUBFUNC,
97			(false, false) => return false,
98		} | mode.into())
99	}
100
101	/// Flushes the given root `trace` and all of its side traces from the cache.
102	///
103	/// The code for the trace will be retained as long as there are any other traces which link to it.
104	#[inline]
105	pub fn jit_flush_trace(&self, trace: u32) {
106		self.jit_set_mode(trace.cast_signed(), ffi::LUAJIT_MODE_TRACE | JITMode::Flush);
107	}
108}