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