xref: /trunk/main/basic/source/comp/codegen.cxx (revision e1f63238)
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