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 {