Merge "Remove mirror:: and ArtMethod deps in utils.{h,cc}"
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 54e52e5..c3321e1 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -2117,7 +2117,7 @@
mov %r8d, %ecx
cmovg %r9d, %ecx
/* Going into loop to compare each character */
- jecxz .Lstring_compareto_keep_length // check loop counter (if 0 then stop)
+ jecxz .Lstring_compareto_keep_length1 // check loop counter (if 0 then stop)
.Lstring_compareto_loop_comparison_this_compressed:
movzbl (%edi), %r8d // move *(this_cur_char) byte to long
movzwl (%esi), %r9d // move *(that_cur_char) word to long
@@ -2126,6 +2126,7 @@
subl %r9d, %r8d
loope .Lstring_compareto_loop_comparison_this_compressed
cmovne %r8d, %eax // return eax = *(this_cur_char) - *(that_cur_char)
+.Lstring_compareto_keep_length1:
ret
.Lstring_compareto_that_is_compressed:
andl LITERAL(0x7FFFFFFF), %r9d
@@ -2134,7 +2135,7 @@
mov %r8d, %ecx
cmovg %r9d, %ecx
/* Comparison this (8-bit) and that (16-bit) */
- jecxz .Lstring_compareto_keep_length // check loop counter (if 0, don't compare)
+ jecxz .Lstring_compareto_keep_length2 // check loop counter (if 0, don't compare)
.Lstring_compareto_loop_comparison_that_compressed:
movzwl (%edi), %r8d // move *(this_cur_char) word to long
movzbl (%esi), %r9d // move *(that_cur_chat) byte to long
@@ -2143,6 +2144,7 @@
subl %r9d, %r8d
loope .Lstring_compareto_loop_comparison_that_compressed
cmovne %r8d, %eax // return eax = *(this_cur_char) - *(that_cur_char)
+.Lstring_compareto_keep_length2:
ret
.Lstring_compareto_both_compressed:
andl LITERAL(0x7FFFFFFF), %r9d
@@ -2151,9 +2153,9 @@
movl %r8d, %eax
subl %r9d, %eax
cmovg %r9d, %ecx
- jecxz .Lstring_compareto_keep_length
+ jecxz .Lstring_compareto_keep_length3
repe cmpsb
- je .Lstring_compareto_keep_length
+ je .Lstring_compareto_keep_length3
movzbl -1(%edi), %eax // get last compared char from this string (8-bit)
movzbl -1(%esi), %ecx // get last compared char from comp string (8-bit)
jmp .Lstring_compareto_count_difference
@@ -2171,14 +2173,14 @@
* esi: pointer to comp string data
* edi: pointer to this string data
*/
- jecxz .Lstring_compareto_keep_length
+ jecxz .Lstring_compareto_keep_length3
repe cmpsw // find nonmatching chars in [%esi] and [%edi], up to length %ecx
- je .Lstring_compareto_keep_length
+ je .Lstring_compareto_keep_length3
movzwl -2(%edi), %eax // get last compared char from this string (16-bit)
movzwl -2(%esi), %ecx // get last compared char from comp string (16-bit)
.Lstring_compareto_count_difference:
subl %ecx, %eax // return the difference
-.Lstring_compareto_keep_length:
+.Lstring_compareto_keep_length3:
ret
END_FUNCTION art_quick_string_compareto
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index 6109ec6..130c10d 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -58,17 +58,15 @@
}
}
-IndirectReferenceTable::IndirectReferenceTable(size_t initialCount,
- size_t maxCount, IndirectRefKind desiredKind,
+IndirectReferenceTable::IndirectReferenceTable(size_t max_count,
+ IndirectRefKind desired_kind,
bool abort_on_error)
- : kind_(desiredKind),
- max_entries_(maxCount) {
- CHECK_GT(initialCount, 0U);
- CHECK_LE(initialCount, maxCount);
- CHECK_NE(desiredKind, kHandleScopeOrInvalid);
+ : kind_(desired_kind),
+ max_entries_(max_count) {
+ CHECK_NE(desired_kind, kHandleScopeOrInvalid);
std::string error_str;
- const size_t table_bytes = maxCount * sizeof(IrtEntry);
+ const size_t table_bytes = max_count * sizeof(IrtEntry);
table_mem_map_.reset(MemMap::MapAnonymous("indirect ref table", nullptr, table_bytes,
PROT_READ | PROT_WRITE, false, false, &error_str));
if (abort_on_error) {
diff --git a/runtime/indirect_reference_table.h b/runtime/indirect_reference_table.h
index 64de7a8..1762b10 100644
--- a/runtime/indirect_reference_table.h
+++ b/runtime/indirect_reference_table.h
@@ -259,8 +259,7 @@
public:
// WARNING: When using with abort_on_error = false, the object may be in a partially
// initialized state. Use IsValid() to check.
- IndirectReferenceTable(size_t initialCount, size_t maxCount, IndirectRefKind kind,
- bool abort_on_error = true);
+ IndirectReferenceTable(size_t max_count, IndirectRefKind kind, bool abort_on_error = true);
~IndirectReferenceTable();
diff --git a/runtime/indirect_reference_table_test.cc b/runtime/indirect_reference_table_test.cc
index 1699110..7b28f0b 100644
--- a/runtime/indirect_reference_table_test.cc
+++ b/runtime/indirect_reference_table_test.cc
@@ -48,9 +48,8 @@
ScopedLogSeverity sls(LogSeverity::FATAL);
ScopedObjectAccess soa(Thread::Current());
- static const size_t kTableInitial = 10;
static const size_t kTableMax = 20;
- IndirectReferenceTable irt(kTableInitial, kTableMax, kGlobal);
+ IndirectReferenceTable irt(kTableMax, kGlobal);
mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
StackHandleScope<4> hs(soa.Self());
@@ -230,6 +229,7 @@
// Test table resizing.
// These ones fit...
+ static const size_t kTableInitial = kTableMax / 2;
IndirectRef manyRefs[kTableInitial];
for (size_t i = 0; i < kTableInitial; i++) {
manyRefs[i] = irt.Add(cookie, obj0.Get());
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index 29dda88..7285b9a 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -42,11 +42,9 @@
namespace art {
-static size_t gGlobalsInitial = 512; // Arbitrary.
-static size_t gGlobalsMax = 51200; // Arbitrary sanity check. (Must fit in 16 bits.)
+static constexpr size_t kGlobalsMax = 51200; // Arbitrary sanity check. (Must fit in 16 bits.)
-static const size_t kWeakGlobalsInitial = 16; // Arbitrary.
-static const size_t kWeakGlobalsMax = 51200; // Arbitrary sanity check. (Must fit in 16 bits.)
+static constexpr size_t kWeakGlobalsMax = 51200; // Arbitrary sanity check. (Must fit in 16 bits.)
bool JavaVMExt::IsBadJniVersion(int version) {
// We don't support JNI_VERSION_1_1. These are the only other valid versions.
@@ -422,10 +420,10 @@
tracing_enabled_(runtime_options.Exists(RuntimeArgumentMap::JniTrace)
|| VLOG_IS_ON(third_party_jni)),
trace_(runtime_options.GetOrDefault(RuntimeArgumentMap::JniTrace)),
- globals_(gGlobalsInitial, gGlobalsMax, kGlobal),
+ globals_(kGlobalsMax, kGlobal),
libraries_(new Libraries),
unchecked_functions_(&gJniInvokeInterface),
- weak_globals_(kWeakGlobalsInitial, kWeakGlobalsMax, kWeakGlobal),
+ weak_globals_(kWeakGlobalsMax, kWeakGlobal),
allow_accessing_weak_globals_(true),
weak_globals_add_condition_("weak globals add condition",
(CHECK(Locks::jni_weak_globals_lock_ != nullptr),
diff --git a/runtime/jni_env_ext.cc b/runtime/jni_env_ext.cc
index bae1567..1ca2cb4 100644
--- a/runtime/jni_env_ext.cc
+++ b/runtime/jni_env_ext.cc
@@ -33,8 +33,6 @@
static constexpr size_t kMonitorsInitial = 32; // Arbitrary.
static constexpr size_t kMonitorsMax = 4096; // Arbitrary sanity check.
-static constexpr size_t kLocalsInitial = 64; // Arbitrary.
-
// Checking "locals" requires the mutator lock, but at creation time we're really only interested
// in validity, which isn't changing. To avoid grabbing the mutator lock, factored out and tagged
// with NO_THREAD_SAFETY_ANALYSIS.
@@ -71,7 +69,7 @@
: self(self_in),
vm(vm_in),
local_ref_cookie(IRT_FIRST_SEGMENT),
- locals(kLocalsInitial, kLocalsMax, kLocal, false),
+ locals(kLocalsInitial, kLocal, false),
check_jni(false),
runtime_deleted(false),
critical(0),
diff --git a/runtime/jni_env_ext.h b/runtime/jni_env_ext.h
index 121f848..549f8c5 100644
--- a/runtime/jni_env_ext.h
+++ b/runtime/jni_env_ext.h
@@ -29,9 +29,9 @@
class JavaVMExt;
-// Maximum number of local references in the indirect reference table. The value is arbitrary but
+// Number of local references in the indirect reference table. The value is arbitrary but
// low enough that it forces sanity checks.
-static constexpr size_t kLocalsMax = 512;
+static constexpr size_t kLocalsInitial = 512;
struct JNIEnvExt : public JNIEnv {
static JNIEnvExt* Create(Thread* self, JavaVMExt* vm);
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 8238f3a..3839e08 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -2395,13 +2395,13 @@
const char* caller)
REQUIRES_SHARED(Locks::mutator_lock_) {
// TODO: we should try to expand the table if necessary.
- if (desired_capacity < 0 || desired_capacity > static_cast<jint>(kLocalsMax)) {
+ if (desired_capacity < 0 || desired_capacity > static_cast<jint>(kLocalsInitial)) {
LOG(ERROR) << "Invalid capacity given to " << caller << ": " << desired_capacity;
return JNI_ERR;
}
// TODO: this isn't quite right, since "capacity" includes holes.
const size_t capacity = soa.Env()->locals.Capacity();
- bool okay = (static_cast<jint>(kLocalsMax - capacity) >= desired_capacity);
+ bool okay = (static_cast<jint>(kLocalsInitial - capacity) >= desired_capacity);
if (!okay) {
soa.Self()->ThrowOutOfMemoryError(caller);
}
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index 61208e1..c6d5c9e 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -865,6 +865,11 @@
GetStaticMethodIdBadArgumentTest(true);
}
+static size_t GetLocalsCapacity(JNIEnv* env) {
+ ScopedObjectAccess soa(Thread::Current());
+ return reinterpret_cast<JNIEnvExt*>(env)->locals.Capacity();
+}
+
TEST_F(JniInternalTest, FromReflectedField_ToReflectedField) {
jclass jlrField = env_->FindClass("java/lang/reflect/Field");
jclass c = env_->FindClass("java/lang/String");
@@ -873,11 +878,15 @@
ASSERT_NE(fid, nullptr);
// Turn the fid into a java.lang.reflect.Field...
jobject field = env_->ToReflectedField(c, fid, JNI_FALSE);
- for (size_t i = 0; i <= kLocalsMax; ++i) {
+ size_t capacity_before = GetLocalsCapacity(env_);
+ for (size_t i = 0; i <= 10; ++i) {
// Regression test for b/18396311, ToReflectedField leaking local refs causing a local
// reference table overflows with 512 references to ArtField
env_->DeleteLocalRef(env_->ToReflectedField(c, fid, JNI_FALSE));
}
+ size_t capacity_after = GetLocalsCapacity(env_);
+ ASSERT_EQ(capacity_before, capacity_after);
+
ASSERT_NE(c, nullptr);
ASSERT_TRUE(env_->IsInstanceOf(field, jlrField));
// ...and back again.
@@ -911,11 +920,14 @@
ASSERT_NE(mid, nullptr);
// Turn the mid into a java.lang.reflect.Constructor...
jobject method = env_->ToReflectedMethod(c, mid, JNI_FALSE);
- for (size_t i = 0; i <= kLocalsMax; ++i) {
+ size_t capacity_before = GetLocalsCapacity(env_);
+ for (size_t i = 0; i <= 10; ++i) {
// Regression test for b/18396311, ToReflectedMethod leaking local refs causing a local
// reference table overflows with 512 references to ArtMethod
env_->DeleteLocalRef(env_->ToReflectedMethod(c, mid, JNI_FALSE));
}
+ size_t capacity_after = GetLocalsCapacity(env_);
+ ASSERT_EQ(capacity_before, capacity_after);
ASSERT_NE(method, nullptr);
ASSERT_TRUE(env_->IsInstanceOf(method, jlrConstructor));
// ...and back again.
@@ -2295,7 +2307,7 @@
// The segment_state_ field is private, and we want to avoid friend declaration. So we'll check
// by modifying memory.
// The parameters don't really matter here.
- IndirectReferenceTable irt(5, 5, IndirectRefKind::kGlobal, true);
+ IndirectReferenceTable irt(5, IndirectRefKind::kGlobal, true);
uint32_t old_state = irt.GetSegmentState();
// Write some new state directly. We invert parts of old_state to ensure a new value.
diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc
index ea2660b..4336aa1 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -292,38 +292,41 @@
if (lhs == rhs) {
return 0;
}
- // TODO: is this still true?
- // The annoying part here is that 0x00e9 - 0xffff != 0x00ea,
- // because the interpreter converts the characters to 32-bit integers
- // *without* sign extension before it subtracts them (which makes some
- // sense since "char" is unsigned). So what we get is the result of
- // 0x000000e9 - 0x0000ffff, which is 0xffff00ea.
- int32_t lhsCount = lhs->GetLength();
- int32_t rhsCount = rhs->GetLength();
- int32_t countDiff = lhsCount - rhsCount;
- int32_t minCount = (countDiff < 0) ? lhsCount : rhsCount;
+ int32_t lhs_count = lhs->GetLength();
+ int32_t rhs_count = rhs->GetLength();
+ int32_t count_diff = lhs_count - rhs_count;
+ int32_t min_count = (count_diff < 0) ? lhs_count : rhs_count;
if (lhs->IsCompressed() && rhs->IsCompressed()) {
- int32_t comparison = memcmp(lhs->GetValueCompressed(),
- rhs->GetValueCompressed(),
- minCount * sizeof(uint8_t));
- if (comparison != 0) {
- return comparison;
+ const uint8_t* lhs_chars = lhs->GetValueCompressed();
+ const uint8_t* rhs_chars = rhs->GetValueCompressed();
+ for (int32_t i = 0; i < min_count; ++i) {
+ int32_t char_diff = static_cast<int32_t>(lhs_chars[i]) - static_cast<int32_t>(rhs_chars[i]);
+ if (char_diff != 0) {
+ return char_diff;
+ }
}
} else if (lhs->IsCompressed() || rhs->IsCompressed()) {
- for (int32_t i = 0; i < minCount; ++i) {
- if (lhs->CharAt(i) != rhs->CharAt(i)) {
- return static_cast<int32_t>(lhs->CharAt(i)) - static_cast<int32_t>(rhs->CharAt(i));
+ const uint8_t* compressed_chars =
+ lhs->IsCompressed() ? lhs->GetValueCompressed() : rhs->GetValueCompressed();
+ const uint16_t* uncompressed_chars = lhs->IsCompressed() ? rhs->GetValue() : lhs->GetValue();
+ for (int32_t i = 0; i < min_count; ++i) {
+ int32_t char_diff =
+ static_cast<int32_t>(compressed_chars[i]) - static_cast<int32_t>(uncompressed_chars[i]);
+ if (char_diff != 0) {
+ return lhs->IsCompressed() ? char_diff : -char_diff;
}
}
} else {
- const uint16_t* lhsChars = lhs->GetValue();
- const uint16_t* rhsChars = rhs->GetValue();
- int32_t otherRes = MemCmp16(lhsChars, rhsChars, minCount);
- if (otherRes != 0) {
- return otherRes;
+ const uint16_t* lhs_chars = lhs->GetValue();
+ const uint16_t* rhs_chars = rhs->GetValue();
+ // FIXME: The MemCmp16() name is misleading. It returns the char difference on mismatch
+ // where memcmp() only guarantees that the returned value has the same sign.
+ int32_t char_diff = MemCmp16(lhs_chars, rhs_chars, min_count);
+ if (char_diff != 0) {
+ return char_diff;
}
}
- return countDiff;
+ return count_diff;
}
void String::VisitRoots(RootVisitor* visitor) {
diff --git a/test/021-string2/src/Main.java b/test/021-string2/src/Main.java
index d1ea0b1..a848fba 100644
--- a/test/021-string2/src/Main.java
+++ b/test/021-string2/src/Main.java
@@ -89,5 +89,424 @@
Method fromUTF8ByteArray = Strings.getDeclaredMethod("fromUTF8ByteArray", byte[].class);
String result = (String) fromUTF8ByteArray.invoke(null, new byte[] {'O', 'K'});
System.out.println(result);
+
+ testCompareToAndEquals();
+ testIndexOf();
}
+
+ public static void testCompareToAndEquals() {
+ String[] strings = {
+ // Special: empty string.
+ "",
+ // Category 0, ASCII strings:
+ // "0123456789abcdef".substring(0, index + 1)
+ "0",
+ "01",
+ "012",
+ "0123",
+ "01234",
+ "012345",
+ "0123456",
+ "01234567",
+ "012345678",
+ "0123456789",
+ "0123456789a",
+ "0123456789ab",
+ "0123456789abc",
+ "0123456789abcd",
+ "0123456789abcde",
+ "0123456789abcdef",
+ // Category 1, ASCII strings:
+ // "0123456789abcdef".substring(0, index) + "x"
+ "x",
+ "0x",
+ "01x",
+ "012x",
+ "0123x",
+ "01234x",
+ "012345x",
+ "0123456x",
+ "01234567x",
+ "012345678x",
+ "0123456789x",
+ "0123456789ax",
+ "0123456789abx",
+ "0123456789abcx",
+ "0123456789abcdx",
+ "0123456789abcdex",
+ // Category 2, ASCII strings,
+ // "0123456789abcdef".substring(0, index) + "x" +
+ // "0123456789abcdef".substring(index + 1)
+ "x123456789abcdef",
+ "0x23456789abcdef",
+ "01x3456789abcdef",
+ "012x456789abcdef",
+ "0123x56789abcdef",
+ "01234x6789abcdef",
+ "012345x789abcdef",
+ "0123456x89abcdef",
+ "01234567x9abcdef",
+ "012345678xabcdef",
+ "0123456789xbcdef",
+ "0123456789axcdef",
+ "0123456789abxdef",
+ "0123456789abcxef",
+ "0123456789abcdxf",
+ "0123456789abcdex",
+ // Category 3, ASCII strings:
+ // "z" + "0123456789abcdef".substring(1, index + 1)
+ "z",
+ "z1",
+ "z12",
+ "z123",
+ "z1234",
+ "z12345",
+ "z123456",
+ "z1234567",
+ "z12345678",
+ "z123456789",
+ "z123456789a",
+ "z123456789ab",
+ "z123456789abc",
+ "z123456789abcd",
+ "z123456789abcde",
+ "z123456789abcdef",
+ // Category 4, non-ASCII strings:
+ // "0123456789abcdef".substring(0, index) + "\u0440"
+ "\u0440",
+ "0\u0440",
+ "01\u0440",
+ "012\u0440",
+ "0123\u0440",
+ "01234\u0440",
+ "012345\u0440",
+ "0123456\u0440",
+ "01234567\u0440",
+ "012345678\u0440",
+ "0123456789\u0440",
+ "0123456789a\u0440",
+ "0123456789ab\u0440",
+ "0123456789abc\u0440",
+ "0123456789abcd\u0440",
+ "0123456789abcde\u0440",
+ // Category 5, non-ASCII strings:
+ // "0123456789abcdef".substring(0, index) + "\u0440" +
+ // "0123456789abcdef".substring(index + 1)
+ "\u0440123456789abcdef",
+ "0\u044023456789abcdef",
+ "01\u04403456789abcdef",
+ "012\u0440456789abcdef",
+ "0123\u044056789abcdef",
+ "01234\u04406789abcdef",
+ "012345\u0440789abcdef",
+ "0123456\u044089abcdef",
+ "01234567\u04409abcdef",
+ "012345678\u0440abcdef",
+ "0123456789\u0440bcdef",
+ "0123456789a\u0440cdef",
+ "0123456789ab\u0440def",
+ "0123456789abc\u0440ef",
+ "0123456789abcd\u0440f",
+ "0123456789abcde\u0440",
+ // Category 6, ASCII strings:
+ // "\u0443" + "0123456789abcdef".substring(1, index + 1)
+ "\u0443",
+ "\u04431",
+ "\u044312",
+ "\u0443123",
+ "\u04431234",
+ "\u044312345",
+ "\u0443123456",
+ "\u04431234567",
+ "\u044312345678",
+ "\u0443123456789",
+ "\u0443123456789a",
+ "\u0443123456789ab",
+ "\u0443123456789abc",
+ "\u0443123456789abcd",
+ "\u0443123456789abcde",
+ "\u0443123456789abcdef",
+ // Category 7, non-ASCII strings:
+ // "0123456789abcdef".substring(0, index) + "\u0482"
+ "\u0482",
+ "0\u0482",
+ "01\u0482",
+ "012\u0482",
+ "0123\u0482",
+ "01234\u0482",
+ "012345\u0482",
+ "0123456\u0482",
+ "01234567\u0482",
+ "012345678\u0482",
+ "0123456789\u0482",
+ "0123456789a\u0482",
+ "0123456789ab\u0482",
+ "0123456789abc\u0482",
+ "0123456789abcd\u0482",
+ "0123456789abcde\u0482",
+ // Category 8, non-ASCII strings:
+ // "0123456789abcdef".substring(0, index) + "\u0482" +
+ // "0123456789abcdef".substring(index + 1)
+ "\u0482123456789abcdef",
+ "0\u048223456789abcdef",
+ "01\u04823456789abcdef",
+ "012\u0482456789abcdef",
+ "0123\u048256789abcdef",
+ "01234\u04826789abcdef",
+ "012345\u0482789abcdef",
+ "0123456\u048289abcdef",
+ "01234567\u04829abcdef",
+ "012345678\u0482abcdef",
+ "0123456789\u0482bcdef",
+ "0123456789a\u0482cdef",
+ "0123456789ab\u0482def",
+ "0123456789abc\u0482ef",
+ "0123456789abcd\u0482f",
+ "0123456789abcde\u0482",
+ // Category 9, ASCII strings:
+ // "\u0489" + "0123456789abcdef".substring(1, index + 1)
+ "\u0489",
+ "\u04891",
+ "\u048912",
+ "\u0489123",
+ "\u04891234",
+ "\u048912345",
+ "\u0489123456",
+ "\u04891234567",
+ "\u048912345678",
+ "\u0489123456789",
+ "\u0489123456789a",
+ "\u0489123456789ab",
+ "\u0489123456789abc",
+ "\u0489123456789abcd",
+ "\u0489123456789abcde",
+ "\u0489123456789abcdef",
+ };
+ int length = strings.length;
+ Assert.assertEquals(1 + 16 * 10, length);
+ for (int i = 0; i != length; ++i) {
+ String lhs = strings[i];
+ for (int j = 0; j != length; ++j) {
+ String rhs = strings[j];
+ int result = $noinline$compareTo(lhs, rhs);
+ final int expected;
+ if (i == 0 || j == 0 || i == j) {
+ // One of the strings is empty or the strings are the same.
+ expected = lhs.length() - rhs.length();
+ } else {
+ int i_category = (i - 1) / 16;
+ int i_index = (i - 1) % 16;
+ int j_category = (j - 1) / 16;
+ int j_index = (j - 1) % 16;
+ int min_ij_index = (i_index < j_index) ? i_index : j_index;
+ if (i_category == j_category) {
+ switch (i_category) {
+ case 0: case 3: case 6: case 9:
+ // Differs in length.
+ expected = lhs.length() - rhs.length();
+ break;
+ case 1: case 2: case 4: case 5: case 7: case 8:
+ // Differs in charAt(min_ij_index).
+ expected = lhs.charAt(min_ij_index) - rhs.charAt(min_ij_index);
+ break;
+ default: throw new Error("Unexpected category.");
+ }
+ } else if (i_category == 3 || i_category == 6 || i_category == 9 ||
+ j_category == 3 || j_category == 6 || j_category == 9) {
+ // In these categories, charAt(0) differs from other categories' strings.
+ expected = lhs.charAt(0) - rhs.charAt(0);
+ } else if (// Category 0 string is a prefix to any longer string in
+ // remaining categories.
+ (i_category == 0 && i_index < j_index) ||
+ (j_category == 0 && j_index < i_index) ||
+ // Category 2 string is a prefix to category 3 string at the same
+ // index. Similar for categories 4 and 5 and also 7 and 8.
+ // This includes matching last strings of these pairs of categories.
+ (i_index == j_index &&
+ ((i_category == 1 && j_category == 2) ||
+ (i_category == 2 && j_category == 1) ||
+ (i_category == 4 && j_category == 5) ||
+ (i_category == 5 && j_category == 4) ||
+ (i_category == 7 && j_category == 8) ||
+ (i_category == 8 && j_category == 7)))) {
+ // Differs in length.
+ expected = lhs.length() - rhs.length();
+ } else {
+ // The remaining cases differ in charAt(min_ij_index), the characters
+ // before that are "0123456789abcdef".substring(0, min_ij_index).
+ for (int k = 0; k < min_ij_index; ++k) {
+ Assert.assertEquals("0123456789abcdef".charAt(k), lhs.charAt(k));
+ Assert.assertEquals("0123456789abcdef".charAt(k), rhs.charAt(k));
+ }
+ expected = lhs.charAt(min_ij_index) - rhs.charAt(min_ij_index);
+ Assert.assertFalse(expected == 0);
+ }
+ }
+ if (expected != result) {
+ throw new Error(
+ "Mismatch at i=" + i + ", j=" + j + ", expected=" + expected +
+ ", result=" + result);
+ }
+ boolean equalsExpected =
+ (i == j) ||
+ // Last string in categories 1 and 2.
+ (i == 32 && j == 48) || (i == 48 && j == 32) ||
+ // Last string in categories 4 and 5.
+ (i == 80 && j == 96) || (i == 96 && j == 80) ||
+ // Last string in categories 7 and 8.
+ (i == 128 && j == 144) || (i == 144 && j == 128);
+ Assert.assertEquals(equalsExpected, $noinline$equals(lhs, rhs));
+ }
+ }
+
+ try {
+ $noinline$compareTo("", null);
+ Assert.fail();
+ } catch (NullPointerException expected) {
+ }
+ try {
+ $noinline$compareTo(null, "");
+ Assert.fail();
+ } catch (NullPointerException expected) {
+ }
+
+ Assert.assertFalse($noinline$equals("", null));
+ try {
+ $noinline$equals(null, "");
+ Assert.fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ public static void testIndexOf() {
+ String[] prefixes = {
+ "",
+ "0",
+ "01",
+ "012",
+ "0123",
+ "01234",
+ "012345",
+ "0123456",
+ "01234567",
+ "012345678",
+ "0123456789",
+ "0123456789a",
+ "0123456789ab",
+ "0123456789abc",
+ "0123456789abcd",
+ "0123456789abcdef",
+ };
+ String[] cores = {
+ "",
+ "x",
+ "xx",
+ "xxx",
+ "xxxx",
+ "xxxxx",
+ "xxxxxx",
+ "xxxxxxx",
+ "xxxxxxxx",
+ "xzx",
+ "xxzx",
+ "xxxzx",
+ "xxxxzx",
+ "xxxxxzx",
+ "xxxxxxzx",
+ "xxxxxxxzx",
+ "xxxxxxxxzx",
+ "\u0440",
+ "\u0440\u0440",
+ "\u0440\u0440\u0440",
+ "\u0440\u0440\u0440\u0440",
+ "\u0440\u0440\u0440\u0440\u0440",
+ "\u0440\u0440\u0440\u0440\u0440\u0440",
+ "\u0440\u0440\u0440\u0440\u0440\u0440\u0440",
+ "\u0440\u0440\u0440\u0440\u0440\u0440\u0440\u0440",
+ "\u0440z\u0440",
+ "\u0440\u0440z\u0440",
+ "\u0440\u0440\u0440z\u0440",
+ "\u0440\u0440\u0440\u0440z\u0440",
+ "\u0440\u0440\u0440\u0440\u0440z\u0440",
+ "\u0440\u0440\u0440\u0440\u0440\u0440z\u0440",
+ "\u0440\u0440\u0440\u0440\u0440\u0440\u0440z\u0440",
+ "\u0440\u0440\u0440\u0440\u0440\u0440\u0440\u0440z\u0440",
+ };
+ String[] suffixes = {
+ "",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy",
+ "yyyyy",
+ "yyyyyy",
+ "yyyyyyy",
+ "yyyyyyyy",
+ "\u0441",
+ "y\u0441",
+ "yy\u0441",
+ "yyy\u0441",
+ "yyyy\u0441",
+ "yyyyy\u0441",
+ "yyyyyy\u0441",
+ "yyyyyyy\u0441",
+ "yyyyyyyy\u0441",
+ };
+ for (String p : prefixes) {
+ for (String c : cores) {
+ for (String s : suffixes) {
+ String full = p + c + s;
+ int expX = (c.isEmpty() || c.charAt(0) != 'x') ? -1 : p.length();
+ int exp0440 = (c.isEmpty() || c.charAt(0) != '\u0440') ? -1 : p.length();
+ Assert.assertEquals(expX, $noinline$indexOf(full, 'x'));
+ Assert.assertEquals(exp0440, $noinline$indexOf(full, '\u0440'));
+ Assert.assertEquals(expX, $noinline$indexOf(full, 'x', -1));
+ Assert.assertEquals(exp0440, $noinline$indexOf(full, '\u0440', -1));
+ Assert.assertEquals(-1, $noinline$indexOf(full, 'x', full.length() + 1));
+ Assert.assertEquals(-1, $noinline$indexOf(full, '\u0440', full.length() + 1));
+ for (int from = 0; from != full.length(); ++from) {
+ final int eX;
+ final int e0440;
+ if (from <= p.length()) {
+ eX = expX;
+ e0440 = exp0440;
+ } else if (from >= p.length() + c.length()) {
+ eX = -1;
+ e0440 = -1;
+ } else if (full.charAt(from) == 'z') {
+ eX = (full.charAt(from + 1) != 'x') ? -1 : from + 1;
+ e0440 = (full.charAt(from + 1) != '\u0440') ? -1 : from + 1;
+ } else {
+ eX = (full.charAt(from) != 'x') ? -1 : from;
+ e0440 = (full.charAt(from) != '\u0440') ? -1 : from;
+ }
+ Assert.assertEquals(eX, $noinline$indexOf(full, 'x', from));
+ Assert.assertEquals(e0440, $noinline$indexOf(full, '\u0440', from));
+ }
+ }
+ }
+ }
+ }
+
+ public static int $noinline$compareTo(String lhs, String rhs) {
+ if (doThrow) { throw new Error(); }
+ return lhs.compareTo(rhs);
+ }
+
+ public static boolean $noinline$equals(String lhs, String rhs) {
+ if (doThrow) { throw new Error(); }
+ return lhs.equals(rhs);
+ }
+
+ public static int $noinline$indexOf(String lhs, int ch) {
+ if (doThrow) { throw new Error(); }
+ return lhs.indexOf(ch);
+ }
+
+ public static int $noinline$indexOf(String lhs, int ch, int fromIndex) {
+ if (doThrow) { throw new Error(); }
+ return lhs.indexOf(ch, fromIndex);
+ }
+
+ public static boolean doThrow = false;
}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 34f8838..3bf7e4b 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -491,6 +491,7 @@
# between those runs to be able to have precise checks.
TEST_ART_BROKEN_JIT_RUN_TESTS := \
137-cfi \
+ 904-object-allocation \
906-iterate-heap \
ifneq (,$(filter jit,$(COMPILER_TYPES)))
diff --git a/tools/ahat/README.txt b/tools/ahat/README.txt
index 8604ff0..dbc1102 100644
--- a/tools/ahat/README.txt
+++ b/tools/ahat/README.txt
@@ -74,7 +74,9 @@
* Instance.isRoot and Instance.getRootTypes.
Release History:
- 0.8 Pending
+ 0.9 Pending
+
+ 0.8 Oct 18, 2016
Show sample path from GC root with field names in place of dominator path.
0.7 Aug 16, 2016
diff --git a/tools/ahat/src/manifest.txt b/tools/ahat/src/manifest.txt
index cac53c5..1993910 100644
--- a/tools/ahat/src/manifest.txt
+++ b/tools/ahat/src/manifest.txt
@@ -1,4 +1,4 @@
Name: ahat/
Implementation-Title: ahat
-Implementation-Version: 0.7
+Implementation-Version: 0.8
Main-Class: com.android.ahat.Main
diff --git a/tools/libcore_failures_concurrent_collector.txt b/tools/libcore_failures_concurrent_collector.txt
deleted file mode 100644
index 0e289a6..0000000
--- a/tools/libcore_failures_concurrent_collector.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * This file contains expectations for ART's buildbot's concurrent collector
- * configurations. The purpose of this file is to temporary and quickly list
- * failing tests and not break the bots on the CC configurations, until they
- * are fixed or until the libcore expectation files get properly updated. The
- * script that uses this file is art/tools/run-libcore-tests.sh.
- *
- * It is also used to enable AOSP experiments, and not mess up with CTS's
- * expectations.
- */
-
-[
-]
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index 01c7f20..41faa69 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -43,10 +43,6 @@
done
expectations="--expectations art/tools/libcore_failures.txt"
-if [ "x$ART_USE_READ_BARRIER" = xtrue ]; then
- # Tolerate some more failures on the concurrent collector configurations.
- expectations="$expectations --expectations art/tools/libcore_failures_concurrent_collector.txt"
-fi
emulator="no"
if [ "$ANDROID_SERIAL" = "emulator-5554" ]; then