diff options
| -rw-r--r-- | Android.mk | 18 | ||||
| -rw-r--r-- | build/Android.oat.mk | 2 | ||||
| -rw-r--r-- | compiler/dex/quick/gen_invoke.cc | 159 | ||||
| -rw-r--r-- | oatdump/oatdump.cc | 19 | ||||
| -rw-r--r-- | runtime/arch/arm/quick_entrypoints_arm.S | 35 | ||||
| -rw-r--r-- | runtime/arch/mips/quick_entrypoints_mips.S | 34 | ||||
| -rw-r--r-- | runtime/arch/x86/quick_entrypoints_x86.S | 53 | ||||
| -rw-r--r-- | runtime/debugger.cc | 4 | ||||
| -rw-r--r-- | runtime/gc/heap.cc | 2 | ||||
| -rw-r--r-- | runtime/gc/heap.h | 4 | ||||
| -rw-r--r-- | runtime/indenter.h | 27 | ||||
| -rw-r--r-- | runtime/instrumentation.cc | 52 | ||||
| -rw-r--r-- | runtime/instrumentation.h | 13 | ||||
| -rw-r--r-- | runtime/mirror/object.cc | 37 | ||||
| -rw-r--r-- | runtime/runtime.cc | 49 | ||||
| -rw-r--r-- | runtime/runtime.h | 5 |
16 files changed, 331 insertions, 182 deletions
diff --git a/Android.mk b/Android.mk index 3112ab0288..8024a3d357 100644 --- a/Android.mk +++ b/Android.mk @@ -305,6 +305,8 @@ build-art-target: $(ART_TARGET_EXECUTABLES) $(ART_TARGET_TEST_EXECUTABLES) $(TAR ######################################################################## # oatdump targets +ART_DUMP_OAT_PATH ?= $(OUT_DIR) + .PHONY: dump-oat dump-oat: dump-oat-core dump-oat-boot @@ -314,29 +316,29 @@ dump-oat-core: dump-oat-core-host dump-oat-core-target .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 5d355a6d86..e505a86ee1 100644 --- a/build/Android.oat.mk +++ b/build/Android.oat.mk @@ -26,7 +26,7 @@ LIBART_COMPILER := $(LIBARTD_COMPILER) # 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/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 7225262647..d1a9a132bc 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -1245,84 +1245,87 @@ bool Mir2Lir::GenIntrinsic(CallInfo* info) { 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/oatdump/oatdump.cc b/oatdump/oatdump.cc index b9716d556f..90276c2678 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -715,14 +715,25 @@ class ImageDumper { 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 9a853d07ab..1a058ea61e 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 @@ ENTRY art_quick_invoke_stub 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 @@ throw_class_cast_exception: 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 @@ ENTRY art_quick_set64_static .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 @@ art_quick_instrumentation_exit: 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 @@ ENTRY art_quick_mul_long 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 451b1bb30f..886271166c 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 @@ ENTRY art_quick_invoke_stub 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 6fe499374a..ee78d45793 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 @@ END_MACRO */ 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 @@ END_MACRO 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 @@ END_MACRO */ 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 @@ MACRO2(INVOKE_TRAMPOLINE, c_name, cxx_name) // 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 @@ MACRO2(INVOKE_TRAMPOLINE, c_name, cxx_name) 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 @@ INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvo */ 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 @@ DEFINE_FUNCTION art_quick_invoke_stub 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 @@ END_FUNCTION art_quick_is_assignable 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 @@ DEFINE_FUNCTION art_quick_check_cast 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 bdcf6ac6ab..0eecd28831 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -3489,9 +3489,9 @@ void Dbg::SetAllocTrackingEnabled(bool enabled) { 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/gc/heap.cc b/runtime/gc/heap.cc index 804c66932e..de3ab0eb9d 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -237,7 +237,7 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max 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 7d2441baa1..91909e4f07 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -300,6 +300,10 @@ class Heap { 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 c432e1ba8d..d055d4e3f4 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 @@ class Indenter : public std::streambuf { 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 8cf486f54d..0f4fa4e577 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 @@ void Instrumentation::ConfigureStubs(bool require_entry_exit_stubs, bool require } } +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 7a0aaf7858..25a4eec976 100644 --- a/runtime/instrumentation.h +++ b/runtime/instrumentation.h @@ -104,7 +104,8 @@ class Instrumentation { 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 @@ class Instrumentation { 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 @@ class Instrumentation { 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 bd187c1835..87d02c9469 100644 --- a/runtime/mirror/object.cc +++ b/runtime/mirror/object.cc @@ -40,48 +40,39 @@ namespace art { 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 34cf45b4c7..53c9b2efbb 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -102,8 +102,7 @@ Runtime::Runtime() 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 @@ void Runtime::SetStatsEnabled(bool new_state) { 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 @@ void Runtime::SetCompileTimeClassPath(jobject class_loader, std::vector<const De 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 0ce2642c98..24b4c87666 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -442,9 +442,6 @@ class Runtime { 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 @@ class Runtime { // As returned by ClassLoader.getSystemClassLoader(). jobject system_class_loader_; - int quick_alloc_entry_points_instrumentation_counter_; - DISALLOW_COPY_AND_ASSIGN(Runtime); }; |