mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-14 08:31:23 +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
|
// (There are linker scripts, but that apparently involves extracting the
|
||||||
// default script from ld and then modifying it.)
|
// default script from ld and then modifying it.)
|
||||||
|
|
||||||
void *ARegHead const __attribute__((section(SECTION_AREG))) = 0;
|
void *const ARegHead __attribute__((section(SECTION_AREG))) = 0;
|
||||||
void *CRegHead const __attribute__((section(SECTION_CREG))) = 0;
|
void *const CRegHead __attribute__((section(SECTION_CREG))) = 0;
|
||||||
void *GRegHead const __attribute__((section(SECTION_GREG))) = 0;
|
void *const GRegHead __attribute__((section(SECTION_GREG))) = 0;
|
||||||
void *MRegHead const __attribute__((section(SECTION_MREG))) = 0;
|
void *const MRegHead __attribute__((section(SECTION_MREG))) = 0;
|
||||||
void *YRegHead const __attribute__((section(SECTION_YREG))) = 0;
|
void *const YRegHead __attribute__((section(SECTION_YREG))) = 0;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
|
@ -94,11 +94,11 @@ void FState::SetAction(PSymbolActionFunction *func, bool setdefaultparams)
|
||||||
|
|
||||||
// Create a function for this state.
|
// Create a function for this state.
|
||||||
VMScriptFunction *vmfunc = new VMScriptFunction;
|
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));
|
memcpy(code, codetemplate, sizeof(codetemplate));
|
||||||
FVoidObj *konsta = vmfunc->AllocKonstA(2);
|
FVoidObj *konsta = vmfunc->AllocKonstA(2);
|
||||||
VM_ATAG *atag = vmfunc->KonstATags();
|
VM_ATAG *atag = vmfunc->KonstATags();
|
||||||
konsta[0].v = func->Function;
|
konsta[0].v = (void *)func->Function;
|
||||||
konsta[1].o = callfunc;
|
konsta[1].o = callfunc;
|
||||||
atag[0] = ATAG_GENERIC;
|
atag[0] = ATAG_GENERIC;
|
||||||
atag[1] = ATAG_OBJECT;
|
atag[1] = ATAG_OBJECT;
|
||||||
|
|
|
@ -316,7 +316,7 @@ static void FinishThingdef()
|
||||||
func->NumRegD, func->NumRegF, func->NumRegA, func->NumRegS, func->MaxParam);
|
func->NumRegD, func->NumRegF, func->NumRegA, func->NumRegS, func->MaxParam);
|
||||||
VMDumpConstants(dump, func);
|
VMDumpConstants(dump, func);
|
||||||
fprintf(dump, "\nDisassembly:\n");
|
fprintf(dump, "\nDisassembly:\n");
|
||||||
VMDisasm(dump, func->Code, func->NumCodeBytes / 4, func);
|
VMDisasm(dump, func->Code, func->CodeSize, func);
|
||||||
#endif
|
#endif
|
||||||
//if(i==6) I_Error("Poop");
|
//if(i==6) I_Error("Poop");
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,41 @@ typedef signed int VM_SWORD;
|
||||||
typedef VM_UBYTE VM_ATAG;
|
typedef VM_UBYTE VM_ATAG;
|
||||||
|
|
||||||
#define VM_EPSILON (1/1024.0)
|
#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
|
enum
|
||||||
{
|
{
|
||||||
|
@ -685,7 +719,7 @@ public:
|
||||||
VMScriptFunction();
|
VMScriptFunction();
|
||||||
~VMScriptFunction();
|
~VMScriptFunction();
|
||||||
size_t PropagateMark();
|
size_t PropagateMark();
|
||||||
VM_UBYTE *AllocCode(int numops);
|
VMOP *AllocCode(int numops);
|
||||||
int *AllocKonstD(int numkonst);
|
int *AllocKonstD(int numkonst);
|
||||||
double *AllocKonstF(int numkonst);
|
double *AllocKonstF(int numkonst);
|
||||||
FString *AllocKonstS(int numkonst);
|
FString *AllocKonstS(int numkonst);
|
||||||
|
@ -694,13 +728,13 @@ public:
|
||||||
VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); }
|
VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); }
|
||||||
const VM_ATAG *KonstATags() const { return (VM_UBYTE *)(KonstA + NumKonstA); }
|
const VM_ATAG *KonstATags() const { return (VM_UBYTE *)(KonstA + NumKonstA); }
|
||||||
|
|
||||||
VM_UBYTE *Code;
|
VMOP *Code;
|
||||||
int *KonstD;
|
int *KonstD;
|
||||||
double *KonstF;
|
double *KonstF;
|
||||||
FString *KonstS;
|
FString *KonstS;
|
||||||
FVoidObj *KonstA;
|
FVoidObj *KonstA;
|
||||||
int ExtraSpace;
|
int ExtraSpace;
|
||||||
int NumCodeBytes;
|
int CodeSize; // Size of code in instructions (not bytes)
|
||||||
VM_UBYTE NumRegD;
|
VM_UBYTE NumRegD;
|
||||||
VM_UBYTE NumRegF;
|
VM_UBYTE NumRegF;
|
||||||
VM_UBYTE NumRegS;
|
VM_UBYTE NumRegS;
|
||||||
|
@ -809,10 +843,10 @@ enum EVMEngine
|
||||||
};
|
};
|
||||||
|
|
||||||
void VMSelectEngine(EVMEngine engine);
|
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 VMFillParams(VMValue *params, VMFrame *callee, int numparam);
|
||||||
|
|
||||||
void VMDumpConstants(FILE *out, const VMScriptFunction *func);
|
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
|
#endif
|
||||||
|
|
|
@ -39,7 +39,7 @@ VMScriptFunction *VMFunctionBuilder::MakeFunction()
|
||||||
VMScriptFunction *func = new VMScriptFunction;
|
VMScriptFunction *func = new VMScriptFunction;
|
||||||
|
|
||||||
// Copy code block.
|
// 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.
|
// Create constant tables.
|
||||||
if (NumIntConstants > 0)
|
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(opa >= 0 && opa <= 255);
|
||||||
assert(opb >= 0 && opb <= 255);
|
assert(opb >= 0 && opb <= 255);
|
||||||
assert(opc >= 0 && opc <= 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)
|
if (opcode == OP_PARAM)
|
||||||
{
|
{
|
||||||
ParamChange(1);
|
ParamChange(1);
|
||||||
|
@ -439,7 +433,12 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc)
|
||||||
{
|
{
|
||||||
ParamChange(-opb);
|
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)
|
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(opcode >= 0 && opcode < NUM_OPS);
|
||||||
assert(opa >= 0 && opa <= 255);
|
assert(opa >= 0 && opa <= 255);
|
||||||
assert(opbc >= -32768 && opbc <= 32767);
|
assert(opbc >= -32768 && opbc <= 32767);
|
||||||
size_t loc = Code.Reserve(4);
|
VMOP op;
|
||||||
VM_UBYTE *code = &Code[loc];
|
op.op = opcode;
|
||||||
code[0] = opcode;
|
op.a = opa;
|
||||||
code[1] = opa;
|
op.i16 = opbc;
|
||||||
*(VM_SHALF *)&code[2] = opbc;
|
return Code.Push(op);
|
||||||
return loc / 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t VMFunctionBuilder::Emit(int opcode, int opabc)
|
size_t VMFunctionBuilder::Emit(int opcode, int opabc)
|
||||||
{
|
{
|
||||||
assert(opcode >= 0 && opcode < NUM_OPS);
|
assert(opcode >= 0 && opcode < NUM_OPS);
|
||||||
assert(opabc >= -(1 << 23) && opabc <= (1 << 24) - 1);
|
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)
|
if (opcode == OP_PARAMI)
|
||||||
{
|
{
|
||||||
ParamChange(1);
|
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)
|
void VMFunctionBuilder::Backpatch(size_t loc, size_t target)
|
||||||
{
|
{
|
||||||
assert(loc < Code.Size() / 4);
|
assert(loc < Code.Size());
|
||||||
int offset = int(target - loc - 1);
|
int offset = int(target - loc - 1);
|
||||||
assert(offset >= -(1 << 24) && offset <= (1 << 24) - 1);
|
assert(((offset << 8) >> 8) == offset);
|
||||||
#ifdef __BIG_ENDIAN__
|
Code[loc].op = OP_JMP;
|
||||||
*(VM_UWORD *)&Code[loc * 4] = (offset & 0xFFFFFF) | (OP_JMP << 24);
|
Code[loc].i24 = offset;
|
||||||
#else
|
|
||||||
*(VM_UWORD *)&Code[loc * 4] = OP_JMP | (offset << 8);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -525,5 +517,5 @@ void VMFunctionBuilder::Backpatch(size_t loc, size_t target)
|
||||||
|
|
||||||
void VMFunctionBuilder::BackpatchToHere(size_t loc)
|
void VMFunctionBuilder::BackpatchToHere(size_t loc)
|
||||||
{
|
{
|
||||||
Backpatch(loc, Code.Size() / 4);
|
Backpatch(loc, Code.Size());
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ private:
|
||||||
int MaxParam;
|
int MaxParam;
|
||||||
int ActiveParam;
|
int ActiveParam;
|
||||||
|
|
||||||
TArray<VM_UBYTE> Code;
|
TArray<VMOP> Code;
|
||||||
|
|
||||||
// PARAM increases ActiveParam; CALL decreases it.
|
// PARAM increases ActiveParam; CALL decreases it.
|
||||||
void ParamChange(int delta);
|
void ParamChange(int delta);
|
||||||
|
|
|
@ -94,14 +94,6 @@ const VMOpInfo OpInfo[NUM_OPS] =
|
||||||
#include "vmops.h"
|
#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 print_reg(FILE *out, int col, int arg, int mode, int immshift, const VMScriptFunction *func);
|
||||||
|
|
||||||
static int printf_wrapper(FILE *f, const char *fmt, ...)
|
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;
|
const char *name;
|
||||||
int col;
|
int col;
|
||||||
int mode;
|
int mode;
|
||||||
int a;
|
int a;
|
||||||
|
|
||||||
for (int i = 0; i < codesize; i += 4)
|
for (int i = 0; i < codesize; ++i)
|
||||||
{
|
{
|
||||||
name = OpInfo[code[i]].Name;
|
name = OpInfo[code[i].op].Name;
|
||||||
mode = OpInfo[code[i]].Mode;
|
mode = OpInfo[code[i].op].Mode;
|
||||||
a = code[i+1];
|
a = code[i].a;
|
||||||
|
|
||||||
// String comparison encodes everything in a single instruction.
|
// String comparison encodes everything in a single instruction.
|
||||||
if (code[i] == OP_CMPS)
|
if (code[i].op == OP_CMPS)
|
||||||
{
|
{
|
||||||
switch (a & CMP_METHOD_MASK)
|
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;
|
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;
|
col = 0;
|
||||||
switch (code[i])
|
switch (code[i].op)
|
||||||
{
|
{
|
||||||
case OP_JMP:
|
case OP_JMP:
|
||||||
case OP_TRY:
|
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;
|
break;
|
||||||
|
|
||||||
case OP_PARAMI:
|
case OP_PARAMI:
|
||||||
col = printf_wrapper(out, "%d", ABCs(&code[i]));
|
col = printf_wrapper(out, "%d", code[i].i24);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_RET:
|
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
|
else
|
||||||
{
|
{
|
||||||
col = print_reg(out, 0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func);
|
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);
|
col += print_reg(out, col, code[i].i16u, MODE_PARAM, 16, func);
|
||||||
if (code[i+2] & REGT_FINAL)
|
if (code[i].b & REGT_FINAL)
|
||||||
{
|
{
|
||||||
col += printf_wrapper(out, " [final]");
|
col += printf_wrapper(out, " [final]");
|
||||||
}
|
}
|
||||||
|
@ -242,7 +234,7 @@ void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunct
|
||||||
default:
|
default:
|
||||||
if ((mode & MODE_BCTYPE) == MODE_BCCAST)
|
if ((mode & MODE_BCTYPE) == MODE_BCCAST)
|
||||||
{
|
{
|
||||||
switch (code[i+3])
|
switch (code[i].c)
|
||||||
{
|
{
|
||||||
case CAST_I2F:
|
case CAST_I2F:
|
||||||
mode = MODE_AF | MODE_BI | MODE_CUNUSED;
|
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);
|
col = print_reg(out, 0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func);
|
||||||
if ((mode & MODE_BCTYPE) == MODE_BCTHROW)
|
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)
|
else if ((mode & MODE_BCTYPE) == MODE_BCCATCH)
|
||||||
{
|
{
|
||||||
switch (code[i+1])
|
switch (code[i].a)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
mode = MODE_BUNUSED | MODE_CUNUSED;
|
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)
|
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
|
else
|
||||||
{
|
{
|
||||||
col += print_reg(out, col, code[i+2], (mode & MODE_BTYPE) >> MODE_BSHIFT, 24, func);
|
col += print_reg(out, col, code[i].b, (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].c, (mode & MODE_CTYPE) >> MODE_CSHIFT, 24, func);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -312,13 +304,13 @@ void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunct
|
||||||
col = 30;
|
col = 30;
|
||||||
}
|
}
|
||||||
printf_wrapper(out, "%*c", 30 - col, ';');
|
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
|
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:
|
case MODE_PARAM:
|
||||||
{
|
{
|
||||||
union { VM_UHALF Together; struct { VM_UBYTE RegType, RegNum; }; } p;
|
int regtype, regnum;
|
||||||
p.Together = arg;
|
#ifdef __BIG_ENDIAN__
|
||||||
switch (p.RegType & (REGT_TYPE | REGT_KONST | REGT_MULTIREG))
|
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:
|
case REGT_INT:
|
||||||
return col+printf_wrapper(out, "d%d", p.RegNum);
|
return col+printf_wrapper(out, "d%d", regnum);
|
||||||
case REGT_FLOAT:
|
case REGT_FLOAT:
|
||||||
return col+printf_wrapper(out, "f%d", p.RegNum);
|
return col+printf_wrapper(out, "f%d", regnum);
|
||||||
case REGT_STRING:
|
case REGT_STRING:
|
||||||
return col+printf_wrapper(out, "s%d", p.RegNum);
|
return col+printf_wrapper(out, "s%d", regnum);
|
||||||
case REGT_POINTER:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
default:
|
||||||
if (p.RegType == REGT_NIL)
|
if (regtype == REGT_NIL)
|
||||||
{
|
{
|
||||||
return col+printf_wrapper(out, "nil");
|
return col+printf_wrapper(out, "nil");
|
||||||
}
|
}
|
||||||
return col+printf_wrapper(out, "param[t=%d,%c,%c,n=%d]",
|
return col+printf_wrapper(out, "param[t=%d,%c,%c,n=%d]",
|
||||||
p.RegType & REGT_TYPE,
|
regtype & REGT_TYPE,
|
||||||
p.RegType & REGT_KONST ? 'k' : 'r',
|
regtype & REGT_KONST ? 'k' : 'r',
|
||||||
p.RegType & REGT_MULTIREG ? 'm' : 's',
|
regtype & REGT_MULTIREG ? 'm' : 's',
|
||||||
p.RegNum);
|
regnum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
#if COMPGOTO
|
#if COMPGOTO
|
||||||
#define OP(x) x
|
#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
|
#else
|
||||||
#define OP(x) case OP_##x
|
#define OP(x) case OP_##x
|
||||||
#define NEXTOP break
|
#define NEXTOP break
|
||||||
|
@ -17,20 +17,14 @@
|
||||||
|
|
||||||
#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b))
|
#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b))
|
||||||
|
|
||||||
#define A (*(pc - 3))
|
#define A (pc[-1].a)
|
||||||
#define B (*(pc - 2))
|
#define B (pc[-1].b)
|
||||||
#define C ( *(pc - 1))
|
#define C (pc[-1].c)
|
||||||
#define Cs (*(VM_SBYTE *)(pc - 1))
|
#define Cs (pc[-1].cs)
|
||||||
#define BC (*(VM_UHALF *)(pc - 2))
|
#define BC (pc[-1].i16u)
|
||||||
#define BCs (*(VM_SHALF *)(pc - 2))
|
#define BCs (pc[-1].i16)
|
||||||
|
#define ABCs (pc[-1].i24)
|
||||||
#ifdef WORDS_BIGENDIAN
|
#define JMPOFS(x) ((x)->i24)
|
||||||
#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 KC (konstd[C])
|
#define KC (konstd[C])
|
||||||
#define RC (reg.d[C])
|
#define RC (reg.d[C])
|
||||||
|
@ -52,10 +46,10 @@
|
||||||
|
|
||||||
#define CMPJMP(test) \
|
#define CMPJMP(test) \
|
||||||
if ((test) == (a & CMP_CHECK)) { \
|
if ((test) == (a & CMP_CHECK)) { \
|
||||||
assert(*pc == OP_JMP); \
|
assert(pc->op == OP_JMP); \
|
||||||
pc += 4 + JMPOFS(pc); \
|
pc += 1 + JMPOFS(pc); \
|
||||||
} else { \
|
} else { \
|
||||||
pc += 4; \
|
pc += 1; \
|
||||||
}
|
}
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
@ -112,7 +106,7 @@ struct VMExec_Unchecked
|
||||||
#undef assert
|
#undef assert
|
||||||
#include <assert.h>
|
#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
|
#ifdef NDEBUG
|
||||||
VMExec_Unchecked::Exec
|
VMExec_Unchecked::Exec
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#endif
|
#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
|
#if COMPGOTO
|
||||||
static const void * const ops[256] =
|
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"
|
#include "vmops.h"
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
const VM_UBYTE *exception_frames[MAX_TRY_DEPTH];
|
const VMOP *exception_frames[MAX_TRY_DEPTH];
|
||||||
int try_depth = 0;
|
int try_depth = 0;
|
||||||
VMFrame *f = stack->TopFrame();
|
VMFrame *f = stack->TopFrame();
|
||||||
VMScriptFunction *sfunc;
|
VMScriptFunction *sfunc;
|
||||||
|
@ -52,7 +52,7 @@ begin:
|
||||||
{
|
{
|
||||||
#if !COMPGOTO
|
#if !COMPGOTO
|
||||||
VM_UBYTE op;
|
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
|
#else
|
||||||
NEXTOP;
|
NEXTOP;
|
||||||
#endif
|
#endif
|
||||||
|
@ -383,17 +383,17 @@ begin:
|
||||||
ASSERTD(a);
|
ASSERTD(a);
|
||||||
if (reg.d[a] != BC)
|
if (reg.d[a] != BC)
|
||||||
{
|
{
|
||||||
pc += 4;
|
pc++;
|
||||||
}
|
}
|
||||||
NEXTOP;
|
NEXTOP;
|
||||||
OP(JMP):
|
OP(JMP):
|
||||||
pc += JMPOFS(pc - 4);
|
pc += JMPOFS(pc - 1);
|
||||||
NEXTOP;
|
NEXTOP;
|
||||||
OP(IJMP):
|
OP(IJMP):
|
||||||
ASSERTD(a);
|
ASSERTD(a);
|
||||||
pc += (BCs + reg.d[a]) << 2;
|
pc += (BCs + reg.d[a]);
|
||||||
assert(*pc == OP_JMP);
|
assert(pc->op == OP_JMP);
|
||||||
pc += (1 + *((VM_SHALF *)pc + 1)) << 2;
|
pc += 1 + JMPOFS(pc);
|
||||||
NEXTOP;
|
NEXTOP;
|
||||||
OP(PARAMI):
|
OP(PARAMI):
|
||||||
assert(f->NumParam < sfunc->MaxParam);
|
assert(f->NumParam < sfunc->MaxParam);
|
||||||
|
@ -536,7 +536,7 @@ begin:
|
||||||
{
|
{
|
||||||
reg.param[--f->NumParam].~VMValue();
|
reg.param[--f->NumParam].~VMValue();
|
||||||
}
|
}
|
||||||
pc += C * 4; // Skip RESULTs
|
pc += C; // Skip RESULTs
|
||||||
}
|
}
|
||||||
NEXTOP;
|
NEXTOP;
|
||||||
OP(RET):
|
OP(RET):
|
||||||
|
@ -567,8 +567,8 @@ begin:
|
||||||
{
|
{
|
||||||
THROW(X_TOO_MANY_TRIES);
|
THROW(X_TOO_MANY_TRIES);
|
||||||
}
|
}
|
||||||
assert(*(pc + JMPOFS(pc - 4)) == OP_CATCH);
|
assert((pc + JMPOFS(pc - 1))->op == OP_CATCH);
|
||||||
exception_frames[try_depth++] = pc + JMPOFS(pc - 4);
|
exception_frames[try_depth++] = pc + JMPOFS(pc - 1);
|
||||||
NEXTOP;
|
NEXTOP;
|
||||||
OP(UNTRY):
|
OP(UNTRY):
|
||||||
assert(a <= try_depth);
|
assert(a <= try_depth);
|
||||||
|
@ -664,12 +664,12 @@ begin:
|
||||||
}
|
}
|
||||||
if (cmp == (a & CMP_CHECK))
|
if (cmp == (a & CMP_CHECK))
|
||||||
{
|
{
|
||||||
assert(*pc == OP_JMP);
|
assert(pc->op == OP_JMP);
|
||||||
pc += 4 + JMPOFS(pc);
|
pc += 1 + JMPOFS(pc);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pc += 4;
|
pc += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NEXTOP;
|
NEXTOP;
|
||||||
|
@ -1255,48 +1255,48 @@ begin:
|
||||||
while(--try_depth >= 0)
|
while(--try_depth >= 0)
|
||||||
{
|
{
|
||||||
pc = exception_frames[try_depth];
|
pc = exception_frames[try_depth];
|
||||||
assert(pc[0] == OP_CATCH);
|
assert(pc->op == OP_CATCH);
|
||||||
while (pc[1] > 1)
|
while (pc->a > 1)
|
||||||
{
|
{
|
||||||
// CATCH must be followed by JMP if it doesn't terminate a catch chain.
|
// 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;
|
PClass *type;
|
||||||
int b = pc[2];
|
int b = pc->b;
|
||||||
|
|
||||||
if (pc[1] == 2)
|
if (pc->a == 2)
|
||||||
{
|
{
|
||||||
ASSERTA(b);
|
ASSERTA(b);
|
||||||
type = (PClass *)reg.a[b];
|
type = (PClass *)reg.a[b];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(pc[1] == 3);
|
assert(pc->a == 3);
|
||||||
ASSERTKA(b);
|
ASSERTKA(b);
|
||||||
assert(konstatag[b] == ATAG_OBJECT);
|
assert(konstatag[b] == ATAG_OBJECT);
|
||||||
type = (PClass *)konsta[b].o;
|
type = (PClass *)konsta[b].o;
|
||||||
}
|
}
|
||||||
ASSERTA(pc[3]);
|
ASSERTA(pc->c);
|
||||||
if (type == extype)
|
if (type == extype)
|
||||||
{
|
{
|
||||||
// Found a handler. Store the exception in pC, skip the JMP,
|
// Found a handler. Store the exception in pC, skip the JMP,
|
||||||
// and begin executing its code.
|
// and begin executing its code.
|
||||||
reg.a[pc[3]] = exception;
|
reg.a[pc->c] = exception;
|
||||||
reg.atag[pc[3]] = ATAG_OBJECT;
|
reg.atag[pc->c] = ATAG_OBJECT;
|
||||||
pc += 8;
|
pc += 2;
|
||||||
goto begin;
|
goto begin;
|
||||||
}
|
}
|
||||||
// This catch didn't handle it. Try the next one.
|
// This catch didn't handle it. Try the next one.
|
||||||
pc += 4 + JMPOFS(pc + 4);
|
pc += 1 + JMPOFS(pc + 1);
|
||||||
assert(pc[0] == OP_CATCH);
|
assert(pc->op == OP_CATCH);
|
||||||
}
|
}
|
||||||
if (pc[1] == 1)
|
if (pc->a == 1)
|
||||||
{
|
{
|
||||||
// Catch any type of VMException. This terminates the chain.
|
// Catch any type of VMException. This terminates the chain.
|
||||||
ASSERTA(pc[3]);
|
ASSERTA(pc->c);
|
||||||
reg.a[pc[3]] = exception;
|
reg.a[pc->c] = exception;
|
||||||
reg.atag[pc[3]] = ATAG_OBJECT;
|
reg.atag[pc->c] = ATAG_OBJECT;
|
||||||
pc += 4;
|
pc += 1;
|
||||||
goto begin;
|
goto begin;
|
||||||
}
|
}
|
||||||
// This frame failed. Try the next one out.
|
// 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;
|
int i, type, num;
|
||||||
VMReturn *ret;
|
VMReturn *ret;
|
||||||
|
|
||||||
assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3);
|
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
|
assert(retval->op == OP_RESULT); // opcode
|
||||||
ret->RegType = type = retval[2];
|
ret->RegType = type = retval->b;
|
||||||
ret->RegNum = num = retval[3];
|
ret->RegNum = num = retval->c;
|
||||||
assert(!(type & REGT_KONST));
|
assert(!(type & REGT_KONST));
|
||||||
type &= REGT_TYPE;
|
type &= REGT_TYPE;
|
||||||
if (type < REGT_STRING)
|
if (type < REGT_STRING)
|
||||||
|
|
|
@ -15,7 +15,7 @@ VMScriptFunction::VMScriptFunction()
|
||||||
KonstS = NULL;
|
KonstS = NULL;
|
||||||
KonstA = NULL;
|
KonstA = NULL;
|
||||||
ExtraSpace = 0;
|
ExtraSpace = 0;
|
||||||
NumCodeBytes = 0;
|
CodeSize = 0;
|
||||||
NumRegD = 0;
|
NumRegD = 0;
|
||||||
NumRegF = 0;
|
NumRegF = 0;
|
||||||
NumRegS = 0;
|
NumRegS = 0;
|
||||||
|
@ -37,12 +37,11 @@ VMScriptFunction::~VMScriptFunction()
|
||||||
if (KonstA != NULL) M_Free(KonstA);
|
if (KonstA != NULL) M_Free(KonstA);
|
||||||
}
|
}
|
||||||
|
|
||||||
VM_UBYTE *VMScriptFunction::AllocCode(int numops)
|
VMOP *VMScriptFunction::AllocCode(int numops)
|
||||||
{
|
{
|
||||||
assert(Code == NULL && numops > 0);
|
assert(Code == NULL && numops > 0);
|
||||||
numops *= VM_OPSIZE;
|
CodeSize = numops;
|
||||||
NumCodeBytes = numops;
|
return Code = (VMOP *)M_Malloc(numops * sizeof(VMOP));
|
||||||
return Code = (VM_UBYTE *)M_Malloc(numops);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int *VMScriptFunction::AllocKonstD(int numkonst)
|
int *VMScriptFunction::AllocKonstD(int numkonst)
|
||||||
|
|
Loading…
Reference in a new issue