Home | History | Annotate | Download | only in Core
      1 /*
      2  * Copyright 2012, 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 "bcc/Source.h"
     18 
     19 #include <new>
     20 
     21 #include <llvm/ADT/STLExtras.h>
     22 #include <llvm/Bitcode/ReaderWriter.h>
     23 #include <llvm/IR/LLVMContext.h>
     24 #include <llvm/IR/Module.h>
     25 #include <llvm/IR/Verifier.h>
     26 #include <llvm/Linker/Linker.h>
     27 #include <llvm/Support/MemoryBuffer.h>
     28 #include "llvm/Support/raw_ostream.h"
     29 
     30 #include "bcc/BCCContext.h"
     31 #include "bcc/Support/Log.h"
     32 
     33 #include "bcinfo/MetadataExtractor.h"
     34 
     35 #include "BCCContextImpl.h"
     36 
     37 namespace {
     38 
     39 // Helper function to load the bitcode. This uses "bitcode lazy load" feature to
     40 // reduce the startup time. On success, return the LLVM module object created
     41 // and take the ownership of input memory buffer (i.e., pInput). On error,
     42 // return nullptr and will NOT take the ownership of pInput.
     43 static inline std::unique_ptr<llvm::Module> helper_load_bitcode(llvm::LLVMContext &pContext,
     44                                                 std::unique_ptr<llvm::MemoryBuffer> &&pInput) {
     45   llvm::ErrorOr<std::unique_ptr<llvm::Module> > moduleOrError
     46       = llvm::getLazyBitcodeModule(std::move(pInput), pContext);
     47   if (std::error_code ec = moduleOrError.getError()) {
     48     ALOGE("Unable to parse the given bitcode file `%s'! (%s)",
     49           pInput->getBufferIdentifier(), ec.message().c_str());
     50   }
     51 
     52   return std::move(moduleOrError.get());
     53 }
     54 
     55 } // end anonymous namespace
     56 
     57 namespace bcc {
     58 
     59 void Source::setModule(llvm::Module *pModule) {
     60   if (!mNoDelete && (mModule != pModule)) delete mModule;
     61   mModule = pModule;
     62 }
     63 
     64 Source *Source::CreateFromBuffer(BCCContext &pContext,
     65                                  const char *pName,
     66                                  const char *pBitcode,
     67                                  size_t pBitcodeSize) {
     68   llvm::StringRef input_data(pBitcode, pBitcodeSize);
     69   std::unique_ptr<llvm::MemoryBuffer> input_memory =
     70       llvm::MemoryBuffer::getMemBuffer(input_data, "", false);
     71 
     72   if (input_memory == nullptr) {
     73     ALOGE("Unable to load bitcode `%s' from buffer!", pName);
     74     return nullptr;
     75   }
     76 
     77   auto managedModule = helper_load_bitcode(pContext.mImpl->mLLVMContext,
     78                                            std::move(input_memory));
     79 
     80   // Release the managed llvm::Module* since this object gets deleted either in
     81   // the error check below or in ~Source() (since pNoDelete is false).
     82   llvm::Module *module = managedModule.release();
     83   if (module == nullptr) {
     84     return nullptr;
     85   }
     86 
     87   Source *result = CreateFromModule(pContext, pName, *module, /* pNoDelete */false);
     88   if (result == nullptr) {
     89     delete module;
     90   }
     91 
     92   return result;
     93 }
     94 
     95 Source *Source::CreateFromFile(BCCContext &pContext, const std::string &pPath) {
     96 
     97   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> mb_or_error =
     98       llvm::MemoryBuffer::getFile(pPath);
     99   if (mb_or_error.getError()) {
    100     ALOGE("Failed to load bitcode from path %s! (%s)", pPath.c_str(),
    101           mb_or_error.getError().message().c_str());
    102     return nullptr;
    103   }
    104   std::unique_ptr<llvm::MemoryBuffer> input_data = std::move(mb_or_error.get());
    105 
    106   std::unique_ptr<llvm::MemoryBuffer> input_memory(input_data.release());
    107   auto managedModule = helper_load_bitcode(pContext.mImpl->mLLVMContext,
    108                                            std::move(input_memory));
    109 
    110   // Release the managed llvm::Module* since this object gets deleted either in
    111   // the error check below or in ~Source() (since pNoDelete is false).
    112   llvm::Module *module = managedModule.release();
    113   if (module == nullptr) {
    114     return nullptr;
    115   }
    116 
    117   Source *result = CreateFromModule(pContext, pPath.c_str(), *module, /* pNoDelete */false);
    118   if (result == nullptr) {
    119     delete module;
    120   }
    121 
    122   return result;
    123 }
    124 
    125 Source *Source::CreateFromModule(BCCContext &pContext, const char* name, llvm::Module &pModule,
    126                                  bool pNoDelete) {
    127   std::string ErrorInfo;
    128   llvm::raw_string_ostream ErrorStream(ErrorInfo);
    129   pModule.materializeAll();
    130   if (llvm::verifyModule(pModule, &ErrorStream)) {
    131     ALOGE("Bitcode of RenderScript module does not pass verification: `%s'!",
    132           ErrorStream.str().c_str());
    133     return nullptr;
    134   }
    135 
    136   Source *result = new (std::nothrow) Source(name, pContext, pModule, pNoDelete);
    137   if (result == nullptr) {
    138     ALOGE("Out of memory during Source object allocation for `%s'!",
    139           pModule.getModuleIdentifier().c_str());
    140   }
    141   return result;
    142 }
    143 
    144 Source::Source(const char* name, BCCContext &pContext, llvm::Module &pModule,
    145                bool pNoDelete)
    146     : mName(name), mContext(pContext), mModule(&pModule), mMetadata(nullptr),
    147       mNoDelete(pNoDelete), mIsModuleDestroyed(false) {
    148     pContext.addSource(*this);
    149 }
    150 
    151 Source::~Source() {
    152   mContext.removeSource(*this);
    153   if (!mNoDelete && !mIsModuleDestroyed)
    154     delete mModule;
    155   delete mMetadata;
    156 }
    157 
    158 bool Source::merge(Source &pSource) {
    159   // TODO(srhines): Add back logging of actual diagnostics from linking.
    160   if (llvm::Linker::linkModules(*mModule, std::unique_ptr<llvm::Module>(&pSource.getModule())) != 0) {
    161     ALOGE("Failed to link source `%s' with `%s'!",
    162           getIdentifier().c_str(), pSource.getIdentifier().c_str());
    163     return false;
    164   }
    165   // pSource.getModule() is destroyed after linking.
    166   pSource.markModuleDestroyed();
    167 
    168   return true;
    169 }
    170 
    171 Source *Source::CreateEmpty(BCCContext &pContext, const std::string &pName) {
    172   // Create an empty module
    173   llvm::Module *module =
    174       new (std::nothrow) llvm::Module(pName, pContext.mImpl->mLLVMContext);
    175 
    176   if (module == nullptr) {
    177     ALOGE("Out of memory when creating empty LLVM module `%s'!", pName.c_str());
    178     return nullptr;
    179   }
    180 
    181   Source *result = CreateFromModule(pContext, pName.c_str(), *module, /* pNoDelete */false);
    182   if (result == nullptr) {
    183     delete module;
    184   }
    185 
    186   return result;
    187 }
    188 
    189 const std::string &Source::getIdentifier() const {
    190   return mModule->getModuleIdentifier();
    191 }
    192 
    193 void Source::addBuildChecksumMetadata(const char *buildChecksum) const {
    194     llvm::LLVMContext &context = mContext.mImpl->mLLVMContext;
    195     llvm::MDString *val = llvm::MDString::get(context, buildChecksum);
    196     llvm::NamedMDNode *node =
    197         mModule->getOrInsertNamedMetadata("#rs_build_checksum");
    198     node->addOperand(llvm::MDNode::get(context, val));
    199 }
    200 
    201 bool Source::getDebugInfoEnabled() const {
    202   return mModule->getNamedMetadata("llvm.dbg.cu") != nullptr;
    203 }
    204 
    205 bool Source::extractMetadata() {
    206   mMetadata = new bcinfo::MetadataExtractor(mModule);
    207   return mMetadata->extract();
    208 }
    209 
    210 } // namespace bcc
    211