1 /* 2 * copyright 2010, the android open source project 3 * 4 * licensed under the apache license, version 2.0 (the "license"); 5 * you may not use this file except in compliance with the license. 6 * you may obtain a copy of the license at 7 * 8 * http://www.apache.org/licenses/license-2.0 9 * 10 * unless required by applicable law or agreed to in writing, software 11 * distributed under the license is distributed on an "as is" basis, 12 * without warranties or conditions of any kind, either express or implied. 13 * see the license for the specific language governing permissions and 14 * limitations under the license. 15 */ 16 17 #include "Script.h" 18 19 #include "Config.h" 20 21 #if USE_OLD_JIT 22 #include "OldJIT/CacheReader.h" 23 #include "OldJIT/CacheWriter.h" 24 #endif 25 26 #include "MCCacheReader.h" 27 #include "MCCacheWriter.h" 28 29 #if USE_OLD_JIT 30 #include "OldJIT/ContextManager.h" 31 #endif 32 33 #include "DebugHelper.h" 34 #include "FileHandle.h" 35 #include "ScriptCompiled.h" 36 #include "ScriptCached.h" 37 #include "Sha1Helper.h" 38 #include "SourceInfo.h" 39 40 #include <errno.h> 41 #include <sys/stat.h> 42 #include <sys/types.h> 43 44 #include <new> 45 #include <string.h> 46 #include <cutils/properties.h> 47 48 49 namespace { 50 51 bool getBooleanProp(const char *str) { 52 char buf[PROPERTY_VALUE_MAX]; 53 property_get(str, buf, "0"); 54 return strcmp(buf, "0") != 0; 55 } 56 57 } // namespace anonymous 58 59 namespace bcc { 60 61 Script::~Script() { 62 switch (mStatus) { 63 case ScriptStatus::Compiled: 64 delete mCompiled; 65 break; 66 67 #if USE_CACHE 68 case ScriptStatus::Cached: 69 delete mCached; 70 break; 71 #endif 72 73 default: 74 break; 75 } 76 77 for (size_t i = 0; i < 2; ++i) { 78 delete mSourceList[i]; 79 } 80 } 81 82 83 int Script::addSourceBC(size_t idx, 84 char const *resName, 85 const char *bitcode, 86 size_t bitcodeSize, 87 unsigned long flags) { 88 89 if (!resName) { 90 mErrorCode = BCC_INVALID_VALUE; 91 LOGE("Invalid argument: resName = NULL\n"); 92 return 1; 93 } 94 95 if (mStatus != ScriptStatus::Unknown) { 96 mErrorCode = BCC_INVALID_OPERATION; 97 LOGE("Bad operation: Adding source after bccPrepareExecutable\n"); 98 return 1; 99 } 100 101 if (!bitcode) { 102 mErrorCode = BCC_INVALID_VALUE; 103 LOGE("Invalid argument: bitcode = NULL\n"); 104 return 1; 105 } 106 107 mSourceList[idx] = SourceInfo::createFromBuffer(resName, 108 bitcode, bitcodeSize, 109 flags); 110 111 if (!mSourceList[idx]) { 112 mErrorCode = BCC_OUT_OF_MEMORY; 113 LOGE("Out of memory while adding source bitcode\n"); 114 return 1; 115 } 116 117 return 0; 118 } 119 120 121 int Script::addSourceModule(size_t idx, 122 llvm::Module *module, 123 unsigned long flags) { 124 if (mStatus != ScriptStatus::Unknown) { 125 mErrorCode = BCC_INVALID_OPERATION; 126 LOGE("Bad operation: Adding source after bccPrepareExecutable\n"); 127 return 1; 128 } 129 130 if (!module) { 131 mErrorCode = BCC_INVALID_VALUE; 132 LOGE("Invalid argument: module = NULL\n"); 133 return 1; 134 } 135 136 mSourceList[idx] = SourceInfo::createFromModule(module, flags); 137 138 if (!mSourceList[idx]) { 139 mErrorCode = BCC_OUT_OF_MEMORY; 140 LOGE("Out of memory when add source module\n"); 141 return 1; 142 } 143 144 return 0; 145 } 146 147 148 int Script::addSourceFile(size_t idx, 149 char const *path, 150 unsigned long flags) { 151 if (mStatus != ScriptStatus::Unknown) { 152 mErrorCode = BCC_INVALID_OPERATION; 153 LOGE("Bad operation: Adding source after bccPrepareExecutable\n"); 154 return 1; 155 } 156 157 if (!path) { 158 mErrorCode = BCC_INVALID_VALUE; 159 LOGE("Invalid argument: path = NULL\n"); 160 return 1; 161 } 162 163 struct stat sb; 164 if (stat(path, &sb) != 0) { 165 mErrorCode = BCC_INVALID_VALUE; 166 LOGE("File not found: %s\n", path); 167 return 1; 168 } 169 170 mSourceList[idx] = SourceInfo::createFromFile(path, flags); 171 172 if (!mSourceList[idx]) { 173 mErrorCode = BCC_OUT_OF_MEMORY; 174 LOGE("Out of memory while adding source file\n"); 175 return 1; 176 } 177 178 return 0; 179 } 180 181 int Script::prepareSharedObject(char const *cacheDir, 182 char const *cacheName, 183 unsigned long flags) { 184 #if USE_CACHE 185 if (cacheDir && cacheName) { 186 // Set Cache Directory and File Name 187 mCacheDir = cacheDir; 188 mCacheName = cacheName; 189 190 if (!mCacheDir.empty() && *mCacheDir.rbegin() != '/') { 191 mCacheDir.push_back('/'); // Ensure mCacheDir is end with '/' 192 } 193 194 // Check Cache File 195 if (internalLoadCache(true) == 0) { 196 return 0; 197 } 198 } 199 #endif 200 int status = internalCompile(true); 201 if (status != 0) { 202 LOGE("LLVM error message: %s\n", getCompilerErrorMessage()); 203 } 204 return status; 205 } 206 207 208 int Script::prepareExecutable(char const *cacheDir, 209 char const *cacheName, 210 unsigned long flags) { 211 if (mStatus != ScriptStatus::Unknown) { 212 mErrorCode = BCC_INVALID_OPERATION; 213 LOGE("Invalid operation: %s\n", __func__); 214 return 1; 215 } 216 217 #if USE_CACHE 218 if (cacheDir && cacheName) { 219 // Set Cache Directory and File Name 220 mCacheDir = cacheDir; 221 mCacheName = cacheName; 222 223 if (!mCacheDir.empty() && *mCacheDir.rbegin() != '/') { 224 mCacheDir.push_back('/'); // Ensure mCacheDir is end with '/' 225 } 226 227 // Load Cache File 228 if (internalLoadCache(false) == 0) { 229 return 0; 230 } 231 } 232 #endif 233 234 int status = internalCompile(false); 235 if (status != 0) { 236 LOGE("LLVM error message: %s\n", getCompilerErrorMessage()); 237 } 238 return status; 239 } 240 241 242 #if USE_CACHE 243 int Script::internalLoadCache(bool checkOnly) { 244 if (getBooleanProp("debug.bcc.nocache")) { 245 // Android system environment property disable the cache mechanism by 246 // setting "debug.bcc.nocache". So we will not load the cache file any 247 // way. 248 return 1; 249 } 250 251 if (mCacheDir.empty() || mCacheName.empty()) { 252 // The application developer has not specify the cachePath, so 253 // we don't know where to open the cache file. 254 return 1; 255 } 256 257 #if USE_OLD_JIT 258 std::string objPath(mCacheDir + mCacheName + ".jit-image"); 259 std::string infoPath(mCacheDir + mCacheName + ".oBCC"); // TODO: .info instead 260 #elif USE_MCJIT 261 std::string objPath(mCacheDir + mCacheName + ".o"); 262 std::string infoPath(mCacheDir + mCacheName + ".info"); 263 #endif 264 265 FileHandle objFile; 266 if (objFile.open(objPath.c_str(), OpenMode::Read) < 0) { 267 // Unable to open the executable file in read mode. 268 return 1; 269 } 270 271 FileHandle infoFile; 272 if (infoFile.open(infoPath.c_str(), OpenMode::Read) < 0) { 273 // Unable to open the metadata information file in read mode. 274 return 1; 275 } 276 277 #if USE_OLD_JIT 278 CacheReader reader; 279 #elif USE_MCJIT 280 MCCacheReader reader; 281 282 // Register symbol lookup function 283 if (mpExtSymbolLookupFn) { 284 reader.registerSymbolCallback(mpExtSymbolLookupFn, 285 mpExtSymbolLookupFnContext); 286 } 287 #endif 288 289 // Dependencies 290 reader.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1); 291 reader.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS); 292 293 for (size_t i = 0; i < 2; ++i) { 294 if (mSourceList[i]) { 295 mSourceList[i]->introDependency(reader); 296 } 297 } 298 299 if (checkOnly) 300 return !reader.checkCacheFile(&objFile, &infoFile, this); 301 302 // Read cache file 303 ScriptCached *cached = reader.readCacheFile(&objFile, &infoFile, this); 304 305 if (!cached) { 306 mIsContextSlotNotAvail = reader.isContextSlotNotAvail(); 307 return 1; 308 } 309 310 mCached = cached; 311 mStatus = ScriptStatus::Cached; 312 313 // Dirty hack for libRS. 314 // TODO(all): This dirty hack should be removed in the future. 315 if (!cached->isLibRSThreadable() && mpExtSymbolLookupFn) { 316 mpExtSymbolLookupFn(mpExtSymbolLookupFnContext, "__clearThreadable"); 317 } 318 319 return 0; 320 } 321 #endif 322 323 int Script::internalCompile(bool compileOnly) { 324 // Create the ScriptCompiled object 325 mCompiled = new (std::nothrow) ScriptCompiled(this); 326 327 if (!mCompiled) { 328 mErrorCode = BCC_OUT_OF_MEMORY; 329 LOGE("Out of memory: %s %d\n", __FILE__, __LINE__); 330 return 1; 331 } 332 333 mStatus = ScriptStatus::Compiled; 334 335 // Register symbol lookup function 336 if (mpExtSymbolLookupFn) { 337 mCompiled->registerSymbolCallback(mpExtSymbolLookupFn, 338 mpExtSymbolLookupFnContext); 339 } 340 341 // Parse Bitcode File (if necessary) 342 for (size_t i = 0; i < 2; ++i) { 343 if (mSourceList[i] && mSourceList[i]->prepareModule(mCompiled) != 0) { 344 LOGE("Unable to parse bitcode for source[%lu]\n", (unsigned long)i); 345 return 1; 346 } 347 } 348 349 // Set the main source module 350 if (!mSourceList[0] || !mSourceList[0]->getModule()) { 351 LOGE("Source bitcode is not setted.\n"); 352 return 1; 353 } 354 355 if (mCompiled->readModule(mSourceList[0]->takeModule()) != 0) { 356 LOGE("Unable to read source module\n"); 357 return 1; 358 } 359 360 // Link the source module with the library module 361 if (mSourceList[1]) { 362 if (mCompiled->linkModule(mSourceList[1]->takeModule()) != 0) { 363 LOGE("Unable to link library module\n"); 364 return 1; 365 } 366 } 367 368 // Compile and JIT the code 369 if (mCompiled->compile(compileOnly) != 0) { 370 LOGE("Unable to compile.\n"); 371 return 1; 372 } 373 374 #if USE_CACHE 375 // Note: If we re-compile the script because the cached context slot not 376 // available, then we don't have to write the cache. 377 378 // Note: If the address of the context is not in the context slot, then 379 // we don't have to cache it. 380 381 if (!mCacheDir.empty() && 382 !mCacheName.empty() && 383 #if USE_OLD_JIT 384 !mIsContextSlotNotAvail && 385 ContextManager::get().isManagingContext(getContext()) && 386 #endif 387 !getBooleanProp("debug.bcc.nocache")) { 388 389 #if USE_OLD_JIT 390 std::string objPath(mCacheDir + mCacheName + ".jit-image"); 391 std::string infoPath(mCacheDir + mCacheName + ".oBCC"); 392 #elif USE_MCJIT 393 std::string objPath(mCacheDir + mCacheName + ".o"); 394 std::string infoPath(mCacheDir + mCacheName + ".info"); 395 #endif 396 397 398 // Remove the file if it already exists before writing the new file. 399 // The old file may still be mapped elsewhere in memory and we do not want 400 // to modify its contents. (The same script may be running concurrently in 401 // the same process or a different process!) 402 ::unlink(objPath.c_str()); 403 #if !USE_OLD_JIT && USE_MCJIT 404 ::unlink(infoPath.c_str()); 405 #endif 406 407 FileHandle objFile; 408 FileHandle infoFile; 409 410 if (objFile.open(objPath.c_str(), OpenMode::Write) >= 0 && 411 infoFile.open(infoPath.c_str(), OpenMode::Write) >= 0) { 412 413 #if USE_OLD_JIT 414 CacheWriter writer; 415 #elif USE_MCJIT 416 MCCacheWriter writer; 417 #endif 418 419 #ifdef TARGET_BUILD 420 // Dependencies 421 writer.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1); 422 writer.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS); 423 #endif 424 425 for (size_t i = 0; i < 2; ++i) { 426 if (mSourceList[i]) { 427 mSourceList[i]->introDependency(writer); 428 } 429 } 430 431 // libRS is threadable dirty hack 432 // TODO: This should be removed in the future 433 uint32_t libRS_threadable = 0; 434 if (mpExtSymbolLookupFn) { 435 libRS_threadable = 436 (uint32_t)mpExtSymbolLookupFn(mpExtSymbolLookupFnContext, 437 "__isThreadable"); 438 } 439 440 if (!writer.writeCacheFile(&objFile, &infoFile, this, libRS_threadable)) { 441 objFile.truncate(); 442 objFile.close(); 443 444 if (unlink(objPath.c_str()) != 0) { 445 LOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n", 446 objPath.c_str(), strerror(errno)); 447 } 448 449 infoFile.truncate(); 450 infoFile.close(); 451 452 if (unlink(infoPath.c_str()) != 0) { 453 LOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n", 454 infoPath.c_str(), strerror(errno)); 455 } 456 } 457 } 458 } 459 #endif // USE_CACHE 460 461 return 0; 462 } 463 464 465 char const *Script::getCompilerErrorMessage() { 466 if (mStatus != ScriptStatus::Compiled) { 467 mErrorCode = BCC_INVALID_OPERATION; 468 return NULL; 469 } 470 471 return mCompiled->getCompilerErrorMessage(); 472 } 473 474 475 void *Script::lookup(const char *name) { 476 switch (mStatus) { 477 case ScriptStatus::Compiled: { 478 return mCompiled->lookup(name); 479 } 480 481 #if USE_CACHE 482 case ScriptStatus::Cached: { 483 return mCached->lookup(name); 484 } 485 #endif 486 487 default: { 488 mErrorCode = BCC_INVALID_OPERATION; 489 return NULL; 490 } 491 } 492 } 493 494 495 size_t Script::getExportVarCount() const { 496 switch (mStatus) { 497 case ScriptStatus::Compiled: { 498 return mCompiled->getExportVarCount(); 499 } 500 501 #if USE_CACHE 502 case ScriptStatus::Cached: { 503 return mCached->getExportVarCount(); 504 } 505 #endif 506 507 default: { 508 return 0; 509 } 510 } 511 } 512 513 514 size_t Script::getExportFuncCount() const { 515 switch (mStatus) { 516 case ScriptStatus::Compiled: { 517 return mCompiled->getExportFuncCount(); 518 } 519 520 #if USE_CACHE 521 case ScriptStatus::Cached: { 522 return mCached->getExportFuncCount(); 523 } 524 #endif 525 526 default: { 527 return 0; 528 } 529 } 530 } 531 532 533 size_t Script::getPragmaCount() const { 534 switch (mStatus) { 535 case ScriptStatus::Compiled: { 536 return mCompiled->getPragmaCount(); 537 } 538 539 #if USE_CACHE 540 case ScriptStatus::Cached: { 541 return mCached->getPragmaCount(); 542 } 543 #endif 544 545 default: { 546 return 0; 547 } 548 } 549 } 550 551 552 size_t Script::getFuncCount() const { 553 switch (mStatus) { 554 case ScriptStatus::Compiled: { 555 return mCompiled->getFuncCount(); 556 } 557 558 #if USE_CACHE 559 case ScriptStatus::Cached: { 560 return mCached->getFuncCount(); 561 } 562 #endif 563 564 default: { 565 return 0; 566 } 567 } 568 } 569 570 571 size_t Script::getObjectSlotCount() const { 572 switch (mStatus) { 573 case ScriptStatus::Compiled: { 574 return mCompiled->getObjectSlotCount(); 575 } 576 577 #if USE_CACHE 578 case ScriptStatus::Cached: { 579 return mCached->getObjectSlotCount(); 580 } 581 #endif 582 583 default: { 584 return 0; 585 } 586 } 587 } 588 589 590 void Script::getExportVarList(size_t varListSize, void **varList) { 591 switch (mStatus) { 592 #define DELEGATE(STATUS) \ 593 case ScriptStatus::STATUS: \ 594 m##STATUS->getExportVarList(varListSize, varList); \ 595 break; 596 597 #if USE_CACHE 598 DELEGATE(Cached); 599 #endif 600 601 DELEGATE(Compiled); 602 #undef DELEGATE 603 604 default: { 605 mErrorCode = BCC_INVALID_OPERATION; 606 } 607 } 608 } 609 610 void Script::getExportVarNameList(std::vector<std::string> &varList) { 611 switch (mStatus) { 612 case ScriptStatus::Compiled: { 613 return mCompiled->getExportVarNameList(varList); 614 } 615 616 default: { 617 mErrorCode = BCC_INVALID_OPERATION; 618 } 619 } 620 } 621 622 623 void Script::getExportFuncList(size_t funcListSize, void **funcList) { 624 switch (mStatus) { 625 #define DELEGATE(STATUS) \ 626 case ScriptStatus::STATUS: \ 627 m##STATUS->getExportFuncList(funcListSize, funcList); \ 628 break; 629 630 #if USE_CACHE 631 DELEGATE(Cached); 632 #endif 633 634 DELEGATE(Compiled); 635 #undef DELEGATE 636 637 default: { 638 mErrorCode = BCC_INVALID_OPERATION; 639 } 640 } 641 } 642 643 void Script::getExportFuncNameList(std::vector<std::string> &funcList) { 644 switch (mStatus) { 645 case ScriptStatus::Compiled: { 646 return mCompiled->getExportFuncNameList(funcList); 647 } 648 649 default: { 650 mErrorCode = BCC_INVALID_OPERATION; 651 } 652 } 653 } 654 655 656 void Script::getPragmaList(size_t pragmaListSize, 657 char const **keyList, 658 char const **valueList) { 659 switch (mStatus) { 660 #define DELEGATE(STATUS) \ 661 case ScriptStatus::STATUS: \ 662 m##STATUS->getPragmaList(pragmaListSize, keyList, valueList); \ 663 break; 664 665 #if USE_CACHE 666 DELEGATE(Cached); 667 #endif 668 669 DELEGATE(Compiled); 670 #undef DELEGATE 671 672 default: { 673 mErrorCode = BCC_INVALID_OPERATION; 674 } 675 } 676 } 677 678 679 void Script::getFuncInfoList(size_t funcInfoListSize, 680 FuncInfo *funcInfoList) { 681 switch (mStatus) { 682 #define DELEGATE(STATUS) \ 683 case ScriptStatus::STATUS: \ 684 m##STATUS->getFuncInfoList(funcInfoListSize, funcInfoList); \ 685 break; 686 687 #if USE_CACHE 688 DELEGATE(Cached); 689 #endif 690 691 DELEGATE(Compiled); 692 #undef DELEGATE 693 694 default: { 695 mErrorCode = BCC_INVALID_OPERATION; 696 } 697 } 698 } 699 700 701 void Script::getObjectSlotList(size_t objectSlotListSize, 702 uint32_t *objectSlotList) { 703 switch (mStatus) { 704 #define DELEGATE(STATUS) \ 705 case ScriptStatus::STATUS: \ 706 m##STATUS->getObjectSlotList(objectSlotListSize, objectSlotList); \ 707 break; 708 709 #if USE_CACHE 710 DELEGATE(Cached); 711 #endif 712 713 DELEGATE(Compiled); 714 #undef DELEGATE 715 716 default: { 717 mErrorCode = BCC_INVALID_OPERATION; 718 } 719 } 720 } 721 722 723 #if USE_OLD_JIT 724 char *Script::getContext() { 725 switch (mStatus) { 726 727 #if USE_CACHE 728 case ScriptStatus::Cached: { 729 return mCached->getContext(); 730 } 731 #endif 732 733 case ScriptStatus::Compiled: { 734 return mCompiled->getContext(); 735 } 736 737 default: { 738 mErrorCode = BCC_INVALID_OPERATION; 739 return NULL; 740 } 741 } 742 } 743 #endif 744 745 746 int Script::registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) { 747 mpExtSymbolLookupFn = pFn; 748 mpExtSymbolLookupFnContext = pContext; 749 750 if (mStatus != ScriptStatus::Unknown) { 751 mErrorCode = BCC_INVALID_OPERATION; 752 LOGE("Invalid operation: %s\n", __func__); 753 return 1; 754 } 755 return 0; 756 } 757 758 #if USE_MCJIT 759 size_t Script::getELFSize() const { 760 switch (mStatus) { 761 case ScriptStatus::Compiled: { 762 return mCompiled->getELFSize(); 763 } 764 765 default: { 766 return 0; 767 } 768 } 769 } 770 771 const char *Script::getELF() const { 772 switch (mStatus) { 773 case ScriptStatus::Compiled: { 774 return mCompiled->getELF(); 775 } 776 777 default: { 778 return NULL; 779 } 780 } 781 } 782 #endif 783 784 } // namespace bcc 785