diff options
22 files changed, 349 insertions, 161 deletions
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 6144162f68..bbf8c26d59 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -445,6 +445,9 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { ? GetGraph()->GetDexFile().PrettyMethod(invoke->GetDexMethodIndex(), kWithSignature) : method->PrettyMethod(kWithSignature); StartAttributeStream("method_name") << method_name; + StartAttributeStream("always_throws") << std::boolalpha + << invoke->AlwaysThrows() + << std::noboolalpha; } void VisitInvokeUnresolved(HInvokeUnresolved* invoke) OVERRIDE { diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 035e5ce3e1..b9ae0ffb12 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -392,10 +392,33 @@ ArtMethod* HInliner::TryCHADevirtualization(ArtMethod* resolved_method) { return single_impl; } -static bool AlwaysThrows(ArtMethod* method) +static bool IsMethodUnverified(CompilerDriver* const compiler_driver, ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) { - CodeItemDataAccessor accessor(method->DexInstructionData()); + if (!method->GetDeclaringClass()->IsVerified()) { + if (Runtime::Current()->UseJitCompilation()) { + // We're at runtime, we know this is cold code if the class + // is not verified, so don't bother analyzing. + return true; + } + uint16_t class_def_idx = method->GetDeclaringClass()->GetDexClassDefIndex(); + if (!compiler_driver->IsMethodVerifiedWithoutFailures( + method->GetDexMethodIndex(), class_def_idx, *method->GetDexFile())) { + // Method has soft or hard failures, don't analyze. + return true; + } + } + return false; +} + +static bool AlwaysThrows(CompilerDriver* const compiler_driver, ArtMethod* method) + REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK(method != nullptr); + // Skip non-compilable and unverified methods. + if (!method->IsCompilable() || IsMethodUnverified(compiler_driver, method)) { + return false; + } // Skip native methods, methods with try blocks, and methods that are too large. + CodeItemDataAccessor accessor(method->DexInstructionData()); if (!accessor.HasCodeItem() || accessor.TriesSize() != 0 || accessor.InsnsSizeInCodeUnits() > kMaximumNumberOfTotalInstructions) { @@ -478,7 +501,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) { MaybeRecordStat(stats_, MethodCompilationStat::kInlinedInvokeVirtualOrInterface); } } - } else if (!cha_devirtualize && AlwaysThrows(actual_method)) { + } else if (!cha_devirtualize && AlwaysThrows(compiler_driver_, actual_method)) { // Set always throws property for non-inlined method call with single target // (unless it was obtained through CHA, because that would imply we have // to add the CHA dependency, which seems not worth it). @@ -1450,16 +1473,11 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, << " has soft failures un-handled by the compiler, so it cannot be inlined"; } - if (!method->GetDeclaringClass()->IsVerified()) { - uint16_t class_def_idx = method->GetDeclaringClass()->GetDexClassDefIndex(); - if (Runtime::Current()->UseJitCompilation() || - !compiler_driver_->IsMethodVerifiedWithoutFailures( - method->GetDexMethodIndex(), class_def_idx, *method->GetDexFile())) { - LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedNotVerified) - << "Method " << method->PrettyMethod() - << " couldn't be verified, so it cannot be inlined"; - return false; - } + if (IsMethodUnverified(compiler_driver_, method)) { + LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedNotVerified) + << "Method " << method->PrettyMethod() + << " couldn't be verified, so it cannot be inlined"; + return false; } if (invoke_instruction->IsInvokeStaticOrDirect() && diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc index 8b4eae1780..237ecd3c10 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -882,6 +882,7 @@ class LSEVisitor : public HGraphDelegateVisitor { } if (ref_info->IsSingletonAndRemovable() && !new_instance->NeedsChecks()) { DCHECK(!new_instance->IsFinalizable()); + // new_instance can potentially be eliminated. singleton_new_instances_.push_back(new_instance); } ScopedArenaVector<HInstruction*>& heap_values = @@ -904,7 +905,13 @@ class LSEVisitor : public HGraphDelegateVisitor { return; } if (ref_info->IsSingletonAndRemovable()) { - singleton_new_instances_.push_back(new_array); + if (new_array->GetLength()->IsIntConstant() && + new_array->GetLength()->AsIntConstant()->GetValue() >= 0) { + // new_array can potentially be eliminated. + singleton_new_instances_.push_back(new_array); + } else { + // new_array may throw NegativeArraySizeException. Keep it. + } } ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[new_array->GetBlock()->GetBlockId()]; diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc index bebdc202e7..a1901f08f3 100644 --- a/dexlayout/dexlayout_test.cc +++ b/dexlayout/dexlayout_test.cc @@ -24,6 +24,7 @@ #include "base/unix_file/fd_file.h" #include "common_runtime_test.h" #include "dex/art_dex_file_loader.h" +#include "dex/base64_test_util.h" #include "dex/code_item_accessors-inl.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc index 39dbebfdf2..8c268d8ab9 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -73,74 +73,6 @@ namespace art { using android::base::StringPrintf; -static const uint8_t kBase64Map[256] = { - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, - 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, - 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255 -}; - -uint8_t* DecodeBase64(const char* src, size_t* dst_size) { - CHECK(dst_size != nullptr); - std::vector<uint8_t> tmp; - uint32_t t = 0, y = 0; - int g = 3; - for (size_t i = 0; src[i] != '\0'; ++i) { - uint8_t c = kBase64Map[src[i] & 0xFF]; - if (c == 255) continue; - // the final = symbols are read and used to trim the remaining bytes - if (c == 254) { - c = 0; - // prevent g < 0 which would potentially allow an overflow later - if (--g < 0) { - *dst_size = 0; - return nullptr; - } - } else if (g != 3) { - // we only allow = to be at the end - *dst_size = 0; - return nullptr; - } - t = (t << 6) | c; - if (++y == 4) { - tmp.push_back((t >> 16) & 255); - if (g > 1) { - tmp.push_back((t >> 8) & 255); - } - if (g > 2) { - tmp.push_back(t & 255); - } - y = t = 0; - } - } - if (y != 0) { - *dst_size = 0; - return nullptr; - } - std::unique_ptr<uint8_t[]> dst(new uint8_t[tmp.size()]); - *dst_size = tmp.size(); - std::copy(tmp.begin(), tmp.end(), dst.get()); - return dst.release(); -} - ScratchFile::ScratchFile() { // ANDROID_DATA needs to be set CHECK_NE(static_cast<char*>(nullptr), getenv("ANDROID_DATA")) << diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h index 0aed70a330..b2b4d545cb 100644 --- a/runtime/common_runtime_test.h +++ b/runtime/common_runtime_test.h @@ -53,8 +53,6 @@ typedef std::vector<std::pair<std::string, const void*>> RuntimeOptions; class Thread; class VariableSizedHandleScope; -uint8_t* DecodeBase64(const char* src, size_t* dst_size); - class ScratchFile { public: ScratchFile(); diff --git a/runtime/dex/base64_test_util.h b/runtime/dex/base64_test_util.h new file mode 100644 index 0000000000..0657f9fd01 --- /dev/null +++ b/runtime/dex/base64_test_util.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef ART_RUNTIME_DEX_BASE64_TEST_UTIL_H_ +#define ART_RUNTIME_DEX_BASE64_TEST_UTIL_H_ + +#include <base/logging.h> +#include <stdint.h> +#include <stdlib.h> + +#include <memory> +#include <vector> + +namespace art { + +static inline uint8_t* DecodeBase64(const char* src, size_t* dst_size) { + static const uint8_t kBase64Map[256] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, + 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, + 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255 + }; + + CHECK(dst_size != nullptr); + std::vector<uint8_t> tmp; + uint32_t t = 0, y = 0; + int g = 3; + for (size_t i = 0; src[i] != '\0'; ++i) { + uint8_t c = kBase64Map[src[i] & 0xFF]; + if (c == 255) continue; + // the final = symbols are read and used to trim the remaining bytes + if (c == 254) { + c = 0; + // prevent g < 0 which would potentially allow an overflow later + if (--g < 0) { + *dst_size = 0; + return nullptr; + } + } else if (g != 3) { + // we only allow = to be at the end + *dst_size = 0; + return nullptr; + } + t = (t << 6) | c; + if (++y == 4) { + tmp.push_back((t >> 16) & 255); + if (g > 1) { + tmp.push_back((t >> 8) & 255); + } + if (g > 2) { + tmp.push_back(t & 255); + } + y = t = 0; + } + } + if (y != 0) { + *dst_size = 0; + return nullptr; + } + std::unique_ptr<uint8_t[]> dst(new uint8_t[tmp.size()]); + *dst_size = tmp.size(); + std::copy(tmp.begin(), tmp.end(), dst.get()); + return dst.release(); +} + +} // namespace art + +#endif // ART_RUNTIME_DEX_BASE64_TEST_UTIL_H_ diff --git a/runtime/dex/code_item_accessors_test.cc b/runtime/dex/code_item_accessors_test.cc index 1bd12a6f09..2bb4dde649 100644 --- a/runtime/dex/code_item_accessors_test.cc +++ b/runtime/dex/code_item_accessors_test.cc @@ -18,42 +18,35 @@ #include <sys/mman.h> #include <memory> +#include <vector> -#include "common_runtime_test.h" -#include "art_dex_file_loader.h" #include "dex_file_loader.h" -#include "mem_map.h" +#include "gtest/gtest.h" namespace art { -class CodeItemAccessorsTest : public CommonRuntimeTest {}; +class CodeItemAccessorsTest : public testing::Test {}; -std::unique_ptr<const DexFile> CreateFakeDex(bool compact_dex) { - std::string error_msg; - std::unique_ptr<MemMap> map( - MemMap::MapAnonymous(/*name*/ "map", - /*addr*/ nullptr, - /*byte_count*/ kPageSize, - PROT_READ | PROT_WRITE, - /*low_4gb*/ false, - /*reuse*/ false, - &error_msg)); - CHECK(map != nullptr) << error_msg; +std::unique_ptr<const DexFile> CreateFakeDex(bool compact_dex, std::vector<uint8_t>* data) { + data->resize(kPageSize); if (compact_dex) { CompactDexFile::Header* header = - const_cast<CompactDexFile::Header*>(CompactDexFile::Header::At(map->Begin())); + const_cast<CompactDexFile::Header*>(CompactDexFile::Header::At(data->data())); CompactDexFile::WriteMagic(header->magic_); CompactDexFile::WriteCurrentVersion(header->magic_); header->data_off_ = 0; - header->data_size_ = map->Size(); + header->data_size_ = data->size(); } else { - StandardDexFile::WriteMagic(map->Begin()); - StandardDexFile::WriteCurrentVersion(map->Begin()); + StandardDexFile::WriteMagic(data->data()); + StandardDexFile::WriteCurrentVersion(data->data()); } - const ArtDexFileLoader dex_file_loader; - std::unique_ptr<const DexFile> dex(dex_file_loader.Open("location", + const DexFileLoader dex_file_loader; + std::string error_msg; + std::unique_ptr<const DexFile> dex(dex_file_loader.Open(data->data(), + data->size(), + "location", /*location_checksum*/ 123, - std::move(map), + /*oat_dex_file*/nullptr, /*verify*/false, /*verify_checksum*/false, &error_msg)); @@ -62,10 +55,13 @@ std::unique_ptr<const DexFile> CreateFakeDex(bool compact_dex) { } TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor) { - MemMap::Init(); - std::unique_ptr<const DexFile> standard_dex(CreateFakeDex(/*compact_dex*/false)); + std::vector<uint8_t> standard_dex_data; + std::unique_ptr<const DexFile> standard_dex(CreateFakeDex(/*compact_dex*/false, + &standard_dex_data)); ASSERT_TRUE(standard_dex != nullptr); - std::unique_ptr<const DexFile> compact_dex(CreateFakeDex(/*compact_dex*/true)); + std::vector<uint8_t> compact_dex_data; + std::unique_ptr<const DexFile> compact_dex(CreateFakeDex(/*compact_dex*/true, + &compact_dex_data)); ASSERT_TRUE(compact_dex != nullptr); static constexpr uint16_t kRegisterSize = 2; static constexpr uint16_t kInsSize = 1; diff --git a/runtime/dex/compact_dex_debug_info_test.cc b/runtime/dex/compact_dex_debug_info_test.cc index 02b95e68d7..3267612443 100644 --- a/runtime/dex/compact_dex_debug_info_test.cc +++ b/runtime/dex/compact_dex_debug_info_test.cc @@ -15,18 +15,14 @@ */ #include <vector> -#include <sys/mman.h> #include "base/logging.h" #include "dex/compact_dex_debug_info.h" #include "gtest/gtest.h" -#include "mem_map.h" namespace art { TEST(CompactDexDebugInfoTest, TestBuildAndAccess) { - MemMap::Init(); - const size_t kDebugInfoMinOffset = 1234567; std::vector<uint32_t> offsets = { 0, 17, 2, 3, 11, 0, 0, 0, 0, 1, 0, 1552, 100, 122, 44, 1234567, 0, 0, @@ -58,17 +54,10 @@ TEST(CompactDexDebugInfoTest, TestBuildAndAccess) { std::string error_msg; // Leave some extra room since we don't copy the table at the start (for testing). constexpr size_t kExtraOffset = 4 * 128; - std::unique_ptr<MemMap> fake_dex(MemMap::MapAnonymous("fake dex", - nullptr, - data.size() + kExtraOffset, - PROT_READ | PROT_WRITE, - /*low_4gb*/ false, - /*reuse*/ false, - &error_msg)); - ASSERT_TRUE(fake_dex != nullptr) << error_msg; - std::copy(data.begin(), data.end(), fake_dex->Begin() + kExtraOffset); + std::vector<uint8_t> fake_dex(data.size() + kExtraOffset); + std::copy(data.begin(), data.end(), fake_dex.data() + kExtraOffset); - CompactDexDebugInfoOffsetTable::Accessor accessor(fake_dex->Begin() + kExtraOffset, + CompactDexDebugInfoOffsetTable::Accessor accessor(fake_dex.data() + kExtraOffset, base_offset, table_offset); for (size_t i = 0; i < offsets.size(); ++i) { diff --git a/runtime/dex/dex_file_test.cc b/runtime/dex/dex_file_test.cc index 998bfd6c7f..2bb86672dc 100644 --- a/runtime/dex/dex_file_test.cc +++ b/runtime/dex/dex_file_test.cc @@ -23,6 +23,7 @@ #include "art_dex_file_loader.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" +#include "base64_test_util.h" #include "code_item_accessors-inl.h" #include "common_runtime_test.h" #include "descriptors_names.h" diff --git a/runtime/dex/dex_file_verifier_test.cc b/runtime/dex/dex_file_verifier_test.cc index d73a7fbfa3..1cd4b2c07b 100644 --- a/runtime/dex/dex_file_verifier_test.cc +++ b/runtime/dex/dex_file_verifier_test.cc @@ -16,28 +16,26 @@ #include "dex_file_verifier.h" -#include <sys/mman.h> #include <zlib.h> #include <functional> #include <memory> -#include "art_dex_file_loader.h" #include "base/bit_utils.h" #include "base/macros.h" -#include "base/unix_file/fd_file.h" -#include "common_runtime_test.h" +#include "base64_test_util.h" #include "descriptors_names.h" #include "dex_file-inl.h" #include "dex_file_loader.h" #include "dex_file_types.h" +#include "gtest/gtest.h" #include "leb128.h" -#include "scoped_thread_state_change-inl.h" #include "standard_dex_file.h" -#include "thread-current-inl.h" namespace art { +static constexpr char kLocationString[] = "dex_file_location"; + // Make the Dex file version 37. static void MakeDexVersion37(DexFile* dex_file) { size_t offset = OFFSETOF_MEMBER(DexFile::Header, magic_) + 6; @@ -55,7 +53,7 @@ static void FixUpChecksum(uint8_t* dex_file) { header->checksum_ = adler_checksum; } -class DexFileVerifierTest : public CommonRuntimeTest { +class DexFileVerifierTest : public testing::Test { protected: DexFile* GetDexFile(const uint8_t* dex_bytes, size_t length) { return new StandardDexFile(dex_bytes, length, "tmp", 0, nullptr, nullptr); @@ -101,28 +99,19 @@ static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64, std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(base64, &length)); CHECK(dex_bytes.get() != nullptr); - // write to provided file - std::unique_ptr<File> file(OS::CreateEmptyFile(location)); - CHECK(file.get() != nullptr); - if (!file->WriteFully(dex_bytes.get(), length)) { - PLOG(FATAL) << "Failed to write base64 as dex file"; - } - if (file->FlushCloseOrErase() != 0) { - PLOG(FATAL) << "Could not flush and close test file."; - } - file.reset(); - - // read dex file - ScopedObjectAccess soa(Thread::Current()); + // read dex std::vector<std::unique_ptr<const DexFile>> tmp; - const ArtDexFileLoader dex_file_loader; - bool success = dex_file_loader.Open( - location, location, /* verify */ true, /* verify_checksum */ true, error_msg, &tmp); + const DexFileLoader dex_file_loader; + bool success = dex_file_loader.OpenAll(dex_bytes.get(), + length, + location, + /* verify */ true, + /* verify_checksum */ true, + error_msg, + &tmp); CHECK(success) << *error_msg; EXPECT_EQ(1U, tmp.size()); std::unique_ptr<const DexFile> dex_file = std::move(tmp[0]); - EXPECT_EQ(PROT_READ, dex_file->GetPermissions()); - EXPECT_TRUE(dex_file->IsReadOnly()); return dex_file; } @@ -148,9 +137,9 @@ static const char kGoodTestDex[] = "AAIgAAANAAAAWgEAAAMgAAACAAAA6AEAAAAgAAABAAAA8wEAAAAQAAABAAAABAIAAA=="; TEST_F(DexFileVerifierTest, GoodDex) { - ScratchFile tmp; std::string error_msg; - std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kGoodTestDex, tmp.GetFilename().c_str(), + std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kGoodTestDex, + kLocationString, &error_msg)); ASSERT_TRUE(raw.get() != nullptr) << error_msg; } @@ -1311,10 +1300,9 @@ static const char kDebugInfoTestDex[] = TEST_F(DexFileVerifierTest, DebugInfoTypeIdxTest) { { // The input dex file should be good before modification. - ScratchFile tmp; std::string error_msg; std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kDebugInfoTestDex, - tmp.GetFilename().c_str(), + kLocationString, &error_msg)); ASSERT_TRUE(raw.get() != nullptr) << error_msg; } @@ -1333,10 +1321,9 @@ TEST_F(DexFileVerifierTest, SectionAlignment) { { // The input dex file should be good before modification. Any file is fine, as long as it // uses all sections. - ScratchFile tmp; std::string error_msg; std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kGoodTestDex, - tmp.GetFilename().c_str(), + kLocationString, &error_msg)); ASSERT_TRUE(raw.get() != nullptr) << error_msg; } @@ -1417,10 +1404,9 @@ static const char kProtoOrderingTestDex[] = TEST_F(DexFileVerifierTest, ProtoOrdering) { { // The input dex file should be good before modification. - ScratchFile tmp; std::string error_msg; std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kProtoOrderingTestDex, - tmp.GetFilename().c_str(), + kLocationString, &error_msg)); ASSERT_TRUE(raw.get() != nullptr) << error_msg; } diff --git a/runtime/dex/utf_test.cc b/runtime/dex/utf_test.cc index d1e97515d3..d2f22d16ef 100644 --- a/runtime/dex/utf_test.cc +++ b/runtime/dex/utf_test.cc @@ -16,15 +16,15 @@ #include "utf.h" -#include "common_runtime_test.h" -#include "utf-inl.h" - #include <map> #include <vector> +#include "gtest/gtest.h" +#include "utf-inl.h" + namespace art { -class UtfTest : public CommonRuntimeTest {}; +class UtfTest : public testing::Test {}; TEST_F(UtfTest, GetLeadingUtf16Char) { EXPECT_EQ(0xffff, GetLeadingUtf16Char(0xeeeeffff)); diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 3afd320f05..b26b09c156 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1178,7 +1178,12 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { // (b) Zygote forked a new process that is not exempt (see ZygoteHooks). // TODO(dbrazdil): Turn the NoHiddenApiChecks negative flag into a positive one // to clean up this logic. - do_hidden_api_checks_ = IsAotCompiler() && !runtime_options.Exists(Opt::NoHiddenApiChecks); + if (kIsTargetBuild && IsAotCompiler() && !runtime_options.Exists(Opt::NoHiddenApiChecks)) { + // dex2oat on target without -Xno-hidden-api-checks. + do_hidden_api_checks_ = !IsCompilingBootImage(); + } else { + do_hidden_api_checks_ = false; + } DCHECK(!is_zygote_ || !do_hidden_api_checks_) << "Zygote should not be started with hidden API checks"; diff --git a/test/530-checker-lse/expected.txt b/test/530-checker-lse/expected.txt index ddae16aff4..fb67e22d0b 100644 --- a/test/530-checker-lse/expected.txt +++ b/test/530-checker-lse/expected.txt @@ -1 +1,2 @@ java.lang.ArrayIndexOutOfBoundsException: length=3; index=3 +Got NegativeArraySizeException. diff --git a/test/530-checker-lse/src/Main.java b/test/530-checker-lse/src/Main.java index 98838c5089..ebde3bf845 100644 --- a/test/530-checker-lse/src/Main.java +++ b/test/530-checker-lse/src/Main.java @@ -1052,6 +1052,23 @@ public class Main { return array[1] + array[i]; } + /// CHECK-START: int Main.testAllocationEliminationOfArray5(int) load_store_elimination (before) + /// CHECK: NewArray + /// CHECK: ArraySet + /// CHECK: ArrayGet + + /// CHECK-START: int Main.testAllocationEliminationOfArray5(int) load_store_elimination (after) + /// CHECK: NewArray + /// CHECK-NOT: ArraySet + /// CHECK-NOT: ArrayGet + private static int testAllocationEliminationOfArray5(int i) { + // Cannot eliminate array allocation due to unknown i that may + // cause NegativeArraySizeException. + int[] array = new int[i]; + array[1] = 12; + return array[1]; + } + /// CHECK-START: int Main.testExitMerge(boolean) load_store_elimination (before) /// CHECK: NewInstance /// CHECK: InstanceFieldSet @@ -1205,6 +1222,12 @@ public class Main { assertIntEquals(testAllocationEliminationOfArray2(), 11); assertIntEquals(testAllocationEliminationOfArray3(2), 4); assertIntEquals(testAllocationEliminationOfArray4(2), 6); + assertIntEquals(testAllocationEliminationOfArray5(2), 12); + try { + testAllocationEliminationOfArray5(-2); + } catch (NegativeArraySizeException e) { + System.out.println("Got NegativeArraySizeException."); + } assertIntEquals(testStoreStore().i, 41); assertIntEquals(testStoreStore().j, 43); diff --git a/test/675-checker-unverified-method/expected.txt b/test/675-checker-unverified-method/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/675-checker-unverified-method/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/675-checker-unverified-method/info.txt b/test/675-checker-unverified-method/info.txt new file mode 100644 index 0000000000..667211a2fa --- /dev/null +++ b/test/675-checker-unverified-method/info.txt @@ -0,0 +1 @@ +Make sure analysis of unverified method is skipped. diff --git a/test/675-checker-unverified-method/smali/TestCase.smali b/test/675-checker-unverified-method/smali/TestCase.smali new file mode 100644 index 0000000000..673b3f2708 --- /dev/null +++ b/test/675-checker-unverified-method/smali/TestCase.smali @@ -0,0 +1,55 @@ +# Copyright (C) 2018 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.class public LTestCase; + +.super Ljava/lang/Object; + +# +# Ensure foo() does not analyze unverified bad() always-throws property. +# +## CHECK-START: void TestCase.foo(java.lang.Object) inliner (after) +## CHECK-DAG: InvokeStaticOrDirect method_name:TestCase.bar always_throws:true +## CHECK-DAG: InvokeStaticOrDirect method_name:TestCase.bad always_throws:false +.method public static foo(Ljava/lang/Object;)V + .registers 1 + if-nez v0, :Skip1 + invoke-static {}, LTestCase;->bar()V +:Skip1 + if-nez v0, :Skip2 + invoke-static {}, LTestCase;->bad()Lwont/be/Resolvable; +:Skip2 + return-void +.end method + +# +# Method bar() that verifies (but is never called). +# +.method public static bar()V + .registers 1 + new-instance v0, Ljava/lang/RuntimeException; + invoke-direct {v0}, Ljava/lang/RuntimeException;-><init>()V + throw v0 +.end method + +# +# Method bad() that fails to verify (but is never called). +# +.method public static bad()Lwont/be/Resolvable; + .registers 1 + invoke-static {}, LTestCase;->bar()Lwont/be/Resolvable; + move-result-object v0 + throw v0 +.end method + diff --git a/test/675-checker-unverified-method/src/Main.java b/test/675-checker-unverified-method/src/Main.java new file mode 100644 index 0000000000..0cdb2fe84b --- /dev/null +++ b/test/675-checker-unverified-method/src/Main.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 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. + */ + +/** + * Ensure unverified method is not analyzed. + */ +public class Main { + public static void main(String[] args) throws Exception { + Object o = new Object(); + Class<?> c = Class.forName("TestCase"); + Object[] arguments = { o }; + c.getMethod("foo", Object.class).invoke(null, arguments); + System.out.println("passed"); + } +} diff --git a/test/956-methodhandles/src/Main.java b/test/956-methodhandles/src/Main.java index cb06e4263e..1ddef03d62 100644 --- a/test/956-methodhandles/src/Main.java +++ b/test/956-methodhandles/src/Main.java @@ -22,6 +22,7 @@ import java.lang.invoke.MethodType; import java.lang.invoke.WrongMethodTypeException; import java.lang.reflect.Constructor; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -79,6 +80,7 @@ public class Main { testVariableArity(); testVariableArity_MethodHandles_bind(); testRevealDirect(); + testReflectiveCalls(); } public static void testfindSpecial_invokeSuperBehaviour() throws Throwable { @@ -1624,4 +1626,20 @@ public class Main { assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup())); assertEquals(MethodType.methodType(String.class), info.getMethodType()); } + + public static void testReflectiveCalls() throws Throwable { + String[] methodNames = { "invoke", "invokeExact" }; + for (String methodName : methodNames) { + Method invokeMethod = MethodHandle.class.getMethod(methodName, Object[].class); + MethodHandle instance = + MethodHandles.lookup().findVirtual(java.io.PrintStream.class, "println", + MethodType.methodType(void.class, String.class)); + try { + invokeMethod.invoke(instance, new Object[] { new Object[] { Integer.valueOf(1) } } ); + fail(); + } catch (InvocationTargetException ite) { + assertEquals(ite.getCause().getClass(), UnsupportedOperationException.class); + } + } + } } diff --git a/tools/external_oj_libjdwp_art_failures.txt b/tools/external_oj_libjdwp_art_failures.txt index 88ffa6eaf7..828c0aac0f 100644 --- a/tools/external_oj_libjdwp_art_failures.txt +++ b/tools/external_oj_libjdwp_art_failures.txt @@ -53,6 +53,19 @@ "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.CapabilitiesNewTest#testCapabilitiesNew001" ] }, { + description: "Test is flaky", + result: EXEC_FAILED, + bug: 69121056, + name: "org.apache.harmony.jpda.tests.jdwp.ObjectReference.IsCollectedTest#testIsCollected001" +}, +{ + description: "Test is flaky", + result: EXEC_FAILED, + bug: 70958370, + names: [ "org.apache.harmony.jpda.tests.jdwp.ObjectReference.EnableCollectionTest#testEnableCollection001", + "org.apache.harmony.jpda.tests.jdwp.MultiSession.EnableCollectionTest#testEnableCollection001" ] +}, +{ description: "Test crashes", result: EXEC_FAILED, bug: 69591477, diff --git a/tools/prebuilt_libjdwp_art_failures.txt b/tools/prebuilt_libjdwp_art_failures.txt index b0475bbdfd..a9d268de0a 100644 --- a/tools/prebuilt_libjdwp_art_failures.txt +++ b/tools/prebuilt_libjdwp_art_failures.txt @@ -102,12 +102,25 @@ "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.CapabilitiesNewTest#testCapabilitiesNew001" ] }, { + description: "Test is flaky", + result: EXEC_FAILED, + bug: 69121056, + name: "org.apache.harmony.jpda.tests.jdwp.ObjectReference.IsCollectedTest#testIsCollected001" +}, +{ description: "Test for ddms extensions that are not implemented for prebuilt-libjdwp", result: EXEC_FAILED, bug: 69169846, name: "org.apache.harmony.jpda.tests.jdwp.DDM.DDMTest#testChunk001" }, { + description: "Test is flakey", + result: EXEC_FAILED, + bug: 70958370, + names: [ "org.apache.harmony.jpda.tests.jdwp.ObjectReference.EnableCollectionTest#testEnableCollection001", + "org.apache.harmony.jpda.tests.jdwp.MultiSession.EnableCollectionTest#testEnableCollection001" ] +}, +{ description: "Test crashes", result: EXEC_FAILED, bug: 69591477, |