Merge "Revert "(dl)Close native libraries on unload""
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index cd463ec..3b459c3 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -650,11 +650,11 @@
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 5b7574a..251dc39 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 @@
check_generic_jni_ = false;
}
+ void TearDown() OVERRIDE {
+ android::ResetNativeLoader();
+ CommonCompilerTest::TearDown();
+ }
+
void SetCheckGenericJni(bool generic) {
check_generic_jni_ = generic;
}
@@ -93,10 +99,12 @@
// 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 @@
void StackArgsSignExtendedMips64Impl();
JNIEnv* env_;
+ jstring library_search_path_;
jmethodID jmethod_;
bool check_generic_jni_;
};
@@ -220,15 +229,14 @@
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 @@
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 b65e98a..6c6e5af 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -800,6 +800,27 @@
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 @@
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 863dd1c..39a1313 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -30,6 +30,10 @@
// 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 86b7bc1..146fea1 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -1985,6 +1985,56 @@
__ 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, 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 04ae3a6..1d82296 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -47,6 +47,7 @@
using helpers::WRegisterFrom;
using helpers::XRegisterFrom;
using helpers::InputRegisterAt;
+using helpers::OutputRegister;
namespace {
@@ -1173,31 +1174,118 @@
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 @@
__ 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 19c6a22..46195c1 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -2283,10 +2283,10 @@
// 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 aeb3109..0978ae1 100644
--- a/compiler/optimizing/ssa_phi_elimination.cc
+++ b/compiler/optimizing/ssa_phi_elimination.cc
@@ -139,8 +139,9 @@
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 6ecfc74..d2ab699 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 @@
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 @@
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 1618ced..bf0f647 100644
--- a/runtime/arch/arm64/entrypoints_init_arm64.cc
+++ b/runtime/arch/arm64/entrypoints_init_arm64.cc
@@ -80,7 +80,8 @@
// 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 7774106..1fba09b 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -2203,108 +2203,3 @@
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 3cdff55..02629e8 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -1205,7 +1205,8 @@
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 6449efa..7647ad6 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -456,13 +456,18 @@
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 a147aba..35c40cd 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -6635,6 +6635,17 @@
// 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 35bb3c3..79c3203 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -318,6 +318,7 @@
}
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 6b7ca40..0624da3 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -238,12 +238,13 @@
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 @@
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 11a9d76..9470624 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -370,6 +370,10 @@
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 66e1d92..41771b5 100644
--- a/test/449-checker-bce/src/Main.java
+++ b/test/449-checker-bce/src/Main.java
@@ -927,6 +927,32 @@
}
}
+ /// 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 @@
}
}
+ 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 c644692..b12fbd6 100644
--- a/test/530-checker-loops2/src/Main.java
+++ b/test/530-checker-loops2/src/Main.java
@@ -710,8 +710,8 @@
// 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 @@
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 @@
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 0000000..11c0f42
--- /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 0000000..6a5618e
--- /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 0000000..a3d5e7e
--- /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 0000000..75b31b8
--- /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 0000000..d81cc07
--- /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 0000000..7f7cf0f
--- /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 0000000..bab2ba9
--- /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 0000000..5a3fffc
--- /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 7671eed..f3db93f 100644
--- a/test/960-default-smali/expected.txt
+++ b/test/960-default-smali/expected.txt
@@ -82,3 +82,19 @@
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 0000000..ed5b35f
--- /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 0000000..d8a5f61
--- /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 0000000..4426be7
--- /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 0000000..c08ab72
--- /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 0000000..affe7e9
--- /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 0aa41f7..f3e50c5 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 464da2e..d6f5d37 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -42,7 +42,8 @@
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 f3cda47..ee651b5 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -563,6 +563,13 @@
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 f25fb98..dd2cc31 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" ]
}
]