mirror of
https://codeberg.org/1414codeforge/ubgpsuite.git
synced 2025-02-21 14:10:40 +01:00
251 lines
5.1 KiB
C
Executable File
251 lines
5.1 KiB
C
Executable File
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
|
|
/**
|
|
* \file bgp/vmintrin.h
|
|
*
|
|
* BGP VM engine operation intrinsics.
|
|
*
|
|
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
|
|
* \author Lorenzo Cogotti
|
|
*
|
|
* Utilities in this file are meant for low level VM interaction,
|
|
* usually to implement actual VM extensions.
|
|
*/
|
|
|
|
#ifndef DF_BGP_VMINTRIN_H_
|
|
#define DF_BGP_VMINTRIN_H_
|
|
|
|
#include "bgp/vm.h"
|
|
|
|
/// Get current VM program counter.
|
|
FORCE_INLINE Uint32 BGP_VMCURPC(Bgpvm *vm)
|
|
{
|
|
return vm->pc - 1; // PC always references *next* instruction
|
|
}
|
|
|
|
/// Get VM stack base pointer.
|
|
FORCE_INLINE Bgpvmval *BGP_VMSTK(Bgpvm *vm)
|
|
{
|
|
return (Bgpvmval *) ((Uint8 *) vm->heap + vm->hLowMark);
|
|
}
|
|
|
|
/// Get stack value at index `idx`, -1 is topmost value, -2 is second to topmost...
|
|
FORCE_INLINE Bgpvmval *BGP_VMSTKGET(Bgpvm *vm, Sint32 idx)
|
|
{
|
|
Bgpvmval *stk = BGP_VMSTK(vm);
|
|
|
|
return &stk[vm->si + idx];
|
|
}
|
|
|
|
/// Equivalent to `BGP_VMSTKGET()`, but returns stack content as `Sint64`.
|
|
FORCE_INLINE Sint64 BGP_VMPEEK(Bgpvm *vm, Sint32 idx)
|
|
{
|
|
return BGP_VMSTKGET(vm, idx)->val;
|
|
}
|
|
|
|
/// Equivalent to `BGP_VMSTKGET()`, but returns stack content as `void *`.
|
|
FORCE_INLINE void *BGP_VMPEEKA(Bgpvm *vm, Sint32 idx)
|
|
{
|
|
return BGP_VMSTKGET(vm, idx)->ptr;
|
|
}
|
|
|
|
/// Pop `n` values from VM stack, **assumes stack is large enough**.
|
|
FORCE_INLINE void BGP_VMPOPN(Bgpvm *vm, Uint32 n)
|
|
{
|
|
vm->si -= n;
|
|
}
|
|
|
|
/// Pop topmost stack value in VM, returning its value as `Sint64`, **assumes stack is not empty**.
|
|
FORCE_INLINE Sint64 BGP_VMPOP(Bgpvm *vm)
|
|
{
|
|
Bgpvmval *stk = BGP_VMSTK(vm);
|
|
|
|
return stk[--vm->si].val;
|
|
}
|
|
|
|
/// Like `BGP_VMPOP()`, but returns value as `void *`.
|
|
FORCE_INLINE void *BGP_VMPOPA(Bgpvm *vm)
|
|
{
|
|
Bgpvmval *stk = BGP_VMSTK(vm);
|
|
|
|
return stk[--vm->si].ptr;
|
|
}
|
|
|
|
/// Push `v` to stack, **assumes enough stack space is available**.
|
|
FORCE_INLINE void BGP_VMPUSH(Bgpvm *vm, Sint64 v)
|
|
{
|
|
Bgpvmval *stk = BGP_VMSTK(vm);
|
|
|
|
stk[vm->si++].val = v;
|
|
}
|
|
|
|
/// Like `BGP_VMPUSH()`, but pushes a pointer.
|
|
FORCE_INLINE void BGP_VMPUSHA(Bgpvm *vm, void *p)
|
|
{
|
|
Bgpvmval *stk = BGP_VMSTK(vm);
|
|
|
|
stk[vm->si++].ptr = p;
|
|
}
|
|
|
|
/// Ensure at least `n` elements may be popped from the stack.
|
|
FORCE_INLINE Boolean BGP_VMCHKSTKSIZ(Bgpvm *vm, Uint32 n)
|
|
{
|
|
if (vm->si < n) {
|
|
vm->errCode = BGPEVMUFLOW;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/// Ensure at least `n` elements may be pushed to the stack.
|
|
FORCE_INLINE Boolean BGP_VMCHKSTK(Bgpvm *vm, Uint32 n)
|
|
{
|
|
size_t siz = vm->si + n;
|
|
|
|
siz *= sizeof(Bgpvmval);
|
|
if (vm->hHighMark - vm->hLowMark < siz) {
|
|
vm->errCode = BGPEVMOFLOW;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* \brief Test whether `vm->msg` header type matches `type`.
|
|
*
|
|
* \return Pointer to message header on successful match, `NULL`
|
|
* otherwise.
|
|
*/
|
|
FORCE_INLINE Bgphdr *BGP_VMCHKMSGTYPE(Bgpvm *vm, BgpType type)
|
|
{
|
|
Bgphdr *hdr = BGP_HDR(vm->msg);
|
|
|
|
return (hdr->type == type) ? hdr : NULL;
|
|
}
|
|
|
|
Judgement Bgp_VmStoreMsgTypeMatch(Bgpvm *vm, Boolean);
|
|
|
|
void Bgp_VmStoreMatch(Bgpvm *vm);
|
|
|
|
/// Implement `LOAD`.
|
|
FORCE_INLINE void Bgp_VmDoLoad(Bgpvm *vm, Sint8 val)
|
|
{
|
|
if (!BGP_VMCHKSTK(vm, 1))
|
|
return;
|
|
|
|
BGP_VMPUSH(vm, val);
|
|
}
|
|
|
|
/// Implement `LOADU`.
|
|
FORCE_INLINE void Bgp_VmDoLoadu(Bgpvm *vm, Uint8 val)
|
|
{
|
|
if (!BGP_VMCHKSTK(vm, 1))
|
|
return;
|
|
|
|
BGP_VMPUSH(vm, val);
|
|
}
|
|
|
|
/// Implement `LOADK` of `vm->k[idx]`.
|
|
FORCE_INLINE void Bgp_VmDoLoadk(Bgpvm *vm, Uint8 idx)
|
|
{
|
|
if (idx >= vm->nk) {
|
|
vm->errCode = BGPEVMBADK;
|
|
return;
|
|
}
|
|
if (!BGP_VMCHKSTK(vm, 1))
|
|
return;
|
|
|
|
Bgpvmval *stk = BGP_VMSTK(vm);
|
|
|
|
stk[vm->si++] = vm->k[idx];
|
|
}
|
|
|
|
/// Implement `LOADN`.
|
|
FORCE_INLINE void Bgp_VmDoLoadn(Bgpvm *vm)
|
|
{
|
|
if (!BGP_VMCHKSTK(vm, 1)) {
|
|
vm->errCode = BGPEVMOFLOW;
|
|
return;
|
|
}
|
|
|
|
BGP_VMPUSHA(vm, NULL);
|
|
}
|
|
|
|
/// Break out of current `BLK`.
|
|
FORCE_INLINE void Bgp_VmDoBreak(Bgpvm *vm)
|
|
{
|
|
Bgpvmopc opc;
|
|
|
|
do
|
|
opc = BGP_VMOPC(vm->prog[vm->pc++]);
|
|
while (opc != BGP_VMOP_ENDBLK && opc != BGP_VMOP_END);
|
|
|
|
if (opc == BGP_VMOP_ENDBLK)
|
|
vm->nblk--;
|
|
}
|
|
|
|
|
|
/// Execute `CALL` of function `vm->funcs[idx]`.
|
|
FORCE_INLINE void Bgp_VmDoCall(Bgpvm *vm, Uint8 idx)
|
|
{
|
|
void (*fn)(Bgpvm *);
|
|
|
|
if (idx >= vm->nfuncs) {
|
|
vm->errCode = BGPEVMBADFN;
|
|
return;
|
|
}
|
|
|
|
fn = vm->funcs[idx];
|
|
if (fn) fn(vm);
|
|
}
|
|
|
|
/// Implement `CPASS` (Conditional `PASS` if `TRUE`).
|
|
Boolean Bgp_VmDoCpass(Bgpvm *vm);
|
|
/// Implement `CFAIL` (Conditional `FAIL` if `TRUE`).
|
|
Boolean Bgp_VmDoCfail(Bgpvm *vm);
|
|
|
|
/// Implement `TAG` instruction with argument `tag`.
|
|
FORCE_INLINE void Bgp_VmDoTag(Bgpvm *vm, Uint8 tag)
|
|
{
|
|
vm->curMatch->tag = tag;
|
|
}
|
|
|
|
/**
|
|
* \brief Implements VM `NOT` instruction.
|
|
*
|
|
* Negate stack topmost value.
|
|
*/
|
|
FORCE_INLINE void Bgp_VmDoNot(Bgpvm *vm)
|
|
{
|
|
// Expected STACK:
|
|
// -1: Any value interpreted as Sint64
|
|
|
|
if (!BGP_VMCHKSTKSIZ(vm, 1))
|
|
return;
|
|
|
|
Bgpvmval *v = BGP_VMSTKGET(vm, -1);
|
|
|
|
v->val = !v->val;
|
|
}
|
|
|
|
/// Implements `CHKT` with argument `type`.
|
|
void Bgp_VmDoChkt(Bgpvm *vm, BgpType type);
|
|
|
|
/// Implements `CHKA` with argument `code`.
|
|
void Bgp_VmDoChka(Bgpvm *vm, BgpAttrCode code);
|
|
|
|
void Bgp_VmDoExct(Bgpvm *vm, Uint8 arg);
|
|
void Bgp_VmDoSupn(Bgpvm *vm, Uint8 arg);
|
|
void Bgp_VmDoSubn(Bgpvm *vm, Uint8 arg);
|
|
void Bgp_VmDoRelt(Bgpvm *vm, Uint8 arg);
|
|
|
|
void Bgp_VmDoAsmtch(Bgpvm *vm);
|
|
void Bgp_VmDoFasmtc(Bgpvm *vm);
|
|
|
|
void Bgp_VmDoComtch(Bgpvm *vm);
|
|
void Bgp_VmDoAcomtc(Bgpvm *vm);
|
|
|
|
#endif
|