1 /* 2 * Copyright 2010-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 "Compiler.h" 18 19 #include "Config.h" 20 #include <bcinfo/MetadataExtractor.h> 21 22 #if USE_DISASSEMBLER 23 #include "Disassembler/Disassembler.h" 24 #endif 25 26 #include "DebugHelper.h" 27 #include "FileHandle.h" 28 #include "Runtime.h" 29 #include "ScriptCompiled.h" 30 #include "Sha1Helper.h" 31 #include "CompilerOption.h" 32 33 #include "librsloader.h" 34 35 #include "Transforms/BCCTransforms.h" 36 37 #include "llvm/ADT/StringRef.h" 38 39 #include "llvm/Analysis/Passes.h" 40 41 #include "llvm/CodeGen/Passes.h" 42 #include "llvm/CodeGen/RegAllocRegistry.h" 43 #include "llvm/CodeGen/SchedulerRegistry.h" 44 45 #include "llvm/MC/MCContext.h" 46 #include "llvm/MC/SubtargetFeature.h" 47 48 #include "llvm/Transforms/IPO.h" 49 #include "llvm/Transforms/Scalar.h" 50 51 #include "llvm/Target/TargetData.h" 52 #include "llvm/Target/TargetMachine.h" 53 54 #include "llvm/Support/ErrorHandling.h" 55 #include "llvm/Support/FormattedStream.h" 56 #include "llvm/Support/TargetRegistry.h" 57 #include "llvm/Support/TargetSelect.h" 58 #include "llvm/Support/raw_ostream.h" 59 60 #include "llvm/Constants.h" 61 #include "llvm/GlobalValue.h" 62 #include "llvm/Linker.h" 63 #include "llvm/LLVMContext.h" 64 #include "llvm/Module.h" 65 #include "llvm/PassManager.h" 66 #include "llvm/Type.h" 67 #include "llvm/Value.h" 68 69 #include <errno.h> 70 #include <sys/file.h> 71 #include <sys/stat.h> 72 #include <sys/types.h> 73 #include <unistd.h> 74 75 #include <string.h> 76 77 #include <algorithm> 78 #include <iterator> 79 #include <string> 80 #include <vector> 81 82 extern char* gDebugDumpDirectory; 83 84 namespace bcc { 85 86 ////////////////////////////////////////////////////////////////////////////// 87 // BCC Compiler Static Variables 88 ////////////////////////////////////////////////////////////////////////////// 89 90 bool Compiler::GlobalInitialized = false; 91 92 93 #if !defined(__HOST__) 94 #define TARGET_TRIPLE_STRING DEFAULT_TARGET_TRIPLE_STRING 95 #else 96 // In host TARGET_TRIPLE_STRING is a variable to allow cross-compilation. 97 #if defined(__cplusplus) 98 extern "C" { 99 #endif 100 char *TARGET_TRIPLE_STRING = (char*)DEFAULT_TARGET_TRIPLE_STRING; 101 #if defined(__cplusplus) 102 }; 103 #endif 104 #endif 105 106 // Code generation optimization level for the compiler 107 llvm::CodeGenOpt::Level Compiler::CodeGenOptLevel; 108 109 std::string Compiler::Triple; 110 llvm::Triple::ArchType Compiler::ArchType; 111 112 std::string Compiler::CPU; 113 114 std::vector<std::string> Compiler::Features; 115 116 117 ////////////////////////////////////////////////////////////////////////////// 118 // Compiler 119 ////////////////////////////////////////////////////////////////////////////// 120 121 void Compiler::GlobalInitialization() { 122 if (GlobalInitialized) { 123 return; 124 } 125 126 #if defined(PROVIDE_ARM_CODEGEN) 127 LLVMInitializeARMAsmPrinter(); 128 LLVMInitializeARMTargetMC(); 129 LLVMInitializeARMTargetInfo(); 130 LLVMInitializeARMTarget(); 131 #endif 132 133 #if defined(PROVIDE_MIPS_CODEGEN) 134 LLVMInitializeMipsAsmPrinter(); 135 LLVMInitializeMipsTargetMC(); 136 LLVMInitializeMipsTargetInfo(); 137 LLVMInitializeMipsTarget(); 138 #endif 139 140 #if defined(PROVIDE_X86_CODEGEN) 141 LLVMInitializeX86AsmPrinter(); 142 LLVMInitializeX86TargetMC(); 143 LLVMInitializeX86TargetInfo(); 144 LLVMInitializeX86Target(); 145 #endif 146 147 #if USE_DISASSEMBLER 148 InitializeDisassembler(); 149 #endif 150 151 // if (!llvm::llvm_is_multithreaded()) 152 // llvm::llvm_start_multithreaded(); 153 154 // Set Triple, CPU and Features here 155 Triple = TARGET_TRIPLE_STRING; 156 157 // Determine ArchType 158 #if defined(__HOST__) 159 { 160 std::string Err; 161 llvm::Target const *Target = llvm::TargetRegistry::lookupTarget(Triple, Err); 162 if (Target != NULL) { 163 ArchType = llvm::Triple::getArchTypeForLLVMName(Target->getName()); 164 } else { 165 ArchType = llvm::Triple::UnknownArch; 166 ALOGE("%s", Err.c_str()); 167 } 168 } 169 #elif defined(DEFAULT_ARM_CODEGEN) 170 ArchType = llvm::Triple::arm; 171 #elif defined(DEFAULT_MIPS_CODEGEN) 172 ArchType = llvm::Triple::mipsel; 173 #elif defined(DEFAULT_X86_CODEGEN) 174 ArchType = llvm::Triple::x86; 175 #elif defined(DEFAULT_X86_64_CODEGEN) 176 ArchType = llvm::Triple::x86_64; 177 #else 178 ArchType = llvm::Triple::UnknownArch; 179 #endif 180 181 if ((ArchType == llvm::Triple::arm) || (ArchType == llvm::Triple::thumb)) { 182 # if defined(ARCH_ARM_HAVE_VFP) 183 Features.push_back("+vfp3"); 184 # if !defined(ARCH_ARM_HAVE_VFP_D32) 185 Features.push_back("+d16"); 186 # endif 187 # endif 188 189 # if defined(ARCH_ARM_HAVE_NEON) && !defined(DISABLE_ARCH_ARM_HAVE_NEON) 190 Features.push_back("+neon"); 191 Features.push_back("+neonfp"); 192 # else 193 Features.push_back("-neon"); 194 Features.push_back("-neonfp"); 195 # endif 196 } 197 198 // Register the scheduler 199 llvm::RegisterScheduler::setDefault(llvm::createDefaultScheduler); 200 201 // Read in SHA1 checksum of libbcc and libRS. 202 readSHA1(sha1LibBCC_SHA1, sizeof(sha1LibBCC_SHA1), pathLibBCC_SHA1); 203 204 calcFileSHA1(sha1LibRS, pathLibRS); 205 206 GlobalInitialized = true; 207 } 208 209 210 void Compiler::LLVMErrorHandler(void *UserData, const std::string &Message) { 211 std::string *Error = static_cast<std::string*>(UserData); 212 Error->assign(Message); 213 ALOGE("%s", Message.c_str()); 214 exit(1); 215 } 216 217 218 Compiler::Compiler(ScriptCompiled *result) 219 : mpResult(result), 220 mRSExecutable(NULL), 221 mpSymbolLookupFn(NULL), 222 mpSymbolLookupContext(NULL), 223 mModule(NULL), 224 mHasLinked(false) /* Turn off linker */ { 225 llvm::remove_fatal_error_handler(); 226 llvm::install_fatal_error_handler(LLVMErrorHandler, &mError); 227 return; 228 } 229 230 231 int Compiler::linkModule(llvm::Module *moduleWith) { 232 if (llvm::Linker::LinkModules(mModule, moduleWith, 233 llvm::Linker::PreserveSource, 234 &mError) != 0) { 235 return hasError(); 236 } 237 238 // Everything for linking should be settled down here with no error occurs 239 mHasLinked = true; 240 return hasError(); 241 } 242 243 244 int Compiler::compile(const CompilerOption &option) { 245 llvm::Target const *Target = NULL; 246 llvm::TargetData *TD = NULL; 247 llvm::TargetMachine *TM = NULL; 248 249 std::vector<std::string> ExtraFeatures; 250 251 std::string FeaturesStr; 252 253 if (mModule == NULL) // No module was loaded 254 return 0; 255 256 bcinfo::MetadataExtractor ME(mModule); 257 ME.extract(); 258 259 size_t VarCount = ME.getExportVarCount(); 260 size_t FuncCount = ME.getExportFuncCount(); 261 size_t ForEachSigCount = ME.getExportForEachSignatureCount(); 262 size_t ObjectSlotCount = ME.getObjectSlotCount(); 263 size_t PragmaCount = ME.getPragmaCount(); 264 265 std::vector<std::string> &VarNameList = mpResult->mExportVarsName; 266 std::vector<std::string> &FuncNameList = mpResult->mExportFuncsName; 267 std::vector<std::string> &ForEachExpandList = mpResult->mExportForEachName; 268 std::vector<std::string> ForEachNameList; 269 std::vector<uint32_t> ForEachSigList; 270 std::vector<const char*> ExportSymbols; 271 272 // Defaults to maximum optimization level from MetadataExtractor. 273 uint32_t OptimizationLevel = ME.getOptimizationLevel(); 274 275 if (OptimizationLevel == 0) { 276 CodeGenOptLevel = llvm::CodeGenOpt::None; 277 } else if (OptimizationLevel == 1) { 278 CodeGenOptLevel = llvm::CodeGenOpt::Less; 279 } else if (OptimizationLevel == 2) { 280 CodeGenOptLevel = llvm::CodeGenOpt::Default; 281 } else if (OptimizationLevel == 3) { 282 CodeGenOptLevel = llvm::CodeGenOpt::Aggressive; 283 } 284 285 // not the best place for this, but we need to set the register allocation 286 // policy after we read the optimization_level metadata from the bitcode 287 288 // Register allocation policy: 289 // createFastRegisterAllocator: fast but bad quality 290 // createLinearScanRegisterAllocator: not so fast but good quality 291 llvm::RegisterRegAlloc::setDefault 292 ((CodeGenOptLevel == llvm::CodeGenOpt::None) ? 293 llvm::createFastRegisterAllocator : 294 llvm::createGreedyRegisterAllocator); 295 296 // Find LLVM Target 297 Target = llvm::TargetRegistry::lookupTarget(Triple, mError); 298 if (hasError()) 299 goto on_bcc_compile_error; 300 301 #if defined(ARCH_ARM_HAVE_NEON) 302 // Full-precision means we have to disable NEON 303 if (ME.getRSFloatPrecision() == bcinfo::RS_FP_Full) { 304 ExtraFeatures.push_back("-neon"); 305 ExtraFeatures.push_back("-neonfp"); 306 } 307 #endif 308 309 if (!CPU.empty() || !Features.empty() || !ExtraFeatures.empty()) { 310 llvm::SubtargetFeatures F; 311 312 for (std::vector<std::string>::const_iterator 313 I = Features.begin(), E = Features.end(); I != E; I++) { 314 F.AddFeature(*I); 315 } 316 317 for (std::vector<std::string>::const_iterator 318 I = ExtraFeatures.begin(), E = ExtraFeatures.end(); I != E; I++) { 319 F.AddFeature(*I); 320 } 321 322 FeaturesStr = F.getString(); 323 } 324 325 // Create LLVM Target Machine 326 TM = Target->createTargetMachine(Triple, CPU, FeaturesStr, 327 option.TargetOpt, 328 option.RelocModelOpt, 329 option.CodeModelOpt); 330 331 if (TM == NULL) { 332 setError("Failed to create target machine implementation for the" 333 " specified triple '" + Triple + "'"); 334 goto on_bcc_compile_error; 335 } 336 337 // Get target data from Module 338 TD = new llvm::TargetData(mModule); 339 340 // Read pragma information from MetadataExtractor 341 if (PragmaCount) { 342 ScriptCompiled::PragmaList &PragmaPairs = mpResult->mPragmas; 343 const char **PragmaKeys = ME.getPragmaKeyList(); 344 const char **PragmaValues = ME.getPragmaValueList(); 345 for (size_t i = 0; i < PragmaCount; i++) { 346 PragmaPairs.push_back(std::make_pair(PragmaKeys[i], PragmaValues[i])); 347 } 348 } 349 350 if (VarCount) { 351 const char **VarNames = ME.getExportVarNameList(); 352 for (size_t i = 0; i < VarCount; i++) { 353 VarNameList.push_back(VarNames[i]); 354 ExportSymbols.push_back(VarNames[i]); 355 } 356 } 357 358 if (FuncCount) { 359 const char **FuncNames = ME.getExportFuncNameList(); 360 for (size_t i = 0; i < FuncCount; i++) { 361 FuncNameList.push_back(FuncNames[i]); 362 ExportSymbols.push_back(FuncNames[i]); 363 } 364 } 365 366 if (ForEachSigCount) { 367 const char **ForEachNames = ME.getExportForEachNameList(); 368 const uint32_t *ForEachSigs = ME.getExportForEachSignatureList(); 369 for (size_t i = 0; i < ForEachSigCount; i++) { 370 std::string Name(ForEachNames[i]); 371 ForEachNameList.push_back(Name); 372 ForEachExpandList.push_back(Name + ".expand"); 373 ForEachSigList.push_back(ForEachSigs[i]); 374 } 375 376 // Need to wait until ForEachExpandList is fully populated to fill in 377 // exported symbols. 378 for (size_t i = 0; i < ForEachSigCount; i++) { 379 ExportSymbols.push_back(ForEachExpandList[i].c_str()); 380 } 381 } 382 383 if (ObjectSlotCount) { 384 ScriptCompiled::ObjectSlotList &objectSlotList = mpResult->mObjectSlots; 385 const uint32_t *ObjectSlots = ME.getObjectSlotList(); 386 for (size_t i = 0; i < ObjectSlotCount; i++) { 387 objectSlotList.push_back(ObjectSlots[i]); 388 } 389 } 390 391 runInternalPasses(ForEachNameList, ForEachSigList); 392 393 // Perform link-time optimization if we have multiple modules 394 if (mHasLinked) { 395 runLTO(new llvm::TargetData(*TD), ExportSymbols, CodeGenOptLevel); 396 } 397 398 // Perform code generation 399 if (runMCCodeGen(new llvm::TargetData(*TD), TM) != 0) { 400 goto on_bcc_compile_error; 401 } 402 403 if (!option.LoadAfterCompile) 404 return 0; 405 406 // Load the ELF Object 407 mRSExecutable = 408 rsloaderCreateExec((unsigned char *)&*mEmittedELFExecutable.begin(), 409 mEmittedELFExecutable.size(), 410 &resolveSymbolAdapter, this); 411 412 if (!mRSExecutable) { 413 setError("Fail to load emitted ELF relocatable file"); 414 goto on_bcc_compile_error; 415 } 416 417 rsloaderUpdateSectionHeaders(mRSExecutable, 418 (unsigned char*) mEmittedELFExecutable.begin()); 419 420 // Once the ELF object has been loaded, populate the various slots for RS 421 // with the appropriate relocated addresses. 422 if (VarCount) { 423 ScriptCompiled::ExportVarList &VarList = mpResult->mExportVars; 424 for (size_t i = 0; i < VarCount; i++) { 425 VarList.push_back(rsloaderGetSymbolAddress(mRSExecutable, 426 VarNameList[i].c_str())); 427 } 428 } 429 430 if (FuncCount) { 431 ScriptCompiled::ExportFuncList &FuncList = mpResult->mExportFuncs; 432 for (size_t i = 0; i < FuncCount; i++) { 433 FuncList.push_back(rsloaderGetSymbolAddress(mRSExecutable, 434 FuncNameList[i].c_str())); 435 } 436 } 437 438 if (ForEachSigCount) { 439 ScriptCompiled::ExportForEachList &ForEachList = mpResult->mExportForEach; 440 for (size_t i = 0; i < ForEachSigCount; i++) { 441 ForEachList.push_back(rsloaderGetSymbolAddress(mRSExecutable, 442 ForEachExpandList[i].c_str())); 443 } 444 } 445 446 #if DEBUG_MC_DISASSEMBLER 447 { 448 // Get MC codegen emitted function name list 449 size_t func_list_size = rsloaderGetFuncCount(mRSExecutable); 450 std::vector<char const *> func_list(func_list_size, NULL); 451 rsloaderGetFuncNameList(mRSExecutable, func_list_size, &*func_list.begin()); 452 453 // Disassemble each function 454 for (size_t i = 0; i < func_list_size; ++i) { 455 void *func = rsloaderGetSymbolAddress(mRSExecutable, func_list[i]); 456 if (func) { 457 size_t size = rsloaderGetSymbolSize(mRSExecutable, func_list[i]); 458 Disassemble(DEBUG_MC_DISASSEMBLER_FILE, 459 Target, TM, func_list[i], (unsigned char const *)func, size); 460 } 461 } 462 } 463 #endif 464 465 on_bcc_compile_error: 466 // ALOGE("on_bcc_compiler_error"); 467 if (TD) { 468 delete TD; 469 } 470 471 if (TM) { 472 delete TM; 473 } 474 475 if (mError.empty()) { 476 return 0; 477 } 478 479 // ALOGE(getErrorMessage()); 480 return 1; 481 } 482 483 484 int Compiler::runMCCodeGen(llvm::TargetData *TD, llvm::TargetMachine *TM) { 485 // Decorate mEmittedELFExecutable with formatted ostream 486 llvm::raw_svector_ostream OutSVOS(mEmittedELFExecutable); 487 488 // Relax all machine instructions 489 TM->setMCRelaxAll(/* RelaxAll= */ true); 490 491 // Create MC code generation pass manager 492 llvm::PassManager MCCodeGenPasses; 493 494 // Add TargetData to MC code generation pass manager 495 MCCodeGenPasses.add(TD); 496 497 // Add MC code generation passes to pass manager 498 llvm::MCContext *Ctx = NULL; 499 if (TM->addPassesToEmitMC(MCCodeGenPasses, Ctx, OutSVOS, false)) { 500 setError("Fail to add passes to emit file"); 501 return 1; 502 } 503 504 MCCodeGenPasses.run(*mModule); 505 OutSVOS.flush(); 506 return 0; 507 } 508 509 int Compiler::runInternalPasses(std::vector<std::string>& Names, 510 std::vector<uint32_t>& Signatures) { 511 llvm::PassManager BCCPasses; 512 513 // Expand ForEach on CPU path to reduce launch overhead. 514 BCCPasses.add(createForEachExpandPass(Names, Signatures)); 515 516 BCCPasses.run(*mModule); 517 518 return 0; 519 } 520 521 int Compiler::runLTO(llvm::TargetData *TD, 522 std::vector<const char*>& ExportSymbols, 523 llvm::CodeGenOpt::Level OptimizationLevel) { 524 // Note: ExportSymbols is a workaround for getting all exported variable, 525 // function, and kernel names. 526 // We should refine it soon. 527 528 // TODO(logan): Remove this after we have finished the 529 // bccMarkExternalSymbol API. 530 531 // root(), init(), and .rs.dtor() are born to be exported 532 ExportSymbols.push_back("root"); 533 ExportSymbols.push_back("init"); 534 ExportSymbols.push_back(".rs.dtor"); 535 536 // User-defined exporting symbols 537 std::vector<char const *> const &UserDefinedExternalSymbols = 538 mpResult->getUserDefinedExternalSymbols(); 539 540 std::copy(UserDefinedExternalSymbols.begin(), 541 UserDefinedExternalSymbols.end(), 542 std::back_inserter(ExportSymbols)); 543 544 llvm::PassManager LTOPasses; 545 546 // Add TargetData to LTO passes 547 LTOPasses.add(TD); 548 549 // We now create passes list performing LTO. These are copied from 550 // (including comments) llvm::createStandardLTOPasses(). 551 // Only a subset of these LTO passes are enabled in optimization level 0 552 // as they interfere with interactive debugging. 553 // FIXME: figure out which passes (if any) makes sense for levels 1 and 2 554 555 if (OptimizationLevel != llvm::CodeGenOpt::None) { 556 // Internalize all other symbols not listed in ExportSymbols 557 LTOPasses.add(llvm::createInternalizePass(ExportSymbols)); 558 559 // Propagate constants at call sites into the functions they call. This 560 // opens opportunities for globalopt (and inlining) by substituting 561 // function pointers passed as arguments to direct uses of functions. 562 LTOPasses.add(llvm::createIPSCCPPass()); 563 564 // Now that we internalized some globals, see if we can hack on them! 565 LTOPasses.add(llvm::createGlobalOptimizerPass()); 566 567 // Linking modules together can lead to duplicated global constants, only 568 // keep one copy of each constant... 569 LTOPasses.add(llvm::createConstantMergePass()); 570 571 // Remove unused arguments from functions... 572 LTOPasses.add(llvm::createDeadArgEliminationPass()); 573 574 // Reduce the code after globalopt and ipsccp. Both can open up 575 // significant simplification opportunities, and both can propagate 576 // functions through function pointers. When this happens, we often have 577 // to resolve varargs calls, etc, so let instcombine do this. 578 LTOPasses.add(llvm::createInstructionCombiningPass()); 579 580 // Inline small functions 581 LTOPasses.add(llvm::createFunctionInliningPass()); 582 583 // Remove dead EH info. 584 LTOPasses.add(llvm::createPruneEHPass()); 585 586 // Internalize the globals again after inlining 587 LTOPasses.add(llvm::createGlobalOptimizerPass()); 588 589 // Remove dead functions. 590 LTOPasses.add(llvm::createGlobalDCEPass()); 591 592 // If we didn't decide to inline a function, check to see if we can 593 // transform it to pass arguments by value instead of by reference. 594 LTOPasses.add(llvm::createArgumentPromotionPass()); 595 596 // The IPO passes may leave cruft around. Clean up after them. 597 LTOPasses.add(llvm::createInstructionCombiningPass()); 598 LTOPasses.add(llvm::createJumpThreadingPass()); 599 600 // Break up allocas 601 LTOPasses.add(llvm::createScalarReplAggregatesPass()); 602 603 // Run a few AA driven optimizations here and now, to cleanup the code. 604 LTOPasses.add(llvm::createFunctionAttrsPass()); // Add nocapture. 605 LTOPasses.add(llvm::createGlobalsModRefPass()); // IP alias analysis. 606 607 // Hoist loop invariants. 608 LTOPasses.add(llvm::createLICMPass()); 609 610 // Remove redundancies. 611 LTOPasses.add(llvm::createGVNPass()); 612 613 // Remove dead memcpys. 614 LTOPasses.add(llvm::createMemCpyOptPass()); 615 616 // Nuke dead stores. 617 LTOPasses.add(llvm::createDeadStoreEliminationPass()); 618 619 // Cleanup and simplify the code after the scalar optimizations. 620 LTOPasses.add(llvm::createInstructionCombiningPass()); 621 622 LTOPasses.add(llvm::createJumpThreadingPass()); 623 624 // Delete basic blocks, which optimization passes may have killed. 625 LTOPasses.add(llvm::createCFGSimplificationPass()); 626 627 // Now that we have optimized the program, discard unreachable functions. 628 LTOPasses.add(llvm::createGlobalDCEPass()); 629 630 } else { 631 LTOPasses.add(llvm::createInternalizePass(ExportSymbols)); 632 LTOPasses.add(llvm::createGlobalOptimizerPass()); 633 LTOPasses.add(llvm::createConstantMergePass()); 634 } 635 636 LTOPasses.run(*mModule); 637 638 #if ANDROID_ENGINEERING_BUILD 639 if (0 != gDebugDumpDirectory) { 640 std::string errs; 641 std::string Filename(gDebugDumpDirectory); 642 Filename += "/post-lto-module.ll"; 643 llvm::raw_fd_ostream FS(Filename.c_str(), errs); 644 mModule->print(FS, 0); 645 FS.close(); 646 } 647 #endif 648 649 return 0; 650 } 651 652 653 void *Compiler::getSymbolAddress(char const *name) { 654 return rsloaderGetSymbolAddress(mRSExecutable, name); 655 } 656 657 658 void *Compiler::resolveSymbolAdapter(void *context, char const *name) { 659 Compiler *self = reinterpret_cast<Compiler *>(context); 660 661 if (void *Addr = FindRuntimeFunction(name)) { 662 return Addr; 663 } 664 665 if (self->mpSymbolLookupFn) { 666 if (void *Addr = self->mpSymbolLookupFn(self->mpSymbolLookupContext, name)) { 667 return Addr; 668 } 669 } 670 671 ALOGE("Unable to resolve symbol: %s\n", name); 672 return NULL; 673 } 674 675 676 Compiler::~Compiler() { 677 rsloaderDisposeExec(mRSExecutable); 678 679 // llvm::llvm_shutdown(); 680 } 681 682 683 } // namespace bcc 684