xref: /AOO41X/main/basic/source/comp/codegen.cxx (revision e1f63238eb022c8a12b30d46a012444ff20e0951)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_basic.hxx"
26 
27 #include <basic/sbx.hxx>
28 #include "sbcomp.hxx"
29 #include "image.hxx"
30 #include <limits>
31 #include <com/sun/star/script/ModuleType.hpp>
32 
33 // nInc ist die Inkrementgroesse der Puffer
34 
SbiCodeGen(SbModule & r,SbiParser * p,short nInc)35 SbiCodeGen::SbiCodeGen( SbModule& r, SbiParser* p, short nInc )
36          : rMod( r ), aCode( p, nInc )
37 {
38     pParser = p;
39     bStmnt = sal_False;
40     nLine = 0;
41     nCol = 0;
42     nForLevel = 0;
43 }
44 
GetPC()45 sal_uInt32 SbiCodeGen::GetPC()
46 {
47     return aCode.GetSize();
48 }
49 
50 // Statement merken
51 
Statement()52 void SbiCodeGen::Statement()
53 {
54     bStmnt = sal_True;
55 
56     nLine = pParser->GetLine();
57     nCol  = pParser->GetCol1();
58 
59     // #29955 Information der for-Schleifen-Ebene
60     // in oberen Byte der Spalte speichern
61     nCol = (nCol & 0xff) + 0x100 * nForLevel;
62 }
63 
64 // Anfang eines Statements markieren
65 
GenStmnt()66 void SbiCodeGen::GenStmnt()
67 {
68     if( bStmnt )
69     {
70         bStmnt = sal_False;
71         Gen( _STMNT, nLine, nCol );
72     }
73 }
74 
75 // Die Gen-Routinen returnen den Offset des 1. Operanden,
76 // damit Jumps dort ihr Backchain versenken koennen
77 
Gen(SbiOpcode eOpcode)78 sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode )
79 {
80 #ifdef DBG_UTIL
81     if( eOpcode < SbOP0_START || eOpcode > SbOP0_END )
82         pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE1" );
83 #endif
84     GenStmnt();
85     aCode += (sal_uInt8) eOpcode;
86     return GetPC();
87 }
88 
Gen(SbiOpcode eOpcode,sal_uInt32 nOpnd)89 sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd )
90 {
91 #ifdef DBG_UTIL
92     if( eOpcode < SbOP1_START || eOpcode > SbOP1_END )
93         pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE2" );
94 #endif
95     GenStmnt();
96     aCode += (sal_uInt8) eOpcode;
97     sal_uInt32 n = GetPC();
98     aCode += nOpnd;
99     return n;
100 }
101 
Gen(SbiOpcode eOpcode,sal_uInt32 nOpnd1,sal_uInt32 nOpnd2)102 sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd1, sal_uInt32 nOpnd2 )
103 {
104 #ifdef DBG_UTIL
105     if( eOpcode < SbOP2_START || eOpcode > SbOP2_END )
106         pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE3" );
107 #endif
108     GenStmnt();
109     aCode += (sal_uInt8) eOpcode;
110     sal_uInt32 n = GetPC();
111     aCode += nOpnd1;
112     aCode += nOpnd2;
113     return n;
114 }
115 
116 // Abspeichern des erzeugten Images im Modul
117 
Save()118 void SbiCodeGen::Save()
119 {
120     SbiImage* p = new SbiImage;
121     rMod.StartDefinitions();
122     // OPTION BASE-Wert:
123     p->nDimBase = pParser->nBase;
124     // OPTION EXPLICIT-Flag uebernehmen
125     if( pParser->bExplicit )
126         p->SetFlag( SBIMG_EXPLICIT );
127 
128     int nIfaceCount = 0;
129     if( rMod.mnType == com::sun::star::script::ModuleType::CLASS )
130     {
131                 OSL_TRACE("COdeGen::save() classmodule processing");
132         rMod.bIsProxyModule = true;
133         p->SetFlag( SBIMG_CLASSMODULE );
134         pCLASSFAC->AddClassModule( &rMod );
135 
136         nIfaceCount = pParser->aIfaceVector.size();
137         if( !rMod.pClassData )
138             rMod.pClassData = new SbClassData;
139         if( nIfaceCount )
140         {
141             for( int i = 0 ; i < nIfaceCount ; i++ )
142             {
143                 const String& rIfaceName = pParser->aIfaceVector[i];
144                 SbxVariable* pIfaceVar = new SbxVariable( SbxVARIANT );
145                 pIfaceVar->SetName( rIfaceName );
146                 SbxArray* pIfaces = rMod.pClassData->mxIfaces;
147                 pIfaces->Insert( pIfaceVar, pIfaces->Count() );
148             }
149         }
150 
151         rMod.pClassData->maRequiredTypes = pParser->aRequiredTypes;
152     }
153     else
154     {
155         pCLASSFAC->RemoveClassModule( &rMod );
156         // Only a ClassModule can revert to Normal
157                 if ( rMod.mnType == com::sun::star::script::ModuleType::CLASS )
158             rMod.mnType = com::sun::star::script::ModuleType::NORMAL;
159         rMod.bIsProxyModule = false;
160     }
161 
162     if( pParser->bText )
163         p->SetFlag( SBIMG_COMPARETEXT );
164     // GlobalCode-Flag
165     if( pParser->HasGlobalCode() )
166         p->SetFlag( SBIMG_INITCODE );
167     // Die Entrypoints:
168     for( SbiSymDef* pDef = pParser->aPublics.First(); pDef;
169                    pDef = pParser->aPublics.Next() )
170     {
171         SbiProcDef* pProc = pDef->GetProcDef();
172         if( pProc && pProc->IsDefined() )
173         {
174             String aProcName = pProc->GetName();
175             String aIfaceProcName;
176             String aIfaceName;
177             sal_uInt16 nPassCount = 1;
178             if( nIfaceCount )
179             {
180                 int nPropPrefixFound =
181                     aProcName.Search( String( RTL_CONSTASCII_USTRINGPARAM("Property ") ) );
182                 String aPureProcName = aProcName;
183                 String aPropPrefix;
184                 if( nPropPrefixFound == 0 )
185                 {
186                     aPropPrefix = aProcName.Copy( 0, 13 );      // 13 == Len( "Property ?et " )
187                     aPureProcName = aProcName.Copy( 13 );
188                 }
189                 for( int i = 0 ; i < nIfaceCount ; i++ )
190                 {
191                     const String& rIfaceName = pParser->aIfaceVector[i];
192                     int nFound = aPureProcName.Search( rIfaceName );
193                     if( nFound == 0 && '_' == aPureProcName.GetChar( rIfaceName.Len() ) )
194                     {
195                         if( nPropPrefixFound == 0 )
196                             aIfaceProcName += aPropPrefix;
197                         aIfaceProcName += aPureProcName.Copy( rIfaceName.Len() + 1 );
198                         aIfaceName = rIfaceName;
199                         nPassCount = 2;
200                         break;
201                     }
202                 }
203             }
204             SbMethod* pMeth = NULL;
205             for( sal_uInt16 nPass = 0 ; nPass < nPassCount ; nPass++ )
206             {
207                 if( nPass == 1 )
208                     aProcName = aIfaceProcName;
209 
210                 PropertyMode ePropMode = pProc->getPropertyMode();
211                 if( ePropMode != PROPERTY_MODE_NONE )
212                 {
213                     SbxDataType ePropType = SbxEMPTY;
214                     switch( ePropMode )
215                     {
216                         case PROPERTY_MODE_GET:
217                             ePropType = pProc->GetType();
218                             break;
219                         case PROPERTY_MODE_LET:
220                         {
221                             // type == type of first parameter
222                             ePropType = SbxVARIANT;     // Default
223                             SbiSymPool* pPool = &pProc->GetParams();
224                             if( pPool->GetSize() > 1 )
225                             {
226                                 SbiSymDef* pPar = pPool->Get( 1 );
227                                 if( pPar )
228                                     ePropType = pPar->GetType();
229                             }
230                             break;
231                         }
232                         case PROPERTY_MODE_SET:
233                             ePropType = SbxOBJECT;
234                             break;
235                         case PROPERTY_MODE_NONE:
236                             DBG_ERROR( "Illegal PropertyMode PROPERTY_MODE_NONE" );
237                             break;
238                     }
239                     String aPropName = pProc->GetPropName();
240                     if( nPass == 1 )
241                         aPropName = aPropName.Copy( aIfaceName.Len() + 1 );
242                     SbProcedureProperty* pProcedureProperty = NULL;
243                     pProcedureProperty = rMod.GetProcedureProperty( aPropName, ePropType );
244                 }
245                 if( nPass == 1 )
246                 {
247                     SbIfaceMapperMethod* pMapperMeth = NULL;
248                     pMapperMeth = rMod.GetIfaceMapperMethod( aProcName, pMeth );
249                 }
250                 else
251                 {
252                     pMeth = rMod.GetMethod( aProcName, pProc->GetType() );
253 
254                     // #110004
255                     if( !pProc->IsPublic() )
256                         pMeth->SetFlag( SBX_PRIVATE );
257 
258                     // Declare? -> Hidden
259                     if( pProc->GetLib().Len() > 0 )
260                         pMeth->SetFlag( SBX_HIDDEN );
261 
262                     pMeth->nStart = pProc->GetAddr();
263                     pMeth->nLine1 = pProc->GetLine1();
264                     pMeth->nLine2 = pProc->GetLine2();
265                     // Die Parameter:
266                     SbxInfo* pInfo = pMeth->GetInfo();
267                     String aHelpFile, aComment;
268                     sal_uIntPtr nHelpId = 0;
269                     if( pInfo )
270                     {
271                         // Die Zusatzdaten retten
272                         aHelpFile = pInfo->GetHelpFile();
273                         aComment  = pInfo->GetComment();
274                         nHelpId   = pInfo->GetHelpId();
275                     }
276                     // Und die Parameterliste neu aufbauen
277                     pInfo = new SbxInfo( aHelpFile, nHelpId );
278                     pInfo->SetComment( aComment );
279                     SbiSymPool* pPool = &pProc->GetParams();
280                     // Das erste Element ist immer der Funktionswert!
281                     for( sal_uInt16 i = 1; i < pPool->GetSize(); i++ )
282                     {
283                         SbiSymDef* pPar = pPool->Get( i );
284                         SbxDataType t = pPar->GetType();
285                         if( !pPar->IsByVal() )
286                             t = (SbxDataType) ( t | SbxBYREF );
287                         if( pPar->GetDims() )
288                             t = (SbxDataType) ( t | SbxARRAY );
289                         // #33677 Optional-Info durchreichen
290                         sal_uInt16 nFlags = SBX_READ;
291                         if( pPar->IsOptional() )
292                             nFlags |= SBX_OPTIONAL;
293 
294                         pInfo->AddParam( pPar->GetName(), t, nFlags );
295 
296                         sal_uInt32 nUserData = 0;
297                         sal_uInt16 nDefaultId = pPar->GetDefaultId();
298                         if( nDefaultId )
299                             nUserData |= nDefaultId;
300                         if( pPar->IsParamArray() )
301                             nUserData |= PARAM_INFO_PARAMARRAY;
302                         if( pPar->IsWithBrackets() )
303                             nUserData |= PARAM_INFO_WITHBRACKETS;
304                         if( nUserData )
305                         {
306                             SbxParamInfo* pParam = (SbxParamInfo*)pInfo->GetParam( i );
307                             pParam->nUserData = nUserData;
308                         }
309                     }
310                     pMeth->SetInfo( pInfo );
311                 }
312 
313             }   // for( iPass...
314         }
315     }
316     // Der Code
317     p->AddCode( aCode.GetBuffer(), aCode.GetSize() );
318 
319     // Der globale StringPool. 0 ist nicht belegt.
320     SbiStringPool* pPool = &pParser->aGblStrings;
321     sal_uInt16 nSize = pPool->GetSize();
322     p->MakeStrings( nSize );
323     sal_uInt16 i;
324     for( i = 1; i <= nSize; i++ )
325         p->AddString( pPool->Find( i ) );
326 
327     // Typen einfuegen
328     sal_uInt16 nCount = pParser->rTypeArray->Count();
329     for (i = 0; i < nCount; i++)
330          p->AddType((SbxObject *)pParser->rTypeArray->Get(i));
331 
332     // Insert enum objects
333     nCount = pParser->rEnumArray->Count();
334     for (i = 0; i < nCount; i++)
335          p->AddEnum((SbxObject *)pParser->rEnumArray->Get(i));
336 
337     if( !p->IsError() )
338         rMod.pImage = p;
339     else
340         delete p;
341 
342     rMod.EndDefinitions();
343 }
344 
345 template < class T >
346 class PCodeVisitor
347 {
348 public:
349     virtual ~PCodeVisitor();
350 
351     virtual void start( sal_uInt8* pStart ) = 0;
352     virtual void processOpCode0( SbiOpcode eOp ) = 0;
353     virtual void processOpCode1( SbiOpcode eOp, T nOp1 ) = 0;
354     virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 ) = 0;
355     virtual bool processParams() = 0;
356     virtual void end() = 0;
357 };
358 
~PCodeVisitor()359 template <class T> PCodeVisitor< T >::~PCodeVisitor()
360 {}
361 
362 template <class T>
363 class PCodeBufferWalker
364 {
365 private:
366     T  m_nBytes;
367     sal_uInt8* m_pCode;
readParam(sal_uInt8 * & pCode)368     T readParam( sal_uInt8*& pCode )
369     {
370         short nBytes = sizeof( T );
371         T nOp1=0;
372         for ( int i=0; i<nBytes; ++i )
373             nOp1 |= *pCode++ << ( i * 8);
374         return nOp1;
375     }
376 public:
PCodeBufferWalker(sal_uInt8 * pCode,T nBytes)377     PCodeBufferWalker( sal_uInt8* pCode, T nBytes ): m_nBytes( nBytes ), m_pCode( pCode )
378     {
379     }
visitBuffer(PCodeVisitor<T> & visitor)380     void visitBuffer( PCodeVisitor< T >& visitor )
381     {
382         sal_uInt8* pCode = m_pCode;
383         if ( !pCode )
384             return;
385         sal_uInt8* pEnd = pCode + m_nBytes;
386         visitor.start( m_pCode );
387         T nOp1 = 0, nOp2 = 0;
388         for( ; pCode < pEnd; )
389         {
390             SbiOpcode eOp = (SbiOpcode)(*pCode++);
391 
392             if ( eOp <= SbOP0_END )
393                 visitor.processOpCode0( eOp );
394             else if( eOp >= SbOP1_START && eOp <= SbOP1_END )
395             {
396                 if ( visitor.processParams() )
397                     nOp1 = readParam( pCode );
398                 else
399                     pCode += sizeof( T );
400                 visitor.processOpCode1( eOp, nOp1 );
401             }
402             else if( eOp >= SbOP2_START && eOp <= SbOP2_END )
403             {
404                 if ( visitor.processParams() )
405                 {
406                     nOp1 = readParam( pCode );
407                     nOp2 = readParam( pCode );
408                 }
409                 else
410                     pCode += ( sizeof( T ) * 2 );
411                 visitor.processOpCode2( eOp, nOp1, nOp2 );
412             }
413         }
414         visitor.end();
415     }
416 };
417 
418 template < class T, class S >
419 class OffSetAccumulator : public PCodeVisitor< T >
420 {
421     T m_nNumOp0;
422     T m_nNumSingleParams;
423     T m_nNumDoubleParams;
424 public:
425 
OffSetAccumulator()426     OffSetAccumulator() : m_nNumOp0(0), m_nNumSingleParams(0), m_nNumDoubleParams(0){}
start(sal_uInt8 *)427     virtual void start( sal_uInt8* /*pStart*/ ){}
processOpCode0(SbiOpcode)428     virtual void processOpCode0( SbiOpcode /*eOp*/ ){ ++m_nNumOp0; }
processOpCode1(SbiOpcode,T)429     virtual void processOpCode1( SbiOpcode /*eOp*/, T /*nOp1*/ ){  ++m_nNumSingleParams; }
processOpCode2(SbiOpcode,T,T)430     virtual void processOpCode2( SbiOpcode /*eOp*/, T /*nOp1*/, T /*nOp2*/ ) { ++m_nNumDoubleParams; }
end()431     virtual void end(){}
offset()432     S offset()
433     {
434         T result = 0 ;
435         static const S max = std::numeric_limits< S >::max();
436         result = m_nNumOp0 + ( ( sizeof(S) + 1 ) * m_nNumSingleParams ) + ( (( sizeof(S) * 2 )+ 1 )  * m_nNumDoubleParams );
437         if ( result > max )
438             return max;
439 
440         return static_cast<S>(result);
441     }
processParams()442    virtual bool processParams(){ return false; }
443 };
444 
445 
446 
447 template < class T, class S >
448 
449 class BufferTransformer : public PCodeVisitor< T >
450 {
451     sal_uInt8* m_pStart;
452     SbiBuffer m_ConvertedBuf;
453 public:
BufferTransformer()454     BufferTransformer():m_pStart(NULL), m_ConvertedBuf( NULL, 1024 ) {}
start(sal_uInt8 * pStart)455     virtual void start( sal_uInt8* pStart ){ m_pStart = pStart; }
processOpCode0(SbiOpcode eOp)456     virtual void processOpCode0( SbiOpcode eOp )
457     {
458         m_ConvertedBuf += (sal_uInt8)eOp;
459     }
processOpCode1(SbiOpcode eOp,T nOp1)460     virtual void processOpCode1( SbiOpcode eOp, T nOp1 )
461     {
462         m_ConvertedBuf += (sal_uInt8)eOp;
463         switch( eOp )
464         {
465             case _JUMP:
466             case _JUMPT:
467             case _JUMPF:
468             case _GOSUB:
469             case _CASEIS:
470             case _RETURN:
471             case _ERRHDL:
472             case _TESTFOR:
473                 nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
474                 break;
475             case _RESUME:
476                 if ( nOp1 > 1 )
477                     nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
478                 break;
479             default:
480                 break; //
481 
482         }
483         m_ConvertedBuf += (S)nOp1;
484     }
processOpCode2(SbiOpcode eOp,T nOp1,T nOp2)485     virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 )
486     {
487         m_ConvertedBuf += (sal_uInt8)eOp;
488         if ( eOp == _CASEIS )
489                 if ( nOp1 )
490                     nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
491         m_ConvertedBuf += (S)nOp1;
492         m_ConvertedBuf += (S)nOp2;
493 
494     }
processParams()495     virtual bool processParams(){ return true; }
end()496     virtual void end() {}
497     // yeuch, careful here, you can only call
498     // GetBuffer on the returned SbiBuffer once, also
499     // you (as the caller) get to own the memory
buffer()500     SbiBuffer& buffer()
501     {
502         return m_ConvertedBuf;
503     }
convertBufferOffSet(sal_uInt8 * pStart,T nOp1)504     static S convertBufferOffSet( sal_uInt8* pStart, T nOp1 )
505     {
506         PCodeBufferWalker< T > aBuff( pStart, nOp1);
507         OffSetAccumulator< T, S > aVisitor;
508         aBuff.visitBuffer( aVisitor );
509         return aVisitor.offset();
510     }
511 };
512 
513 sal_uInt32
calcNewOffSet(sal_uInt8 * pCode,sal_uInt16 nOffset)514 SbiCodeGen::calcNewOffSet( sal_uInt8* pCode, sal_uInt16 nOffset )
515 {
516     return BufferTransformer< sal_uInt16, sal_uInt32 >::convertBufferOffSet( pCode, nOffset );
517 }
518 
519 sal_uInt16
calcLegacyOffSet(sal_uInt8 * pCode,sal_uInt32 nOffset)520 SbiCodeGen::calcLegacyOffSet( sal_uInt8* pCode, sal_uInt32 nOffset )
521 {
522     return BufferTransformer< sal_uInt32, sal_uInt16 >::convertBufferOffSet( pCode, nOffset );
523 }
524 
525 template <class T, class S>
526 void
convert()527 PCodeBuffConvertor<T,S>::convert()
528 {
529     PCodeBufferWalker< T > aBuf( m_pStart, m_nSize );
530     BufferTransformer< T, S > aTrnsfrmer;
531     aBuf.visitBuffer( aTrnsfrmer );
532     m_pCnvtdBuf = (sal_uInt8*)aTrnsfrmer.buffer().GetBuffer();
533     m_nCnvtdSize = static_cast<S>( aTrnsfrmer.buffer().GetSize() );
534 }
535 
536 template class PCodeBuffConvertor< sal_uInt16, sal_uInt32 >;
537 template class PCodeBuffConvertor< sal_uInt32, sal_uInt16 >;
538