/* * $Id$ */ /* * Harbour Project source code: * dead (unaccessible) PCODE eliminator * * Copyright 2006 Przemyslaw Czerpak < druzus /at/ priv.onet.pl > * www - http://www.harbour-project.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). * * As a special exception, the Harbour Project gives permission for * additional uses of the text contained in its release of Harbour. * * The exception is that, if you link the Harbour libraries with other * files to produce an executable, this does not by itself cause the * resulting executable to be covered by the GNU General Public License. * Your use of that executable is in no way restricted on account of * linking the Harbour library code into it. * * This exception does not however invalidate any other reasons why * the executable file might be covered by the GNU General Public License. * * This exception applies only to the code released by the Harbour * Project under the name Harbour. If you copy code from other * Harbour Project or Free Software Foundation releases into a copy of * Harbour, as the General Public License permits, the exception does * not apply to the code that you add in this way. To avoid misleading * anyone as to the status of such modified files, you must delete * this exception notice from them. * * If you write modifications of your own for Harbour, it is your choice * whether to permit this exception to apply to your modifications. * If you do not wish that, delete this exception notice. * */ #include #include "hbcomp.h" /* helper structure to pass information */ typedef struct _HB_CODETRACE_INFO { BYTE * pCodeMark; ULONG * plJumps; ULONG ulJumpPos; ULONG ulJumpSize; ULONG ulJumpCount; ULONG ulPCodeSize; BOOL fFinished; } HB_CODETRACE_INFO, * PHB_CODETRACE_INFO; #define HB_CODETRACE_FUNC( func ) HB_PCODE_FUNC( func, PHB_CODETRACE_INFO ) typedef HB_CODETRACE_FUNC( HB_CODETRACE_FUNC_ ); typedef HB_CODETRACE_FUNC_ * PHB_CODETRACE_FUNC; #define HB_JUMPADDR_ALLOC 64 static void hb_compCodeTraceAddJump( PHB_CODETRACE_INFO pInfo, ULONG ulPCodePos ) { if( pInfo->pCodeMark[ ulPCodePos ] == 0 ) { if( pInfo->ulJumpSize == 0 ) { pInfo->ulJumpSize = HB_JUMPADDR_ALLOC; pInfo->plJumps = ( ULONG * ) hb_xgrab( pInfo->ulJumpSize * sizeof( ULONG ) ); } else if( pInfo->ulJumpSize == pInfo->ulJumpCount ) { pInfo->ulJumpSize += HB_JUMPADDR_ALLOC; pInfo->plJumps = ( ULONG * ) hb_xrealloc( pInfo->plJumps, pInfo->ulJumpSize * sizeof( ULONG ) ); } pInfo->plJumps[ pInfo->ulJumpCount++ ] = ulPCodePos; pInfo->pCodeMark[ ulPCodePos ] = 1; } } static ULONG hb_compCodeTraceNextPos( PHB_CODETRACE_INFO pInfo, ULONG ulPCodePos ) { if( ulPCodePos < pInfo->ulPCodeSize && pInfo->pCodeMark[ ulPCodePos ] == 0 ) return ulPCodePos; while( pInfo->ulJumpPos < pInfo->ulJumpCount ) { ulPCodePos = pInfo->plJumps[ pInfo->ulJumpPos++ ]; if( pInfo->pCodeMark[ ulPCodePos ] == 1 ) return ulPCodePos; } pInfo->fFinished = TRUE; return pInfo->ulPCodeSize; } static void hb_compCodeTraceMark( PHB_CODETRACE_INFO pInfo, ULONG ulPCodePos, ULONG ulSize ) { memset( &pInfo->pCodeMark[ ulPCodePos ], 2, ulSize ); } /* * PCODE trace functions */ static HB_CODETRACE_FUNC( hb_p_default ) { ULONG ulSize = hb_comp_pcode_len[ pFunc->pCode[ lPCodePos ] ]; hb_compCodeTraceMark( cargo, lPCodePos, ulSize ); return hb_compCodeTraceNextPos( cargo, lPCodePos + ulSize ); } static HB_CODETRACE_FUNC( hb_p_pushstr ) { BYTE * pAddr = &pFunc->pCode[ lPCodePos + 1 ]; ULONG ulSize = 3 + HB_PCODE_MKUSHORT( pAddr ); hb_compCodeTraceMark( cargo, lPCodePos, ulSize ); return hb_compCodeTraceNextPos( cargo, lPCodePos + ulSize ); } static HB_CODETRACE_FUNC( hb_p_pushstrshort ) { ULONG ulSize = 2 + pFunc->pCode[ lPCodePos + 1 ]; hb_compCodeTraceMark( cargo, lPCodePos, ulSize ); return hb_compCodeTraceNextPos( cargo, lPCodePos + ulSize ); } static HB_CODETRACE_FUNC( hb_p_pushblock ) { BYTE * pAddr = &pFunc->pCode[ lPCodePos + 1 ]; ULONG ulSize = HB_PCODE_MKUSHORT( pAddr ); hb_compCodeTraceMark( cargo, lPCodePos, ulSize ); return hb_compCodeTraceNextPos( cargo, lPCodePos + ulSize ); } static HB_CODETRACE_FUNC( hb_p_pushblockshort ) { ULONG ulSize = pFunc->pCode[ lPCodePos + 1 ]; hb_compCodeTraceMark( cargo, lPCodePos, ulSize ); return hb_compCodeTraceNextPos( cargo, lPCodePos + ulSize ); } static HB_CODETRACE_FUNC( hb_p_localname ) { ULONG ulStart = lPCodePos; lPCodePos += 3; while( pFunc->pCode[ lPCodePos++ ] ); hb_compCodeTraceMark( cargo, ulStart, lPCodePos - ulStart ); return hb_compCodeTraceNextPos( cargo, lPCodePos ); } static HB_CODETRACE_FUNC( hb_p_modulename ) { ULONG ulStart = lPCodePos; while( pFunc->pCode[ lPCodePos++ ] ); hb_compCodeTraceMark( cargo, ulStart, lPCodePos - ulStart ); return hb_compCodeTraceNextPos( cargo, lPCodePos ); } static HB_CODETRACE_FUNC( hb_p_staticname ) { ULONG ulStart = lPCodePos; lPCodePos += 4; while( pFunc->pCode[ lPCodePos++ ] ); hb_compCodeTraceMark( cargo, ulStart, lPCodePos - ulStart ); return hb_compCodeTraceNextPos( cargo, lPCodePos ); } static HB_CODETRACE_FUNC( hb_p_jumpnear ) { ULONG ulNewPos = lPCodePos + ( signed char ) pFunc->pCode[ lPCodePos + 1 ]; hb_compCodeTraceMark( cargo, lPCodePos, 2 ); return hb_compCodeTraceNextPos( cargo, ulNewPos ); } static HB_CODETRACE_FUNC( hb_p_jump ) { BYTE * pAddr = &pFunc->pCode[ lPCodePos + 1 ]; ULONG ulNewPos = lPCodePos + HB_PCODE_MKSHORT( pAddr ); hb_compCodeTraceMark( cargo, lPCodePos, 3 ); return hb_compCodeTraceNextPos( cargo, ulNewPos ); } static HB_CODETRACE_FUNC( hb_p_jumpfar ) { BYTE * pAddr = &pFunc->pCode[ lPCodePos + 1 ]; ULONG ulNewPos = lPCodePos + HB_PCODE_MKINT24( pAddr ); hb_compCodeTraceMark( cargo, lPCodePos, 4 ); return hb_compCodeTraceNextPos( cargo, ulNewPos ); } static HB_CODETRACE_FUNC( hb_p_jumpfalsenear ) { ULONG ulNewPos = lPCodePos + ( signed char ) pFunc->pCode[ lPCodePos + 1 ]; hb_compCodeTraceMark( cargo, lPCodePos, 2 ); hb_compCodeTraceAddJump( cargo, ulNewPos ); return hb_compCodeTraceNextPos( cargo, lPCodePos + 2 ); } static HB_CODETRACE_FUNC( hb_p_jumpfalse ) { BYTE * pAddr = &pFunc->pCode[ lPCodePos + 1 ]; ULONG ulNewPos = lPCodePos + HB_PCODE_MKSHORT( pAddr ); hb_compCodeTraceMark( cargo, lPCodePos, 3 ); hb_compCodeTraceAddJump( cargo, ulNewPos ); return hb_compCodeTraceNextPos( cargo, lPCodePos + 3 ); } static HB_CODETRACE_FUNC( hb_p_jumpfalsefar ) { BYTE * pAddr = &pFunc->pCode[ lPCodePos + 1 ]; ULONG ulNewPos = lPCodePos + HB_PCODE_MKINT24( pAddr ); hb_compCodeTraceMark( cargo, lPCodePos, 4 ); hb_compCodeTraceAddJump( cargo, ulNewPos ); return hb_compCodeTraceNextPos( cargo, lPCodePos + 4 ); } static HB_CODETRACE_FUNC( hb_p_jumptruenear ) { ULONG ulNewPos = lPCodePos + ( signed char ) pFunc->pCode[ lPCodePos + 1 ]; hb_compCodeTraceMark( cargo, lPCodePos, 2 ); hb_compCodeTraceAddJump( cargo, ulNewPos ); return hb_compCodeTraceNextPos( cargo, lPCodePos + 2 ); } static HB_CODETRACE_FUNC( hb_p_jumptrue ) { BYTE * pAddr = &pFunc->pCode[ lPCodePos + 1 ]; ULONG ulNewPos = lPCodePos + HB_PCODE_MKSHORT( pAddr ); hb_compCodeTraceMark( cargo, lPCodePos, 3 ); hb_compCodeTraceAddJump( cargo, ulNewPos ); return hb_compCodeTraceNextPos( cargo, lPCodePos + 3 ); } static HB_CODETRACE_FUNC( hb_p_jumptruefar ) { BYTE * pAddr = &pFunc->pCode[ lPCodePos + 1 ]; ULONG ulNewPos = lPCodePos + HB_PCODE_MKINT24( pAddr ); hb_compCodeTraceMark( cargo, lPCodePos, 4 ); hb_compCodeTraceAddJump( cargo, ulNewPos ); return hb_compCodeTraceNextPos( cargo, lPCodePos + 4 ); } static HB_CODETRACE_FUNC( hb_p_seqbegin ) { BYTE * pAddr = &pFunc->pCode[ lPCodePos + 1 ]; ULONG ulRecoverPos = lPCodePos + HB_PCODE_MKINT24( pAddr ); hb_compCodeTraceMark( cargo, lPCodePos, 4 ); hb_compCodeTraceAddJump( cargo, ulRecoverPos ); return hb_compCodeTraceNextPos( cargo, lPCodePos + 4 ); } static HB_CODETRACE_FUNC( hb_p_seqend ) { BYTE * pAddr = &pFunc->pCode[ lPCodePos + 1 ]; ULONG ulNewPos = lPCodePos + HB_PCODE_MKINT24( pAddr ); hb_compCodeTraceMark( cargo, lPCodePos, 4 ); return hb_compCodeTraceNextPos( cargo, ulNewPos ); } static HB_CODETRACE_FUNC( hb_p_switch ) { HB_SYMBOL_UNUSED( pFunc ); HB_SYMBOL_UNUSED( lPCodePos ); /* * TODO: it has to be updated in differ way * HB_P_SWITCH is not normal PCODE, it generates a table * with case conditions and jumps using standard PCODEs * which are not evaluated by HVM but by hb_vmSwitch() * working like a small VM but using differ actions for * given PCODE so we will have to repeat it here. * Ryszard if you want then please update it. * Personally I do not like such exceptions which needs * special code, we will have the same problem with real * stack context optimizer if we will have it in the * future, [druzus] */ /* break farther code scanning here without setting cargo->fFinished */ return cargo->ulPCodeSize; } static HB_CODETRACE_FUNC( hb_p_endblock ) { HB_SYMBOL_UNUSED( pFunc ); HB_SYMBOL_UNUSED( lPCodePos ); hb_compCodeTraceMark( cargo, lPCodePos, 1 ); return hb_compCodeTraceNextPos( cargo, cargo->ulPCodeSize ); } static HB_CODETRACE_FUNC( hb_p_endproc ) { HB_SYMBOL_UNUSED( pFunc ); HB_SYMBOL_UNUSED( lPCodePos ); hb_compCodeTraceMark( cargo, lPCodePos, 1 ); return hb_compCodeTraceNextPos( cargo, cargo->ulPCodeSize ); } /* NOTE: The order of functions have to match the order of opcodes * mnemonics */ static PHB_CODETRACE_FUNC s_codeTraceFuncTable[ HB_P_LAST_PCODE ] = { hb_p_default, /* HB_P_AND, */ hb_p_default, /* HB_P_ARRAYPUSH, */ hb_p_default, /* HB_P_ARRAYPOP, */ hb_p_default, /* HB_P_ARRAYDIM, */ hb_p_default, /* HB_P_ARRAYGEN, */ hb_p_default, /* HB_P_EQUAL, */ hb_p_endblock, /* HB_P_ENDBLOCK, */ hb_p_endproc, /* HB_P_ENDPROC, */ hb_p_default, /* HB_P_EXACTLYEQUAL, */ hb_p_default, /* HB_P_FALSE, */ hb_p_default, /* HB_P_FORTEST, */ hb_p_default, /* HB_P_FUNCTION, */ hb_p_default, /* HB_P_FUNCTIONSHORT, */ hb_p_default, /* HB_P_FRAME, */ hb_p_default, /* HB_P_FUNCPTR, */ hb_p_default, /* HB_P_GREATER, */ hb_p_default, /* HB_P_GREATEREQUAL, */ hb_p_default, /* HB_P_DEC, */ hb_p_default, /* HB_P_DIVIDE, */ hb_p_default, /* HB_P_DO, */ hb_p_default, /* HB_P_DOSHORT, */ hb_p_default, /* HB_P_DUPLICATE, */ hb_p_default, /* HB_P_DUPLTWO, */ hb_p_default, /* HB_P_INC, */ hb_p_default, /* HB_P_INSTRING, */ hb_p_jumpnear, /* HB_P_JUMPNEAR, */ hb_p_jump, /* HB_P_JUMP, */ hb_p_jumpfar, /* HB_P_JUMPFAR, */ hb_p_jumpfalsenear, /* HB_P_JUMPFALSENEAR, */ hb_p_jumpfalse, /* HB_P_JUMPFALSE, */ hb_p_jumpfalsefar, /* HB_P_JUMPFALSEFAR, */ hb_p_jumptruenear, /* HB_P_JUMPTRUENEAR, */ hb_p_jumptrue, /* HB_P_JUMPTRUE, */ hb_p_jumptruefar, /* HB_P_JUMPTRUEFAR, */ hb_p_default, /* HB_P_LESSEQUAL, */ hb_p_default, /* HB_P_LESS, */ hb_p_default, /* HB_P_LINE, */ hb_p_localname, /* HB_P_LOCALNAME, */ hb_p_default, /* HB_P_MACROPOP, */ hb_p_default, /* HB_P_MACROPOPALIASED, */ hb_p_default, /* HB_P_MACROPUSH, */ hb_p_default, /* HB_P_MACROPUSHARG, */ hb_p_default, /* HB_P_MACROPUSHLIST, */ hb_p_default, /* HB_P_MACROPUSHINDEX, */ hb_p_default, /* HB_P_MACROPUSHPARE, */ hb_p_default, /* HB_P_MACROPUSHALIASED, */ hb_p_default, /* HB_P_MACROSYMBOL, */ hb_p_default, /* HB_P_MACROTEXT, */ hb_p_default, /* HB_P_MESSAGE, */ hb_p_default, /* HB_P_MINUS, */ hb_p_default, /* HB_P_MODULUS, */ hb_p_modulename, /* HB_P_MODULENAME, */ /* start: pcodes generated by macro compiler */ hb_p_default, /* HB_P_MMESSAGE, */ hb_p_default, /* HB_P_MPOPALIASEDFIELD, */ hb_p_default, /* HB_P_MPOPALIASEDVAR, */ hb_p_default, /* HB_P_MPOPFIELD, */ hb_p_default, /* HB_P_MPOPMEMVAR, */ hb_p_default, /* HB_P_MPUSHALIASEDFIELD, */ hb_p_default, /* HB_P_MPUSHALIASEDVAR, */ hb_p_default, /* HB_P_MPUSHBLOCK, */ hb_p_default, /* HB_P_MPUSHFIELD, */ hb_p_default, /* HB_P_MPUSHMEMVAR, */ hb_p_default, /* HB_P_MPUSHMEMVARREF, */ hb_p_default, /* HB_P_MPUSHSYM, */ hb_p_default, /* HB_P_MPUSHVARIABLE, */ /* end: */ hb_p_default, /* HB_P_MULT, */ hb_p_default, /* HB_P_NEGATE, */ hb_p_default, /* HB_P_NOOP, */ hb_p_default, /* HB_P_NOT, */ hb_p_default, /* HB_P_NOTEQUAL, */ hb_p_default, /* HB_P_OR, */ hb_p_default, /* HB_P_PARAMETER, */ hb_p_default, /* HB_P_PLUS, */ hb_p_default, /* HB_P_POP, */ hb_p_default, /* HB_P_POPALIAS, */ hb_p_default, /* HB_P_POPALIASEDFIELD, */ hb_p_default, /* HB_P_POPALIASEDFIELDNEAR, */ hb_p_default, /* HB_P_POPALIASEDVAR, */ hb_p_default, /* HB_P_POPFIELD, */ hb_p_default, /* HB_P_POPLOCAL, */ hb_p_default, /* HB_P_POPLOCALNEAR, */ hb_p_default, /* HB_P_POPMEMVAR, */ hb_p_default, /* HB_P_POPSTATIC, */ hb_p_default, /* HB_P_POPVARIABLE, */ hb_p_default, /* HB_P_POWER, */ hb_p_default, /* HB_P_PUSHALIAS, */ hb_p_default, /* HB_P_PUSHALIASEDFIELD, */ hb_p_default, /* HB_P_PUSHALIASEDFIELDNEAR, */ hb_p_default, /* HB_P_PUSHALIASEDVAR, */ hb_p_pushblock, /* HB_P_PUSHBLOCK, */ hb_p_pushblockshort, /* HB_P_PUSHBLOCKSHORT, */ hb_p_default, /* HB_P_PUSHFIELD, */ hb_p_default, /* HB_P_PUSHBYTE, */ hb_p_default, /* HB_P_PUSHINT, */ hb_p_default, /* HB_P_PUSHLOCAL, */ hb_p_default, /* HB_P_PUSHLOCALNEAR, */ hb_p_default, /* HB_P_PUSHLOCALREF, */ hb_p_default, /* HB_P_PUSHLONG, */ hb_p_default, /* HB_P_PUSHMEMVAR, */ hb_p_default, /* HB_P_PUSHMEMVARREF, */ hb_p_default, /* HB_P_PUSHNIL, */ hb_p_default, /* HB_P_PUSHDOUBLE, */ hb_p_default, /* HB_P_PUSHSELF, */ hb_p_default, /* HB_P_PUSHSTATIC, */ hb_p_default, /* HB_P_PUSHSTATICREF, */ hb_p_pushstr, /* HB_P_PUSHSTR, */ hb_p_pushstrshort, /* HB_P_PUSHSTRSHORT, */ hb_p_default, /* HB_P_PUSHSYM, */ hb_p_default, /* HB_P_PUSHSYMNEAR, */ hb_p_default, /* HB_P_PUSHVARIABLE, */ hb_p_default, /* HB_P_RETVALUE, */ hb_p_default, /* HB_P_SEND, */ hb_p_default, /* HB_P_SENDSHORT, */ hb_p_seqbegin, /* HB_P_SEQBEGIN, */ hb_p_seqend, /* HB_P_SEQEND, */ hb_p_default, /* HB_P_SEQRECOVER, */ hb_p_default, /* HB_P_SFRAME, */ hb_p_default, /* HB_P_STATICS, */ hb_p_staticname, /* HB_P_STATICNAME, */ hb_p_default, /* HB_P_SWAPALIAS, */ hb_p_default, /* HB_P_TRUE, */ hb_p_default, /* HB_P_ZERO, */ hb_p_default, /* HB_P_ONE, */ hb_p_default, /* HB_P_MACROLIST, */ hb_p_default, /* HB_P_MACROLISTEND, */ hb_p_default, /* HB_P_MPUSHSTR, */ hb_p_default, /* HB_P_LOCALNEARADDINT, */ hb_p_default, /* HB_P_MACROPUSHREF */ hb_p_default, /* HB_P_PUSHLONGLONG */ hb_p_default, /* HB_P_ENUMSTART */ hb_p_default, /* HB_P_ENUMNEXT */ hb_p_default, /* HB_P_ENUMPREV */ hb_p_default, /* HB_P_ENUMEND */ hb_p_switch, /* HB_P_SWITCH */ hb_p_default /* HB_P_PUSHDATE */ }; void hb_compCodeTraceMarkDead( PFUNCTION pFunc ) { HB_CODETRACE_INFO code_info; if( ! HB_COMP_ISSUPPORTED(HB_COMPFLAG_OPTJUMP) || pFunc->lPCodePos < 2 ) return; assert( HB_P_LAST_PCODE == sizeof( s_codeTraceFuncTable ) / sizeof( PHB_CODETRACE_FUNC ) ); code_info.plJumps = NULL; code_info.ulJumpPos = 0; code_info.ulJumpSize = 0; code_info.ulJumpCount = 0; code_info.ulPCodeSize = pFunc->lPCodePos; code_info.fFinished = FALSE; code_info.pCodeMark = ( BYTE * ) hb_xgrab( code_info.ulPCodeSize ); memset( code_info.pCodeMark, 0, code_info.ulPCodeSize ); hb_compPCodeTrace( pFunc, ( HB_PCODE_FUNC_PTR * ) s_codeTraceFuncTable, ( void * ) &code_info ); if( code_info.fFinished ) { ULONG ulPos = 0, ulCount = 0; do { if( code_info.pCodeMark[ ulPos ] == 0 ) ++ulCount; else if( ulCount ) { hb_compNOOPfill( pFunc, ulPos - ulCount, ulCount, FALSE, TRUE ); ulCount = 0; } } while( ++ulPos < code_info.ulPCodeSize ); if( ulCount > 1 ) { /* do not strip the last HB_P_ENDBLOCK / HB_P_ENDPROC marker */ --ulPos; --ulCount; /* * We cannot simply decrease size of the generated PCODE here * because jumps or noops tables may point to the this area * and we will have to update also the jump table, [druzus] */ /* pFunc->pCode[ ulPos - ulCount ] = pFunc->pCode[ ulPos - 1 ]; pFunc->lPCodePos = pFunc->lPCodeSize = ulPos - ulCount + 1; */ hb_compNOOPfill( pFunc, ulPos - ulCount, ulCount, FALSE, TRUE ); } } hb_xfree( code_info.pCodeMark ); if( code_info.plJumps ) hb_xfree( code_info.plJumps ); }