|
|
@ -1704,110 +1704,6 @@ PH7_PRIVATE sxi32 PH7_VmConfigure( |
|
|
|
return rc; |
|
|
|
} |
|
|
|
/* Forward declaration */ |
|
|
|
static const char *VmInstrToString(sxi32 nOp); |
|
|
|
/* |
|
|
|
* This routine is used to dump the debug stacktrace based on all active frames. |
|
|
|
*/ |
|
|
|
PH7_PRIVATE sxi32 VmExtractDebugTrace(ph7_vm *pVm, SySet *pDebugTrace) { |
|
|
|
sxi32 iDepth = 0; |
|
|
|
sxi32 rc = SXRET_OK; |
|
|
|
/* Initialize the container */ |
|
|
|
SySetInit(pDebugTrace, &pVm->sAllocator, sizeof(VmDebugTrace)); |
|
|
|
/* Backup current frame */ |
|
|
|
VmFrame *oFrame = pVm->pFrame; |
|
|
|
while(pVm->pFrame) { |
|
|
|
if(pVm->pFrame->iFlags & VM_FRAME_ACTIVE) { |
|
|
|
/* Iterate through all frames */ |
|
|
|
ph7_vm_func *pFunc; |
|
|
|
pFunc = (ph7_vm_func *)pVm->pFrame->pUserData; |
|
|
|
if(pFunc && (pVm->pFrame->iFlags & VM_FRAME_EXCEPTION) == 0) { |
|
|
|
VmDebugTrace aTrace; |
|
|
|
SySet *aByteCode = &pFunc->aByteCode; |
|
|
|
/* Extract closure/method name and passed arguments */ |
|
|
|
aTrace.pFuncName = &pFunc->sName; |
|
|
|
aTrace.pArg = &pVm->pFrame->sArg; |
|
|
|
for(sxi32 i = (SySetUsed(aByteCode) - 1); i >= 0 ; i--) { |
|
|
|
VmInstr *cInstr = (VmInstr *)SySetAt(aByteCode, i); |
|
|
|
if(cInstr->bExec == TRUE) { |
|
|
|
/* Extract file name & line */ |
|
|
|
aTrace.pFile = cInstr->pFile; |
|
|
|
aTrace.nLine = cInstr->iLine; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
if(aTrace.pFile) { |
|
|
|
aTrace.pClassName = NULL; |
|
|
|
aTrace.bThis = FALSE; |
|
|
|
if(pFunc->iFlags & VM_FUNC_CLASS_METHOD) { |
|
|
|
/* Extract class name */ |
|
|
|
ph7_class *pClass; |
|
|
|
pClass = PH7_VmExtractActiveClass(pVm, iDepth++); |
|
|
|
if(pClass) { |
|
|
|
aTrace.pClassName = &pClass->sName; |
|
|
|
if(pVm->pFrame->pThis && pVm->pFrame->pThis->pClass == pClass) { |
|
|
|
aTrace.bThis = TRUE; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
rc = SySetPut(pDebugTrace, (const void *)&aTrace); |
|
|
|
if(rc != SXRET_OK) { |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
/* Roll frame */ |
|
|
|
pVm->pFrame = pVm->pFrame->pParent; |
|
|
|
} |
|
|
|
/* Restore original frame */ |
|
|
|
pVm->pFrame = oFrame; |
|
|
|
return rc; |
|
|
|
} |
|
|
|
/* |
|
|
|
* This routine is used to dump PH7 byte-code instructions to a human readable |
|
|
|
* format. |
|
|
|
* The dump is redirected to the given consumer callback which is responsible |
|
|
|
* of consuming the generated dump perhaps redirecting it to its standard output |
|
|
|
* (STDOUT). |
|
|
|
*/ |
|
|
|
static sxi32 VmByteCodeDump( |
|
|
|
SySet *pByteCode, /* Bytecode container */ |
|
|
|
ProcConsumer xConsumer, /* Dump consumer callback */ |
|
|
|
void *pUserData /* Last argument to xConsumer() */ |
|
|
|
) { |
|
|
|
static const char zDump[] = { |
|
|
|
"========================================================================================================\n" |
|
|
|
" SEQ | OP | INSTRUCTION | P1 | P2 | P3 | LINE | SOURCE FILE \n" |
|
|
|
"========================================================================================================\n" |
|
|
|
}; |
|
|
|
VmInstr *pInstr, *pEnd; |
|
|
|
sxi32 rc = SXRET_OK; |
|
|
|
sxu32 n; |
|
|
|
/* Point to the PH7 instructions */ |
|
|
|
pInstr = (VmInstr *)SySetBasePtr(pByteCode); |
|
|
|
pEnd = &pInstr[SySetUsed(pByteCode)]; |
|
|
|
n = 1; |
|
|
|
xConsumer((const void *)zDump, sizeof(zDump) - 1, pUserData); |
|
|
|
/* Dump instructions */ |
|
|
|
for(;;) { |
|
|
|
if(pInstr >= pEnd) { |
|
|
|
/* No more instructions */ |
|
|
|
break; |
|
|
|
} |
|
|
|
/* Format and call the consumer callback */ |
|
|
|
rc = SyProcFormat(xConsumer, pUserData, " #%08u | %4d | %-11s | %8d | %8u | %#10x | %6u | %z\n", |
|
|
|
n, pInstr->iOp, VmInstrToString(pInstr->iOp), pInstr->iP1, pInstr->iP2, |
|
|
|
SX_PTR_TO_INT(pInstr->p3), pInstr->iLine, pInstr->pFile); |
|
|
|
if(rc != SXRET_OK) { |
|
|
|
/* Consumer routine request an operation abort */ |
|
|
|
return rc; |
|
|
|
} |
|
|
|
++n; |
|
|
|
pInstr++; /* Next instruction in the stream */ |
|
|
|
} |
|
|
|
return rc; |
|
|
|
} |
|
|
|
/* Forward declaration */ |
|
|
|
static int VmObConsumer(const void *pData, unsigned int nDataLen, void *pUserData); |
|
|
|
static sxi32 VmExecFinallyBlock(ph7_vm *pVm, ph7_exception *pException); |
|
|
|
static sxi32 VmUncaughtException(ph7_vm *pVm, ph7_class_instance *pThis); |
|
|
@ -5247,267 +5143,6 @@ PH7_PRIVATE sxi32 PH7_VmOutputConsumeAp( |
|
|
|
SyBlobRelease(&sWorker); |
|
|
|
return rc; |
|
|
|
} |
|
|
|
/* |
|
|
|
* Return a string representation of the given PH7 OP code. |
|
|
|
* This function never fail and always return a pointer |
|
|
|
* to a null terminated string. |
|
|
|
*/ |
|
|
|
static const char *VmInstrToString(sxi32 nOp) { |
|
|
|
const char *zOp = "UNKNOWN"; |
|
|
|
switch(nOp) { |
|
|
|
case PH7_OP_DONE: |
|
|
|
zOp = "DONE"; |
|
|
|
break; |
|
|
|
case PH7_OP_HALT: |
|
|
|
zOp = "HALT"; |
|
|
|
break; |
|
|
|
case PH7_OP_IMPORT: |
|
|
|
zOp = "IMPORT"; |
|
|
|
break; |
|
|
|
case PH7_OP_INCLUDE: |
|
|
|
zOp = "INCLUDE"; |
|
|
|
break; |
|
|
|
case PH7_OP_DECLARE: |
|
|
|
zOp = "DECLARE"; |
|
|
|
break; |
|
|
|
case PH7_OP_LOADV: |
|
|
|
zOp = "LOADV"; |
|
|
|
break; |
|
|
|
case PH7_OP_LOADC: |
|
|
|
zOp = "LOADC"; |
|
|
|
break; |
|
|
|
case PH7_OP_LOAD_MAP: |
|
|
|
zOp = "LOAD_MAP"; |
|
|
|
break; |
|
|
|
case PH7_OP_LOAD_IDX: |
|
|
|
zOp = "LOAD_IDX"; |
|
|
|
break; |
|
|
|
case PH7_OP_LOAD_CLOSURE: |
|
|
|
zOp = "LOAD_CLOSR"; |
|
|
|
break; |
|
|
|
case PH7_OP_NOOP: |
|
|
|
zOp = "NOOP"; |
|
|
|
break; |
|
|
|
case PH7_OP_JMP: |
|
|
|
zOp = "JMP"; |
|
|
|
break; |
|
|
|
case PH7_OP_JMPZ: |
|
|
|
zOp = "JMPZ"; |
|
|
|
break; |
|
|
|
case PH7_OP_JMPNZ: |
|
|
|
zOp = "JMPNZ"; |
|
|
|
break; |
|
|
|
case PH7_OP_LF_START: |
|
|
|
zOp = "LF_START"; |
|
|
|
break; |
|
|
|
case PH7_OP_LF_STOP: |
|
|
|
zOp = "LF_STOP"; |
|
|
|
break; |
|
|
|
case PH7_OP_POP: |
|
|
|
zOp = "POP"; |
|
|
|
break; |
|
|
|
case PH7_OP_CVT_INT: |
|
|
|
zOp = "CVT_INT"; |
|
|
|
break; |
|
|
|
case PH7_OP_CVT_STR: |
|
|
|
zOp = "CVT_STR"; |
|
|
|
break; |
|
|
|
case PH7_OP_CVT_REAL: |
|
|
|
zOp = "CVT_FLOAT"; |
|
|
|
break; |
|
|
|
case PH7_OP_CALL: |
|
|
|
zOp = "CALL"; |
|
|
|
break; |
|
|
|
case PH7_OP_UMINUS: |
|
|
|
zOp = "UMINUS"; |
|
|
|
break; |
|
|
|
case PH7_OP_UPLUS: |
|
|
|
zOp = "UPLUS"; |
|
|
|
break; |
|
|
|
case PH7_OP_BITNOT: |
|
|
|
zOp = "BITNOT"; |
|
|
|
break; |
|
|
|
case PH7_OP_LNOT: |
|
|
|
zOp = "LOGNOT"; |
|
|
|
break; |
|
|
|
case PH7_OP_MUL: |
|
|
|
zOp = "MUL"; |
|
|
|
break; |
|
|
|
case PH7_OP_DIV: |
|
|
|
zOp = "DIV"; |
|
|
|
break; |
|
|
|
case PH7_OP_MOD: |
|
|
|
zOp = "MOD"; |
|
|
|
break; |
|
|
|
case PH7_OP_ADD: |
|
|
|
zOp = "ADD"; |
|
|
|
break; |
|
|
|
case PH7_OP_SUB: |
|
|
|
zOp = "SUB"; |
|
|
|
break; |
|
|
|
case PH7_OP_SHL: |
|
|
|
zOp = "SHL"; |
|
|
|
break; |
|
|
|
case PH7_OP_SHR: |
|
|
|
zOp = "SHR"; |
|
|
|
break; |
|
|
|
case PH7_OP_LT: |
|
|
|
zOp = "LT"; |
|
|
|
break; |
|
|
|
case PH7_OP_LE: |
|
|
|
zOp = "LE"; |
|
|
|
break; |
|
|
|
case PH7_OP_GT: |
|
|
|
zOp = "GT"; |
|
|
|
break; |
|
|
|
case PH7_OP_GE: |
|
|
|
zOp = "GE"; |
|
|
|
break; |
|
|
|
case PH7_OP_EQ: |
|
|
|
zOp = "EQ"; |
|
|
|
break; |
|
|
|
case PH7_OP_NEQ: |
|
|
|
zOp = "NEQ"; |
|
|
|
break; |
|
|
|
case PH7_OP_NULLC: |
|
|
|
zOp = "NULLC"; |
|
|
|
break; |
|
|
|
case PH7_OP_BAND: |
|
|
|
zOp = "BITAND"; |
|
|
|
break; |
|
|
|
case PH7_OP_BXOR: |
|
|
|
zOp = "BITXOR"; |
|
|
|
break; |
|
|
|
case PH7_OP_BOR: |
|
|
|
zOp = "BITOR"; |
|
|
|
break; |
|
|
|
case PH7_OP_LAND: |
|
|
|
zOp = "LOGAND"; |
|
|
|
break; |
|
|
|
case PH7_OP_LOR: |
|
|
|
zOp = "LOGOR"; |
|
|
|
break; |
|
|
|
case PH7_OP_LXOR: |
|
|
|
zOp = "LOGXOR"; |
|
|
|
break; |
|
|
|
case PH7_OP_STORE: |
|
|
|
zOp = "STORE"; |
|
|
|
break; |
|
|
|
case PH7_OP_STORE_IDX: |
|
|
|
zOp = "STORE_IDX"; |
|
|
|
break; |
|
|
|
case PH7_OP_PULL: |
|
|
|
zOp = "PULL"; |
|
|
|
break; |
|
|
|
case PH7_OP_SWAP: |
|
|
|
zOp = "SWAP"; |
|
|
|
break; |
|
|
|
case PH7_OP_YIELD: |
|
|
|
zOp = "YIELD"; |
|
|
|
break; |
|
|
|
case PH7_OP_CVT_BOOL: |
|
|
|
zOp = "CVT_BOOL"; |
|
|
|
break; |
|
|
|
case PH7_OP_CVT_OBJ: |
|
|
|
zOp = "CVT_OBJ"; |
|
|
|
break; |
|
|
|
case PH7_OP_INCR: |
|
|
|
zOp = "INCR"; |
|
|
|
break; |
|
|
|
case PH7_OP_DECR: |
|
|
|
zOp = "DECR"; |
|
|
|
break; |
|
|
|
case PH7_OP_NEW: |
|
|
|
zOp = "NEW"; |
|
|
|
break; |
|
|
|
case PH7_OP_CLONE: |
|
|
|
zOp = "CLONE"; |
|
|
|
break; |
|
|
|
case PH7_OP_ADD_STORE: |
|
|
|
zOp = "ADD_STORE"; |
|
|
|
break; |
|
|
|
case PH7_OP_SUB_STORE: |
|
|
|
zOp = "SUB_STORE"; |
|
|
|
break; |
|
|
|
case PH7_OP_MUL_STORE: |
|
|
|
zOp = "MUL_STORE"; |
|
|
|
break; |
|
|
|
case PH7_OP_DIV_STORE: |
|
|
|
zOp = "DIV_STORE"; |
|
|
|
break; |
|
|
|
case PH7_OP_MOD_STORE: |
|
|
|
zOp = "MOD_STORE"; |
|
|
|
break; |
|
|
|
case PH7_OP_SHL_STORE: |
|
|
|
zOp = "SHL_STORE"; |
|
|
|
break; |
|
|
|
case PH7_OP_SHR_STORE: |
|
|
|
zOp = "SHR_STORE"; |
|
|
|
break; |
|
|
|
case PH7_OP_BAND_STORE: |
|
|
|
zOp = "BAND_STORE"; |
|
|
|
break; |
|
|
|
case PH7_OP_BOR_STORE: |
|
|
|
zOp = "BOR_STORE"; |
|
|
|
break; |
|
|
|
case PH7_OP_BXOR_STORE: |
|
|
|
zOp = "BXOR_STORE"; |
|
|
|
break; |
|
|
|
case PH7_OP_CONSUME: |
|
|
|
zOp = "CONSUME"; |
|
|
|
break; |
|
|
|
case PH7_OP_MEMBER: |
|
|
|
zOp = "MEMBER"; |
|
|
|
break; |
|
|
|
case PH7_OP_IS: |
|
|
|
zOp = "IS"; |
|
|
|
break; |
|
|
|
case PH7_OP_SWITCH: |
|
|
|
zOp = "SWITCH"; |
|
|
|
break; |
|
|
|
case PH7_OP_LOAD_EXCEPTION: |
|
|
|
zOp = "LOAD_EXCEP"; |
|
|
|
break; |
|
|
|
case PH7_OP_POP_EXCEPTION: |
|
|
|
zOp = "POP_EXCEP"; |
|
|
|
break; |
|
|
|
case PH7_OP_THROW: |
|
|
|
zOp = "THROW"; |
|
|
|
break; |
|
|
|
case PH7_OP_CLASS_INIT: |
|
|
|
zOp = "CLASS_INIT"; |
|
|
|
break; |
|
|
|
case PH7_OP_INTERFACE_INIT: |
|
|
|
zOp = "INTER_INIT"; |
|
|
|
break; |
|
|
|
case PH7_OP_FOREACH_INIT: |
|
|
|
zOp = "4EACH_INIT"; |
|
|
|
break; |
|
|
|
case PH7_OP_FOREACH_STEP: |
|
|
|
zOp = "4EACH_STEP"; |
|
|
|
break; |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
return zOp; |
|
|
|
} |
|
|
|
/* |
|
|
|
* Dump PH7 bytecodes instructions to a human readable format. |
|
|
|
* The xConsumer() callback which is an used defined function |
|
|
|
* is responsible of consuming the generated dump. |
|
|
|
*/ |
|
|
|
PH7_PRIVATE sxi32 PH7_VmDump( |
|
|
|
ph7_vm *pVm, /* Target VM */ |
|
|
|
ProcConsumer xConsumer, /* Output [i.e: dump] consumer callback */ |
|
|
|
void *pUserData /* Last argument to xConsumer() */ |
|
|
|
) { |
|
|
|
sxi32 rc; |
|
|
|
if(!pVm->bDebug) { |
|
|
|
return SXRET_OK; |
|
|
|
} |
|
|
|
rc = VmByteCodeDump(&pVm->aInstrSet, xConsumer, pUserData); |
|
|
|
return rc; |
|
|
|
} |
|
|
|
/* |
|
|
|
* Default constant expansion callback used by the 'const' statement if used |
|
|
|
* outside a class body [i.e: global or function scope]. |
|
|
|