@ -47,6 +47,8 @@
* by any VM and is always discarded by ` Bgp_VmStoreMatch ( ) ` .
* by any VM and is always discarded by ` Bgp_VmStoreMatch ( ) ` .
*/
*/
static Bgpvmmatch discardMatch ;
static Bgpvmmatch discardMatch ;
// Used for empty programs
static const Bgpvmbytec emptyProg = BGP_VMOP_END ;
Judgement Bgp_InitVm ( Bgpvm * vm , size_t heapSiz )
Judgement Bgp_InitVm ( Bgpvm * vm , size_t heapSiz )
{
{
@ -64,6 +66,7 @@ Judgement Bgp_InitVm(Bgpvm *vm, size_t heapSiz)
vm - > heap = heap ;
vm - > heap = heap ;
vm - > hMemSiz = siz ;
vm - > hMemSiz = siz ;
vm - > hHighMark = siz ;
vm - > hHighMark = siz ;
vm - > prog = ( Bgpvmbytec * ) & emptyProg ;
return Bgp_SetErrStat ( BGPENOERR ) ;
return Bgp_SetErrStat ( BGPENOERR ) ;
}
}
@ -76,8 +79,12 @@ Judgement Bgp_VmEmit(Bgpvm *vm, Bgpvmbytec bytec)
if ( vm - > progLen + 1 > = vm - > progCap ) {
if ( vm - > progLen + 1 > = vm - > progCap ) {
// Grow the VM program segment
// Grow the VM program segment
Bgpvmbytec * oldProg = vm - > prog ;
if ( vm - > prog = = & emptyProg )
oldProg = NULL ;
size_t newSiz = vm - > progCap + BGP_VM_GROWPROGN ;
size_t newSiz = vm - > progCap + BGP_VM_GROWPROGN ;
Bgpvmbytec * newProg = ( Bgpvmbytec * ) realloc ( vm - > prog , newSiz * sizeof ( * newProg ) ) ;
Bgpvmbytec * newProg = ( Bgpvmbytec * ) realloc ( oldP rog, newSiz * sizeof ( * newProg ) ) ;
if ( ! newProg ) {
if ( ! newProg ) {
// Flag the VM as bad
// Flag the VM as bad
vm - > setupFailed = TRUE ;
vm - > setupFailed = TRUE ;
@ -157,7 +164,7 @@ Boolean Bgp_VmExec(Bgpvm *vm, Bgpmsg *msg)
}
}
// Setup initial VM state
// Setup initial VM state
Boolean result = TRUE ; // assume PASS unless CFAIL says otherwise
Boolean result = TRUE ; // assume pass unless found otherwise
vm - > pc = 0 ;
vm - > pc = 0 ;
vm - > si = 0 ;
vm - > si = 0 ;
@ -217,20 +224,29 @@ Boolean Bgp_VmExec(Bgpvm *vm, Bgpmsg *msg)
break ;
break ;
EXECUTE ( NOT ) :
EXECUTE ( NOT ) :
Bgp_VmDoNot ( vm ) ;
Bgp_VmDoNot ( vm ) ;
EXPECT ( CFAIL , ir , vm ) ;
EXPECT ( CPASS , ir , vm ) ;
break ;
break ;
EXECUTE ( CFAIL ) :
EXECUTE ( CFAIL ) :
if ( Bgp_VmDoCfail ( vm ) ) {
if ( ! Bgp_VmDoBreakPoint ( vm , /*breakIf=*/ TRUE , /*onBreak=*/ FALSE ) ) {
result = FALSE ; // immediate terminate on FAIL
result = FALSE ; // immediate failure
goto terminate ;
goto terminate ;
}
}
break ;
break ;
EXECUTE ( CPASS ) :
EXECUTE ( CPASS ) :
if ( Bgp_VmDoCpass ( vm ) )
if ( ! Bgp_VmDoBreakPoint ( vm , /*breakIf=*/ TRUE , /*onBreak=*/ TRUE ) )
goto terminate ; // immediate PASS
goto terminate ; // immediate pass
break ;
EXECUTE ( ORFAIL ) :
if ( ! Bgp_VmDoBreakPoint ( vm , /*breakIf=*/ FALSE , /*onBreak=*/ FALSE ) ) {
result = FALSE ; // immediate failure
goto terminate ;
}
break ;
EXECUTE ( ORPASS ) :
if ( ! Bgp_VmDoBreakPoint ( vm , /*breakIf=*/ FALSE , /*onBreak=*/ TRUE ) )
goto terminate ; // immediate pass
break ;
break ;
EXECUTE ( JZ ) :
EXECUTE ( JZ ) :
@ -243,9 +259,9 @@ Boolean Bgp_VmExec(Bgpvm *vm, Bgpmsg *msg)
if ( vm - > pc > vm - > progLen ) UNLIKELY
if ( vm - > pc > vm - > progLen ) UNLIKELY
vm - > errCode = BGPEVMBADJMP ; // jump target out of bounds
vm - > errCode = BGPEVMBADJMP ; // jump target out of bounds
} else
} else {
BGP_VMPOP ( vm ) ; // no jump, pop the stack and move on
BGP_VMPOP ( vm ) ; // no jump, pop the stack and move on
}
break ;
break ;
EXECUTE ( JNZ ) :
EXECUTE ( JNZ ) :
if ( ! BGP_VMCHKSTKSIZ ( vm , 1 ) ) UNLIKELY
if ( ! BGP_VMCHKSTKSIZ ( vm , 1 ) ) UNLIKELY
@ -257,9 +273,9 @@ Boolean Bgp_VmExec(Bgpvm *vm, Bgpmsg *msg)
if ( vm - > pc > vm - > progLen ) UNLIKELY
if ( vm - > pc > vm - > progLen ) UNLIKELY
vm - > errCode = BGPEVMBADJMP ; // jump target out of bounds
vm - > errCode = BGPEVMBADJMP ; // jump target out of bounds
} else
} else {
BGP_VMPOP ( vm ) ; // no jump, pop the stack and move on
BGP_VMPOP ( vm ) ; // no jump, pop the stack and move on
}
break ;
break ;
EXECUTE ( CHKT ) :
EXECUTE ( CHKT ) :
Bgp_VmDoChkt ( vm , ( BgpType ) BGP_VMOPARG ( ir ) ) ;
Bgp_VmDoChkt ( vm , ( BgpType ) BGP_VMOPARG ( ir ) ) ;
@ -282,9 +298,6 @@ Boolean Bgp_VmExec(Bgpvm *vm, Bgpmsg *msg)
EXECUTE ( ASMTCH ) :
EXECUTE ( ASMTCH ) :
Bgp_VmDoAsmtch ( vm ) ;
Bgp_VmDoAsmtch ( vm ) ;
break ;
break ;
EXECUTE ( FASMTC ) :
Bgp_VmDoFasmtc ( vm ) ;
break ;
EXECUTE ( COMTCH ) :
EXECUTE ( COMTCH ) :
Bgp_VmDoComtch ( vm ) ;
Bgp_VmDoComtch ( vm ) ;
break ;
break ;
@ -348,86 +361,43 @@ void Bgp_VmStoreMatch(Bgpvm *vm)
vm - > nmatches + + ;
vm - > nmatches + + ;
}
}
Boolean Bgp_VmDoCpass ( Bgpvm * vm )
Boolean Bgp_VmDoBreakPoint ( Bgpvm * vm ,
{
Boolean breakIf ,
/* POPS:
Boolean onBreak )
* - 1 : Last operation Boolean result ( as a Sint64 , 0 for FALSE )
*
* PUSHES :
* * On PASS result :
* - TRUE
* * Otherwise :
* - Nothing .
*
* SIDE - EFFECTS :
* - Breaks current BLK on PASS
* - Updates ` curMatch - > isPassing ` flag accordingly
*/
if ( ! BGP_VMCHKSTKSIZ ( vm , 1 ) ) UNLIKELY
return FALSE ; // error, let vm->errCode handle this
Boolean shouldTerm = FALSE ; // unless proven otherwise
// If stack top is non-zero we FAIL
if ( BGP_VMPEEK ( vm , - 1 ) ) {
// Leave TRUE on stack and break current BLK, this is a PASS
vm - > curMatch - > isPassing = TRUE ;
if ( vm - > nblk > 0 )
Bgp_VmDoBreak ( vm ) ;
else
shouldTerm = TRUE ; // no more BLK
} else {
// Pop the stack and move on, no PASS
vm - > curMatch - > isPassing = FALSE ;
BGP_VMPOP ( vm ) ;
}
// Current match information has been collected,
// discard anything up to the next relevant operation
vm - > curMatch = & discardMatch ;
return shouldTerm ;
}
Boolean Bgp_VmDoCfail ( Bgpvm * vm )
{
{
/* POPS:
/* POPS:
* - 1 : Last operation Boolean result ( as a Sint64 , 0 for FALSE )
* - 1 : Last operation Boolean result ( as a Sint64 , 0 for FALSE )
*
*
* PUSHES :
* PUSHES :
* * On FAIL result :
* * On break result :
* - FALSE
* - ` onBreak `
* * Otherwise :
* * Otherwise :
* - Nothing .
* - Nothing .
*
*
* SIDE - EFFECTS :
* SIDE - EFFECTS :
* - Breaks current BLK on FAIL
* - Breaks current BLK if condition is met
* - Updates ` curMatch - > isPassing ` flag accordingly
* - Updates ` curMatch - > isPassing ` flag accordingly
*/
*/
if ( ! BGP_VMCHKSTKSIZ ( vm , 1 ) ) UNLIKELY
if ( ! BGP_VMCHKSTKSIZ ( vm , 1 ) ) UNLIKELY
return FALS E; // error, let vm->errCode handle this
return TRUE ; // error, let vm->errCode handle this
Boolean shouldTerm = FALSE ; // unless proven otherwise
Boolean res = TRUE ; // unless we're out of blocks
// If stack top is non-zero we FAIL
Bgpvmval * v = BGP_VMSTKGET ( vm , - 1 ) ;
Bgpvmval * v = BGP_VMSTKGET ( vm , - 1 ) ;
if ( v - > val ) {
if ( ! ! ( v - > val ) = = breakIf ) {
// Push FALSE and break current BLK, this is a FAIL
// Push `onBreak` and break current BLK
vm - > curMatch - > isPassing = FALSE ;
vm - > curMatch - > isPassing = onBreak ;
v - > val = FALSE ;
v - > val = onBreak ;
if ( vm - > nblk > 0 )
if ( vm - > nblk > 0 )
Bgp_VmDoBreak ( vm ) ;
Bgp_VmDoBreak ( vm ) ;
else
else
shouldTerm = TRU E; // no more BLK
res = FALSE ; // no more BLK
} else {
} else {
// Pop the stack and move on, no FAIL
// Pop the stack and move on, no break
vm - > curMatch - > isPassing = TRUE ;
vm - > curMatch - > isPassing = ! onBreak ;
BGP_VMPOP ( vm ) ;
BGP_VMPOP ( vm ) ;
}
}
@ -435,7 +405,7 @@ Boolean Bgp_VmDoCfail(Bgpvm *vm)
// discard anything up to the next relevant operation
// discard anything up to the next relevant operation
vm - > curMatch = & discardMatch ;
vm - > curMatch = & discardMatch ;
return shouldTerm ;
return re s;
}
}
void Bgp_VmDoChkt ( Bgpvm * vm , BgpType type )
void Bgp_VmDoChkt ( Bgpvm * vm , BgpType type )
@ -813,5 +783,6 @@ void Bgp_ResetVm(Bgpvm *vm)
void Bgp_ClearVm ( Bgpvm * vm )
void Bgp_ClearVm ( Bgpvm * vm )
{
{
free ( vm - > heap ) ;
free ( vm - > heap ) ;
free ( vm - > prog ) ;
if ( vm - > prog ! = & emptyProg )
free ( vm - > prog ) ;
}
}