resolved conflicts for merge of 7c75d915 to master
Change-Id: I25c1dc90af679e2463abffd33ee8838b4727396f
diff --git a/lib/ExecutionEngine/Android.mk b/lib/ExecutionEngine/Android.mk
index e222a41..cc66435 100644
--- a/lib/ExecutionEngine/Android.mk
+++ b/lib/ExecutionEngine/Android.mk
@@ -25,6 +25,8 @@
libbcc_executionengine_SRC_FILES := \
Compiler.cpp \
FileHandle.cpp \
+ GDBJIT.cpp \
+ GDBJITRegistrar.cpp \
Runtime.c \
RuntimeStub.c \
Script.cpp \
diff --git a/lib/ExecutionEngine/Compiler.cpp b/lib/ExecutionEngine/Compiler.cpp
index cee5daa..4199fb2 100644
--- a/lib/ExecutionEngine/Compiler.cpp
+++ b/lib/ExecutionEngine/Compiler.cpp
@@ -47,6 +47,7 @@
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
+#include "llvm/MC/MCContext.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Transforms/IPO.h"
@@ -59,14 +60,16 @@
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
-#include "llvm/Type.h"
+#include "llvm/Constants.h"
#include "llvm/GlobalValue.h"
#include "llvm/Linker.h"
#include "llvm/LLVMContext.h"
#include "llvm/Metadata.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
+#include "llvm/Type.h"
#include "llvm/Value.h"
#include <errno.h>
@@ -82,6 +85,8 @@
#include <string>
#include <vector>
+extern char* gDebugDumpDirectory;
+
namespace bcc {
//////////////////////////////////////////////////////////////////////////////
@@ -140,6 +145,12 @@
// synced with slang_rs_metadata.h)
const llvm::StringRef Compiler::ObjectSlotMetadataName = "#rs_object_slots";
+// Name of metadata node where RS optimization level resides (should be
+// synced with slang_rs_metadata.h)
+const llvm::StringRef OptimizationLevelMetadataName = "#optimization_level";
+
+
+
//////////////////////////////////////////////////////////////////////////////
// Compiler
//////////////////////////////////////////////////////////////////////////////
@@ -226,23 +237,9 @@
InitializeDisassembler();
#endif
- // -O0: llvm::CodeGenOpt::None
- // -O1: llvm::CodeGenOpt::Less
- // -O2: llvm::CodeGenOpt::Default
- // -O3: llvm::CodeGenOpt::Aggressive
- CodeGenOptLevel = llvm::CodeGenOpt::Aggressive;
-
// Register the scheduler
llvm::RegisterScheduler::setDefault(llvm::createDefaultScheduler);
- // Register allocation policy:
- // createFastRegisterAllocator: fast but bad quality
- // createLinearScanRegisterAllocator: not so fast but good quality
- llvm::RegisterRegAlloc::setDefault
- ((CodeGenOptLevel == llvm::CodeGenOpt::None) ?
- llvm::createFastRegisterAllocator :
- llvm::createGreedyRegisterAllocator);
-
#if USE_CACHE
// Read in SHA1 checksum of libbcc and libRS.
readSHA1(sha1LibBCC_SHA1, sizeof(sha1LibBCC_SHA1), pathLibBCC_SHA1);
@@ -313,6 +310,9 @@
std::string FeaturesStr;
+ if (mModule == NULL) // No module was loaded
+ return 0;
+
llvm::NamedMDNode const *PragmaMetadata;
llvm::NamedMDNode const *ExportVarMetadata;
llvm::NamedMDNode const *ExportFuncMetadata;
@@ -324,8 +324,37 @@
std::vector<std::string> ForEachExpandList;
std::vector<uint32_t> forEachSigList;
- if (mModule == NULL) // No module was loaded
- return 0;
+ llvm::NamedMDNode const *OptimizationLevelMetadata =
+ mModule->getNamedMetadata(OptimizationLevelMetadataName);
+
+ // Default to maximum optimization in the absence of named metadata node
+ int OptimizationLevel = 3;
+ if (OptimizationLevelMetadata) {
+ llvm::ConstantInt* OL = llvm::dyn_cast<llvm::ConstantInt>(
+ OptimizationLevelMetadata->getOperand(0)->getOperand(0));
+ OptimizationLevel = OL->getZExtValue();
+ }
+
+ if (OptimizationLevel == 0) {
+ CodeGenOptLevel = llvm::CodeGenOpt::None;
+ } else if (OptimizationLevel == 1) {
+ CodeGenOptLevel = llvm::CodeGenOpt::Less;
+ } else if (OptimizationLevel == 2) {
+ CodeGenOptLevel = llvm::CodeGenOpt::Default;
+ } else if (OptimizationLevel == 3) {
+ CodeGenOptLevel = llvm::CodeGenOpt::Aggressive;
+ }
+
+ // not the best place for this, but we need to set the register allocation
+ // policy after we read the optimization_level metadata from the bitcode
+
+ // Register allocation policy:
+ // createFastRegisterAllocator: fast but bad quality
+ // createLinearScanRegisterAllocator: not so fast but good quality
+ llvm::RegisterRegAlloc::setDefault
+ ((CodeGenOptLevel == llvm::CodeGenOpt::None) ?
+ llvm::createFastRegisterAllocator :
+ llvm::createGreedyRegisterAllocator);
// Find LLVM Target
Target = llvm::TargetRegistry::lookupTarget(Triple, mError);
@@ -410,7 +439,7 @@
// Perform link-time optimization if we have multiple modules
if (mHasLinked) {
runLTO(new llvm::TargetData(*TD), ExportVarMetadata, ExportFuncMetadata,
- ForEachExpandList);
+ ForEachExpandList, CodeGenOptLevel);
}
// Perform code generation
@@ -440,6 +469,9 @@
goto on_bcc_compile_error;
}
+ rsloaderUpdateSectionHeaders(mRSExecutable,
+ (unsigned char*) mEmittedELFExecutable.begin());
+
if (ExportVarMetadata) {
ScriptCompiled::ExportVarList &varList = mpResult->mExportVars;
std::vector<std::string> &varNameList = mpResult->mExportVarsName;
@@ -754,7 +786,7 @@
MCCodeGenPasses.add(TD);
// Add MC code generation passes to pass manager
- llvm::MCContext *Ctx;
+ llvm::MCContext *Ctx = NULL;
if (TM->addPassesToEmitMC(MCCodeGenPasses, Ctx, OutSVOS, false)) {
setError("Fail to add passes to emit file");
return 1;
@@ -781,12 +813,8 @@
int Compiler::runLTO(llvm::TargetData *TD,
llvm::NamedMDNode const *ExportVarMetadata,
llvm::NamedMDNode const *ExportFuncMetadata,
- std::vector<std::string>& ForEachExpandList) {
- llvm::PassManager LTOPasses;
-
- // Add TargetData to LTO passes
- LTOPasses.add(TD);
-
+ std::vector<std::string>& ForEachExpandList,
+ llvm::CodeGenOpt::Level OptimizationLevel) {
// Collect All Exported Symbols
std::vector<const char*> ExportSymbols;
@@ -840,85 +868,111 @@
UserDefinedExternalSymbols.end(),
std::back_inserter(ExportSymbols));
+ llvm::PassManager LTOPasses;
+
+ // Add TargetData to LTO passes
+ LTOPasses.add(TD);
+
// We now create passes list performing LTO. These are copied from
// (including comments) llvm::createStandardLTOPasses().
+ // Only a subset of these LTO passes are enabled in optimization level 0
+ // as they interfere with interactive debugging.
+ // FIXME: figure out which passes (if any) makes sense for levels 1 and 2
- // Internalize all other symbols not listed in ExportSymbols
- LTOPasses.add(llvm::createInternalizePass(ExportSymbols));
+ if (OptimizationLevel != llvm::CodeGenOpt::None) {
+ // Internalize all other symbols not listed in ExportSymbols
+ LTOPasses.add(llvm::createInternalizePass(ExportSymbols));
- // Propagate constants at call sites into the functions they call. This
- // opens opportunities for globalopt (and inlining) by substituting
- // function pointers passed as arguments to direct uses of functions.
- LTOPasses.add(llvm::createIPSCCPPass());
+ // Propagate constants at call sites into the functions they call. This
+ // opens opportunities for globalopt (and inlining) by substituting
+ // function pointers passed as arguments to direct uses of functions.
+ LTOPasses.add(llvm::createIPSCCPPass());
- // Now that we internalized some globals, see if we can hack on them!
- LTOPasses.add(llvm::createGlobalOptimizerPass());
+ // Now that we internalized some globals, see if we can hack on them!
+ LTOPasses.add(llvm::createGlobalOptimizerPass());
- // Linking modules together can lead to duplicated global constants, only
- // keep one copy of each constant...
- LTOPasses.add(llvm::createConstantMergePass());
+ // Linking modules together can lead to duplicated global constants, only
+ // keep one copy of each constant...
+ LTOPasses.add(llvm::createConstantMergePass());
- // Remove unused arguments from functions...
- LTOPasses.add(llvm::createDeadArgEliminationPass());
+ // Remove unused arguments from functions...
+ LTOPasses.add(llvm::createDeadArgEliminationPass());
- // Reduce the code after globalopt and ipsccp. Both can open up
- // significant simplification opportunities, and both can propagate
- // functions through function pointers. When this happens, we often have
- // to resolve varargs calls, etc, so let instcombine do this.
- LTOPasses.add(llvm::createInstructionCombiningPass());
+ // Reduce the code after globalopt and ipsccp. Both can open up
+ // significant simplification opportunities, and both can propagate
+ // functions through function pointers. When this happens, we often have
+ // to resolve varargs calls, etc, so let instcombine do this.
+ LTOPasses.add(llvm::createInstructionCombiningPass());
- // Inline small functions
- LTOPasses.add(llvm::createFunctionInliningPass());
+ // Inline small functions
+ LTOPasses.add(llvm::createFunctionInliningPass());
- // Remove dead EH info.
- LTOPasses.add(llvm::createPruneEHPass());
+ // Remove dead EH info.
+ LTOPasses.add(llvm::createPruneEHPass());
- // Internalize the globals again after inlining
- LTOPasses.add(llvm::createGlobalOptimizerPass());
+ // Internalize the globals again after inlining
+ LTOPasses.add(llvm::createGlobalOptimizerPass());
- // Remove dead functions.
- LTOPasses.add(llvm::createGlobalDCEPass());
+ // Remove dead functions.
+ LTOPasses.add(llvm::createGlobalDCEPass());
- // If we didn't decide to inline a function, check to see if we can
- // transform it to pass arguments by value instead of by reference.
- LTOPasses.add(llvm::createArgumentPromotionPass());
+ // If we didn't decide to inline a function, check to see if we can
+ // transform it to pass arguments by value instead of by reference.
+ LTOPasses.add(llvm::createArgumentPromotionPass());
- // The IPO passes may leave cruft around. Clean up after them.
- LTOPasses.add(llvm::createInstructionCombiningPass());
- LTOPasses.add(llvm::createJumpThreadingPass());
+ // The IPO passes may leave cruft around. Clean up after them.
+ LTOPasses.add(llvm::createInstructionCombiningPass());
+ LTOPasses.add(llvm::createJumpThreadingPass());
- // Break up allocas
- LTOPasses.add(llvm::createScalarReplAggregatesPass());
+ // Break up allocas
+ LTOPasses.add(llvm::createScalarReplAggregatesPass());
- // Run a few AA driven optimizations here and now, to cleanup the code.
- LTOPasses.add(llvm::createFunctionAttrsPass()); // Add nocapture.
- LTOPasses.add(llvm::createGlobalsModRefPass()); // IP alias analysis.
+ // Run a few AA driven optimizations here and now, to cleanup the code.
+ LTOPasses.add(llvm::createFunctionAttrsPass()); // Add nocapture.
+ LTOPasses.add(llvm::createGlobalsModRefPass()); // IP alias analysis.
- // Hoist loop invariants.
- LTOPasses.add(llvm::createLICMPass());
+ // Hoist loop invariants.
+ LTOPasses.add(llvm::createLICMPass());
- // Remove redundancies.
- LTOPasses.add(llvm::createGVNPass());
+ // Remove redundancies.
+ LTOPasses.add(llvm::createGVNPass());
- // Remove dead memcpys.
- LTOPasses.add(llvm::createMemCpyOptPass());
+ // Remove dead memcpys.
+ LTOPasses.add(llvm::createMemCpyOptPass());
- // Nuke dead stores.
- LTOPasses.add(llvm::createDeadStoreEliminationPass());
+ // Nuke dead stores.
+ LTOPasses.add(llvm::createDeadStoreEliminationPass());
- // Cleanup and simplify the code after the scalar optimizations.
- LTOPasses.add(llvm::createInstructionCombiningPass());
+ // Cleanup and simplify the code after the scalar optimizations.
+ LTOPasses.add(llvm::createInstructionCombiningPass());
- LTOPasses.add(llvm::createJumpThreadingPass());
+ LTOPasses.add(llvm::createJumpThreadingPass());
- // Delete basic blocks, which optimization passes may have killed.
- LTOPasses.add(llvm::createCFGSimplificationPass());
+ // Delete basic blocks, which optimization passes may have killed.
+ LTOPasses.add(llvm::createCFGSimplificationPass());
- // Now that we have optimized the program, discard unreachable functions.
- LTOPasses.add(llvm::createGlobalDCEPass());
+ // Now that we have optimized the program, discard unreachable functions.
+ LTOPasses.add(llvm::createGlobalDCEPass());
+
+ } else {
+ LTOPasses.add(llvm::createInternalizePass(ExportSymbols));
+ LTOPasses.add(llvm::createGlobalOptimizerPass());
+ LTOPasses.add(llvm::createConstantMergePass());
+ }
LTOPasses.run(*mModule);
+#if ANDROID_ENGINEERING_BUILD
+ if (0 != gDebugDumpDirectory) {
+ std::string errs;
+ std::string Filename(gDebugDumpDirectory);
+ Filename += "/post-lto-module.ll";
+ llvm::raw_fd_ostream FS(Filename.c_str(), errs);
+ mModule->print(FS, 0);
+ FS.close();
+ }
+#endif
+
return 0;
}
diff --git a/lib/ExecutionEngine/Compiler.h b/lib/ExecutionEngine/Compiler.h
index 8cc3d2e..c70a920 100644
--- a/lib/ExecutionEngine/Compiler.h
+++ b/lib/ExecutionEngine/Compiler.h
@@ -184,7 +184,8 @@
int runLTO(llvm::TargetData *TD,
llvm::NamedMDNode const *ExportVarMetadata,
llvm::NamedMDNode const *ExportFuncMetadata,
- std::vector<std::string>& ForEachExpandList);
+ std::vector<std::string>& ForEachExpandList,
+ llvm::CodeGenOpt::Level OptimizationLevel);
bool hasError() const {
return !mError.empty();
diff --git a/lib/ExecutionEngine/GDBJIT.cpp b/lib/ExecutionEngine/GDBJIT.cpp
new file mode 100644
index 0000000..4038098
--- /dev/null
+++ b/lib/ExecutionEngine/GDBJIT.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file contains portions derived from LLVM, with the original copyright
+// header below:
+//===-- GDBJIT.cpp - Common Implementation shared by GDB-JIT users --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is used to support GDB's JIT interface
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Compiler.h"
+
+// This interface must be kept in sync with gdb/gdb/jit.h .
+extern "C" {
+
+ // GDB 7.0+ puts a (silent) breakpoint in this function.
+ LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() { }
+
+}
diff --git a/lib/ExecutionEngine/GDBJIT.h b/lib/ExecutionEngine/GDBJIT.h
new file mode 100644
index 0000000..442b666
--- /dev/null
+++ b/lib/ExecutionEngine/GDBJIT.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file contains portions derived from LLVM, with the original copyright
+// header below:
+//===-------------- GDBJIT.h - Register debug symbols for JIT -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the data structures used by JIT engines to register object
+// files (ideally containing debug info) with GDB.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BCC_EXECUTION_ENGINE_GDB_JIT_H
+#define BCC_EXECUTION_ENGINE_GDB_JIT_H
+
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Compiler.h"
+
+// This must be kept in sync with gdb/gdb/jit.h .
+extern "C" {
+
+ typedef enum {
+ JIT_NOACTION = 0,
+ JIT_REGISTER_FN,
+ JIT_UNREGISTER_FN
+ } jit_actions_t;
+
+ struct jit_code_entry {
+ struct jit_code_entry *next_entry;
+ struct jit_code_entry *prev_entry;
+ const char *symfile_addr;
+ uint64_t symfile_size;
+ };
+
+ struct jit_descriptor {
+ uint32_t version;
+ // This should be jit_actions_t, but we want to be specific about the
+ // bit-width.
+ uint32_t action_flag;
+ struct jit_code_entry *relevant_entry;
+ struct jit_code_entry *first_entry;
+ };
+
+ // GDB 7.0+ puts a (silent) breakpoint in this function.
+ LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code();
+
+}
+
+#endif // BCC_EXECUTION_ENGINE_GDB_JIT_H
diff --git a/lib/ExecutionEngine/GDBJITRegistrar.cpp b/lib/ExecutionEngine/GDBJITRegistrar.cpp
new file mode 100644
index 0000000..5d8428a
--- /dev/null
+++ b/lib/ExecutionEngine/GDBJITRegistrar.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file contains portions derived from LLVM, with the original copyright
+// header below:
+//==----- GDBJITRegistrar.cpp - Notify GDB about in-memory object files ---==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the GDBJITRegistrar object which is used by JIT engines to
+// register in-memory object files with GDB for debugging.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBJITRegistrar.h"
+#include "llvm/ADT/DenseMap.h"
+#include "GDBJIT.h"
+#include "llvm/Support/Memory.h"
+#include "llvm/Support/MutexGuard.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/ErrorHandling.h"
+
+#include <fstream>
+
+#ifdef ANDROID_ENGINEERING_BUILD
+// Path to write dump output.
+// It is expected that a debugger (plugin) sets this
+// string to a writeable directory where files (such as JITted object files,
+// IR dumps) are to be written. If this variable is 0, no debug dumps
+// are generated.
+char* gDebugDumpDirectory = 0;
+#endif // ANDROID_ENGINEERING_BUILD
+
+//************************************************************************
+// COPIED/ADAPTED FROM llvm/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp
+//************************************************************************
+// This must be kept in sync with gdb/gdb/jit.h .
+extern "C" {
+
+ // We put information about the JITed function in this global, which the
+ // debugger reads. Make sure to specify the version statically, because the
+ // debugger checks the version before we can set it during runtime.
+ static struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+
+}
+//****************************************************************************
+// END COPIED/ADAPTED FROM llvm/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp
+//****************************************************************************
+
+namespace {
+
+// Buffer for an in-memory object file in executable memory
+typedef llvm::DenseMap< const ObjectBuffer*, std::pair<std::size_t, jit_code_entry*> >
+ RegisteredObjectBufferMap;
+
+/// Global access point for the GDB JIT interface designed for use with a
+/// singleton toolbox. Handles thread-safe registration and deregistration of
+/// object files that are in executable memory managed by the client of this
+/// class.
+class GDBJITRegistrar {
+ /// A map of in-memory object files that have been registered with the GDB JIT interface.
+ RegisteredObjectBufferMap ObjectBufferMap;
+
+public:
+ /// Instantiates the GDB JIT service.
+ GDBJITRegistrar() : ObjectBufferMap() {}
+
+ /// Unregisters each object that was previously registered with GDB, and
+ /// releases all internal resources.
+ ~GDBJITRegistrar();
+
+ /// Creates an entry in the GDB JIT registry for the buffer @p Object,
+ /// which must contain an object file in executable memory with any
+ /// debug information for GDB.
+ void registerObject(const ObjectBuffer* Object, std::size_t Size);
+
+ /// Removes the internal registration of @p Object, and
+ /// frees associated resources.
+ /// Returns true if @p Object was found in ObjectBufferMap.
+ bool deregisterObject(const ObjectBuffer* Object);
+
+private:
+ /// Deregister the debug info for the given object file from the debugger
+ /// and delete any temporary copies. This private method does not remove
+ /// the function from Map so that it can be called while iterating over Map.
+ void deregisterObjectInternal(RegisteredObjectBufferMap::iterator I);
+};
+
+/// Lock used to serialize all gdb-jit registration events, since they
+/// modify global variables.
+llvm::sys::Mutex JITDebugLock;
+
+/// Acquire the lock and do the registration.
+void NotifyGDB(jit_code_entry* JITCodeEntry) {
+ llvm::MutexGuard locked(JITDebugLock);
+ __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
+
+ // Insert this entry at the head of the list.
+ JITCodeEntry->prev_entry = NULL;
+ jit_code_entry* NextEntry = __jit_debug_descriptor.first_entry;
+ JITCodeEntry->next_entry = NextEntry;
+ if (NextEntry != NULL) {
+ NextEntry->prev_entry = JITCodeEntry;
+ }
+ __jit_debug_descriptor.first_entry = JITCodeEntry;
+ __jit_debug_descriptor.relevant_entry = JITCodeEntry;
+ __jit_debug_register_code();
+}
+
+GDBJITRegistrar* RegistrarSingleton() {
+ static GDBJITRegistrar* sRegistrar = NULL;
+ if (sRegistrar == NULL) {
+ // The mutex is here so that it won't slow down access once the registrar
+ // is instantiated
+ llvm::MutexGuard locked(JITDebugLock);
+ // Check again to be sure another thread didn't create this while we waited
+ if (sRegistrar == NULL) {
+ sRegistrar = new GDBJITRegistrar;
+ }
+ }
+ return sRegistrar;
+}
+
+GDBJITRegistrar::~GDBJITRegistrar() {
+ // Free all registered object files.
+ for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(), E = ObjectBufferMap.end();
+ I != E; ++I) {
+ // Call the private method that doesn't update the map so our iterator
+ // doesn't break.
+ deregisterObjectInternal(I);
+ }
+ ObjectBufferMap.clear();
+}
+
+void GDBJITRegistrar::registerObject(const ObjectBuffer* Object, std::size_t Size) {
+
+ assert(Object && "Attempt to register a null object with a debugger.");
+ assert(ObjectBufferMap.find(Object) == ObjectBufferMap.end()
+ && "Second attempt to perform debug registration.");
+
+ jit_code_entry* JITCodeEntry = new jit_code_entry();
+
+ if (JITCodeEntry == 0) {
+ llvm::report_fatal_error("Allocation failed when registering a GDB-JIT entry!\n");
+ }
+ else {
+ JITCodeEntry->symfile_addr = Object;
+ JITCodeEntry->symfile_size = Size;
+
+ ObjectBufferMap[Object] = std::make_pair(Size, JITCodeEntry);
+ NotifyGDB(JITCodeEntry);
+
+#ifdef ANDROID_ENGINEERING_BUILD
+ if (0 != gDebugDumpDirectory) {
+ std::string Filename(gDebugDumpDirectory);
+ Filename += "/jit_registered.o";
+
+ std::ofstream outfile(Filename.c_str(), std::ofstream::binary);
+ outfile.write((char*)JITCodeEntry->symfile_addr, JITCodeEntry->symfile_size);
+ outfile.close();
+ }
+#endif
+ }
+}
+
+bool GDBJITRegistrar::deregisterObject(const ObjectBuffer *Object) {
+ RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(Object);
+
+ if (I != ObjectBufferMap.end()) {
+ deregisterObjectInternal(I);
+ ObjectBufferMap.erase(I);
+ return true;
+ }
+ return false;
+}
+
+void GDBJITRegistrar::deregisterObjectInternal(
+ RegisteredObjectBufferMap::iterator I) {
+
+ jit_code_entry*& JITCodeEntry = I->second.second;
+
+ // Acquire the lock and do the unregistration.
+ {
+ llvm::MutexGuard locked(JITDebugLock);
+ __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
+
+ // Remove the jit_code_entry from the linked list.
+ jit_code_entry* PrevEntry = JITCodeEntry->prev_entry;
+ jit_code_entry* NextEntry = JITCodeEntry->next_entry;
+
+ if (NextEntry) {
+ NextEntry->prev_entry = PrevEntry;
+ }
+ if (PrevEntry) {
+ PrevEntry->next_entry = NextEntry;
+ }
+ else {
+ assert(__jit_debug_descriptor.first_entry == JITCodeEntry);
+ __jit_debug_descriptor.first_entry = NextEntry;
+ }
+
+ // Tell GDB which entry we removed, and unregister the code.
+ __jit_debug_descriptor.relevant_entry = JITCodeEntry;
+ __jit_debug_register_code();
+ }
+
+ delete JITCodeEntry;
+ JITCodeEntry = NULL;
+}
+
+} // end namespace
+
+void registerObjectWithGDB(const ObjectBuffer* Object, std::size_t Size) {
+ GDBJITRegistrar* Registrar = RegistrarSingleton();
+ if (Registrar) {
+ Registrar->registerObject(Object, Size);
+ }
+}
+
+void deregisterObjectWithGDB(const ObjectBuffer* Object) {
+ GDBJITRegistrar* Registrar = RegistrarSingleton();
+ if (Registrar) {
+ Registrar->deregisterObject(Object);
+ }
+}
diff --git a/lib/ExecutionEngine/GDBJITRegistrar.h b/lib/ExecutionEngine/GDBJITRegistrar.h
new file mode 100644
index 0000000..debf503
--- /dev/null
+++ b/lib/ExecutionEngine/GDBJITRegistrar.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file contains portions derived from LLVM, with the original copyright
+// header below:
+//===-- GDBJITRegistrar.h - Common Implementation shared by GDB-JIT users --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains declarations of the interface an ExecutionEngine would use
+// to register an in-memory object file with GDB.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BCC_GDBJITREGISTRAR_H
+#define BCC_GDBJITREGISTRAR_H
+
+#include <cstddef>
+
+// Buffer for an in-memory object file in executable memory
+typedef char ObjectBuffer;
+
+void registerObjectWithGDB(const ObjectBuffer* Object, std::size_t Size);
+void deregisterObjectWithGDB(const ObjectBuffer* Object);
+
+#endif // BCC_GDBJITREGISTRAR_H
diff --git a/lib/ExecutionEngine/MCCacheReader.cpp b/lib/ExecutionEngine/MCCacheReader.cpp
index 57499b6..5beff88 100644
--- a/lib/ExecutionEngine/MCCacheReader.cpp
+++ b/lib/ExecutionEngine/MCCacheReader.cpp
@@ -449,21 +449,25 @@
}
bool MCCacheReader::readObjFile() {
- llvm::SmallVector<char, 1024> mEmittedELFExecutable;
+ if (mpResult->mCachedELFExecutable.size() != 0) {
+ ALOGE("Attempted to read cached object into a non-empty script");
+ return false;
+ }
char readBuffer[1024];
int readSize;
while ((readSize = mObjFile->read(readBuffer, 1024)) > 0) {
- mEmittedELFExecutable.append(readBuffer, readBuffer + readSize);
+ mpResult->mCachedELFExecutable.append(readBuffer, readBuffer + readSize);
}
if (readSize != 0) {
ALOGE("Read file Error");
return false;
}
- ALOGD("Read object file size %d", (int)mEmittedELFExecutable.size());
+ ALOGD("Read object file size %d", (int)mpResult->mCachedELFExecutable.size());
mpResult->mRSExecutable =
- rsloaderCreateExec((unsigned char *)&*mEmittedELFExecutable.begin(),
- mEmittedELFExecutable.size(),
+ rsloaderCreateExec((unsigned char *)&*(mpResult->mCachedELFExecutable.begin()),
+ mpResult->mCachedELFExecutable.size(),
&resolveSymbolAdapter, this);
+
return true;
}
diff --git a/lib/ExecutionEngine/Script.cpp b/lib/ExecutionEngine/Script.cpp
index ddd9933..14d38bf 100644
--- a/lib/ExecutionEngine/Script.cpp
+++ b/lib/ExecutionEngine/Script.cpp
@@ -33,6 +33,7 @@
#include "DebugHelper.h"
#include "FileHandle.h"
+#include "GDBJITRegistrar.h"
#include "ScriptCompiled.h"
#include "ScriptCached.h"
#include "Sha1Helper.h"
@@ -47,7 +48,6 @@
#include <string.h>
#include <cutils/properties.h>
-
namespace {
bool getBooleanProp(const char *str) {
@@ -221,22 +221,30 @@
return 1;
}
+ int status = -1;
#if USE_CACHE
if (internalLoadCache(cacheDir, cacheName,
ScriptObject::Executable, /* checkOnly */ false) == 0) {
- return 0;
+ status = 0;
}
#endif
- CompilerOption option;
- int status = internalCompile(option);
+ if (status != 0) {
+ CompilerOption option;
+ status = internalCompile(option);
+ }
+
if (status != 0) {
ALOGE("LLVM error message: %s\n", getCompilerErrorMessage());
}
+
+ // FIXME: Registration can be conditional on the presence of debug metadata
+ if (status == 0) {
+ registerObjectWithGDB(getELF(), getELFSize()); // thread-safe registration
+ }
return status;
}
-
#if USE_CACHE
int Script::internalLoadCache(char const *cacheDir, char const *cacheName,
ScriptObject::ObjectType objectType,
@@ -832,7 +840,11 @@
case ScriptStatus::Compiled: {
return mCompiled->getELFSize();
}
-
+#if USE_CACHE
+ case ScriptStatus::Cached: {
+ return mCached->getELFSize();
+ }
+#endif
default: {
return 0;
}
@@ -844,7 +856,11 @@
case ScriptStatus::Compiled: {
return mCompiled->getELF();
}
-
+#if USE_CACHE
+ case ScriptStatus::Cached: {
+ return mCached->getELF();
+ }
+#endif
default: {
return NULL;
}
diff --git a/lib/ExecutionEngine/Script.h b/lib/ExecutionEngine/Script.h
index 27931e6..870d354 100644
--- a/lib/ExecutionEngine/Script.h
+++ b/lib/ExecutionEngine/Script.h
@@ -31,6 +31,7 @@
namespace llvm {
class Module;
+ class GDBJITRegistrar;
}
namespace bcc {
@@ -262,7 +263,6 @@
ScriptObject::ObjectType objectType, bool checkOnly);
#endif
int internalCompile(const CompilerOption&);
-
};
} // namespace bcc
diff --git a/lib/ExecutionEngine/ScriptCached.h b/lib/ExecutionEngine/ScriptCached.h
index 67cf635..f18cb88 100644
--- a/lib/ExecutionEngine/ScriptCached.h
+++ b/lib/ExecutionEngine/ScriptCached.h
@@ -73,6 +73,7 @@
#if USE_MCJIT
RSExecRef mRSExecutable;
+ llvm::SmallVector<char, 1024> mCachedELFExecutable;
#endif
OBCC_StringPool *mpStringPoolRaw;
@@ -144,6 +145,15 @@
}
#endif
+#if USE_MCJIT
+ const char *getELF() const {
+ return &*mCachedELFExecutable.begin();
+ }
+
+ size_t getELFSize() const {
+ return mCachedELFExecutable.size();
+ }
+#endif
// Dirty hack for libRS.
// TODO(all): This should be removed in the future.
bool isLibRSThreadable() const {