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
