Files
harbour-core/harbour/source/vm/dynsym.c
Przemyslaw Czerpak 69503c8a2b 2006-09-03 16:20 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* harbour/include/hboo.ch
    + added HB_OO_CLSTP_PERSIST and HB_OO_MSG_INITIALIZED

  * harbour/include/hbapi.h
  * harbour/include/hbvmpub.h
  * harbour/source/vm/dynsym.c
    % changed HB_HANDLE hArea to USHORT uiArea to reduce HB_DYNS size.
      RDD code internally uses USHORT as area number so it's not
      necessary to keep it as HB_HANDLE value.

  * harbour/source/vm/arrays.c
    * modified internal static function name

  * harbour/source/vm/itemapi.c
    + added missing HB_TRACE in hb_itemClone()

  * harbour/source/vm/classes.c
    ! moved initialization values to separate structure not bound with
      methods. We can inherit the same method names from more then one
      object so we will store only the first one but we are inheriting
      whole instance area which is accessible with super casting (last
      fixes) so we have to properly initialize it even if methods does
      not exist. This modification also fixes some possible memory leaks.
    % replaced bIsPersistent by HB_OO_CLSTP_PERSIST in uiScope in method
      definition
    ! added basic parameter validation to __CLSADDMSG() to avoid some
      possible strange behavior at runtime when broken messages are
      defined.
    * updated __OBJHASMSG() and __OBJSENDMSG() to accept SYMBOL items
      too (@funcName()). Using symbol items it faster then strings.
      Also added support to use non array parametes. F.e. now
         __OBJHASMSG( {||NIL}, "EVAL" )
      returns TRUE
    * some other fixes, reduced memory consumption and speed optimizations
2006-09-03 14:30:26 +00:00

513 lines
15 KiB
C

