xref: /core/basic/source/comp/codegen.cxx (revision 754c6af4)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
21 #include <basic/sbx.hxx>
22 #include <image.hxx>
23 #include <codegen.hxx>
24 #include <parser.hxx>
25 #include <cstddef>
26 #include <limits>
27 #include <algorithm>
28 #include <string_view>
29 #include <osl/diagnose.h>
30 #include <rtl/ustrbuf.hxx>
31 #include <com/sun/star/script/ModuleType.hpp>
32 
33 // nInc is the increment size of the buffers
34 
35 SbiCodeGen::SbiCodeGen( SbModule& r, SbiParser* p, short nInc )
36          : rMod( r ), aCode( p, nInc )
37 {
38     pParser = p;
39     bStmnt = false;
40     nLine = 0;
41     nCol = 0;
42     nForLevel = 0;
43 }
44 
45 sal_uInt32 SbiCodeGen::GetPC()
46 {
47     return aCode.GetSize();
48 }
49 
50 // memorize the statement
51 
52 void SbiCodeGen::Statement()
53 {
54     if( pParser->IsCodeCompleting() )
55         return;
56 
57     bStmnt = true;
58 
59     nLine = pParser->GetLine();
60     nCol  = pParser->GetCol1();
61 
62     // #29955 Store the information of the for-loop-layer
63     // in the upper Byte of the column
64     nCol = (nCol & 0xff) + 0x100 * nForLevel;
65 }
66 
67 // Mark the beginning of a statement
68 
69 void SbiCodeGen::GenStmnt()
70 {
71     if( pParser->IsCodeCompleting() )
72         return;
73 
74     if( bStmnt )
75     {
76         bStmnt = false;
77         Gen( SbiOpcode::STMNT_, nLine, nCol );
78     }
79 }
80 
81 // The Gen-Routines return the offset of the 1. operand,
82 // so that jumps can sink their backchain there.
83 
84 sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode )
85 {
86     if( pParser->IsCodeCompleting() )
87         return 0;
88 
89 #ifdef DBG_UTIL
90     if( eOpcode < SbiOpcode::SbOP0_START || eOpcode > SbiOpcode::SbOP0_END )
91         pParser->Error( ERRCODE_BASIC_INTERNAL_ERROR, "OPCODE1" );
92 #endif
93     GenStmnt();
94     aCode += static_cast<sal_uInt8>(eOpcode);
95     return GetPC();
96 }
97 
98 sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd )
99 {
100     if( pParser->IsCodeCompleting() )
101         return 0;
102 
103 #ifdef DBG_UTIL
104     if( eOpcode < SbiOpcode::SbOP1_START || eOpcode > SbiOpcode::SbOP1_END )
105         pParser->Error( ERRCODE_BASIC_INTERNAL_ERROR, "OPCODE2" );
106 #endif
107     GenStmnt();
108     aCode += static_cast<sal_uInt8>(eOpcode);
109     sal_uInt32 n = GetPC();
110     aCode += nOpnd;
111     return n;
112 }
113 
114 sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd1, sal_uInt32 nOpnd2 )
115 {
116     if( pParser->IsCodeCompleting() )
117         return 0;
118 
119 #ifdef DBG_UTIL
120     if( eOpcode < SbiOpcode::SbOP2_START || eOpcode > SbiOpcode::SbOP2_END )
121         pParser->Error( ERRCODE_BASIC_INTERNAL_ERROR, "OPCODE3" );
122 #endif
123     GenStmnt();
124     aCode += static_cast<sal_uInt8>(eOpcode);
125     sal_uInt32 n = GetPC();
126     aCode += nOpnd1;
127     aCode += nOpnd2;
128     return n;
129 }
130 
131 // Storing of the created image in the module
132 
133 void SbiCodeGen::Save()
134 {
135     if( pParser->IsCodeCompleting() )
136         return;
137 
138     std::unique_ptr<SbiImage> p( new SbiImage );
139     rMod.StartDefinitions();
140     // OPTION BASE-Value:
141     p->nDimBase = pParser->nBase;
142     // OPTION take over the EXPLICIT-Flag
143     if( pParser->bExplicit )
144         p->SetFlag( SbiImageFlags::EXPLICIT );
145 
146     int nIfaceCount = 0;
147     if( rMod.mnType == css::script::ModuleType::CLASS )
148     {
149         rMod.bIsProxyModule = true;
150         p->SetFlag( SbiImageFlags::CLASSMODULE );
151         GetSbData()->pClassFac->AddClassModule( &rMod );
152 
153         nIfaceCount = pParser->aIfaceVector.size();
154         if( !rMod.pClassData )
155             rMod.pClassData.reset( new SbClassData );
156         if( nIfaceCount )
157         {
158             for( int i = 0 ; i < nIfaceCount ; i++ )
159             {
160                 const OUString& rIfaceName = pParser->aIfaceVector[i];
161                 SbxVariable* pIfaceVar = new SbxVariable( SbxVARIANT );
162                 pIfaceVar->SetName( rIfaceName );
163                 SbxArray* pIfaces = rMod.pClassData->mxIfaces.get();
164                 pIfaces->Insert( pIfaceVar, pIfaces->Count() );
165             }
166         }
167 
168         rMod.pClassData->maRequiredTypes = pParser->aRequiredTypes;
169     }
170     else
171     {
172         GetSbData()->pClassFac->RemoveClassModule( &rMod );
173         // Only a ClassModule can revert to Normal
174         if ( rMod.mnType == css::script::ModuleType::CLASS )
175         {
176             rMod.mnType = css::script::ModuleType::NORMAL;
177         }
178         rMod.bIsProxyModule = false;
179     }
180 
181     // GlobalCode-Flag
182     if( pParser->HasGlobalCode() )
183     {
184         p->SetFlag( SbiImageFlags::INITCODE );
185     }
186     // The entry points:
187     for( SbiSymDef* pDef = pParser->aPublics.First(); pDef;
188          pDef = pParser->aPublics.Next() )
189     {
190         SbiProcDef* pProc = pDef->GetProcDef();
191         if( pProc && pProc->IsDefined() )
192         {
193             OUString aProcName = pProc->GetName();
194             OUStringBuffer aIfaceProcName;
195             OUString aIfaceName;
196             sal_uInt16 nPassCount = 1;
197             if( nIfaceCount )
198             {
199                 int nPropPrefixFound = aProcName.indexOf("Property ");
200                 OUString aPureProcName = aProcName;
201                 OUString aPropPrefix;
202                 if( nPropPrefixFound == 0 )
203                 {
204                     aPropPrefix = aProcName.copy( 0, 13 );      // 13 == Len( "Property ?et " )
205                     aPureProcName = aProcName.copy( 13 );
206                 }
207                 for( int i = 0 ; i < nIfaceCount ; i++ )
208                 {
209                     const OUString& rIfaceName = pParser->aIfaceVector[i];
210                     int nFound = aPureProcName.indexOf( rIfaceName );
211                     if( nFound == 0 && aPureProcName[rIfaceName.getLength()] == '_' )
212                     {
213                         if( nPropPrefixFound == 0 )
214                         {
215                             aIfaceProcName.append(aPropPrefix);
216                         }
217                         aIfaceProcName.append(std::u16string_view(aPureProcName).substr(rIfaceName.getLength() + 1) );
218                         aIfaceName = rIfaceName;
219                         nPassCount = 2;
220                         break;
221                     }
222                 }
223             }
224             SbMethod* pMeth = nullptr;
225             for( sal_uInt16 nPass = 0 ; nPass < nPassCount ; nPass++ )
226             {
227                 if( nPass == 1 )
228                 {
229                     aProcName = aIfaceProcName.toString();
230                 }
231                 PropertyMode ePropMode = pProc->getPropertyMode();
232                 if( ePropMode != PropertyMode::NONE )
233                 {
234                     SbxDataType ePropType = SbxEMPTY;
235                     switch( ePropMode )
236                     {
237                     case PropertyMode::Get:
238                         ePropType = pProc->GetType();
239                         break;
240                     case PropertyMode::Let:
241                     {
242                         // type == type of first parameter
243                         ePropType = SbxVARIANT;     // Default
244                         SbiSymPool* pPool = &pProc->GetParams();
245                         if( pPool->GetSize() > 1 )
246                         {
247                             SbiSymDef* pPar = pPool->Get( 1 );
248                             if( pPar )
249                             {
250                                 ePropType = pPar->GetType();
251                             }
252                         }
253                         break;
254                     }
255                     case PropertyMode::Set:
256                         ePropType = SbxOBJECT;
257                         break;
258                     default:
259                         OSL_FAIL("Illegal PropertyMode");
260                         break;
261                     }
262                     OUString aPropName = pProc->GetPropName();
263                     if( nPass == 1 )
264                     {
265                         aPropName = aPropName.copy( aIfaceName.getLength() + 1 );
266                     }
267                     rMod.GetProcedureProperty( aPropName, ePropType );
268                 }
269                 if( nPass == 1 )
270                 {
271                     rMod.GetIfaceMapperMethod( aProcName, pMeth );
272                 }
273                 else
274                 {
275                     pMeth = rMod.GetMethod( aProcName, pProc->GetType() );
276 
277                     if( !pProc->IsPublic() )
278                     {
279                         pMeth->SetFlag( SbxFlagBits::Private );
280                     }
281                     // Declare? -> Hidden
282                     if( !pProc->GetLib().isEmpty())
283                     {
284                         pMeth->SetFlag( SbxFlagBits::Hidden );
285                     }
286                     pMeth->nStart = pProc->GetAddr();
287                     pMeth->nLine1 = pProc->GetLine1();
288                     pMeth->nLine2 = pProc->GetLine2();
289                     // The parameter:
290                     SbxInfo* pInfo = pMeth->GetInfo();
291                     OUString aHelpFile, aComment;
292                     sal_uInt32 nHelpId = 0;
293                     if( pInfo )
294                     {
295                         // Rescue the additional data
296                         aHelpFile = pInfo->GetHelpFile();
297                         aComment  = pInfo->GetComment();
298                         nHelpId   = pInfo->GetHelpId();
299                     }
300                     // And reestablish the parameter list
301                     pInfo = new SbxInfo( aHelpFile, nHelpId );
302                     pInfo->SetComment( aComment );
303                     SbiSymPool* pPool = &pProc->GetParams();
304                     // The first element is always the value of the function!
305                     for( sal_uInt16 i = 1; i < pPool->GetSize(); i++ )
306                     {
307                         SbiSymDef* pPar = pPool->Get( i );
308                         SbxDataType t = pPar->GetType();
309                         if( !pPar->IsByVal() )
310                         {
311                             t = static_cast<SbxDataType>( t | SbxBYREF );
312                         }
313                         if( pPar->GetDims() )
314                         {
315                             t = static_cast<SbxDataType>( t | SbxARRAY );
316                         }
317                         // #33677 hand-over an Optional-Info
318                         SbxFlagBits nFlags = SbxFlagBits::Read;
319                         if( pPar->IsOptional() )
320                         {
321                             nFlags |= SbxFlagBits::Optional;
322                         }
323                         pInfo->AddParam( pPar->GetName(), t, nFlags );
324 
325                         sal_uInt32 nUserData = 0;
326                         sal_uInt16 nDefaultId = pPar->GetDefaultId();
327                         if( nDefaultId )
328                         {
329                             nUserData |= nDefaultId;
330                         }
331                         if( pPar->IsParamArray() )
332                         {
333                             nUserData |= PARAM_INFO_PARAMARRAY;
334                         }
335                         if( pPar->IsWithBrackets() )
336                         {
337                             nUserData |= PARAM_INFO_WITHBRACKETS;
338                         }
339                         SbxParamInfo* pParam = nullptr;
340                         if( nUserData )
341                         {
342                             pParam = const_cast<SbxParamInfo*>(pInfo->GetParam( i ));
343                         }
344                         if( pParam )
345                         {
346                             pParam->nUserData = nUserData;
347                         }
348                     }
349                     pMeth->SetInfo( pInfo );
350                 }
351             }   // for( iPass...
352         }
353     }
354     // The code
355     p->AddCode( std::unique_ptr<char[]>(aCode.GetBuffer()), aCode.GetSize() );
356 
357     // The global StringPool. 0 is not occupied.
358     SbiStringPool* pPool = &pParser->aGblStrings;
359     sal_uInt16 nSize = pPool->GetSize();
360     p->MakeStrings( nSize );
361     sal_uInt16 i;
362     for( i = 1; i <= nSize; i++ )
363     {
364         p->AddString( pPool->Find( i ) );
365     }
366     // Insert types
367     sal_uInt16 nCount = pParser->rTypeArray->Count();
368     for (i = 0; i < nCount; i++)
369     {
370          p->AddType(static_cast<SbxObject *>(pParser->rTypeArray->Get(i)));
371     }
372     // Insert enum objects
373     nCount = pParser->rEnumArray->Count();
374     for (i = 0; i < nCount; i++)
375     {
376          p->AddEnum(static_cast<SbxObject *>(pParser->rEnumArray->Get(i)));
377     }
378     if( !p->IsError() )
379     {
380         rMod.pImage = std::move(p);
381     }
382     rMod.EndDefinitions();
383 }
384 
385 template < class T >
386 class PCodeVisitor
387 {
388 public:
389     virtual ~PCodeVisitor();
390 
391     virtual void start( const sal_uInt8* pStart ) = 0;
392     virtual void processOpCode0( SbiOpcode eOp ) = 0;
393     virtual void processOpCode1( SbiOpcode eOp, T nOp1 ) = 0;
394     virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 ) = 0;
395     virtual bool processParams() = 0;
396 };
397 
398 template <class T> PCodeVisitor< T >::~PCodeVisitor()
399 {}
400 
401 template <class T>
402 class PCodeBufferWalker
403 {
404 private:
405     T  m_nBytes;
406     const sal_uInt8* m_pCode;
407     static T readParam( sal_uInt8 const *& pCode )
408     {
409         T nOp1=0;
410         for ( std::size_t i=0; i<sizeof( T ); ++i )
411             nOp1 |= *pCode++ << ( i * 8);
412         return nOp1;
413     }
414 public:
415     PCodeBufferWalker( const sal_uInt8* pCode, T nBytes ): m_nBytes( nBytes ), m_pCode( pCode )
416     {
417     }
418     void visitBuffer( PCodeVisitor< T >& visitor )
419     {
420         const sal_uInt8* pCode = m_pCode;
421         if ( !pCode )
422             return;
423         const sal_uInt8* pEnd = pCode + m_nBytes;
424         visitor.start( m_pCode );
425         T nOp1 = 0, nOp2 = 0;
426         for( ; pCode < pEnd; )
427         {
428             SbiOpcode eOp = static_cast<SbiOpcode>(*pCode++);
429 
430             if ( eOp <= SbiOpcode::SbOP0_END )
431                 visitor.processOpCode0( eOp );
432             else if( eOp >= SbiOpcode::SbOP1_START && eOp <= SbiOpcode::SbOP1_END )
433             {
434                 if ( visitor.processParams() )
435                     nOp1 = readParam( pCode );
436                 else
437                     pCode += sizeof( T );
438                 visitor.processOpCode1( eOp, nOp1 );
439             }
440             else if( eOp >= SbiOpcode::SbOP2_START && eOp <= SbiOpcode::SbOP2_END )
441             {
442                 if ( visitor.processParams() )
443                 {
444                     nOp1 = readParam( pCode );
445                     nOp2 = readParam( pCode );
446                 }
447                 else
448                     pCode += ( sizeof( T ) * 2 );
449                 visitor.processOpCode2( eOp, nOp1, nOp2 );
450             }
451         }
452     }
453 };
454 
455 template < class T, class S >
456 class OffSetAccumulator : public PCodeVisitor< T >
457 {
458     T m_nNumOp0;
459     T m_nNumSingleParams;
460     T m_nNumDoubleParams;
461 public:
462 
463     OffSetAccumulator() : m_nNumOp0(0), m_nNumSingleParams(0), m_nNumDoubleParams(0){}
464     virtual void start( const sal_uInt8* /*pStart*/ ) override {}
465     virtual void processOpCode0( SbiOpcode /*eOp*/ ) override { ++m_nNumOp0; }
466     virtual void processOpCode1( SbiOpcode /*eOp*/, T /*nOp1*/ ) override {  ++m_nNumSingleParams; }
467     virtual void processOpCode2( SbiOpcode /*eOp*/, T /*nOp1*/, T /*nOp2*/ ) override { ++m_nNumDoubleParams; }
468     S offset()
469     {
470         typedef decltype(T(1) + S(1)) larger_t; // type capable to hold both value ranges of T and S
471         T result = 0 ;
472         static const S max = std::numeric_limits< S >::max();
473         result = m_nNumOp0 + ( ( sizeof(S) + 1 ) * m_nNumSingleParams ) + ( (( sizeof(S) * 2 )+ 1 )  * m_nNumDoubleParams );
474         return std::min<larger_t>(max, result);
475     }
476     virtual bool processParams() override { return false; }
477 };
478 
479 
480 template < class T, class S >
481 class BufferTransformer : public PCodeVisitor< T >
482 {
483     const sal_uInt8* m_pStart;
484     SbiBuffer m_ConvertedBuf;
485 public:
486     BufferTransformer():m_pStart(nullptr), m_ConvertedBuf( nullptr, 1024 ) {}
487     virtual void start( const sal_uInt8* pStart ) override { m_pStart = pStart; }
488     virtual void processOpCode0( SbiOpcode eOp ) override
489     {
490         m_ConvertedBuf += static_cast<sal_uInt8>(eOp);
491     }
492     virtual void processOpCode1( SbiOpcode eOp, T nOp1 ) override
493     {
494         m_ConvertedBuf += static_cast<sal_uInt8>(eOp);
495         switch( eOp )
496         {
497             case SbiOpcode::JUMP_:
498             case SbiOpcode::JUMPT_:
499             case SbiOpcode::JUMPF_:
500             case SbiOpcode::GOSUB_:
501             case SbiOpcode::CASEIS_:
502             case SbiOpcode::RETURN_:
503             case SbiOpcode::ERRHDL_:
504             case SbiOpcode::TESTFOR_:
505                 nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
506                 break;
507             case SbiOpcode::RESUME_:
508                 if ( nOp1 > 1 )
509                     nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
510                 break;
511             default:
512                 break;
513 
514         }
515         m_ConvertedBuf += static_cast<S>(nOp1);
516     }
517     virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 ) override
518     {
519         m_ConvertedBuf += static_cast<sal_uInt8>(eOp);
520         if ( eOp == SbiOpcode::CASEIS_  && nOp1 )
521             nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
522         m_ConvertedBuf += static_cast<S>(nOp1);
523         m_ConvertedBuf += static_cast<S>(nOp2);
524 
525     }
526     virtual bool processParams() override { return true; }
527     // yeuch, careful here, you can only call
528     // GetBuffer on the returned SbiBuffer once, also
529     // you (as the caller) get to own the memory
530     SbiBuffer& buffer()
531     {
532         return m_ConvertedBuf;
533     }
534     static S convertBufferOffSet( const sal_uInt8* pStart, T nOp1 )
535     {
536         PCodeBufferWalker< T > aBuff( pStart, nOp1);
537         OffSetAccumulator< T, S > aVisitor;
538         aBuff.visitBuffer( aVisitor );
539         return aVisitor.offset();
540     }
541 };
542 
543 sal_uInt32
544 SbiCodeGen::calcNewOffSet( sal_uInt8 const * pCode, sal_uInt16 nOffset )
545 {
546     return BufferTransformer< sal_uInt16, sal_uInt32 >::convertBufferOffSet( pCode, nOffset );
547 }
548 
549 sal_uInt16
550 SbiCodeGen::calcLegacyOffSet( sal_uInt8 const * pCode, sal_uInt32 nOffset )
551 {
552     return BufferTransformer< sal_uInt32, sal_uInt16 >::convertBufferOffSet( pCode, nOffset );
553 }
554 
555 template <class T, class S>
556 void
557 PCodeBuffConvertor<T,S>::convert()
558 {
559     PCodeBufferWalker< T > aBuf( m_pStart, m_nSize );
560     BufferTransformer< T, S > aTrnsfrmer;
561     aBuf.visitBuffer( aTrnsfrmer );
562     m_pCnvtdBuf = reinterpret_cast<sal_uInt8*>(aTrnsfrmer.buffer().GetBuffer());
563     m_nCnvtdSize = static_cast<S>( aTrnsfrmer.buffer().GetSize() );
564 }
565 
566 template class PCodeBuffConvertor< sal_uInt16, sal_uInt32 >;
567 template class PCodeBuffConvertor< sal_uInt32, sal_uInt16 >;
568 
569 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
570