use crate::CallInfo;
use crate::LuaResult;
use crate::lua_value::Chunk;
use crate::lua_vm::LUA_HOOKCOUNT;
use crate::lua_vm::LUA_HOOKLINE;
use crate::lua_vm::LUA_HOOKRET;
use crate::lua_vm::LUA_MASKLINE;
use crate::lua_vm::LuaState;
use crate::lua_vm::call_info::call_status::CIST_TAIL;
use crate::lua_vm::{LUA_HOOKCALL, LUA_HOOKTAILCALL, LUA_MASKCALL, LUA_MASKCOUNT};
#[cold]
#[inline(never)]
pub fn hook_on_call(
lua_state: &mut LuaState,
hook_mask: u8,
call_status: u32,
chunk: &Chunk,
) -> LuaResult<()> {
if hook_mask & LUA_MASKCALL != 0 {
let event = if call_status & CIST_TAIL != 0 {
LUA_HOOKTAILCALL
} else {
LUA_HOOKCALL
};
lua_state.run_hook(event, -1, 1, chunk.param_count as i32)?;
}
if hook_mask & LUA_MASKCOUNT != 0 {
lua_state.hook_count = lua_state.base_hook_count;
}
Ok(())
}
#[cold]
#[inline(never)]
pub fn hook_on_return(
lua_state: &mut LuaState,
ci: &mut CallInfo,
pc: usize,
nres: i32,
) -> LuaResult<()> {
ci.save_pc(pc);
let base = ci.base;
let first_res = if nres > 0 {
lua_state.get_top() - nres as usize
} else {
lua_state.get_top()
};
let ftransfer = (first_res - base + 1) as i32;
lua_state.run_hook(LUA_HOOKRET, -1, ftransfer, nres)
}
#[cold]
#[inline(never)]
pub fn hook_check_instruction(
lua_state: &mut LuaState,
pc: usize,
chunk: &Chunk,
ci: &mut CallInfo,
) -> LuaResult<bool> {
let hook_mask = lua_state.hook_mask;
#[cfg(not(feature = "sandbox"))]
if hook_mask == 0 {
return Ok(false);
}
#[cfg(feature = "sandbox")]
if hook_mask == 0 && !lua_state.has_active_instruction_watch() {
return Ok(false);
}
#[cfg(feature = "sandbox")]
lua_state.check_sandbox_runtime_limits()?;
#[cfg(feature = "sandbox")]
if hook_mask == 0 {
return Ok(lua_state.has_active_instruction_watch());
}
if !lua_state.allow_hook {
return Ok(true);
}
if hook_mask & LUA_MASKCOUNT != 0 {
lua_state.hook_count -= 1;
if lua_state.hook_count == 0 {
lua_state.hook_count = lua_state.base_hook_count;
ci.save_pc(pc);
lua_state.run_hook(LUA_HOOKCOUNT, -1, 0, 0)?;
}
}
if hook_mask & LUA_MASKLINE != 0 {
let line_info = &chunk.line_info;
if !line_info.is_empty() {
let npci = pc.saturating_sub(1);
let oldpc = lua_state.oldpc as usize;
let should_fire = if oldpc >= line_info.len() {
true
} else {
npci < oldpc || {
let old_line = line_info[oldpc];
let new_line = if npci < line_info.len() {
line_info[npci]
} else {
line_info[line_info.len() - 1]
};
old_line != new_line
}
};
if should_fire {
let new_line = if npci < line_info.len() {
line_info[npci]
} else {
line_info[line_info.len() - 1]
};
ci.save_pc(pc);
lua_state.run_hook(LUA_HOOKLINE, new_line as i32, 0, 0)?;
}
lua_state.oldpc = npci as u32;
} else {
let npci = pc.saturating_sub(1);
let oldpc = lua_state.oldpc as usize;
if oldpc == usize::MAX || npci < oldpc {
ci.save_pc(pc);
lua_state.run_hook(LUA_HOOKLINE, -1, 0, 0)?;
}
lua_state.oldpc = npci as u32;
}
}
#[cfg(not(feature = "sandbox"))]
{
Ok(lua_state.hook_mask != 0)
}
#[cfg(feature = "sandbox")]
{
Ok(lua_state.has_active_instruction_watch())
}
}