Files
libreoffice/basic/source/comp/codegen.cxx
Jens-Heiner Rechtien 94ed655741 INTEGRATION: CWS gcc430 (1.18.30); FILE MERGED
2007/12/13 10:21:16 cmc 1.18.30.1: #i84499# gcc 4.3.0 is better at not generated unneeded templates, and like all compilers handles each .cxx file seperately so cannot know that the template code to generate the needed methods from is in a different .cxx so we have to force that method to be generated
2008-01-04 12:06:18 +00:00

545 lines
17 KiB
C++

/*************************************************************************
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: codegen.cxx,v $
*
* $Revision: 1.19 $
*
* last change: $Author: hr $ $Date: 2008-01-04 13:06:18 $
*
* The Contents of this file are made available subject to
* the terms of GNU Lesser General Public License Version 2.1.
*
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2005 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
************************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_basic.hxx"
#include <basic/sbx.hxx>
#include "sbcomp.hxx"
#include "image.hxx"
#include <limits>
// nInc ist die Inkrementgroesse der Puffer
SbiCodeGen::SbiCodeGen( SbModule& r, SbiParser* p, short nInc )
: rMod( r ), aCode( p, nInc )
{
pParser = p;
bStmnt = FALSE;
nLine = 0;
nCol = 0;
nForLevel = 0;
}
UINT32 SbiCodeGen::GetPC()
{
return aCode.GetSize();
}
// Statement merken
void SbiCodeGen::Statement()
{
bStmnt = TRUE;
nLine = pParser->GetLine();
nCol = pParser->GetCol1();
// #29955 Information der for-Schleifen-Ebene
// in oberen Byte der Spalte speichern
nCol = (nCol & 0xff) + 0x100 * nForLevel;
}
// Anfang eines Statements markieren
void SbiCodeGen::GenStmnt()
{
if( bStmnt )
{
bStmnt = FALSE;
Gen( _STMNT, nLine, nCol );
}
}
// Die Gen-Routinen returnen den Offset des 1. Operanden,
// damit Jumps dort ihr Backchain versenken koennen
UINT32 SbiCodeGen::Gen( SbiOpcode eOpcode )
{
#ifndef PRODUCT
if( eOpcode < SbOP0_START || eOpcode > SbOP0_END )
pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE1" );
#endif
GenStmnt();
aCode += (UINT8) eOpcode;
return GetPC();
}
UINT32 SbiCodeGen::Gen( SbiOpcode eOpcode, UINT32 nOpnd )
{
#ifndef PRODUCT
if( eOpcode < SbOP1_START || eOpcode > SbOP1_END )
pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE2" );
#endif
GenStmnt();
aCode += (UINT8) eOpcode;
UINT32 n = GetPC();
aCode += nOpnd;
return n;
}
UINT32 SbiCodeGen::Gen( SbiOpcode eOpcode, UINT32 nOpnd1, UINT32 nOpnd2 )
{
#ifndef PRODUCT
if( eOpcode < SbOP2_START || eOpcode > SbOP2_END )
pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE3" );
#endif
GenStmnt();
aCode += (UINT8) eOpcode;
UINT32 n = GetPC();
aCode += nOpnd1;
aCode += nOpnd2;
return n;
}
// Abspeichern des erzeugten Images im Modul
void SbiCodeGen::Save()
{
SbiImage* p = new SbiImage;
rMod.StartDefinitions();
// OPTION BASE-Wert:
p->nDimBase = pParser->nBase;
// OPTION EXPLICIT-Flag uebernehmen
if( pParser->bExplicit )
p->SetFlag( SBIMG_EXPLICIT );
if( pParser->IsVBASupportOn() )
p->SetFlag( SBIMG_VBASUPPORT );
int nIfaceCount = 0;
if( pParser->bClassModule )
{
p->SetFlag( SBIMG_CLASSMODULE );
pCLASSFAC->AddClassModule( &rMod );
nIfaceCount = pParser->aIfaceVector.size();
if( nIfaceCount )
{
if( !rMod.pClassData )
rMod.pClassData = new SbClassData;
for( int i = 0 ; i < nIfaceCount ; i++ )
{
const String& rIfaceName = pParser->aIfaceVector[i];
SbxVariable* pIfaceVar = new SbxVariable( SbxVARIANT );
pIfaceVar->SetName( rIfaceName );
SbxArray* pIfaces = rMod.pClassData->mxIfaces;
pIfaces->Insert( pIfaceVar, pIfaces->Count() );
}
}
}
else
{
pCLASSFAC->RemoveClassModule( &rMod );
}
if( pParser->bText )
p->SetFlag( SBIMG_COMPARETEXT );
// GlobalCode-Flag
if( pParser->HasGlobalCode() )
p->SetFlag( SBIMG_INITCODE );
// Die Entrypoints:
for( SbiSymDef* pDef = pParser->aPublics.First(); pDef;
pDef = pParser->aPublics.Next() )
{
SbiProcDef* pProc = pDef->GetProcDef();
if( pProc && pProc->IsDefined() )
{
String aProcName = pProc->GetName();
String aIfaceProcName;
String aIfaceName;
USHORT nPassCount = 1;
if( nIfaceCount )
{
int nPropPrefixFound =
aProcName.Search( String( RTL_CONSTASCII_USTRINGPARAM("Property ") ) );
String aPureProcName = aProcName;
String aPropPrefix;
if( nPropPrefixFound == 0 )
{
aPropPrefix = aProcName.Copy( 0, 13 ); // 13 == Len( "Property ?et " )
aPureProcName = aProcName.Copy( 13 );
}
for( int i = 0 ; i < nIfaceCount ; i++ )
{
const String& rIfaceName = pParser->aIfaceVector[i];
int nFound = aPureProcName.Search( rIfaceName );
if( nFound == 0 && '_' == aPureProcName.GetChar( rIfaceName.Len() ) )
{
if( nPropPrefixFound == 0 )
aIfaceProcName += aPropPrefix;
aIfaceProcName += aPureProcName.Copy( rIfaceName.Len() + 1 );
aIfaceName = rIfaceName;
nPassCount = 2;
break;
}
}
}
SbMethod* pMeth = NULL;
for( USHORT nPass = 0 ; nPass < nPassCount ; nPass++ )
{
if( nPass == 1 )
aProcName = aIfaceProcName;
PropertyMode ePropMode = pProc->getPropertyMode();
if( ePropMode != PROPERTY_MODE_NONE )
{
SbxDataType ePropType = SbxEMPTY;
switch( ePropMode )
{
case PROPERTY_MODE_GET:
ePropType = pProc->GetType();
break;
case PROPERTY_MODE_LET:
{
// type == type of first parameter
ePropType = SbxVARIANT; // Default
SbiSymPool* pPool = &pProc->GetParams();
if( pPool->GetSize() > 1 )
{
SbiSymDef* pPar = pPool->Get( 1 );
if( pPar )
ePropType = pPar->GetType();
}
break;
}
case PROPERTY_MODE_SET:
ePropType = SbxOBJECT;
break;
case PROPERTY_MODE_NONE:
DBG_ERROR( "Illegal PropertyMode PROPERTY_MODE_NONE" );
break;
}
String aPropName = pProc->GetPropName();
if( nPass == 1 )
aPropName = aPropName.Copy( aIfaceName.Len() + 1 );
SbProcedureProperty* pProcedureProperty = NULL;
pProcedureProperty = rMod.GetProcedureProperty( aPropName, ePropType );
}
if( nPass == 1 )
{
SbIfaceMapperMethod* pMapperMeth = NULL;
pMapperMeth = rMod.GetIfaceMapperMethod( aProcName, pMeth );
}
else
{
pMeth = rMod.GetMethod( aProcName, pProc->GetType() );
// #110004
if( !pProc->IsPublic() )
pMeth->SetFlag( SBX_PRIVATE );
pMeth->nStart = pProc->GetAddr();
pMeth->nLine1 = pProc->GetLine1();
pMeth->nLine2 = pProc->GetLine2();
// Die Parameter:
SbxInfo* pInfo = pMeth->GetInfo();
String aHelpFile, aComment;
ULONG nHelpId = 0;
if( pInfo )
{
// Die Zusatzdaten retten
aHelpFile = pInfo->GetHelpFile();
aComment = pInfo->GetComment();
nHelpId = pInfo->GetHelpId();
}
// Und die Parameterliste neu aufbauen
pInfo = new SbxInfo( aHelpFile, nHelpId );
pInfo->SetComment( aComment );
SbiSymPool* pPool = &pProc->GetParams();
// Das erste Element ist immer der Funktionswert!
for( USHORT i = 1; i < pPool->GetSize(); i++ )
{
SbiSymDef* pPar = pPool->Get( i );
SbxDataType t = pPar->GetType();
if( !pPar->IsByVal() )
t = (SbxDataType) ( t | SbxBYREF );
if( pPar->GetDims() )
t = (SbxDataType) ( t | SbxARRAY );
// #33677 Optional-Info durchreichen
USHORT nFlags = SBX_READ;
if( pPar->IsOptional() )
nFlags |= SBX_OPTIONAL;
pInfo->AddParam( pPar->GetName(), t, nFlags );
UINT32 nUserData = 0;
USHORT nDefaultId = pPar->GetDefaultId();
if( nDefaultId )
nUserData |= nDefaultId;
if( pPar->IsParamArray() )
nUserData |= PARAM_INFO_PARAMARRAY;
if( nUserData )
{
SbxParamInfo* pParam = (SbxParamInfo*)pInfo->GetParam( i );
pParam->nUserData = nUserData;
}
}
pMeth->SetInfo( pInfo );
}
} // for( iPass...
}
}
// Der Code
p->AddCode( aCode.GetBuffer(), aCode.GetSize() );
// Der globale StringPool. 0 ist nicht belegt.
SbiStringPool* pPool = &pParser->aGblStrings;
USHORT nSize = pPool->GetSize();
p->MakeStrings( nSize );
USHORT i;
for( i = 1; i <= nSize; i++ )
p->AddString( pPool->Find( i ) );
// Typen einfuegen
USHORT nCount = pParser->rTypeArray->Count();
for (i = 0; i < nCount; i++)
p->AddType((SbxObject *)pParser->rTypeArray->Get(i));
// Insert enum objects
nCount = pParser->rEnumArray->Count();
for (i = 0; i < nCount; i++)
p->AddEnum((SbxObject *)pParser->rEnumArray->Get(i));
if( !p->IsError() )
rMod.pImage = p;
else
delete p;
rMod.EndDefinitions();
}
template < class T >
class PCodeVisitor
{
public:
virtual ~PCodeVisitor();
virtual void start( BYTE* pStart ) = 0;
virtual void processOpCode0( SbiOpcode eOp ) = 0;
virtual void processOpCode1( SbiOpcode eOp, T nOp1 ) = 0;
virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 ) = 0;
virtual bool processParams() = 0;
virtual void end() = 0;
};
template <class T> PCodeVisitor< T >::~PCodeVisitor()
{}
template <class T>
class PCodeBufferWalker
{
private:
T m_nBytes;
BYTE* m_pCode;
T readParam( BYTE*& pCode )
{
short nBytes = sizeof( T );
T nOp1=0;
for ( int i=0; i<nBytes; ++i )
nOp1 |= *pCode++ << ( i * 8);
return nOp1;
}
public:
PCodeBufferWalker( BYTE* pCode, T nBytes ): m_nBytes( nBytes ), m_pCode( pCode )
{
}
void visitBuffer( PCodeVisitor< T >& visitor )
{
BYTE* pCode = m_pCode;
if ( !pCode )
return;
BYTE* pEnd = pCode + m_nBytes;
visitor.start( m_pCode );
T nOp1 = 0, nOp2 = 0;
for( ; pCode < pEnd; )
{
SbiOpcode eOp = (SbiOpcode)(*pCode++);
if ( eOp <= SbOP0_END )
visitor.processOpCode0( eOp );
else if( eOp >= SbOP1_START && eOp <= SbOP1_END )
{
if ( visitor.processParams() )
nOp1 = readParam( pCode );
else
pCode += sizeof( T );
visitor.processOpCode1( eOp, nOp1 );
}
else if( eOp >= SbOP2_START && eOp <= SbOP2_END )
{
if ( visitor.processParams() )
{
nOp1 = readParam( pCode );
nOp2 = readParam( pCode );
}
else
pCode += ( sizeof( T ) * 2 );
visitor.processOpCode2( eOp, nOp1, nOp2 );
}
}
visitor.end();
}
};
template < class T, class S >
class OffSetAccumulator : public PCodeVisitor< T >
{
T m_nNumOp0;
T m_nNumSingleParams;
T m_nNumDoubleParams;
public:
OffSetAccumulator() : m_nNumOp0(0), m_nNumSingleParams(0), m_nNumDoubleParams(0){}
virtual void start( BYTE* /*pStart*/ ){}
virtual void processOpCode0( SbiOpcode /*eOp*/ ){ ++m_nNumOp0; }
virtual void processOpCode1( SbiOpcode /*eOp*/, T /*nOp1*/ ){ ++m_nNumSingleParams; }
virtual void processOpCode2( SbiOpcode /*eOp*/, T /*nOp1*/, T /*nOp2*/ ) { ++m_nNumDoubleParams; }
virtual void end(){}
S offset()
{
T result = 0 ;
static const S max = std::numeric_limits< S >::max();
result = m_nNumOp0 + ( ( sizeof(S) + 1 ) * m_nNumSingleParams ) + ( (( sizeof(S) * 2 )+ 1 ) * m_nNumDoubleParams );
if ( result > max )
return max;
return static_cast<S>(result);
}
virtual bool processParams(){ return false; }
};
template < class T, class S >
class BufferTransformer : public PCodeVisitor< T >
{
BYTE* m_pStart;
SbiBuffer m_ConvertedBuf;
public:
BufferTransformer():m_pStart(NULL), m_ConvertedBuf( NULL, 1024 ) {}
virtual void start( BYTE* pStart ){ m_pStart = pStart; }
virtual void processOpCode0( SbiOpcode eOp )
{
m_ConvertedBuf += (UINT8)eOp;
}
virtual void processOpCode1( SbiOpcode eOp, T nOp1 )
{
m_ConvertedBuf += (UINT8)eOp;
switch( eOp )
{
case _JUMP:
case _JUMPT:
case _JUMPF:
case _GOSUB:
case _CASEIS:
case _RETURN:
case _ERRHDL:
case _TESTFOR:
nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
break;
case _RESUME:
if ( nOp1 > 1 )
nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
break;
default:
break; //
}
m_ConvertedBuf += (S)nOp1;
}
virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 )
{
m_ConvertedBuf += (UINT8)eOp;
if ( eOp == _CASEIS )
if ( nOp1 )
nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
m_ConvertedBuf += (S)nOp1;
m_ConvertedBuf += (S)nOp2;
}
virtual bool processParams(){ return true; }
virtual void end() {}
// yeuch, careful here, you can only call
// GetBuffer on the returned SbiBuffer once, also
// you (as the caller) get to own the memory
SbiBuffer& buffer()
{
return m_ConvertedBuf;
}
static S convertBufferOffSet( BYTE* pStart, T nOp1 )
{
PCodeBufferWalker< T > aBuff( pStart, nOp1);
OffSetAccumulator< T, S > aVisitor;
aBuff.visitBuffer( aVisitor );
return aVisitor.offset();
}
};
UINT32
SbiCodeGen::calcNewOffSet( BYTE* pCode, UINT16 nOffset )
{
return BufferTransformer< UINT16, UINT32 >::convertBufferOffSet( pCode, nOffset );
}
UINT16
SbiCodeGen::calcLegacyOffSet( BYTE* pCode, UINT32 nOffset )
{
return BufferTransformer< UINT32, UINT16 >::convertBufferOffSet( pCode, nOffset );
}
template <class T, class S>
void
PCodeBuffConvertor<T,S>::convert()
{
PCodeBufferWalker< T > aBuf( m_pStart, m_nSize );
BufferTransformer< T, S > aTrnsfrmer;
aBuf.visitBuffer( aTrnsfrmer );
m_pCnvtdBuf = (BYTE*)aTrnsfrmer.buffer().GetBuffer();
m_nCnvtdSize = static_cast<S>( aTrnsfrmer.buffer().GetSize() );
}
void NeverRunsEver()
{
// force instatiation of templates... I dunno why, but I have to do
// this to force instatiation of the template. Otherwise using the template
// in another code module results in link errors :-(
PCodeBuffConvertor< UINT16, UINT32 > aInst1(0,0);
aInst1.convert();
PCodeBuffConvertor< UINT32, UINT16 > aInst2(0,0);
aInst2.convert();
}