Merge "Remove non-existent ARM insn kThumb2SubsRRI12."
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 704da68..28546e9 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -91,10 +91,12 @@
# Don't fail a dalvik minimal host build.
-include $(LLVM_ROOT_PATH)/llvm.mk
-# Clang build.
-# ART_TARGET_CLANG := true
+# Clang build support.
+ART_TARGET_CLANG := false
ifeq ($(HOST_OS),darwin)
-ART_HOST_CLANG := true
+ ART_HOST_CLANG := true
+else
+ ART_HOST_CLANG := false
endif
# directory used for dalvik-cache on device
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 2ddd09e..0b0c445 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -155,7 +155,6 @@
LOCAL_SHARED_LIBRARIES += libdl libicuuc libicui18n libnativehelper libz libcutils
LOCAL_STATIC_LIBRARIES += libgtest
LOCAL_MODULE_PATH := $(ART_NATIVETEST_OUT)
- include $(LLVM_DEVICE_BUILD_MK)
include $(BUILD_EXECUTABLE)
art_gtest_exe := $$(LOCAL_MODULE_PATH)/$$(LOCAL_MODULE)
ART_TARGET_GTEST_EXECUTABLES += $$(art_gtest_exe)
@@ -168,7 +167,6 @@
# Mac OS complains about unresolved symbols if you don't include this.
LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_host
endif
- include $(LLVM_HOST_BUILD_MK)
include $(BUILD_HOST_EXECUTABLE)
art_gtest_exe := $(HOST_OUT_EXECUTABLES)/$$(LOCAL_MODULE)
ART_HOST_GTEST_EXECUTABLES += $$(art_gtest_exe)
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 8f840cc..b1b6fc5 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -106,7 +106,7 @@
LIBART_COMPILER_CFLAGS :=
ifeq ($(ART_USE_PORTABLE_COMPILER),true)
-LIBART_COMPILER_SRC_FILES +=
+LIBART_COMPILER_SRC_FILES += \
dex/portable/mir_to_gbc.cc \
elf_writer_mclinker.cc \
jni/portable/jni_compiler.cc \
@@ -120,11 +120,12 @@
llvm/runtime_support_builder.cc \
llvm/runtime_support_builder_arm.cc \
llvm/runtime_support_builder_x86.cc
- LIBART_COMPILER_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
+LIBART_COMPILER_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
endif
LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES := \
- dex/compiler_enums.h
+ dex/compiler_enums.h \
+ dex/quick/dex_file_method_inliner.h
# $(1): target or host
# $(2): ndebug or debug
@@ -211,12 +212,15 @@
ifeq ($(TARGET_ARCH),arm64)
$$(info TODOAArch64: $$(LOCAL_PATH)/Android.mk Add Arm64 specific MCLinker libraries)
endif # TARGET_ARCH != arm64
+ include $(LLVM_DEVICE_BUILD_MK)
else # host
LOCAL_STATIC_LIBRARIES += libmcldARMInfo libmcldARMTarget
LOCAL_STATIC_LIBRARIES += libmcldX86Info libmcldX86Target
LOCAL_STATIC_LIBRARIES += libmcldMipsInfo libmcldMipsTarget
+ include $(LLVM_HOST_BUILD_MK)
endif
LOCAL_STATIC_LIBRARIES += libmcldCore libmcldObject libmcldADT libmcldFragment libmcldTarget libmcldCodeGen libmcldLDVariant libmcldMC libmcldSupport libmcldLD
+ include $(LLVM_GEN_INTRINSICS_MK)
endif
LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime
@@ -228,13 +232,9 @@
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
ifeq ($$(art_target_or_host),target)
LOCAL_SHARED_LIBRARIES += libcutils
- include $(LLVM_GEN_INTRINSICS_MK)
- include $(LLVM_DEVICE_BUILD_MK)
include $(BUILD_SHARED_LIBRARY)
else # host
LOCAL_STATIC_LIBRARIES += libcutils
- include $(LLVM_GEN_INTRINSICS_MK)
- include $(LLVM_HOST_BUILD_MK)
include $(BUILD_HOST_SHARED_LIBRARY)
endif
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index 0999d09..d034b79 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -240,7 +240,7 @@
#if GCC_VERSION >= 40303
__builtin___clear_cache(reinterpret_cast<void*>(base), reinterpret_cast<void*>(base + len));
#else
- LOG(FATAL) << "UNIMPLEMENTED: cache flush";
+ LOG(WARNING) << "UNIMPLEMENTED: cache flush";
#endif
}
@@ -353,7 +353,7 @@
CHECK(method != nullptr);
TimingLogger timings("CommonTest::CompileMethod", false, false);
timings.StartSplit("CompileOne");
- compiler_driver_->CompileOne(method, timings);
+ compiler_driver_->CompileOne(method, &timings);
MakeExecutable(method);
timings.EndSplit();
}
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index f6d724a..d884bc0 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -153,12 +153,14 @@
const uint32_t fp_spill_mask,
const std::vector<uint8_t>& mapping_table,
const std::vector<uint8_t>& vmap_table,
- const std::vector<uint8_t>& native_gc_map)
+ const std::vector<uint8_t>& native_gc_map,
+ const std::vector<uint8_t>* cfi_info)
: CompiledCode(&driver, instruction_set, quick_code), frame_size_in_bytes_(frame_size_in_bytes),
core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask),
mapping_table_(driver.DeduplicateMappingTable(mapping_table)),
vmap_table_(driver.DeduplicateVMapTable(vmap_table)),
- gc_map_(driver.DeduplicateGCMap(native_gc_map)) {
+ gc_map_(driver.DeduplicateGCMap(native_gc_map)),
+ cfi_info_(driver.DeduplicateCFIInfo(cfi_info)) {
}
CompiledMethod::CompiledMethod(CompilerDriver& driver,
@@ -169,10 +171,11 @@
const uint32_t fp_spill_mask)
: CompiledCode(&driver, instruction_set, code),
frame_size_in_bytes_(frame_size_in_bytes),
- core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask) {
- mapping_table_ = driver.DeduplicateMappingTable(std::vector<uint8_t>());
- vmap_table_ = driver.DeduplicateVMapTable(std::vector<uint8_t>());
- gc_map_ = driver.DeduplicateGCMap(std::vector<uint8_t>());
+ core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask),
+ mapping_table_(driver.DeduplicateMappingTable(std::vector<uint8_t>())),
+ vmap_table_(driver.DeduplicateVMapTable(std::vector<uint8_t>())),
+ gc_map_(driver.DeduplicateGCMap(std::vector<uint8_t>())),
+ cfi_info_(nullptr) {
}
// Constructs a CompiledMethod for the Portable compiler.
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 6112305..90ae6ee 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -110,7 +110,8 @@
const uint32_t fp_spill_mask,
const std::vector<uint8_t>& mapping_table,
const std::vector<uint8_t>& vmap_table,
- const std::vector<uint8_t>& native_gc_map);
+ const std::vector<uint8_t>& native_gc_map,
+ const std::vector<uint8_t>* cfi_info);
// Constructs a CompiledMethod for the QuickJniCompiler.
CompiledMethod(CompilerDriver& driver,
@@ -157,6 +158,10 @@
return *gc_map_;
}
+ const std::vector<uint8_t>* GetCFIInfo() const {
+ return cfi_info_;
+ }
+
private:
// For quick code, the size of the activation used by the code.
const size_t frame_size_in_bytes_;
@@ -172,6 +177,8 @@
// For quick code, a map keyed by native PC indices to bitmaps describing what dalvik registers
// are live. For portable code, the key is a dalvik PC.
std::vector<uint8_t>* gc_map_;
+ // For quick code, a FDE entry for the debug_frame section.
+ std::vector<uint8_t>* cfi_info_;
};
} // namespace art
diff --git a/compiler/compiler_backend.cc b/compiler/compiler_backend.cc
index eaa39f8..0afa665 100644
--- a/compiler/compiler_backend.cc
+++ b/compiler/compiler_backend.cc
@@ -83,6 +83,9 @@
}
+// Hack for CFI CIE initialization
+extern std::vector<uint8_t>* X86CFIInitialization();
+
class QuickBackend : public CompilerBackend {
public:
QuickBackend() : CompilerBackend(100) {}
@@ -135,10 +138,11 @@
}
bool WriteElf(art::File* file,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
const std::vector<const art::DexFile*>& dex_files,
const std::string& android_root,
bool is_host, const CompilerDriver& driver) const
+ OVERRIDE
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return art::ElfWriterQuick::Create(file, oat_writer, dex_files, android_root, is_host, driver);
}
@@ -165,11 +169,27 @@
bool set_max = cu->mir_graph->SetMaxAvailableNonSpecialCompilerTemps(max_temps);
CHECK(set_max);
}
- return mir_to_lir;;
+ return mir_to_lir;
}
void InitCompilationUnit(CompilationUnit& cu) const {}
+ /*
+ * @brief Generate and return Dwarf CFI initialization, if supported by the
+ * backend.
+ * @param driver CompilerDriver for this compile.
+ * @returns nullptr if not supported by backend or a vector of bytes for CFI DWARF
+ * information.
+ * @note This is used for backtrace information in generated code.
+ */
+ std::vector<uint8_t>* GetCallFrameInformationInitialization(const CompilerDriver& driver) const
+ OVERRIDE {
+ if (driver.GetInstructionSet() == kX86) {
+ return X86CFIInitialization();
+ }
+ return nullptr;
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(QuickBackend);
};
@@ -249,11 +269,12 @@
}
bool WriteElf(art::File* file,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
const std::vector<const art::DexFile*>& dex_files,
const std::string& android_root,
bool is_host, const CompilerDriver& driver) const
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ OVERRIDE
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return art::ElfWriterMclinker::Create(
file, oat_writer, dex_files, android_root, is_host, driver);
}
@@ -271,15 +292,17 @@
(1 << kSuppressExceptionEdges);
}
- bool isPortable() const { return true; }
+ bool IsPortable() const OVERRIDE {
+ return true;
+ }
- void SetBitcodeFileName(std::string const& filename) {
- typedef void (*SetBitcodeFileNameFn)(CompilerDriver&, std::string const&);
+ void SetBitcodeFileName(const CompilerDriver& driver, const std::string& filename) {
+ typedef void (*SetBitcodeFileNameFn)(const CompilerDriver&, const std::string&);
SetBitcodeFileNameFn set_bitcode_file_name =
reinterpret_cast<SetBitcodeFileNameFn>(compilerLLVMSetBitcodeFileName);
- set_bitcode_file_name(*this, filename);
+ set_bitcode_file_name(driver, filename);
}
private:
diff --git a/compiler/compiler_backend.h b/compiler/compiler_backend.h
index 01a69af..b473806 100644
--- a/compiler/compiler_backend.h
+++ b/compiler/compiler_backend.h
@@ -23,7 +23,7 @@
namespace art {
class Backend;
-class CompilationUnit;
+struct CompilationUnit;
class CompilerDriver;
class CompiledMethod;
class MIRGraph;
@@ -40,8 +40,9 @@
kPortable
};
- explicit CompilerBackend(int warning)
- : maximum_compilation_time_before_warning_(warning) {}
+ explicit CompilerBackend(uint64_t warning)
+ : maximum_compilation_time_before_warning_(warning) {
+ }
static CompilerBackend* Create(Kind kind);
@@ -49,7 +50,7 @@
virtual void UnInit(CompilerDriver& driver) const = 0;
- virtual CompiledMethod* Compile(CompilerDriver& compiler,
+ virtual CompiledMethod* Compile(CompilerDriver& driver,
const DexFile::CodeItem* code_item,
uint32_t access_flags,
InvokeType invoke_type,
@@ -66,7 +67,7 @@
virtual uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const = 0;
virtual bool WriteElf(art::File* file,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
const std::vector<const art::DexFile*>& dex_files,
const std::string& android_root,
bool is_host, const CompilerDriver& driver) const
@@ -79,8 +80,12 @@
return maximum_compilation_time_before_warning_;
}
- virtual bool IsPortable() const { return false; }
- void SetBitcodeFileName(std::string const& filename) {
+ virtual bool IsPortable() const {
+ return false;
+ }
+
+ void SetBitcodeFileName(const CompilerDriver& driver, const std::string& filename) {
+ UNUSED(driver);
UNUSED(filename);
}
@@ -88,8 +93,21 @@
virtual ~CompilerBackend() {}
+ /*
+ * @brief Generate and return Dwarf CFI initialization, if supported by the
+ * backend.
+ * @param driver CompilerDriver for this compile.
+ * @returns nullptr if not supported by backend or a vector of bytes for CFI DWARF
+ * information.
+ * @note This is used for backtrace information in generated code.
+ */
+ virtual std::vector<uint8_t>* GetCallFrameInformationInitialization(const CompilerDriver& driver)
+ const {
+ return nullptr;
+ }
+
private:
- uint64_t maximum_compilation_time_before_warning_;
+ const uint64_t maximum_compilation_time_before_warning_;
DISALLOW_COPY_AND_ASSIGN(CompilerBackend);
};
diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h
index 8447d23..b9a26d6 100644
--- a/compiler/dex/compiler_ir.h
+++ b/compiler/dex/compiler_ir.h
@@ -64,7 +64,7 @@
const CompilerBackend* compiler_backend;
InstructionSet instruction_set;
- const InstructionSetFeatures& GetInstructionSetFeatures() {
+ InstructionSetFeatures GetInstructionSetFeatures() {
return compiler_driver->GetInstructionSetFeatures();
}
// TODO: much of this info available elsewhere. Go to the original source?
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 6800f7b..2619258 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -128,7 +128,7 @@
}
}
-static CompiledMethod* CompileMethod(CompilerDriver& compiler,
+static CompiledMethod* CompileMethod(CompilerDriver& driver,
CompilerBackend* compiler_backend,
const DexFile::CodeItem* code_item,
uint32_t access_flags, InvokeType invoke_type,
@@ -143,11 +143,11 @@
}
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- CompilationUnit cu(&compiler.GetArenaPool());
+ CompilationUnit cu(driver.GetArenaPool());
- cu.compiler_driver = &compiler;
+ cu.compiler_driver = &driver;
cu.class_linker = class_linker;
- cu.instruction_set = compiler.GetInstructionSet();
+ cu.instruction_set = driver.GetInstructionSet();
cu.compiler_backend = compiler_backend;
DCHECK((cu.instruction_set == kThumb2) ||
(cu.instruction_set == kX86) ||
@@ -216,8 +216,8 @@
}
/* Create the pass driver and launch it */
- PassDriver driver(&cu);
- driver.Launch();
+ PassDriver pass_driver(&cu);
+ pass_driver.Launch();
if (cu.enable_debug & (1 << kDebugDumpCheckStats)) {
cu.mir_graph->DumpCheckStats();
@@ -257,9 +257,9 @@
}
cu.EndTiming();
- compiler.GetTimingsLogger().Start();
- compiler.GetTimingsLogger().AddLogger(cu.timings);
- compiler.GetTimingsLogger().End();
+ driver.GetTimingsLogger()->Start();
+ driver.GetTimingsLogger()->AddLogger(cu.timings);
+ driver.GetTimingsLogger()->End();
return result;
}
diff --git a/compiler/dex/frontend.h b/compiler/dex/frontend.h
index 8ce1206..22a7b8c 100644
--- a/compiler/dex/frontend.h
+++ b/compiler/dex/frontend.h
@@ -105,7 +105,7 @@
UniquePtr<art::llvm::IRBuilder> ir_builder_;
};
-struct CompiledMethod;
+class CompiledMethod;
class CompilerDriver;
} // namespace art
diff --git a/compiler/dex/pass.h b/compiler/dex/pass.h
index 255892e..9457d5b 100644
--- a/compiler/dex/pass.h
+++ b/compiler/dex/pass.h
@@ -22,8 +22,8 @@
namespace art {
// Forward declarations.
-class BasicBlock;
-class CompilationUnit;
+struct BasicBlock;
+struct CompilationUnit;
class Pass;
/**
diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc
index 3187fbb..70438ec 100644
--- a/compiler/dex/portable/mir_to_gbc.cc
+++ b/compiler/dex/portable/mir_to_gbc.cc
@@ -30,6 +30,7 @@
#include "dex/compiler_internals.h"
#include "dex/dataflow_iterator-inl.h"
#include "dex/frontend.h"
+#include "llvm/ir_builder.h"
#include "llvm/llvm_compilation_unit.h"
#include "llvm/utils_llvm.h"
#include "mir_to_gbc.h"
diff --git a/compiler/dex/portable/mir_to_gbc.h b/compiler/dex/portable/mir_to_gbc.h
index 2b681f6..e97634c 100644
--- a/compiler/dex/portable/mir_to_gbc.h
+++ b/compiler/dex/portable/mir_to_gbc.h
@@ -17,11 +17,18 @@
#ifndef ART_COMPILER_DEX_PORTABLE_MIR_TO_GBC_H_
#define ART_COMPILER_DEX_PORTABLE_MIR_TO_GBC_H_
+#include <llvm/ADT/ArrayRef.h>
+#include <llvm/IR/BasicBlock.h>
+#include <llvm/IR/IRBuilder.h>
+#include <llvm/IR/LLVMContext.h>
+#include <llvm/IR/Module.h>
+
#include "invoke_type.h"
#include "compiled_method.h"
#include "dex/compiler_enums.h"
#include "dex/compiler_ir.h"
#include "dex/backend.h"
+#include "llvm/intrinsic_helper.h"
#include "llvm/llvm_compilation_unit.h"
#include "safe_map.h"
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 3185449..b0b8d1e 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -1070,10 +1070,12 @@
DCHECK_EQ(fp_vmap_table_.size(), 0u);
vmap_encoder.PushBackUnsigned(0u); // Size is 0.
}
+
+ UniquePtr<std::vector<uint8_t> > cfi_info(ReturnCallFrameInformation());
CompiledMethod* result =
new CompiledMethod(*cu_->compiler_driver, cu_->instruction_set, code_buffer_, frame_size_,
core_spill_mask_, fp_spill_mask_, encoded_mapping_table_,
- vmap_encoder.GetData(), native_gc_map_);
+ vmap_encoder.GetData(), native_gc_map_, cfi_info.get());
return result;
}
@@ -1216,4 +1218,9 @@
AppendLIR(load_pc_rel);
}
+std::vector<uint8_t>* Mir2Lir::ReturnCallFrameInformation() {
+ // Default case is to do nothing.
+ return nullptr;
+}
+
} // namespace art
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index 3dcb964..b4d8dd6 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -31,7 +31,7 @@
class MethodVerifier;
} // namespace verifier
-class CallInfo;
+struct CallInfo;
class Mir2Lir;
enum InlineMethodOpcode : uint16_t {
@@ -61,6 +61,7 @@
kInlineOpIGet,
kInlineOpIPut,
};
+std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs);
enum InlineMethodFlags : uint16_t {
kNoInlineMethodFlags = 0x0000,
@@ -78,13 +79,13 @@
// kIntrinsicIsEmptyOrLength
kIntrinsicFlagLength = kIntrinsicFlagNone,
- kIntrinsicFlagIsEmpty = 1,
+ kIntrinsicFlagIsEmpty = kIntrinsicFlagMin,
// kIntrinsicIndexOf
- kIntrinsicFlagBase0 = 1,
+ kIntrinsicFlagBase0 = kIntrinsicFlagMin,
// kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas
- kIntrinsicFlagIsLong = 1,
+ kIntrinsicFlagIsLong = kIntrinsicFlagMin,
// kIntrinsicUnsafeGet, kIntrinsicUnsafePut
kIntrinsicFlagIsVolatile = 2,
// kIntrinsicUnsafePut, kIntrinsicUnsafeCas
@@ -187,7 +188,6 @@
*/
bool GenSpecial(Mir2Lir* backend, uint32_t method_idx);
- private:
/**
* To avoid multiple lookups of a class by its descriptor, we cache its
* type index in the IndexCache. These are the indexes into the IndexCache
@@ -311,6 +311,7 @@
kProtoCacheLast
};
+ private:
/**
* The maximum number of method parameters we support in the ProtoDef.
*/
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index b74052c..8f199f8 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -1089,6 +1089,11 @@
bool can_assume_type_is_in_dex_cache,
uint32_t type_idx, RegLocation rl_dest,
RegLocation rl_src);
+ /*
+ * @brief Generate the debug_frame FDE information if possible.
+ * @returns pointer to vector containg CFE information, or NULL.
+ */
+ virtual std::vector<uint8_t>* ReturnCallFrameInformation();
/**
* @brief Used to insert marker that can be used to associate MIR with LIR.
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 0613cdf..399001c 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -198,7 +198,7 @@
LockTemp(rX86_ARG2);
/* Build frame, return address already on stack */
- OpRegImm(kOpSub, rX86_SP, frame_size_ - 4);
+ stack_decrement_ = OpRegImm(kOpSub, rX86_SP, frame_size_ - 4);
/*
* We can safely skip the stack overflow check if we're
@@ -246,7 +246,7 @@
NewLIR0(kPseudoMethodExit);
UnSpillCoreRegs();
/* Remove frame except for return address */
- OpRegImm(kOpAdd, rX86_SP, frame_size_ - 4);
+ stack_increment_ = OpRegImm(kOpAdd, rX86_SP, frame_size_ - 4);
NewLIR0(kX86Ret);
}
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 421d51e..c97d0e6 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -302,6 +302,18 @@
*/
void InstallLiteralPools();
+ /*
+ * @brief Generate the debug_frame CFI information.
+ * @returns pointer to vector containing CFE information
+ */
+ static std::vector<uint8_t>* ReturnCommonCallFrameInformation();
+
+ /*
+ * @brief Generate the debug_frame FDE information.
+ * @returns pointer to vector containing CFE information
+ */
+ std::vector<uint8_t>* ReturnCallFrameInformation();
+
private:
void EmitPrefix(const X86EncodingMap* entry);
void EmitOpcode(const X86EncodingMap* entry);
@@ -549,6 +561,12 @@
// Instructions needing patching with PC relative code addresses.
GrowableArray<LIR*> call_method_insns_;
+
+ // Prologue decrement of stack pointer.
+ LIR* stack_decrement_;
+
+ // Epilogue increment of stack pointer.
+ LIR* stack_increment_;
};
} // namespace art
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index eea7191..7bb866d 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -539,7 +539,8 @@
: Mir2Lir(cu, mir_graph, arena),
method_address_insns_(arena, 100, kGrowableArrayMisc),
class_type_address_insns_(arena, 100, kGrowableArrayMisc),
- call_method_insns_(arena, 100, kGrowableArrayMisc) {
+ call_method_insns_(arena, 100, kGrowableArrayMisc),
+ stack_decrement_(nullptr), stack_increment_(nullptr) {
store_method_addr_used_ = false;
for (int i = 0; i < kX86Last; i++) {
if (X86Mir2Lir::EncodingMap[i].opcode != i) {
@@ -1118,4 +1119,166 @@
return true;
}
+/*
+ * @brief Enter a 32 bit quantity into the FDE buffer
+ * @param buf FDE buffer.
+ * @param data Data value.
+ */
+static void PushWord(std::vector<uint8_t>&buf, int data) {
+ buf.push_back(data & 0xff);
+ buf.push_back((data >> 8) & 0xff);
+ buf.push_back((data >> 16) & 0xff);
+ buf.push_back((data >> 24) & 0xff);
+}
+
+/*
+ * @brief Enter an 'advance LOC' into the FDE buffer
+ * @param buf FDE buffer.
+ * @param increment Amount by which to increase the current location.
+ */
+static void AdvanceLoc(std::vector<uint8_t>&buf, uint32_t increment) {
+ if (increment < 64) {
+ // Encoding in opcode.
+ buf.push_back(0x1 << 6 | increment);
+ } else if (increment < 256) {
+ // Single byte delta.
+ buf.push_back(0x02);
+ buf.push_back(increment);
+ } else if (increment < 256 * 256) {
+ // Two byte delta.
+ buf.push_back(0x03);
+ buf.push_back(increment & 0xff);
+ buf.push_back((increment >> 8) & 0xff);
+ } else {
+ // Four byte delta.
+ buf.push_back(0x04);
+ PushWord(buf, increment);
+ }
+}
+
+
+std::vector<uint8_t>* X86CFIInitialization() {
+ return X86Mir2Lir::ReturnCommonCallFrameInformation();
+}
+
+std::vector<uint8_t>* X86Mir2Lir::ReturnCommonCallFrameInformation() {
+ std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
+
+ // Length of the CIE (except for this field).
+ PushWord(*cfi_info, 16);
+
+ // CIE id.
+ PushWord(*cfi_info, 0xFFFFFFFFU);
+
+ // Version: 3.
+ cfi_info->push_back(0x03);
+
+ // Augmentation: empty string.
+ cfi_info->push_back(0x0);
+
+ // Code alignment: 1.
+ cfi_info->push_back(0x01);
+
+ // Data alignment: -4.
+ cfi_info->push_back(0x7C);
+
+ // Return address register (R8).
+ cfi_info->push_back(0x08);
+
+ // Initial return PC is 4(ESP): DW_CFA_def_cfa R4 4.
+ cfi_info->push_back(0x0C);
+ cfi_info->push_back(0x04);
+ cfi_info->push_back(0x04);
+
+ // Return address location: 0(SP): DW_CFA_offset R8 1 (* -4);.
+ cfi_info->push_back(0x2 << 6 | 0x08);
+ cfi_info->push_back(0x01);
+
+ // And 2 Noops to align to 4 byte boundary.
+ cfi_info->push_back(0x0);
+ cfi_info->push_back(0x0);
+
+ DCHECK_EQ(cfi_info->size() & 3, 0U);
+ return cfi_info;
+}
+
+static void EncodeUnsignedLeb128(std::vector<uint8_t>& buf, uint32_t value) {
+ uint8_t buffer[12];
+ uint8_t *ptr = EncodeUnsignedLeb128(buffer, value);
+ for (uint8_t *p = buffer; p < ptr; p++) {
+ buf.push_back(*p);
+ }
+}
+
+std::vector<uint8_t>* X86Mir2Lir::ReturnCallFrameInformation() {
+ std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
+
+ // Generate the FDE for the method.
+ DCHECK_NE(data_offset_, 0U);
+
+ // Length (will be filled in later in this routine).
+ PushWord(*cfi_info, 0);
+
+ // CIE_pointer (can be filled in by linker); might be left at 0 if there is only
+ // one CIE for the whole debug_frame section.
+ PushWord(*cfi_info, 0);
+
+ // 'initial_location' (filled in by linker).
+ PushWord(*cfi_info, 0);
+
+ // 'address_range' (number of bytes in the method).
+ PushWord(*cfi_info, data_offset_);
+
+ // The instructions in the FDE.
+ if (stack_decrement_ != nullptr) {
+ // Advance LOC to just past the stack decrement.
+ uint32_t pc = NEXT_LIR(stack_decrement_)->offset;
+ AdvanceLoc(*cfi_info, pc);
+
+ // Now update the offset to the call frame: DW_CFA_def_cfa_offset frame_size.
+ cfi_info->push_back(0x0e);
+ EncodeUnsignedLeb128(*cfi_info, frame_size_);
+
+ // We continue with that stack until the epilogue.
+ if (stack_increment_ != nullptr) {
+ uint32_t new_pc = NEXT_LIR(stack_increment_)->offset;
+ AdvanceLoc(*cfi_info, new_pc - pc);
+
+ // We probably have code snippets after the epilogue, so save the
+ // current state: DW_CFA_remember_state.
+ cfi_info->push_back(0x0a);
+
+ // We have now popped the stack: DW_CFA_def_cfa_offset 4. There is only the return
+ // PC on the stack now.
+ cfi_info->push_back(0x0e);
+ EncodeUnsignedLeb128(*cfi_info, 4);
+
+ // Everything after that is the same as before the epilogue.
+ // Stack bump was followed by RET instruction.
+ LIR *post_ret_insn = NEXT_LIR(NEXT_LIR(stack_increment_));
+ if (post_ret_insn != nullptr) {
+ pc = new_pc;
+ new_pc = post_ret_insn->offset;
+ AdvanceLoc(*cfi_info, new_pc - pc);
+ // Restore the state: DW_CFA_restore_state.
+ cfi_info->push_back(0x0b);
+ }
+ }
+ }
+
+ // Padding to a multiple of 4
+ while ((cfi_info->size() & 3) != 0) {
+ // DW_CFA_nop is encoded as 0.
+ cfi_info->push_back(0);
+ }
+
+ // Set the length of the FDE inside the generated bytes.
+ uint32_t length = cfi_info->size() - 4;
+ (*cfi_info)[0] = length;
+ (*cfi_info)[1] = length >> 8;
+ (*cfi_info)[2] = length >> 16;
+ (*cfi_info)[3] = length >> 24;
+ return cfi_info;
+}
+
} // namespace art
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 1b284de..708cce6 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -31,6 +31,7 @@
#include "dex/verification_results.h"
#include "dex/verified_method.h"
#include "dex/quick/dex_file_method_inliner.h"
+#include "driver/compiler_options.h"
#include "jni_internal.h"
#include "object_utils.h"
#include "runtime.h"
@@ -323,10 +324,12 @@
compiler_enable_auto_elf_loading_(NULL),
compiler_get_method_code_addr_(NULL),
support_boot_image_fixup_(instruction_set != kMips),
+ cfi_info_(nullptr),
dedupe_code_("dedupe code"),
dedupe_mapping_table_("dedupe mapping table"),
dedupe_vmap_table_("dedupe vmap table"),
- dedupe_gc_map_("dedupe gc map") {
+ dedupe_gc_map_("dedupe gc map"),
+ dedupe_cfi_info_("dedupe cfi info") {
DCHECK(compiler_options_ != nullptr);
DCHECK(verification_results_ != nullptr);
DCHECK(method_inliner_map_ != nullptr);
@@ -341,6 +344,11 @@
if (!image_) {
CHECK(image_classes_.get() == NULL);
}
+
+ // Are we generating CFI information?
+ if (compiler_options->GetGenerateGDBInformation()) {
+ cfi_info_.reset(compiler_backend_->GetCallFrameInformationInitialization(*this));
+ }
}
std::vector<uint8_t>* CompilerDriver::DeduplicateCode(const std::vector<uint8_t>& code) {
@@ -359,6 +367,13 @@
return dedupe_gc_map_.Add(Thread::Current(), code);
}
+std::vector<uint8_t>* CompilerDriver::DeduplicateCFIInfo(const std::vector<uint8_t>* cfi_info) {
+ if (cfi_info == nullptr) {
+ return nullptr;
+ }
+ return dedupe_cfi_info_.Add(Thread::Current(), *cfi_info);
+}
+
CompilerDriver::~CompilerDriver() {
Thread* self = Thread::Current();
{
@@ -441,11 +456,11 @@
void CompilerDriver::CompileAll(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- TimingLogger& timings) {
+ TimingLogger* timings) {
DCHECK(!Runtime::Current()->IsStarted());
UniquePtr<ThreadPool> thread_pool(new ThreadPool("Compiler driver thread pool", thread_count_ - 1));
- PreCompile(class_loader, dex_files, *thread_pool.get(), timings);
- Compile(class_loader, dex_files, *thread_pool.get(), timings);
+ PreCompile(class_loader, dex_files, thread_pool.get(), timings);
+ Compile(class_loader, dex_files, thread_pool.get(), timings);
if (dump_stats_) {
stats_->Dump();
}
@@ -483,7 +498,7 @@
}
}
-void CompilerDriver::CompileOne(mirror::ArtMethod* method, TimingLogger& timings) {
+void CompilerDriver::CompileOne(mirror::ArtMethod* method, TimingLogger* timings) {
DCHECK(!Runtime::Current()->IsStarted());
Thread* self = Thread::Current();
jobject jclass_loader;
@@ -510,7 +525,7 @@
dex_files.push_back(dex_file);
UniquePtr<ThreadPool> thread_pool(new ThreadPool("Compiler driver thread pool", 0U));
- PreCompile(jclass_loader, dex_files, *thread_pool.get(), timings);
+ PreCompile(jclass_loader, dex_files, thread_pool.get(), timings);
// Can we run DEX-to-DEX compiler on this class ?
DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile;
@@ -531,7 +546,7 @@
}
void CompilerDriver::Resolve(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings) {
+ ThreadPool* thread_pool, TimingLogger* timings) {
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
@@ -540,7 +555,7 @@
}
void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings) {
+ ThreadPool* thread_pool, TimingLogger* timings) {
LoadImageClasses(timings);
Resolve(class_loader, dex_files, thread_pool, timings);
@@ -625,13 +640,13 @@
}
// Make a list of descriptors for classes to include in the image
-void CompilerDriver::LoadImageClasses(TimingLogger& timings)
+void CompilerDriver::LoadImageClasses(TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_) {
if (!IsImage()) {
return;
}
- timings.NewSplit("LoadImageClasses");
+ timings->NewSplit("LoadImageClasses");
// Make a first class to load all classes explicitly listed in the file
Thread* self = Thread::Current();
ScopedObjectAccess soa(self);
@@ -713,9 +728,9 @@
MaybeAddToImageClasses(object->GetClass(), compiler_driver->image_classes_.get());
}
-void CompilerDriver::UpdateImageClasses(TimingLogger& timings) {
+void CompilerDriver::UpdateImageClasses(TimingLogger* timings) {
if (IsImage()) {
- timings.NewSplit("UpdateImageClasses");
+ timings->NewSplit("UpdateImageClasses");
// Update image_classes_ with classes for objects created by <clinit> methods.
Thread* self = Thread::Current();
@@ -1368,13 +1383,13 @@
jobject class_loader,
CompilerDriver* compiler,
const DexFile* dex_file,
- ThreadPool& thread_pool)
+ ThreadPool* thread_pool)
: index_(0),
class_linker_(class_linker),
class_loader_(class_loader),
compiler_(compiler),
dex_file_(dex_file),
- thread_pool_(&thread_pool) {}
+ thread_pool_(thread_pool) {}
ClassLinker* GetClassLinker() const {
CHECK(class_linker_ != NULL);
@@ -1628,7 +1643,7 @@
}
void CompilerDriver::ResolveDexFile(jobject class_loader, const DexFile& dex_file,
- ThreadPool& thread_pool, TimingLogger& timings) {
+ ThreadPool* thread_pool, TimingLogger* timings) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
// TODO: we could resolve strings here, although the string table is largely filled with class
@@ -1638,16 +1653,16 @@
if (IsImage()) {
// For images we resolve all types, such as array, whereas for applications just those with
// classdefs are resolved by ResolveClassFieldsAndMethods.
- timings.NewSplit("Resolve Types");
+ timings->NewSplit("Resolve Types");
context.ForAll(0, dex_file.NumTypeIds(), ResolveType, thread_count_);
}
- timings.NewSplit("Resolve MethodsAndFields");
+ timings->NewSplit("Resolve MethodsAndFields");
context.ForAll(0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods, thread_count_);
}
void CompilerDriver::Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings) {
+ ThreadPool* thread_pool, TimingLogger* timings) {
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
@@ -1702,8 +1717,8 @@
}
void CompilerDriver::VerifyDexFile(jobject class_loader, const DexFile& dex_file,
- ThreadPool& thread_pool, TimingLogger& timings) {
- timings.NewSplit("Verify Dex File");
+ ThreadPool* thread_pool, TimingLogger* timings) {
+ timings->NewSplit("Verify Dex File");
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, thread_pool);
context.ForAll(0, dex_file.NumClassDefs(), VerifyClass, thread_count_);
@@ -1805,8 +1820,8 @@
}
void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile& dex_file,
- ThreadPool& thread_pool, TimingLogger& timings) {
- timings.NewSplit("InitializeNoClinit");
+ ThreadPool* thread_pool, TimingLogger* timings) {
+ timings->NewSplit("InitializeNoClinit");
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
ParallelCompilationManager context(class_linker, jni_class_loader, this, &dex_file, thread_pool);
size_t thread_count;
@@ -1825,7 +1840,7 @@
void CompilerDriver::InitializeClasses(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings) {
+ ThreadPool* thread_pool, TimingLogger* timings) {
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
@@ -1834,7 +1849,7 @@
}
void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings) {
+ ThreadPool* thread_pool, TimingLogger* timings) {
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
@@ -1916,8 +1931,8 @@
}
void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_file,
- ThreadPool& thread_pool, TimingLogger& timings) {
- timings.NewSplit("Compile Dex File");
+ ThreadPool* thread_pool, TimingLogger* timings) {
+ timings->NewSplit("Compile Dex File");
ParallelCompilationManager context(Runtime::Current()->GetClassLinker(), class_loader, this,
&dex_file, thread_pool);
context.ForAll(0, dex_file.NumClassDefs(), CompilerDriver::CompileClass, thread_count_);
@@ -2037,38 +2052,38 @@
bool CompilerDriver::WriteElf(const std::string& android_root,
bool is_host,
const std::vector<const art::DexFile*>& dex_files,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
art::File* file)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return compiler_backend_->WriteElf(file, oat_writer, dex_files, android_root, is_host, *this);
}
void CompilerDriver::InstructionSetToLLVMTarget(InstructionSet instruction_set,
- std::string& target_triple,
- std::string& target_cpu,
- std::string& target_attr) {
+ std::string* target_triple,
+ std::string* target_cpu,
+ std::string* target_attr) {
switch (instruction_set) {
case kThumb2:
- target_triple = "thumb-none-linux-gnueabi";
- target_cpu = "cortex-a9";
- target_attr = "+thumb2,+neon,+neonfp,+vfp3,+db";
+ *target_triple = "thumb-none-linux-gnueabi";
+ *target_cpu = "cortex-a9";
+ *target_attr = "+thumb2,+neon,+neonfp,+vfp3,+db";
break;
case kArm:
- target_triple = "armv7-none-linux-gnueabi";
+ *target_triple = "armv7-none-linux-gnueabi";
// TODO: Fix for Nexus S.
- target_cpu = "cortex-a9";
+ *target_cpu = "cortex-a9";
// TODO: Fix for Xoom.
- target_attr = "+v7,+neon,+neonfp,+vfp3,+db";
+ *target_attr = "+v7,+neon,+neonfp,+vfp3,+db";
break;
case kX86:
- target_triple = "i386-pc-linux-gnu";
- target_attr = "";
+ *target_triple = "i386-pc-linux-gnu";
+ *target_attr = "";
break;
case kMips:
- target_triple = "mipsel-unknown-linux";
- target_attr = "mips32r2";
+ *target_triple = "mipsel-unknown-linux";
+ *target_attr = "mips32r2";
break;
default:
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 377eb6f..6ccbf0f 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -48,7 +48,7 @@
class CompilerOptions;
class DexCompilationUnit;
class DexFileToMethodInlinerMap;
-class InlineIGetIPutData;
+struct InlineIGetIPutData;
class OatWriter;
class ParallelCompilationManager;
class TimingLogger;
@@ -108,11 +108,11 @@
~CompilerDriver();
void CompileAll(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- TimingLogger& timings)
+ TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
// Compile a single Method.
- void CompileOne(mirror::ArtMethod* method, TimingLogger& timings)
+ void CompileOne(mirror::ArtMethod* method, TimingLogger* timings)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
VerificationResults* GetVerificationResults() const {
@@ -123,16 +123,15 @@
return method_inliner_map_;
}
- const InstructionSet& GetInstructionSet() const {
+ InstructionSet GetInstructionSet() const {
return instruction_set_;
}
- const InstructionSetFeatures& GetInstructionSetFeatures() const {
+ InstructionSetFeatures GetInstructionSetFeatures() const {
return instruction_set_features_;
}
const CompilerOptions& GetCompilerOptions() const {
- DCHECK(compiler_options_ != nullptr);
return *compiler_options_;
}
@@ -275,21 +274,21 @@
support_boot_image_fixup_ = support_boot_image_fixup;
}
- ArenaPool& GetArenaPool() {
- return arena_pool_;
+ ArenaPool* GetArenaPool() {
+ return &arena_pool_;
}
bool WriteElf(const std::string& android_root,
bool is_host,
const std::vector<const DexFile*>& dex_files,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
File* file);
- // TODO: move to a common home for llvm helpers once quick/portable are merged
+ // TODO: move to a common home for llvm helpers once quick/portable are merged.
static void InstructionSetToLLVMTarget(InstructionSet instruction_set,
- std::string& target_triple,
- std::string& target_cpu,
- std::string& target_attr);
+ std::string* target_triple,
+ std::string* target_cpu,
+ std::string* target_attr);
void SetCompilerContext(void* compiler_context) {
compiler_context_ = compiler_context;
@@ -310,8 +309,8 @@
return dump_passes_;
}
- CumulativeLogger& GetTimingsLogger() const {
- return *timings_logger_;
+ CumulativeLogger* GetTimingsLogger() const {
+ return timings_logger_;
}
class PatchInformation {
@@ -494,6 +493,15 @@
std::vector<uint8_t>* DeduplicateMappingTable(const std::vector<uint8_t>& code);
std::vector<uint8_t>* DeduplicateVMapTable(const std::vector<uint8_t>& code);
std::vector<uint8_t>* DeduplicateGCMap(const std::vector<uint8_t>& code);
+ std::vector<uint8_t>* DeduplicateCFIInfo(const std::vector<uint8_t>* cfi_info);
+
+ /*
+ * @brief return the pointer to the Call Frame Information.
+ * @return pointer to call frame information for this compilation.
+ */
+ std::vector<uint8_t>* GetCallFrameInformation() const {
+ return cfi_info_.get();
+ }
private:
// Compute constant code and method pointers when possible
@@ -507,43 +515,42 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings)
+ ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
- void LoadImageClasses(TimingLogger& timings);
+ void LoadImageClasses(TimingLogger* timings);
// Attempt to resolve all type, methods, fields, and strings
// referenced from code in the dex file following PathClassLoader
// ordering semantics.
void Resolve(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings)
+ ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
void ResolveDexFile(jobject class_loader, const DexFile& dex_file,
- ThreadPool& thread_pool, TimingLogger& timings)
+ ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
void Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings);
+ ThreadPool* thread_pool, TimingLogger* timings);
void VerifyDexFile(jobject class_loader, const DexFile& dex_file,
- ThreadPool& thread_pool, TimingLogger& timings)
+ ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
void InitializeClasses(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings)
+ ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
void InitializeClasses(jobject class_loader, const DexFile& dex_file,
- ThreadPool& thread_pool, TimingLogger& timings)
+ ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_, compiled_classes_lock_);
- void UpdateImageClasses(TimingLogger& timings)
- LOCKS_EXCLUDED(Locks::mutator_lock_);
+ void UpdateImageClasses(TimingLogger* timings) LOCKS_EXCLUDED(Locks::mutator_lock_);
static void FindClinitImageClassesCallback(mirror::Object* object, void* arg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings);
+ ThreadPool* thread_pool, TimingLogger* timings);
void CompileDexFile(jobject class_loader, const DexFile& dex_file,
- ThreadPool& thread_pool, TimingLogger& timings)
+ ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,
InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx,
@@ -627,6 +634,9 @@
bool support_boot_image_fixup_;
+ // Call Frame Information, which might be generated to help stack tracebacks.
+ UniquePtr<std::vector<uint8_t> > cfi_info_;
+
// DeDuplication data structures, these own the corresponding byte arrays.
class DedupeHashFunc {
public:
@@ -665,6 +675,7 @@
DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_mapping_table_;
DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_vmap_table_;
DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_gc_map_;
+ DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_cfi_info_;
DISALLOW_COPY_AND_ASSIGN(CompilerDriver);
};
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 34806ce..2b3af62 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -40,7 +40,7 @@
timings.StartSplit("CompileAll");
compiler_driver_->CompileAll(class_loader,
Runtime::Current()->GetCompileTimeClassPath(class_loader),
- timings);
+ &timings);
MakeAllExecutable(class_loader);
timings.EndSplit();
}
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 9f6745b..39738ab 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -43,7 +43,8 @@
large_method_threshold_(kDefaultLargeMethodThreshold),
small_method_threshold_(kDefaultSmallMethodThreshold),
tiny_method_threshold_(kDefaultTinyMethodThreshold),
- num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold)
+ num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold),
+ generate_gdb_information_(false)
#ifdef ART_SEA_IR_MODE
, sea_ir_mode_(false)
#endif
@@ -54,7 +55,8 @@
size_t large_method_threshold,
size_t small_method_threshold,
size_t tiny_method_threshold,
- size_t num_dex_methods_threshold
+ size_t num_dex_methods_threshold,
+ bool generate_gdb_information
#ifdef ART_SEA_IR_MODE
, bool sea_ir_mode
#endif
@@ -64,7 +66,8 @@
large_method_threshold_(large_method_threshold),
small_method_threshold_(small_method_threshold),
tiny_method_threshold_(tiny_method_threshold),
- num_dex_methods_threshold_(num_dex_methods_threshold)
+ num_dex_methods_threshold_(num_dex_methods_threshold),
+ generate_gdb_information_(generate_gdb_information)
#ifdef ART_SEA_IR_MODE
, sea_ir_mode_(sea_ir_mode)
#endif
@@ -118,6 +121,10 @@
bool GetSeaIrMode();
#endif
+ bool GetGenerateGDBInformation() const {
+ return generate_gdb_information_;
+ }
+
private:
CompilerFilter compiler_filter_;
size_t huge_method_threshold_;
@@ -125,6 +132,7 @@
size_t small_method_threshold_;
size_t tiny_method_threshold_;
size_t num_dex_methods_threshold_;
+ bool generate_gdb_information_;
#ifdef ART_SEA_IR_MODE
bool sea_ir_mode_;
diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc
index 6db3fa1..ccc26a1 100644
--- a/compiler/elf_writer.cc
+++ b/compiler/elf_writer.cc
@@ -30,12 +30,7 @@
namespace art {
-ElfWriter::ElfWriter(const CompilerDriver& driver, File* elf_file)
- : compiler_driver_(&driver), elf_file_(elf_file) {}
-
-ElfWriter::~ElfWriter() {}
-
-Elf32_Addr ElfWriter::GetOatDataAddress(ElfFile* elf_file) {
+uint32_t ElfWriter::GetOatDataAddress(ElfFile* elf_file) {
Elf32_Addr oatdata_address = elf_file->FindSymbolAddress(SHT_DYNSYM,
"oatdata",
false);
diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h
index 99dfc56..3610d1a 100644
--- a/compiler/elf_writer.h
+++ b/compiler/elf_writer.h
@@ -23,7 +23,6 @@
#include <vector>
#include "base/macros.h"
-#include "elf_utils.h"
#include "os.h"
namespace art {
@@ -42,21 +41,23 @@
size_t& oat_data_offset);
// Returns runtime oat_data runtime address for an opened ElfFile.
- static Elf32_Addr GetOatDataAddress(ElfFile* elf_file);
+ static uint32_t GetOatDataAddress(ElfFile* elf_file);
protected:
- ElfWriter(const CompilerDriver& driver, File* elf_file);
- virtual ~ElfWriter();
+ ElfWriter(const CompilerDriver& driver, File* elf_file)
+ : compiler_driver_(&driver), elf_file_(elf_file) {
+ }
- virtual bool Write(OatWriter& oat_writer,
+ virtual ~ElfWriter() {}
+
+ virtual bool Write(OatWriter* oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
- // Setup by constructor
- const CompilerDriver* compiler_driver_;
- File* elf_file_;
+ const CompilerDriver* const compiler_driver_;
+ File* const elf_file_;
};
} // namespace art
diff --git a/compiler/elf_writer_mclinker.cc b/compiler/elf_writer_mclinker.cc
index c7baf4f..b2d3a69 100644
--- a/compiler/elf_writer_mclinker.cc
+++ b/compiler/elf_writer_mclinker.cc
@@ -16,6 +16,7 @@
#include "elf_writer_mclinker.h"
+#include <llvm/Support/ELF.h>
#include <llvm/Support/TargetSelect.h>
#include <mcld/Environment.h>
@@ -32,7 +33,6 @@
#include "class_linker.h"
#include "dex_method_iterator.h"
#include "driver/compiler_driver.h"
-#include "elf_file.h"
#include "globals.h"
#include "mirror/art_method.h"
#include "mirror/art_method-inl.h"
@@ -44,12 +44,14 @@
namespace art {
ElfWriterMclinker::ElfWriterMclinker(const CompilerDriver& driver, File* elf_file)
- : ElfWriter(driver, elf_file), oat_input_(NULL) {}
+ : ElfWriter(driver, elf_file), oat_input_(nullptr) {
+}
-ElfWriterMclinker::~ElfWriterMclinker() {}
+ElfWriterMclinker::~ElfWriterMclinker() {
+}
bool ElfWriterMclinker::Create(File* elf_file,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host,
@@ -58,29 +60,29 @@
return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
}
-bool ElfWriterMclinker::Write(OatWriter& oat_writer,
+bool ElfWriterMclinker::Write(OatWriter* oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host) {
std::vector<uint8_t> oat_contents;
- oat_contents.reserve(oat_writer.GetSize());
+ oat_contents.reserve(oat_writer->GetSize());
VectorOutputStream output_stream("oat contents", oat_contents);
- CHECK(oat_writer.Write(output_stream));
- CHECK_EQ(oat_writer.GetSize(), oat_contents.size());
+ CHECK(oat_writer->Write(&output_stream));
+ CHECK_EQ(oat_writer->GetSize(), oat_contents.size());
Init();
AddOatInput(oat_contents);
-#if defined(ART_USE_PORTABLE_COMPILER)
- AddMethodInputs(dex_files);
- AddRuntimeInputs(android_root, is_host);
-#endif
+ if (kUsePortableCompiler) {
+ AddMethodInputs(dex_files);
+ AddRuntimeInputs(android_root, is_host);
+ }
if (!Link()) {
return false;
}
oat_contents.clear();
-#if defined(ART_USE_PORTABLE_COMPILER)
- FixupOatMethodOffsets(dex_files);
-#endif
+ if (kUsePortableCompiler) {
+ FixupOatMethodOffsets(dex_files);
+ }
return true;
}
@@ -100,9 +102,9 @@
std::string target_cpu;
std::string target_attr;
CompilerDriver::InstructionSetToLLVMTarget(compiler_driver_->GetInstructionSet(),
- target_triple,
- target_cpu,
- target_attr);
+ &target_triple,
+ &target_cpu,
+ &target_attr);
// Based on mclinker's llvm-mcld.cpp main() and LinkerTest
//
@@ -236,7 +238,6 @@
text_section);
}
-#if defined(ART_USE_PORTABLE_COMPILER)
void ElfWriterMclinker::AddMethodInputs(const std::vector<const DexFile*>& dex_files) {
DCHECK(oat_input_ != NULL);
@@ -320,7 +321,6 @@
mcld::Input* libm_lib_input_input = ir_builder_->ReadInput(libm_lib, libm_lib);
CHECK(libm_lib_input_input != NULL);
}
-#endif
bool ElfWriterMclinker::Link() {
// link inputs
@@ -345,7 +345,6 @@
return true;
}
-#if defined(ART_USE_PORTABLE_COMPILER)
void ElfWriterMclinker::FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files) {
std::string error_msg;
UniquePtr<ElfFile> elf_file(ElfFile::Open(elf_file_, true, false, &error_msg));
@@ -409,6 +408,5 @@
}
return compiled_code_offset;
}
-#endif
} // namespace art
diff --git a/compiler/elf_writer_mclinker.h b/compiler/elf_writer_mclinker.h
index 8ee7231..13757ed 100644
--- a/compiler/elf_writer_mclinker.h
+++ b/compiler/elf_writer_mclinker.h
@@ -37,11 +37,11 @@
class CompiledCode;
-class ElfWriterMclinker : public ElfWriter {
+class ElfWriterMclinker FINAL : public ElfWriter {
public:
// Write an ELF file. Returns true on success, false on failure.
static bool Create(File* file,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host,
@@ -49,10 +49,11 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
protected:
- virtual bool Write(OatWriter& oat_writer,
- const std::vector<const DexFile*>& dex_files,
- const std::string& android_root,
- bool is_host)
+ bool Write(OatWriter* oat_writer,
+ const std::vector<const DexFile*>& dex_files,
+ const std::string& android_root,
+ bool is_host)
+ OVERRIDE
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
@@ -65,13 +66,11 @@
void AddCompiledCodeInput(const CompiledCode& compiled_code);
void AddRuntimeInputs(const std::string& android_root, bool is_host);
bool Link();
-#if defined(ART_USE_PORTABLE_COMPILER)
void FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
uint32_t FixupCompiledCodeOffset(ElfFile& elf_file,
- ::llvm::ELF::Elf32_Addr oatdata_address,
+ uint32_t oatdata_address,
const CompiledCode& compiled_code);
-#endif
// Setup by Init()
UniquePtr<mcld::LinkerConfig> linker_config_;
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 3191374..4b823ef 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -29,13 +29,8 @@
namespace art {
-ElfWriterQuick::ElfWriterQuick(const CompilerDriver& driver, File* elf_file)
- : ElfWriter(driver, elf_file) {}
-
-ElfWriterQuick::~ElfWriterQuick() {}
-
bool ElfWriterQuick::Create(File* elf_file,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host,
@@ -44,7 +39,7 @@
return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
}
-bool ElfWriterQuick::Write(OatWriter& oat_writer,
+bool ElfWriterQuick::Write(OatWriter* oat_writer,
const std::vector<const DexFile*>& dex_files_unused,
const std::string& android_root_unused,
bool is_host_unused) {
@@ -103,6 +98,7 @@
// | .rodata\0 |
// | .text\0 |
// | .shstrtab\0 |
+ // | .debug_frame\0 |
// +-------------------------+
// | Elf32_Shdr NULL |
// | Elf32_Shdr .dynsym |
@@ -112,6 +108,9 @@
// | Elf32_Shdr .rodata |
// | Elf32_Shdr .dynamic |
// | Elf32_Shdr .shstrtab |
+ // | Elf32_Shdr .debug_info | (Optional)
+ // | Elf32_Shdr .debug_abbrev| (Optional)
+ // | Elf32_Shdr .debug_frame | (Optional)
// +-------------------------+
// phase 1: computing offsets
@@ -197,7 +196,7 @@
// .rodata
uint32_t oat_data_alignment = kPageSize;
uint32_t oat_data_offset = expected_offset = RoundUp(expected_offset, oat_data_alignment);
- const OatHeader& oat_header = oat_writer.GetOatHeader();
+ const OatHeader& oat_header = oat_writer->GetOatHeader();
CHECK(oat_header.IsValid());
uint32_t oat_data_size = oat_header.GetExecutableOffset();
expected_offset += oat_data_size;
@@ -210,9 +209,9 @@
uint32_t oat_exec_alignment = kPageSize;
CHECK_ALIGNED(expected_offset, kPageSize);
uint32_t oat_exec_offset = expected_offset = RoundUp(expected_offset, oat_exec_alignment);
- uint32_t oat_exec_size = oat_writer.GetSize() - oat_data_size;
+ uint32_t oat_exec_size = oat_writer->GetSize() - oat_data_size;
expected_offset += oat_exec_size;
- CHECK_EQ(oat_data_offset + oat_writer.GetSize(), expected_offset);
+ CHECK_EQ(oat_data_offset + oat_writer->GetSize(), expected_offset);
if (debug) {
LOG(INFO) << "oat_exec_offset=" << oat_exec_offset << std::hex << " " << oat_exec_offset;
LOG(INFO) << "oat_exec_size=" << oat_exec_size << std::hex << " " << oat_exec_size;
@@ -264,6 +263,18 @@
uint32_t shstrtab_shstrtab_offset = shstrtab.size();
shstrtab += ".shstrtab";
shstrtab += '\0';
+ uint32_t shstrtab_debug_info_offset = shstrtab.size();
+ shstrtab += ".debug_info";
+ shstrtab += '\0';
+ uint32_t shstrtab_debug_abbrev_offset = shstrtab.size();
+ shstrtab += ".debug_abbrev";
+ shstrtab += '\0';
+ uint32_t shstrtab_debug_str_offset = shstrtab.size();
+ shstrtab += ".debug_str";
+ shstrtab += '\0';
+ uint32_t shstrtab_debug_frame_offset = shstrtab.size();
+ shstrtab += ".debug_frame";
+ shstrtab += '\0';
uint32_t shstrtab_size = shstrtab.size();
expected_offset += shstrtab_size;
if (debug) {
@@ -271,6 +282,52 @@
LOG(INFO) << "shstrtab_size=" << shstrtab_size << std::hex << " " << shstrtab_size;
}
+ // Create debug informatin, if we have it.
+ bool generateDebugInformation = compiler_driver_->GetCallFrameInformation() != nullptr;
+ std::vector<uint8_t> dbg_info;
+ std::vector<uint8_t> dbg_abbrev;
+ std::vector<uint8_t> dbg_str;
+ if (generateDebugInformation) {
+ FillInCFIInformation(oat_writer, &dbg_info, &dbg_abbrev, &dbg_str);
+ }
+
+ uint32_t shdbg_info_alignment = 1;
+ uint32_t shdbg_info_offset = expected_offset;
+ uint32_t shdbg_info_size = dbg_info.size();
+ expected_offset += shdbg_info_size;
+ if (debug) {
+ LOG(INFO) << "shdbg_info_offset=" << shdbg_info_offset << std::hex << " " << shdbg_info_offset;
+ LOG(INFO) << "shdbg_info_size=" << shdbg_info_size << std::hex << " " << shdbg_info_size;
+ }
+
+ uint32_t shdbg_abbrev_alignment = 1;
+ uint32_t shdbg_abbrev_offset = expected_offset;
+ uint32_t shdbg_abbrev_size = dbg_abbrev.size();
+ expected_offset += shdbg_abbrev_size;
+ if (debug) {
+ LOG(INFO) << "shdbg_abbrev_offset=" << shdbg_abbrev_offset << std::hex << " " << shdbg_abbrev_offset;
+ LOG(INFO) << "shdbg_abbrev_size=" << shdbg_abbrev_size << std::hex << " " << shdbg_abbrev_size;
+ }
+
+ uint32_t shdbg_frm_alignment = 4;
+ uint32_t shdbg_frm_offset = expected_offset = RoundUp(expected_offset, shdbg_frm_alignment);
+ uint32_t shdbg_frm_size =
+ generateDebugInformation ? compiler_driver_->GetCallFrameInformation()->size() : 0;
+ expected_offset += shdbg_frm_size;
+ if (debug) {
+ LOG(INFO) << "shdbg_frm_offset=" << shdbg_frm_offset << std::hex << " " << shdbg_frm_offset;
+ LOG(INFO) << "shdbg_frm_size=" << shdbg_frm_size << std::hex << " " << shdbg_frm_size;
+ }
+
+ uint32_t shdbg_str_alignment = 1;
+ uint32_t shdbg_str_offset = expected_offset;
+ uint32_t shdbg_str_size = dbg_str.size();
+ expected_offset += shdbg_str_size;
+ if (debug) {
+ LOG(INFO) << "shdbg_str_offset=" << shdbg_str_offset << std::hex << " " << shdbg_str_offset;
+ LOG(INFO) << "shdbg_str_size=" << shdbg_str_size << std::hex << " " << shdbg_str_size;
+ }
+
// section headers (after all sections)
uint32_t shdr_alignment = sizeof(Elf32_Word);
uint32_t shdr_offset = expected_offset = RoundUp(expected_offset, shdr_alignment);
@@ -282,7 +339,11 @@
const uint8_t SH_TEXT = 5;
const uint8_t SH_DYNAMIC = 6;
const uint8_t SH_SHSTRTAB = 7;
- const uint8_t SH_NUM = 8;
+ const uint8_t SH_DBG_INFO = 8;
+ const uint8_t SH_DBG_ABRV = 9;
+ const uint8_t SH_DBG_FRM = 10;
+ const uint8_t SH_DBG_STR = 11;
+ const uint8_t SH_NUM = generateDebugInformation ? 12 : 8;
uint32_t shdr_size = sizeof(Elf32_Shdr) * SH_NUM;
expected_offset += shdr_size;
if (debug) {
@@ -559,6 +620,52 @@
section_headers[SH_SHSTRTAB].sh_addralign = shstrtab_alignment;
section_headers[SH_SHSTRTAB].sh_entsize = 0;
+ if (generateDebugInformation) {
+ section_headers[SH_DBG_INFO].sh_name = shstrtab_debug_info_offset;
+ section_headers[SH_DBG_INFO].sh_type = SHT_PROGBITS;
+ section_headers[SH_DBG_INFO].sh_flags = 0;
+ section_headers[SH_DBG_INFO].sh_addr = 0;
+ section_headers[SH_DBG_INFO].sh_offset = shdbg_info_offset;
+ section_headers[SH_DBG_INFO].sh_size = shdbg_info_size;
+ section_headers[SH_DBG_INFO].sh_link = 0;
+ section_headers[SH_DBG_INFO].sh_info = 0;
+ section_headers[SH_DBG_INFO].sh_addralign = shdbg_info_alignment;
+ section_headers[SH_DBG_INFO].sh_entsize = 0;
+
+ section_headers[SH_DBG_ABRV].sh_name = shstrtab_debug_abbrev_offset;
+ section_headers[SH_DBG_ABRV].sh_type = SHT_PROGBITS;
+ section_headers[SH_DBG_ABRV].sh_flags = 0;
+ section_headers[SH_DBG_ABRV].sh_addr = 0;
+ section_headers[SH_DBG_ABRV].sh_offset = shdbg_abbrev_offset;
+ section_headers[SH_DBG_ABRV].sh_size = shdbg_abbrev_size;
+ section_headers[SH_DBG_ABRV].sh_link = 0;
+ section_headers[SH_DBG_ABRV].sh_info = 0;
+ section_headers[SH_DBG_ABRV].sh_addralign = shdbg_abbrev_alignment;
+ section_headers[SH_DBG_ABRV].sh_entsize = 0;
+
+ section_headers[SH_DBG_FRM].sh_name = shstrtab_debug_frame_offset;
+ section_headers[SH_DBG_FRM].sh_type = SHT_PROGBITS;
+ section_headers[SH_DBG_FRM].sh_flags = 0;
+ section_headers[SH_DBG_FRM].sh_addr = 0;
+ section_headers[SH_DBG_FRM].sh_offset = shdbg_frm_offset;
+ section_headers[SH_DBG_FRM].sh_size = shdbg_frm_size;
+ section_headers[SH_DBG_FRM].sh_link = 0;
+ section_headers[SH_DBG_FRM].sh_info = 0;
+ section_headers[SH_DBG_FRM].sh_addralign = shdbg_frm_alignment;
+ section_headers[SH_DBG_FRM].sh_entsize = 0;
+
+ section_headers[SH_DBG_STR].sh_name = shstrtab_debug_str_offset;
+ section_headers[SH_DBG_STR].sh_type = SHT_PROGBITS;
+ section_headers[SH_DBG_STR].sh_flags = 0;
+ section_headers[SH_DBG_STR].sh_addr = 0;
+ section_headers[SH_DBG_STR].sh_offset = shdbg_str_offset;
+ section_headers[SH_DBG_STR].sh_size = shdbg_str_size;
+ section_headers[SH_DBG_STR].sh_link = 0;
+ section_headers[SH_DBG_STR].sh_info = 0;
+ section_headers[SH_DBG_STR].sh_addralign = shdbg_str_alignment;
+ section_headers[SH_DBG_STR].sh_entsize = 0;
+ }
+
// phase 3: writing file
// Elf32_Ehdr
@@ -622,13 +729,13 @@
return false;
}
BufferedOutputStream output_stream(new FileOutputStream(elf_file_));
- if (!oat_writer.Write(output_stream)) {
+ if (!oat_writer->Write(&output_stream)) {
PLOG(ERROR) << "Failed to write .rodata and .text for " << elf_file_->GetPath();
return false;
}
// .dynamic
- DCHECK_LE(oat_data_offset + oat_writer.GetSize(), dynamic_offset);
+ DCHECK_LE(oat_data_offset + oat_writer->GetSize(), dynamic_offset);
if (static_cast<off_t>(dynamic_offset) != lseek(elf_file_->Fd(), dynamic_offset, SEEK_SET)) {
PLOG(ERROR) << "Failed to seek to .dynamic offset " << dynamic_offset
<< " for " << elf_file_->GetPath();
@@ -651,8 +758,62 @@
return false;
}
+ if (generateDebugInformation) {
+ // .debug_info
+ DCHECK_LE(shstrtab_offset + shstrtab_size, shdbg_info_offset);
+ if (static_cast<off_t>(shdbg_info_offset) != lseek(elf_file_->Fd(), shdbg_info_offset, SEEK_SET)) {
+ PLOG(ERROR) << "Failed to seek to .shdbg_info offset " << shdbg_info_offset
+ << " for " << elf_file_->GetPath();
+ return false;
+ }
+ if (!elf_file_->WriteFully(&dbg_info[0], shdbg_info_size)) {
+ PLOG(ERROR) << "Failed to write .debug_info for " << elf_file_->GetPath();
+ return false;
+ }
+
+ // .debug_abbrev
+ DCHECK_LE(shdbg_info_offset + shdbg_info_size, shdbg_abbrev_offset);
+ if (static_cast<off_t>(shdbg_abbrev_offset) != lseek(elf_file_->Fd(), shdbg_abbrev_offset, SEEK_SET)) {
+ PLOG(ERROR) << "Failed to seek to .shdbg_abbrev offset " << shdbg_abbrev_offset
+ << " for " << elf_file_->GetPath();
+ return false;
+ }
+ if (!elf_file_->WriteFully(&dbg_abbrev[0], shdbg_abbrev_size)) {
+ PLOG(ERROR) << "Failed to write .debug_abbrev for " << elf_file_->GetPath();
+ return false;
+ }
+
+ // .debug_frame
+ DCHECK_LE(shdbg_abbrev_offset + shdbg_abbrev_size, shdbg_frm_offset);
+ if (static_cast<off_t>(shdbg_frm_offset) != lseek(elf_file_->Fd(), shdbg_frm_offset, SEEK_SET)) {
+ PLOG(ERROR) << "Failed to seek to .shdbg_frm offset " << shdbg_frm_offset
+ << " for " << elf_file_->GetPath();
+ return false;
+ }
+ if (!elf_file_->WriteFully(&((*compiler_driver_->GetCallFrameInformation())[0]), shdbg_frm_size)) {
+ PLOG(ERROR) << "Failed to write .debug_frame for " << elf_file_->GetPath();
+ return false;
+ }
+
+ // .debug_str
+ DCHECK_LE(shdbg_frm_offset + shdbg_frm_size, shdbg_str_offset);
+ if (static_cast<off_t>(shdbg_str_offset) != lseek(elf_file_->Fd(), shdbg_str_offset, SEEK_SET)) {
+ PLOG(ERROR) << "Failed to seek to .shdbg_str offset " << shdbg_str_offset
+ << " for " << elf_file_->GetPath();
+ return false;
+ }
+ if (!elf_file_->WriteFully(&dbg_str[0], shdbg_str_size)) {
+ PLOG(ERROR) << "Failed to write .debug_frame for " << elf_file_->GetPath();
+ return false;
+ }
+ }
+
// section headers (after all sections)
- DCHECK_LE(shstrtab_offset + shstrtab_size, shdr_offset);
+ if (generateDebugInformation) {
+ DCHECK_LE(shdbg_str_offset + shdbg_str_size, shdr_offset);
+ } else {
+ DCHECK_LE(shstrtab_offset + shstrtab_size, shdr_offset);
+ }
if (static_cast<off_t>(shdr_offset) != lseek(elf_file_->Fd(), shdr_offset, SEEK_SET)) {
PLOG(ERROR) << "Failed to seek to ELF section headers offset " << shdr_offset
<< " for " << elf_file_->GetPath();
@@ -665,6 +826,164 @@
VLOG(compiler) << "ELF file written successfully: " << elf_file_->GetPath();
return true;
+} // NOLINT(readability/fn_size)
+
+static void UpdateWord(std::vector<uint8_t>*buf, int offset, int data) {
+ (*buf)[offset+0] = data;
+ (*buf)[offset+1] = data >> 8;
+ (*buf)[offset+2] = data >> 16;
+ (*buf)[offset+3] = data >> 24;
+}
+
+static void PushWord(std::vector<uint8_t>*buf, int data) {
+ buf->push_back(data & 0xff);
+ buf->push_back((data >> 8) & 0xff);
+ buf->push_back((data >> 16) & 0xff);
+ buf->push_back((data >> 24) & 0xff);
+}
+
+static void PushHalf(std::vector<uint8_t>*buf, int data) {
+ buf->push_back(data & 0xff);
+ buf->push_back((data >> 8) & 0xff);
+}
+
+// DWARF constants needed to generate CFI information.
+enum {
+ // Tag encodings.
+ DW_TAG_compile_unit = 0x11,
+ DW_TAG_subprogram = 0X2e,
+
+ // Attribute encodings.
+ DW_AT_name = 0x03,
+ DW_AT_low_pc = 0x11,
+ DW_AT_high_pc = 0x12,
+ DW_AT_language = 0x13,
+
+ // Constant encoding.
+ DW_CHILDREN_no = 0x00,
+ DW_CHILDREN_yes = 0x01,
+
+ // Attribute form encodings.
+ DW_FORM_addr = 0x01,
+ DW_FORM_data1 = 0x0b,
+ DW_FORM_strp = 0x0e,
+
+ // Language encoding.
+ DW_LANG_Java = 0x000b
+};
+
+void ElfWriterQuick::FillInCFIInformation(OatWriter* oat_writer,
+ std::vector<uint8_t>* dbg_info,
+ std::vector<uint8_t>* dbg_abbrev,
+ std::vector<uint8_t>* dbg_str) {
+ // Create the debug_abbrev section with boilerplate information.
+ // We only care about low_pc and high_pc right now for the compilation
+ // unit and methods.
+
+ // Tag 1: Compilation unit: DW_TAG_compile_unit.
+ dbg_abbrev->push_back(1);
+ dbg_abbrev->push_back(DW_TAG_compile_unit);
+
+ // There are children (the methods).
+ dbg_abbrev->push_back(DW_CHILDREN_yes);
+
+ // DW_LANG_Java DW_FORM_data1.
+ dbg_abbrev->push_back(DW_AT_language);
+ dbg_abbrev->push_back(DW_FORM_data1);
+
+ // DW_AT_low_pc DW_FORM_addr.
+ dbg_abbrev->push_back(DW_AT_low_pc);
+ dbg_abbrev->push_back(DW_FORM_addr);
+
+ // DW_AT_high_pc DW_FORM_addr.
+ dbg_abbrev->push_back(DW_AT_high_pc);
+ dbg_abbrev->push_back(DW_FORM_addr);
+
+ // End of DW_TAG_compile_unit.
+ PushHalf(dbg_abbrev, 0);
+
+ // Tag 2: Compilation unit: DW_TAG_subprogram.
+ dbg_abbrev->push_back(2);
+ dbg_abbrev->push_back(DW_TAG_subprogram);
+
+ // There are no children.
+ dbg_abbrev->push_back(DW_CHILDREN_no);
+
+ // Name of the method.
+ dbg_abbrev->push_back(DW_AT_name);
+ dbg_abbrev->push_back(DW_FORM_strp);
+
+ // DW_AT_low_pc DW_FORM_addr.
+ dbg_abbrev->push_back(DW_AT_low_pc);
+ dbg_abbrev->push_back(DW_FORM_addr);
+
+ // DW_AT_high_pc DW_FORM_addr.
+ dbg_abbrev->push_back(DW_AT_high_pc);
+ dbg_abbrev->push_back(DW_FORM_addr);
+
+ // End of DW_TAG_subprogram.
+ PushHalf(dbg_abbrev, 0);
+
+ // Start the debug_info section with the header information
+ // 'unit_length' will be filled in later.
+ PushWord(dbg_info, 0);
+
+ // 'version' - 3.
+ PushHalf(dbg_info, 3);
+
+ // Offset into .debug_abbrev section (always 0).
+ PushWord(dbg_info, 0);
+
+ // Address size: 4.
+ dbg_info->push_back(4);
+
+ // Start the description for the compilation unit.
+ // This uses tag 1.
+ dbg_info->push_back(1);
+
+ // The language is Java.
+ dbg_info->push_back(DW_LANG_Java);
+
+ // Leave space for low_pc and high_pc.
+ int low_pc_offset = dbg_info->size();
+ PushWord(dbg_info, 0);
+ PushWord(dbg_info, 0);
+
+ // Walk through the information in the method table, and enter into dbg_info.
+ const std::vector<OatWriter::DebugInfo>& dbg = oat_writer->GetCFIMethodInfo();
+ uint32_t low_pc = 0xFFFFFFFFU;
+ uint32_t high_pc = 0;
+
+ for (uint32_t i = 0; i < dbg.size(); i++) {
+ const OatWriter::DebugInfo& info = dbg[i];
+ if (info.low_pc_ < low_pc) {
+ low_pc = info.low_pc_;
+ }
+ if (info.high_pc_ > high_pc) {
+ high_pc = info.high_pc_;
+ }
+
+ // Start a new TAG: subroutine (2).
+ dbg_info->push_back(2);
+
+ // Enter the name into the string table (and NUL terminate).
+ uint32_t str_offset = dbg_str->size();
+ dbg_str->insert(dbg_str->end(), info.method_name_.begin(), info.method_name_.end());
+ dbg_str->push_back('\0');
+
+ // Enter name, low_pc, high_pc.
+ PushWord(dbg_info, str_offset);
+ PushWord(dbg_info, info.low_pc_);
+ PushWord(dbg_info, info.high_pc_);
+ }
+
+ // One byte terminator
+ dbg_info->push_back(0);
+
+ // We have now walked all the methods. Fill in lengths and low/high PCs.
+ UpdateWord(dbg_info, 0, dbg_info->size() - 4);
+ UpdateWord(dbg_info, low_pc_offset, low_pc);
+ UpdateWord(dbg_info, low_pc_offset + 4, high_pc);
}
} // namespace art
diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h
index f36d06f..dec75dc 100644
--- a/compiler/elf_writer_quick.h
+++ b/compiler/elf_writer_quick.h
@@ -21,11 +21,11 @@
namespace art {
-class ElfWriterQuick : public ElfWriter {
+class ElfWriterQuick FINAL : public ElfWriter {
public:
// Write an ELF file. Returns true on success, false on failure.
static bool Create(File* file,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host,
@@ -33,15 +33,27 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
protected:
- virtual bool Write(OatWriter& oat_writer,
- const std::vector<const DexFile*>& dex_files,
- const std::string& android_root,
- bool is_host)
+ bool Write(OatWriter* oat_writer,
+ const std::vector<const DexFile*>& dex_files,
+ const std::string& android_root,
+ bool is_host)
+ OVERRIDE
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
- ElfWriterQuick(const CompilerDriver& driver, File* elf_file);
- ~ElfWriterQuick();
+ ElfWriterQuick(const CompilerDriver& driver, File* elf_file)
+ : ElfWriter(driver, elf_file) {}
+ ~ElfWriterQuick() {}
+
+ /*
+ * @brief Generate the DWARF debug_info and debug_abbrev sections
+ * @param oat_writer The Oat file Writer.
+ * @param dbg_info Compilation unit information.
+ * @param dbg_abbrev Abbreviations used to generate dbg_info.
+ * @param dbg_str Debug strings.
+ */
+ void FillInCFIInformation(OatWriter* oat_writer, std::vector<uint8_t>* dbg_info,
+ std::vector<uint8_t>* dbg_abbrev, std::vector<uint8_t>* dbg_str);
DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick);
};
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index 16e2aa2..619b056 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -49,15 +49,15 @@
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
TimingLogger timings("ImageTest::WriteRead", false, false);
timings.StartSplit("CompileAll");
-#if defined(ART_USE_PORTABLE_COMPILER)
- // TODO: we disable this for portable so the test executes in a reasonable amount of time.
- // We shouldn't need to do this.
- runtime_->SetCompilerFilter(Runtime::kInterpretOnly);
-#endif
+ if (kUsePortableCompiler) {
+ // TODO: we disable this for portable so the test executes in a reasonable amount of time.
+ // We shouldn't need to do this.
+ compiler_options_->SetCompilerFilter(CompilerOptions::kInterpretOnly);
+ }
for (const DexFile* dex_file : class_linker->GetBootClassPath()) {
dex_file->EnableWrite();
}
- compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings);
+ compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
ScopedObjectAccess soa(Thread::Current());
OatWriter oat_writer(class_linker->GetBootClassPath(),
@@ -65,7 +65,7 @@
bool success = compiler_driver_->WriteElf(GetTestAndroidRoot(),
!kIsTargetBuild,
class_linker->GetBootClassPath(),
- oat_writer,
+ &oat_writer,
tmp_elf.GetFile());
ASSERT_TRUE(success);
timings.EndSplit();
diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc
index a5acd2a..4ce714a 100644
--- a/compiler/llvm/compiler_llvm.cc
+++ b/compiler/llvm/compiler_llvm.cc
@@ -175,16 +175,16 @@
} // namespace llvm
} // namespace art
-inline static art::llvm::CompilerLLVM* ContextOf(art::CompilerDriver& driver) {
+static art::llvm::CompilerLLVM* ContextOf(art::CompilerDriver& driver) {
void *compiler_context = driver.GetCompilerContext();
CHECK(compiler_context != NULL);
return reinterpret_cast<art::llvm::CompilerLLVM*>(compiler_context);
}
-inline static const art::llvm::CompilerLLVM* ContextOf(const art::CompilerDriver& driver) {
+static art::llvm::CompilerLLVM* ContextOf(const art::CompilerDriver& driver) {
void *compiler_context = driver.GetCompilerContext();
CHECK(compiler_context != NULL);
- return reinterpret_cast<const art::llvm::CompilerLLVM*>(compiler_context);
+ return reinterpret_cast<art::llvm::CompilerLLVM*>(compiler_context);
}
extern "C" void ArtInitCompilerContext(art::CompilerDriver& driver) {
@@ -233,7 +233,7 @@
return result;
}
-extern "C" void compilerLLVMSetBitcodeFileName(art::CompilerDriver& driver,
- std::string const& filename) {
+extern "C" void compilerLLVMSetBitcodeFileName(const art::CompilerDriver& driver,
+ const std::string& filename) {
ContextOf(driver)->SetBitcodeFileName(filename);
}
diff --git a/compiler/llvm/compiler_llvm.h b/compiler/llvm/compiler_llvm.h
index 65bc16b..c2211fb 100644
--- a/compiler/llvm/compiler_llvm.h
+++ b/compiler/llvm/compiler_llvm.h
@@ -70,7 +70,7 @@
return insn_set_;
}
- void SetBitcodeFileName(std::string const& filename) {
+ void SetBitcodeFileName(const std::string& filename) {
bitcode_filename_ = filename;
}
diff --git a/compiler/llvm/llvm_compilation_unit.cc b/compiler/llvm/llvm_compilation_unit.cc
index d23706d..1d027f9 100644
--- a/compiler/llvm/llvm_compilation_unit.cc
+++ b/compiler/llvm/llvm_compilation_unit.cc
@@ -199,7 +199,8 @@
std::string target_triple;
std::string target_cpu;
std::string target_attr;
- CompilerDriver::InstructionSetToLLVMTarget(GetInstructionSet(), target_triple, target_cpu, target_attr);
+ CompilerDriver::InstructionSetToLLVMTarget(GetInstructionSet(), &target_triple, &target_cpu,
+ &target_attr);
std::string errmsg;
const ::llvm::Target* target =
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 55a962f..6dbba9f 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -105,7 +105,7 @@
jobject class_loader = NULL;
if (kCompile) {
TimingLogger timings("OatTest::WriteRead", false, false);
- compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings);
+ compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
}
ScopedObjectAccess soa(Thread::Current());
@@ -119,12 +119,12 @@
bool success = compiler_driver_->WriteElf(GetTestAndroidRoot(),
!kIsTargetBuild,
class_linker->GetBootClassPath(),
- oat_writer,
+ &oat_writer,
tmp.GetFile());
ASSERT_TRUE(success);
if (kCompile) { // OatWriter strips the code, regenerate to compare
- compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings);
+ compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
}
std::string error_msg;
UniquePtr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), NULL, false,
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 7c5669a..a400bdd 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -229,7 +229,7 @@
oat_classes_.push_back(oat_class);
offset += oat_class->SizeOf();
}
- oat_dex_files_[i]->UpdateChecksum(*oat_header_);
+ oat_dex_files_[i]->UpdateChecksum(oat_header_);
}
return offset;
}
@@ -293,7 +293,7 @@
class_def_index++, (*oat_class_index)++) {
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
offset = InitOatCodeClassDef(offset, *oat_class_index, class_def_index, dex_file, class_def);
- oat_classes_[*oat_class_index]->UpdateChecksum(*oat_header_);
+ oat_classes_[*oat_class_index]->UpdateChecksum(oat_header_);
}
return offset;
}
@@ -378,6 +378,27 @@
uint32_t thumb_offset = compiled_method->CodeDelta();
quick_code_offset = offset + sizeof(code_size) + thumb_offset;
+ std::vector<uint8_t>* cfi_info = compiler_driver_->GetCallFrameInformation();
+ if (cfi_info != nullptr) {
+ // Copy in the FDE, if present
+ const std::vector<uint8_t>* fde = compiled_method->GetCFIInfo();
+ if (fde != nullptr) {
+ // Copy the information into cfi_info and then fix the address in the new copy.
+ int cur_offset = cfi_info->size();
+ cfi_info->insert(cfi_info->end(), fde->begin(), fde->end());
+
+ // Set the 'initial_location' field to address the start of the method.
+ uint32_t new_value = quick_code_offset - oat_header_->GetExecutableOffset();
+ uint32_t offset_to_update = cur_offset + 2*sizeof(uint32_t);
+ (*cfi_info)[offset_to_update+0] = new_value;
+ (*cfi_info)[offset_to_update+1] = new_value >> 8;
+ (*cfi_info)[offset_to_update+2] = new_value >> 16;
+ (*cfi_info)[offset_to_update+3] = new_value >> 24;
+ method_info_.push_back(DebugInfo(PrettyMethod(class_def_method_index, dex_file, false),
+ new_value, new_value + code_size));
+ }
+ }
+
// Deduplicate code arrays
SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter =
code_offsets_.find(quick_code);
@@ -499,42 +520,42 @@
}
#define DCHECK_OFFSET() \
- DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out.Seek(0, kSeekCurrent)) \
+ DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \
<< "file_offset=" << file_offset << " relative_offset=" << relative_offset
#define DCHECK_OFFSET_() \
- DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out.Seek(0, kSeekCurrent)) \
+ DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
<< "file_offset=" << file_offset << " offset_=" << offset_
-bool OatWriter::Write(OutputStream& out) {
- const size_t file_offset = out.Seek(0, kSeekCurrent);
+bool OatWriter::Write(OutputStream* out) {
+ const size_t file_offset = out->Seek(0, kSeekCurrent);
- if (!out.WriteFully(oat_header_, sizeof(*oat_header_))) {
- PLOG(ERROR) << "Failed to write oat header to " << out.GetLocation();
+ if (!out->WriteFully(oat_header_, sizeof(*oat_header_))) {
+ PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
return false;
}
size_oat_header_ += sizeof(*oat_header_);
- if (!out.WriteFully(image_file_location_.data(), image_file_location_.size())) {
- PLOG(ERROR) << "Failed to write oat header image file location to " << out.GetLocation();
+ if (!out->WriteFully(image_file_location_.data(), image_file_location_.size())) {
+ PLOG(ERROR) << "Failed to write oat header image file location to " << out->GetLocation();
return false;
}
size_oat_header_image_file_location_ += image_file_location_.size();
if (!WriteTables(out, file_offset)) {
- LOG(ERROR) << "Failed to write oat tables to " << out.GetLocation();
+ LOG(ERROR) << "Failed to write oat tables to " << out->GetLocation();
return false;
}
size_t relative_offset = WriteCode(out, file_offset);
if (relative_offset == 0) {
- LOG(ERROR) << "Failed to write oat code to " << out.GetLocation();
+ LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
return false;
}
relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
if (relative_offset == 0) {
- LOG(ERROR) << "Failed to write oat code for dex files to " << out.GetLocation();
+ LOG(ERROR) << "Failed to write oat code for dex files to " << out->GetLocation();
return false;
}
@@ -577,26 +598,26 @@
#undef DO_STAT
VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \
- CHECK_EQ(file_offset + size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+ CHECK_EQ(file_offset + size_total, static_cast<uint32_t>(out->Seek(0, kSeekCurrent)));
CHECK_EQ(size_, size_total);
}
- CHECK_EQ(file_offset + size_, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+ CHECK_EQ(file_offset + size_, static_cast<uint32_t>(out->Seek(0, kSeekCurrent)));
CHECK_EQ(size_, relative_offset);
return true;
}
-bool OatWriter::WriteTables(OutputStream& out, const size_t file_offset) {
+bool OatWriter::WriteTables(OutputStream* out, const size_t file_offset) {
for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
if (!oat_dex_files_[i]->Write(this, out, file_offset)) {
- PLOG(ERROR) << "Failed to write oat dex information to " << out.GetLocation();
+ PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation();
return false;
}
}
for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
uint32_t expected_offset = file_offset + oat_dex_files_[i]->dex_file_offset_;
- off_t actual_offset = out.Seek(expected_offset, kSeekSet);
+ off_t actual_offset = out->Seek(expected_offset, kSeekSet);
if (static_cast<uint32_t>(actual_offset) != expected_offset) {
const DexFile* dex_file = (*dex_files_)[i];
PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
@@ -604,29 +625,29 @@
return false;
}
const DexFile* dex_file = (*dex_files_)[i];
- if (!out.WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
+ if (!out->WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation()
- << " to " << out.GetLocation();
+ << " to " << out->GetLocation();
return false;
}
size_dex_file_ += dex_file->GetHeader().file_size_;
}
for (size_t i = 0; i != oat_classes_.size(); ++i) {
if (!oat_classes_[i]->Write(this, out, file_offset)) {
- PLOG(ERROR) << "Failed to write oat methods information to " << out.GetLocation();
+ PLOG(ERROR) << "Failed to write oat methods information to " << out->GetLocation();
return false;
}
}
return true;
}
-size_t OatWriter::WriteCode(OutputStream& out, const size_t file_offset) {
+size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset) {
size_t relative_offset = oat_header_->GetExecutableOffset();
- off_t new_offset = out.Seek(size_executable_offset_alignment_, kSeekCurrent);
+ off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
size_t expected_file_offset = file_offset + relative_offset;
if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
- << " Expected: " << expected_file_offset << " File: " << out.GetLocation();
+ << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
return 0;
}
DCHECK_OFFSET();
@@ -637,10 +658,10 @@
do { \
uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set); \
uint32_t alignment_padding = aligned_offset - relative_offset; \
- out.Seek(alignment_padding, kSeekCurrent); \
+ out->Seek(alignment_padding, kSeekCurrent); \
size_trampoline_alignment_ += alignment_padding; \
- if (!out.WriteFully(&(*field)[0], field->size())) { \
- PLOG(ERROR) << "Failed to write " # field " to " << out.GetLocation(); \
+ if (!out->WriteFully(&(*field)[0], field->size())) { \
+ PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \
return false; \
} \
size_ ## field += field->size(); \
@@ -662,7 +683,7 @@
return relative_offset;
}
-size_t OatWriter::WriteCodeDexFiles(OutputStream& out,
+size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
const size_t file_offset,
size_t relative_offset) {
size_t oat_class_index = 0;
@@ -678,7 +699,7 @@
return relative_offset;
}
-size_t OatWriter::WriteCodeDexFile(OutputStream& out, const size_t file_offset,
+size_t OatWriter::WriteCodeDexFile(OutputStream* out, const size_t file_offset,
size_t relative_offset, size_t* oat_class_index,
const DexFile& dex_file) {
for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs();
@@ -694,12 +715,12 @@
}
void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx,
- const DexFile& dex_file, OutputStream& out) const {
+ const DexFile& dex_file, const OutputStream& out) const {
PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(method_idx, dex_file)
<< " to " << out.GetLocation();
}
-size_t OatWriter::WriteCodeClassDef(OutputStream& out,
+size_t OatWriter::WriteCodeClassDef(OutputStream* out,
const size_t file_offset,
size_t relative_offset,
size_t oat_class_index,
@@ -747,7 +768,7 @@
return relative_offset;
}
-size_t OatWriter::WriteCodeMethod(OutputStream& out, const size_t file_offset,
+size_t OatWriter::WriteCodeMethod(OutputStream* out, const size_t file_offset,
size_t relative_offset, size_t oat_class_index,
size_t class_def_method_index, size_t* method_offsets_index,
bool is_static, uint32_t method_idx, const DexFile& dex_file) {
@@ -763,12 +784,12 @@
uint32_t aligned_offset = compiled_method->AlignCode(relative_offset);
uint32_t aligned_code_delta = aligned_offset - relative_offset;
if (aligned_code_delta != 0) {
- off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent);
+ off_t new_offset = out->Seek(aligned_code_delta, kSeekCurrent);
size_code_alignment_ += aligned_code_delta;
uint32_t expected_offset = file_offset + aligned_offset;
if (static_cast<uint32_t>(new_offset) != expected_offset) {
PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
- << " Expected: " << expected_offset << " File: " << out.GetLocation();
+ << " Expected: " << expected_offset << " File: " << out->GetLocation();
return 0;
}
relative_offset += aligned_code_delta;
@@ -787,15 +808,15 @@
<< PrettyMethod(method_idx, dex_file);
} else {
DCHECK(code_offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file);
- if (!out.WriteFully(&code_size, sizeof(code_size))) {
- ReportWriteFailure("method code size", method_idx, dex_file, out);
+ if (!out->WriteFully(&code_size, sizeof(code_size))) {
+ ReportWriteFailure("method code size", method_idx, dex_file, *out);
return 0;
}
size_code_size_ += sizeof(code_size);
relative_offset += sizeof(code_size);
DCHECK_OFFSET();
- if (!out.WriteFully(&(*quick_code)[0], code_size)) {
- ReportWriteFailure("method code", method_idx, dex_file, out);
+ if (!out->WriteFully(&(*quick_code)[0], code_size)) {
+ ReportWriteFailure("method code", method_idx, dex_file, *out);
return 0;
}
size_code_ += code_size;
@@ -818,8 +839,8 @@
DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
|| relative_offset == method_offsets.mapping_table_offset_)
<< PrettyMethod(method_idx, dex_file);
- if (!out.WriteFully(&mapping_table[0], mapping_table_size)) {
- ReportWriteFailure("mapping table", method_idx, dex_file, out);
+ if (!out->WriteFully(&mapping_table[0], mapping_table_size)) {
+ ReportWriteFailure("mapping table", method_idx, dex_file, *out);
return 0;
}
size_mapping_table_ += mapping_table_size;
@@ -842,8 +863,8 @@
DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
|| relative_offset == method_offsets.vmap_table_offset_)
<< PrettyMethod(method_idx, dex_file);
- if (!out.WriteFully(&vmap_table[0], vmap_table_size)) {
- ReportWriteFailure("vmap table", method_idx, dex_file, out);
+ if (!out->WriteFully(&vmap_table[0], vmap_table_size)) {
+ ReportWriteFailure("vmap table", method_idx, dex_file, *out);
return 0;
}
size_vmap_table_ += vmap_table_size;
@@ -866,8 +887,8 @@
DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
|| relative_offset == method_offsets.gc_map_offset_)
<< PrettyMethod(method_idx, dex_file);
- if (!out.WriteFully(&gc_map[0], gc_map_size)) {
- ReportWriteFailure("GC map", method_idx, dex_file, out);
+ if (!out->WriteFully(&gc_map[0], gc_map_size)) {
+ ReportWriteFailure("GC map", method_idx, dex_file, *out);
return 0;
}
size_gc_map_ += gc_map_size;
@@ -897,42 +918,42 @@
+ (sizeof(methods_offsets_[0]) * methods_offsets_.size());
}
-void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
- oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
- oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
- oat_header.UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_));
- oat_header.UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
- oat_header.UpdateChecksum(&methods_offsets_[0],
+void OatWriter::OatDexFile::UpdateChecksum(OatHeader* oat_header) const {
+ oat_header->UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
+ oat_header->UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
+ oat_header->UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_));
+ oat_header->UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
+ oat_header->UpdateChecksum(&methods_offsets_[0],
sizeof(methods_offsets_[0]) * methods_offsets_.size());
}
bool OatWriter::OatDexFile::Write(OatWriter* oat_writer,
- OutputStream& out,
+ OutputStream* out,
const size_t file_offset) const {
DCHECK_OFFSET_();
- if (!out.WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
- PLOG(ERROR) << "Failed to write dex file location length to " << out.GetLocation();
+ if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
+ PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation();
return false;
}
oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
- if (!out.WriteFully(dex_file_location_data_, dex_file_location_size_)) {
- PLOG(ERROR) << "Failed to write dex file location data to " << out.GetLocation();
+ if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
+ PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation();
return false;
}
oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
- if (!out.WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
- PLOG(ERROR) << "Failed to write dex file location checksum to " << out.GetLocation();
+ if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
+ PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation();
return false;
}
oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
- if (!out.WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
- PLOG(ERROR) << "Failed to write dex file offset to " << out.GetLocation();
+ if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
+ PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation();
return false;
}
oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
- if (!out.WriteFully(&methods_offsets_[0],
+ if (!out->WriteFully(&methods_offsets_[0],
sizeof(methods_offsets_[0]) * methods_offsets_.size())) {
- PLOG(ERROR) << "Failed to write methods offsets to " << out.GetLocation();
+ PLOG(ERROR) << "Failed to write methods offsets to " << out->GetLocation();
return false;
}
oat_writer->size_oat_dex_file_methods_offsets_ +=
@@ -1020,48 +1041,48 @@
+ (sizeof(method_offsets_[0]) * method_offsets_.size());
}
-void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const {
- oat_header.UpdateChecksum(&status_, sizeof(status_));
- oat_header.UpdateChecksum(&type_, sizeof(type_));
+void OatWriter::OatClass::UpdateChecksum(OatHeader* oat_header) const {
+ oat_header->UpdateChecksum(&status_, sizeof(status_));
+ oat_header->UpdateChecksum(&type_, sizeof(type_));
if (method_bitmap_size_ != 0) {
CHECK_EQ(kOatClassSomeCompiled, type_);
- oat_header.UpdateChecksum(&method_bitmap_size_, sizeof(method_bitmap_size_));
- oat_header.UpdateChecksum(method_bitmap_->GetRawStorage(), method_bitmap_size_);
+ oat_header->UpdateChecksum(&method_bitmap_size_, sizeof(method_bitmap_size_));
+ oat_header->UpdateChecksum(method_bitmap_->GetRawStorage(), method_bitmap_size_);
}
- oat_header.UpdateChecksum(&method_offsets_[0],
- sizeof(method_offsets_[0]) * method_offsets_.size());
+ oat_header->UpdateChecksum(&method_offsets_[0],
+ sizeof(method_offsets_[0]) * method_offsets_.size());
}
bool OatWriter::OatClass::Write(OatWriter* oat_writer,
- OutputStream& out,
+ OutputStream* out,
const size_t file_offset) const {
DCHECK_OFFSET_();
- if (!out.WriteFully(&status_, sizeof(status_))) {
- PLOG(ERROR) << "Failed to write class status to " << out.GetLocation();
+ if (!out->WriteFully(&status_, sizeof(status_))) {
+ PLOG(ERROR) << "Failed to write class status to " << out->GetLocation();
return false;
}
oat_writer->size_oat_class_status_ += sizeof(status_);
- if (!out.WriteFully(&type_, sizeof(type_))) {
- PLOG(ERROR) << "Failed to write oat class type to " << out.GetLocation();
+ if (!out->WriteFully(&type_, sizeof(type_))) {
+ PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation();
return false;
}
oat_writer->size_oat_class_type_ += sizeof(type_);
if (method_bitmap_size_ != 0) {
CHECK_EQ(kOatClassSomeCompiled, type_);
- if (!out.WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
- PLOG(ERROR) << "Failed to write method bitmap size to " << out.GetLocation();
+ if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
+ PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation();
return false;
}
oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_);
- if (!out.WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
- PLOG(ERROR) << "Failed to write method bitmap to " << out.GetLocation();
+ if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
+ PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation();
return false;
}
oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_;
}
- if (!out.WriteFully(&method_offsets_[0],
+ if (!out->WriteFully(&method_offsets_[0],
sizeof(method_offsets_[0]) * method_offsets_.size())) {
- PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation();
+ PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation();
return false;
}
oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size();
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 067c789..3d4b48a 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -78,10 +78,23 @@
return size_;
}
- bool Write(OutputStream& out);
+ bool Write(OutputStream* out);
~OatWriter();
+ struct DebugInfo {
+ DebugInfo(const std::string& method_name, uint32_t low_pc, uint32_t high_pc)
+ : method_name_(method_name), low_pc_(low_pc), high_pc_(high_pc) {
+ }
+ std::string method_name_;
+ uint32_t low_pc_;
+ uint32_t high_pc_;
+ };
+
+ const std::vector<DebugInfo>& GetCFIMethodInfo() const {
+ return method_info_;
+ }
+
private:
size_t InitOatHeader();
size_t InitOatDexFiles(size_t offset);
@@ -105,28 +118,28 @@
bool is_native, InvokeType type, uint32_t method_idx, const DexFile&)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool WriteTables(OutputStream& out, const size_t file_offset);
- size_t WriteCode(OutputStream& out, const size_t file_offset);
- size_t WriteCodeDexFiles(OutputStream& out, const size_t file_offset, size_t relative_offset);
- size_t WriteCodeDexFile(OutputStream& out, const size_t file_offset, size_t relative_offset,
+ bool WriteTables(OutputStream* out, const size_t file_offset);
+ size_t WriteCode(OutputStream* out, const size_t file_offset);
+ size_t WriteCodeDexFiles(OutputStream* out, const size_t file_offset, size_t relative_offset);
+ size_t WriteCodeDexFile(OutputStream* out, const size_t file_offset, size_t relative_offset,
size_t* oat_class_index, const DexFile& dex_file);
- size_t WriteCodeClassDef(OutputStream& out, const size_t file_offset, size_t relative_offset,
+ size_t WriteCodeClassDef(OutputStream* out, const size_t file_offset, size_t relative_offset,
size_t oat_class_index, const DexFile& dex_file,
const DexFile::ClassDef& class_def);
- size_t WriteCodeMethod(OutputStream& out, const size_t file_offset, size_t relative_offset,
+ size_t WriteCodeMethod(OutputStream* out, const size_t file_offset, size_t relative_offset,
size_t oat_class_index, size_t class_def_method_index,
size_t* method_offsets_index, bool is_static, uint32_t method_idx,
const DexFile& dex_file);
void ReportWriteFailure(const char* what, uint32_t method_idx, const DexFile& dex_file,
- OutputStream& out) const;
+ const OutputStream& out) const;
class OatDexFile {
public:
explicit OatDexFile(size_t offset, const DexFile& dex_file);
size_t SizeOf() const;
- void UpdateChecksum(OatHeader& oat_header) const;
- bool Write(OatWriter* oat_writer, OutputStream& out, const size_t file_offset) const;
+ void UpdateChecksum(OatHeader* oat_header) const;
+ bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const;
// Offset of start of OatDexFile from beginning of OatHeader. It is
// used to validate file position when writing.
@@ -153,8 +166,8 @@
size_t GetOatMethodOffsetsOffsetFromOatHeader(size_t class_def_method_index_) const;
size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const;
size_t SizeOf() const;
- void UpdateChecksum(OatHeader& oat_header) const;
- bool Write(OatWriter* oat_writer, OutputStream& out, const size_t file_offset) const;
+ void UpdateChecksum(OatHeader* oat_header) const;
+ bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const;
CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const {
DCHECK(compiled_methods_ != NULL);
@@ -205,6 +218,8 @@
DISALLOW_COPY_AND_ASSIGN(OatClass);
};
+ std::vector<DebugInfo> method_info_;
+
const CompilerDriver* const compiler_driver_;
// note OatFile does not take ownership of the DexFiles
diff --git a/compiler/utils/arena_bit_vector.cc b/compiler/utils/arena_bit_vector.cc
index 6f03524..220ff14 100644
--- a/compiler/utils/arena_bit_vector.cc
+++ b/compiler/utils/arena_bit_vector.cc
@@ -42,6 +42,8 @@
ArenaBitVector::ArenaBitVector(ArenaAllocator* arena, unsigned int start_bits,
bool expandable, OatBitMapKind kind)
- : BitVector(start_bits, expandable, new (arena) ArenaBitVectorAllocator(arena)), kind_(kind) {}
+ : BitVector(start_bits, expandable, new (arena) ArenaBitVectorAllocator(arena)), kind_(kind) {
+ UNUSED(kind_);
+}
} // namespace art
diff --git a/compiler/utils/arm/managed_register_arm.cc b/compiler/utils/arm/managed_register_arm.cc
index 57c2305..1fdc110 100644
--- a/compiler/utils/arm/managed_register_arm.cc
+++ b/compiler/utils/arm/managed_register_arm.cc
@@ -21,16 +21,6 @@
namespace art {
namespace arm {
-// We need all registers for caching of locals.
-// Register R9 .. R15 are reserved.
-static const int kNumberOfAvailableCoreRegisters = (R8 - R0) + 1;
-static const int kNumberOfAvailableSRegisters = kNumberOfSRegisters;
-static const int kNumberOfAvailableDRegisters = kNumberOfDRegisters;
-static const int kNumberOfAvailableOverlappingDRegisters =
- kNumberOfOverlappingDRegisters;
-static const int kNumberOfAvailableRegisterPairs = kNumberOfRegisterPairs;
-
-
// Returns true if this managed-register overlaps the other managed-register.
bool ArmManagedRegister::Overlaps(const ArmManagedRegister& other) const {
if (IsNoRegister() || other.IsNoRegister()) return false;
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index c9be4ed..296254d 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -282,7 +282,9 @@
byte* cursor_;
byte* limit_;
AssemblerFixup* fixup_;
+#ifndef NDEBUG
bool fixups_processed_;
+#endif
// Head of linked list of slow paths
SlowPath* slow_path_;
diff --git a/compiler/utils/mips/managed_register_mips.cc b/compiler/utils/mips/managed_register_mips.cc
index 195dafb..5a8c048 100644
--- a/compiler/utils/mips/managed_register_mips.cc
+++ b/compiler/utils/mips/managed_register_mips.cc
@@ -21,17 +21,6 @@
namespace art {
namespace mips {
-// These core registers are never available for allocation.
-static const Register kReservedCoreRegistersArray[] = { S0, S1 };
-
-// We need all registers for caching.
-static const int kNumberOfAvailableCoreRegisters = (S7 - T0) + 1;
-static const int kNumberOfAvailableFRegisters = kNumberOfFRegisters;
-static const int kNumberOfAvailableDRegisters = kNumberOfDRegisters;
-static const int kNumberOfAvailableOverlappingDRegisters =
- kNumberOfOverlappingDRegisters;
-static const int kNumberOfAvailableRegisterPairs = kNumberOfRegisterPairs;
-
bool MipsManagedRegister::Overlaps(const MipsManagedRegister& other) const {
if (IsNoRegister() || other.IsNoRegister()) return false;
CHECK(IsValidManagedRegister());
diff --git a/compiler/utils/x86/managed_register_x86.cc b/compiler/utils/x86/managed_register_x86.cc
index 4697d06..7fae7a8 100644
--- a/compiler/utils/x86/managed_register_x86.cc
+++ b/compiler/utils/x86/managed_register_x86.cc
@@ -21,19 +21,6 @@
namespace art {
namespace x86 {
-// These cpu registers are never available for allocation.
-static const Register kReservedCpuRegistersArray[] = { ESP };
-
-
-// We reduce the number of available registers for allocation in debug-code
-// mode in order to increase register pressure.
-
-// We need all registers for caching.
-static const int kNumberOfAvailableCpuRegisters = kNumberOfCpuRegisters;
-static const int kNumberOfAvailableXmmRegisters = kNumberOfXmmRegisters;
-static const int kNumberOfAvailableRegisterPairs = kNumberOfRegisterPairs;
-
-
// Define register pairs.
// This list must be kept in sync with the RegisterPair enum.
#define REGISTER_PAIR_LIST(P) \
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index a082e36..041a66b 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -349,9 +349,9 @@
dump_passes,
&compiler_phases_timings));
- driver->GetCompilerBackend()->SetBitcodeFileName(bitcode_filename);
+ driver->GetCompilerBackend()->SetBitcodeFileName(*driver.get(), bitcode_filename);
- driver->CompileAll(class_loader, dex_files, timings);
+ driver->CompileAll(class_loader, dex_files, &timings);
timings.NewSplit("dex2oat OatWriter");
std::string image_file_location;
@@ -377,7 +377,7 @@
&timings);
TimingLogger::ScopedSplit split("Writing ELF", &timings);
- if (!driver->WriteElf(android_root, is_host, dex_files, oat_writer, oat_file)) {
+ if (!driver->WriteElf(android_root, is_host, dex_files, &oat_writer, oat_file)) {
LOG(ERROR) << "Failed to write ELF file " << oat_file->GetPath();
return NULL;
}
@@ -760,6 +760,7 @@
bool dump_passes = false;
bool dump_slow_timing = kIsDebugBuild;
bool watch_dog_enabled = !kIsTargetBuild;
+ bool generate_gdb_information = kIsDebugBuild;
for (int i = 0; i < argc; i++) {
const StringPiece option(argv[i]);
@@ -797,6 +798,10 @@
watch_dog_enabled = true;
} else if (option == "--no-watch-dog") {
watch_dog_enabled = false;
+ } else if (option == "--gen-gdb-info") {
+ generate_gdb_information = true;
+ } else if (option == "--no-gen-gdb-info") {
+ generate_gdb_information = false;
} else if (option.starts_with("-j")) {
const char* thread_count_str = option.substr(strlen("-j")).data();
if (!ParseInt(thread_count_str, &thread_count)) {
@@ -1042,7 +1047,8 @@
large_method_threshold,
small_method_threshold,
tiny_method_threshold,
- num_dex_methods_threshold
+ num_dex_methods_threshold,
+ generate_gdb_information
#ifdef ART_SEA_IR_MODE
, compiler_options.sea_ir_ = true;
#endif
@@ -1302,7 +1308,7 @@
LOG(INFO) << Dumpable<TimingLogger>(timings);
}
if (dump_passes) {
- LOG(INFO) << Dumpable<CumulativeLogger>(compiler.get()->GetTimingsLogger());
+ LOG(INFO) << Dumpable<CumulativeLogger>(*compiler.get()->GetTimingsLogger());
}
return EXIT_SUCCESS;
}
diff --git a/disassembler/Android.mk b/disassembler/Android.mk
index 1ce7b13..ca08b09 100644
--- a/disassembler/Android.mk
+++ b/disassembler/Android.mk
@@ -90,13 +90,9 @@
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
ifeq ($$(art_target_or_host),target)
LOCAL_SHARED_LIBRARIES += libcutils
- include $(LLVM_GEN_INTRINSICS_MK)
- include $(LLVM_DEVICE_BUILD_MK)
include $(BUILD_SHARED_LIBRARY)
else # host
LOCAL_STATIC_LIBRARIES += libcutils
- include $(LLVM_GEN_INTRINSICS_MK)
- include $(LLVM_HOST_BUILD_MK)
include $(BUILD_HOST_SHARED_LIBRARY)
endif
endef
diff --git a/runtime/Android.mk b/runtime/Android.mk
index d6d2b42..10ef64b 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -74,7 +74,6 @@
intern_table.cc \
interpreter/interpreter.cc \
interpreter/interpreter_common.cc \
- interpreter/interpreter_goto_table_impl.cc \
interpreter/interpreter_switch_impl.cc \
jdwp/jdwp_event.cc \
jdwp/jdwp_expand_buf.cc \
@@ -185,6 +184,10 @@
entrypoints/quick/quick_throw_entrypoints.cc \
entrypoints/quick/quick_trampoline_entrypoints.cc
+# Source files that only compile with GCC.
+LIBART_GCC_ONLY_SRC_FILES := \
+ interpreter/interpreter_goto_table_impl.cc
+
LIBART_LDFLAGS := -Wl,--no-fatal-warnings
LIBART_TARGET_SRC_FILES := \
@@ -300,6 +303,7 @@
# $(1): target or host
# $(2): ndebug or debug
+# 3(3): true or false for LOCAL_CLANG
define build-libart
ifneq ($(1),target)
ifneq ($(1),host)
@@ -311,9 +315,15 @@
$$(error expected ndebug or debug for argument 2, received $(2))
endif
endif
+ ifneq ($(3),true)
+ ifneq ($(3),false)
+ $$(error expected true or false for argument 3, received $(3))
+ endif
+ endif
art_target_or_host := $(1)
art_ndebug_or_debug := $(2)
+ art_clang := $(3)
include $(CLEAR_VARS)
ifeq ($$(art_target_or_host),target)
@@ -354,11 +364,14 @@
$(foreach arch,$(ART_SUPPORTED_ARCH),
LOCAL_LDFLAGS_$(arch) := $$(LIBART_TARGET_LDFLAGS_$(arch)))
+ ifeq ($$(art_clang),false)
+ LOCAL_SRC_FILES += $(LIBART_GCC_ONLY_SRC_FILES)
+ else
+ LOCAL_CLANG := true
+ endif
ifeq ($$(art_target_or_host),target)
- LOCAL_CLANG := $(ART_TARGET_CLANG)
LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
else # host
- LOCAL_CLANG := $(ART_HOST_CLANG)
LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
endif
ifeq ($$(art_ndebug_or_debug),debug)
@@ -389,7 +402,14 @@
LOCAL_LDLIBS += -lrt
endif
endif
- include $(LLVM_GEN_INTRINSICS_MK)
+ ifeq ($(ART_USE_PORTABLE_COMPILER),true)
+ include $(LLVM_GEN_INTRINSICS_MK)
+ ifeq ($$(art_target_or_host),target)
+ include $(LLVM_DEVICE_BUILD_MK)
+ else # host
+ include $(LLVM_HOST_BUILD_MK)
+ endif
+ endif
LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
@@ -398,27 +418,25 @@
endif
ifeq ($$(art_target_or_host),target)
- include $(LLVM_DEVICE_BUILD_MK)
include $(BUILD_SHARED_LIBRARY)
else # host
- include $(LLVM_HOST_BUILD_MK)
include $(BUILD_HOST_SHARED_LIBRARY)
endif
endef
ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
- $(eval $(call build-libart,target,ndebug))
+ $(eval $(call build-libart,target,ndebug,$(ART_TARGET_CLANG)))
endif
ifeq ($(ART_BUILD_TARGET_DEBUG),true)
- $(eval $(call build-libart,target,debug))
+ $(eval $(call build-libart,target,debug,$(ART_TARGET_CLANG)))
endif
# We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
ifeq ($(WITH_HOST_DALVIK),true)
ifeq ($(ART_BUILD_NDEBUG),true)
- $(eval $(call build-libart,host,ndebug))
+ $(eval $(call build-libart,host,ndebug,$(ART_HOST_CLANG)))
endif
ifeq ($(ART_BUILD_DEBUG),true)
- $(eval $(call build-libart,host,debug))
+ $(eval $(call build-libart,host,debug,$(ART_HOST_CLANG)))
endif
endif
diff --git a/runtime/arch/x86/asm_support_x86.S b/runtime/arch/x86/asm_support_x86.S
index 9ec1995..267717a 100644
--- a/runtime/arch/x86/asm_support_x86.S
+++ b/runtime/arch/x86/asm_support_x86.S
@@ -19,38 +19,25 @@
#include "asm_support_x86.h"
-#if defined(__APPLE__)
- // Mac OS' as(1) doesn't let you name macro parameters.
+#if defined(__clang__)
+ // Clang's as(1) doesn't let you name macro parameters.
#define MACRO0(macro_name) .macro macro_name
#define MACRO1(macro_name, macro_arg1) .macro macro_name
#define MACRO2(macro_name, macro_arg1, macro_args2) .macro macro_name
#define MACRO3(macro_name, macro_arg1, macro_args2, macro_args3) .macro macro_name
#define END_MACRO .endmacro
- // Mac OS' as(1) uses $0, $1, and so on for macro arguments, and function names
- // are mangled with an extra underscore prefix. The use of $x for arguments
- // mean that literals need to be represented with $$x in macros.
- #define SYMBOL(name) _ ## name
- #define PLT_SYMBOL(name) _ ## name
+ // Clang's as(1) uses $0, $1, and so on for macro arguments.
#define VAR(name,index) SYMBOL($index)
#define PLT_VAR(name, index) SYMBOL($index)
#define REG_VAR(name,index) %$index
#define CALL_MACRO(name,index) $index
+ #define FUNCTION_TYPE(name,index) .type $index, @function
+ #define SIZE(name,index) .size $index, .-$index
+
+ // The use of $x for arguments mean that literals need to be represented with $$x in macros.
#define LITERAL(value) $value
#define MACRO_LITERAL(value) $$value
-
- // Mac OS' doesn't like cfi_* directives
- #define CFI_STARTPROC
- #define CFI_ENDPROC
- #define CFI_ADJUST_CFA_OFFSET(size)
- #define CFI_DEF_CFA(reg,size)
- #define CFI_DEF_CFA_REGISTER(reg)
- #define CFI_RESTORE(reg)
- #define CFI_REL_OFFSET(reg,size)
-
- // Mac OS' doesn't support certain directives
- #define FUNCTION_TYPE(name)
- #define SIZE(name)
#else
// Regular gas(1) lets you name macro parameters.
#define MACRO0(macro_name) .macro macro_name
@@ -65,16 +52,19 @@
// no special meaning to $, so literals are still just $x. The use of altmacro means % is a
// special character meaning care needs to be taken when passing registers as macro arguments.
.altmacro
- #define SYMBOL(name) name
- #define PLT_SYMBOL(name) name@PLT
#define VAR(name,index) name&
#define PLT_VAR(name, index) name&@PLT
#define REG_VAR(name,index) %name
#define CALL_MACRO(name,index) name&
+ #define FUNCTION_TYPE(name,index) .type name&, @function
+ #define SIZE(name,index) .size name, .-name
+
#define LITERAL(value) $value
#define MACRO_LITERAL(value) $value
+#endif
- // CFI support
+ // CFI support.
+#if !defined(__APPLE__)
#define CFI_STARTPROC .cfi_startproc
#define CFI_ENDPROC .cfi_endproc
#define CFI_ADJUST_CFA_OFFSET(size) .cfi_adjust_cfa_offset size
@@ -82,9 +72,25 @@
#define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg
#define CFI_RESTORE(reg) .cfi_restore reg
#define CFI_REL_OFFSET(reg,size) .cfi_rel_offset reg,size
+#else
+ // Mac OS' doesn't like cfi_* directives.
+ #define CFI_STARTPROC
+ #define CFI_ENDPROC
+ #define CFI_ADJUST_CFA_OFFSET(size)
+ #define CFI_DEF_CFA(reg,size)
+ #define CFI_DEF_CFA_REGISTER(reg)
+ #define CFI_RESTORE(reg)
+ #define CFI_REL_OFFSET(reg,size)
+#endif
- #define FUNCTION_TYPE(name) .type name&, @function
- #define SIZE(name) .size name, .-name
+ // Symbols.
+#if !defined(__APPLE__)
+ #define SYMBOL(name) name
+ #define PLT_SYMBOL(name) name
+#else
+ // Mac OS' symbols have an _ prefix.
+ #define SYMBOL(name) _ ## name
+ #define PLT_SYMBOL(name) _ ## name
#endif
/* Cache alignment for function entry */
@@ -93,7 +99,7 @@
END_MACRO
MACRO1(DEFINE_FUNCTION, c_name)
- FUNCTION_TYPE(\c_name)
+ FUNCTION_TYPE(\c_name, 0)
.globl VAR(c_name, 0)
ALIGN_FUNCTION_ENTRY
VAR(c_name, 0):
@@ -102,7 +108,7 @@
MACRO1(END_FUNCTION, c_name)
CFI_ENDPROC
- SIZE(\c_name)
+ SIZE(\c_name, 0)
END_MACRO
MACRO1(PUSH, reg)
@@ -118,7 +124,7 @@
END_MACRO
MACRO1(UNIMPLEMENTED,name)
- FUNCTION_TYPE(\name)
+ FUNCTION_TYPE(\name, 0)
.globl VAR(name, 0)
ALIGN_FUNCTION_ENTRY
VAR(name, 0):
@@ -126,7 +132,7 @@
int3
int3
CFI_ENDPROC
- SIZE(\name)
+ SIZE(\name, 0)
END_MACRO
MACRO0(SETUP_GOT_NOSAVE)
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 3da7409..754d1dd 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -46,6 +46,7 @@
return array_class;
}
}
+ DCHECK(!element_class->IsPrimitiveVoid());
std::string descriptor("[");
descriptor += ClassHelper(element_class).GetDescriptor();
SirtRef<mirror::ClassLoader> class_loader(self, element_class->GetClassLoader());
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 3a17e41..c646b86 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -22,6 +22,83 @@
namespace art {
+// -------------------------------------------------------------------
+// Binary GDB JIT Interface as described in
+// http://sourceware.org/gdb/onlinedocs/gdb/Declarations.html
+extern "C" {
+ typedef enum {
+ JIT_NOACTION = 0,
+ JIT_REGISTER_FN,
+ JIT_UNREGISTER_FN
+ } JITAction;
+
+ struct JITCodeEntry {
+ JITCodeEntry* next_;
+ JITCodeEntry* prev_;
+ const byte *symfile_addr_;
+ uint64_t symfile_size_;
+ };
+
+ struct JITDescriptor {
+ uint32_t version_;
+ uint32_t action_flag_;
+ JITCodeEntry* relevant_entry_;
+ JITCodeEntry* first_entry_;
+ };
+
+ // GDB will place breakpoint into this function.
+ // To prevent GCC from inlining or removing it we place noinline attribute
+ // and inline assembler statement inside.
+ void __attribute__((noinline)) __jit_debug_register_code() {
+ __asm__("");
+ }
+
+ // GDB will inspect contents of this descriptor.
+ // Static initialization is necessary to prevent GDB from seeing
+ // uninitialized descriptor.
+ JITDescriptor __jit_debug_descriptor = { 1, JIT_NOACTION, nullptr, nullptr };
+}
+
+
+static JITCodeEntry* CreateCodeEntry(const byte *symfile_addr,
+ uintptr_t symfile_size) {
+ JITCodeEntry* entry = new JITCodeEntry;
+ entry->symfile_addr_ = symfile_addr;
+ entry->symfile_size_ = symfile_size;
+ entry->prev_ = nullptr;
+
+ // TODO: Do we need a lock here?
+ entry->next_ = __jit_debug_descriptor.first_entry_;
+ if (entry->next_ != nullptr) {
+ entry->next_->prev_ = entry;
+ }
+ __jit_debug_descriptor.first_entry_ = entry;
+ __jit_debug_descriptor.relevant_entry_ = entry;
+
+ __jit_debug_descriptor.action_flag_ = JIT_REGISTER_FN;
+ __jit_debug_register_code();
+ return entry;
+}
+
+
+static void UnregisterCodeEntry(JITCodeEntry* entry) {
+ // TODO: Do we need a lock here?
+ if (entry->prev_ != nullptr) {
+ entry->prev_->next_ = entry->next_;
+ } else {
+ __jit_debug_descriptor.first_entry_ = entry->next_;
+ }
+
+ if (entry->next_ != nullptr) {
+ entry->next_->prev_ = entry->prev_;
+ }
+
+ __jit_debug_descriptor.relevant_entry_ = entry;
+ __jit_debug_descriptor.action_flag_ = JIT_UNREGISTER_FN;
+ __jit_debug_register_code();
+ delete entry;
+}
+
ElfFile::ElfFile(File* file, bool writable, bool program_header_only)
: file_(file),
writable_(writable),
@@ -38,7 +115,9 @@
dynstr_section_start_(NULL),
hash_section_start_(NULL),
symtab_symbol_table_(NULL),
- dynsym_symbol_table_(NULL) {
+ dynsym_symbol_table_(NULL),
+ jit_elf_image_(NULL),
+ jit_gdb_entry_(NULL) {
CHECK(file != NULL);
}
@@ -172,6 +251,10 @@
STLDeleteElements(&segments_);
delete symtab_symbol_table_;
delete dynsym_symbol_table_;
+ delete jit_elf_image_;
+ if (jit_gdb_entry_) {
+ UnregisterCodeEntry(jit_gdb_entry_);
+ }
}
bool ElfFile::SetMap(MemMap* map, std::string* error_msg) {
@@ -830,6 +913,11 @@
}
}
+ // Use GDB JIT support to do stack backtrace, etc.
+ if (executable) {
+ GdbJITSupport();
+ }
+
return true;
}
@@ -843,4 +931,269 @@
return false;
}
+static bool check_section_name(ElfFile& file, int section_num, const char *name) {
+ Elf32_Shdr& section_header = file.GetSectionHeader(section_num);
+ const char *section_name = file.GetString(SHT_SYMTAB, section_header.sh_name);
+ return strcmp(name, section_name) == 0;
+}
+
+static void IncrementUint32(byte *p, uint32_t increment) {
+ uint32_t *u = reinterpret_cast<uint32_t *>(p);
+ *u += increment;
+}
+
+static void RoundAndClear(byte *image, uint32_t& offset, int pwr2) {
+ uint32_t mask = pwr2 - 1;
+ while (offset & mask) {
+ image[offset++] = 0;
+ }
+}
+
+// Simple macro to bump a point to a section header to the next one.
+#define BUMP_SHENT(sp) \
+ sp = reinterpret_cast<Elf32_Shdr *> (\
+ reinterpret_cast<byte*>(sp) + elf_hdr.e_shentsize);\
+ offset += elf_hdr.e_shentsize
+
+void ElfFile::GdbJITSupport() {
+ // We only get here if we only are mapping the program header.
+ DCHECK(program_header_only_);
+
+ // Well, we need the whole file to do this.
+ std::string error_msg;
+ UniquePtr<ElfFile> ptr(Open(const_cast<File*>(file_), false, false, &error_msg));
+ ElfFile& all = *ptr;
+
+ // Do we have interesting sections?
+ // Is this an OAT file with interesting sections?
+ if (all.GetSectionHeaderNum() != kExpectedSectionsInOATFile) {
+ return;
+ }
+ if (!check_section_name(all, 8, ".debug_info") ||
+ !check_section_name(all, 9, ".debug_abbrev") ||
+ !check_section_name(all, 10, ".debug_frame") ||
+ !check_section_name(all, 11, ".debug_str")) {
+ return;
+ }
+
+ // Okay, we are good enough. Fake up an ELF image and tell GDB about it.
+ // We need some extra space for the debug and string sections, the ELF header, and the
+ // section header.
+ uint32_t needed_size = KB;
+
+ for (Elf32_Word i = 1; i < all.GetSectionHeaderNum(); i++) {
+ Elf32_Shdr& section_header = all.GetSectionHeader(i);
+ if (section_header.sh_addr == 0 && section_header.sh_type != SHT_DYNSYM) {
+ // Debug section: we need it.
+ needed_size += section_header.sh_size;
+ } else if (section_header.sh_type == SHT_STRTAB &&
+ strcmp(".shstrtab",
+ all.GetString(SHT_SYMTAB, section_header.sh_name)) == 0) {
+ // We also need the shared string table.
+ needed_size += section_header.sh_size;
+
+ // We also need the extra strings .symtab\0.strtab\0
+ needed_size += 16;
+ }
+ }
+
+ // Start creating our image.
+ jit_elf_image_ = new byte[needed_size];
+
+ // Create the Elf Header by copying the old one
+ Elf32_Ehdr& elf_hdr =
+ *reinterpret_cast<Elf32_Ehdr*>(jit_elf_image_);
+
+ elf_hdr = all.GetHeader();
+ elf_hdr.e_entry = 0;
+ elf_hdr.e_phoff = 0;
+ elf_hdr.e_phnum = 0;
+ elf_hdr.e_phentsize = 0;
+ elf_hdr.e_type = ET_EXEC;
+
+ uint32_t offset = sizeof(Elf32_Ehdr);
+
+ // Copy the debug sections and string table.
+ uint32_t debug_offsets[kExpectedSectionsInOATFile];
+ memset(debug_offsets, '\0', sizeof debug_offsets);
+ Elf32_Shdr *text_header = nullptr;
+ int extra_shstrtab_entries = -1;
+ int text_section_index = -1;
+ int section_index = 1;
+ for (Elf32_Word i = 1; i < kExpectedSectionsInOATFile; i++) {
+ Elf32_Shdr& section_header = all.GetSectionHeader(i);
+ // Round up to multiple of 4, ensuring zero fill.
+ RoundAndClear(jit_elf_image_, offset, 4);
+ if (section_header.sh_addr == 0 && section_header.sh_type != SHT_DYNSYM) {
+ // Debug section: we need it. Unfortunately, it wasn't mapped in.
+ debug_offsets[i] = offset;
+ // Read it from the file.
+ lseek(file_->Fd(), section_header.sh_offset, SEEK_SET);
+ read(file_->Fd(), jit_elf_image_ + offset, section_header.sh_size);
+ offset += section_header.sh_size;
+ section_index++;
+ offset += 16;
+ } else if (section_header.sh_type == SHT_STRTAB &&
+ strcmp(".shstrtab",
+ all.GetString(SHT_SYMTAB, section_header.sh_name)) == 0) {
+ // We also need the shared string table.
+ debug_offsets[i] = offset;
+ // Read it from the file.
+ lseek(file_->Fd(), section_header.sh_offset, SEEK_SET);
+ read(file_->Fd(), jit_elf_image_ + offset, section_header.sh_size);
+ offset += section_header.sh_size;
+ // We also need the extra strings .symtab\0.strtab\0
+ extra_shstrtab_entries = section_header.sh_size;
+ memcpy(jit_elf_image_+offset, ".symtab\0.strtab\0", 16);
+ offset += 16;
+ section_index++;
+ } else if (section_header.sh_flags & SHF_EXECINSTR) {
+ DCHECK(strcmp(".text", all.GetString(SHT_SYMTAB,
+ section_header.sh_name)) == 0);
+ text_header = §ion_header;
+ text_section_index = section_index++;
+ }
+ }
+ DCHECK(text_header != nullptr);
+ DCHECK_NE(extra_shstrtab_entries, -1);
+
+ // We now need to update the addresses for debug_info and debug_frame to get to the
+ // correct offset within the .text section.
+ uint32_t text_start_addr = 0;
+ for (uint32_t i = 0; i < segments_.size(); i++) {
+ if (segments_[i]->GetProtect() & PROT_EXEC) {
+ // We found the .text section.
+ text_start_addr = reinterpret_cast<uint32_t>(segments_[i]->Begin());
+ break;
+ }
+ }
+ DCHECK_NE(text_start_addr, 0U);
+
+ byte *p = jit_elf_image_+debug_offsets[8];
+ byte *end = p + all.GetSectionHeader(8).sh_size;
+
+ // For debug_info; patch compilation using low_pc @ offset 13, high_pc at offset 17.
+ IncrementUint32(p + 13, text_start_addr);
+ IncrementUint32(p + 17, text_start_addr);
+
+ // Now fix the low_pc, high_pc for each method address.
+ // First method starts at offset 0x15, each subsequent method is 1+3*4 bytes further.
+ for (p += 0x15; p < end; p += 1 /* attr# */ + 3 * sizeof(uint32_t) /* addresses */) {
+ IncrementUint32(p + 1 + sizeof(uint32_t), text_start_addr);
+ IncrementUint32(p + 1 + 2 * sizeof(uint32_t), text_start_addr);
+ }
+
+ // Now we have to handle the debug_frame method start addresses
+ p = jit_elf_image_+debug_offsets[10];
+ end = p + all.GetSectionHeader(10).sh_size;
+
+ // Skip past the CIE.
+ p += *reinterpret_cast<uint32_t *>(p) + 4;
+
+ // And walk the FDEs.
+ for (; p < end; p += *reinterpret_cast<uint32_t *>(p) + sizeof(uint32_t)) {
+ IncrementUint32(p + 2 * sizeof(uint32_t), text_start_addr);
+ }
+
+ // Create the data for the symbol table.
+ const int kSymbtabAlignment = 16;
+ RoundAndClear(jit_elf_image_, offset, kSymbtabAlignment);
+ uint32_t symtab_offset = offset;
+
+ // First entry is empty.
+ memset(jit_elf_image_+offset, 0, sizeof(Elf32_Sym));
+ offset += sizeof(Elf32_Sym);
+
+ // Symbol 1 is the real .text section.
+ Elf32_Sym& sym_ent = *reinterpret_cast<Elf32_Sym*>(jit_elf_image_+offset);
+ sym_ent.st_name = 1; /* .text */
+ sym_ent.st_value = text_start_addr;
+ sym_ent.st_size = text_header->sh_size;
+ SetBindingAndType(&sym_ent, STB_LOCAL, STT_SECTION);
+ sym_ent.st_other = 0;
+ sym_ent.st_shndx = text_section_index;
+ offset += sizeof(Elf32_Sym);
+
+ // Create the data for the string table.
+ RoundAndClear(jit_elf_image_, offset, kSymbtabAlignment);
+ const int kTextStringSize = 7;
+ uint32_t strtab_offset = offset;
+ memcpy(jit_elf_image_+offset, "\0.text", kTextStringSize);
+ offset += kTextStringSize;
+
+ // Create the section header table.
+ // Round up to multiple of kSymbtabAlignment, ensuring zero fill.
+ RoundAndClear(jit_elf_image_, offset, kSymbtabAlignment);
+ elf_hdr.e_shoff = offset;
+ Elf32_Shdr *sp =
+ reinterpret_cast<Elf32_Shdr *>(jit_elf_image_ + offset);
+
+ // Copy the first empty index.
+ *sp = all.GetSectionHeader(0);
+ BUMP_SHENT(sp);
+
+ elf_hdr.e_shnum = 1;
+ for (Elf32_Word i = 1; i < kExpectedSectionsInOATFile; i++) {
+ Elf32_Shdr& section_header = all.GetSectionHeader(i);
+ if (section_header.sh_addr == 0 && section_header.sh_type != SHT_DYNSYM) {
+ // Debug section: we need it.
+ *sp = section_header;
+ sp->sh_offset = debug_offsets[i];
+ sp->sh_addr = 0;
+ elf_hdr.e_shnum++;
+ BUMP_SHENT(sp);
+ } else if (section_header.sh_type == SHT_STRTAB &&
+ strcmp(".shstrtab",
+ all.GetString(SHT_SYMTAB, section_header.sh_name)) == 0) {
+ // We also need the shared string table.
+ *sp = section_header;
+ sp->sh_offset = debug_offsets[i];
+ sp->sh_size += 16; /* sizeof ".symtab\0.strtab\0" */
+ sp->sh_addr = 0;
+ elf_hdr.e_shstrndx = elf_hdr.e_shnum;
+ elf_hdr.e_shnum++;
+ BUMP_SHENT(sp);
+ }
+ }
+
+ // Add a .text section for the matching code section.
+ *sp = *text_header;
+ sp->sh_type = SHT_NOBITS;
+ sp->sh_offset = 0;
+ sp->sh_addr = text_start_addr;
+ elf_hdr.e_shnum++;
+ BUMP_SHENT(sp);
+
+ // .symtab section: Need an empty index and the .text entry
+ sp->sh_name = extra_shstrtab_entries;
+ sp->sh_type = SHT_SYMTAB;
+ sp->sh_flags = 0;
+ sp->sh_addr = 0;
+ sp->sh_offset = symtab_offset;
+ sp->sh_size = 2 * sizeof(Elf32_Sym);
+ sp->sh_link = elf_hdr.e_shnum + 1; // Link to .strtab section.
+ sp->sh_info = 0;
+ sp->sh_addralign = 16;
+ sp->sh_entsize = sizeof(Elf32_Sym);
+ elf_hdr.e_shnum++;
+ BUMP_SHENT(sp);
+
+ // .strtab section: Enough for .text\0.
+ sp->sh_name = extra_shstrtab_entries + 8;
+ sp->sh_type = SHT_STRTAB;
+ sp->sh_flags = 0;
+ sp->sh_addr = 0;
+ sp->sh_offset = strtab_offset;
+ sp->sh_size = kTextStringSize;
+ sp->sh_link = 0;
+ sp->sh_info = 0;
+ sp->sh_addralign = 16;
+ sp->sh_entsize = 0;
+ elf_hdr.e_shnum++;
+ BUMP_SHENT(sp);
+
+ // We now have enough information to tell GDB about our file.
+ jit_gdb_entry_ = CreateCodeEntry(jit_elf_image_, offset);
+}
+
} // namespace art
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index 8a0a5f8..d2a044e 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -29,6 +29,12 @@
namespace art {
+// Interface to GDB JIT for backtrace information.
+extern "C" {
+ struct JITCodeEntry;
+}
+
+
// Used for compile time and runtime for ElfFile access. Because of
// the need for use at runtime, cannot directly use LLVM classes such as
// ELFObjectFile.
@@ -171,6 +177,13 @@
SymbolTable* symtab_symbol_table_;
SymbolTable* dynsym_symbol_table_;
+
+ // Support for GDB JIT
+ byte* jit_elf_image_;
+ JITCodeEntry* jit_gdb_entry_;
+ void GdbJITSupport();
+ // Is this an OAT file with debug information in it?
+ static constexpr uint32_t kExpectedSectionsInOATFile = 12;
};
} // namespace art
diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
index 59da7a0..737fa3e 100644
--- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
@@ -92,6 +92,7 @@
}
CheckReferenceResult(o, self);
}
+ VerifyObject(o);
return o;
}
@@ -109,6 +110,7 @@
}
CheckReferenceResult(o, self);
}
+ VerifyObject(o);
return o;
}
diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h
index 5b4ca80..dd2bb5d 100644
--- a/runtime/gc/allocator/rosalloc.h
+++ b/runtime/gc/allocator/rosalloc.h
@@ -439,9 +439,6 @@
hash_set<Run*, hash_run, eq_run> full_runs_[kNumOfSizeBrackets];
// The set of free pages.
std::set<FreePageRun*> free_page_runs_ GUARDED_BY(lock_);
- // The free page run whose end address is the end of the memory
- // region that's managed by this allocator, if any.
- FreePageRun* last_free_page_run_;
// The current runs where the allocations are first attempted for
// the size brackes that do not use thread-local
// runs. current_runs_[i] is guarded by size_bracket_locks_[i].
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 7b2bc3b..c39e56f 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -861,7 +861,7 @@
size_t mark_stack_increment = std::min(mark_stack_delta, mark_stack_remaining);
mark_stack_end -= mark_stack_increment;
mark_stack_->PopBackCount(static_cast<int32_t>(mark_stack_increment));
- DCHECK_EQ(mark_stack_end, mark_stack_->End());
+ DCHECK_EQ(mark_stack_end, const_cast<const art::mirror::Object **>(mark_stack_->End()));
// Add the new task to the thread pool.
auto* task = new CardScanTask(thread_pool, this, space->GetMarkBitmap(), card_begin,
card_begin + card_increment, minimum_age,
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index a4c9dea..4668a19 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -61,7 +61,8 @@
namespace collector {
static constexpr bool kProtectFromSpace = true;
-static constexpr bool kResetFromSpace = true;
+static constexpr bool kClearFromSpace = true;
+static constexpr bool kStoreStackTraces = false;
// TODO: Unduplicate logic.
void SemiSpace::ImmuneSpace(space::ContinuousSpace* space) {
@@ -169,6 +170,19 @@
}
void SemiSpace::MarkingPhase() {
+ if (kStoreStackTraces) {
+ Locks::mutator_lock_->AssertExclusiveHeld(self_);
+ // Store the stack traces into the runtime fault string in case we get a heap corruption
+ // related crash later.
+ ThreadState old_state = self_->SetStateUnsafe(kRunnable);
+ std::ostringstream oss;
+ Runtime* runtime = Runtime::Current();
+ runtime->GetThreadList()->DumpForSigQuit(oss);
+ runtime->GetThreadList()->DumpNativeStacks(oss);
+ runtime->SetFaultMessage(oss.str());
+ CHECK_EQ(self_->SetStateUnsafe(old_state), kRunnable);
+ }
+
if (generational_) {
if (gc_cause_ == kGcCauseExplicit || gc_cause_ == kGcCauseForNativeAlloc ||
clear_soft_references_) {
@@ -353,19 +367,17 @@
TimingLogger::ScopedSplit split("UnBindBitmaps", &timings_);
GetHeap()->UnBindBitmaps();
}
- // Release the memory used by the from space.
- if (kResetFromSpace) {
- // Clearing from space.
+ if (kClearFromSpace) {
+ // Release the memory used by the from space.
from_space_->Clear();
}
+ from_space_->Reset();
// Protect the from space.
- VLOG(heap)
- << "mprotect region " << reinterpret_cast<void*>(from_space_->Begin()) << " - "
- << reinterpret_cast<void*>(from_space_->Limit());
+ VLOG(heap) << "Protecting space " << *from_space_;
if (kProtectFromSpace) {
- mprotect(from_space_->Begin(), from_space_->Capacity(), PROT_NONE);
+ from_space_->GetMemMap()->Protect(PROT_NONE);
} else {
- mprotect(from_space_->Begin(), from_space_->Capacity(), PROT_READ);
+ from_space_->GetMemMap()->Protect(PROT_READ);
}
if (saved_bytes_ > 0) {
VLOG(heap) << "Avoided dirtying " << PrettySize(saved_bytes_);
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 2e6d2c2..9ad21cf 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -318,6 +318,91 @@
}
}
+std::string Heap::SafeGetClassDescriptor(mirror::Class* klass) {
+ if (!IsValidContinuousSpaceObjectAddress(klass)) {
+ return StringPrintf("<non heap address klass %p>", klass);
+ }
+ mirror::Class* component_type = klass->GetComponentType<kVerifyNone>();
+ if (IsValidContinuousSpaceObjectAddress(component_type) && klass->IsArrayClass<kVerifyNone>()) {
+ std::string result("[");
+ result += SafeGetClassDescriptor(component_type);
+ return result;
+ } else if (UNLIKELY(klass->IsPrimitive<kVerifyNone>())) {
+ return Primitive::Descriptor(klass->GetPrimitiveType<kVerifyNone>());
+ } else if (UNLIKELY(klass->IsProxyClass())) {
+ return Runtime::Current()->GetClassLinker()->GetDescriptorForProxy(klass);
+ } else {
+ mirror::DexCache* dex_cache = klass->GetDexCache();
+ if (!IsValidContinuousSpaceObjectAddress(dex_cache)) {
+ return StringPrintf("<non heap address dex_cache %p>", dex_cache);
+ }
+ const DexFile* dex_file = dex_cache->GetDexFile();
+ uint16_t class_def_idx = klass->GetDexClassDefIndex();
+ if (class_def_idx == DexFile::kDexNoIndex16) {
+ return "<class def not found>";
+ }
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx);
+ const DexFile::TypeId& type_id = dex_file->GetTypeId(class_def.class_idx_);
+ return dex_file->GetTypeDescriptor(type_id);
+ }
+}
+
+std::string Heap::SafePrettyTypeOf(mirror::Object* obj) {
+ if (obj == nullptr) {
+ return "null";
+ }
+ mirror::Class* klass = obj->GetClass<kVerifyNone>();
+ if (klass == nullptr) {
+ return "(class=null)";
+ }
+ std::string result(SafeGetClassDescriptor(klass));
+ if (obj->IsClass()) {
+ result += "<" + SafeGetClassDescriptor(obj->AsClass()) + ">";
+ }
+ return result;
+}
+
+void Heap::DumpObject(std::ostream& stream, mirror::Object* obj) {
+ if (obj == nullptr) {
+ stream << "(obj=null)";
+ return;
+ }
+ if (IsAligned<kObjectAlignment>(obj)) {
+ space::Space* space = nullptr;
+ // Don't use find space since it only finds spaces which actually contain objects instead of
+ // spaces which may contain objects (e.g. cleared bump pointer spaces).
+ for (const auto& cur_space : continuous_spaces_) {
+ if (cur_space->HasAddress(obj)) {
+ space = cur_space;
+ break;
+ }
+ }
+ if (space == nullptr) {
+ if (allocator_mem_map_.get() == nullptr || !allocator_mem_map_->HasAddress(obj)) {
+ stream << "obj " << obj << " not a valid heap address";
+ return;
+ } else if (allocator_mem_map_.get() != nullptr) {
+ allocator_mem_map_->Protect(PROT_READ | PROT_WRITE);
+ }
+ }
+ // Unprotect all the spaces.
+ for (const auto& space : continuous_spaces_) {
+ mprotect(space->Begin(), space->Capacity(), PROT_READ | PROT_WRITE);
+ }
+ stream << "Object " << obj;
+ if (space != nullptr) {
+ stream << " in space " << *space;
+ }
+ mirror::Class* klass = obj->GetClass();
+ stream << "\nclass=" << klass;
+ if (klass != nullptr) {
+ stream << " type= " << SafePrettyTypeOf(obj);
+ }
+ // Re-protect the address we faulted on.
+ mprotect(AlignDown(obj, kPageSize), kPageSize, PROT_NONE);
+ }
+}
+
bool Heap::IsCompilingBoot() const {
for (const auto& space : continuous_spaces_) {
if (space->IsImageSpace() || space->IsZygoteSpace()) {
@@ -809,16 +894,23 @@
if (obj == nullptr) {
return true;
}
- return IsAligned<kObjectAlignment>(obj) && IsHeapAddress(obj);
+ return IsAligned<kObjectAlignment>(obj) && FindSpaceFromObject(obj, true) != nullptr;
}
bool Heap::IsNonDiscontinuousSpaceHeapAddress(const mirror::Object* obj) const {
return FindContinuousSpaceFromObject(obj, true) != nullptr;
}
-bool Heap::IsHeapAddress(const mirror::Object* obj) const {
- // TODO: This might not work for large objects.
- return FindSpaceFromObject(obj, true) != nullptr;
+bool Heap::IsValidContinuousSpaceObjectAddress(const mirror::Object* obj) const {
+ if (obj == nullptr || !IsAligned<kObjectAlignment>(obj)) {
+ return false;
+ }
+ for (const auto& space : continuous_spaces_) {
+ if (space->HasAddress(obj)) {
+ return true;
+ }
+ }
+ return false;
}
bool Heap::IsLiveObjectLocked(mirror::Object* obj, bool search_allocation_stack,
@@ -1539,6 +1631,7 @@
void Heap::SwapSemiSpaces() {
// Swap the spaces so we allocate into the space which we just evacuated.
std::swap(bump_pointer_space_, temp_space_);
+ bump_pointer_space_->Clear();
}
void Heap::Compact(space::ContinuousMemMapAllocSpace* target_space,
@@ -1616,7 +1709,7 @@
CHECK(temp_space_->IsEmpty());
semi_space_collector_->SetFromSpace(bump_pointer_space_);
semi_space_collector_->SetToSpace(temp_space_);
- mprotect(temp_space_->Begin(), temp_space_->Capacity(), PROT_READ | PROT_WRITE);
+ temp_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
collector = semi_space_collector_;
gc_type = collector::kGcTypeFull;
} else if (current_allocator_ == kAllocatorTypeRosAlloc ||
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 2f227d0..b194d8d 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -223,9 +223,6 @@
bool IsValidObjectAddress(const mirror::Object* obj) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Returns true if the address passed in is a heap address, doesn't need to be aligned.
- bool IsHeapAddress(const mirror::Object* obj) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
// Faster alternative to IsHeapAddress since finding if an object is in the large object space is
// very slow.
bool IsNonDiscontinuousSpaceHeapAddress(const mirror::Object* obj) const
@@ -519,6 +516,12 @@
void DumpSpaces(std::ostream& stream = LOG(INFO));
+ // Dump object should only be used by the signal handler.
+ void DumpObject(std::ostream& stream, mirror::Object* obj) NO_THREAD_SAFETY_ANALYSIS;
+ // Safe version of pretty type of which check to make sure objects are heap addresses.
+ std::string SafeGetClassDescriptor(mirror::Class* klass) NO_THREAD_SAFETY_ANALYSIS;
+ std::string SafePrettyTypeOf(mirror::Object* obj) NO_THREAD_SAFETY_ANALYSIS;
+
// GC performance measuring
void DumpGcPerformanceInfo(std::ostream& os);
@@ -600,6 +603,10 @@
template <bool kGrow>
bool IsOutOfMemoryOnAllocation(AllocatorType allocator_type, size_t alloc_size);
+ // Returns true if the address passed in is within the address range of a continuous space.
+ bool IsValidContinuousSpaceObjectAddress(const mirror::Object* obj) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Pushes a list of cleared references out to the managed heap.
void SetReferenceReferent(mirror::Object* reference, mirror::Object* referent)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/gc/space/bump_pointer_space.cc b/runtime/gc/space/bump_pointer_space.cc
index 43674ea..fcd3b70 100644
--- a/runtime/gc/space/bump_pointer_space.cc
+++ b/runtime/gc/space/bump_pointer_space.cc
@@ -61,6 +61,9 @@
void BumpPointerSpace::Clear() {
// Release the pages back to the operating system.
CHECK_NE(madvise(Begin(), Limit() - Begin(), MADV_DONTNEED), -1) << "madvise failed";
+}
+
+void BumpPointerSpace::Reset() {
// Reset the end of the space back to the beginning, we move the end forward as we allocate
// objects.
SetEnd(Begin());
@@ -75,8 +78,9 @@
}
void BumpPointerSpace::Dump(std::ostream& os) const {
- os << reinterpret_cast<void*>(Begin()) << "-" << reinterpret_cast<void*>(End()) << " - "
- << reinterpret_cast<void*>(Limit());
+ os << GetName() << " "
+ << reinterpret_cast<void*>(Begin()) << "-" << reinterpret_cast<void*>(End()) << " - "
+ << reinterpret_cast<void*>(Limit());
}
mirror::Object* BumpPointerSpace::GetNextObject(mirror::Object* obj) {
diff --git a/runtime/gc/space/bump_pointer_space.h b/runtime/gc/space/bump_pointer_space.h
index 476b833..2c9d35f 100644
--- a/runtime/gc/space/bump_pointer_space.h
+++ b/runtime/gc/space/bump_pointer_space.h
@@ -92,8 +92,11 @@
return nullptr;
}
- // Clear the memory and reset the pointer to the start of the space.
- void Clear() OVERRIDE LOCKS_EXCLUDED(block_lock_);
+ // Madvise the memory back to the OS.
+ void Clear() OVERRIDE;
+
+ // Reset the pointer to the start of the space.
+ void Reset() OVERRIDE LOCKS_EXCLUDED(block_lock_);
void Dump(std::ostream& os) const;
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index caedaaf..b591486 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -281,12 +281,15 @@
}
void DlMallocSpace::Clear() {
- // TODO: Delete and create new mspace here.
madvise(GetMemMap()->Begin(), GetMemMap()->Size(), MADV_DONTNEED);
GetLiveBitmap()->Clear();
GetMarkBitmap()->Clear();
}
+void DlMallocSpace::Reset() {
+ // TODO: Delete and create new mspace here.
+}
+
#ifndef NDEBUG
void DlMallocSpace::CheckMoreCoreForPrecondition() {
lock_.AssertHeld(Thread::Current());
diff --git a/runtime/gc/space/dlmalloc_space.h b/runtime/gc/space/dlmalloc_space.h
index 6ea10ad..4bf16ce 100644
--- a/runtime/gc/space/dlmalloc_space.h
+++ b/runtime/gc/space/dlmalloc_space.h
@@ -113,6 +113,7 @@
uint64_t GetObjectsAllocated() OVERRIDE;
void Clear() OVERRIDE;
+ void Reset() OVERRIDE;
bool IsDlMallocSpace() const OVERRIDE {
return true;
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index fe8421d..fb621ea 100644
--- a/runtime/gc/space/rosalloc_space.cc
+++ b/runtime/gc/space/rosalloc_space.cc
@@ -304,12 +304,15 @@
}
void RosAllocSpace::Clear() {
- // TODO: Delete and create new mspace here.
madvise(GetMemMap()->Begin(), GetMemMap()->Size(), MADV_DONTNEED);
GetLiveBitmap()->Clear();
GetMarkBitmap()->Clear();
}
+void RosAllocSpace::Reset() {
+ // TODO: Delete and create new mspace here.
+}
+
} // namespace space
} // namespace gc
} // namespace art
diff --git a/runtime/gc/space/rosalloc_space.h b/runtime/gc/space/rosalloc_space.h
index bd32196..5bc425d 100644
--- a/runtime/gc/space/rosalloc_space.h
+++ b/runtime/gc/space/rosalloc_space.h
@@ -80,6 +80,7 @@
void SetFootprintLimit(size_t limit) OVERRIDE;
void Clear() OVERRIDE;
+ void Reset() OVERRIDE;
MallocSpace* CreateInstance(const std::string& name, MemMap* mem_map, void* allocator,
byte* begin, byte* end, byte* limit, size_t growth_limit);
diff --git a/runtime/gc/space/space.h b/runtime/gc/space/space.h
index 0f8f38a..37d7c80 100644
--- a/runtime/gc/space/space.h
+++ b/runtime/gc/space/space.h
@@ -399,6 +399,9 @@
// Free all memory associated with this space.
virtual void Clear() = 0;
+ // Reset the space back to an empty space.
+ virtual void Reset() = 0;
+
accounting::SpaceBitmap* GetLiveBitmap() const {
return live_bitmap_.get();
}
diff --git a/runtime/gc/space/zygote_space.cc b/runtime/gc/space/zygote_space.cc
index a60ab38..d1c3d03 100644
--- a/runtime/gc/space/zygote_space.cc
+++ b/runtime/gc/space/zygote_space.cc
@@ -61,6 +61,10 @@
LOG(FATAL) << "Unimplemented";
}
+void ZygoteSpace::Reset() {
+ LOG(FATAL) << "Unimplemented";
+}
+
ZygoteSpace::ZygoteSpace(const std::string& name, MemMap* mem_map, size_t objects_allocated)
: ContinuousMemMapAllocSpace(name, mem_map, mem_map->Begin(), mem_map->End(), mem_map->End(),
kGcRetentionPolicyFullCollect),
diff --git a/runtime/gc/space/zygote_space.h b/runtime/gc/space/zygote_space.h
index 8cd1a9f..8880548 100644
--- a/runtime/gc/space/zygote_space.h
+++ b/runtime/gc/space/zygote_space.h
@@ -71,7 +71,8 @@
return objects_allocated_;
}
- void Clear();
+ void Clear() OVERRIDE;
+ void Reset() OVERRIDE;
protected:
virtual accounting::SpaceBitmap::SweepCallback* GetSweepCallback() {
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 40d4ea3..abe7fe1 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -286,11 +286,39 @@
}
enum InterpreterImplKind {
- kSwitchImpl, // switch-based interpreter implementation.
- kComputedGotoImplKind // computed-goto-based interpreter implementation.
+ kSwitchImpl, // Switch-based interpreter implementation.
+ kComputedGotoImplKind // Computed-goto-based interpreter implementation.
};
-static const InterpreterImplKind kInterpreterImplKind = kComputedGotoImplKind;
+#if !defined(__clang__)
+static constexpr InterpreterImplKind kInterpreterImplKind = kComputedGotoImplKind;
+#else
+// Clang 3.4 fails to build the goto interpreter implementation.
+static constexpr InterpreterImplKind kInterpreterImplKind = kSwitchImpl;
+template<bool do_access_check, bool transaction_active>
+JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register) {
+ LOG(FATAL) << "UNREACHABLE";
+ exit(0);
+}
+// Explicit definitions of ExecuteGotoImpl.
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteGotoImpl<true, false>(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register);
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteGotoImpl<false, false>(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register);
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteGotoImpl<true, true>(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register);
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteGotoImpl<false, true>(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register);
+#endif
static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register)
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index a03e420..589e0b0 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -515,11 +515,11 @@
return found_dex_pc;
}
-static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
- __attribute__((cold, noreturn, noinline));
+static inline void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
+ __attribute__((cold, noreturn))
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+static inline void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh) {
LOG(FATAL) << "Unexpected instruction: " << inst->DumpString(&mh.GetDexFile());
exit(0); // Unreachable, keep GCC happy.
}
diff --git a/runtime/jdwp/jdwp.h b/runtime/jdwp/jdwp.h
index 1ec795f..fdbdfeb 100644
--- a/runtime/jdwp/jdwp.h
+++ b/runtime/jdwp/jdwp.h
@@ -96,9 +96,9 @@
};
struct JdwpEvent;
-struct JdwpNetStateBase;
+class JdwpNetStateBase;
struct ModBasket;
-struct Request;
+class Request;
/*
* State for JDWP functions.
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 478cc36..484c21a 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -323,9 +323,9 @@
size_t result;
constexpr auto kNewFlags = static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis);
if (IsArrayInstance<kVerifyFlags>()) {
- result = AsArray<kNewFlags>()->SizeOf<>();
+ result = AsArray<kNewFlags>()->template SizeOf<kNewFlags>();
} else if (IsClass<kNewFlags>()) {
- result = AsClass<kNewFlags>()->SizeOf<kNewFlags>();
+ result = AsClass<kNewFlags>()->template SizeOf<kNewFlags>();
} else {
result = GetClass<kNewFlags>()->GetObjectSize();
}
@@ -485,7 +485,6 @@
if (kVerifyFlags & kVerifyWrites) {
VerifyObject(new_value);
}
- HeapReference<Object> objref(HeapReference<Object>::FromMirrorPtr(new_value));
byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
HeapReference<Object>* objref_addr = reinterpret_cast<HeapReference<Object>*>(raw_addr);
if (UNLIKELY(is_volatile)) {
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 3c703ba..decbc66 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -56,13 +56,17 @@
static jobject VMRuntime_newNonMovableArray(JNIEnv* env, jobject, jclass javaElementClass,
jint length) {
ScopedFastNativeObjectAccess soa(env);
+ if (UNLIKELY(length < 0)) {
+ ThrowNegativeArraySizeException(length);
+ return nullptr;
+ }
mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
if (UNLIKELY(element_class == nullptr)) {
ThrowNullPointerException(NULL, "element class == null");
return nullptr;
}
- if (UNLIKELY(length < 0)) {
- ThrowNegativeArraySizeException(length);
+ if (UNLIKELY(element_class->IsPrimitiveVoid())) {
+ ThrowIllegalArgumentException(NULL, "Can't allocate an array of void");
return nullptr;
}
Runtime* runtime = Runtime::Current();
@@ -76,6 +80,34 @@
return soa.AddLocalReference<jobject>(result);
}
+static jobject VMRuntime_newUnpaddedArray(JNIEnv* env, jobject, jclass javaElementClass,
+ jint length) {
+ ScopedFastNativeObjectAccess soa(env);
+ if (UNLIKELY(length < 0)) {
+ ThrowNegativeArraySizeException(length);
+ return nullptr;
+ }
+ mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
+ if (UNLIKELY(element_class == nullptr)) {
+ ThrowNullPointerException(NULL, "element class == null");
+ return nullptr;
+ }
+ if (UNLIKELY(element_class->IsPrimitiveVoid())) {
+ ThrowIllegalArgumentException(NULL, "Can't allocate an array of void");
+ return nullptr;
+ }
+ Runtime* runtime = Runtime::Current();
+ mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(), element_class);
+ if (UNLIKELY(array_class == nullptr)) {
+ return nullptr;
+ }
+ gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator();
+ mirror::Array* result = mirror::Array::Alloc<true>(soa.Self(), array_class, length,
+ array_class->GetComponentSize(), allocator,
+ true);
+ return soa.AddLocalReference<jobject>(result);
+}
+
static jlong VMRuntime_addressOf(JNIEnv* env, jobject, jobject javaArray) {
if (javaArray == NULL) { // Most likely allocation failed
return 0;
@@ -497,6 +529,7 @@
NATIVE_METHOD(VMRuntime, isDebuggerActive, "()Z"),
NATIVE_METHOD(VMRuntime, nativeSetTargetHeapUtilization, "(F)V"),
NATIVE_METHOD(VMRuntime, newNonMovableArray, "!(Ljava/lang/Class;I)Ljava/lang/Object;"),
+ NATIVE_METHOD(VMRuntime, newUnpaddedArray, "!(Ljava/lang/Class;I)Ljava/lang/Object;"),
NATIVE_METHOD(VMRuntime, properties, "()[Ljava/lang/String;"),
NATIVE_METHOD(VMRuntime, setTargetSdkVersionNative, "(I)V"),
NATIVE_METHOD(VMRuntime, registerNativeAllocation, "(I)V"),
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 1ef15f7..90ba7d3 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -91,6 +91,8 @@
resolution_method_(nullptr),
imt_conflict_method_(nullptr),
default_imt_(nullptr),
+ fault_message_lock_("Fault message lock"),
+ fault_message_(""),
method_verifiers_lock_("Method verifiers lock"),
threads_being_born_(0),
shutdown_cond_(new ConditionVariable("Runtime shutdown", *Locks::runtime_shutdown_lock_)),
@@ -1598,4 +1600,9 @@
DCHECK(IsActiveTransaction());
preinitialization_transaction->RecordWeakStringRemoval(s, hash_code);
}
+
+void Runtime::SetFaultMessage(const std::string& message) {
+ MutexLock mu(Thread::Current(), fault_message_lock_);
+ fault_message_ = message;
+}
} // namespace art
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 8924921..7f8e915 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -60,7 +60,7 @@
class CompilerCallbacks;
class DexFile;
class InternTable;
-struct JavaVMExt;
+class JavaVMExt;
class MonitorList;
class MonitorPool;
class SignalCatcher;
@@ -446,6 +446,13 @@
void RecordWeakStringRemoval(mirror::String* s, uint32_t hash_code) const
EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+ void SetFaultMessage(const std::string& message);
+ // Only read by the signal handler, NO_THREAD_SAFETY_ANALYSIS to prevent lock order violations
+ // with the unexpected_signal_lock_.
+ const std::string& GetFaultMessage() NO_THREAD_SAFETY_ANALYSIS {
+ return fault_message_;
+ }
+
private:
static void InitPlatformSignalHandlers();
@@ -520,6 +527,10 @@
mirror::ObjectArray<mirror::ArtMethod>* default_imt_;
+ // Fault message, printed when we get a SIGSEGV.
+ Mutex fault_message_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ std::string fault_message_ GUARDED_BY(fault_message_lock_);
+
// Method verifier set, used so that we can update their GC roots.
Mutex method_verifiers_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
std::set<verifier::MethodVerifier*> method_verifiers_;
diff --git a/runtime/runtime_android.cc b/runtime/runtime_android.cc
index 2013294..14e5574 100644
--- a/runtime/runtime_android.cc
+++ b/runtime/runtime_android.cc
@@ -14,12 +14,58 @@
* limitations under the License.
*/
-#include "runtime.h"
+#include <signal.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <inttypes.h>
+
+#include "base/logging.h"
+#include "base/mutex.h"
+#include "base/stringprintf.h"
+#include "thread-inl.h"
+#include "utils.h"
namespace art {
+struct sigaction old_action;
+void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void* raw_context) {
+ static bool handlingUnexpectedSignal = false;
+ if (handlingUnexpectedSignal) {
+ LogMessageData data(__FILE__, __LINE__, INTERNAL_FATAL, -1);
+ LogMessage::LogLine(data, "HandleUnexpectedSignal reentered\n");
+ _exit(1);
+ }
+ handlingUnexpectedSignal = true;
+ gAborting++; // set before taking any locks
+ MutexLock mu(Thread::Current(), *Locks::unexpected_signal_lock_);
+
+ Runtime* runtime = Runtime::Current();
+ if (runtime != nullptr) {
+ // Print this out first in case DumpObject faults.
+ LOG(INTERNAL_FATAL) << "Fault message: " << runtime->GetFaultMessage();
+ gc::Heap* heap = runtime->GetHeap();
+ if (heap != nullptr && info != nullptr) {
+ LOG(INTERNAL_FATAL) << "Dump heap object at fault address: ";
+ heap->DumpObject(LOG(INTERNAL_FATAL), reinterpret_cast<mirror::Object*>(info->si_addr));
+ }
+ }
+ // Run the old signal handler.
+ old_action.sa_sigaction(signal_number, info, raw_context);
+}
+
void Runtime::InitPlatformSignalHandlers() {
- // On a device, debuggerd will give us a stack trace. Nothing to do here.
+ // On the host, we don't have debuggerd to dump a stack for us when something unexpected happens.
+ struct sigaction action;
+ memset(&action, 0, sizeof(action));
+ sigemptyset(&action.sa_mask);
+ action.sa_sigaction = HandleUnexpectedSignal;
+ // Use the three-argument sa_sigaction handler.
+ action.sa_flags |= SA_SIGINFO;
+ // Use the alternate signal stack so we can catch stack overflows.
+ action.sa_flags |= SA_ONSTACK;
+ int rc = 0;
+ rc += sigaction(SIGSEGV, &action, &old_action);
+ CHECK_EQ(rc, 0);
}
} // namespace art
diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc
index 73ac034..f15e0bf 100644
--- a/runtime/runtime_linux.cc
+++ b/runtime/runtime_linux.cc
@@ -24,7 +24,7 @@
#include "base/logging.h"
#include "base/mutex.h"
#include "base/stringprintf.h"
-#include "thread.h"
+#include "thread-inl.h"
#include "utils.h"
namespace art {
@@ -305,7 +305,15 @@
<< "Thread: " << tid << " \"" << thread_name << "\"\n"
<< "Registers:\n" << Dumpable<UContext>(thread_context) << "\n"
<< "Backtrace:\n" << Dumpable<Backtrace>(thread_backtrace);
-
+ Runtime* runtime = Runtime::Current();
+ if (runtime != nullptr) {
+ gc::Heap* heap = runtime->GetHeap();
+ LOG(INTERNAL_FATAL) << "Fault message: " << runtime->GetFaultMessage();
+ if (heap != nullptr && info != nullptr) {
+ LOG(INTERNAL_FATAL) << "Dump heap object at fault address: ";
+ heap->DumpObject(LOG(INTERNAL_FATAL), reinterpret_cast<mirror::Object*>(info->si_addr));
+ }
+ }
if (getenv("debug_db_uid") != NULL || getenv("art_wait_for_gdb_on_crash") != NULL) {
LOG(INTERNAL_FATAL) << "********************************************************\n"
<< "* Process " << getpid() << " thread " << tid << " \"" << thread_name << "\""
diff --git a/runtime/thread.h b/runtime/thread.h
index f9d31af..6df2b1c 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -42,6 +42,12 @@
namespace art {
+namespace gc {
+namespace collector {
+class SemiSpace;
+} // namespace collector
+} // namespace gc
+
namespace mirror {
class ArtMethod;
class Array;
@@ -61,7 +67,7 @@
class Context;
struct DebugInvokeReq;
class DexFile;
-struct JavaVMExt;
+class JavaVMExt;
struct JNIEnvExt;
class Monitor;
class Runtime;
@@ -851,6 +857,7 @@
private:
friend class Dbg; // For SetStateUnsafe.
+ friend class gc::collector::SemiSpace; // For getting stack traces.
friend class Monitor;
friend class MonitorInfo;
friend class Runtime; // For CreatePeer.
diff --git a/runtime/utils.cc b/runtime/utils.cc
index df1ab94..d8f8f8f 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1232,8 +1232,8 @@
execv(program, &args[0]);
- PLOG(FATAL) << "Failed to execv(" << command_line << ")";
- return false;
+ PLOG(ERROR) << "Failed to execv(" << command_line << ")";
+ exit(1);
} else {
if (pid == -1) {
*error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s",
diff --git a/runtime/zip_archive_test.cc b/runtime/zip_archive_test.cc
index 0bf6767..c43fee5 100644
--- a/runtime/zip_archive_test.cc
+++ b/runtime/zip_archive_test.cc
@@ -32,10 +32,10 @@
TEST_F(ZipArchiveTest, FindAndExtract) {
std::string error_msg;
UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(GetLibCoreDexFileName().c_str(), &error_msg));
- ASSERT_TRUE(zip_archive.get() != false) << error_msg;
+ ASSERT_TRUE(zip_archive.get() != nullptr) << error_msg;
ASSERT_TRUE(error_msg.empty());
UniquePtr<ZipEntry> zip_entry(zip_archive->Find("classes.dex", &error_msg));
- ASSERT_TRUE(zip_entry.get() != false);
+ ASSERT_TRUE(zip_entry.get() != nullptr);
ASSERT_TRUE(error_msg.empty());
ScratchFile tmp;
diff --git a/tools/generate-operator-out.py b/tools/generate-operator-out.py
index 19266b4..56b8674 100755
--- a/tools/generate-operator-out.py
+++ b/tools/generate-operator-out.py
@@ -23,7 +23,7 @@
import sys
-_ENUM_START_RE = re.compile(r'\benum\b\s+(\S+)\s+\{')
+_ENUM_START_RE = re.compile(r'\benum\b\s+(\S+)\s+:?.*\{')
_ENUM_VALUE_RE = re.compile(r'([A-Za-z0-9_]+)(.*)')
_ENUM_END_RE = re.compile(r'^\s*\};$')
_ENUMS = {}