Merge "Move x86 constant area code to its own file"
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 02f2e0b..b569f50 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3486,28 +3486,31 @@
if (!klass->IsInterface()) {
// Initialize interfaces with default methods for the JLS.
size_t num_direct_interfaces = klass->NumDirectInterfaces();
- for (size_t i = 0; i < num_direct_interfaces; i++) {
+ // Only setup the (expensive) handle scope if we actually need to.
+ if (UNLIKELY(num_direct_interfaces > 0)) {
StackHandleScope<1> hs_iface(self);
- Handle<mirror::Class> handle_scope_iface(
- hs_iface.NewHandle(mirror::Class::GetDirectInterface(self, klass, i)));
- CHECK(handle_scope_iface.Get() != nullptr);
- CHECK(handle_scope_iface->IsInterface());
- if (handle_scope_iface->HasBeenRecursivelyInitialized()) {
- // We have already done this once for this interface. Skip it.
- continue;
- }
- // We cannot just call initialize class directly because we need to ensure that ALL interfaces
- // with default methods are initialized. Non-default interface initialization will not affect
- // other non-default super-interfaces.
- bool iface_initialized = InitializeDefaultInterfaceRecursive(self,
- handle_scope_iface,
- can_init_statics,
- can_init_parents);
- if (!iface_initialized) {
- ObjectLock<mirror::Class> lock(self, klass);
- // Initialization failed because one of our interfaces with default methods is erroneous.
- mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self);
- return false;
+ MutableHandle<mirror::Class> handle_scope_iface(hs_iface.NewHandle<mirror::Class>(nullptr));
+ for (size_t i = 0; i < num_direct_interfaces; i++) {
+ handle_scope_iface.Assign(mirror::Class::GetDirectInterface(self, klass, i));
+ CHECK(handle_scope_iface.Get() != nullptr);
+ CHECK(handle_scope_iface->IsInterface());
+ if (handle_scope_iface->HasBeenRecursivelyInitialized()) {
+ // We have already done this for this interface. Skip it.
+ continue;
+ }
+ // We cannot just call initialize class directly because we need to ensure that ALL
+ // interfaces with default methods are initialized. Non-default interface initialization
+ // will not affect other non-default super-interfaces.
+ bool iface_initialized = InitializeDefaultInterfaceRecursive(self,
+ handle_scope_iface,
+ can_init_statics,
+ can_init_parents);
+ if (!iface_initialized) {
+ ObjectLock<mirror::Class> lock(self, klass);
+ // Initialization failed because one of our interfaces with default methods is erroneous.
+ mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self);
+ return false;
+ }
}
}
}
@@ -3609,18 +3612,22 @@
bool can_init_parents) {
CHECK(iface->IsInterface());
size_t num_direct_ifaces = iface->NumDirectInterfaces();
- // First we initialize all of iface's super-interfaces recursively.
- for (size_t i = 0; i < num_direct_ifaces; i++) {
- mirror::Class* super_iface = mirror::Class::GetDirectInterface(self, iface, i);
- if (!super_iface->HasBeenRecursivelyInitialized()) {
- // Recursive step
- StackHandleScope<1> hs(self);
- Handle<mirror::Class> handle_super_iface(hs.NewHandle(super_iface));
- if (!InitializeDefaultInterfaceRecursive(self,
- handle_super_iface,
- can_init_statics,
- can_init_parents)) {
- return false;
+ // Only create the (expensive) handle scope if we need it.
+ if (UNLIKELY(num_direct_ifaces > 0)) {
+ StackHandleScope<1> hs(self);
+ MutableHandle<mirror::Class> handle_super_iface(hs.NewHandle<mirror::Class>(nullptr));
+ // First we initialize all of iface's super-interfaces recursively.
+ for (size_t i = 0; i < num_direct_ifaces; i++) {
+ mirror::Class* super_iface = mirror::Class::GetDirectInterface(self, iface, i);
+ if (!super_iface->HasBeenRecursivelyInitialized()) {
+ // Recursive step
+ handle_super_iface.Assign(super_iface);
+ if (!InitializeDefaultInterfaceRecursive(self,
+ handle_super_iface,
+ can_init_statics,
+ can_init_parents)) {
+ return false;
+ }
}
}
}
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 1a6bead..8e6eae9 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -74,7 +74,7 @@
const OatFile* oat_file,
std::vector<std::unique_ptr<const DexFile>>& vec) {
// Add one for the oat file.
- jlongArray long_array = env->NewLongArray(static_cast<jsize>(1u + vec.size()));
+ jlongArray long_array = env->NewLongArray(static_cast<jsize>(kDexFileIndexStart + vec.size()));
if (env->ExceptionCheck() == JNI_TRUE) {
return nullptr;
}
@@ -230,7 +230,8 @@
}
}
- if (all_deleted) {
+ // oat_file can be null if we are running without dex2oat.
+ if (all_deleted && oat_file != nullptr) {
// If all of the dex files are no longer in use we can unmap the corresponding oat file.
VLOG(class_linker) << "Unregistering " << oat_file;
runtime->GetOatFileManager().UnRegisterAndDeleteOatFile(oat_file);
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 3371a39..9eee156 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -22,7 +22,7 @@
#include "base/logging.h"
#include "base/stl_util.h"
-#include "dex_file.h"
+#include "dex_file-inl.h"
#include "gc/space/image_space.h"
#include "oat_file_assistant.h"
#include "thread-inl.h"
@@ -30,7 +30,9 @@
namespace art {
// For b/21333911.
-static constexpr bool kDuplicateClassesCheck = false;
+// Only enabled for debug builds to prevent bit rot. There are too many performance regressions for
+// normal builds.
+static constexpr bool kDuplicateClassesCheck = kIsDebugBuild;
const OatFile* OatFileManager::RegisterOatFile(std::unique_ptr<const OatFile> oat_file) {
WriterMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
@@ -115,9 +117,9 @@
current_class_index_(current_class_index),
from_loaded_oat_(from_loaded_oat) {}
- DexFileAndClassPair(DexFileAndClassPair&& rhs) = default;
+ DexFileAndClassPair(const DexFileAndClassPair& rhs) = default;
- DexFileAndClassPair& operator=(DexFileAndClassPair&& rhs) = default;
+ DexFileAndClassPair& operator=(const DexFileAndClassPair& rhs) = default;
const char* GetCachedDescriptor() const {
return cached_descriptor_;
@@ -139,7 +141,7 @@
void Next() {
++current_class_index_;
- cached_descriptor_ = nullptr;
+ cached_descriptor_ = GetClassDescriptor(dex_file_.get(), current_class_index_);
}
size_t GetCurrentClassIndex() const {
@@ -162,7 +164,7 @@
}
const char* cached_descriptor_;
- std::unique_ptr<const DexFile> dex_file_;
+ std::shared_ptr<const DexFile> dex_file_;
size_t current_class_index_;
bool from_loaded_oat_; // We only need to compare mismatches between what we load now
// and what was loaded before. Any old duplicates must have been
@@ -215,8 +217,17 @@
// Add dex files from already loaded oat files, but skip boot.
const OatFile* boot_oat = GetBootOatFile();
+ // The same OatFile can be loaded multiple times at different addresses. In this case, we don't
+ // need to check both against each other since they would have resolved the same way at compile
+ // time.
+ std::unordered_set<std::string> unique_locations;
for (const std::unique_ptr<const OatFile>& loaded_oat_file : oat_files_) {
- if (loaded_oat_file.get() != boot_oat) {
+ DCHECK_NE(loaded_oat_file.get(), oat_file);
+ const std::string& location = loaded_oat_file->GetLocation();
+ if (loaded_oat_file.get() != boot_oat &&
+ location != oat_file->GetLocation() &&
+ unique_locations.find(location) == unique_locations.end()) {
+ unique_locations.insert(location);
AddDexFilesFromOat(loaded_oat_file.get(), /*already_loaded*/true, &queue);
}
}
@@ -232,12 +243,12 @@
// Now drain the queue.
while (!queue.empty()) {
// Modifying the top element is only safe if we pop right after.
- DexFileAndClassPair compare_pop(std::move(const_cast<DexFileAndClassPair&>(queue.top())));
+ DexFileAndClassPair compare_pop(queue.top());
queue.pop();
// Compare against the following elements.
while (!queue.empty()) {
- DexFileAndClassPair top(std::move(const_cast<DexFileAndClassPair&>(queue.top())));
+ DexFileAndClassPair top(queue.top());
if (strcmp(compare_pop.GetCachedDescriptor(), top.GetCachedDescriptor()) == 0) {
// Same descriptor. Check whether it's crossing old-oat-files to new-oat-files.
@@ -249,7 +260,6 @@
top.GetDexFile()->GetLocation().c_str());
return true;
}
- // Pop it.
queue.pop();
AddNext(&top, &queue);
} else {
diff --git a/runtime/verifier/register_line.cc b/runtime/verifier/register_line.cc
index 33c90e3..02c93cf 100644
--- a/runtime/verifier/register_line.cc
+++ b/runtime/verifier/register_line.cc
@@ -391,6 +391,34 @@
}
}
+// Check whether there is another register in the search map that is locked the same way as the
+// register in the src map. This establishes an alias.
+static bool FindLockAliasedRegister(
+ uint32_t src,
+ const AllocationTrackingSafeMap<uint32_t, uint32_t, kAllocatorTagVerifier>& src_map,
+ const AllocationTrackingSafeMap<uint32_t, uint32_t, kAllocatorTagVerifier>& search_map) {
+ auto it = src_map.find(src);
+ if (it == src_map.end()) {
+ // "Not locked" is trivially aliased.
+ return true;
+ }
+ uint32_t src_lock_levels = it->second;
+ if (src_lock_levels == 0) {
+ // "Not locked" is trivially aliased.
+ return true;
+ }
+
+ // Scan the map for the same value.
+ for (const std::pair<uint32_t, uint32_t>& pair : search_map) {
+ if (pair.first != src && pair.second == src_lock_levels) {
+ return true;
+ }
+ }
+
+ // Nothing found, no alias.
+ return false;
+}
+
bool RegisterLine::MergeRegisters(MethodVerifier* verifier, const RegisterLine* incoming_line) {
bool changed = false;
DCHECK(incoming_line != nullptr);
@@ -417,9 +445,29 @@
size_t depths = reg_to_lock_depths_.count(idx);
size_t incoming_depths = incoming_line->reg_to_lock_depths_.count(idx);
if (depths != incoming_depths) {
- if (depths == 0 || incoming_depths == 0) {
- reg_to_lock_depths_.erase(idx);
- } else {
+ // Stack levels aren't matching. This is potentially bad, as we don't do a
+ // flow-sensitive analysis.
+ // However, this could be an alias of something locked in one path, and the alias was
+ // destroyed in another path. It is fine to drop this as long as there's another alias
+ // for the lock around. The last vanishing alias will then report that things would be
+ // left unlocked. We need to check for aliases for both lock levels.
+ //
+ // Example (lock status in curly braces as pair of register and lock leels):
+ //
+ // lock v1 {v1=1}
+ // | |
+ // v0 = v1 {v0=1, v1=1} v0 = v2 {v1=1}
+ // | |
+ // {v1=1}
+ // // Dropping v0, as the status can't be merged
+ // // but the lock info ("locked at depth 1" and)
+ // // "not locked at all") is available.
+ if (!FindLockAliasedRegister(idx,
+ reg_to_lock_depths_,
+ reg_to_lock_depths_) ||
+ !FindLockAliasedRegister(idx,
+ incoming_line->reg_to_lock_depths_,
+ reg_to_lock_depths_)) {
verifier->Fail(VERIFY_ERROR_LOCKING);
if (kDumpLockFailures) {
LOG(WARNING) << "mismatched stack depths for register v" << idx
@@ -429,20 +477,51 @@
}
break;
}
+ // We found aliases, set this to zero.
+ reg_to_lock_depths_.erase(idx);
} else if (depths > 0) {
// Check whether they're actually the same levels.
uint32_t locked_levels = reg_to_lock_depths_.find(idx)->second;
uint32_t incoming_locked_levels = incoming_line->reg_to_lock_depths_.find(idx)->second;
if (locked_levels != incoming_locked_levels) {
- verifier->Fail(VERIFY_ERROR_LOCKING);
- if (kDumpLockFailures) {
- LOG(WARNING) << "mismatched lock levels for register v" << idx << ": "
- << std::hex << locked_levels << std::dec << " != "
- << std::hex << incoming_locked_levels << std::dec << " in "
- << PrettyMethod(verifier->GetMethodReference().dex_method_index,
- *verifier->GetMethodReference().dex_file);
+ // Lock levels aren't matching. This is potentially bad, as we don't do a
+ // flow-sensitive analysis.
+ // However, this could be an alias of something locked in one path, and the alias was
+ // destroyed in another path. It is fine to drop this as long as there's another alias
+ // for the lock around. The last vanishing alias will then report that things would be
+ // left unlocked. We need to check for aliases for both lock levels.
+ //
+ // Example (lock status in curly braces as pair of register and lock leels):
+ //
+ // lock v1 {v1=1}
+ // lock v2 {v1=1, v2=2}
+ // | |
+ // v0 = v1 {v0=1, v1=1, v2=2} v0 = v2 {v0=2, v1=1, v2=2}
+ // | |
+ // {v1=1, v2=2}
+ // // Dropping v0, as the status can't be
+ // // merged but the lock info ("locked at
+ // // depth 1" and "locked at depth 2") is
+ // // available.
+ if (!FindLockAliasedRegister(idx,
+ reg_to_lock_depths_,
+ reg_to_lock_depths_) ||
+ !FindLockAliasedRegister(idx,
+ incoming_line->reg_to_lock_depths_,
+ reg_to_lock_depths_)) {
+ // No aliases for both current and incoming, we'll lose information.
+ verifier->Fail(VERIFY_ERROR_LOCKING);
+ if (kDumpLockFailures) {
+ LOG(WARNING) << "mismatched lock levels for register v" << idx << ": "
+ << std::hex << locked_levels << std::dec << " != "
+ << std::hex << incoming_locked_levels << std::dec << " in "
+ << PrettyMethod(verifier->GetMethodReference().dex_method_index,
+ *verifier->GetMethodReference().dex_file);
+ }
+ break;
}
- break;
+ // We found aliases, set this to zero.
+ reg_to_lock_depths_.erase(idx);
}
}
}
diff --git a/test/088-monitor-verification/src/TwoPath.java b/test/088-monitor-verification/src/TwoPath.java
index 2542de7..bdc15ad 100644
--- a/test/088-monitor-verification/src/TwoPath.java
+++ b/test/088-monitor-verification/src/TwoPath.java
@@ -31,6 +31,8 @@
* Conditionally uses one of the synchronized objects.
*/
public static void twoPath(Object obj1, Object obj2, int x) {
+ Main.assertIsManaged();
+
Object localObj;
synchronized (obj1) {
diff --git a/test/131-structural-change/expected.txt b/test/131-structural-change/expected.txt
index cc7713d..1d19278 100644
--- a/test/131-structural-change/expected.txt
+++ b/test/131-structural-change/expected.txt
@@ -1,2 +1,3 @@
+JNI_OnLoad called
Should really reach here.
Done.
diff --git a/test/131-structural-change/src/Main.java b/test/131-structural-change/src/Main.java
index 6cbbd12..c748899 100644
--- a/test/131-structural-change/src/Main.java
+++ b/test/131-structural-change/src/Main.java
@@ -35,7 +35,7 @@
e.printStackTrace(System.out);
}
- boolean haveOatFile = hasOat();
+ boolean haveOatFile = hasOatFile();
boolean gotError = false;
try {
Class<?> bClass = getClass().getClassLoader().loadClass("B");
@@ -45,10 +45,10 @@
e.printStackTrace(System.out);
}
if (haveOatFile ^ gotError) {
- System.out.println("Did not get expected error.");
+ System.out.println("Did not get expected error. " + haveOatFile + " " + gotError);
}
System.out.println("Done.");
}
- private native static boolean hasOat();
+ private native static boolean hasOatFile();
}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index ad64b68..e114a2e 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -214,19 +214,24 @@
055-enum-performance \
133-static-invoke-super
+# disable timing sensitive tests on "dist" builds.
+ifdef dist_goal
+ 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), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), $(TEST_ART_TIMING_SENSITIVE_RUN_TESTS), $(ALL_ADDRESS_SIZES))
+endif
+
# Tests that require python3.
TEST_ART_PYTHON3_DEPENDENCY_RUN_TESTS := \
960-default-smali \
961-default-iface-resolution-generated \
964-default-iface-init-generated \
-# disable timing sensitive tests on "dist" builds.
-ifdef dist_goal
- 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), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), $(TEST_ART_TIMING_SENSITIVE_RUN_TESTS), $(ALL_ADDRESS_SIZES))
+# Check if we have python3 to run our tests.
+ifeq ($(wildcard /usr/bin/python3),)
+ $(warning "No python3 found. Disabling tests: $(TEST_ART_PYTHON3_DEPENDENCY_RUN_TESTS)")
- # Currently disable tsts requiring python3.
+ # Currently disable tests requiring python3 when it is not installed.
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), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), $(TEST_ART_PYTHON3_DEPENDENCY_RUN_TESTS), $(ALL_ADDRESS_SIZES))
@@ -324,13 +329,15 @@
$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),130-hprof,$(ALL_ADDRESS_SIZES))
# 131 is an old test. The functionality has been implemented at an earlier stage and is checked
-# in tests 138.
-ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+# in tests 138. Blacklisted for debug builds since these builds have duplicate classes checks which
+# punt to interpreter.
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),debug,$(PREBUILD_TYPES), \
$(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES), \
$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),131-structural-change,$(ALL_ADDRESS_SIZES))
-# 138-duplicate-classes-check. Turned off temporarily, b/21333911.
-ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+# 138-duplicate-classes-check. Turned on for debug builds since debug builds have duplicate classes
+# checks enabled, b/2133391.
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),ndebug,$(PREBUILD_TYPES), \
$(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES), \
$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),138-duplicate-classes-check,$(ALL_ADDRESS_SIZES))