diff options
Diffstat (limited to 'compiler/utils')
| -rw-r--r-- | compiler/utils/atomic_method_ref_map-inl.h | 83 | ||||
| -rw-r--r-- | compiler/utils/atomic_method_ref_map.h | 71 | ||||
| -rw-r--r-- | compiler/utils/atomic_method_ref_map_test.cc | 71 | ||||
| -rw-r--r-- | compiler/utils/string_reference_test.cc | 19 | ||||
| -rw-r--r-- | compiler/utils/test_dex_file_builder_test.cc | 3 |
5 files changed, 238 insertions, 9 deletions
diff --git a/compiler/utils/atomic_method_ref_map-inl.h b/compiler/utils/atomic_method_ref_map-inl.h new file mode 100644 index 0000000000..70ea028b17 --- /dev/null +++ b/compiler/utils/atomic_method_ref_map-inl.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2016 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_COMPILER_UTILS_ATOMIC_METHOD_REF_MAP_INL_H_ +#define ART_COMPILER_UTILS_ATOMIC_METHOD_REF_MAP_INL_H_ + +#include "atomic_method_ref_map.h" + +#include "dex_file-inl.h" + +namespace art { + +template <typename T> +inline typename AtomicMethodRefMap<T>::InsertResult AtomicMethodRefMap<T>::Insert( + MethodReference ref, + const T& expected, + const T& desired) { + ElementArray* const array = GetArray(ref.dex_file); + if (array == nullptr) { + return kInsertResultInvalidDexFile; + } + return (*array)[ref.dex_method_index].CompareExchangeStrongSequentiallyConsistent( + expected, desired) + ? kInsertResultSuccess + : kInsertResultCASFailure; +} + +template <typename T> +inline bool AtomicMethodRefMap<T>::Get(MethodReference ref, T* out) const { + const ElementArray* const array = GetArray(ref.dex_file); + if (array == nullptr) { + return kInsertResultInvalidDexFile; + } + *out = (*array)[ref.dex_method_index].LoadRelaxed(); + return true; +} + +template <typename T> +inline void AtomicMethodRefMap<T>::AddDexFile(const DexFile* dex_file) { + arrays_.Put(dex_file, std::move(ElementArray(dex_file->NumMethodIds()))); +} + +template <typename T> +inline typename AtomicMethodRefMap<T>::ElementArray* AtomicMethodRefMap<T>::GetArray( + const DexFile* dex_file) { + auto it = arrays_.find(dex_file); + return (it != arrays_.end()) ? &it->second : nullptr; +} + +template <typename T> +inline const typename AtomicMethodRefMap<T>::ElementArray* AtomicMethodRefMap<T>::GetArray( + const DexFile* dex_file) const { + auto it = arrays_.find(dex_file); + return (it != arrays_.end()) ? &it->second : nullptr; +} + +template <typename T> template <typename Visitor> +inline void AtomicMethodRefMap<T>::Visit(const Visitor& visitor) { + for (auto& pair : arrays_) { + const DexFile* dex_file = pair.first; + const ElementArray& elements = pair.second; + for (size_t i = 0; i < elements.size(); ++i) { + visitor(MethodReference(dex_file, i), elements[i].LoadRelaxed()); + } + } +} + +} // namespace art + +#endif // ART_COMPILER_UTILS_ATOMIC_METHOD_REF_MAP_INL_H_ diff --git a/compiler/utils/atomic_method_ref_map.h b/compiler/utils/atomic_method_ref_map.h new file mode 100644 index 0000000000..11ab211817 --- /dev/null +++ b/compiler/utils/atomic_method_ref_map.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 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_COMPILER_UTILS_ATOMIC_METHOD_REF_MAP_H_ +#define ART_COMPILER_UTILS_ATOMIC_METHOD_REF_MAP_H_ + +#include "base/dchecked_vector.h" +#include "method_reference.h" +#include "safe_map.h" + +namespace art { + +class DexFile; + +// Used by CompilerCallbacks to track verification information from the Runtime. +template <typename T> +class AtomicMethodRefMap { + public: + explicit AtomicMethodRefMap() {} + ~AtomicMethodRefMap() {} + + // Atomically swap the element in if the existing value matches expected. + enum InsertResult { + kInsertResultInvalidDexFile, + kInsertResultCASFailure, + kInsertResultSuccess, + }; + InsertResult Insert(MethodReference ref, const T& expected, const T& desired); + + // Retreive an item, returns false if the dex file is not added. + bool Get(MethodReference ref, T* out) const; + + // Dex files must be added before method references belonging to them can be used as keys. Not + // thread safe. + void AddDexFile(const DexFile* dex_file); + + bool HaveDexFile(const DexFile* dex_file) const { + return arrays_.find(dex_file) != arrays_.end(); + } + + // Visit all of the dex files and elements. + template <typename Visitor> + void Visit(const Visitor& visitor); + + private: + // Verified methods. The method array is fixed to avoid needing a lock to extend it. + using ElementArray = dchecked_vector<Atomic<T>>; + using DexFileArrays = SafeMap<const DexFile*, ElementArray>; + + const ElementArray* GetArray(const DexFile* dex_file) const; + ElementArray* GetArray(const DexFile* dex_file); + + DexFileArrays arrays_; +}; + +} // namespace art + +#endif // ART_COMPILER_UTILS_ATOMIC_METHOD_REF_MAP_H_ diff --git a/compiler/utils/atomic_method_ref_map_test.cc b/compiler/utils/atomic_method_ref_map_test.cc new file mode 100644 index 0000000000..9e5bf4bbe1 --- /dev/null +++ b/compiler/utils/atomic_method_ref_map_test.cc @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 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 "atomic_method_ref_map-inl.h" + +#include <memory> + +#include "common_runtime_test.h" +#include "dex_file-inl.h" +#include "method_reference.h" +#include "scoped_thread_state_change-inl.h" + +namespace art { + +class AtomicMethodRefMapTest : public CommonRuntimeTest {}; + +TEST_F(AtomicMethodRefMapTest, RunTests) { + ScopedObjectAccess soa(Thread::Current()); + std::unique_ptr<const DexFile> dex(OpenTestDexFile("Interfaces")); + ASSERT_TRUE(dex != nullptr); + using Map = AtomicMethodRefMap<int>; + Map map; + int value = 123; + // Error case: Not already inserted. + EXPECT_FALSE(map.Get(MethodReference(dex.get(), 1), &value)); + EXPECT_FALSE(map.HaveDexFile(dex.get())); + // Error case: Dex file not registered. + EXPECT_TRUE(map.Insert(MethodReference(dex.get(), 1), 0, 1) == Map::kInsertResultInvalidDexFile); + map.AddDexFile(dex.get()); + EXPECT_TRUE(map.HaveDexFile(dex.get())); + EXPECT_GT(dex->NumMethodIds(), 10u); + // After we have added the get should succeed but return the default value. + EXPECT_TRUE(map.Get(MethodReference(dex.get(), 1), &value)); + EXPECT_EQ(value, 0); + // Actually insert an item and make sure we can retreive it. + static const int kInsertValue = 44; + EXPECT_TRUE(map.Insert(MethodReference(dex.get(), 1), 0, kInsertValue) == + Map::kInsertResultSuccess); + EXPECT_TRUE(map.Get(MethodReference(dex.get(), 1), &value)); + EXPECT_EQ(value, kInsertValue); + static const int kInsertValue2 = 123; + EXPECT_TRUE(map.Insert(MethodReference(dex.get(), 2), 0, kInsertValue2) == + Map::kInsertResultSuccess); + EXPECT_TRUE(map.Get(MethodReference(dex.get(), 1), &value)); + EXPECT_EQ(value, kInsertValue); + EXPECT_TRUE(map.Get(MethodReference(dex.get(), 2), &value)); + EXPECT_EQ(value, kInsertValue2); + // Error case: Incorrect expected value for CAS. + EXPECT_TRUE(map.Insert(MethodReference(dex.get(), 1), 0, kInsertValue + 1) == + Map::kInsertResultCASFailure); + // Correctly overwrite the value and verify. + EXPECT_TRUE(map.Insert(MethodReference(dex.get(), 1), kInsertValue, kInsertValue + 1) == + Map::kInsertResultSuccess); + EXPECT_TRUE(map.Get(MethodReference(dex.get(), 1), &value)); + EXPECT_EQ(value, kInsertValue + 1); +} + +} // namespace art diff --git a/compiler/utils/string_reference_test.cc b/compiler/utils/string_reference_test.cc index 0fd9e5ba53..90335eb048 100644 --- a/compiler/utils/string_reference_test.cc +++ b/compiler/utils/string_reference_test.cc @@ -18,6 +18,7 @@ #include <memory> +#include "dex_file_types.h" #include "gtest/gtest.h" #include "utils/test_dex_file_builder.h" @@ -34,15 +35,15 @@ TEST(StringReference, ValueComparator) { builder1.AddString("String1"); std::unique_ptr<const DexFile> dex_file1 = builder1.Build("dummy location 1"); ASSERT_EQ(1u, dex_file1->NumStringIds()); - ASSERT_STREQ("String1", dex_file1->GetStringData(dex_file1->GetStringId(0))); - StringReference sr1(dex_file1.get(), 0); + ASSERT_STREQ("String1", dex_file1->GetStringData(dex_file1->GetStringId(dex::StringIndex(0)))); + StringReference sr1(dex_file1.get(), dex::StringIndex(0)); TestDexFileBuilder builder2; builder2.AddString("String2"); std::unique_ptr<const DexFile> dex_file2 = builder2.Build("dummy location 2"); ASSERT_EQ(1u, dex_file2->NumStringIds()); - ASSERT_STREQ("String2", dex_file2->GetStringData(dex_file2->GetStringId(0))); - StringReference sr2(dex_file2.get(), 0); + ASSERT_STREQ("String2", dex_file2->GetStringData(dex_file2->GetStringId(dex::StringIndex(0)))); + StringReference sr2(dex_file2.get(), dex::StringIndex(0)); StringReferenceValueComparator cmp; EXPECT_TRUE(cmp(sr1, sr2)); // "String1" < "String2" is true. @@ -80,7 +81,8 @@ TEST(StringReference, ValueComparator2) { std::unique_ptr<const DexFile> dex_file1 = builder1.Build("dummy location 1"); ASSERT_EQ(arraysize(kDexFile1Strings), dex_file1->NumStringIds()); for (size_t index = 0; index != arraysize(kDexFile1Strings); ++index) { - ASSERT_STREQ(kDexFile1Strings[index], dex_file1->GetStringData(dex_file1->GetStringId(index))); + ASSERT_STREQ(kDexFile1Strings[index], + dex_file1->GetStringData(dex_file1->GetStringId(dex::StringIndex(index)))); } TestDexFileBuilder builder2; @@ -90,14 +92,15 @@ TEST(StringReference, ValueComparator2) { std::unique_ptr<const DexFile> dex_file2 = builder2.Build("dummy location 1"); ASSERT_EQ(arraysize(kDexFile2Strings), dex_file2->NumStringIds()); for (size_t index = 0; index != arraysize(kDexFile2Strings); ++index) { - ASSERT_STREQ(kDexFile2Strings[index], dex_file2->GetStringData(dex_file2->GetStringId(index))); + ASSERT_STREQ(kDexFile2Strings[index], + dex_file2->GetStringData(dex_file2->GetStringId(dex::StringIndex(index)))); } StringReferenceValueComparator cmp; for (size_t index1 = 0; index1 != arraysize(kDexFile1Strings); ++index1) { for (size_t index2 = 0; index2 != arraysize(kDexFile2Strings); ++index2) { - StringReference sr1(dex_file1.get(), index1); - StringReference sr2(dex_file2.get(), index2); + StringReference sr1(dex_file1.get(), dex::StringIndex(index1)); + StringReference sr2(dex_file2.get(), dex::StringIndex(index2)); EXPECT_EQ(expectedCmp12[index1][index2], cmp(sr1, sr2)) << index1 << " " << index2; EXPECT_EQ(expectedCmp21[index2][index1], cmp(sr2, sr1)) << index1 << " " << index2; } diff --git a/compiler/utils/test_dex_file_builder_test.cc b/compiler/utils/test_dex_file_builder_test.cc index 922f8b1dfa..c76739b3b1 100644 --- a/compiler/utils/test_dex_file_builder_test.cc +++ b/compiler/utils/test_dex_file_builder_test.cc @@ -49,7 +49,8 @@ TEST(TestDexFileBuilderTest, SimpleTest) { }; ASSERT_EQ(arraysize(expected_strings), dex_file->NumStringIds()); for (size_t i = 0; i != arraysize(expected_strings); ++i) { - EXPECT_STREQ(expected_strings[i], dex_file->GetStringData(dex_file->GetStringId(i))) << i; + EXPECT_STREQ(expected_strings[i], + dex_file->GetStringData(dex_file->GetStringId(dex::StringIndex(i)))) << i; } static const char* const expected_types[] = { |