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