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