2016-10-08 06:35:16 +00:00
/*
* * vmexec . cpp
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright - 2016 Randy Heit
* * All rights reserved .
* *
* * Redistribution and use in source and binary forms , with or without
* * modification , are permitted provided that the following conditions
* * are met :
* *
* * 1. Redistributions of source code must retain the above copyright
* * notice , this list of conditions and the following disclaimer .
* * 2. Redistributions in binary form must reproduce the above copyright
* * notice , this list of conditions and the following disclaimer in the
* * documentation and / or other materials provided with the distribution .
* * 3. The name of the author may not be used to endorse or promote products
* * derived from this software without specific prior written permission .
* *
* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* * IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* * INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* * NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* * DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* * THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
*/
2016-03-01 15:47:10 +00:00
# include <math.h>
2016-10-16 17:42:22 +00:00
# include <v_video.h>
# include <s_sound.h>
2016-11-17 12:10:19 +00:00
# include "dobject.h"
2016-03-01 15:47:10 +00:00
# include "xs_Float.h"
2016-11-21 12:45:33 +00:00
# include "r_state.h"
# include "textures/textures.h"
2016-03-11 14:45:47 +00:00
# include "math/cmath.h"
2016-12-31 16:59:48 +00:00
# include "stats.h"
extern cycle_t VMCycles [ 10 ] ;
extern int VMCalls [ 10 ] ;
2016-03-01 15:47:10 +00:00
2016-12-03 11:23:13 +00:00
// This must be a separate function because the VC compiler would otherwise allocate memory on the stack for every separate instance of the exception object that may get thrown.
void ThrowAbortException ( EVMAbortException reason , const char * moreinfo , . . . ) ;
// intentionally implemented in a different source file tp prevent inlining.
void ThrowVMException ( VMException * x ) ;
2016-03-01 15:47:10 +00:00
# define IMPLEMENT_VMEXEC
# if !defined(COMPGOTO) && defined(__GNUC__)
# define COMPGOTO 1
# endif
# if COMPGOTO
# define OP(x) x
2016-10-22 03:08:12 +00:00
# define NEXTOP do { pc++; unsigned op = pc->op; a = pc->a; goto *ops[op]; } while(0)
2016-03-01 15:47:10 +00:00
# else
# define OP(x) case OP_##x
2016-10-22 03:08:12 +00:00
# define NEXTOP pc++; break
2016-03-01 15:47:10 +00:00
# endif
# define luai_nummod(a,b) ((a) - floor((a) / (b))*(b))
2016-10-22 03:08:12 +00:00
# define A (pc[0].a)
# define B (pc[0].b)
# define C (pc[0].c)
# define Cs (pc[0].cs)
# define BC (pc[0].i16u)
# define BCs (pc[0].i16)
# define ABCs (pc[0].i24)
2016-03-01 15:47:10 +00:00
# define JMPOFS(x) ((x)->i24)
# define KC (konstd[C])
# define RC (reg.d[C])
# define PA (reg.a[A])
# define PB (reg.a[B])
# define ASSERTD(x) assert((unsigned)(x) < f->NumRegD)
# define ASSERTF(x) assert((unsigned)(x) < f->NumRegF)
# define ASSERTA(x) assert((unsigned)(x) < f->NumRegA)
# define ASSERTS(x) assert((unsigned)(x) < f->NumRegS)
2016-11-24 19:02:44 +00:00
# define ASSERTO(x) assert((unsigned)(x) < f->NumRegA && reg.atag[x] == ATAG_OBJECT)
2016-03-01 15:47:10 +00:00
# define ASSERTKD(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstD)
# define ASSERTKF(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstF)
# define ASSERTKA(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstA)
# define ASSERTKS(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstS)
# define CMPJMP(test) \
2016-11-02 09:52:14 +00:00
if ( ( test ) = = ( a & CMP_CHECK ) ) { \
2016-10-22 03:08:12 +00:00
assert ( pc [ 1 ] . op = = OP_JMP ) ; \
2016-11-02 09:52:14 +00:00
pc + = 1 + JMPOFS ( pc + 1 ) ; \
} else { \
pc + = 1 ; \
2016-03-01 15:47:10 +00:00
}
# define GETADDR(a,o,x) \
2016-12-03 11:23:13 +00:00
if ( a = = NULL ) { ThrowAbortException ( x , nullptr ) ; } \
2016-03-01 15:47:10 +00:00
ptr = ( VM_SBYTE * ) a + o
static const VM_UWORD ZapTable [ 16 ] =
{
0x00000000 , 0x000000FF , 0x0000FF00 , 0x0000FFFF ,
0x00FF0000 , 0x00FF00FF , 0x00FFFF00 , 0x00FFFFFF ,
0xFF000000 , 0xFF0000FF , 0xFF00FF00 , 0xFF00FFFF ,
0xFFFF0000 , 0xFFFF00FF , 0xFFFFFF00 , 0xFFFFFFFF
} ;
# ifdef NDEBUG
# define WAS_NDEBUG 1
# else
# define WAS_NDEBUG 0
# endif
# if WAS_NDEBUG
# undef NDEBUG
# endif
# undef assert
# include <assert.h>
struct VMExec_Checked
{
# include "vmexec.h"
} ;
# if WAS_NDEBUG
# define NDEBUG
# endif
# if !WAS_NDEBUG
# define NDEBUG
# endif
# undef assert
# include <assert.h>
struct VMExec_Unchecked
{
# include "vmexec.h"
} ;
# if !WAS_NDEBUG
# undef NDEBUG
# endif
# undef assert
# include <assert.h>
int ( * VMExec ) ( VMFrameStack * stack , const VMOP * pc , VMReturn * ret , int numret ) =
# ifdef NDEBUG
VMExec_Unchecked : : Exec
# else
VMExec_Checked : : Exec
# endif
;
2016-11-30 16:15:01 +00:00
// Note: If the VM is being used in multiple threads, this should be declared as thread_local.
// ZDoom doesn't need this at the moment so this is disabled.
thread_local VMFrameStack GlobalVMStack ;
2016-03-01 15:47:10 +00:00
//===========================================================================
//
// VMSelectEngine
//
// Selects the VM engine, either checked or unchecked. Default will decide
// based on the NDEBUG preprocessor definition.
//
//===========================================================================
void VMSelectEngine ( EVMEngine engine )
{
switch ( engine )
{
case VMEngine_Default :
# ifdef NDEBUG
VMExec = VMExec_Unchecked : : Exec ;
# else
# endif
VMExec = VMExec_Checked : : Exec ;
break ;
case VMEngine_Unchecked :
VMExec = VMExec_Unchecked : : Exec ;
break ;
case VMEngine_Checked :
VMExec = VMExec_Checked : : Exec ;
break ;
}
}
//===========================================================================
//
// VMFillParams
//
// Takes parameters from the parameter stack and stores them in the callee's
// registers.
//
//===========================================================================
void VMFillParams ( VMValue * params , VMFrame * callee , int numparam )
{
unsigned int regd , regf , regs , rega ;
VMScriptFunction * calleefunc = static_cast < VMScriptFunction * > ( callee - > Func ) ;
const VMRegisters calleereg ( callee ) ;
assert ( calleefunc ! = NULL & & ! calleefunc - > Native ) ;
2016-10-30 08:05:42 +00:00
assert ( numparam = = calleefunc - > NumArgs | | ( ( int ) calleefunc - > DefaultArgs . Size ( ) = = calleefunc - > NumArgs ) ) ;
2016-03-01 15:47:10 +00:00
assert ( REGT_INT = = 0 & & REGT_FLOAT = = 1 & & REGT_STRING = = 2 & & REGT_POINTER = = 3 ) ;
regd = regf = regs = rega = 0 ;
2016-10-26 23:30:34 +00:00
for ( int i = 0 ; i < calleefunc - > NumArgs ; + + i )
2016-03-01 15:47:10 +00:00
{
2016-10-26 23:30:34 +00:00
// get all actual parameters and fill the rest from the defaults.
2016-10-30 08:05:42 +00:00
VMValue & p = i < numparam ? params [ i ] : calleefunc - > DefaultArgs [ i ] ;
2016-03-01 15:47:10 +00:00
if ( p . Type < REGT_STRING )
{
if ( p . Type = = REGT_INT )
{
calleereg . d [ regd + + ] = p . i ;
}
else // p.Type == REGT_FLOAT
{
calleereg . f [ regf + + ] = p . f ;
}
}
else if ( p . Type = = REGT_STRING )
{
calleereg . s [ regs + + ] = p . s ( ) ;
}
else
{
assert ( p . Type = = REGT_POINTER ) ;
calleereg . a [ rega ] = p . a ;
calleereg . atag [ rega + + ] = p . atag ;
}
}
}
2016-12-02 11:06:49 +00:00
2016-12-02 16:36:29 +00:00