diff options
-rw-r--r-- | build/Android.gtest.mk | 3 | ||||
-rw-r--r-- | compiler/dex/quick/local_optimizations.cc | 4 | ||||
-rw-r--r-- | runtime/class_linker.cc | 17 | ||||
-rw-r--r-- | runtime/common_runtime_test.cc | 15 | ||||
-rw-r--r-- | runtime/common_runtime_test.h | 8 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints.cc | 3 | ||||
-rw-r--r-- | runtime/gc/accounting/card_table.cc | 19 | ||||
-rw-r--r-- | runtime/gc/accounting/card_table.h | 8 | ||||
-rw-r--r-- | runtime/gc/accounting/card_table_test.cc | 143 | ||||
-rw-r--r-- | runtime/mirror/art_method.cc | 12 | ||||
-rw-r--r-- | runtime/monitor_pool.cc | 6 | ||||
-rw-r--r-- | runtime/proxy_test.cc | 10 | ||||
-rw-r--r-- | test/Android.run-test.mk | 30 |
13 files changed, 215 insertions, 63 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index 6e27190bd3..17c478c6d1 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -91,6 +91,7 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \ runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc \ runtime/entrypoints_order_test.cc \ runtime/exception_test.cc \ + runtime/gc/accounting/card_table_test.cc \ runtime/gc/accounting/space_bitmap_test.cc \ runtime/gc/heap_test.cc \ runtime/gc/space/dlmalloc_space_base_test.cc \ @@ -113,6 +114,7 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \ runtime/monitor_pool_test.cc \ runtime/monitor_test.cc \ runtime/parsed_options_test.cc \ + runtime/proxy_test.cc \ runtime/reference_table_test.cc \ runtime/thread_pool_test.cc \ runtime/transaction_test.cc \ @@ -123,7 +125,6 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \ COMPILER_GTEST_COMMON_SRC_FILES := \ runtime/jni_internal_test.cc \ - runtime/proxy_test.cc \ runtime/reflection_test.cc \ compiler/dex/global_value_numbering_test.cc \ compiler/dex/local_value_numbering_test.cc \ diff --git a/compiler/dex/quick/local_optimizations.cc b/compiler/dex/quick/local_optimizations.cc index eec2b32726..e0f4691063 100644 --- a/compiler/dex/quick/local_optimizations.cc +++ b/compiler/dex/quick/local_optimizations.cc @@ -200,7 +200,7 @@ void Mir2Lir::ApplyLoadStoreElimination(LIR* head_lir, LIR* tail_lir) { /* Initialize alias list */ alias_list.clear(); ResourceMask alias_reg_list_mask = kEncodeNone; - if (!this_mem_mask.Intersects(kEncodeLiteral)) { + if (!this_mem_mask.Intersects(kEncodeMem) && !this_mem_mask.Intersects(kEncodeLiteral)) { alias_list.push_back(dest_reg_id); SetupRegMask(&alias_reg_list_mask, dest_reg_id); } @@ -248,7 +248,7 @@ void Mir2Lir::ApplyLoadStoreElimination(LIR* head_lir, LIR* tail_lir) { bool is_check_lir_load = check_flags & IS_LOAD; bool reg_compatible = RegStorage::SameRegType(check_lir->operands[0], native_reg_id); - if (alias_mem_mask.Equals(kEncodeLiteral)) { + if (!alias_mem_mask.Intersects(kEncodeMem) && alias_mem_mask.Equals(kEncodeLiteral)) { DCHECK(check_flags & IS_LOAD); /* Same value && same register type */ if (reg_compatible && (this_lir->target == check_lir->target)) { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index c1e3b257f7..f0b1b9578f 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -3516,14 +3516,19 @@ mirror::ArtMethod* ClassLinker::CreateProxyConstructor(Thread* self, proxy_class->GetDirectMethods(); CHECK_EQ(proxy_direct_methods->GetLength(), 16); mirror::ArtMethod* proxy_constructor = proxy_direct_methods->Get(2); - // Clone the existing constructor of Proxy (our constructor would just invoke it so steal its - // code_ too) - mirror::ArtMethod* constructor = - down_cast<mirror::ArtMethod*>(proxy_constructor->Clone(self)); - if (constructor == NULL) { + mirror::ArtMethod* constructor = down_cast<mirror::ArtMethod*>(proxy_constructor->Clone(self)); + if (constructor == nullptr) { CHECK(self->IsExceptionPending()); // OOME. - return NULL; + return nullptr; } + // Make the proxy constructor's code always point to the uninstrumented code. This avoids + // getting a method enter event for the proxy constructor as the proxy constructor doesn't + // have an activation. + bool have_portable_code; + constructor->SetEntryPointFromQuickCompiledCode(GetQuickOatCodeFor(proxy_constructor)); + constructor->SetEntryPointFromPortableCompiledCode(GetPortableOatCodeFor(proxy_constructor, + &have_portable_code)); + // Make this constructor public and fix the class to be our Proxy version constructor->SetAccessFlags((constructor->GetAccessFlags() & ~kAccProtected) | kAccPublic); constructor->SetDeclaringClass(klass.Get()); diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc index 8e363c4fa3..6cf56196d6 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -212,7 +212,7 @@ void CommonRuntimeTest::ClearDirectory(const char* dirpath) { if ((strcmp(e->d_name, ".") == 0) || (strcmp(e->d_name, "..") == 0)) { continue; } - std::string filename(dalvik_cache_); + std::string filename(dirpath); filename.push_back('/'); filename.append(e->d_name); int stat_result = lstat(filename.c_str(), &s); @@ -265,6 +265,19 @@ std::string CommonRuntimeTest::GetDexFileName(const std::string& jar_prefix) { return StringPrintf("%s/framework/%s.jar", GetAndroidRoot(), jar_prefix.c_str()); } +std::string CommonRuntimeTest::GetLibCoreOatFileName() { + return GetOatFileName("core"); +} + +std::string CommonRuntimeTest::GetOatFileName(const std::string& oat_prefix) { + if (IsHost()) { + const char* host_dir = getenv("ANDROID_HOST_OUT"); + CHECK(host_dir != nullptr); + return StringPrintf("%s/framework/%s.art", host_dir, oat_prefix.c_str()); + } + return StringPrintf("%s/framework/%s.art", GetAndroidRoot(), oat_prefix.c_str()); +} + std::string CommonRuntimeTest::GetTestAndroidRoot() { if (IsHost()) { const char* host_dir = getenv("ANDROID_HOST_OUT"); diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h index eb963525e8..363d8daaf8 100644 --- a/runtime/common_runtime_test.h +++ b/runtime/common_runtime_test.h @@ -85,10 +85,18 @@ class CommonRuntimeTest : public testing::Test { virtual void TearDown(); + // Gets the path of the libcore dex file. std::string GetLibCoreDexFileName(); + // Gets the path of the specified dex file for host or target. std::string GetDexFileName(const std::string& jar_prefix); + // Gets the path of the libcore oat file. + std::string GetLibCoreOatFileName(); + + // Gets the path of the specified oat file for host or target. + std::string GetOatFileName(const std::string& oat_prefix); + std::string GetTestAndroidRoot(); std::vector<const DexFile*> OpenTestDexFiles(const char* name) diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 49bb65f488..fa198d7ef5 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -592,8 +592,7 @@ extern "C" uint64_t artQuickProxyInvokeHandler(mirror::ArtMethod* proxy_method, const char* old_cause = self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments"); // Register the top of the managed stack, making stack crawlable. - DCHECK_EQ(sp->AsMirrorPtr(), proxy_method) - << PrettyMethod(proxy_method); + DCHECK_EQ(sp->AsMirrorPtr(), proxy_method) << PrettyMethod(proxy_method); self->SetTopOfStack(sp, 0); DCHECK_EQ(proxy_method->GetFrameSizeInBytes(), Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes()) diff --git a/runtime/gc/accounting/card_table.cc b/runtime/gc/accounting/card_table.cc index ceb42e5936..049855000b 100644 --- a/runtime/gc/accounting/card_table.cc +++ b/runtime/gc/accounting/card_table.cc @@ -28,6 +28,11 @@ namespace art { namespace gc { namespace accounting { +constexpr size_t CardTable::kCardShift; +constexpr size_t CardTable::kCardSize; +constexpr uint8_t CardTable::kCardClean; +constexpr uint8_t CardTable::kCardDirty; + /* * Maintain a card table from the write barrier. All writes of * non-NULL values to heap addresses should go through an entry in @@ -55,9 +60,9 @@ CardTable* CardTable::Create(const byte* heap_begin, size_t heap_capacity) { size_t capacity = heap_capacity / kCardSize; /* Allocate an extra 256 bytes to allow fixed low-byte of base */ std::string error_msg; - std::unique_ptr<MemMap> mem_map(MemMap::MapAnonymous("card table", NULL, - capacity + 256, PROT_READ | PROT_WRITE, - false, &error_msg)); + std::unique_ptr<MemMap> mem_map( + MemMap::MapAnonymous("card table", nullptr, capacity + 256, PROT_READ | PROT_WRITE, + false, &error_msg)); CHECK(mem_map.get() != NULL) << "couldn't allocate card table: " << error_msg; // All zeros is the correct initial value; all clean. Anonymous mmaps are initialized to zero, we // don't clear the card table to avoid unnecessary pages being allocated @@ -67,17 +72,17 @@ CardTable* CardTable::Create(const byte* heap_begin, size_t heap_capacity) { CHECK(cardtable_begin != NULL); // We allocated up to a bytes worth of extra space to allow biased_begin's byte value to equal - // GC_CARD_DIRTY, compute a offset value to make this the case + // kCardDirty, compute a offset value to make this the case size_t offset = 0; byte* biased_begin = reinterpret_cast<byte*>(reinterpret_cast<uintptr_t>(cardtable_begin) - (reinterpret_cast<uintptr_t>(heap_begin) >> kCardShift)); - if (((uintptr_t)biased_begin & 0xff) != kCardDirty) { - int delta = kCardDirty - (reinterpret_cast<uintptr_t>(biased_begin) & 0xff); + uintptr_t biased_byte = reinterpret_cast<uintptr_t>(biased_begin) & 0xff; + if (biased_byte != kCardDirty) { + int delta = kCardDirty - biased_byte; offset = delta + (delta < 0 ? 0x100 : 0); biased_begin += offset; } CHECK_EQ(reinterpret_cast<uintptr_t>(biased_begin) & 0xff, kCardDirty); - return new CardTable(mem_map.release(), biased_begin, offset); } diff --git a/runtime/gc/accounting/card_table.h b/runtime/gc/accounting/card_table.h index 7934974081..fbeea85554 100644 --- a/runtime/gc/accounting/card_table.h +++ b/runtime/gc/accounting/card_table.h @@ -46,10 +46,10 @@ template<size_t kAlignment> class SpaceBitmap; // WriteBarrier, and from there to here. class CardTable { public: - static const size_t kCardShift = 7; - static const size_t kCardSize = (1 << kCardShift); - static const uint8_t kCardClean = 0x0; - static const uint8_t kCardDirty = 0x70; + static constexpr size_t kCardShift = 7; + static constexpr size_t kCardSize = 1 << kCardShift; + static constexpr uint8_t kCardClean = 0x0; + static constexpr uint8_t kCardDirty = 0x70; static CardTable* Create(const byte* heap_begin, size_t heap_capacity); diff --git a/runtime/gc/accounting/card_table_test.cc b/runtime/gc/accounting/card_table_test.cc new file mode 100644 index 0000000000..a88b2c9881 --- /dev/null +++ b/runtime/gc/accounting/card_table_test.cc @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2014 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. + */ + +#include "card_table-inl.h" + +#include <string> + +#include "atomic.h" +#include "common_runtime_test.h" +#include "handle_scope-inl.h" +#include "mirror/class-inl.h" +#include "mirror/string-inl.h" // Strings are easiest to allocate +#include "scoped_thread_state_change.h" +#include "thread_pool.h" +#include "utils.h" + +namespace art { + +namespace mirror { + class Object; +} // namespace mirror + +class CardTableTest : public CommonRuntimeTest { + public: + std::unique_ptr<gc::accounting::CardTable> card_table_; + static constexpr size_t kCardSize = gc::accounting::CardTable::kCardSize; + + void CommonSetup() { + if (card_table_.get() == nullptr) { + card_table_.reset(gc::accounting::CardTable::Create(heap_begin_, heap_size_)); + EXPECT_TRUE(card_table_.get() != nullptr); + } else { + ClearCardTable(); + } + } + // Default values for the test, not random to avoid undeterministic behaviour. + CardTableTest() : heap_begin_(reinterpret_cast<byte*>(0x2000000)), heap_size_(2 * MB) { + } + void ClearCardTable() { + card_table_->ClearCardTable(); + } + byte* HeapBegin() const { + return heap_begin_; + } + byte* HeapLimit() const { + return HeapBegin() + heap_size_; + } + byte PRandCard(const byte* addr) const { + size_t offset = RoundDown(addr - heap_begin_, kCardSize); + return 1 + offset % 254; + } + void FillRandom() { + for (const byte* addr = HeapBegin(); addr != HeapLimit(); addr += kCardSize) { + EXPECT_TRUE(card_table_->AddrIsInCardTable(addr)); + byte* card = card_table_->CardFromAddr(addr); + *card = PRandCard(addr); + } + } + + private: + byte* const heap_begin_; + const size_t heap_size_; +}; + +TEST_F(CardTableTest, TestMarkCard) { + CommonSetup(); + for (const byte* addr = HeapBegin(); addr < HeapLimit(); addr += kObjectAlignment) { + auto obj = reinterpret_cast<const mirror::Object*>(addr); + EXPECT_EQ(card_table_->GetCard(obj), gc::accounting::CardTable::kCardClean); + EXPECT_TRUE(!card_table_->IsDirty(obj)); + card_table_->MarkCard(addr); + EXPECT_TRUE(card_table_->IsDirty(obj)); + EXPECT_EQ(card_table_->GetCard(obj), gc::accounting::CardTable::kCardDirty); + byte* card_addr = card_table_->CardFromAddr(addr); + EXPECT_EQ(*card_addr, gc::accounting::CardTable::kCardDirty); + *card_addr = gc::accounting::CardTable::kCardClean; + EXPECT_EQ(*card_addr, gc::accounting::CardTable::kCardClean); + } +} + +class UpdateVisitor { + public: + byte operator()(byte c) const { + return c * 93 + 123; + } + void operator()(byte* /*card*/, byte /*expected_value*/, byte /*new_value*/) const { + } +}; + +TEST_F(CardTableTest, TestModifyCardsAtomic) { + CommonSetup(); + FillRandom(); + const size_t delta = std::min(static_cast<size_t>(HeapLimit() - HeapBegin()), 8U * kCardSize); + UpdateVisitor visitor; + size_t start_offset = 0; + for (byte* cstart = HeapBegin(); cstart < HeapBegin() + delta; cstart += kCardSize) { + start_offset = (start_offset + kObjectAlignment) % kCardSize; + size_t end_offset = 0; + for (byte* cend = HeapLimit() - delta; cend < HeapLimit(); cend += kCardSize) { + // Don't always start at a card boundary. + byte* start = cstart + start_offset; + byte* end = cend - end_offset; + end_offset = (end_offset + kObjectAlignment) % kCardSize; + // Modify cards. + card_table_->ModifyCardsAtomic(start, end, visitor, visitor); + // Check adjacent cards not modified. + for (byte* cur = start - kCardSize; cur >= HeapBegin(); cur -= kCardSize) { + EXPECT_EQ(card_table_->GetCard(reinterpret_cast<mirror::Object*>(cur)), PRandCard(cur)); + } + for (byte* cur = end + kCardSize; cur < HeapLimit(); cur += kCardSize) { + EXPECT_EQ(card_table_->GetCard(reinterpret_cast<mirror::Object*>(cur)), PRandCard(cur)); + } + // Verify Range. + for (byte* cur = start; cur < AlignUp(end, kCardSize); cur += kCardSize) { + byte* card = card_table_->CardFromAddr(cur); + byte value = PRandCard(cur); + if (visitor(value) != *card) { + LOG(ERROR) << reinterpret_cast<void*>(start) << " " << reinterpret_cast<void*>(cur) << " " << reinterpret_cast<void*>(end); + } + EXPECT_EQ(visitor(value), *card); + // Restore for next iteration. + *card = value; + } + } + } +} + +// TODO: Add test for CardTable::Scan. + +} // namespace art diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc index 4882728e0d..8eacb1c3d7 100644 --- a/runtime/mirror/art_method.cc +++ b/runtime/mirror/art_method.cc @@ -157,12 +157,12 @@ ArtMethod* ArtMethod::FindOverriddenMethod() { } } } -#ifndef NDEBUG - StackHandleScope<2> hs(Thread::Current()); - MethodHelper result_mh(hs.NewHandle(result)); - MethodHelper this_mh(hs.NewHandle(this)); - DCHECK(result == NULL || this_mh.HasSameNameAndSignature(&result_mh)); -#endif + if (kIsDebugBuild) { + StackHandleScope<2> hs(Thread::Current()); + MethodHelper result_mh(hs.NewHandle(result)); + MethodHelper this_mh(hs.NewHandle(this)); + DCHECK(result == nullptr || this_mh.HasSameNameAndSignature(&result_mh)); + } return result; } diff --git a/runtime/monitor_pool.cc b/runtime/monitor_pool.cc index 440a6be07b..4964aa06c5 100644 --- a/runtime/monitor_pool.cc +++ b/runtime/monitor_pool.cc @@ -52,7 +52,7 @@ void MonitorPool::AllocateChunk() { monitor_chunks_.StoreRelaxed(new_backing); capacity_ = new_capacity; old_chunk_arrays_.push_back(old_backing); - LOG(INFO) << "Resizing to capacity " << capacity_; + VLOG(monitor) << "Resizing to capacity " << capacity_; } } @@ -64,7 +64,7 @@ void MonitorPool::AllocateChunk() { CHECK_EQ(0U, reinterpret_cast<uintptr_t>(chunk) % kMonitorAlignment); // Add the chunk. - *(monitor_chunks_.LoadRelaxed()+num_chunks_) = reinterpret_cast<uintptr_t>(chunk); + *(monitor_chunks_.LoadRelaxed() + num_chunks_) = reinterpret_cast<uintptr_t>(chunk); num_chunks_++; // Set up the free list @@ -96,7 +96,7 @@ Monitor* MonitorPool::CreateMonitorInPool(Thread* self, Thread* owner, mirror::O // Enough space, or need to resize? if (first_free_ == nullptr) { - LOG(INFO) << "Allocating a new chunk."; + VLOG(monitor) << "Allocating a new chunk."; AllocateChunk(); } diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc index bd6656dda1..308142157c 100644 --- a/runtime/proxy_test.cc +++ b/runtime/proxy_test.cc @@ -17,14 +17,14 @@ #include <jni.h> #include <vector> -#include "common_compiler_test.h" +#include "common_runtime_test.h" #include "field_helper.h" #include "mirror/art_field-inl.h" #include "scoped_thread_state_change.h" namespace art { -class ProxyTest : public CommonCompilerTest { +class ProxyTest : public CommonRuntimeTest { public: // Generate a proxy class with the given name and interfaces. This is a simplification from what // libcore does to fit to our test needs. We do not check for duplicated interfaces or methods and @@ -103,6 +103,12 @@ class ProxyTest : public CommonCompilerTest { soa.Self()->AssertNoPendingException(); return proxyClass; } + + protected: + void SetUpRuntimeOptions(RuntimeOptions *options) OVERRIDE { + options->push_back(std::make_pair(StringPrintf("-Ximage:%s", GetLibCoreOatFileName().c_str()), + nullptr)); + } }; // Creates a proxy class and check ClassHelper works correctly. diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index 5c1bc0395f..d7ee383db7 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -81,38 +81,10 @@ endif # Tests that are broken in --trace mode. TEST_ART_BROKEN_TRACE_RUN_TESTS := \ - 003-omnibus-opcodes \ - 004-InterfaceTest \ 004-SignalTest \ - 004-ThreadStress \ - 005-annotations \ - 012-math \ 018-stack-overflow \ - 023-many-interfaces \ - 027-arithmetic \ - 031-class-attributes \ - 037-inherit \ - 044-proxy \ - 046-reflect \ - 051-thread \ - 055-enum-performance \ - 062-character-encodings \ - 064-field-access \ - 074-gc-thrash \ - 078-polymorphic-virtual \ - 080-oom-throw \ - 082-inline-execute \ - 083-compiler-regressions \ - 093-serialization \ 097-duplicate-method \ - 100-reflect2 \ - 102-concurrent-gc \ - 103-string-append \ - 107-int-math2 \ - 112-double-math \ - 114-ParallelGC \ - 700-LoadArgRegs \ - 701-easy-div-rem + 107-int-math2 ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_TRACE_RUN_TESTS), $(call all-run-test-names,$(test),-trace,-relocate)) ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_TRACE_RUN_TESTS), $(call all-run-test-names,$(test),-trace,-no-prebuild)) |