/*
* $Id$
*/
/*
* Harbour Project source code:
* Dynamic symbol table management
*
* Copyright 1999 Antonio Linares <alinares@fivetech.com>
* 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 "hbvmopt.h"
#include "hbapi.h"
#include "hbapiitm.h"
#include "hbstack.h"
typedef struct
{
PHB_DYNS pDynSym; /* Pointer to dynamic symbol */
} DYNHB_ITEM, * PDYNHB_ITEM, * DYNHB_ITEM_PTR;
static PDYNHB_ITEM s_pDynItems = NULL; /* Pointer to dynamic items */
static USHORT s_uiDynSymbols = 0; /* Number of symbols present */
typedef struct _HB_SYM_HOLDER
{
HB_SYMB symbol;
struct _HB_SYM_HOLDER * pNext;
char szName[ 1 ];
}
HB_SYM_HOLDER, * PHB_SYM_HOLDER;
static PHB_SYM_HOLDER s_pAllocSyms = NULL;
/* Closest symbol for match. hb_dynsymFind() will search for the name. */
/* If it cannot find the name, it positions itself to the */
/* closest symbol. */
static USHORT s_uiClosestDynSym = 0; /* TOFIX: This solution is not thread safe. */
void hb_dynsymLog( void )
{
USHORT uiPos;
HB_TRACE(HB_TR_DEBUG, ("hb_dynsymLog()"));
for( uiPos = 0; uiPos < s_uiDynSymbols; uiPos++ ) /* For all dynamic symbols */
printf( "%i %s\n", uiPos + 1, s_pDynItems[ uiPos ].pDynSym->pSymbol->szName );
}
HB_EXPORT PHB_SYMB hb_symbolNew( char * szName ) /* Create a new symbol */
{
PHB_SYM_HOLDER pHolder;
int iLen;
HB_TRACE(HB_TR_DEBUG, ("hb_symbolNew(%s)", szName));
iLen = strlen( szName );
pHolder = ( PHB_SYM_HOLDER ) hb_xgrab( sizeof( HB_SYM_HOLDER ) + iLen );
memcpy( pHolder->szName, szName, iLen + 1 );
pHolder->pNext = s_pAllocSyms;
s_pAllocSyms = pHolder;
pHolder->symbol.szName = pHolder->szName;
pHolder->symbol.scope.value = 0;
pHolder->symbol.value.pFunPtr = NULL;
pHolder->symbol.pDynSym = NULL;
return &pHolder->symbol;
}
HB_EXPORT PHB_DYNS hb_dynsymNew( PHB_SYMB pSymbol ) /* creates a new dynamic symbol */
{
PHB_DYNS pDynSym;
HB_TRACE(HB_TR_DEBUG, ("hb_dynsymNew(%p)", pSymbol));
pDynSym = hb_dynsymFind( pSymbol->szName ); /* Find position */
if( pDynSym ) /* If name exists */
{
if( ( !pDynSym->pSymbol->value.pFunPtr && pSymbol->value.pFunPtr ) ||
( pSymbol->scope.value & HB_FS_LOCAL ) != 0 )
{
pDynSym->pSymbol = pSymbol;
#ifndef HB_NO_PROFILER
pDynSym->ulCalls = 0; /* profiler support */
pDynSym->ulTime = 0; /* profiler support */
pDynSym->ulRecurse = 0; /* profiler support */
#endif
}
pSymbol->pDynSym = pDynSym; /* place a pointer to DynSym */
return pDynSym; /* Return pointer to DynSym */
}
if( s_uiDynSymbols == 0 ) /* Do we have any symbols ? */
pDynSym = s_pDynItems[ 0 ].pDynSym; /* Point to first symbol */
/* *<1>* Remember we already got this one */
else
{ /* We want more symbols ! */
s_pDynItems = ( PDYNHB_ITEM ) hb_xrealloc( s_pDynItems, ( s_uiDynSymbols + 1 ) * sizeof( DYNHB_ITEM ) );
if( s_uiClosestDynSym <= s_uiDynSymbols ) /* Closest < current !! */
{ /* Here it goes :-) */
USHORT uiPos;
for( uiPos = 0; uiPos < ( s_uiDynSymbols - s_uiClosestDynSym ); uiPos++ )
memcpy( &s_pDynItems[ s_uiDynSymbols - uiPos ],
&s_pDynItems[ s_uiDynSymbols - uiPos - 1 ], sizeof( DYNHB_ITEM ) );
} /* Insert element in array */
pDynSym = ( PHB_DYNS ) hb_xgrab( sizeof( HB_DYNS ) );
s_pDynItems[ s_uiClosestDynSym ].pDynSym = pDynSym; /* Enter DynSym */
}
s_uiDynSymbols++; /* Got one more symbol */
pDynSym->pSymbol = pSymbol;
pDynSym->hMemvar = 0;
pDynSym->uiArea = 0;
pDynSym->uiSymNum = s_uiDynSymbols;
#ifndef HB_NO_PROFILER
pDynSym->ulCalls = 0; /* profiler support */
pDynSym->ulTime = 0; /* profiler support */
pDynSym->ulRecurse = 0; /* profiler support */
#endif
pSymbol->pDynSym = pDynSym; /* place a pointer to DynSym */
return pDynSym;
}
HB_EXPORT PHB_DYNS hb_dynsymGetCase( char * szName ) /* finds and creates a symbol if not found */
{
PHB_DYNS pDynSym;
HB_TRACE(HB_TR_DEBUG, ("hb_dynsymGetCase(%s)", szName));
pDynSym = hb_dynsymFind( szName );
if( ! pDynSym ) /* Does it exists ? */
pDynSym = hb_dynsymNew( hb_symbolNew( szName ) ); /* Make new symbol */
return pDynSym;
}
HB_EXPORT PHB_DYNS hb_dynsymGet( char * szName ) /* finds and creates a symbol if not found */
{
PHB_DYNS pDynSym;
char szUprName[ HB_SYMBOL_NAME_LEN + 1 ];
HB_TRACE(HB_TR_DEBUG, ("hb_dynsymGet(%s)", szName));
/* make a copy as we may get a const string, then turn it to uppercase */
/* NOTE: This block is optimized for speed [vszakats] */
{
int iLen = strlen( szName );
char * pDest = szUprName;
if( iLen > HB_SYMBOL_NAME_LEN )
iLen = HB_SYMBOL_NAME_LEN;
pDest[ iLen ] = '\0';
while( iLen-- )
{
char cChar = *szName++;
if( cChar >= 'a' && cChar <= 'z' )
{
*pDest++ = cChar - ( 'a' - 'A' );
}
else if( cChar == ' ' || cChar == '\t' )
{
*pDest = '\0';
break;
}
else
{
*pDest++ = cChar;
}
}
}
pDynSym = hb_dynsymFind( szUprName );
if( ! pDynSym ) /* Does it exists ? */
pDynSym = hb_dynsymNew( hb_symbolNew( szUprName ) ); /* Make new symbol */
return pDynSym;
}
HB_EXPORT PHB_DYNS hb_dynsymFindName( char * szName ) /* finds a symbol */
{
char szUprName[ HB_SYMBOL_NAME_LEN + 1 ];
HB_TRACE(HB_TR_DEBUG, ("hb_dynsymFindName(%s)", szName));
/* make a copy as we may get a const string, then turn it to uppercase */
/* NOTE: This block is optimized for speed [vszakats] */
{
int iLen = strlen( szName );
char * pDest = szUprName;
if( iLen > HB_SYMBOL_NAME_LEN )
iLen = HB_SYMBOL_NAME_LEN;
pDest[ iLen ] = '\0';
while( iLen-- )
{
char cChar = *szName++;
if( cChar >= 'a' && cChar <= 'z' )
{
*pDest++ = cChar - ( 'a' - 'A' );
}
else if( cChar == ' ' || cChar == '\t' )
{
*pDest = '\0';
break;
}
else
{
*pDest++ = cChar;
}
}
}
return hb_dynsymFind( szUprName );
}
HB_EXPORT PHB_DYNS hb_dynsymFind( char * szName )
{
HB_TRACE(HB_TR_DEBUG, ("hb_dynsymFind(%s)", szName));
if( s_pDynItems == NULL )
{
s_pDynItems = ( PDYNHB_ITEM ) hb_xgrab( sizeof( DYNHB_ITEM ) ); /* Grab array */
s_pDynItems->pDynSym = ( PHB_DYNS ) hb_xgrab( sizeof( HB_DYNS ) );
/* Always grab a first symbol. Never an empty bucket. *<1>* */
memset( s_pDynItems->pDynSym, 0, sizeof( HB_DYNS ) );
return NULL;
}
else
{
/* Classic Tree Insert Sort Mechanism
*
* Insert Sort means the new item is entered alphabetically into
* the array. In this case s_pDynItems !
*
* 1) We start in the middle of the array.
* 2a) If the symbols are equal -> we have found the symbol !!
* Champagne ! We're done.
* b) If the symbol we are looking for ('ge') is greater than the
* middle ('po'), we start looking left.
* Only the first part of the array is going to be searched.
* Go to (1)
* c) If the symbol we are looking for ('ge') is smaller than the
* middle ('ko'), we start looking right
* Only the last part of the array is going to be searched.
* Go to (1)
*/
USHORT uiFirst = 0;
USHORT uiLast = s_uiDynSymbols;
USHORT uiMiddle = uiLast / 2;
s_uiClosestDynSym = uiMiddle; /* Start in the middle */
while( uiFirst < uiLast )
{
int iCmp = strcmp( s_pDynItems[ uiMiddle ].pDynSym->pSymbol->szName, szName );
if( iCmp == 0 )
{
s_uiClosestDynSym = uiMiddle;
return s_pDynItems[ uiMiddle ].pDynSym;
}
else if( iCmp < 0 )
{
uiLast = uiMiddle;
s_uiClosestDynSym = uiMiddle;
}
else /* if( iCmp > 0 ) */
{
uiFirst = uiMiddle + 1;
s_uiClosestDynSym = uiFirst;
}
uiMiddle = uiFirst + ( ( uiLast - uiFirst ) / 2 );
}
}
return NULL;
}
HB_EXPORT PHB_SYMB hb_dynsymGetSymbol( char * szName )
{
HB_TRACE(HB_TR_DEBUG, ("hb_dynsymGetSymbol(%s)", szName));
return hb_dynsymGet( szName )->pSymbol;
}
HB_EXPORT PHB_SYMB hb_dynsymFindSymbol( char * szName )
{
PHB_DYNS pDynSym;
HB_TRACE(HB_TR_DEBUG, ("hb_dynsymFindSymbol(%s)", szName));
pDynSym = hb_dynsymFind( szName );
return pDynSym ? pDynSym->pSymbol : NULL;
}
HB_EXPORT PHB_SYMB hb_dynsymSymbol( PHB_DYNS pDynSym )
{
HB_TRACE(HB_TR_DEBUG, ("hb_dynsymSymbol(%p)", pDynSym));
return pDynSym->pSymbol;
}
HB_EXPORT char * hb_dynsymName( PHB_DYNS pDynSym )
{
HB_TRACE(HB_TR_DEBUG, ("hb_dynsymName(%p)", pDynSym));
return pDynSym->pSymbol->szName;
}
HB_EXPORT HB_HANDLE hb_dynsymMemvarHandle( PHB_DYNS pDynSym )
{
HB_TRACE(HB_TR_DEBUG, ("hb_dynsymMemvarHandle(%p)", pDynSym));
return pDynSym->hMemvar;
}
HB_EXPORT int hb_dynsymAreaHandle( PHB_DYNS pDynSym )
{
HB_TRACE(HB_TR_DEBUG, ("hb_dynsymAreaHandle(%p)", pDynSym));
return pDynSym->uiArea;
}
HB_EXPORT void hb_dynsymSetAreaHandle( PHB_DYNS pDynSym, int iArea )
{
HB_TRACE(HB_TR_DEBUG, ("hb_dynsymSetAreaHandle(%p,%d)", pDynSym, iArea));
pDynSym->uiArea = ( USHORT ) iArea;
}
void hb_dynsymEval( PHB_DYNS_FUNC pFunction, void * Cargo )
{
BOOL bCont = TRUE;
USHORT uiPos;
HB_TRACE(HB_TR_DEBUG, ("hb_dynsymEval(%p, %p)", pFunction, Cargo));
for( uiPos = 0; uiPos < s_uiDynSymbols && bCont; uiPos++ )
bCont = ( pFunction )( s_pDynItems[ uiPos ].pDynSym, Cargo );
}
void hb_dynsymRelease( void )
{
PHB_SYM_HOLDER pHolder;
USHORT uiPos;
HB_TRACE(HB_TR_DEBUG, ("hb_dynsymRelease()"));
for( uiPos = 0; uiPos < s_uiDynSymbols; uiPos++ )
{
hb_xfree( ( s_pDynItems + uiPos )->pDynSym );
}
hb_xfree( s_pDynItems );
s_pDynItems = NULL;
s_uiDynSymbols = 0;
while( s_pAllocSyms )
{
pHolder = s_pAllocSyms;
s_pAllocSyms = s_pAllocSyms->pNext;
hb_xfree( pHolder );
}
}
#ifdef HB_EXTENSION
HB_FUNC( __DYNSCOUNT ) /* How much symbols do we have: dsCount = __dynsymCount() */
{
hb_retnl( ( long ) s_uiDynSymbols );
}
HB_FUNC( __DYNSGETNAME ) /* Get name of symbol: cSymbol = __dynsymGetName( dsIndex ) */
{
long lIndex = hb_parnl( 1 ); /* NOTE: This will return zero if the parameter is not numeric */
if( lIndex >= 1 && lIndex <= s_uiDynSymbols )
hb_retc( s_pDynItems[ lIndex - 1 ].pDynSym->pSymbol->szName );
else
hb_retc( NULL );
}
HB_FUNC( __DYNSGETINDEX ) /* Gimme index number of symbol: dsIndex = __dynsymGetIndex( cSymbol ) */
{
PHB_DYNS pDynSym;
char * szName = hb_parc( 1 );
if( szName )
pDynSym = hb_dynsymFindName( szName );
else
pDynSym = NULL;
if( pDynSym )
hb_retnl( ( long ) ( s_uiClosestDynSym + 1 ) );
else
hb_retnl( 0L );
}
HB_FUNC( __DYNSISFUN ) /* returns .t. if a symbol has a function/procedure pointer,
given its symbol index */
{
long lIndex = hb_parnl( 1 ); /* NOTE: This will return zero if the parameter is not numeric */
if( lIndex >= 1 && lIndex <= s_uiDynSymbols )
hb_retl( s_pDynItems[ lIndex - 1 ].pDynSym->pSymbol->value.pFunPtr != NULL );
else
hb_retl( FALSE );
}
HB_FUNC( __DYNSGETPRF ) /* profiler: It returns an array with a function or procedure
called and consumed times { nTimes, nTime }
, given the dynamic symbol index */
{
#ifndef HB_NO_PROFILER
long lIndex = hb_parnl( 1 ); /* NOTE: This will return zero if the parameter is not numeric */
#endif
hb_reta( 2 );
hb_stornl( 0, -1, 1 );
hb_stornl( 0, -1, 2 );
#ifndef HB_NO_PROFILER
if( lIndex >= 1 && lIndex <= s_uiDynSymbols )
{
if( s_pDynItems[ lIndex - 1 ].pDynSym->pSymbol->value.pFunPtr ) /* it is a function or procedure */
{
hb_stornl( s_pDynItems[ lIndex - 1 ].pDynSym->ulCalls, -1, 1 );
hb_stornl( s_pDynItems[ lIndex - 1 ].pDynSym->ulTime, -1, 2 );
}
}
#endif
}
#endif
HB_FUNC( __DYNSN2PTR )
{
char * szName = hb_parc( 1 );
hb_retptr( szName ? hb_dynsymGet( szName ) : NULL );
}
HB_FUNC( __DYNSN2SYM )
{
char * szName = hb_parc( 1 );
if( szName )
{
hb_itemPutSymbol( hb_stackReturnItem(), hb_dynsymGet( szName )->pSymbol );
}
}
HB_FUNC( __DYNSP2NAME )
{
PHB_DYNS pDynSym = ( PHB_DYNS ) hb_parptr( 1 );
hb_retc( ( pDynSym != NULL ? pDynSym->pSymbol->szName : "" ) );
}