mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-16 09:11:17 +00:00
- Use a union, rather than pointer aliasing, to access the parts of a VM instruction.
SVN r1922 (scripting)
This commit is contained in:
parent
c424c61ffc
commit
e5ef25591d
10 changed files with 171 additions and 154 deletions
|
@ -98,11 +98,11 @@ __declspec(allocate(".yreg$a")) void *const YRegHead = 0;
|
|||
// (There are linker scripts, but that apparently involves extracting the
|
||||
// default script from ld and then modifying it.)
|
||||
|
||||
void *ARegHead const __attribute__((section(SECTION_AREG))) = 0;
|
||||
void *CRegHead const __attribute__((section(SECTION_CREG))) = 0;
|
||||
void *GRegHead const __attribute__((section(SECTION_GREG))) = 0;
|
||||
void *MRegHead const __attribute__((section(SECTION_MREG))) = 0;
|
||||
void *YRegHead const __attribute__((section(SECTION_YREG))) = 0;
|
||||
void *const ARegHead __attribute__((section(SECTION_AREG))) = 0;
|
||||
void *const CRegHead __attribute__((section(SECTION_CREG))) = 0;
|
||||
void *const GRegHead __attribute__((section(SECTION_GREG))) = 0;
|
||||
void *const MRegHead __attribute__((section(SECTION_MREG))) = 0;
|
||||
void *const YRegHead __attribute__((section(SECTION_YREG))) = 0;
|
||||
|
||||
#else
|
||||
|
||||
|
|
|
@ -94,11 +94,11 @@ void FState::SetAction(PSymbolActionFunction *func, bool setdefaultparams)
|
|||
|
||||
// Create a function for this state.
|
||||
VMScriptFunction *vmfunc = new VMScriptFunction;
|
||||
VM_UBYTE *code = vmfunc->AllocCode(sizeof(codetemplate)/VM_OPSIZE);
|
||||
VMOP *code = vmfunc->AllocCode(sizeof(codetemplate)/sizeof(VMOP));
|
||||
memcpy(code, codetemplate, sizeof(codetemplate));
|
||||
FVoidObj *konsta = vmfunc->AllocKonstA(2);
|
||||
VM_ATAG *atag = vmfunc->KonstATags();
|
||||
konsta[0].v = func->Function;
|
||||
konsta[0].v = (void *)func->Function;
|
||||
konsta[1].o = callfunc;
|
||||
atag[0] = ATAG_GENERIC;
|
||||
atag[1] = ATAG_OBJECT;
|
||||
|
|
|
@ -316,7 +316,7 @@ static void FinishThingdef()
|
|||
func->NumRegD, func->NumRegF, func->NumRegA, func->NumRegS, func->MaxParam);
|
||||
VMDumpConstants(dump, func);
|
||||
fprintf(dump, "\nDisassembly:\n");
|
||||
VMDisasm(dump, func->Code, func->NumCodeBytes / 4, func);
|
||||
VMDisasm(dump, func->Code, func->CodeSize, func);
|
||||
#endif
|
||||
//if(i==6) I_Error("Poop");
|
||||
}
|
||||
|
|
|
@ -17,7 +17,41 @@ typedef signed int VM_SWORD;
|
|||
typedef VM_UBYTE VM_ATAG;
|
||||
|
||||
#define VM_EPSILON (1/1024.0)
|
||||
#define VM_OPSIZE 4 // Number of bytes used by one opcode
|
||||
|
||||
union VMOP
|
||||
{
|
||||
struct
|
||||
{
|
||||
VM_UBYTE op, a, b, c;
|
||||
};
|
||||
struct
|
||||
{
|
||||
VM_SBYTE pad0, as, bs, cs;
|
||||
};
|
||||
struct
|
||||
{
|
||||
VM_SWORD pad1:8, i24:24;
|
||||
};
|
||||
struct
|
||||
{
|
||||
VM_SWORD pad2:16, i16:16;
|
||||
};
|
||||
struct
|
||||
{
|
||||
VM_UHALF pad3, i16u;
|
||||
};
|
||||
VM_UWORD word;
|
||||
|
||||
// Interesting fact: VC++ produces better code for i16 when it's defined
|
||||
// as a bitfield than when it's defined as two discrete units.
|
||||
// Compare:
|
||||
// mov eax,dword ptr [op] ; As two discrete units
|
||||
// shr eax,10h
|
||||
// movsx eax,ax
|
||||
// versus:
|
||||
// mov eax,dword ptr [op] ; As a bitfield
|
||||
// sar eax,10h
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -685,7 +719,7 @@ public:
|
|||
VMScriptFunction();
|
||||
~VMScriptFunction();
|
||||
size_t PropagateMark();
|
||||
VM_UBYTE *AllocCode(int numops);
|
||||
VMOP *AllocCode(int numops);
|
||||
int *AllocKonstD(int numkonst);
|
||||
double *AllocKonstF(int numkonst);
|
||||
FString *AllocKonstS(int numkonst);
|
||||
|
@ -694,13 +728,13 @@ public:
|
|||
VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); }
|
||||
const VM_ATAG *KonstATags() const { return (VM_UBYTE *)(KonstA + NumKonstA); }
|
||||
|
||||
VM_UBYTE *Code;
|
||||
VMOP *Code;
|
||||
int *KonstD;
|
||||
double *KonstF;
|
||||
FString *KonstS;
|
||||
FVoidObj *KonstA;
|
||||
int ExtraSpace;
|
||||
int NumCodeBytes;
|
||||
int CodeSize; // Size of code in instructions (not bytes)
|
||||
VM_UBYTE NumRegD;
|
||||
VM_UBYTE NumRegF;
|
||||
VM_UBYTE NumRegS;
|
||||
|
@ -809,10 +843,10 @@ enum EVMEngine
|
|||
};
|
||||
|
||||
void VMSelectEngine(EVMEngine engine);
|
||||
extern int (*VMExec)(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numret);
|
||||
extern int (*VMExec)(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret);
|
||||
void VMFillParams(VMValue *params, VMFrame *callee, int numparam);
|
||||
|
||||
void VMDumpConstants(FILE *out, const VMScriptFunction *func);
|
||||
void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunction *func);
|
||||
void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -39,7 +39,7 @@ VMScriptFunction *VMFunctionBuilder::MakeFunction()
|
|||
VMScriptFunction *func = new VMScriptFunction;
|
||||
|
||||
// Copy code block.
|
||||
memcpy(func->AllocCode(Code.Size()), &Code[0], Code.Size());
|
||||
memcpy(func->AllocCode(Code.Size()), &Code[0], Code.Size() * sizeof(VMOP));
|
||||
|
||||
// Create constant tables.
|
||||
if (NumIntConstants > 0)
|
||||
|
@ -425,12 +425,6 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc)
|
|||
assert(opa >= 0 && opa <= 255);
|
||||
assert(opb >= 0 && opb <= 255);
|
||||
assert(opc >= 0 && opc <= 255);
|
||||
size_t loc = Code.Reserve(4);
|
||||
VM_UBYTE *code = &Code[loc];
|
||||
code[0] = opcode;
|
||||
code[1] = opa;
|
||||
code[2] = opb;
|
||||
code[3] = opc;
|
||||
if (opcode == OP_PARAM)
|
||||
{
|
||||
ParamChange(1);
|
||||
|
@ -439,7 +433,12 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc)
|
|||
{
|
||||
ParamChange(-opb);
|
||||
}
|
||||
return loc / 4;
|
||||
VMOP op;
|
||||
op.op = opcode;
|
||||
op.a = opa;
|
||||
op.b = opb;
|
||||
op.c = opc;
|
||||
return Code.Push(op);
|
||||
}
|
||||
|
||||
size_t VMFunctionBuilder::Emit(int opcode, int opa, VM_SHALF opbc)
|
||||
|
@ -447,29 +446,25 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, VM_SHALF opbc)
|
|||
assert(opcode >= 0 && opcode < NUM_OPS);
|
||||
assert(opa >= 0 && opa <= 255);
|
||||
assert(opbc >= -32768 && opbc <= 32767);
|
||||
size_t loc = Code.Reserve(4);
|
||||
VM_UBYTE *code = &Code[loc];
|
||||
code[0] = opcode;
|
||||
code[1] = opa;
|
||||
*(VM_SHALF *)&code[2] = opbc;
|
||||
return loc / 4;
|
||||
VMOP op;
|
||||
op.op = opcode;
|
||||
op.a = opa;
|
||||
op.i16 = opbc;
|
||||
return Code.Push(op);
|
||||
}
|
||||
|
||||
size_t VMFunctionBuilder::Emit(int opcode, int opabc)
|
||||
{
|
||||
assert(opcode >= 0 && opcode < NUM_OPS);
|
||||
assert(opabc >= -(1 << 23) && opabc <= (1 << 24) - 1);
|
||||
size_t loc = Code.Reserve(4);
|
||||
#ifdef __BIG_ENDIAN__
|
||||
*(VM_UWORD *)&Code[loc] = (opabc & 0xFFFFFF) | (opcode << 24);
|
||||
#else
|
||||
*(VM_UWORD *)&Code[loc] = opcode | (opabc << 8);
|
||||
#endif
|
||||
if (opcode == OP_PARAMI)
|
||||
{
|
||||
ParamChange(1);
|
||||
}
|
||||
return loc / 4;
|
||||
VMOP op;
|
||||
op.op = opcode;
|
||||
op.i24 = opabc;
|
||||
return Code.Push(op);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -504,14 +499,11 @@ size_t VMFunctionBuilder::EmitLoadInt(int regnum, int value)
|
|||
|
||||
void VMFunctionBuilder::Backpatch(size_t loc, size_t target)
|
||||
{
|
||||
assert(loc < Code.Size() / 4);
|
||||
assert(loc < Code.Size());
|
||||
int offset = int(target - loc - 1);
|
||||
assert(offset >= -(1 << 24) && offset <= (1 << 24) - 1);
|
||||
#ifdef __BIG_ENDIAN__
|
||||
*(VM_UWORD *)&Code[loc * 4] = (offset & 0xFFFFFF) | (OP_JMP << 24);
|
||||
#else
|
||||
*(VM_UWORD *)&Code[loc * 4] = OP_JMP | (offset << 8);
|
||||
#endif
|
||||
assert(((offset << 8) >> 8) == offset);
|
||||
Code[loc].op = OP_JMP;
|
||||
Code[loc].i24 = offset;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -525,5 +517,5 @@ void VMFunctionBuilder::Backpatch(size_t loc, size_t target)
|
|||
|
||||
void VMFunctionBuilder::BackpatchToHere(size_t loc)
|
||||
{
|
||||
Backpatch(loc, Code.Size() / 4);
|
||||
Backpatch(loc, Code.Size());
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ private:
|
|||
int MaxParam;
|
||||
int ActiveParam;
|
||||
|
||||
TArray<VM_UBYTE> Code;
|
||||
TArray<VMOP> Code;
|
||||
|
||||
// PARAM increases ActiveParam; CALL decreases it.
|
||||
void ParamChange(int delta);
|
||||
|
|
|
@ -94,14 +94,6 @@ const VMOpInfo OpInfo[NUM_OPS] =
|
|||
#include "vmops.h"
|
||||
};
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define ABCs(x) ((*(VM_SWORD *)(x) << 8) >> 8)
|
||||
#define JMPOFS(x) ((*(VM_SWORD *)(x) << 8) >> 6)
|
||||
#else
|
||||
#define ABCs(x) (*(VM_SWORD *)(x) >> 8)
|
||||
#define JMPOFS(x) ((*(VM_SWORD *)(x) >> 6) & ~3)
|
||||
#endif
|
||||
|
||||
static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const VMScriptFunction *func);
|
||||
|
||||
static int printf_wrapper(FILE *f, const char *fmt, ...)
|
||||
|
@ -179,21 +171,21 @@ void VMDumpConstants(FILE *out, const VMScriptFunction *func)
|
|||
}
|
||||
}
|
||||
|
||||
void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunction *func)
|
||||
void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func)
|
||||
{
|
||||
const char *name;
|
||||
int col;
|
||||
int mode;
|
||||
int a;
|
||||
|
||||
for (int i = 0; i < codesize; i += 4)
|
||||
for (int i = 0; i < codesize; ++i)
|
||||
{
|
||||
name = OpInfo[code[i]].Name;
|
||||
mode = OpInfo[code[i]].Mode;
|
||||
a = code[i+1];
|
||||
name = OpInfo[code[i].op].Name;
|
||||
mode = OpInfo[code[i].op].Mode;
|
||||
a = code[i].a;
|
||||
|
||||
// String comparison encodes everything in a single instruction.
|
||||
if (code[i] == OP_CMPS)
|
||||
if (code[i].op == OP_CMPS)
|
||||
{
|
||||
switch (a & CMP_METHOD_MASK)
|
||||
{
|
||||
|
@ -207,31 +199,31 @@ void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunct
|
|||
a &= CMP_CHECK | CMP_APPROX;
|
||||
}
|
||||
|
||||
printf_wrapper(out, "%08x: %02x%02x%02x%02x %-8s", i, code[i], code[i+1], code[i+2], code[i+3], name);
|
||||
printf_wrapper(out, "%08x: %02x%02x%02x%02x %-8s", i << 2, code[i].op, code[i].a, code[i].b, code[i].c, name);
|
||||
col = 0;
|
||||
switch (code[i])
|
||||
switch (code[i].op)
|
||||
{
|
||||
case OP_JMP:
|
||||
case OP_TRY:
|
||||
col = printf_wrapper(out, "%08x", i + 4 + JMPOFS(&code[i]));
|
||||
col = printf_wrapper(out, "%08x", i + 4 + (code[i].i24 << 2));
|
||||
break;
|
||||
|
||||
case OP_PARAMI:
|
||||
col = printf_wrapper(out, "%d", ABCs(&code[i]));
|
||||
col = printf_wrapper(out, "%d", code[i].i24);
|
||||
break;
|
||||
|
||||
case OP_RET:
|
||||
if (code[i+2] != REGT_NIL)
|
||||
if (code[i].b != REGT_NIL)
|
||||
{
|
||||
if ((code[i+2] & REGT_FINAL) && a == 0)
|
||||
if ((code[i].b & REGT_FINAL) && a == 0)
|
||||
{
|
||||
col = print_reg(out, 0, *(VM_UHALF *)&code[i+2], MODE_PARAM, 16, func);
|
||||
col = print_reg(out, 0, code[i].i16u, MODE_PARAM, 16, func);
|
||||
}
|
||||
else
|
||||
{
|
||||
col = print_reg(out, 0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func);
|
||||
col += print_reg(out, col, *(VM_UHALF *)&code[i+2], MODE_PARAM, 16, func);
|
||||
if (code[i+2] & REGT_FINAL)
|
||||
col += print_reg(out, col, code[i].i16u, MODE_PARAM, 16, func);
|
||||
if (code[i].b & REGT_FINAL)
|
||||
{
|
||||
col += printf_wrapper(out, " [final]");
|
||||
}
|
||||
|
@ -242,7 +234,7 @@ void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunct
|
|||
default:
|
||||
if ((mode & MODE_BCTYPE) == MODE_BCCAST)
|
||||
{
|
||||
switch (code[i+3])
|
||||
switch (code[i].c)
|
||||
{
|
||||
case CAST_I2F:
|
||||
mode = MODE_AF | MODE_BI | MODE_CUNUSED;
|
||||
|
@ -273,11 +265,11 @@ void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunct
|
|||
col = print_reg(out, 0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func);
|
||||
if ((mode & MODE_BCTYPE) == MODE_BCTHROW)
|
||||
{
|
||||
mode = (code[i+1] == 0) ? (MODE_BP | MODE_CUNUSED) : (MODE_BKP | MODE_CUNUSED);
|
||||
mode = (code[i].a == 0) ? (MODE_BP | MODE_CUNUSED) : (MODE_BKP | MODE_CUNUSED);
|
||||
}
|
||||
else if ((mode & MODE_BCTYPE) == MODE_BCCATCH)
|
||||
{
|
||||
switch (code[i+1])
|
||||
switch (code[i].a)
|
||||
{
|
||||
case 0:
|
||||
mode = MODE_BUNUSED | MODE_CUNUSED;
|
||||
|
@ -298,12 +290,12 @@ void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunct
|
|||
}
|
||||
if ((mode & (MODE_BTYPE | MODE_CTYPE)) == MODE_BCJOINT)
|
||||
{
|
||||
col += print_reg(out, col, *(VM_UHALF *)&code[i+2], (mode & MODE_BCTYPE) >> MODE_BCSHIFT, 16, func);
|
||||
col += print_reg(out, col, code[i].i16u, (mode & MODE_BCTYPE) >> MODE_BCSHIFT, 16, func);
|
||||
}
|
||||
else
|
||||
{
|
||||
col += print_reg(out, col, code[i+2], (mode & MODE_BTYPE) >> MODE_BSHIFT, 24, func);
|
||||
col += print_reg(out, col, code[i+3], (mode & MODE_CTYPE) >> MODE_CSHIFT, 24, func);
|
||||
col += print_reg(out, col, code[i].b, (mode & MODE_BTYPE) >> MODE_BSHIFT, 24, func);
|
||||
col += print_reg(out, col, code[i].c, (mode & MODE_CTYPE) >> MODE_CSHIFT, 24, func);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -312,13 +304,13 @@ void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunct
|
|||
col = 30;
|
||||
}
|
||||
printf_wrapper(out, "%*c", 30 - col, ';');
|
||||
if (code[i] == OP_JMP || code[i] == OP_TRY)
|
||||
if (code[i].op == OP_JMP || code[i].op == OP_TRY || code[i].op == OP_PARAMI)
|
||||
{
|
||||
printf_wrapper(out, "%d\n", JMPOFS(&code[i]) >> 2);
|
||||
printf_wrapper(out, "%d\n", code[i].i24);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf_wrapper(out, "%d,%d,%d\n", code[i+1], code[i+2], code[i+3]);
|
||||
printf_wrapper(out, "%d,%d,%d\n", code[i].a, code[i].b, code[i].c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -385,40 +377,46 @@ static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const
|
|||
|
||||
case MODE_PARAM:
|
||||
{
|
||||
union { VM_UHALF Together; struct { VM_UBYTE RegType, RegNum; }; } p;
|
||||
p.Together = arg;
|
||||
switch (p.RegType & (REGT_TYPE | REGT_KONST | REGT_MULTIREG))
|
||||
int regtype, regnum;
|
||||
#ifdef __BIG_ENDIAN__
|
||||
regtype = (arg >> 8) & 255;
|
||||
regnum = arg & 255;
|
||||
#else
|
||||
regtype = arg & 255;
|
||||
regnum = (arg >> 8) & 255;
|
||||
#endif
|
||||
switch (regtype & (REGT_TYPE | REGT_KONST | REGT_MULTIREG))
|
||||
{
|
||||
case REGT_INT:
|
||||
return col+printf_wrapper(out, "d%d", p.RegNum);
|
||||
return col+printf_wrapper(out, "d%d", regnum);
|
||||
case REGT_FLOAT:
|
||||
return col+printf_wrapper(out, "f%d", p.RegNum);
|
||||
return col+printf_wrapper(out, "f%d", regnum);
|
||||
case REGT_STRING:
|
||||
return col+printf_wrapper(out, "s%d", p.RegNum);
|
||||
return col+printf_wrapper(out, "s%d", regnum);
|
||||
case REGT_POINTER:
|
||||
return col+printf_wrapper(out, "a%d", p.RegNum);
|
||||
return col+printf_wrapper(out, "a%d", regnum);
|
||||
case REGT_FLOAT | REGT_MULTIREG:
|
||||
return col+printf_wrapper(out, "v%d", p.RegNum);
|
||||
return col+printf_wrapper(out, "v%d", regnum);
|
||||
case REGT_INT | REGT_KONST:
|
||||
return col+print_reg(out, 0, p.RegNum, MODE_KI, 0, func);
|
||||
return col+print_reg(out, 0, regnum, MODE_KI, 0, func);
|
||||
case REGT_FLOAT | REGT_KONST:
|
||||
return col+print_reg(out, 0, p.RegNum, MODE_KF, 0, func);
|
||||
return col+print_reg(out, 0, regnum, MODE_KF, 0, func);
|
||||
case REGT_STRING | REGT_KONST:
|
||||
return col+print_reg(out, 0, p.RegNum, MODE_KS, 0, func);
|
||||
return col+print_reg(out, 0, regnum, MODE_KS, 0, func);
|
||||
case REGT_POINTER | REGT_KONST:
|
||||
return col+print_reg(out, 0, p.RegNum, MODE_KP, 0, func);
|
||||
return col+print_reg(out, 0, regnum, MODE_KP, 0, func);
|
||||
case REGT_FLOAT | REGT_MULTIREG | REGT_KONST:
|
||||
return col+print_reg(out, 0, p.RegNum, MODE_KV, 0, func);
|
||||
return col+print_reg(out, 0, regnum, MODE_KV, 0, func);
|
||||
default:
|
||||
if (p.RegType == REGT_NIL)
|
||||
if (regtype == REGT_NIL)
|
||||
{
|
||||
return col+printf_wrapper(out, "nil");
|
||||
}
|
||||
return col+printf_wrapper(out, "param[t=%d,%c,%c,n=%d]",
|
||||
p.RegType & REGT_TYPE,
|
||||
p.RegType & REGT_KONST ? 'k' : 'r',
|
||||
p.RegType & REGT_MULTIREG ? 'm' : 's',
|
||||
p.RegNum);
|
||||
regtype & REGT_TYPE,
|
||||
regtype & REGT_KONST ? 'k' : 'r',
|
||||
regtype & REGT_MULTIREG ? 'm' : 's',
|
||||
regnum);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#if COMPGOTO
|
||||
#define OP(x) x
|
||||
#define NEXTOP do { unsigned op = *pc; a = pc[1]; pc += 4; goto *ops[op]; } while(0)
|
||||
#define NEXTOP do { unsigned op = pc->op; a = pc->a; pc++; goto *ops[op]; } while(0)
|
||||
#else
|
||||
#define OP(x) case OP_##x
|
||||
#define NEXTOP break
|
||||
|
@ -17,20 +17,14 @@
|
|||
|
||||
#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b))
|
||||
|
||||
#define A (*(pc - 3))
|
||||
#define B (*(pc - 2))
|
||||
#define C ( *(pc - 1))
|
||||
#define Cs (*(VM_SBYTE *)(pc - 1))
|
||||
#define BC (*(VM_UHALF *)(pc - 2))
|
||||
#define BCs (*(VM_SHALF *)(pc - 2))
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define ABCs ((*(VM_SWORD *)(pc - 4) << 8) >> 8)
|
||||
#define JMPOFS(x) ((*(VM_SWORD *)(x) << 8) >> 6)
|
||||
#else
|
||||
#define ABCs (*(VM_SWORD *)(pc - 4) >> 8)
|
||||
#define JMPOFS(x) ((*(VM_SWORD *)(x) >> 6) & ~3)
|
||||
#endif
|
||||
#define A (pc[-1].a)
|
||||
#define B (pc[-1].b)
|
||||
#define C (pc[-1].c)
|
||||
#define Cs (pc[-1].cs)
|
||||
#define BC (pc[-1].i16u)
|
||||
#define BCs (pc[-1].i16)
|
||||
#define ABCs (pc[-1].i24)
|
||||
#define JMPOFS(x) ((x)->i24)
|
||||
|
||||
#define KC (konstd[C])
|
||||
#define RC (reg.d[C])
|
||||
|
@ -52,10 +46,10 @@
|
|||
|
||||
#define CMPJMP(test) \
|
||||
if ((test) == (a & CMP_CHECK)) { \
|
||||
assert(*pc == OP_JMP); \
|
||||
pc += 4 + JMPOFS(pc); \
|
||||
assert(pc->op == OP_JMP); \
|
||||
pc += 1 + JMPOFS(pc); \
|
||||
} else { \
|
||||
pc += 4; \
|
||||
pc += 1; \
|
||||
}
|
||||
|
||||
enum
|
||||
|
@ -112,7 +106,7 @@ struct VMExec_Unchecked
|
|||
#undef assert
|
||||
#include <assert.h>
|
||||
|
||||
int (*VMExec)(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numret) =
|
||||
int (*VMExec)(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret) =
|
||||
#ifdef NDEBUG
|
||||
VMExec_Unchecked::Exec
|
||||
#else
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#endif
|
||||
|
||||
|
||||
static int Exec(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numret)
|
||||
static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret)
|
||||
{
|
||||
#if COMPGOTO
|
||||
static const void * const ops[256] =
|
||||
|
@ -12,7 +12,7 @@ static int Exec(VMFrameStack *stack, const VM_UBYTE *pc, VMReturn *ret, int numr
|
|||
#include "vmops.h"
|
||||
};
|
||||
#endif
|
||||
const VM_UBYTE *exception_frames[MAX_TRY_DEPTH];
|
||||
const VMOP *exception_frames[MAX_TRY_DEPTH];
|
||||
int try_depth = 0;
|
||||
VMFrame *f = stack->TopFrame();
|
||||
VMScriptFunction *sfunc;
|
||||
|
@ -52,7 +52,7 @@ begin:
|
|||
{
|
||||
#if !COMPGOTO
|
||||
VM_UBYTE op;
|
||||
for(;;) switch(op = pc[0], a = pc[1], pc += 4, op)
|
||||
for(;;) switch(op = pc->op, a = pc->a, pc++, op)
|
||||
#else
|
||||
NEXTOP;
|
||||
#endif
|
||||
|
@ -383,17 +383,17 @@ begin:
|
|||
ASSERTD(a);
|
||||
if (reg.d[a] != BC)
|
||||
{
|
||||
pc += 4;
|
||||
pc++;
|
||||
}
|
||||
NEXTOP;
|
||||
OP(JMP):
|
||||
pc += JMPOFS(pc - 4);
|
||||
pc += JMPOFS(pc - 1);
|
||||
NEXTOP;
|
||||
OP(IJMP):
|
||||
ASSERTD(a);
|
||||
pc += (BCs + reg.d[a]) << 2;
|
||||
assert(*pc == OP_JMP);
|
||||
pc += (1 + *((VM_SHALF *)pc + 1)) << 2;
|
||||
pc += (BCs + reg.d[a]);
|
||||
assert(pc->op == OP_JMP);
|
||||
pc += 1 + JMPOFS(pc);
|
||||
NEXTOP;
|
||||
OP(PARAMI):
|
||||
assert(f->NumParam < sfunc->MaxParam);
|
||||
|
@ -536,7 +536,7 @@ begin:
|
|||
{
|
||||
reg.param[--f->NumParam].~VMValue();
|
||||
}
|
||||
pc += C * 4; // Skip RESULTs
|
||||
pc += C; // Skip RESULTs
|
||||
}
|
||||
NEXTOP;
|
||||
OP(RET):
|
||||
|
@ -567,8 +567,8 @@ begin:
|
|||
{
|
||||
THROW(X_TOO_MANY_TRIES);
|
||||
}
|
||||
assert(*(pc + JMPOFS(pc - 4)) == OP_CATCH);
|
||||
exception_frames[try_depth++] = pc + JMPOFS(pc - 4);
|
||||
assert((pc + JMPOFS(pc - 1))->op == OP_CATCH);
|
||||
exception_frames[try_depth++] = pc + JMPOFS(pc - 1);
|
||||
NEXTOP;
|
||||
OP(UNTRY):
|
||||
assert(a <= try_depth);
|
||||
|
@ -664,12 +664,12 @@ begin:
|
|||
}
|
||||
if (cmp == (a & CMP_CHECK))
|
||||
{
|
||||
assert(*pc == OP_JMP);
|
||||
pc += 4 + JMPOFS(pc);
|
||||
assert(pc->op == OP_JMP);
|
||||
pc += 1 + JMPOFS(pc);
|
||||
}
|
||||
else
|
||||
{
|
||||
pc += 4;
|
||||
pc += 1;
|
||||
}
|
||||
}
|
||||
NEXTOP;
|
||||
|
@ -1255,48 +1255,48 @@ begin:
|
|||
while(--try_depth >= 0)
|
||||
{
|
||||
pc = exception_frames[try_depth];
|
||||
assert(pc[0] == OP_CATCH);
|
||||
while (pc[1] > 1)
|
||||
assert(pc->op == OP_CATCH);
|
||||
while (pc->a > 1)
|
||||
{
|
||||
// CATCH must be followed by JMP if it doesn't terminate a catch chain.
|
||||
assert(pc[4] == OP_JMP);
|
||||
assert(pc[1].op == OP_JMP);
|
||||
|
||||
PClass *type;
|
||||
int b = pc[2];
|
||||
int b = pc->b;
|
||||
|
||||
if (pc[1] == 2)
|
||||
if (pc->a == 2)
|
||||
{
|
||||
ASSERTA(b);
|
||||
type = (PClass *)reg.a[b];
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(pc[1] == 3);
|
||||
assert(pc->a == 3);
|
||||
ASSERTKA(b);
|
||||
assert(konstatag[b] == ATAG_OBJECT);
|
||||
type = (PClass *)konsta[b].o;
|
||||
}
|
||||
ASSERTA(pc[3]);
|
||||
ASSERTA(pc->c);
|
||||
if (type == extype)
|
||||
{
|
||||
// Found a handler. Store the exception in pC, skip the JMP,
|
||||
// and begin executing its code.
|
||||
reg.a[pc[3]] = exception;
|
||||
reg.atag[pc[3]] = ATAG_OBJECT;
|
||||
pc += 8;
|
||||
reg.a[pc->c] = exception;
|
||||
reg.atag[pc->c] = ATAG_OBJECT;
|
||||
pc += 2;
|
||||
goto begin;
|
||||
}
|
||||
// This catch didn't handle it. Try the next one.
|
||||
pc += 4 + JMPOFS(pc + 4);
|
||||
assert(pc[0] == OP_CATCH);
|
||||
pc += 1 + JMPOFS(pc + 1);
|
||||
assert(pc->op == OP_CATCH);
|
||||
}
|
||||
if (pc[1] == 1)
|
||||
if (pc->a == 1)
|
||||
{
|
||||
// Catch any type of VMException. This terminates the chain.
|
||||
ASSERTA(pc[3]);
|
||||
reg.a[pc[3]] = exception;
|
||||
reg.atag[pc[3]] = ATAG_OBJECT;
|
||||
pc += 4;
|
||||
ASSERTA(pc->c);
|
||||
reg.a[pc->c] = exception;
|
||||
reg.atag[pc->c] = ATAG_OBJECT;
|
||||
pc += 1;
|
||||
goto begin;
|
||||
}
|
||||
// This frame failed. Try the next one out.
|
||||
|
@ -1382,18 +1382,18 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
static void FillReturns(const VMRegisters ®, VMFrame *frame, VMReturn *returns, const VM_UBYTE *retval, int numret)
|
||||
static void FillReturns(const VMRegisters ®, VMFrame *frame, VMReturn *returns, const VMOP *retval, int numret)
|
||||
{
|
||||
int i, type, num;
|
||||
VMReturn *ret;
|
||||
|
||||
assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3);
|
||||
|
||||
for (i = 0, ret = returns; i < numret; ++i, ++ret, retval += 4)
|
||||
for (i = 0, ret = returns; i < numret; ++i, ++ret, ++retval)
|
||||
{
|
||||
assert(retval[0] == OP_RESULT); // opcode
|
||||
ret->RegType = type = retval[2];
|
||||
ret->RegNum = num = retval[3];
|
||||
assert(retval->op == OP_RESULT); // opcode
|
||||
ret->RegType = type = retval->b;
|
||||
ret->RegNum = num = retval->c;
|
||||
assert(!(type & REGT_KONST));
|
||||
type &= REGT_TYPE;
|
||||
if (type < REGT_STRING)
|
||||
|
|
|
@ -15,7 +15,7 @@ VMScriptFunction::VMScriptFunction()
|
|||
KonstS = NULL;
|
||||
KonstA = NULL;
|
||||
ExtraSpace = 0;
|
||||
NumCodeBytes = 0;
|
||||
CodeSize = 0;
|
||||
NumRegD = 0;
|
||||
NumRegF = 0;
|
||||
NumRegS = 0;
|
||||
|
@ -37,12 +37,11 @@ VMScriptFunction::~VMScriptFunction()
|
|||
if (KonstA != NULL) M_Free(KonstA);
|
||||
}
|
||||
|
||||
VM_UBYTE *VMScriptFunction::AllocCode(int numops)
|
||||
VMOP *VMScriptFunction::AllocCode(int numops)
|
||||
{
|
||||
assert(Code == NULL && numops > 0);
|
||||
numops *= VM_OPSIZE;
|
||||
NumCodeBytes = numops;
|
||||
return Code = (VM_UBYTE *)M_Malloc(numops);
|
||||
CodeSize = numops;
|
||||
return Code = (VMOP *)M_Malloc(numops * sizeof(VMOP));
|
||||
}
|
||||
|
||||
int *VMScriptFunction::AllocKonstD(int numkonst)
|
||||
|
|
Loading…
Reference in a new issue