diff options
37 files changed, 721 insertions, 163 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index cd463ecc7c..3b459c3ad1 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -650,11 +650,11 @@ endef # define-art-gtest ifeq ($(ART_BUILD_TARGET),true) $(foreach file,$(RUNTIME_GTEST_TARGET_SRC_FILES), $(eval $(call define-art-gtest,target,$(file),,libbacktrace))) - $(foreach file,$(COMPILER_GTEST_TARGET_SRC_FILES), $(eval $(call define-art-gtest,target,$(file),art/compiler,libartd-compiler libbacktrace))) + $(foreach file,$(COMPILER_GTEST_TARGET_SRC_FILES), $(eval $(call define-art-gtest,target,$(file),art/compiler,libartd-compiler libbacktrace libnativeloader))) endif ifeq ($(ART_BUILD_HOST),true) $(foreach file,$(RUNTIME_GTEST_HOST_SRC_FILES), $(eval $(call define-art-gtest,host,$(file),,libbacktrace))) - $(foreach file,$(COMPILER_GTEST_HOST_SRC_FILES), $(eval $(call define-art-gtest,host,$(file),art/compiler,libartd-compiler libbacktrace))) + $(foreach file,$(COMPILER_GTEST_HOST_SRC_FILES), $(eval $(call define-art-gtest,host,$(file),art/compiler,libartd-compiler libbacktrace libnativeloader))) endif # Used outside the art project to get a list of the current tests diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc index 5b7574a36c..251dc39864 100644 --- a/compiler/jni/jni_compiler_test.cc +++ b/compiler/jni/jni_compiler_test.cc @@ -31,6 +31,7 @@ #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" #include "mirror/stack_trace_element.h" +#include "nativeloader/native_loader.h" #include "runtime.h" #include "ScopedLocalRef.h" #include "scoped_thread_state_change.h" @@ -53,6 +54,11 @@ class JniCompilerTest : public CommonCompilerTest { check_generic_jni_ = false; } + void TearDown() OVERRIDE { + android::ResetNativeLoader(); + CommonCompilerTest::TearDown(); + } + void SetCheckGenericJni(bool generic) { check_generic_jni_ = generic; } @@ -93,10 +99,12 @@ class JniCompilerTest : public CommonCompilerTest { // Start runtime. Thread::Current()->TransitionFromSuspendedToRunnable(); bool started = runtime_->Start(); + android::InitializeNativeLoader(); CHECK(started); } // JNI operations after runtime start. env_ = Thread::Current()->GetJniEnv(); + library_search_path_ = env_->NewStringUTF(""); jklass_ = env_->FindClass("MyClassNatives"); ASSERT_TRUE(jklass_ != nullptr) << method_name << " " << method_sig; @@ -168,6 +176,7 @@ class JniCompilerTest : public CommonCompilerTest { void StackArgsSignExtendedMips64Impl(); JNIEnv* env_; + jstring library_search_path_; jmethodID jmethod_; bool check_generic_jni_; }; @@ -220,15 +229,14 @@ void JniCompilerTest::CompileAndRunIntMethodThroughStubImpl() { std::string reason; ASSERT_TRUE(Runtime::Current()->GetJavaVM()-> - LoadNativeLibrary(env_, "", class_loader_, nullptr, &reason)) + LoadNativeLibrary(env_, "", class_loader_, library_search_path_, &reason)) << reason; jint result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 24); EXPECT_EQ(25, result); } -// Disabled due to NativeLoader b/28449304. -// JNI_TEST(CompileAndRunIntMethodThroughStub) +JNI_TEST(CompileAndRunIntMethodThroughStub) void JniCompilerTest::CompileAndRunStaticIntMethodThroughStubImpl() { SetUpForTest(true, "sbar", "(I)I", nullptr); @@ -236,15 +244,14 @@ void JniCompilerTest::CompileAndRunStaticIntMethodThroughStubImpl() { std::string reason; ASSERT_TRUE(Runtime::Current()->GetJavaVM()-> - LoadNativeLibrary(env_, "", class_loader_, nullptr, &reason)) + LoadNativeLibrary(env_, "", class_loader_, library_search_path_, &reason)) << reason; jint result = env_->CallStaticIntMethod(jklass_, jmethod_, 42); EXPECT_EQ(43, result); } -// Disabled due to NativeLoader b/28449304. -// JNI_TEST(CompileAndRunStaticIntMethodThroughStub) +JNI_TEST(CompileAndRunStaticIntMethodThroughStub) int gJava_MyClassNatives_fooI_calls = 0; jint Java_MyClassNatives_fooI(JNIEnv* env, jobject thisObj, jint x) { diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc index b65e98a120..6c6e5af0b2 100644 --- a/compiler/optimizing/bounds_check_elimination.cc +++ b/compiler/optimizing/bounds_check_elimination.cc @@ -800,6 +800,27 @@ class BCEVisitor : public HGraphVisitor { ValueRange(GetGraph()->GetArena(), ValueBound::Min(), new_upper); ApplyRangeFromComparison(left, block, false_successor, new_range); } + } else if (cond == kCondNE || cond == kCondEQ) { + if (left->IsArrayLength() && lower.IsConstant() && upper.IsConstant()) { + // Special case: + // length == [c,d] yields [c, d] along true + // length != [c,d] yields [c, d] along false + if (!lower.Equals(ValueBound::Min()) || !upper.Equals(ValueBound::Max())) { + ValueRange* new_range = new (GetGraph()->GetArena()) + ValueRange(GetGraph()->GetArena(), lower, upper); + ApplyRangeFromComparison( + left, block, cond == kCondEQ ? true_successor : false_successor, new_range); + } + // In addition: + // length == 0 yields [1, max] along false + // length != 0 yields [1, max] along true + if (lower.GetConstant() == 0 && upper.GetConstant() == 0) { + ValueRange* new_range = new (GetGraph()->GetArena()) + ValueRange(GetGraph()->GetArena(), ValueBound(nullptr, 1), ValueBound::Max()); + ApplyRangeFromComparison( + left, block, cond == kCondEQ ? false_successor : true_successor, new_range); + } + } } } @@ -955,13 +976,7 @@ class BCEVisitor : public HGraphVisitor { void VisitIf(HIf* instruction) OVERRIDE { if (instruction->InputAt(0)->IsCondition()) { HCondition* cond = instruction->InputAt(0)->AsCondition(); - IfCondition cmp = cond->GetCondition(); - if (cmp == kCondGT || cmp == kCondGE || - cmp == kCondLT || cmp == kCondLE) { - HInstruction* left = cond->GetLeft(); - HInstruction* right = cond->GetRight(); - HandleIf(instruction, left, right, cmp); - } + HandleIf(instruction, cond->GetLeft(), cond->GetRight(), cond->GetCondition()); } } diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h index 863dd1c6f6..39a1313ba0 100644 --- a/compiler/optimizing/intrinsics.h +++ b/compiler/optimizing/intrinsics.h @@ -30,6 +30,10 @@ class DexFile; // Temporary measure until we have caught up with the Java 7 definition of Math.round. b/26327751 static constexpr bool kRoundIsPlusPointFive = false; +// Positive floating-point infinities. +static constexpr uint32_t kPositiveInfinityFloat = 0x7f800000U; +static constexpr uint64_t kPositiveInfinityDouble = UINT64_C(0x7ff0000000000000); + // Recognize intrinsics from HInvoke nodes. class IntrinsicsRecognizer : public HOptimization { public: diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc index 86b7bc138c..146fea1fe0 100644 --- a/compiler/optimizing/intrinsics_arm.cc +++ b/compiler/optimizing/intrinsics_arm.cc @@ -1985,6 +1985,56 @@ void IntrinsicCodeGeneratorARM::VisitStringGetCharsNoCheck(HInvoke* invoke) { __ Bind(&done); } +void IntrinsicLocationsBuilderARM::VisitFloatIsInfinite(HInvoke* invoke) { + CreateFPToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM::VisitFloatIsInfinite(HInvoke* invoke) { + ArmAssembler* const assembler = GetAssembler(); + LocationSummary* const locations = invoke->GetLocations(); + const Register out = locations->Out().AsRegister<Register>(); + // Shifting left by 1 bit makes the value encodable as an immediate operand; + // we don't care about the sign bit anyway. + constexpr uint32_t infinity = kPositiveInfinityFloat << 1U; + + __ vmovrs(out, locations->InAt(0).AsFpuRegister<SRegister>()); + // We don't care about the sign bit, so shift left. + __ Lsl(out, out, 1); + __ eor(out, out, ShifterOperand(infinity)); + // If the result is 0, then it has 32 leading zeros, and less than that otherwise. + __ clz(out, out); + // Any number less than 32 logically shifted right by 5 bits results in 0; + // the same operation on 32 yields 1. + __ Lsr(out, out, 5); +} + +void IntrinsicLocationsBuilderARM::VisitDoubleIsInfinite(HInvoke* invoke) { + CreateFPToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM::VisitDoubleIsInfinite(HInvoke* invoke) { + ArmAssembler* const assembler = GetAssembler(); + LocationSummary* const locations = invoke->GetLocations(); + const Register out = locations->Out().AsRegister<Register>(); + // The highest 32 bits of double precision positive infinity separated into + // two constants encodable as immediate operands. + constexpr uint32_t infinity_high = 0x7f000000U; + constexpr uint32_t infinity_high2 = 0x00f00000U; + + static_assert((infinity_high | infinity_high2) == static_cast<uint32_t>(kPositiveInfinityDouble >> 32U), + "The constants do not add up to the high 32 bits of double precision positive infinity."); + __ vmovrrd(IP, out, FromLowSToD(locations->InAt(0).AsFpuRegisterPairLow<SRegister>())); + __ eor(out, out, ShifterOperand(infinity_high)); + __ eor(out, out, ShifterOperand(infinity_high2)); + // We don't care about the sign bit, so shift left. + __ orr(out, IP, ShifterOperand(out, LSL, 1)); + // If the result is 0, then it has 32 leading zeros, and less than that otherwise. + __ clz(out, out); + // Any number less than 32 logically shifted right by 5 bits results in 0; + // the same operation on 32 yields 1. + __ Lsr(out, out, 5); +} + UNIMPLEMENTED_INTRINSIC(ARM, IntegerBitCount) UNIMPLEMENTED_INTRINSIC(ARM, LongBitCount) UNIMPLEMENTED_INTRINSIC(ARM, MathMinDoubleDouble) @@ -2001,8 +2051,6 @@ UNIMPLEMENTED_INTRINSIC(ARM, MathRoundFloat) // Could be done by changing rou UNIMPLEMENTED_INTRINSIC(ARM, UnsafeCASLong) // High register pressure. UNIMPLEMENTED_INTRINSIC(ARM, SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(ARM, ReferenceGetReferent) -UNIMPLEMENTED_INTRINSIC(ARM, FloatIsInfinite) -UNIMPLEMENTED_INTRINSIC(ARM, DoubleIsInfinite) UNIMPLEMENTED_INTRINSIC(ARM, IntegerHighestOneBit) UNIMPLEMENTED_INTRINSIC(ARM, LongHighestOneBit) UNIMPLEMENTED_INTRINSIC(ARM, IntegerLowestOneBit) diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 04ae3a6732..1d8229674c 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -47,6 +47,7 @@ using helpers::SRegisterFrom; using helpers::WRegisterFrom; using helpers::XRegisterFrom; using helpers::InputRegisterAt; +using helpers::OutputRegister; namespace { @@ -1173,31 +1174,118 @@ void IntrinsicCodeGeneratorARM64::VisitStringCharAt(HInvoke* invoke) { void IntrinsicLocationsBuilderARM64::VisitStringCompareTo(HInvoke* invoke) { LocationSummary* locations = new (arena_) LocationSummary(invoke, - LocationSummary::kCall, + invoke->InputAt(1)->CanBeNull() + ? LocationSummary::kCallOnSlowPath + : LocationSummary::kNoCall, kIntrinsified); - InvokeRuntimeCallingConvention calling_convention; - locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0))); - locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1))); - locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimInt)); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); } void IntrinsicCodeGeneratorARM64::VisitStringCompareTo(HInvoke* invoke) { vixl::MacroAssembler* masm = GetVIXLAssembler(); LocationSummary* locations = invoke->GetLocations(); + Register str = XRegisterFrom(locations->InAt(0)); + Register arg = XRegisterFrom(locations->InAt(1)); + Register out = OutputRegister(invoke); + + Register temp0 = WRegisterFrom(locations->GetTemp(0)); + Register temp1 = WRegisterFrom(locations->GetTemp(1)); + Register temp2 = WRegisterFrom(locations->GetTemp(2)); + + vixl::Label loop; + vixl::Label find_char_diff; + vixl::Label end; + + // Get offsets of count and value fields within a string object. + const int32_t count_offset = mirror::String::CountOffset().Int32Value(); + const int32_t value_offset = mirror::String::ValueOffset().Int32Value(); + // Note that the null check must have been done earlier. DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); - Register argument = WRegisterFrom(locations->InAt(1)); - __ Cmp(argument, 0); - SlowPathCodeARM64* slow_path = new (GetAllocator()) IntrinsicSlowPathARM64(invoke); - codegen_->AddSlowPath(slow_path); - __ B(eq, slow_path->GetEntryLabel()); + // Take slow path and throw if input can be and is null. + SlowPathCodeARM64* slow_path = nullptr; + const bool can_slow_path = invoke->InputAt(1)->CanBeNull(); + if (can_slow_path) { + slow_path = new (GetAllocator()) IntrinsicSlowPathARM64(invoke); + codegen_->AddSlowPath(slow_path); + __ Cbz(arg, slow_path->GetEntryLabel()); + } - __ Ldr( - lr, MemOperand(tr, QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pStringCompareTo).Int32Value())); - __ Blr(lr); - __ Bind(slow_path->GetExitLabel()); + // Reference equality check, return 0 if same reference. + __ Subs(out, str, arg); + __ B(&end, eq); + // Load lengths of this and argument strings. + __ Ldr(temp0, MemOperand(str.X(), count_offset)); + __ Ldr(temp1, MemOperand(arg.X(), count_offset)); + // Return zero if both strings are empty. + __ Orr(out, temp0, temp1); + __ Cbz(out, &end); + // out = length diff. + __ Subs(out, temp0, temp1); + // temp2 = min(len(str), len(arg)). + __ Csel(temp2, temp1, temp0, ge); + // Shorter string is empty? + __ Cbz(temp2, &end); + + // Store offset of string value in preparation for comparison loop. + __ Mov(temp1, value_offset); + + UseScratchRegisterScope scratch_scope(masm); + Register temp4 = scratch_scope.AcquireX(); + + // Assertions that must hold in order to compare strings 4 characters at a time. + DCHECK_ALIGNED(value_offset, 8); + static_assert(IsAligned<8>(kObjectAlignment), "String of odd length is not zero padded"); + + const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar); + DCHECK_EQ(char_size, 2u); + + // Promote temp0 to an X reg, ready for LDR. + temp0 = temp0.X(); + + // Loop to compare 4x16-bit characters at a time (ok because of string data alignment). + __ Bind(&loop); + __ Ldr(temp4, MemOperand(str.X(), temp1)); + __ Ldr(temp0, MemOperand(arg.X(), temp1)); + __ Cmp(temp4, temp0); + __ B(ne, &find_char_diff); + __ Add(temp1, temp1, char_size * 4); + __ Subs(temp2, temp2, 4); + __ B(gt, &loop); + __ B(&end); + + // Promote temp1 to an X reg, ready for EOR. + temp1 = temp1.X(); + + // Find the single 16-bit character difference. + __ Bind(&find_char_diff); + // Get the bit position of the first character that differs. + __ Eor(temp1, temp0, temp4); + __ Rbit(temp1, temp1); + __ Clz(temp1, temp1); + __ Bic(temp1, temp1, 0xf); + // If the number of 16-bit chars remaining <= the index where the difference occurs (0-3), then + // the difference occurs outside the remaining string data, so just return length diff (out). + __ Cmp(temp2, Operand(temp1, LSR, 4)); + __ B(le, &end); + // Extract the characters and calculate the difference. + __ Lsr(temp0, temp0, temp1); + __ Lsr(temp4, temp4, temp1); + __ And(temp4, temp4, 0xffff); + __ Sub(out, temp4, Operand(temp0, UXTH)); + + __ Bind(&end); + + if (can_slow_path) { + __ Bind(slow_path->GetExitLabel()); + } } void IntrinsicLocationsBuilderARM64::VisitStringEquals(HInvoke* invoke) { @@ -2201,9 +2289,46 @@ void IntrinsicCodeGeneratorARM64::VisitSystemArrayCopy(HInvoke* invoke) { __ Bind(slow_path->GetExitLabel()); } +static void GenIsInfinite(LocationSummary* locations, + bool is64bit, + vixl::MacroAssembler* masm) { + Operand infinity; + Register out; + + if (is64bit) { + infinity = kPositiveInfinityDouble; + out = XRegisterFrom(locations->Out()); + } else { + infinity = kPositiveInfinityFloat; + out = WRegisterFrom(locations->Out()); + } + + const Register zero = vixl::Assembler::AppropriateZeroRegFor(out); + + MoveFPToInt(locations, is64bit, masm); + __ Eor(out, out, infinity); + // We don't care about the sign bit, so shift left. + __ Cmp(zero, Operand(out, LSL, 1)); + __ Cset(out, eq); +} + +void IntrinsicLocationsBuilderARM64::VisitFloatIsInfinite(HInvoke* invoke) { + CreateFPToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitFloatIsInfinite(HInvoke* invoke) { + GenIsInfinite(invoke->GetLocations(), /* is64bit */ false, GetVIXLAssembler()); +} + +void IntrinsicLocationsBuilderARM64::VisitDoubleIsInfinite(HInvoke* invoke) { + CreateFPToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitDoubleIsInfinite(HInvoke* invoke) { + GenIsInfinite(invoke->GetLocations(), /* is64bit */ true, GetVIXLAssembler()); +} + UNIMPLEMENTED_INTRINSIC(ARM64, ReferenceGetReferent) -UNIMPLEMENTED_INTRINSIC(ARM64, FloatIsInfinite) -UNIMPLEMENTED_INTRINSIC(ARM64, DoubleIsInfinite) UNIMPLEMENTED_INTRINSIC(ARM64, IntegerHighestOneBit) UNIMPLEMENTED_INTRINSIC(ARM64, LongHighestOneBit) UNIMPLEMENTED_INTRINSIC(ARM64, IntegerLowestOneBit) diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc index 19c6a225ac..46195c104a 100644 --- a/compiler/optimizing/intrinsics_mips.cc +++ b/compiler/optimizing/intrinsics_mips.cc @@ -2283,10 +2283,10 @@ static void GenIsInfinite(LocationSummary* locations, // If one, or more, of the exponent bits is zero, then the number can't be infinite. if (type == Primitive::kPrimDouble) { __ MoveFromFpuHigh(TMP, in); - __ LoadConst32(AT, 0x7FF00000); + __ LoadConst32(AT, High32Bits(kPositiveInfinityDouble)); } else { __ Mfc1(TMP, in); - __ LoadConst32(AT, 0x7F800000); + __ LoadConst32(AT, kPositiveInfinityFloat); } __ Xor(TMP, TMP, AT); diff --git a/compiler/optimizing/ssa_phi_elimination.cc b/compiler/optimizing/ssa_phi_elimination.cc index aeb31094d4..0978ae17f8 100644 --- a/compiler/optimizing/ssa_phi_elimination.cc +++ b/compiler/optimizing/ssa_phi_elimination.cc @@ -139,8 +139,9 @@ void SsaRedundantPhiElimination::Run() { continue; } - if (phi->InputCount() == 0) { - DCHECK(phi->IsDead()); + // If the phi is dead, we know we won't revive it and it will be removed, + // so don't process it. + if (phi->IsDead()) { continue; } diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 6ecfc74e8c..d2ab699599 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -59,6 +59,7 @@ #include "stack_map.h" #include "ScopedLocalRef.h" #include "thread_list.h" +#include "type_lookup_table.h" #include "verifier/method_verifier.h" #include "well_known_classes.h" @@ -573,8 +574,15 @@ class OatDumper { os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str()); os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum()); - // Create the verifier early. + // Print embedded dex file data range. + const uint8_t* const oat_file_begin = oat_dex_file.GetOatFile()->Begin(); + const uint8_t* const dex_file_pointer = oat_dex_file.GetDexFilePointer(); + uint32_t dex_offset = dchecked_integral_cast<uint32_t>(dex_file_pointer - oat_file_begin); + os << StringPrintf("dex-file: 0x%08x..0x%08x\n", + dex_offset, + dchecked_integral_cast<uint32_t>(dex_offset + oat_dex_file.FileSize() - 1)); + // Create the dex file early. A lot of print-out things depend on it. std::string error_msg; const DexFile* const dex_file = OpenDexFile(&oat_dex_file, &error_msg); if (dex_file == nullptr) { @@ -583,6 +591,16 @@ class OatDumper { return false; } + // Print lookup table, if it exists. + if (oat_dex_file.GetLookupTableData() != nullptr) { + uint32_t table_offset = dchecked_integral_cast<uint32_t>( + oat_dex_file.GetLookupTableData() - oat_file_begin); + uint32_t table_size = TypeLookupTable::RawDataLength(*dex_file); + os << StringPrintf("type-table: 0x%08x..0x%08x\n", + table_offset, + table_offset + table_size - 1); + } + VariableIndentationOutputStream vios(&os); ScopedIndentation indent1(&vios); for (size_t class_def_index = 0; diff --git a/runtime/arch/arm64/entrypoints_init_arm64.cc b/runtime/arch/arm64/entrypoints_init_arm64.cc index 1618cedef7..bf0f6470d1 100644 --- a/runtime/arch/arm64/entrypoints_init_arm64.cc +++ b/runtime/arch/arm64/entrypoints_init_arm64.cc @@ -80,7 +80,8 @@ void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) { // Intrinsics qpoints->pIndexOf = art_quick_indexof; - qpoints->pStringCompareTo = art_quick_string_compareto; + // The ARM64 StringCompareTo intrinsic does not call the runtime. + qpoints->pStringCompareTo = nullptr; qpoints->pMemcpy = memcpy; // Read barrier. diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S index 7774106da4..1fba09bae3 100644 --- a/runtime/arch/arm64/quick_entrypoints_arm64.S +++ b/runtime/arch/arm64/quick_entrypoints_arm64.S @@ -2203,108 +2203,3 @@ ENTRY art_quick_indexof asr x0, x0, #1 ret END art_quick_indexof - - /* - * String's compareTo. - * - * TODO: Not very optimized. - * - * On entry: - * x0: this object pointer - * x1: comp object pointer - * - */ - .extern __memcmp16 -ENTRY art_quick_string_compareto - mov x2, x0 // x0 is return, use x2 for first input. - sub x0, x2, x1 // Same string object? - cbnz x0,1f - ret -1: // Different string objects. - - ldr w4, [x2, #MIRROR_STRING_COUNT_OFFSET] - ldr w3, [x1, #MIRROR_STRING_COUNT_OFFSET] - add x2, x2, #MIRROR_STRING_VALUE_OFFSET - add x1, x1, #MIRROR_STRING_VALUE_OFFSET - - /* - * Now: Data* Count - * first arg x2 w4 - * second arg x1 w3 - */ - - // x0 := str1.length(w4) - str2.length(w3). ldr zero-extended w3/w4 into x3/x4. - subs x0, x4, x3 - // Min(count1, count2) into w3. - csel x3, x3, x4, ge - - // TODO: Tune this value. - // Check for long string, do memcmp16 for them. - cmp w3, #28 // Constant from arm32. - bgt .Ldo_memcmp16 - - /* - * Now: - * x2: *first string data - * x1: *second string data - * w3: iteration count - * x0: return value if comparison equal - * x4, x5, x6, x7: free - */ - - // Do a simple unrolled loop. -.Lloop: - // At least two more elements? - subs w3, w3, #2 - b.lt .Lremainder_or_done - - ldrh w4, [x2], #2 - ldrh w5, [x1], #2 - - ldrh w6, [x2], #2 - ldrh w7, [x1], #2 - - subs w4, w4, w5 - b.ne .Lw4_result - - subs w6, w6, w7 - b.ne .Lw6_result - - b .Lloop - -.Lremainder_or_done: - adds w3, w3, #1 - b.eq .Lremainder - ret - -.Lremainder: - ldrh w4, [x2], #2 - ldrh w5, [x1], #2 - subs w4, w4, w5 - b.ne .Lw4_result - ret - -// Result is in w4 -.Lw4_result: - sxtw x0, w4 - ret - -// Result is in w6 -.Lw6_result: - sxtw x0, w6 - ret - -.Ldo_memcmp16: - mov x14, x0 // Save x0 and LR. __memcmp16 does not use these temps. - mov x15, xLR // TODO: Codify and check that? - - mov x0, x2 - uxtw x2, w3 - bl __memcmp16 - - mov xLR, x15 // Restore LR. - - cmp x0, #0 // Check the memcmp difference. - csel x0, x0, x14, ne // x0 := x0 != 0 ? x14(prev x0=length diff) : x1. - ret -END art_quick_string_compareto diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc index 3cdff55677..02629e8196 100644 --- a/runtime/arch/stub_test.cc +++ b/runtime/arch/stub_test.cc @@ -1205,7 +1205,8 @@ TEST_F(StubTest, AllocObjectArray) { TEST_F(StubTest, StringCompareTo) { -#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || \ + // There is no StringCompareTo runtime entrypoint for __aarch64__. +#if defined(__i386__) || defined(__arm__) || \ defined(__mips__) || (defined(__x86_64__) && !defined(__APPLE__)) // TODO: Check the "Unresolved" allocation stubs diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index 6449efad78..7647ad6e57 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -456,13 +456,18 @@ void ArtMethod::VisitRoots(RootVisitorType& visitor, size_t pointer_size) { interface_method->VisitRoots(visitor, pointer_size); } visitor.VisitRoot(declaring_class_.AddressWithoutBarrier()); - // Runtime methods and native methods use the same field as the profiling info for - // storing their own data (jni entrypoint for native methods, and ImtConflictTable for - // some runtime methods). - if (!IsNative() && !IsRuntimeMethod()) { - ProfilingInfo* profiling_info = GetProfilingInfo(pointer_size); - if (profiling_info != nullptr) { - profiling_info->VisitRoots(visitor); + // We know we don't have profiling information if the class hasn't been verified. Note + // that this check also ensures the IsNative call can be made, as IsNative expects a fully + // created class (and not a retired one). + if (klass->IsVerified()) { + // Runtime methods and native methods use the same field as the profiling info for + // storing their own data (jni entrypoint for native methods, and ImtConflictTable for + // some runtime methods). + if (!IsNative() && !IsRuntimeMethod()) { + ProfilingInfo* profiling_info = GetProfilingInfo(pointer_size); + if (profiling_info != nullptr) { + profiling_info->VisitRoots(visitor); + } } } } diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index a147aba62f..35c40cd219 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -6635,6 +6635,17 @@ bool ClassLinker::LinkInterfaceMethods( // The method is not overridable by a default method (i.e. it is directly implemented // in some class). Therefore move onto the next interface method. continue; + } else { + // If the super-classes method is override-able by a default method we need to keep + // track of it since though it is override-able it is not guaranteed to be 'overridden'. + // If it turns out not to be overridden and we did not keep track of it we might add it + // to the vtable twice, causing corruption (vtable entries having inconsistent and + // illegal states, incorrect vtable size, and incorrect or inconsistent iftable entries) + // in this class and any subclasses. + DCHECK(vtable_impl == nullptr || vtable_impl == supers_method) + << "vtable_impl was " << PrettyMethod(vtable_impl) << " and not 'nullptr' or " + << PrettyMethod(supers_method) << " as expected. IFTable appears to be corrupt!"; + vtable_impl = supers_method; } } // If we haven't found it yet we should search through the interfaces for default methods. diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc index eebcc689c9..3de718b397 100644 --- a/runtime/java_vm_ext.cc +++ b/runtime/java_vm_ext.cc @@ -321,6 +321,7 @@ class JII { } JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm); delete raw_vm->GetRuntime(); + android::ResetNativeLoader(); return JNI_OK; } diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index 6b7ca40bee..0624da38c8 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -238,12 +238,13 @@ static mirror::Field* GetPublicFieldRecursive( DCHECK(name != nullptr); DCHECK(self != nullptr); - StackHandleScope<1> hs(self); + StackHandleScope<2> hs(self); MutableHandle<mirror::Class> h_clazz(hs.NewHandle(clazz)); + Handle<mirror::String> h_name(hs.NewHandle(name)); // We search the current class, its direct interfaces then its superclass. while (h_clazz.Get() != nullptr) { - mirror::Field* result = GetDeclaredField(self, h_clazz.Get(), name); + mirror::Field* result = GetDeclaredField(self, h_clazz.Get(), h_name.Get()); if ((result != nullptr) && (result->GetAccessFlags() & kAccPublic)) { return result; } else if (UNLIKELY(self->IsExceptionPending())) { @@ -258,7 +259,7 @@ static mirror::Field* GetPublicFieldRecursive( self->AssertPendingException(); return nullptr; } - result = GetPublicFieldRecursive(self, iface, name); + result = GetPublicFieldRecursive(self, iface, h_name.Get()); if (result != nullptr) { DCHECK(result->GetAccessFlags() & kAccPublic); return result; diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 11a9d76dad..9470624df8 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -370,6 +370,10 @@ class OatDexFile FINAL { return lookup_table_data_; } + const uint8_t* GetDexFilePointer() const { + return dex_file_pointer_; + } + ~OatDexFile(); private: diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java index 66e1d92cc2..41771b52c4 100644 --- a/test/449-checker-bce/src/Main.java +++ b/test/449-checker-bce/src/Main.java @@ -927,6 +927,32 @@ public class Main { } } + /// CHECK-START: void Main.nonzeroLength(int[]) BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.nonzeroLength(int[]) BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-NOT: Deoptimize + public static void nonzeroLength(int[] a) { + if (a.length != 0) { + a[0] = 112; + } + } + + /// CHECK-START: void Main.knownLength(int[]) BCE (before) + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.knownLength(int[]) BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-NOT: Deoptimize + public static void knownLength(int[] a) { + if (a.length == 2) { + a[0] = -1; + a[1] = -2; + } + } + static int[][] mA; /// CHECK-START: void Main.dynamicBCEAndIntrinsic(int) BCE (before) @@ -1586,6 +1612,26 @@ public class Main { } } + nonzeroLength(array); + if (array[0] != 112) { + System.out.println("nonzero length failed!"); + } + + knownLength(array); + if (array[0] != 112 || array[1] != 1) { + System.out.println("nonzero length failed!"); + } + array = new int[2]; + knownLength(array); + if (array[0] != -1 || array[1] != -2) { + System.out.println("nonzero length failed!"); + } + + // Zero length array does not break. + array = new int[0]; + nonzeroLength(array); + knownLength(array); + mA = new int[4][4]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { diff --git a/test/530-checker-loops2/src/Main.java b/test/530-checker-loops2/src/Main.java index c644692f03..b12fbd6091 100644 --- a/test/530-checker-loops2/src/Main.java +++ b/test/530-checker-loops2/src/Main.java @@ -710,8 +710,8 @@ public class Main { // making them a candidate for deoptimization based on constant indices. // Compiler should ensure the array loads are not subsequently hoisted // "above" the deoptimization "barrier" on the bounds. - a[0][i] = 1; - a[1][i] = 2; + a[1][i] = 1; + a[2][i] = 2; a[99][i] = 3; } } @@ -1042,11 +1042,11 @@ public class Main { a = new int[100][10]; expectEquals(55, dynamicBCEAndConstantIndices(x, a, 0, 10)); for (int i = 0; i < 10; i++) { - expectEquals((i % 10) != 0 ? 1 : 0, a[0][i]); - expectEquals((i % 10) != 0 ? 2 : 0, a[1][i]); + expectEquals((i % 10) != 0 ? 1 : 0, a[1][i]); + expectEquals((i % 10) != 0 ? 2 : 0, a[2][i]); expectEquals((i % 10) != 0 ? 3 : 0, a[99][i]); } - a = new int[2][10]; + a = new int[3][10]; sResult = 0; try { expectEquals(55, dynamicBCEAndConstantIndices(x, a, 0, 10)); @@ -1054,8 +1054,8 @@ public class Main { sResult = 1; } expectEquals(1, sResult); - expectEquals(a[0][1], 1); - expectEquals(a[1][1], 2); + expectEquals(a[1][1], 1); + expectEquals(a[2][1], 2); // Dynamic BCE combined with constant indices of all types. boolean[] x1 = { true }; diff --git a/test/596-app-images/app_images.cc b/test/596-app-images/app_images.cc new file mode 100644 index 0000000000..11c0f424ba --- /dev/null +++ b/test/596-app-images/app_images.cc @@ -0,0 +1,69 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <assert.h> +#include <iostream> +#include <pthread.h> +#include <stdio.h> +#include <vector> + +#include "gc/heap.h" +#include "gc/space/image_space.h" +#include "gc/space/space-inl.h" +#include "image.h" +#include "jni.h" +#include "mirror/class.h" +#include "runtime.h" +#include "scoped_thread_state_change.h" + +namespace art { + +namespace { + +extern "C" JNIEXPORT jboolean JNICALL Java_Main_checkAppImageLoaded(JNIEnv*, jclass) { + ScopedObjectAccess soa(Thread::Current()); + for (auto* space : Runtime::Current()->GetHeap()->GetContinuousSpaces()) { + if (space->IsImageSpace()) { + auto* image_space = space->AsImageSpace(); + const auto& image_header = image_space->GetImageHeader(); + if (image_header.IsAppImage()) { + return JNI_TRUE; + } + } + } + return JNI_FALSE; +} + +extern "C" JNIEXPORT jboolean JNICALL Java_Main_checkAppImageContains(JNIEnv*, jclass, jclass c) { + ScopedObjectAccess soa(Thread::Current()); + mirror::Class* klass_ptr = soa.Decode<mirror::Class*>(c); + for (auto* space : Runtime::Current()->GetHeap()->GetContinuousSpaces()) { + if (space->IsImageSpace()) { + auto* image_space = space->AsImageSpace(); + const auto& image_header = image_space->GetImageHeader(); + if (image_header.IsAppImage()) { + if (image_space->HasAddress(klass_ptr)) { + return JNI_TRUE; + } + } + } + } + return JNI_FALSE; +} + +} // namespace + +} // namespace art diff --git a/test/596-app-images/expected.txt b/test/596-app-images/expected.txt new file mode 100644 index 0000000000..6a5618ebc6 --- /dev/null +++ b/test/596-app-images/expected.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/596-app-images/info.txt b/test/596-app-images/info.txt new file mode 100644 index 0000000000..a3d5e7ea70 --- /dev/null +++ b/test/596-app-images/info.txt @@ -0,0 +1 @@ +Tests that app-images are loaded and used. diff --git a/test/596-app-images/src/Main.java b/test/596-app-images/src/Main.java new file mode 100644 index 0000000000..75b31b8061 --- /dev/null +++ b/test/596-app-images/src/Main.java @@ -0,0 +1,33 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class Main { + static class Inner { + public static int abc = 0; + } + + public static void main(String[] args) { + System.loadLibrary(args[0]); + if (!checkAppImageLoaded()) { + System.out.println("App image is not loaded!"); + } else if (!checkAppImageContains(Inner.class)) { + System.out.println("App image does not contain Inner!"); + } + } + + public static native boolean checkAppImageLoaded(); + public static native boolean checkAppImageContains(Class<?> klass); +} diff --git a/test/596-checker-dead-phi/expected.txt b/test/596-checker-dead-phi/expected.txt new file mode 100644 index 0000000000..d81cc0710e --- /dev/null +++ b/test/596-checker-dead-phi/expected.txt @@ -0,0 +1 @@ +42 diff --git a/test/596-checker-dead-phi/info.txt b/test/596-checker-dead-phi/info.txt new file mode 100644 index 0000000000..7f7cf0f9e6 --- /dev/null +++ b/test/596-checker-dead-phi/info.txt @@ -0,0 +1,2 @@ +Regression test for optimizing where we used to replace a dead loop +phi with its first incoming input. diff --git a/test/596-checker-dead-phi/smali/IrreducibleLoop.smali b/test/596-checker-dead-phi/smali/IrreducibleLoop.smali new file mode 100644 index 0000000000..bab2ba99cc --- /dev/null +++ b/test/596-checker-dead-phi/smali/IrreducibleLoop.smali @@ -0,0 +1,74 @@ +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.class public LIrreducibleLoop; + +.super Ljava/lang/Object; + +# Test case where liveness analysis produces linear order where loop blocks are +# not adjacent. This revealed a bug in our SSA builder, where a dead loop phi would +# be replaced by its incoming input during SsaRedundantPhiElimination. + +# Check that the outer loop suspend check environment only has the parameter vreg. +## CHECK-START: int IrreducibleLoop.liveness(int) builder (after) +## CHECK-DAG: <<Phi:i\d+>> Phi reg:4 loop:{{B\d+}} irreducible:false +## CHECK-DAG: SuspendCheck env:[[_,_,_,_,<<Phi>>]] loop:{{B\d+}} irreducible:false + +# Check that the linear order has non-adjacent loop blocks. +## CHECK-START: int IrreducibleLoop.liveness(int) liveness (after) +## CHECK-DAG: Mul liveness:<<LPreEntry2:\d+>> +## CHECK-DAG: Add liveness:<<LBackEdge1:\d+>> +## CHECK-EVAL: <<LBackEdge1>> < <<LPreEntry2>> + +.method public static liveness(I)I + .registers 5 + + const-string v1, "MyString" + + :header1 + if-eqz p0, :body1 + + :exit + return p0 + + :body1 + # The test will generate an incorrect linear order when the following IF swaps + # its successors. To do that, load a boolean value and compare NotEqual to 1. + sget-boolean v2, LIrreducibleLoop;->f:Z + const v3, 1 + if-ne v2, v3, :pre_header2 + + :pre_entry2 + # Add a marker on the irreducible loop entry. + mul-int/2addr p0, p0 + goto :back_edge2 + + :back_edge2 + goto :header2 + + :header2 + if-eqz p0, :back_edge2 + + :back_edge1 + # Add a marker on the outer loop back edge. + add-int/2addr p0, p0 + # Set a wide register, to have v1 undefined at the back edge. + const-wide/16 v0, 0x1 + goto :header1 + + :pre_header2 + goto :header2 +.end method + +.field public static f:Z diff --git a/test/596-checker-dead-phi/src/Main.java b/test/596-checker-dead-phi/src/Main.java new file mode 100644 index 0000000000..5a3fffc8f0 --- /dev/null +++ b/test/596-checker-dead-phi/src/Main.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.lang.reflect.Method; + +public class Main { + // Workaround for b/18051191. + class InnerClass {} + + public static void main(String[] args) throws Exception { + Class<?> c = Class.forName("IrreducibleLoop"); + // Note that we don't actually enter the loops in the 'liveness' + // method, so this is just a sanity check that part of the code we + // generated for that method is correct. + Method m = c.getMethod("liveness", int.class); + Object[] arguments = { 42 }; + System.out.println(m.invoke(null, arguments)); + } +} diff --git a/test/960-default-smali/expected.txt b/test/960-default-smali/expected.txt index 7671eed5de..f3db93f87f 100644 --- a/test/960-default-smali/expected.txt +++ b/test/960-default-smali/expected.txt @@ -82,3 +82,19 @@ J-virtual A.SayHiTwice()='Hi Hi ' J-interface Greeter.SayHiTwice()='Hi Hi ' J-virtual J.SayHiTwice()='Hi Hi ' End testing for type J +Testing for type K +K-interface Foo.bar()='foobar' +K-virtual K.bar()='foobar' +End testing for type K +Testing for type L +L-interface Foo.bar()='foobar' +L-virtual K.bar()='foobar' +L-virtual L.bar()='foobar' +End testing for type L +Testing for type M +M-interface Foo.bar()='BAZ!' +M-interface Fooer.bar()='BAZ!' +M-virtual K.bar()='BAZ!' +M-virtual L.bar()='BAZ!' +M-virtual M.bar()='BAZ!' +End testing for type M diff --git a/test/960-default-smali/src/Foo.java b/test/960-default-smali/src/Foo.java new file mode 100644 index 0000000000..ed5b35f47b --- /dev/null +++ b/test/960-default-smali/src/Foo.java @@ -0,0 +1,20 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +interface Foo { + public default String bar() { + return "foobar"; + } +} diff --git a/test/960-default-smali/src/Fooer.java b/test/960-default-smali/src/Fooer.java new file mode 100644 index 0000000000..d8a5f61636 --- /dev/null +++ b/test/960-default-smali/src/Fooer.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface Fooer extends Foo { + public String bar(); +} diff --git a/test/960-default-smali/src/K.java b/test/960-default-smali/src/K.java new file mode 100644 index 0000000000..4426be7192 --- /dev/null +++ b/test/960-default-smali/src/K.java @@ -0,0 +1,17 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class K implements Foo { } diff --git a/test/960-default-smali/src/L.java b/test/960-default-smali/src/L.java new file mode 100644 index 0000000000..c08ab72a99 --- /dev/null +++ b/test/960-default-smali/src/L.java @@ -0,0 +1,17 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class L extends K { } diff --git a/test/960-default-smali/src/M.java b/test/960-default-smali/src/M.java new file mode 100644 index 0000000000..affe7e9c9e --- /dev/null +++ b/test/960-default-smali/src/M.java @@ -0,0 +1,21 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class M extends L implements Fooer { + public String bar() { + return "BAZ!"; + } +} diff --git a/test/960-default-smali/src/classes.xml b/test/960-default-smali/src/classes.xml index 0aa41f7fb6..f3e50c570b 100644 --- a/test/960-default-smali/src/classes.xml +++ b/test/960-default-smali/src/classes.xml @@ -81,6 +81,27 @@ <implements> </implements> <methods> </methods> </class> + + <class name="K" super="java/lang/Object"> + <implements> + <item>Foo</item> + </implements> + <methods> </methods> + </class> + + <class name="L" super="K"> + <implements> </implements> + <methods> </methods> + </class> + + <class name="M" super="L"> + <implements> + <item>Fooer</item> + </implements> + <methods> + <method>bar</method> + </methods> + </class> </classes> <interfaces> @@ -123,5 +144,22 @@ <method type="abstract">GetPlace</method> </methods> </interface> + + <interface name="Foo" super="java/lang/Object"> + <implements> + </implements> + <methods> + <method type="default">bar</method> + </methods> + </interface> + + <interface name="Fooer" super="java/lang/Object"> + <implements> + <item>Foo</item> + </implements> + <methods> + <method type="abstract">bar</method> + </methods> + </interface> </interfaces> </data> diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk index 464da2e1de..d6f5d372a9 100644 --- a/test/Android.libarttest.mk +++ b/test/Android.libarttest.mk @@ -42,7 +42,8 @@ LIBARTTEST_COMMON_SRC_FILES := \ 543-env-long-ref/env_long_ref.cc \ 566-polymorphic-inlining/polymorphic_inline.cc \ 570-checker-osr/osr.cc \ - 595-profile-saving/profile-saving.cc + 595-profile-saving/profile-saving.cc \ + 596-app-images/app_images.cc ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttestd.so diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index f3cda479db..ee651b5494 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -563,6 +563,13 @@ endif TEST_ART_BROKEN_OPTIMIZING_READ_BARRIER_RUN_TESTS := TEST_ART_BROKEN_JIT_READ_BARRIER_RUN_TESTS := +TEST_ART_BROKEN_NPIC_RUN_TESTS := 596-app-images +ifneq (,$(filter npictest,$(PICTEST_TYPES))) + ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \ + ${COMPILER_TYPES},$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \ + $(IMAGE_TYPES),npictest,$(DEBUGGABLE_TYPES),$(TEST_ART_BROKEN_NPIC_RUN_TESTS),$(ALL_ADDRESS_SIZES)) +endif + # Tests that should fail in the heap poisoning configuration with the Optimizing compiler. # 055: Exceeds run time limits due to heap poisoning instrumentation (on ARM and ARM64 devices). TEST_ART_BROKEN_OPTIMIZING_HEAP_POISONING_RUN_TESTS := \ diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt index f25fb98c4d..dd2cc3140f 100644 --- a/tools/libcore_failures.txt +++ b/tools/libcore_failures.txt @@ -253,5 +253,11 @@ names: ["jsr166.CollectionTest#testEmptyMeansEmpty", "jsr166.Collection8Test#testForEach", "jsr166.Collection8Test#testForEachConcurrentStressTest"] +}, +{ + description: "Unclear why this started to fail", + result: EXEC_FAILED, + bug: 28574453, + names: [ "org.apache.harmony.tests.javax.security.cert.X509CertificateTest#testVerifyPublicKey" ] } ] |