diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-11-17 15:57:28 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-11-17 16:14:05 +0000 |
commit | 786b0d588ae72cefea69731c517c8c446a5e5d19 (patch) | |
tree | a0f8322798dce8f92a9298340a606bdd257df81f | |
parent | c46296ca738801d1e7bbfcffb7873ed72ef80e10 (diff) | |
parent | 3cb3670d162285c6e4304f1f9f85f7c3ff78150d (diff) | |
download | art-android12-mainline-art-release.tar.gz |
Make change and version bump to aml_art_311310000 for mainline module file: build/apex/manifest-art.jsonandroid-mainline-12.0.0_r42android12-mainline-art-release
Change-Id: I74e9ef32d76376ff9640c7876c1805bdd0b90dfc
35 files changed, 438 insertions, 84 deletions
diff --git a/build/Android.bp b/build/Android.bp index 21858db130..d4be1e2a09 100644 --- a/build/Android.bp +++ b/build/Android.bp @@ -257,7 +257,7 @@ art_module_art_global_defaults { "-extra-arg=-Wno-unreachable-code", ], - min_sdk_version: "S", + min_sdk_version: "31", } // Used to generate binaries that can be backed by transparent hugepages. @@ -326,7 +326,7 @@ art_debug_defaults { }, }, - min_sdk_version: "S", + min_sdk_version: "31", } // Use this to enable a cc_* module only when building ART from sources. diff --git a/build/apex/Android.bp b/build/apex/Android.bp index c5acc915d4..dfef28df62 100644 --- a/build/apex/Android.bp +++ b/build/apex/Android.bp @@ -271,7 +271,7 @@ apex_defaults { enabled: false, }, }, - min_sdk_version: "S", + min_sdk_version: "31", // Indicates that pre-installed version of this apex can be compressed. // Whether it actually will be compressed is controlled on per-device basis. compressible: true, diff --git a/build/apex/manifest-art.json b/build/apex/manifest-art.json index 8136f1b2be..f23b9f3769 100644 --- a/build/apex/manifest-art.json +++ b/build/apex/manifest-art.json @@ -1,6 +1,6 @@ { "name": "com.android.art", - "version": 311214000, + "version": 311310000, "provideNativeLibs": [ "libjdwp.so" ], diff --git a/cmdline/Android.bp b/cmdline/Android.bp index fdc762caaa..b68c23cff6 100644 --- a/cmdline/Android.bp +++ b/cmdline/Android.bp @@ -33,7 +33,7 @@ cc_library_headers { "com.android.art.debug", "com.android.art", ], - min_sdk_version: "S", + min_sdk_version: "31", } art_cc_defaults { diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index e1a4718140..92b43fb927 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -4636,6 +4636,7 @@ void CodeGeneratorARM64::GenerateStaticOrDirectCall( switch (invoke->GetCodePtrLocation()) { case CodePtrLocation::kCallSelf: { + DCHECK(!GetGraph()->HasShouldDeoptimizeFlag()); // Use a scope to help guarantee that `RecordPcInfo()` records the correct pc. ExactAssemblyScope eas(GetVIXLAssembler(), kInstructionSize, diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index bca093606d..b24dca9cb2 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -9253,6 +9253,7 @@ void CodeGeneratorARMVIXL::GenerateStaticOrDirectCall( switch (invoke->GetCodePtrLocation()) { case CodePtrLocation::kCallSelf: { + DCHECK(!GetGraph()->HasShouldDeoptimizeFlag()); // Use a scope to help guarantee that `RecordPcInfo()` records the correct pc. ExactAssemblyScope aas(GetVIXLAssembler(), vixl32::k32BitT32InstructionSizeInBytes, diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 4fc29fcb0c..099d84d9a6 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -5280,6 +5280,7 @@ void CodeGeneratorX86::GenerateStaticOrDirectCall( switch (invoke->GetCodePtrLocation()) { case CodePtrLocation::kCallSelf: + DCHECK(!GetGraph()->HasShouldDeoptimizeFlag()); __ call(GetFrameEntryLabel()); RecordPcInfo(invoke, invoke->GetDexPc(), slow_path); break; diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index d54484c065..9541933a2d 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1077,6 +1077,7 @@ void CodeGeneratorX86_64::GenerateStaticOrDirectCall( switch (invoke->GetCodePtrLocation()) { case CodePtrLocation::kCallSelf: + DCHECK(!GetGraph()->HasShouldDeoptimizeFlag()); __ call(&frame_entry_label_); RecordPcInfo(invoke, invoke->GetDexPc(), slow_path); break; diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc index 722cc83872..b7670329e6 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -3889,7 +3889,7 @@ bool LoadStoreElimination::Run(bool enable_partial_lse) { stats_, &allocator, enable_partial_lse ? LoadStoreAnalysisType::kFull - : LoadStoreAnalysisType::kNoPredicatedInstructions); + : LoadStoreAnalysisType::kBasic); lsa.Run(); const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector(); if (heap_location_collector.GetNumberOfHeapLocations() == 0) { diff --git a/compiler/optimizing/load_store_elimination_test.cc b/compiler/optimizing/load_store_elimination_test.cc index 812a32aeec..01a00d0c4a 100644 --- a/compiler/optimizing/load_store_elimination_test.cc +++ b/compiler/optimizing/load_store_elimination_test.cc @@ -4532,7 +4532,8 @@ TEST_F(LoadStoreEliminationTest, PartialLoadPreserved3) { // // DO NOT ELIMINATE // return obj.field; // EXIT -TEST_F(LoadStoreEliminationTest, PartialLoadPreserved4) { +// Disabled due to b/205813546. +TEST_F(LoadStoreEliminationTest, DISABLED_PartialLoadPreserved4) { ScopedObjectAccess soa(Thread::Current()); VariableSizedHandleScope vshs(soa.Self()); CreateGraph(&vshs); @@ -4724,7 +4725,8 @@ TEST_F(LoadStoreEliminationTest, PartialLoadPreserved5) { // EXIT // ELIMINATE // return obj.field -TEST_F(LoadStoreEliminationTest, PartialLoadPreserved6) { +// Disabled due to b/205813546. +TEST_F(LoadStoreEliminationTest, DISABLED_PartialLoadPreserved6) { CreateGraph(); AdjacencyListGraph blks(SetupFromAdjacencyList("entry", "exit", diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 939c49f9a6..5a62580fac 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -4932,7 +4932,18 @@ class HInvokeStaticOrDirect final : public HInvoke { } MethodLoadKind GetMethodLoadKind() const { return dispatch_info_.method_load_kind; } - CodePtrLocation GetCodePtrLocation() const { return dispatch_info_.code_ptr_location; } + CodePtrLocation GetCodePtrLocation() const { + // We do CHA analysis after sharpening. When a method has CHA inlining, it + // cannot call itself, as if the CHA optmization is invalid we want to make + // sure the method is never executed again. So, while sharpening can return + // kCallSelf, we bypass it here if there is a CHA optimization. + if (dispatch_info_.code_ptr_location == CodePtrLocation::kCallSelf && + GetBlock()->GetGraph()->HasShouldDeoptimizeFlag()) { + return CodePtrLocation::kCallArtMethod; + } else { + return dispatch_info_.code_ptr_location; + } + } bool IsRecursive() const { return GetMethodLoadKind() == MethodLoadKind::kRecursive; } bool IsStringInit() const { return GetMethodLoadKind() == MethodLoadKind::kStringInit; } bool HasMethodAddress() const { return GetMethodLoadKind() == MethodLoadKind::kJitDirectAddress; } diff --git a/dexoptanalyzer/Android.bp b/dexoptanalyzer/Android.bp index a66bd290fb..c72ab8a9a2 100644 --- a/dexoptanalyzer/Android.bp +++ b/dexoptanalyzer/Android.bp @@ -50,7 +50,7 @@ cc_library_headers { "com.android.art.debug", "com.android.art", ], - min_sdk_version: "S", + min_sdk_version: "31", } art_cc_binary { diff --git a/disassembler/Android.bp b/disassembler/Android.bp index 71ad051927..cafa83d1c2 100644 --- a/disassembler/Android.bp +++ b/disassembler/Android.bp @@ -131,5 +131,5 @@ cc_library_headers { "com.android.art.debug", "com.android.art", ], - min_sdk_version: "S", + min_sdk_version: "31", } diff --git a/dt_fd_forward/export/Android.bp b/dt_fd_forward/export/Android.bp index a4e96732cb..405e558415 100644 --- a/dt_fd_forward/export/Android.bp +++ b/dt_fd_forward/export/Android.bp @@ -33,5 +33,5 @@ cc_library_headers { "com.android.art.debug", "com.android.art", ], - min_sdk_version: "S", + min_sdk_version: "31", } diff --git a/libartbase/Android.bp b/libartbase/Android.bp index 8bd3bd12aa..3aae1b90fa 100644 --- a/libartbase/Android.bp +++ b/libartbase/Android.bp @@ -341,5 +341,5 @@ cc_library_headers { "com.android.art", "com.android.art.debug", ], - min_sdk_version: "S", + min_sdk_version: "31", } diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp index 47f2e29a58..658dbc407b 100644 --- a/libdexfile/Android.bp +++ b/libdexfile/Android.bp @@ -333,7 +333,7 @@ cc_library_headers { "com.android.media", "com.android.runtime", ], - min_sdk_version: "S", + min_sdk_version: "31", } // Make dex_instruction_list.h available for tools/jvmti-agents/titrace @@ -347,7 +347,7 @@ cc_library_headers { "com.android.art", "com.android.art.debug", ], - min_sdk_version: "S", + min_sdk_version: "31", } art_cc_test { @@ -409,7 +409,7 @@ art_cc_library_static { "com.android.media.swcodec", "com.android.runtime", ], - min_sdk_version: "S", + min_sdk_version: "31", } art_cc_defaults { diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp index 8e87997b00..9b988e1187 100644 --- a/libnativebridge/Android.bp +++ b/libnativebridge/Android.bp @@ -32,7 +32,7 @@ cc_library_headers { "com.android.art.debug", "com.android.media", ], - min_sdk_version: "S", + min_sdk_version: "31", } art_cc_library { diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp index 3f13506e33..87d21afb97 100644 --- a/libnativeloader/Android.bp +++ b/libnativeloader/Android.bp @@ -102,7 +102,7 @@ cc_library_headers { "com.android.art.debug", "com.android.media", ], - min_sdk_version: "S", + min_sdk_version: "31", visibility: [ "//art:__subpackages__", // TODO(b/133140750): Clean this up. diff --git a/openjdkjvmti/Android.bp b/openjdkjvmti/Android.bp index 841a964657..988d4597b3 100644 --- a/openjdkjvmti/Android.bp +++ b/openjdkjvmti/Android.bp @@ -58,7 +58,7 @@ cc_library_headers { "com.android.art", "com.android.art.debug", ], - min_sdk_version: "S", + min_sdk_version: "31", } cc_defaults { diff --git a/runtime/Android.bp b/runtime/Android.bp index e9343e7315..8d2a321cae 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -888,7 +888,7 @@ cc_library_headers { "com.android.art", "com.android.art.debug", ], - min_sdk_version: "S", + min_sdk_version: "31", } genrule { diff --git a/runtime/jit/jit_memory_region.cc b/runtime/jit/jit_memory_region.cc index 1592767f98..56407f58c0 100644 --- a/runtime/jit/jit_memory_region.cc +++ b/runtime/jit/jit_memory_region.cc @@ -20,6 +20,7 @@ #include <unistd.h> #include <android-base/unique_fd.h> +#include <log/log.h> #include "base/bit_utils.h" // For RoundDown, RoundUp #include "base/globals.h" #include "base/logging.h" // For VLOG. @@ -64,7 +65,15 @@ bool JitMemoryRegion::Initialize(size_t initial_capacity, // File descriptor enabling dual-view mapping of code section. unique_fd mem_fd; + + // The memory mappings we are going to create. + MemMap data_pages; + MemMap exec_pages; + MemMap non_exec_pages; + MemMap writable_data_pages; + if (is_zygote) { + android_errorWriteLog(0x534e4554, "200284993"); // Report to SafetyNet. // Because we are not going to GC code generated by the zygote, just use all available. current_capacity_ = max_capacity; mem_fd = unique_fd(CreateZygoteMemory(capacity, error_msg)); @@ -92,17 +101,12 @@ bool JitMemoryRegion::Initialize(size_t initial_capacity, } } + // Map name specific for android_os_Debug.cpp accounting. std::string data_cache_name = is_zygote ? "zygote-data-code-cache" : "data-code-cache"; std::string exec_cache_name = is_zygote ? "zygote-jit-code-cache" : "jit-code-cache"; std::string error_str; - // Map name specific for android_os_Debug.cpp accounting. - // Map in low 4gb to simplify accessing root tables for x86_64. - // We could do PC-relative addressing to avoid this problem, but that - // would require reserving code and data area before submitting, which - // means more windows for the code memory to be RWX. int base_flags; - MemMap data_pages; if (mem_fd.get() >= 0) { // Dual view of JIT code cache case. Create an initial mapping of data pages large enough // for data and non-writable view of JIT code pages. We use the memory file descriptor to @@ -131,7 +135,63 @@ bool JitMemoryRegion::Initialize(size_t initial_capacity, // Additionally, the zyzote will create a dual view of the data portion of // the cache. This mapping will be read-only, whereas the second mapping // will be writable. + base_flags = MAP_SHARED; + + // Create the writable mappings now, so that in case of the zygote, we can + // prevent any future writable mappings through sealing. + if (exec_capacity > 0) { + // For dual view, create the secondary view of code memory used for updating code. This view + // is never executable. + std::string name = exec_cache_name + "-rw"; + non_exec_pages = MemMap::MapFile(exec_capacity, + kIsDebugBuild ? kProtR : kProtRW, + base_flags, + mem_fd, + /* start= */ data_capacity, + /* low_4GB= */ false, + name.c_str(), + &error_str); + if (!non_exec_pages.IsValid()) { + // This is unexpected. + *error_msg = "Failed to map non-executable view of JIT code cache"; + return false; + } + // Create a dual view of the data cache. + name = data_cache_name + "-rw"; + writable_data_pages = MemMap::MapFile(data_capacity, + kProtRW, + base_flags, + mem_fd, + /* start= */ 0, + /* low_4GB= */ false, + name.c_str(), + &error_str); + if (!writable_data_pages.IsValid()) { + std::ostringstream oss; + oss << "Failed to create dual data view: " << error_str; + *error_msg = oss.str(); + return false; + } + if (writable_data_pages.MadviseDontFork() != 0) { + *error_msg = "Failed to MadviseDontFork the writable data view"; + return false; + } + if (non_exec_pages.MadviseDontFork() != 0) { + *error_msg = "Failed to MadviseDontFork the writable code view"; + return false; + } + // Now that we have created the writable and executable mappings, prevent creating any new + // ones. + if (is_zygote && !ProtectZygoteMemory(mem_fd.get(), error_msg)) { + return false; + } + } + + // Map in low 4gb to simplify accessing root tables for x86_64. + // We could do PC-relative addressing to avoid this problem, but that + // would require reserving code and data area before submitting, which + // means more windows for the code memory to be RWX. data_pages = MemMap::MapFile( data_capacity + exec_capacity, kProtR, @@ -172,9 +232,6 @@ bool JitMemoryRegion::Initialize(size_t initial_capacity, return false; } - MemMap exec_pages; - MemMap non_exec_pages; - MemMap writable_data_pages; if (exec_capacity > 0) { uint8_t* const divider = data_pages.Begin() + data_capacity; // Set initial permission for executable view to catch any SELinux permission problems early @@ -193,59 +250,6 @@ bool JitMemoryRegion::Initialize(size_t initial_capacity, *error_msg = oss.str(); return false; } - - if (mem_fd.get() >= 0) { - // For dual view, create the secondary view of code memory used for updating code. This view - // is never executable. - std::string name = exec_cache_name + "-rw"; - non_exec_pages = MemMap::MapFile(exec_capacity, - kIsDebugBuild ? kProtR : kProtRW, - base_flags, - mem_fd, - /* start= */ data_capacity, - /* low_4GB= */ false, - name.c_str(), - &error_str); - if (!non_exec_pages.IsValid()) { - static const char* kFailedNxView = "Failed to map non-executable view of JIT code cache"; - if (rwx_memory_allowed) { - // Log and continue as single view JIT (requires RWX memory). - VLOG(jit) << kFailedNxView; - } else { - *error_msg = kFailedNxView; - return false; - } - } - // Create a dual view of the data cache. - name = data_cache_name + "-rw"; - writable_data_pages = MemMap::MapFile(data_capacity, - kProtRW, - base_flags, - mem_fd, - /* start= */ 0, - /* low_4GB= */ false, - name.c_str(), - &error_str); - if (!writable_data_pages.IsValid()) { - std::ostringstream oss; - oss << "Failed to create dual data view: " << error_str; - *error_msg = oss.str(); - return false; - } - if (writable_data_pages.MadviseDontFork() != 0) { - *error_msg = "Failed to madvise dont fork the writable data view"; - return false; - } - if (non_exec_pages.MadviseDontFork() != 0) { - *error_msg = "Failed to madvise dont fork the writable code view"; - return false; - } - // Now that we have created the writable and executable mappings, prevent creating any new - // ones. - if (is_zygote && !ProtectZygoteMemory(mem_fd.get(), error_msg)) { - return false; - } - } } else { // Profiling only. No memory for code required. } diff --git a/runtime/jit/jit_memory_region_test.cc b/runtime/jit/jit_memory_region_test.cc index 20496118db..18f34fb229 100644 --- a/runtime/jit/jit_memory_region_test.cc +++ b/runtime/jit/jit_memory_region_test.cc @@ -492,6 +492,62 @@ class TestZygoteMemory : public testing::Test { munmap(addr, kPageSize); munmap(shared, kPageSize); } + + // Test that a readable mapping created befire sealing future writes, can be + // changed into a writable mapping. + void TestVmMayWriteBefore() { + // Zygote JIT memory only works on kernels that don't segfault on flush. + TEST_DISABLED_FOR_KERNELS_WITH_CACHE_SEGFAULT(); + std::string error_msg; + size_t size = kPageSize; + int32_t* addr = nullptr; + { + android::base::unique_fd fd(JitMemoryRegion::CreateZygoteMemory(size, &error_msg)); + CHECK_NE(fd.get(), -1); + + // Create a shared readable mapping. + addr = reinterpret_cast<int32_t*>( + mmap(nullptr, kPageSize, PROT_READ, MAP_SHARED, fd.get(), 0)); + CHECK(addr != nullptr); + CHECK_NE(addr, MAP_FAILED); + + // Protect the memory. + bool res = JitMemoryRegion::ProtectZygoteMemory(fd.get(), &error_msg); + CHECK(res); + } + // At this point, the fd has been dropped, but the memory mappings are still + // there. + int res = mprotect(addr, kPageSize, PROT_WRITE); + CHECK_EQ(res, 0); + } + + // Test that we cannot create a writable mapping after sealing future writes. + void TestVmMayWriteAfter() { + // Zygote JIT memory only works on kernels that don't segfault on flush. + TEST_DISABLED_FOR_KERNELS_WITH_CACHE_SEGFAULT(); + std::string error_msg; + size_t size = kPageSize; + int32_t* addr = nullptr; + { + android::base::unique_fd fd(JitMemoryRegion::CreateZygoteMemory(size, &error_msg)); + CHECK_NE(fd.get(), -1); + + // Protect the memory. + bool res = JitMemoryRegion::ProtectZygoteMemory(fd.get(), &error_msg); + CHECK(res); + + // Create a shared readable mapping. + addr = reinterpret_cast<int32_t*>( + mmap(nullptr, kPageSize, PROT_READ, MAP_SHARED, fd.get(), 0)); + CHECK(addr != nullptr); + CHECK_NE(addr, MAP_FAILED); + } + // At this point, the fd has been dropped, but the memory mappings are still + // there. + int res = mprotect(addr, kPageSize, PROT_WRITE); + CHECK_EQ(res, -1); + CHECK_EQ(errno, EACCES); + } }; TEST_F(TestZygoteMemory, BasicTest) { @@ -510,6 +566,14 @@ TEST_F(TestZygoteMemory, TestFromSharedToPrivate) { TestFromSharedToPrivate(); } +TEST_F(TestZygoteMemory, TestVmMayWriteBefore) { + TestVmMayWriteBefore(); +} + +TEST_F(TestZygoteMemory, TestVmMayWriteAfter) { + TestVmMayWriteAfter(); +} + #endif // defined (__BIONIC__) } // namespace jit diff --git a/test/099-vmdebug/expected-stdout.txt b/test/099-vmdebug/expected-stdout.txt index b8d72f66f8..4a1b63dc6c 100644 --- a/test/099-vmdebug/expected-stdout.txt +++ b/test/099-vmdebug/expected-stdout.txt @@ -15,8 +15,10 @@ Test tracing with empty filename Got expected exception Test tracing with bogus (< 1024 && != 0) filesize Got expected exception +Got expected exception Test sampling with bogus (<= 0) interval Got expected exception +Got expected exception Instances of ClassA 2 Instances of ClassB 1 Instances of null 0 diff --git a/test/099-vmdebug/src/Main.java b/test/099-vmdebug/src/Main.java index 8fed123852..aa240b6dc2 100644 --- a/test/099-vmdebug/src/Main.java +++ b/test/099-vmdebug/src/Main.java @@ -35,6 +35,9 @@ public class Main { testCountInstances(); testRuntimeStat(); testRuntimeStats(); + testGetAllocCount(); + testGetVmFeatureList(); + testDebuggerDetails(); } private static File createTempFile() throws Exception { @@ -117,6 +120,13 @@ public class Main { System.out.println("Got expected exception"); } + try { + VMDebug.startMethodTracingDdms(1000, 0, false, 0); + System.out.println("Should have thrown an exception"); + } catch (Exception e) { + System.out.println("Got expected exception"); + } + System.out.println("Test sampling with bogus (<= 0) interval"); try { VMDebug.startMethodTracing(tempFileName, 0, 0, true, 0); @@ -124,6 +134,12 @@ public class Main { } catch (Exception e) { System.out.println("Got expected exception"); } + try { + VMDebug.startMethodTracingDdms(0, 0, true, 0); + System.out.println("Should have thrown an exception"); + } catch (Exception e) { + System.out.println("Got expected exception"); + } tempFile.delete(); } @@ -139,6 +155,18 @@ public class Main { } } + private static void checkBiggerThanZero(int i) throws Exception { + if (i <= 0) { + System.out.println("Got zero or smaller " + i); + } + } + + private static void checkZero(int i) throws Exception { + if (i != 0) { + System.out.println("Got non-zero result after reset " + i); + } + } + private static void checkHistogram(String s) throws Exception { if (s == null || s.length() == 0) { System.out.println("Got null or empty string"); @@ -224,6 +252,67 @@ public class Main { checkHistogram(blocking_gc_count_rate_histogram); } + /* constants for getAllocCount */ + private static final int KIND_ALLOCATED_OBJECTS = 1<<0; + private static final int KIND_ALLOCATED_BYTES = 1<<1; + private static final int KIND_FREED_OBJECTS = 1<<2; + private static final int KIND_FREED_BYTES = 1<<3; + private static final int RESET_ALL = 0xffffffff; + + private static void testGetAllocCount() throws Exception { + VMDebug.startAllocCounting(); + + ClassA a1 = new ClassA(); + Object obj1 = new Object(); + Runtime.getRuntime().gc(); + + int alloc_objects = VMDebug.getAllocCount(KIND_ALLOCATED_OBJECTS); + int alloc_bytes = VMDebug.getAllocCount(KIND_ALLOCATED_BYTES); + int freed_objects = VMDebug.getAllocCount(KIND_FREED_OBJECTS); + int freed_bytes = VMDebug.getAllocCount(KIND_FREED_BYTES); + checkBiggerThanZero(alloc_objects); + checkBiggerThanZero(alloc_bytes); + checkBiggerThanZero(freed_objects); + checkBiggerThanZero(freed_bytes); + + VMDebug.stopAllocCounting(); + VMDebug.resetAllocCount(RESET_ALL); + checkZero(VMDebug.getAllocCount(KIND_ALLOCATED_OBJECTS)); + checkZero(VMDebug.getAllocCount(KIND_ALLOCATED_BYTES)); + checkZero(VMDebug.getAllocCount(KIND_FREED_OBJECTS)); + checkZero(VMDebug.getAllocCount(KIND_FREED_BYTES)); + + // Even if we create new classes the count should remain 0. + ClassA a2 = new ClassA(); + Object obj2 = new Object(); + + checkZero(VMDebug.getAllocCount(KIND_ALLOCATED_OBJECTS)); + } + + private static void testGetVmFeatureList() throws Exception { + String[] feature_list = VMDebug.getVmFeatureList(); + if (feature_list.length == 0) { + System.out.println("Got empty feature list"); + } + } + + private static void testDebuggerDetails() throws Exception { + boolean debugger_connected = VMDebug.isDebuggerConnected(); + boolean debugging_enabled = VMDebug.isDebuggingEnabled(); + long last_activity = VMDebug.lastDebuggerActivity(); + if (debugger_connected && last_activity < 0) { + System.out.println("Last debugging activity expected but not found"); + } + if (!debugger_connected && last_activity != -1) { + System.out.println("Found unexpected last activity"); + } + if (VMDebug.threadCpuTimeNanos() <= 0) { + System.out.println("Could not get CPU thread time"); + } + VMDebug.dumpHprofDataDdms(); + VMDebug.dumpReferenceTables(); + } + static class ClassA { } static class ClassB { } static class ClassC extends ClassA { } @@ -247,6 +336,8 @@ public class Main { System.out.println("Array counts " + Arrays.toString(counts)); counts = VMDebug.countInstancesofClasses(classes, true); System.out.println("Array counts assignable " + Arrays.toString(counts)); + int class_count = VMDebug.getLoadedClassCount(); + checkBiggerThanZero(class_count); } static class ClassD { @@ -265,17 +356,33 @@ public class Main { private static class VMDebug { private static final Method startMethodTracingMethod; + private static final Method startMethodTracingDdmsMethod; private static final Method stopMethodTracingMethod; private static final Method getMethodTracingModeMethod; private static final Method getRuntimeStatMethod; private static final Method getRuntimeStatsMethod; private static final Method countInstancesOfClassMethod; private static final Method countInstancesOfClassesMethod; + private static final Method getAllocCountMethod; + private static final Method startAllocCountingMethod; + private static final Method stopAllocCountingMethod; + private static final Method setAllocTrackerStackDepthMethod; + private static final Method resetAllocCountMethod; + private static final Method getLoadedClassCountMethod; + private static final Method getVmFeatureListMethod; + private static final Method isDebuggerConnectedMethod; + private static final Method isDebuggingEnabledMethod; + private static final Method lastDebuggerActivityMethod; + private static final Method threadCpuTimeNanosMethod; + private static final Method dumpHprofDataDdmsMethod; + private static final Method dumpReferenceTablesMethod; static { try { Class<?> c = Class.forName("dalvik.system.VMDebug"); startMethodTracingMethod = c.getDeclaredMethod("startMethodTracing", String.class, Integer.TYPE, Integer.TYPE, Boolean.TYPE, Integer.TYPE); + startMethodTracingDdmsMethod = c.getDeclaredMethod("startMethodTracingDdms", + Integer.TYPE, Integer.TYPE, Boolean.TYPE, Integer.TYPE); stopMethodTracingMethod = c.getDeclaredMethod("stopMethodTracing"); getMethodTracingModeMethod = c.getDeclaredMethod("getMethodTracingMode"); getRuntimeStatMethod = c.getDeclaredMethod("getRuntimeStat", String.class); @@ -284,6 +391,22 @@ public class Main { Class.class, Boolean.TYPE); countInstancesOfClassesMethod = c.getDeclaredMethod("countInstancesOfClasses", Class[].class, Boolean.TYPE); + getAllocCountMethod = c.getDeclaredMethod("getAllocCount", + Integer.TYPE); + startAllocCountingMethod = c.getDeclaredMethod("startAllocCounting"); + stopAllocCountingMethod = c.getDeclaredMethod("stopAllocCounting"); + setAllocTrackerStackDepthMethod = c.getDeclaredMethod("setAllocTrackerStackDepth", + Integer.TYPE); + resetAllocCountMethod = c.getDeclaredMethod("resetAllocCount", + Integer.TYPE); + getLoadedClassCountMethod = c.getDeclaredMethod("getLoadedClassCount"); + getVmFeatureListMethod = c.getDeclaredMethod("getVmFeatureList"); + isDebuggerConnectedMethod = c.getDeclaredMethod("isDebuggerConnected"); + isDebuggingEnabledMethod = c.getDeclaredMethod("isDebuggingEnabled"); + lastDebuggerActivityMethod = c.getDeclaredMethod("lastDebuggerActivity"); + threadCpuTimeNanosMethod = c.getDeclaredMethod("threadCpuTimeNanos"); + dumpHprofDataDdmsMethod = c.getDeclaredMethod("dumpHprofDataDdms"); + dumpReferenceTablesMethod = c.getDeclaredMethod("dumpReferenceTables"); } catch (Exception e) { throw new RuntimeException(e); } @@ -294,6 +417,11 @@ public class Main { startMethodTracingMethod.invoke(null, filename, bufferSize, flags, samplingEnabled, intervalUs); } + public static void startMethodTracingDdms(int bufferSize, int flags, + boolean samplingEnabled, int intervalUs) throws Exception { + startMethodTracingDdmsMethod.invoke(null, bufferSize, flags, samplingEnabled, + intervalUs); + } public static void stopMethodTracing() throws Exception { stopMethodTracingMethod.invoke(null); } @@ -314,5 +442,44 @@ public class Main { return (long[]) countInstancesOfClassesMethod.invoke( null, new Object[]{classes, assignable}); } + public static int getAllocCount(Integer kind) throws Exception { + return (int) getAllocCountMethod.invoke(null, kind); + } + public static void startAllocCounting() throws Exception { + startAllocCountingMethod.invoke(null); + } + public static void stopAllocCounting() throws Exception { + stopAllocCountingMethod.invoke(null); + } + public static void setAllocTrackerStackDepth(Integer stackDepth) throws Exception { + setAllocTrackerStackDepthMethod.invoke(null, stackDepth); + } + public static void resetAllocCount(Integer kind) throws Exception { + resetAllocCountMethod.invoke(null, kind); + } + public static int getLoadedClassCount() throws Exception { + return (int) getLoadedClassCountMethod.invoke(null); + } + public static String[] getVmFeatureList() throws Exception { + return (String[]) getVmFeatureListMethod.invoke(null); + } + public static boolean isDebuggerConnected() throws Exception { + return (boolean) isDebuggerConnectedMethod.invoke(null); + } + public static boolean isDebuggingEnabled() throws Exception { + return (boolean) isDebuggingEnabledMethod.invoke(null); + } + public static long lastDebuggerActivity() throws Exception { + return (long) lastDebuggerActivityMethod.invoke(null); + } + public static long threadCpuTimeNanos() throws Exception { + return (long) threadCpuTimeNanosMethod.invoke(null); + } + public static void dumpHprofDataDdms() throws Exception { + dumpHprofDataDdmsMethod.invoke(null); + } + public static void dumpReferenceTables() throws Exception { + dumpReferenceTablesMethod.invoke(null); + } } } diff --git a/test/530-checker-lse/src/Main.java b/test/530-checker-lse/src/Main.java index a707a8ae5c..3d97049f2c 100644 --- a/test/530-checker-lse/src/Main.java +++ b/test/530-checker-lse/src/Main.java @@ -3942,6 +3942,8 @@ public class Main { /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (after) /// CHECK: InstanceFieldSet // + // TODO: We should be able to remove this setter by realizing `i` only escapes in a branch. + /// CHECK: InstanceFieldSet /// CHECK-NOT: InstanceFieldSet // /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (after) diff --git a/test/832-cha-recursive/expected-stderr.txt b/test/832-cha-recursive/expected-stderr.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/832-cha-recursive/expected-stderr.txt diff --git a/test/832-cha-recursive/expected-stdout.txt b/test/832-cha-recursive/expected-stdout.txt new file mode 100644 index 0000000000..6a5618ebc6 --- /dev/null +++ b/test/832-cha-recursive/expected-stdout.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/832-cha-recursive/info.txt b/test/832-cha-recursive/info.txt new file mode 100644 index 0000000000..4913993c63 --- /dev/null +++ b/test/832-cha-recursive/info.txt @@ -0,0 +1,2 @@ +Regression test for the optimization compiler which used to have a bug when a +recursive method was doing CHA inlining. diff --git a/test/832-cha-recursive/src/Main.java b/test/832-cha-recursive/src/Main.java new file mode 100644 index 0000000000..ed865a78f1 --- /dev/null +++ b/test/832-cha-recursive/src/Main.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 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 Main { + int mainField = 42; + + public static void main(String[] args) throws Exception { + System.loadLibrary(args[0]); + ensureJitCompiled(Main.class, "$noinline$callRecursiveMethod"); + $noinline$callRecursiveMethod(true); + } + + public static void expectEquals(int expected, int actual) { + if (expected != actual) { + throw new Error("Expected " + expected + ", got " + actual); + } + } + + public static void $noinline$callRecursiveMethod(boolean firstEntry) throws Exception { + Class<?> cls = Class.forName("LoadedLater"); + Main m = (Main)cls.newInstance(); + if (firstEntry) { + $noinline$callRecursiveMethod(false); + } else { + expectEquals(0, m.getField()); + } + } + + public int getField() { + return mainField; + } + + public static native void ensureJitCompiled(Class<?> cls, String methodName); +} + +class LoadedLater extends Main { + public int getField() { + return 0; + } +} diff --git a/test/834-lse/expected-stderr.txt b/test/834-lse/expected-stderr.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/834-lse/expected-stderr.txt diff --git a/test/834-lse/expected-stdout.txt b/test/834-lse/expected-stdout.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/834-lse/expected-stdout.txt diff --git a/test/834-lse/info.txt b/test/834-lse/info.txt new file mode 100644 index 0000000000..8229be934f --- /dev/null +++ b/test/834-lse/info.txt @@ -0,0 +1,2 @@ +Regression test for the load-store-elimination pass, which used to remove stores +too agressively. diff --git a/test/834-lse/src/Main.java b/test/834-lse/src/Main.java new file mode 100644 index 0000000000..65139696bc --- /dev/null +++ b/test/834-lse/src/Main.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 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 { + int myField; + static boolean test; + + static void $noinline$assertEquals(int expected, int actual) { + if (expected != actual) { + throw new Error("Expected " + expected + ", got " + actual); + } + } + + static void $noinline$empty() {} + static void $noinline$escape(Object m) {} + + public static void main(String[] args) { + Main m = new Main(); + if (test) { + $noinline$escape(m); + } else { + m.myField = 42; + } + $noinline$empty(); + $noinline$assertEquals(42, m.myField); + } +} diff --git a/tools/Android.bp b/tools/Android.bp index 9b9d3a765d..85648e555e 100644 --- a/tools/Android.bp +++ b/tools/Android.bp @@ -122,6 +122,6 @@ python_binary_host { }, test_suites: [ "general-tests", - "mts", + "mts-art", ], } diff --git a/tools/cpp-define-generator/Android.bp b/tools/cpp-define-generator/Android.bp index a436430c16..28d4dc5d0a 100644 --- a/tools/cpp-define-generator/Android.bp +++ b/tools/cpp-define-generator/Android.bp @@ -111,7 +111,7 @@ cc_library_headers { "com.android.art", "com.android.art.debug", ], - min_sdk_version: "S", + min_sdk_version: "31", } python_binary_host { |