Merge "Remove bogus DCHECK."
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 5fa58f7..90b8fdb 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -694,25 +694,52 @@
std::unordered_set<uint32_t> direct_method_indexes;
// These calls use the raw access flags to check whether the whole dex field is valid.
-
+ uint32_t prev_index = 0;
for (; it.HasNextStaticField(); it.Next()) {
- if (!CheckClassDataItemField(it.GetMemberIndex(), it.GetRawMemberAccessFlags(), true)) {
+ uint32_t curr_index = it.GetMemberIndex();
+ if (curr_index < prev_index) {
+ ErrorStringPrintf("out-of-order static field indexes %d and %d", prev_index, curr_index);
+ return false;
+ }
+ prev_index = curr_index;
+ if (!CheckClassDataItemField(curr_index, it.GetRawMemberAccessFlags(), true)) {
return false;
}
}
+ prev_index = 0;
for (; it.HasNextInstanceField(); it.Next()) {
- if (!CheckClassDataItemField(it.GetMemberIndex(), it.GetRawMemberAccessFlags(), false)) {
+ uint32_t curr_index = it.GetMemberIndex();
+ if (curr_index < prev_index) {
+ ErrorStringPrintf("out-of-order instance field indexes %d and %d", prev_index, curr_index);
+ return false;
+ }
+ prev_index = curr_index;
+ if (!CheckClassDataItemField(curr_index, it.GetRawMemberAccessFlags(), false)) {
return false;
}
}
+ prev_index = 0;
for (; it.HasNextDirectMethod(); it.Next()) {
- if (!CheckClassDataItemMethod(it.GetMemberIndex(), it.GetRawMemberAccessFlags(),
+ uint32_t curr_index = it.GetMemberIndex();
+ if (curr_index < prev_index) {
+ ErrorStringPrintf("out-of-order direct method indexes %d and %d", prev_index, curr_index);
+ return false;
+ }
+ prev_index = curr_index;
+ if (!CheckClassDataItemMethod(curr_index, it.GetRawMemberAccessFlags(),
it.GetMethodCodeItemOffset(), direct_method_indexes, true)) {
return false;
}
}
+ prev_index = 0;
for (; it.HasNextVirtualMethod(); it.Next()) {
- if (!CheckClassDataItemMethod(it.GetMemberIndex(), it.GetRawMemberAccessFlags(),
+ uint32_t curr_index = it.GetMemberIndex();
+ if (curr_index < prev_index) {
+ ErrorStringPrintf("out-of-order virtual method indexes %d and %d", prev_index, curr_index);
+ return false;
+ }
+ prev_index = curr_index;
+ if (!CheckClassDataItemMethod(curr_index, it.GetRawMemberAccessFlags(),
it.GetMethodCodeItemOffset(), direct_method_indexes, false)) {
return false;
}
diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc
index f32d5a1..8ba6172 100644
--- a/runtime/hprof/hprof.cc
+++ b/runtime/hprof/hprof.cc
@@ -1255,15 +1255,16 @@
size_t size_patch_offset = output_->Length();
__ AddU4(0x77777777);
- // Write the instance data; fields for this class, followed by super class fields,
- // and so on. Don't write the klass or monitor fields of Object.class.
- mirror::Class* orig_klass = klass;
+ // What we will use for the string value if the object is a string.
+ mirror::Object* string_value = nullptr;
+
+ // Write the instance data; fields for this class, followed by super class fields, and so on.
do {
- int ifieldCount = klass->NumInstanceFields();
- for (int i = 0; i < ifieldCount; ++i) {
+ const size_t instance_fields = klass->NumInstanceFields();
+ for (size_t i = 0; i < instance_fields; ++i) {
ArtField* f = klass->GetInstanceField(i);
size_t size;
- auto t = SignatureToBasicTypeAndSize(f->GetTypeDescriptor(), &size);
+ HprofBasicType t = SignatureToBasicTypeAndSize(f->GetTypeDescriptor(), &size);
switch (t) {
case hprof_basic_byte:
__ AddU1(f->GetByte(obj));
@@ -1288,34 +1289,35 @@
break;
}
}
+ // Add value field for String if necessary.
+ if (klass->IsStringClass()) {
+ mirror::String* s = obj->AsString();
+ if (s->GetLength() == 0) {
+ // If string is empty, use an object-aligned address within the string for the value.
+ string_value = reinterpret_cast<mirror::Object*>(
+ reinterpret_cast<uintptr_t>(s) + kObjectAlignment);
+ } else {
+ string_value = reinterpret_cast<mirror::Object*>(s->GetValue());
+ }
+ __ AddObjectId(string_value);
+ }
klass = klass->GetSuperClass();
} while (klass != nullptr);
+ // Patch the instance field length.
+ __ UpdateU4(size_patch_offset, output_->Length() - (size_patch_offset + 4));
+
// Output native value character array for strings.
- if (orig_klass->IsStringClass()) {
+ CHECK_EQ(obj->IsString(), string_value != nullptr);
+ if (string_value != nullptr) {
mirror::String* s = obj->AsString();
- mirror::Object* value;
- if (s->GetLength() == 0) {
- // If string is empty, use an object-aligned address within the string for the value.
- value = reinterpret_cast<mirror::Object*>(reinterpret_cast<uintptr_t>(s) + kObjectAlignment);
- } else {
- value = reinterpret_cast<mirror::Object*>(s->GetValue());
- }
- __ AddObjectId(value);
-
- // Patch the instance field length.
- __ UpdateU4(size_patch_offset, output_->Length() - (size_patch_offset + 4));
-
__ AddU1(HPROF_PRIMITIVE_ARRAY_DUMP);
- __ AddObjectId(value);
+ __ AddObjectId(string_value);
__ AddStackTraceSerialNumber(LookupStackTraceSerialNumber(obj));
__ AddU4(s->GetLength());
__ AddU1(hprof_basic_char);
__ AddU2List(s->GetValue(), s->GetLength());
- } else {
- // Patch the instance field length.
- __ UpdateU4(size_patch_offset, output_->Length() - (size_patch_offset + 4));
}
}
diff --git a/runtime/indenter.h b/runtime/indenter.h
index d055d4e..38b398d 100644
--- a/runtime/indenter.h
+++ b/runtime/indenter.h
@@ -27,45 +27,76 @@
class Indenter : public std::streambuf {
public:
Indenter(std::streambuf* out, char text, size_t count)
- : indent_next_(true), out_sbuf_(out), text_(text), count_(count) {}
+ : indent_next_(true), out_sbuf_(out),
+ text_{text, text, text, text, text, text, text, text}, // NOLINT(whitespace/braces)
+ count_(count) {}
private:
- int_type overflow(int_type c) {
+ std::streamsize xsputn(const char* s, std::streamsize n) OVERRIDE {
+ std::streamsize result = n; // Aborts on failure.
+ const char* eol = static_cast<const char*>(memchr(s, '\n', n));
+ while (eol != nullptr) {
+ size_t to_write = eol + 1 - s;
+ Write(s, to_write);
+ s += to_write;
+ n -= to_write;
+ indent_next_ = true;
+ eol = static_cast<const char*>(memchr(s, '\n', n));
+ }
+ if (n != 0u) {
+ Write(s, n);
+ }
+ return result;
+ }
+
+ int_type overflow(int_type c) OVERRIDE {
if (UNLIKELY(c == std::char_traits<char>::eof())) {
out_sbuf_->pubsync();
return c;
}
- if (indent_next_) {
- for (size_t i = 0; i < count_; ++i) {
- int_type r = out_sbuf_->sputc(text_);
- if (UNLIKELY(r != text_)) {
- out_sbuf_->pubsync();
- r = out_sbuf_->sputc(text_);
- CHECK_EQ(r, text_) << "Error writing to buffer. Disk full?";
- }
- }
- }
+ char data[1] = { static_cast<char>(c) };
+ Write(data, 1u);
indent_next_ = (c == '\n');
- int_type r = out_sbuf_->sputc(c);
- if (UNLIKELY(r != c)) {
- out_sbuf_->pubsync();
- r = out_sbuf_->sputc(c);
- CHECK_EQ(r, c) << "Error writing to buffer. Disk full?";
- }
- return r;
+ return c;
}
int sync() {
return out_sbuf_->pubsync();
}
+ void Write(const char* s, std::streamsize n) {
+ if (indent_next_) {
+ size_t remaining = count_;
+ while (remaining != 0u) {
+ size_t to_write = std::min(remaining, sizeof(text_));
+ RawWrite(text_, to_write);
+ remaining -= to_write;
+ }
+ indent_next_ = false;
+ }
+ RawWrite(s, n);
+ }
+
+ void RawWrite(const char* s, std::streamsize n) {
+ size_t written = out_sbuf_->sputn(s, n);
+ s += written;
+ n -= written;
+ while (n != 0u) {
+ out_sbuf_->pubsync();
+ written = out_sbuf_->sputn(s, n);
+ CHECK_NE(written, 0u) << "Error writing to buffer. Disk full?";
+ s += written;
+ n -= written;
+ }
+ }
+
bool indent_next_;
// Buffer to write output to.
std::streambuf* const out_sbuf_;
// Text output as indent.
- const char text_;
+ const char text_[8];
// Number of times text is output.
const size_t count_;
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index ddd1caa..5d685da 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2402,9 +2402,9 @@
StackHandleScope<1> hs(self_);
mirror::Class* return_type_class = called_method->GetReturnType(can_load_classes_);
if (return_type_class != nullptr) {
- return_type = ®_types_.FromClass(called_method->GetReturnTypeDescriptor(),
- return_type_class,
- return_type_class->CannotBeAssignedFromOtherTypes());
+ return_type = &FromClass(called_method->GetReturnTypeDescriptor(),
+ return_type_class,
+ return_type_class->CannotBeAssignedFromOtherTypes());
} else {
DCHECK(!can_load_classes_ || self_->IsExceptionPending());
self_->ClearException();
@@ -2444,9 +2444,9 @@
StackHandleScope<1> hs(self_);
mirror::Class* return_type_class = called_method->GetReturnType(can_load_classes_);
if (return_type_class != nullptr) {
- return_type = ®_types_.FromClass(return_type_descriptor,
- return_type_class,
- return_type_class->CannotBeAssignedFromOtherTypes());
+ return_type = &FromClass(return_type_descriptor,
+ return_type_class,
+ return_type_class->CannotBeAssignedFromOtherTypes());
} else {
DCHECK(!can_load_classes_ || self_->IsExceptionPending());
self_->ClearException();
@@ -3195,7 +3195,7 @@
const RegType& referrer = GetDeclaringClass();
mirror::Class* klass = dex_cache_->GetResolvedType(class_idx);
const RegType& result = klass != nullptr ?
- reg_types_.FromClass(descriptor, klass, klass->CannotBeAssignedFromOtherTypes()) :
+ FromClass(descriptor, klass, klass->CannotBeAssignedFromOtherTypes()) :
reg_types_.FromDescriptor(GetClassLoader(), descriptor, false);
if (result.IsConflict()) {
Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "accessing broken descriptor '" << descriptor
@@ -3414,8 +3414,8 @@
if (res_method != nullptr && !res_method->IsMiranda()) {
mirror::Class* klass = res_method->GetDeclaringClass();
std::string temp;
- res_method_class = ®_types_.FromClass(klass->GetDescriptor(&temp), klass,
- klass->CannotBeAssignedFromOtherTypes());
+ res_method_class = &FromClass(klass->GetDescriptor(&temp), klass,
+ klass->CannotBeAssignedFromOtherTypes());
} else {
const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const uint16_t class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
@@ -3672,8 +3672,7 @@
mirror::Class* klass = res_method->GetDeclaringClass();
std::string temp;
const RegType& res_method_class =
- reg_types_.FromClass(klass->GetDescriptor(&temp), klass,
- klass->CannotBeAssignedFromOtherTypes());
+ FromClass(klass->GetDescriptor(&temp), klass, klass->CannotBeAssignedFromOtherTypes());
if (!res_method_class.IsAssignableFrom(actual_arg_type)) {
Fail(actual_arg_type.IsUnresolvedTypes() ? VERIFY_ERROR_NO_CLASS :
VERIFY_ERROR_BAD_CLASS_SOFT) << "'this' argument '" << actual_arg_type
@@ -3983,8 +3982,8 @@
} else {
mirror::Class* klass = field->GetDeclaringClass();
const RegType& field_klass =
- reg_types_.FromClass(dex_file_->GetFieldDeclaringClassDescriptor(field_id),
- klass, klass->CannotBeAssignedFromOtherTypes());
+ FromClass(dex_file_->GetFieldDeclaringClassDescriptor(field_id),
+ klass, klass->CannotBeAssignedFromOtherTypes());
if (obj_type.IsUninitializedTypes() &&
(!IsConstructor() || GetDeclaringClass().Equals(obj_type) ||
!field_klass.Equals(GetDeclaringClass()))) {
@@ -4034,8 +4033,8 @@
mirror::Class* field_type_class =
can_load_classes_ ? field->GetType<true>() : field->GetType<false>();
if (field_type_class != nullptr) {
- field_type = ®_types_.FromClass(field->GetTypeDescriptor(), field_type_class,
- field_type_class->CannotBeAssignedFromOtherTypes());
+ field_type = &FromClass(field->GetTypeDescriptor(), field_type_class,
+ field_type_class->CannotBeAssignedFromOtherTypes());
} else {
DCHECK(!can_load_classes_ || self_->IsExceptionPending());
self_->ClearException();
@@ -4146,8 +4145,8 @@
field->GetType<false>();
if (field_type_class != nullptr) {
- field_type = ®_types_.FromClass(field->GetTypeDescriptor(), field_type_class,
- field_type_class->CannotBeAssignedFromOtherTypes());
+ field_type = &FromClass(field->GetTypeDescriptor(), field_type_class,
+ field_type_class->CannotBeAssignedFromOtherTypes());
} else {
Thread* self = Thread::Current();
DCHECK(!can_load_classes_ || self->IsExceptionPending());
@@ -4339,9 +4338,9 @@
if (mirror_method_ != nullptr) {
mirror::Class* return_type_class = mirror_method_->GetReturnType(can_load_classes_);
if (return_type_class != nullptr) {
- return_type_ = ®_types_.FromClass(mirror_method_->GetReturnTypeDescriptor(),
- return_type_class,
- return_type_class->CannotBeAssignedFromOtherTypes());
+ return_type_ = &FromClass(mirror_method_->GetReturnTypeDescriptor(),
+ return_type_class,
+ return_type_class->CannotBeAssignedFromOtherTypes());
} else {
DCHECK(!can_load_classes_ || self_->IsExceptionPending());
self_->ClearException();
@@ -4365,8 +4364,8 @@
= dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_));
if (mirror_method_ != nullptr) {
mirror::Class* klass = mirror_method_->GetDeclaringClass();
- declaring_class_ = ®_types_.FromClass(descriptor, klass,
- klass->CannotBeAssignedFromOtherTypes());
+ declaring_class_ = &FromClass(descriptor, klass,
+ klass->CannotBeAssignedFromOtherTypes());
} else {
declaring_class_ = ®_types_.FromDescriptor(GetClassLoader(), descriptor, false);
}
@@ -4466,5 +4465,17 @@
reg_types_.VisitRoots(visitor, root_info);
}
+const RegType& MethodVerifier::FromClass(const char* descriptor,
+ mirror::Class* klass,
+ bool precise) {
+ DCHECK(klass != nullptr);
+ if (precise && !klass->IsInstantiable() && !klass->IsPrimitive()) {
+ Fail(VerifyError::VERIFY_ERROR_NO_CLASS) << "Could not create precise reference for "
+ << "non-instantiable klass " << descriptor;
+ precise = false;
+ }
+ return reg_types_.FromClass(descriptor, klass, precise);
+}
+
} // namespace verifier
} // namespace art
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 824daf6..994616f 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -670,6 +670,14 @@
const RegType& DetermineCat1Constant(int32_t value, bool precise)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Try to create a register type from the given class. In case a precise type is requested, but
+ // the class is not instantiable, a soft error (of type NO_CLASS) will be enqueued and a
+ // non-precise reference will be returned.
+ // Note: we reuse NO_CLASS as this will throw an exception at runtime, when the failing class is
+ // actually touched.
+ const RegType& FromClass(const char* descriptor, mirror::Class* klass, bool precise)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// The thread we're verifying on.
Thread* const self_;
diff --git a/test/496-checker-inlining-and-class-loader/expected.txt b/test/496-checker-inlining-and-class-loader/expected.txt
index c6fcb51..312c28f 100644
--- a/test/496-checker-inlining-and-class-loader/expected.txt
+++ b/test/496-checker-inlining-and-class-loader/expected.txt
@@ -1,4 +1,4 @@
Request for LoadedByMyClassLoader
-Request for Main
+Request for FirstSeenByMyClassLoader
In between the two calls.
In $noinline$bar
diff --git a/test/496-checker-inlining-and-class-loader/src/FirstSeenByMyClassLoader.java b/test/496-checker-inlining-and-class-loader/src/FirstSeenByMyClassLoader.java
new file mode 100644
index 0000000..e97b4e3
--- /dev/null
+++ b/test/496-checker-inlining-and-class-loader/src/FirstSeenByMyClassLoader.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+public class FirstSeenByMyClassLoader {
+ public static void $inline$bar() {
+ }
+
+ public static void $noinline$bar() {
+ try {
+ System.out.println("In $noinline$bar");
+ } catch (Throwable t) { /* Ignore */ }
+ }
+}
diff --git a/test/496-checker-inlining-and-class-loader/src/Main.java b/test/496-checker-inlining-and-class-loader/src/Main.java
index 4f23eec..39c031a 100644
--- a/test/496-checker-inlining-and-class-loader/src/Main.java
+++ b/test/496-checker-inlining-and-class-loader/src/Main.java
@@ -82,7 +82,7 @@
/// CHECK-START: void LoadedByMyClassLoader.bar() inliner (after)
/// CHECK: LoadClass
/// CHECK-NEXT: ClinitCheck
- /* We inlined Main.$inline$bar */
+ /* We inlined FirstSeenByMyClassLoader.$inline$bar */
/// CHECK-NEXT: LoadClass
/// CHECK-NEXT: ClinitCheck
/// CHECK-NEXT: StaticFieldGet
@@ -91,7 +91,7 @@
/// CHECK-NEXT: InvokeVirtual
/// CHECK-START: void LoadedByMyClassLoader.bar() register (before)
- /* Load and initialize Main */
+ /* Load and initialize FirstSeenByMyClassLoader */
/// CHECK: LoadClass gen_clinit_check:true
/* Load and initialize System */
/// CHECK-NEXT: LoadClass gen_clinit_check:true
@@ -100,9 +100,9 @@
/// CHECK-NEXT: NullCheck
/// CHECK-NEXT: InvokeVirtual
public static void bar() {
- Main.$inline$bar();
+ FirstSeenByMyClassLoader.$inline$bar();
System.out.println("In between the two calls.");
- Main.$noinline$bar();
+ FirstSeenByMyClassLoader.$noinline$bar();
}
}
@@ -113,13 +113,4 @@
Method m = foo.getDeclaredMethod("bar");
m.invoke(null);
}
-
- public static void $inline$bar() {
- }
-
- public static void $noinline$bar() {
- try {
- System.out.println("In $noinline$bar");
- } catch (Throwable t) { /* Ignore */ }
- }
}
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index 1b8748b..e28de09 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -84,7 +84,7 @@
# Increase the timeout, as vogar cannot set individual test
# timeout when being asked to run packages, and some tests go above
# the default timeout.
- vogar_args="$vogar_args --timeout 180"
+ vogar_args="$vogar_args --timeout 240"
shift
elif [[ "$1" == "" ]]; then
break