am 08f20c63: Change monitor checks to warnings in verifier.
* commit '08f20c63e2bd0c41d53a4c3ddaa34fd637f5405d':
Change monitor checks to warnings in verifier.
diff --git a/Android.mk b/Android.mk
index 3112ab0..8024a3d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -305,6 +305,8 @@
########################################################################
# oatdump targets
+ART_DUMP_OAT_PATH ?= $(OUT_DIR)
+
.PHONY: dump-oat
dump-oat: dump-oat-core dump-oat-boot
@@ -314,29 +316,29 @@
.PHONY: dump-oat-core-host
ifeq ($(ART_BUILD_HOST),true)
dump-oat-core-host: $(HOST_CORE_IMG_OUT) $(OATDUMP)
- $(OATDUMP) --image=$(HOST_CORE_IMG_OUT) --output=/tmp/core.host.oatdump.txt --host-prefix=""
- @echo Output in /tmp/core.host.oatdump.txt
+ $(OATDUMP) --image=$(HOST_CORE_IMG_OUT) --output=$(ART_DUMP_OAT_PATH)/core.host.oatdump.txt --host-prefix=""
+ @echo Output in $(ART_DUMP_OAT_PATH)/core.host.oatdump.txt
endif
.PHONY: dump-oat-core-target
ifeq ($(ART_BUILD_TARGET),true)
dump-oat-core-target: $(TARGET_CORE_IMG_OUT) $(OATDUMP)
- $(OATDUMP) --image=$(TARGET_CORE_IMG_OUT) --output=/tmp/core.target.oatdump.txt
- @echo Output in /tmp/core.target.oatdump.txt
+ $(OATDUMP) --image=$(TARGET_CORE_IMG_OUT) --output=$(ART_DUMP_OAT_PATH)/core.target.oatdump.txt
+ @echo Output in $(ART_DUMP_OAT_PATH)/core.target.oatdump.txt
endif
.PHONY: dump-oat-boot
ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
dump-oat-boot: $(TARGET_BOOT_IMG_OUT) $(OATDUMP)
- $(OATDUMP) --image=$(TARGET_BOOT_IMG_OUT) --output=/tmp/boot.oatdump.txt
- @echo Output in /tmp/boot.oatdump.txt
+ $(OATDUMP) --image=$(TARGET_BOOT_IMG_OUT) --output=$(ART_DUMP_OAT_PATH)/boot.oatdump.txt
+ @echo Output in $(ART_DUMP_OAT_PATH)/boot.oatdump.txt
endif
.PHONY: dump-oat-Calculator
ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
dump-oat-Calculator: $(TARGET_OUT_APPS)/Calculator.odex $(TARGET_BOOT_IMG_OUT) $(OATDUMP)
- $(OATDUMP) --oat-file=$< --output=/tmp/Calculator.oatdump.txt
- @echo Output in /tmp/Calculator.oatdump.txt
+ $(OATDUMP) --oat-file=$< --output=$(ART_DUMP_OAT_PATH)/Calculator.oatdump.txt
+ @echo Output in $(ART_DUMP_OAT_PATH)/Calculator.oatdump.txt
endif
########################################################################
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index f964346..c04b38b 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -26,7 +26,7 @@
# By default, do not run rerun dex2oat if the tool changes.
# Comment out the | to force dex2oat to rerun on after all changes.
-DEX2OAT_DEPENDENCY := #|
+DEX2OAT_DEPENDENCY := |
DEX2OAT_DEPENDENCY += $(DEX2OAT)
DEX2OAT_DEPENDENCY += $(LIBART_COMPILER)
diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc
index 07bd2aa..963cbeb 100644
--- a/compiler/dex/portable/mir_to_gbc.cc
+++ b/compiler/dex/portable/mir_to_gbc.cc
@@ -1970,7 +1970,7 @@
::llvm::OwningPtr< ::llvm::tool_output_file> out_file(
new ::llvm::tool_output_file(fname.c_str(), errmsg,
- ::llvm::sys::fs::F_Binary));
+ ::llvm::raw_fd_ostream::F_Binary));
if (!errmsg.empty()) {
LOG(ERROR) << "Failed to create bitcode output file: " << errmsg;
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 7225262..d1a9a13 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -1245,84 +1245,87 @@
const DexFile::TypeId& declaring_type = cu_->dex_file->GetTypeId(target_mid.class_idx_);
StringPiece tgt_methods_declaring_class(
cu_->dex_file->StringDataByIdx(declaring_type.descriptor_idx_));
- if (tgt_methods_declaring_class.starts_with("Ljava/lang/Double;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "long java.lang.Double.doubleToRawLongBits(double)") {
- return GenInlinedDoubleCvt(info);
- }
- if (tgt_method == "double java.lang.Double.longBitsToDouble(long)") {
- return GenInlinedDoubleCvt(info);
- }
- } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Float;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "int java.lang.Float.floatToRawIntBits(float)") {
- return GenInlinedFloatCvt(info);
- }
- if (tgt_method == "float java.lang.Float.intBitsToFloat(int)") {
- return GenInlinedFloatCvt(info);
- }
- } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Integer;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "int java.lang.Integer.reverseBytes(int)") {
- return GenInlinedReverseBytes(info, kWord);
- }
- } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Long;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "long java.lang.Long.reverseBytes(long)") {
- return GenInlinedReverseBytes(info, kLong);
- }
- } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Math;") ||
- tgt_methods_declaring_class.starts_with("Ljava/lang/StrictMath;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "int java.lang.Math.abs(int)" ||
- tgt_method == "int java.lang.StrictMath.abs(int)") {
- return GenInlinedAbsInt(info);
- }
- if (tgt_method == "long java.lang.Math.abs(long)" ||
- tgt_method == "long java.lang.StrictMath.abs(long)") {
- return GenInlinedAbsLong(info);
- }
- if (tgt_method == "int java.lang.Math.max(int, int)" ||
- tgt_method == "int java.lang.StrictMath.max(int, int)") {
- return GenInlinedMinMaxInt(info, false /* is_min */);
- }
- if (tgt_method == "int java.lang.Math.min(int, int)" ||
- tgt_method == "int java.lang.StrictMath.min(int, int)") {
- return GenInlinedMinMaxInt(info, true /* is_min */);
- }
- if (tgt_method == "double java.lang.Math.sqrt(double)" ||
- tgt_method == "double java.lang.StrictMath.sqrt(double)") {
- return GenInlinedSqrt(info);
- }
- } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Short;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "short java.lang.Short.reverseBytes(short)") {
- return GenInlinedReverseBytes(info, kSignedHalf);
- }
- } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/String;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "char java.lang.String.charAt(int)") {
- return GenInlinedCharAt(info);
- }
- if (tgt_method == "int java.lang.String.compareTo(java.lang.String)") {
- return GenInlinedStringCompareTo(info);
- }
- if (tgt_method == "boolean java.lang.String.is_empty()") {
- return GenInlinedStringIsEmptyOrLength(info, true /* is_empty */);
- }
- if (tgt_method == "int java.lang.String.index_of(int, int)") {
- return GenInlinedIndexOf(info, false /* base 0 */);
- }
- if (tgt_method == "int java.lang.String.index_of(int)") {
- return GenInlinedIndexOf(info, true /* base 0 */);
- }
- if (tgt_method == "int java.lang.String.length()") {
- return GenInlinedStringIsEmptyOrLength(info, false /* is_empty */);
- }
- } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Thread;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "java.lang.Thread java.lang.Thread.currentThread()") {
- return GenInlinedCurrentThread(info);
+ if (tgt_methods_declaring_class.starts_with("Ljava/lang/")) {
+ tgt_methods_declaring_class.remove_prefix(sizeof("Ljava/lang/") - 1);
+ if (tgt_methods_declaring_class.starts_with("Double;")) {
+ std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
+ if (tgt_method == "long java.lang.Double.doubleToRawLongBits(double)") {
+ return GenInlinedDoubleCvt(info);
+ }
+ if (tgt_method == "double java.lang.Double.longBitsToDouble(long)") {
+ return GenInlinedDoubleCvt(info);
+ }
+ } else if (tgt_methods_declaring_class.starts_with("Float;")) {
+ std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
+ if (tgt_method == "int java.lang.Float.floatToRawIntBits(float)") {
+ return GenInlinedFloatCvt(info);
+ }
+ if (tgt_method == "float java.lang.Float.intBitsToFloat(int)") {
+ return GenInlinedFloatCvt(info);
+ }
+ } else if (tgt_methods_declaring_class.starts_with("Integer;")) {
+ std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
+ if (tgt_method == "int java.lang.Integer.reverseBytes(int)") {
+ return GenInlinedReverseBytes(info, kWord);
+ }
+ } else if (tgt_methods_declaring_class.starts_with("Long;")) {
+ std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
+ if (tgt_method == "long java.lang.Long.reverseBytes(long)") {
+ return GenInlinedReverseBytes(info, kLong);
+ }
+ } else if (tgt_methods_declaring_class.starts_with("Math;") ||
+ tgt_methods_declaring_class.starts_with("StrictMath;")) {
+ std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
+ if (tgt_method == "int java.lang.Math.abs(int)" ||
+ tgt_method == "int java.lang.StrictMath.abs(int)") {
+ return GenInlinedAbsInt(info);
+ }
+ if (tgt_method == "long java.lang.Math.abs(long)" ||
+ tgt_method == "long java.lang.StrictMath.abs(long)") {
+ return GenInlinedAbsLong(info);
+ }
+ if (tgt_method == "int java.lang.Math.max(int, int)" ||
+ tgt_method == "int java.lang.StrictMath.max(int, int)") {
+ return GenInlinedMinMaxInt(info, false /* is_min */);
+ }
+ if (tgt_method == "int java.lang.Math.min(int, int)" ||
+ tgt_method == "int java.lang.StrictMath.min(int, int)") {
+ return GenInlinedMinMaxInt(info, true /* is_min */);
+ }
+ if (tgt_method == "double java.lang.Math.sqrt(double)" ||
+ tgt_method == "double java.lang.StrictMath.sqrt(double)") {
+ return GenInlinedSqrt(info);
+ }
+ } else if (tgt_methods_declaring_class.starts_with("Short;")) {
+ std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
+ if (tgt_method == "short java.lang.Short.reverseBytes(short)") {
+ return GenInlinedReverseBytes(info, kSignedHalf);
+ }
+ } else if (tgt_methods_declaring_class.starts_with("String;")) {
+ std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
+ if (tgt_method == "char java.lang.String.charAt(int)") {
+ return GenInlinedCharAt(info);
+ }
+ if (tgt_method == "int java.lang.String.compareTo(java.lang.String)") {
+ return GenInlinedStringCompareTo(info);
+ }
+ if (tgt_method == "boolean java.lang.String.is_empty()") {
+ return GenInlinedStringIsEmptyOrLength(info, true /* is_empty */);
+ }
+ if (tgt_method == "int java.lang.String.index_of(int, int)") {
+ return GenInlinedIndexOf(info, false /* base 0 */);
+ }
+ if (tgt_method == "int java.lang.String.index_of(int)") {
+ return GenInlinedIndexOf(info, true /* base 0 */);
+ }
+ if (tgt_method == "int java.lang.String.length()") {
+ return GenInlinedStringIsEmptyOrLength(info, false /* is_empty */);
+ }
+ } else if (tgt_methods_declaring_class.starts_with("Thread;")) {
+ std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
+ if (tgt_method == "java.lang.Thread java.lang.Thread.currentThread()") {
+ return GenInlinedCurrentThread(info);
+ }
}
} else if (tgt_methods_declaring_class.starts_with("Llibcore/io/Memory;")) {
std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
diff --git a/compiler/llvm/llvm_compilation_unit.cc b/compiler/llvm/llvm_compilation_unit.cc
index 038f5dc..feb495e 100644
--- a/compiler/llvm/llvm_compilation_unit.cc
+++ b/compiler/llvm/llvm_compilation_unit.cc
@@ -211,6 +211,7 @@
::llvm::TargetOptions target_options;
target_options.FloatABIType = ::llvm::FloatABI::Soft;
target_options.NoFramePointerElim = true;
+ target_options.NoFramePointerElimNonLeaf = true;
target_options.UseSoftFloat = false;
target_options.EnableFastISel = false;
@@ -254,7 +255,7 @@
::llvm::OwningPtr< ::llvm::tool_output_file> out_file(
new ::llvm::tool_output_file(bitcode_filename_.c_str(), errmsg,
- ::llvm::sys::fs::F_Binary));
+ ::llvm::raw_fd_ostream::F_Binary));
if (!errmsg.empty()) {
@@ -274,6 +275,7 @@
// pm_builder.Inliner = ::llvm::createAlwaysInlinerPass();
// pm_builder.Inliner = ::llvm::createPartialInliningPass();
pm_builder.OptLevel = 3;
+ pm_builder.DisableSimplifyLibCalls = 1;
pm_builder.DisableUnitAtATime = 1;
pm_builder.populateFunctionPassManager(fpm);
pm_builder.populateModulePassManager(pm);
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index 8d4f3ce..65f2383 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -180,6 +180,44 @@
return os;
}
+struct FpRegister {
+ explicit FpRegister(uint32_t instr, uint16_t at_bit, uint16_t extra_at_bit) {
+ size = (instr >> 8) & 1;
+ uint32_t Vn = (instr >> at_bit) & 0xF;
+ uint32_t N = (instr >> extra_at_bit) & 1;
+ r = (size != 0 ? ((N << 4) | Vn) : ((Vn << 1) | N));
+ }
+ FpRegister(const FpRegister& other, uint32_t offset)
+ : size(other.size), r(other.r + offset) {}
+
+ uint32_t size; // 0 = f32, 1 = f64
+ uint32_t r;
+};
+std::ostream& operator<<(std::ostream& os, const FpRegister& rhs) {
+ return os << ((rhs.size != 0) ? "d" : "s") << rhs.r;
+}
+
+struct FpRegisterRange {
+ explicit FpRegisterRange(uint32_t instr)
+ : first(instr, 12, 22), imm8(instr & 0xFF) {}
+ FpRegister first;
+ uint32_t imm8;
+};
+std::ostream& operator<<(std::ostream& os, const FpRegisterRange& rhs) {
+ os << "{" << rhs.first;
+ int count = (rhs.first.size != 0 ? ((rhs.imm8 + 1u) >> 1) : rhs.imm8);
+ if (count > 1) {
+ os << "-" << FpRegister(rhs.first, count - 1);
+ }
+ if (rhs.imm8 == 0) {
+ os << " (EMPTY)";
+ } else if (rhs.first.size != 0 && (rhs.imm8 & 1) != 0) {
+ os << rhs.first << " (HALF)";
+ }
+ os << "}";
+ return os;
+}
+
void DisassemblerArm::DumpArm(std::ostream& os, const uint8_t* instr_ptr) {
uint32_t instruction = ReadU32(instr_ptr);
uint32_t cond = (instruction >> 28) & 0xf;
@@ -616,57 +654,115 @@
uint32_t op4 = (instr >> 4) & 0x1;
if (coproc == 10 || coproc == 11) { // 101x
- if (op3 < 0x20 && (op3 >> 1) != 2) { // 0xxxxx and not 00010x
- // extension load/store instructions
- int op = op3 & 0x1f;
+ if (op3 < 0x20 && (op3 & ~5) != 0) { // 0xxxxx and not 000x0x
+ // Extension register load/store instructions
+ // |1111|110|00000|0000|1111|110|0|00000000|
+ // |5 2|1 9|87654|3 0|5 2|1 9|8|7 0|
+ // |----|---|-----|----|----|---|-|--------|
+ // |3322|222|22222|1111|1111|110|0|00000000|
+ // |1 8|7 5|4 0|9 6|5 2|1 9|8|7 0|
+ // |----|---|-----|----|----|---|-|--------|
+ // |1110|110|PUDWL| Rn | Vd |101|S| imm8 |
uint32_t P = (instr >> 24) & 1;
uint32_t U = (instr >> 23) & 1;
- uint32_t D = (instr >> 22) & 1;
uint32_t W = (instr >> 21) & 1;
- uint32_t S = (instr >> 8) & 1;
- ArmRegister Rn(instr, 16);
- uint32_t Vd = (instr >> 12) & 0xF;
- uint32_t imm8 = instr & 0xFF;
- uint32_t d = (S == 0 ? ((Vd << 1) | D) : (Vd | (D << 4)));
- ArmRegister Rd(d, 0);
-
- if (op == 8 || op == 12 || op == 10 || op == 14 ||
- op == 18 || op == 22) { // 01x00 or 01x10
- // vector store multiple or vpush
- if (P == 1 && U == 0 && W == 1 && Rn.r == 13) {
- opcode << "vpush" << (S == 0 ? ".f64" : ".f32");
- args << Rd << " .. " << (Rd.r + imm8);
- } else {
- opcode << "vstm" << (S == 0 ? ".f64" : ".f32");
- args << Rn << ", " << Rd << " .. " << (Rd.r + imm8);
+ if (P == U && W == 1) {
+ opcode << "UNDEFINED";
+ } else {
+ uint32_t L = (instr >> 20) & 1;
+ uint32_t S = (instr >> 8) & 1;
+ ArmRegister Rn(instr, 16);
+ if (P == 1 && W == 0) { // VLDR
+ FpRegister d(instr, 12, 22);
+ uint32_t imm8 = instr & 0xFF;
+ opcode << (L == 1 ? "vldr" : "vstr");
+ args << d << ", [" << Rn << ", #" << ((U == 1) ? "" : "-")
+ << (imm8 << 2) << "]";
+ } else if (Rn.r == 13 && W == 1 && U == L) { // VPUSH/VPOP
+ opcode << (L == 1 ? "vpop" : "vpush");
+ args << FpRegisterRange(instr);
+ } else { // VLDM
+ opcode << (L == 1 ? "vldm" : "vstm");
+ args << Rn << ((W == 1) ? "!" : "") << ", "
+ << FpRegisterRange(instr);
}
- } else if (op == 16 || op == 20 || op == 24 || op == 28) {
- // 1xx00
- // vector store register
- opcode << "vstr" << (S == 0 ? ".f64" : ".f32");
- args << Rd << ", [" << Rn << ", #" << imm8 << "]";
- } else if (op == 17 || op == 21 || op == 25 || op == 29) {
- // 1xx01
- // vector load register
- opcode << "vldr" << (S == 0 ? ".f64" : ".f32");
- args << Rd << ", [" << Rn << ", #" << imm8 << "]";
- } else if (op == 9 || op == 13 || op == 11 || op == 15 ||
- op == 19 || op == 23 ) { // 01x11 10x11
- // vldm or vpop
- if (P == 1 && U == 0 && W == 1 && Rn.r == 13) {
- opcode << "vpop" << (S == 0 ? ".f64" : ".f32");
- args << Rd << " .. " << (Rd.r + imm8);
- } else {
- opcode << "vldm" << (S == 0 ? ".f64" : ".f32");
- args << Rn << ", " << Rd << " .. " << (Rd.r + imm8);
- }
+ opcode << (S == 1 ? ".f64" : ".f32");
}
} else if ((op3 >> 1) == 2) { // 00010x
- // 64 bit transfers
+ if ((instr & 0xD0) == 0x10) {
+ // 64bit transfers between ARM core and extension registers.
+ uint32_t L = (instr >> 20) & 1;
+ uint32_t S = (instr >> 8) & 1;
+ ArmRegister Rt2(instr, 16);
+ ArmRegister Rt(instr, 12);
+ FpRegister m(instr, 0, 5);
+ opcode << "vmov" << (S ? ".f64" : ".f32");
+ if (L == 1) {
+ args << Rt << ", " << Rt2 << ", ";
+ }
+ if (S) {
+ args << m;
+ } else {
+ args << m << ", " << FpRegister(m, 1);
+ }
+ if (L == 0) {
+ args << ", " << Rt << ", " << Rt2;
+ }
+ if (Rt.r == 15 || Rt.r == 13 || Rt2.r == 15 || Rt2.r == 13 ||
+ (S == 0 && m.r == 31) || (L == 1 && Rt.r == Rt2.r)) {
+ args << " (UNPREDICTABLE)";
+ }
+ }
} else if ((op3 >> 4) == 2 && op4 == 0) { // 10xxxx, op = 0
// fp data processing
} else if ((op3 >> 4) == 2 && op4 == 1) { // 10xxxx, op = 1
- // 8,16,32 bit transfers
+ if (coproc == 10 && (op3 & 0xE) == 0) {
+ // VMOV (between ARM core register and single-precision register)
+ // |1111|1100|000|0 |0000|1111|1100|0|00|0|0000|
+ // |5 |1 8|7 5|4 |3 0|5 2|1 8|7|65|4|3 0|
+ // |----|----|---|- |----|----|----|-|--|-|----|
+ // |3322|2222|222|2 |1111|1111|1100|0|00|0|0000|
+ // |1 8|7 4|3 1|0 |9 6|5 2|1 8|7|65|4|3 0|
+ // |----|----|---|- |----|----|----|-|--|-|----|
+ // |1110|1110|000|op| Vn | Rt |1010|N|00|1|0000|
+ uint32_t op = op3 & 1;
+ ArmRegister Rt(instr, 12);
+ FpRegister n(instr, 16, 7);
+ opcode << "vmov.f32";
+ if (op) {
+ args << Rt << ", " << n;
+ } else {
+ args << n << ", " << Rt;
+ }
+ if (Rt.r == 13 || Rt.r == 15 || (instr & 0x6F) != 0) {
+ args << " (UNPREDICTABLE)";
+ }
+ } else if (coproc == 10 && op3 == 0x2F) {
+ // VMRS
+ // |1111|11000000|0000|1111|1100|000|0|0000|
+ // |5 |1 4|3 0|5 2|1 8|7 5|4|3 0|
+ // |----|--------|----|----|----|---|-|----|
+ // |3322|22222222|1111|1111|1100|000|0|0000|
+ // |1 8|7 0|9 6|5 2|1 8|7 5|4|3 0|
+ // |----|--------|----|----|----|---|-|----|
+ // |1110|11101111|reg | Rt |1010|000|1|0000| - last 7 0s are (0)
+ uint32_t spec_reg = (instr >> 16) & 0xF;
+ ArmRegister Rt(instr, 12);
+ opcode << "vmrs";
+ if (spec_reg == 1) {
+ if (Rt.r == 15) {
+ args << "APSR_nzcv, FPSCR";
+ } else if (Rt.r == 13) {
+ args << Rt << ", FPSCR (UNPREDICTABLE)";
+ } else {
+ args << Rt << ", FPSCR";
+ }
+ } else {
+ args << "(PRIVILEGED)";
+ }
+ } else if (coproc == 11 && (op3 & 0x9) != 8) {
+ // VMOV (ARM core register to scalar or vice versa; 8/16/32-bit)
+ }
}
}
@@ -686,30 +782,19 @@
uint32_t opc3 = (instr >> 6) & 0x3;
if ((opc1 & 0xB) == 0xB) { // 1x11
// Other VFP data-processing instructions.
- uint32_t D = (instr >> 22) & 0x1;
- uint32_t Vd = (instr >> 12) & 0xF;
uint32_t sz = (instr >> 8) & 1;
- uint32_t M = (instr >> 5) & 1;
- uint32_t Vm = instr & 0xF;
- bool dp_operation = sz == 1;
+ FpRegister d(instr, 12, 22);
+ FpRegister m(instr, 0, 5);
switch (opc2) {
case 0x1: // Vneg/Vsqrt
// 1110 11101 D 11 0001 dddd 101s o1M0 mmmm
- opcode << (opc3 == 1 ? "vneg" : "vsqrt") << (dp_operation ? ".f64" : ".f32");
- if (dp_operation) {
- args << "f" << ((D << 4) | Vd) << ", " << "f" << ((M << 4) | Vm);
- } else {
- args << "f" << ((Vd << 1) | D) << ", " << "f" << ((Vm << 1) | M);
- }
+ opcode << (opc3 == 1 ? "vneg" : "vsqrt") << (sz == 1 ? ".f64" : ".f32");
+ args << d << ", " << m;
break;
case 0x4: case 0x5: { // Vector compare
// 1110 11101 D 11 0100 dddd 101 sE1M0 mmmm
- opcode << (opc3 == 1 ? "vcmp" : "vcmpe") << (dp_operation ? ".f64" : ".f32");
- if (dp_operation) {
- args << "f" << ((D << 4) | Vd) << ", " << "f" << ((M << 4) | Vm);
- } else {
- args << "f" << ((Vd << 1) | D) << ", " << "f" << ((Vm << 1) | M);
- }
+ opcode << (opc3 == 1 ? "vcmp" : "vcmpe") << (sz == 1 ? ".f64" : ".f32");
+ args << d << ", " << m;
break;
}
}
@@ -720,18 +805,11 @@
if ((instr & 0xFFBF0ED0) == 0xeeb10ac0) { // Vsqrt
// 1110 11101 D 11 0001 dddd 101S 11M0 mmmm
// 1110 11101 0 11 0001 1101 1011 1100 1000 - eeb1dbc8
- uint32_t D = (instr >> 22) & 1;
- uint32_t Vd = (instr >> 12) & 0xF;
uint32_t sz = (instr >> 8) & 1;
- uint32_t M = (instr >> 5) & 1;
- uint32_t Vm = instr & 0xF;
- bool dp_operation = sz == 1;
- opcode << "vsqrt" << (dp_operation ? ".f64" : ".f32");
- if (dp_operation) {
- args << "f" << ((D << 4) | Vd) << ", " << "f" << ((M << 4) | Vm);
- } else {
- args << "f" << ((Vd << 1) | D) << ", " << "f" << ((Vm << 1) | M);
- }
+ FpRegister d(instr, 12, 22);
+ FpRegister m(instr, 0, 5);
+ opcode << "vsqrt" << (sz == 1 ? ".f64" : ".f32");
+ args << d << ", " << m;
}
}
}
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index b9716d5..90276c2 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -715,14 +715,25 @@
if (image_root_object->IsObjectArray()) {
Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count);
std::ostream indent2_os(&indent2_filter);
- // TODO: replace down_cast with AsObjectArray (g++ currently has a problem with this)
mirror::ObjectArray<mirror::Object>* image_root_object_array
- = down_cast<mirror::ObjectArray<mirror::Object>*>(image_root_object);
- // = image_root_object->AsObjectArray<Object>();
+ = image_root_object->AsObjectArray<mirror::Object>();
for (int i = 0; i < image_root_object_array->GetLength(); i++) {
mirror::Object* value = image_root_object_array->Get(i);
+ size_t run = 0;
+ for (int32_t j = i + 1; j < image_root_object_array->GetLength(); j++) {
+ if (value == image_root_object_array->Get(j)) {
+ run++;
+ } else {
+ break;
+ }
+ }
+ if (run == 0) {
+ indent2_os << StringPrintf("%d: ", i);
+ } else {
+ indent2_os << StringPrintf("%d to %zd: ", i, i + run);
+ i = i + run;
+ }
if (value != NULL) {
- indent2_os << i << ": ";
PrettyObjectValue(indent2_os, value->GetClass(), value);
} else {
indent2_os << i << ": null\n";
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 9a853d0..1a058ea 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -69,12 +69,24 @@
.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
add sp, #4 @ bottom word holds Method*
pop {r5-r8, r10-r11, lr} @ 7 words of callee saves
+ .cfi_restore r5
+ .cfi_restore r6
+ .cfi_restore r7
+ .cfi_restore r8
+ .cfi_restore r10
+ .cfi_restore r11
.cfi_adjust_cfa_offset -32
.endm
.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
add sp, #4 @ bottom word holds Method*
pop {r5-r8, r10-r11, lr} @ 7 words of callee saves
+ .cfi_restore r5
+ .cfi_restore r6
+ .cfi_restore r7
+ .cfi_restore r8
+ .cfi_restore r10
+ .cfi_restore r11
.cfi_adjust_cfa_offset -32
bx lr @ return
.endm
@@ -86,7 +98,6 @@
.macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
push {r1-r3, r5-r8, r10-r11, lr} @ 10 words of callee saves
.save {r1-r3, r5-r8, r10-r11, lr}
- .cfi_adjust_cfa_offset 40
.cfi_rel_offset r1, 0
.cfi_rel_offset r2, 4
.cfi_rel_offset r3, 8
@@ -97,6 +108,7 @@
.cfi_rel_offset r10, 28
.cfi_rel_offset r11, 32
.cfi_rel_offset lr, 36
+ .cfi_adjust_cfa_offset 40
sub sp, #8 @ 2 words of space, bottom word will hold Method*
.pad #8
.cfi_adjust_cfa_offset 8
@@ -105,6 +117,15 @@
.macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
add sp, #8 @ rewind sp
pop {r1-r3, r5-r8, r10-r11, lr} @ 10 words of callee saves
+ .cfi_restore r1
+ .cfi_restore r2
+ .cfi_restore r3
+ .cfi_restore r5
+ .cfi_restore r6
+ .cfi_restore r7
+ .cfi_restore r8
+ .cfi_restore r10
+ .cfi_restore r11
.cfi_adjust_cfa_offset -48
.endm
@@ -285,6 +306,11 @@
ldr ip, [sp, #24] @ load the result pointer
strd r0, [ip] @ store r0/r1 into result pointer
pop {r0, r4, r5, r9, r11, lr} @ restore spill regs
+ .cfi_restore r0
+ .cfi_restore r4
+ .cfi_restore r5
+ .cfi_restore r9
+ .cfi_restore lr
.cfi_adjust_cfa_offset -24
bx lr
END art_quick_invoke_stub
@@ -413,6 +439,8 @@
add sp, #4
.cfi_adjust_cfa_offset -4
pop {r0-r1, lr}
+ .cfi_restore r0
+ .cfi_restore r1
SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
mov r2, r9 @ pass Thread::Current
mov r3, sp @ pass SP
@@ -689,6 +717,7 @@
.cfi_rel_offset r9, 0
bl artSet64StaticFromCode @ (field_idx, referrer, new_val, Thread*, SP)
add sp, #16 @ release out args
+ .cfi_adjust_cfa_offset -16
RESTORE_REF_ONLY_CALLEE_SAVE_FRAME @ TODO: we can clearly save an add here
RETURN_IF_RESULT_IS_ZERO
DELIVER_PENDING_EXCEPTION
@@ -1137,6 +1166,8 @@
mov r2, r0 @ link register saved by instrumentation
mov lr, r1 @ r1 is holding link register if we're to bounce to deoptimize
pop {r0, r1} @ restore return value
+ .cfi_restore r0
+ .cfi_restore r1
add sp, #32 @ remove callee save frame
.cfi_adjust_cfa_offset -32
bx r2 @ return
@@ -1187,6 +1218,8 @@
mov r1,r10
pop {r9 - r10}
.cfi_adjust_cfa_offset -8
+ .cfi_restore r9
+ .cfi_restore r10
bx lr
END art_quick_mul_long
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index 451b1bb..8862711 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -89,28 +89,46 @@
.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
lw $ra, 60($sp)
+ .cfi_restore 31
lw $s8, 56($sp)
+ .cfi_restore 30
lw $gp, 52($sp)
+ .cfi_restore 28
lw $s7, 48($sp)
+ .cfi_restore 23
lw $s6, 44($sp)
+ .cfi_restore 22
lw $s5, 40($sp)
+ .cfi_restore 21
lw $s4, 36($sp)
+ .cfi_restore 20
lw $s3, 32($sp)
+ .cfi_restore 19
lw $s2, 28($sp)
+ .cfi_restore 18
addiu $sp, $sp, 64
.cfi_adjust_cfa_offset -64
.endm
.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
lw $ra, 60($sp)
+ .cfi_restore 31
lw $s8, 56($sp)
+ .cfi_restore 30
lw $gp, 52($sp)
+ .cfi_restore 28
lw $s7, 48($sp)
+ .cfi_restore 23
lw $s6, 44($sp)
+ .cfi_restore 22
lw $s5, 40($sp)
+ .cfi_restore 21
lw $s4, 36($sp)
+ .cfi_restore 20
lw $s3, 32($sp)
+ .cfi_restore 19
lw $s2, 28($sp)
+ .cfi_restore 18
jr $ra
addiu $sp, $sp, 64
.cfi_adjust_cfa_offset -64
@@ -153,17 +171,29 @@
.macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
lw $ra, 60($sp)
+ .cfi_restore 31
lw $s8, 56($sp)
+ .cfi_restore 30
lw $gp, 52($sp)
+ .cfi_restore 28
lw $s7, 48($sp)
+ .cfi_restore 23
lw $s6, 44($sp)
+ .cfi_restore 22
lw $s5, 40($sp)
+ .cfi_restore 21
lw $s4, 36($sp)
+ .cfi_restore 20
lw $s3, 32($sp)
+ .cfi_restore 19
lw $s2, 28($sp)
+ .cfi_restore 18
lw $a3, 12($sp)
+ .cfi_restore 7
lw $a2, 8($sp)
+ .cfi_restore 6
lw $a1, 4($sp)
+ .cfi_restore 5
addiu $sp, $sp, 64 # pop frame
.cfi_adjust_cfa_offset -64
.endm
@@ -463,9 +493,13 @@
sw $zero, 0($sp) # store NULL for method* at bottom of frame
move $sp, $fp # restore the stack
lw $s0, 0($sp)
+ .cfi_restore 16
lw $s1, 4($sp)
+ .cfi_restore 17
lw $fp, 8($sp)
+ .cfi_restore 30
lw $ra, 12($sp)
+ .cfi_restore 31
addiu $sp, $sp, 16
.cfi_adjust_cfa_offset -16
lw $t0, 16($sp) # get result pointer
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 6fe4993..ee78d45 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -16,14 +16,19 @@
#include "asm_support_x86.S"
+// For x86, the CFA is esp+4, the address above the pushed return address on the stack.
+
/*
* Macro that sets up the callee save frame to conform with
* Runtime::CreateCalleeSaveMethod(kSaveAll)
*/
MACRO0(SETUP_SAVE_ALL_CALLEE_SAVE_FRAME)
PUSH edi // Save callee saves (ebx is saved/restored by the upcall)
+ .cfi_rel_offset edi, -8
PUSH esi
+ .cfi_rel_offset esi, -12
PUSH ebp
+ .cfi_rel_offset ebp, -16
subl MACRO_LITERAL(16), %esp // Grow stack by 4 words, bottom word will hold Method*
.cfi_adjust_cfa_offset 16
END_MACRO
@@ -34,8 +39,11 @@
*/
MACRO0(SETUP_REF_ONLY_CALLEE_SAVE_FRAME)
PUSH edi // Save callee saves (ebx is saved/restored by the upcall)
+ .cfi_rel_offset edi, -8
PUSH esi
+ .cfi_rel_offset esi, -12
PUSH ebp
+ .cfi_rel_offset ebp, -16
subl MACRO_LITERAL(16), %esp // Grow stack by 4 words, bottom word will hold Method*
.cfi_adjust_cfa_offset 16
END_MACRO
@@ -43,8 +51,11 @@
MACRO0(RESTORE_REF_ONLY_CALLEE_SAVE_FRAME)
addl MACRO_LITERAL(16), %esp // Unwind stack up to return address
POP ebp // Restore callee saves (ebx is saved/restored by the upcall)
+ .cfi_restore ebp
POP esi
+ .cfi_restore esi
POP edi
+ .cfi_restore edi
.cfi_adjust_cfa_offset -28
END_MACRO
@@ -54,23 +65,36 @@
*/
MACRO0(SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME)
PUSH edi // Save callee saves
+ .cfi_rel_offset edi, -8
PUSH esi
+ .cfi_rel_offset esi, -12
PUSH ebp
+ .cfi_rel_offset ebp, -16
PUSH ebx // Save args
+ .cfi_rel_offset ebx, -20
PUSH edx
+ .cfi_rel_offset edx, -24
PUSH ecx
+ .cfi_rel_offset ecx, -28
PUSH eax // Align stack, eax will be clobbered by Method*
+ .cfi_rel_offset eax, -28
END_MACRO
MACRO0(RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME)
addl MACRO_LITERAL(4), %esp // Remove padding
.cfi_adjust_cfa_offset -4
POP ecx // Restore args except eax
+ .cfi_restore ecx
POP edx
+ .cfi_restore edx
POP ebx
+ .cfi_restore ebx
POP ebp // Restore callee saves
+ .cfi_restore ebp
POP esi
+ .cfi_restore esi
POP edi
+ .cfi_restore edi
END_MACRO
/*
@@ -188,12 +212,19 @@
// Set up the callee save frame to conform with Runtime::CreateCalleeSaveMethod(kRefsAndArgs)
// return address
PUSH edi
+ .cfi_rel_offset edi, -8
PUSH esi
+ .cfi_rel_offset esi, -12
PUSH ebp
- PUSH ebx
+ .cfi_rel_offset ebp, -16
+ PUSH ebx // Save args
+ .cfi_rel_offset ebx, -20
PUSH edx
+ .cfi_rel_offset edx, -24
PUSH ecx
- PUSH eax // <-- callee save Method* to go here
+ .cfi_rel_offset ecx, -28
+ PUSH eax // <-- callee save Method* to go here
+ .cfi_rel_offset eax, -32
movl %esp, %edx // remember SP
// Outgoing argument set up
subl MACRO_LITERAL(12), %esp // alignment padding
@@ -209,11 +240,16 @@
movl %edx, %edi // save code pointer in EDI
addl MACRO_LITERAL(36), %esp // Pop arguments skip eax
.cfi_adjust_cfa_offset -36
- POP ecx // Restore args
+ POP ecx // Restore args except eax
+ .cfi_restore ecx
POP edx
+ .cfi_restore edx
POP ebx
- POP ebp // Restore callee saves.
+ .cfi_restore ebx
+ POP ebp // Restore callee saves
+ .cfi_restore ebp
POP esi
+ .cfi_restore esi
// Swap EDI callee save with code pointer.
xchgl %edi, (%esp)
testl %eax, %eax // Branch forward if exception pending.
@@ -248,7 +284,9 @@
*/
DEFINE_FUNCTION art_quick_invoke_stub
PUSH ebp // save ebp
+ .cfi_rel_offset ebp, -8
PUSH ebx // save ebx
+ .cfi_rel_offset ebx, -12
mov %esp, %ebp // copy value of stack pointer into base pointer
.cfi_def_cfa_register ebp
mov 20(%ebp), %ebx // get arg array size
@@ -269,8 +307,11 @@
mov 12(%esp), %ebx // copy arg3 into ebx
call *METHOD_CODE_OFFSET(%eax) // call the method
mov %ebp, %esp // restore stack pointer
+ .cfi_def_cfa_register esp
POP ebx // pop ebx
+ .cfi_restore ebx
POP ebp // pop ebp
+ .cfi_restore ebp
mov 20(%esp), %ecx // get result pointer
cmpl LITERAL(68), 24(%esp) // test if result type char == 'D'
je return_double_quick
@@ -495,7 +536,9 @@
DEFINE_FUNCTION art_quick_check_cast
PUSH eax // alignment padding
PUSH ecx // pass arg2 - obj->klass
+ .cfi_rel_offset ecx, -12
PUSH eax // pass arg1 - checked class
+ .cfi_rel_offset eax, -16
call SYMBOL(artIsAssignableFromCode) // (Class* klass, Class* ref_klass)
testl %eax, %eax
jz 1f // jump forward if not assignable
@@ -504,7 +547,9 @@
ret
1:
POP eax // pop arguments
+ .cfi_restore eax
POP ecx
+ .cfi_restore ecx
addl LITERAL(4), %esp
.cfi_adjust_cfa_offset -12
SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index bdcf6ac..0eecd28 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -3489,9 +3489,9 @@
recent_allocation_records_ = new AllocRecord[gAllocRecordMax];
CHECK(recent_allocation_records_ != NULL);
}
- Runtime::Current()->InstrumentQuickAllocEntryPoints();
+ Runtime::Current()->GetInstrumentation()->InstrumentQuickAllocEntryPoints();
} else {
- Runtime::Current()->UninstrumentQuickAllocEntryPoints();
+ Runtime::Current()->GetInstrumentation()->UninstrumentQuickAllocEntryPoints();
delete[] recent_allocation_records_;
recent_allocation_records_ = NULL;
}
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 7e09a48..a897cce 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -36,6 +36,7 @@
#include "mirror/string.h"
#include "os.h"
#include "safe_map.h"
+#include "ScopedFd.h"
#include "thread.h"
#include "UniquePtr.h"
#include "utf-inl.h"
@@ -64,34 +65,34 @@
static int OpenAndReadMagic(const char* filename, uint32_t* magic, std::string* error_msg) {
CHECK(magic != NULL);
- int fd = open(filename, O_RDONLY, 0);
- if (fd == -1) {
+ ScopedFd fd(open(filename, O_RDONLY, 0));
+ if (fd.get() == -1) {
*error_msg = StringPrintf("Unable to open '%s' : %s", filename, strerror(errno));
return -1;
}
- int n = TEMP_FAILURE_RETRY(read(fd, magic, sizeof(*magic)));
+ int n = TEMP_FAILURE_RETRY(read(fd.get(), magic, sizeof(*magic)));
if (n != sizeof(*magic)) {
*error_msg = StringPrintf("Failed to find magic in '%s'", filename);
return -1;
}
- if (lseek(fd, 0, SEEK_SET) != 0) {
+ if (lseek(fd.get(), 0, SEEK_SET) != 0) {
*error_msg = StringPrintf("Failed to seek to beginning of file '%s' : %s", filename,
strerror(errno));
return -1;
}
- return fd;
+ return fd.release();
}
bool DexFile::GetChecksum(const char* filename, uint32_t* checksum, std::string* error_msg) {
CHECK(checksum != NULL);
uint32_t magic;
- int fd = OpenAndReadMagic(filename, &magic, error_msg);
- if (fd == -1) {
+ ScopedFd fd(OpenAndReadMagic(filename, &magic, error_msg));
+ if (fd.get() == -1) {
DCHECK(!error_msg->empty());
return false;
}
if (IsZipMagic(magic)) {
- UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, filename, error_msg));
+ UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd.release(), filename, error_msg));
if (zip_archive.get() == NULL) {
*error_msg = StringPrintf("Failed to open zip archive '%s'", filename);
return false;
@@ -105,7 +106,7 @@
return true;
}
if (IsDexMagic(magic)) {
- UniquePtr<const DexFile> dex_file(DexFile::OpenFile(fd, filename, false, error_msg));
+ UniquePtr<const DexFile> dex_file(DexFile::OpenFile(fd.release(), filename, false, error_msg));
if (dex_file.get() == NULL) {
return false;
}
@@ -120,16 +121,16 @@
const char* location,
std::string* error_msg) {
uint32_t magic;
- int fd = OpenAndReadMagic(filename, &magic, error_msg);
- if (fd == -1) {
+ ScopedFd fd(OpenAndReadMagic(filename, &magic, error_msg));
+ if (fd.get() == -1) {
DCHECK(!error_msg->empty());
return NULL;
}
if (IsZipMagic(magic)) {
- return DexFile::OpenZip(fd, location, error_msg);
+ return DexFile::OpenZip(fd.release(), location, error_msg);
}
if (IsDexMagic(magic)) {
- return DexFile::OpenFile(fd, location, true, error_msg);
+ return DexFile::OpenFile(fd.release(), location, true, error_msg);
}
*error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
return nullptr;
@@ -168,26 +169,26 @@
const DexFile* DexFile::OpenFile(int fd, const char* location, bool verify,
std::string* error_msg) {
CHECK(location != nullptr);
- struct stat sbuf;
- memset(&sbuf, 0, sizeof(sbuf));
- if (fstat(fd, &sbuf) == -1) {
- *error_msg = StringPrintf("DexFile: fstat \'%s\' failed: %s", location, strerror(errno));
- close(fd);
- return nullptr;
+ UniquePtr<MemMap> map;
+ {
+ ScopedFd delayed_close(fd);
+ struct stat sbuf;
+ memset(&sbuf, 0, sizeof(sbuf));
+ if (fstat(fd, &sbuf) == -1) {
+ *error_msg = StringPrintf("DexFile: fstat \'%s\' failed: %s", location, strerror(errno));
+ return nullptr;
+ }
+ if (S_ISDIR(sbuf.st_mode)) {
+ *error_msg = StringPrintf("Attempt to mmap directory '%s'", location);
+ return nullptr;
+ }
+ size_t length = sbuf.st_size;
+ map.reset(MemMap::MapFile(length, PROT_READ, MAP_PRIVATE, fd, 0, location, error_msg));
+ if (map.get() == nullptr) {
+ DCHECK(!error_msg->empty());
+ return nullptr;
+ }
}
- if (S_ISDIR(sbuf.st_mode)) {
- *error_msg = StringPrintf("Attempt to mmap directory '%s'", location);
- return nullptr;
- }
- size_t length = sbuf.st_size;
- UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ, MAP_PRIVATE, fd, 0, location,
- error_msg));
- if (map.get() == nullptr) {
- DCHECK(!error_msg->empty());
- close(fd);
- return nullptr;
- }
- close(fd);
if (map->Size() < sizeof(DexFile::Header)) {
*error_msg = StringPrintf(
@@ -220,7 +221,7 @@
DCHECK(!error_msg->empty());
return nullptr;
}
- return DexFile::Open(*zip_archive.get(), location, error_msg);
+ return DexFile::Open(*zip_archive, location, error_msg);
}
const DexFile* DexFile::OpenMemory(const std::string& location,
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 804c669..de3ab0e 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -237,7 +237,7 @@
CHECK_NE(max_allowed_footprint_, 0U);
if (running_on_valgrind_) {
- Runtime::Current()->InstrumentQuickAllocEntryPoints();
+ Runtime::Current()->GetInstrumentation()->InstrumentQuickAllocEntryPoints();
}
if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 7d2441b..91909e4 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -300,6 +300,10 @@
card_table_->MarkCard(dst);
}
+ void WriteBarrierEveryFieldOf(const mirror::Object* obj) {
+ card_table_->MarkCard(obj);
+ }
+
accounting::CardTable* GetCardTable() const {
return card_table_.get();
}
diff --git a/runtime/indenter.h b/runtime/indenter.h
index c432e1b..d055d4e 100644
--- a/runtime/indenter.h
+++ b/runtime/indenter.h
@@ -17,6 +17,7 @@
#ifndef ART_RUNTIME_INDENTER_H_
#define ART_RUNTIME_INDENTER_H_
+#include "base/logging.h"
#include "base/macros.h"
#include <streambuf>
@@ -30,16 +31,28 @@
private:
int_type overflow(int_type c) {
- if (c != std::char_traits<char>::eof()) {
- if (indent_next_) {
- for (size_t i = 0; i < count_; ++i) {
- out_sbuf_->sputc(text_);
+ if (UNLIKELY(c == std::char_traits<char>::eof())) {
+ out_sbuf_->pubsync();
+ return c;
+ }
+ if (indent_next_) {
+ for (size_t i = 0; i < count_; ++i) {
+ int_type r = out_sbuf_->sputc(text_);
+ if (UNLIKELY(r != text_)) {
+ out_sbuf_->pubsync();
+ r = out_sbuf_->sputc(text_);
+ CHECK_EQ(r, text_) << "Error writing to buffer. Disk full?";
}
}
- out_sbuf_->sputc(c);
- indent_next_ = (c == '\n');
}
- return std::char_traits<char>::not_eof(c);
+ indent_next_ = (c == '\n');
+ int_type r = out_sbuf_->sputc(c);
+ if (UNLIKELY(r != c)) {
+ out_sbuf_->pubsync();
+ r = out_sbuf_->sputc(c);
+ CHECK_EQ(r, c) << "Error writing to buffer. Disk full?";
+ }
+ return r;
}
int sync() {
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 8cf486f..0f4fa4e 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -39,6 +39,9 @@
#include "thread_list.h"
namespace art {
+
+extern void SetQuickAllocEntryPointsInstrumented(bool instrumented);
+
namespace instrumentation {
// Do we want to deoptimize for method entry and exit listeners or just try to intercept
@@ -391,6 +394,55 @@
}
}
+static void ResetQuickAllocEntryPointsForThread(Thread* thread, void* arg) {
+ thread->ResetQuickAllocEntryPointsForThread();
+}
+
+void Instrumentation::InstrumentQuickAllocEntryPoints() {
+ // TODO: the read of quick_alloc_entry_points_instrumentation_counter_ is racey and this code
+ // should be guarded by a lock.
+ DCHECK_GE(quick_alloc_entry_points_instrumentation_counter_, 0U);
+ bool enable_instrumentation = (quick_alloc_entry_points_instrumentation_counter_ == 0);
+ quick_alloc_entry_points_instrumentation_counter_++;
+ if (enable_instrumentation) {
+ // Instrumentation wasn't enabled so enable it.
+ SetQuickAllocEntryPointsInstrumented(true);
+ Runtime* runtime = Runtime::Current();
+ if (runtime->IsStarted()) {
+ ThreadList* tl = runtime->GetThreadList();
+ Thread* self = Thread::Current();
+ tl->SuspendAll();
+ {
+ MutexLock mu(self, *Locks::thread_list_lock_);
+ tl->ForEach(ResetQuickAllocEntryPointsForThread, NULL);
+ }
+ tl->ResumeAll();
+ }
+ }
+}
+
+void Instrumentation::UninstrumentQuickAllocEntryPoints() {
+ // TODO: the read of quick_alloc_entry_points_instrumentation_counter_ is racey and this code
+ // should be guarded by a lock.
+ DCHECK_GT(quick_alloc_entry_points_instrumentation_counter_, 0U);
+ quick_alloc_entry_points_instrumentation_counter_--;
+ bool disable_instrumentation = (quick_alloc_entry_points_instrumentation_counter_ == 0);
+ if (disable_instrumentation) {
+ SetQuickAllocEntryPointsInstrumented(false);
+ Runtime* runtime = Runtime::Current();
+ if (runtime->IsStarted()) {
+ ThreadList* tl = Runtime::Current()->GetThreadList();
+ Thread* self = Thread::Current();
+ tl->SuspendAll();
+ {
+ MutexLock mu(self, *Locks::thread_list_lock_);
+ tl->ForEach(ResetQuickAllocEntryPointsForThread, NULL);
+ }
+ tl->ResumeAll();
+ }
+ }
+}
+
void Instrumentation::UpdateMethodsCode(mirror::ArtMethod* method, const void* code) const {
if (LIKELY(!instrumentation_stubs_installed_)) {
method->SetEntryPointFromCompiledCode(code);
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index 7a0aaf7..25a4eec 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -104,7 +104,8 @@
have_method_entry_listeners_(false), have_method_exit_listeners_(false),
have_method_unwind_listeners_(false), have_dex_pc_listeners_(false),
have_exception_caught_listeners_(false),
- interpreter_handler_table_(kMainHandlerTable) {}
+ interpreter_handler_table_(kMainHandlerTable),
+ quick_alloc_entry_points_instrumentation_counter_(0) {}
// Add a listener to be notified of the masked together sent of instrumentation events. This
// suspend the runtime to install stubs. You are expected to hold the mutator lock as a proxy
@@ -123,6 +124,9 @@
return interpreter_handler_table_;
}
+ void InstrumentQuickAllocEntryPoints() LOCKS_EXCLUDED(Locks::thread_list_lock_);
+ void UninstrumentQuickAllocEntryPoints() LOCKS_EXCLUDED(Locks::thread_list_lock_);
+
// Update the code of a method respecting any installed stubs.
void UpdateMethodsCode(mirror::ArtMethod* method, const void* code) const;
@@ -289,9 +293,14 @@
std::list<InstrumentationListener*> dex_pc_listeners_ GUARDED_BY(Locks::mutator_lock_);
std::list<InstrumentationListener*> exception_caught_listeners_ GUARDED_BY(Locks::mutator_lock_);
- // Current interpreter handler table. This is updated each time the thread state flags are modified.
+ // Current interpreter handler table. This is updated each time the thread state flags are
+ // modified.
InterpreterHandlerTable interpreter_handler_table_;
+ // Greater than 0 if quick alloc entry points instrumented.
+ // TODO: The access and changes to this is racy and should be guarded by a lock.
+ size_t quick_alloc_entry_points_instrumentation_counter_;
+
DISALLOW_COPY_AND_ASSIGN(Instrumentation);
};
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index bd187c1..87d02c9 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -40,48 +40,39 @@
namespace mirror {
Object* Object::Clone(Thread* self) {
- Class* c = GetClass();
+ mirror::Class* c = GetClass();
DCHECK(!c->IsClassClass());
-
// Object::SizeOf gets the right size even if we're an array.
// Using c->AllocObject() here would be wrong.
size_t num_bytes = SizeOf();
gc::Heap* heap = Runtime::Current()->GetHeap();
- SirtRef<Object> copy(self, heap->AllocObject(self, c, num_bytes));
- if (copy.get() == NULL) {
- return NULL;
+ SirtRef<mirror::Object> sirt_this(self, this);
+ Object* copy = heap->AllocObject(self, c, num_bytes);
+ if (UNLIKELY(copy == nullptr)) {
+ return nullptr;
}
-
// Copy instance data. We assume memcpy copies by words.
// TODO: expose and use move32.
- byte* src_bytes = reinterpret_cast<byte*>(this);
- byte* dst_bytes = reinterpret_cast<byte*>(copy.get());
+ byte* src_bytes = reinterpret_cast<byte*>(sirt_this.get());
+ byte* dst_bytes = reinterpret_cast<byte*>(copy);
size_t offset = sizeof(Object);
memcpy(dst_bytes + offset, src_bytes + offset, num_bytes - offset);
-
// Perform write barriers on copied object references.
+ c = copy->GetClass(); // Re-read Class in case it moved.
if (c->IsArrayClass()) {
if (!c->GetComponentType()->IsPrimitive()) {
const ObjectArray<Object>* array = copy->AsObjectArray<Object>();
- heap->WriteBarrierArray(copy.get(), 0, array->GetLength());
+ heap->WriteBarrierArray(copy, 0, array->GetLength());
}
} else {
- for (const Class* klass = c; klass != NULL; klass = klass->GetSuperClass()) {
- size_t num_reference_fields = klass->NumReferenceInstanceFields();
- for (size_t i = 0; i < num_reference_fields; ++i) {
- ArtField* field = klass->GetInstanceField(i);
- MemberOffset field_offset = field->GetOffset();
- const Object* ref = copy->GetFieldObject<const Object*>(field_offset, false);
- heap->WriteBarrierField(copy.get(), field_offset, ref);
- }
- }
+ heap->WriteBarrierEveryFieldOf(copy);
}
-
if (c->IsFinalizable()) {
- heap->AddFinalizerReference(Thread::Current(), copy.get());
+ SirtRef<mirror::Object> sirt_copy(self, copy);
+ heap->AddFinalizerReference(self, copy);
+ return sirt_copy.get();
}
-
- return copy.get();
+ return copy;
}
int32_t Object::GenerateIdentityHashCode() {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 34cf45b..53c9b2e 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -102,8 +102,7 @@
use_compile_time_class_path_(false),
main_thread_group_(NULL),
system_thread_group_(NULL),
- system_class_loader_(NULL),
- quick_alloc_entry_points_instrumentation_counter_(0) {
+ system_class_loader_(NULL) {
for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
callee_save_methods_[i] = NULL;
}
@@ -1077,9 +1076,9 @@
GetStats()->Clear(~0);
// TODO: wouldn't it make more sense to clear _all_ threads' stats?
Thread::Current()->GetStats()->Clear(~0);
- InstrumentQuickAllocEntryPoints();
+ GetInstrumentation()->InstrumentQuickAllocEntryPoints();
} else {
- UninstrumentQuickAllocEntryPoints();
+ GetInstrumentation()->UninstrumentQuickAllocEntryPoints();
}
stats_enabled_ = new_state;
}
@@ -1336,46 +1335,4 @@
compile_time_class_paths_.Put(class_loader, class_path);
}
-static void ResetQuickAllocEntryPointsForThread(Thread* thread, void* arg) {
- thread->ResetQuickAllocEntryPointsForThread();
-}
-
-void SetQuickAllocEntryPointsInstrumented(bool instrumented);
-
-void Runtime::InstrumentQuickAllocEntryPoints() {
- ThreadList* tl = thread_list_;
- Thread* self = Thread::Current();
- tl->SuspendAll();
- {
- MutexLock mu(self, *Locks::runtime_shutdown_lock_);
- MutexLock mu2(self, *Locks::thread_list_lock_);
- DCHECK_GE(quick_alloc_entry_points_instrumentation_counter_, 0);
- int old_counter = quick_alloc_entry_points_instrumentation_counter_++;
- if (old_counter == 0) {
- // If it was disabled, enable it.
- SetQuickAllocEntryPointsInstrumented(true);
- tl->ForEach(ResetQuickAllocEntryPointsForThread, NULL);
- }
- }
- tl->ResumeAll();
-}
-
-void Runtime::UninstrumentQuickAllocEntryPoints() {
- ThreadList* tl = thread_list_;
- Thread* self = Thread::Current();
- tl->SuspendAll();
- {
- MutexLock mu(self, *Locks::runtime_shutdown_lock_);
- MutexLock mu2(self, *Locks::thread_list_lock_);
- DCHECK_GT(quick_alloc_entry_points_instrumentation_counter_, 0);
- int new_counter = --quick_alloc_entry_points_instrumentation_counter_;
- if (new_counter == 0) {
- // Disable it if the counter becomes zero.
- SetQuickAllocEntryPointsInstrumented(false);
- tl->ForEach(ResetQuickAllocEntryPointsForThread, NULL);
- }
- }
- tl->ResumeAll();
-}
-
} // namespace art
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 0ce2642..24b4c87 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -442,9 +442,6 @@
const std::vector<const DexFile*>& GetCompileTimeClassPath(jobject class_loader);
void SetCompileTimeClassPath(jobject class_loader, std::vector<const DexFile*>& class_path);
- void InstrumentQuickAllocEntryPoints();
- void UninstrumentQuickAllocEntryPoints();
-
private:
static void InitPlatformSignalHandlers();
@@ -567,8 +564,6 @@
// As returned by ClassLoader.getSystemClassLoader().
jobject system_class_loader_;
- int quick_alloc_entry_points_instrumentation_counter_;
-
DISALLOW_COPY_AND_ASSIGN(Runtime);
};