Home | History | Annotate | Download | only in ExecutionEngine
      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