Source.cpp revision 579361346abc6696c805e3904a18178ebce4e4a3
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/Bitcode/ReaderWriter.h> 22#include <llvm/IR/LLVMContext.h> 23#include <llvm/IR/Module.h> 24#include <llvm/IR/Verifier.h> 25#include <llvm/Linker/Linker.h> 26#include <llvm/Support/MemoryBuffer.h> 27#include "llvm/Support/raw_ostream.h" 28 29#include "bcc/BCCContext.h" 30#include "bcc/Support/Log.h" 31 32#include "BCCContextImpl.h" 33 34namespace { 35 36// Helper function to load the bitcode. This uses "bitcode lazy load" feature to 37// reduce the startup time. On success, return the LLVM module object created 38// and take the ownership of input memory buffer (i.e., pInput). On error, 39// return nullptr and will NOT take the ownership of pInput. 40static inline llvm::Module *helper_load_bitcode(llvm::LLVMContext &pContext, 41 std::unique_ptr<llvm::MemoryBuffer> &&pInput) { 42 llvm::ErrorOr<llvm::Module *> moduleOrError = llvm::getLazyBitcodeModule(std::move(pInput), pContext); 43 if (std::error_code ec = moduleOrError.getError()) { 44 ALOGE("Unable to parse the given bitcode file `%s'! (%s)", 45 pInput->getBufferIdentifier(), ec.message().c_str()); 46 } 47 48 return moduleOrError.get(); 49} 50 51} // end anonymous namespace 52 53namespace bcc { 54 55void Source::setModule(llvm::Module *pModule) { 56 if (!mNoDelete && (mModule != pModule)) delete mModule; 57 mModule = pModule; 58} 59 60Source *Source::CreateFromBuffer(BCCContext &pContext, 61 const char *pName, 62 const char *pBitcode, 63 size_t pBitcodeSize) { 64 llvm::StringRef input_data(pBitcode, pBitcodeSize); 65 std::unique_ptr<llvm::MemoryBuffer> input_memory = 66 llvm::MemoryBuffer::getMemBuffer(input_data, "", false); 67 68 if (input_memory == nullptr) { 69 ALOGE("Unable to load bitcode `%s' from buffer!", pName); 70 return nullptr; 71 } 72 73 llvm::Module *module = helper_load_bitcode(pContext.mImpl->mLLVMContext, 74 std::move(input_memory)); 75 if (module == nullptr) { 76 return nullptr; 77 } 78 79 Source *result = CreateFromModule(pContext, *module, /* pNoDelete */false); 80 if (result == nullptr) { 81 delete module; 82 } 83 84 return result; 85} 86 87Source *Source::CreateFromFile(BCCContext &pContext, const std::string &pPath) { 88 89 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> mb_or_error = 90 llvm::MemoryBuffer::getFile(pPath); 91 if (mb_or_error.getError()) { 92 ALOGE("Failed to load bitcode from path %s! (%s)", pPath.c_str(), 93 mb_or_error.getError().message().c_str()); 94 return nullptr; 95 } 96 std::unique_ptr<llvm::MemoryBuffer> input_data = std::move(mb_or_error.get()); 97 98 std::unique_ptr<llvm::MemoryBuffer> input_memory(input_data.release()); 99 llvm::Module *module = helper_load_bitcode(pContext.mImpl->mLLVMContext, 100 std::move(input_memory)); 101 if (module == nullptr) { 102 return nullptr; 103 } 104 105 Source *result = CreateFromModule(pContext, *module, /* pNoDelete */false); 106 if (result == nullptr) { 107 delete module; 108 } 109 110 return result; 111} 112 113Source *Source::CreateFromModule(BCCContext &pContext, llvm::Module &pModule, 114 bool pNoDelete) { 115 std::string ErrorInfo; 116 llvm::raw_string_ostream ErrorStream(ErrorInfo); 117 if (llvm::verifyModule(pModule, &ErrorStream)) { 118 ALOGE("Bitcode of RenderScript module does not pass verification: `%s'!", 119 ErrorStream.str().c_str()); 120 return nullptr; 121 } 122 123 Source *result = new (std::nothrow) Source(pContext, pModule, pNoDelete); 124 if (result == nullptr) { 125 ALOGE("Out of memory during Source object allocation for `%s'!", 126 pModule.getModuleIdentifier().c_str()); 127 } 128 return result; 129} 130 131Source::Source(BCCContext &pContext, llvm::Module &pModule, bool pNoDelete) 132 : mContext(pContext), mModule(&pModule), mNoDelete(pNoDelete) { 133 pContext.addSource(*this); 134} 135 136Source::~Source() { 137 mContext.removeSource(*this); 138 if (!mNoDelete) 139 delete mModule; 140} 141 142bool Source::merge(Source &pSource) { 143 // TODO(srhines): Add back logging of actual diagnostics from linking. 144 if (llvm::Linker::LinkModules(mModule, &pSource.getModule()) != 0) { 145 ALOGE("Failed to link source `%s' with `%s'!", 146 getIdentifier().c_str(), pSource.getIdentifier().c_str()); 147 return false; 148 } 149 150 return true; 151} 152 153Source *Source::CreateEmpty(BCCContext &pContext, const std::string &pName) { 154 // Create an empty module 155 llvm::Module *module = 156 new (std::nothrow) llvm::Module(pName, pContext.mImpl->mLLVMContext); 157 158 if (module == nullptr) { 159 ALOGE("Out of memory when creating empty LLVM module `%s'!", pName.c_str()); 160 return nullptr; 161 } 162 163 Source *result = CreateFromModule(pContext, *module, /* pNoDelete */false); 164 if (result == nullptr) { 165 delete module; 166 } 167 168 return result; 169} 170 171const std::string &Source::getIdentifier() const { 172 return mModule->getModuleIdentifier(); 173} 174 175} // namespace bcc 176