diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/Android.mk | 2 | ||||
-rw-r--r-- | compiler/dex/arena_allocator_test.cc (renamed from compiler/utils/allocator.h) | 32 | ||||
-rw-r--r-- | compiler/dex/arena_bit_vector.h | 2 | ||||
-rw-r--r-- | compiler/oat_test.cc | 17 | ||||
-rw-r--r-- | compiler/oat_writer.cc | 239 | ||||
-rw-r--r-- | compiler/oat_writer.h | 60 | ||||
-rw-r--r-- | compiler/utils/allocator.cc | 74 | ||||
-rw-r--r-- | compiler/utils/bit_vector.cc | 155 | ||||
-rw-r--r-- | compiler/utils/bit_vector.h | 134 | ||||
-rw-r--r-- | compiler/utils/bit_vector_test.cc | 96 | ||||
-rw-r--r-- | compiler/utils/dedupe_set.h | 1 | ||||
-rw-r--r-- | compiler/utils/dedupe_set_test.cc | 3 |
12 files changed, 262 insertions, 553 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk index 0d3acbdb71..fc2f02b59e 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -79,8 +79,6 @@ LIBART_COMPILER_SRC_FILES := \ utils/arm/assembler_arm.cc \ utils/arm/managed_register_arm.cc \ utils/assembler.cc \ - utils/allocator.cc \ - utils/bit_vector.cc \ utils/mips/assembler_mips.cc \ utils/mips/managed_register_mips.cc \ utils/x86/assembler_x86.cc \ diff --git a/compiler/utils/allocator.h b/compiler/dex/arena_allocator_test.cc index 3482a7928e..63dc6159eb 100644 --- a/compiler/utils/allocator.h +++ b/compiler/dex/arena_allocator_test.cc @@ -14,28 +14,20 @@ * limitations under the License. */ -#ifndef ART_COMPILER_UTILS_ALLOCATOR_H_ -#define ART_COMPILER_UTILS_ALLOCATOR_H_ - -#include "base/macros.h" +#include "arena_allocator.h" +#include "arena_bit_vector.h" +#include "gtest/gtest.h" namespace art { -class Allocator { - public: - static Allocator* GetMallocAllocator(); - static Allocator* GetNoopAllocator(); - - Allocator() {} - virtual ~Allocator() {} - - virtual void* Alloc(size_t) = 0; - virtual void Free(void*) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(Allocator); -}; +TEST(ArenaAllocator, Test) { + ArenaPool pool; + ArenaAllocator arena(&pool); + ArenaBitVector bv(&arena, 10, true); + bv.SetBit(5); + EXPECT_EQ(1U, bv.GetStorageSize()); + bv.SetBit(35); + EXPECT_EQ(2U, bv.GetStorageSize()); +} } // namespace art - -#endif // ART_COMPILER_UTILS_ALLOCATOR_H_ diff --git a/compiler/dex/arena_bit_vector.h b/compiler/dex/arena_bit_vector.h index 7d2f3ffa5e..4b2193a3f1 100644 --- a/compiler/dex/arena_bit_vector.h +++ b/compiler/dex/arena_bit_vector.h @@ -18,8 +18,8 @@ #define ART_COMPILER_DEX_ARENA_BIT_VECTOR_H_ #include "arena_allocator.h" +#include "base/bit_vector.h" #include "compiler_enums.h" -#include "utils/bit_vector.h" namespace art { diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index 634a160a97..af86743014 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -28,6 +28,8 @@ namespace art { class OatTest : public CommonTest { protected: + static const bool kCompile = false; // DISABLED_ due to the time to compile libcore + void CheckMethod(mirror::ArtMethod* method, const OatFile::OatMethod& oat_method, const DexFile* dex_file) @@ -40,7 +42,7 @@ class OatTest : public CommonTest { EXPECT_TRUE(oat_method.GetCode() == NULL) << PrettyMethod(method) << " " << oat_method.GetCode(); #if !defined(ART_USE_PORTABLE_COMPILER) - EXPECT_EQ(oat_method.GetFrameSizeInBytes(), static_cast<uint32_t>(kStackAlignment)); + EXPECT_EQ(oat_method.GetFrameSizeInBytes(), kCompile ? kStackAlignment : 0); EXPECT_EQ(oat_method.GetCoreSpillMask(), 0U); EXPECT_EQ(oat_method.GetFpSpillMask(), 0U); #endif @@ -65,7 +67,6 @@ class OatTest : public CommonTest { }; TEST_F(OatTest, WriteRead) { - const bool compile = false; // DISABLED_ due to the time to compile libcore ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); // TODO: make selectable @@ -77,7 +78,7 @@ TEST_F(OatTest, WriteRead) { InstructionSet insn_set = kIsTargetBuild ? kThumb2 : kX86; compiler_driver_.reset(new CompilerDriver(compiler_backend, insn_set, false, NULL, 2, true)); jobject class_loader = NULL; - if (compile) { + if (kCompile) { base::TimingLogger timings("OatTest::WriteRead", false, false); compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings); } @@ -96,7 +97,7 @@ TEST_F(OatTest, WriteRead) { tmp.GetFile()); ASSERT_TRUE(success); - if (compile) { // OatWriter strips the code, regenerate to compare + if (kCompile) { // OatWriter strips the code, regenerate to compare base::TimingLogger timings("CommonTest::WriteRead", false, false); compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings); } @@ -120,16 +121,18 @@ TEST_F(OatTest, WriteRead) { for (size_t i = 0; i < dex_file->NumClassDefs(); i++) { const DexFile::ClassDef& class_def = dex_file->GetClassDef(i); const byte* class_data = dex_file->GetClassData(class_def); - size_t num_virtual_methods =0; + size_t num_virtual_methods = 0; if (class_data != NULL) { ClassDataItemIterator it(*dex_file, class_data); num_virtual_methods = it.NumVirtualMethods(); } const char* descriptor = dex_file->GetClassDescriptor(class_def); + mirror::Class* klass = class_linker->FindClass(descriptor, NULL); UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(i)); - - mirror::Class* klass = class_linker->FindClass(descriptor, NULL); + CHECK_EQ(mirror::Class::Status::kStatusNotReady, oat_class->GetStatus()) << descriptor; + CHECK_EQ(kCompile ? OatClassType::kOatClassAllCompiled : OatClassType::kOatClassNoneCompiled, + oat_class->GetType()) << descriptor; size_t method_index = 0; for (size_t i = 0; i < klass->NumDirectMethods(); i++, method_index++) { diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index f23b72b466..f681d7da6f 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -18,6 +18,7 @@ #include <zlib.h> +#include "base/bit_vector.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" #include "class_linker.h" @@ -70,7 +71,9 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, size_oat_dex_file_location_checksum_(0), size_oat_dex_file_offset_(0), size_oat_dex_file_methods_offsets_(0), + size_oat_class_type_(0), size_oat_class_status_(0), + size_oat_class_method_bitmaps_(0), size_oat_class_method_offsets_(0) { size_t offset = InitOatHeader(); offset = InitOatDexFiles(offset); @@ -142,12 +145,48 @@ size_t OatWriter::InitOatClasses(size_t offset) { oat_dex_files_[i]->methods_offsets_[class_def_index] = offset; const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); const byte* class_data = dex_file->GetClassData(class_def); - uint32_t num_methods = 0; + uint32_t num_non_null_compiled_methods = 0; + UniquePtr<std::vector<CompiledMethod*> > compiled_methods(new std::vector<CompiledMethod*>()); if (class_data != NULL) { // ie not an empty class, such as a marker interface ClassDataItemIterator it(*dex_file, class_data); size_t num_direct_methods = it.NumDirectMethods(); size_t num_virtual_methods = it.NumVirtualMethods(); - num_methods = num_direct_methods + num_virtual_methods; + size_t num_methods = num_direct_methods + num_virtual_methods; + + // Fill in the compiled_methods_ array for methods that have a + // CompiledMethod. We track the number of non-null entries in + // num_non_null_compiled_methods since we only want to allocate + // OatMethodOffsets for the compiled methods. + compiled_methods->reserve(num_methods); + while (it.HasNextStaticField()) { + it.Next(); + } + while (it.HasNextInstanceField()) { + it.Next(); + } + size_t class_def_method_index = 0; + while (it.HasNextDirectMethod()) { + uint32_t method_idx = it.GetMemberIndex(); + CompiledMethod* compiled_method = + compiler_driver_->GetCompiledMethod(MethodReference(dex_file, method_idx)); + compiled_methods->push_back(compiled_method); + if (compiled_method != NULL) { + num_non_null_compiled_methods++; + } + class_def_method_index++; + it.Next(); + } + while (it.HasNextVirtualMethod()) { + uint32_t method_idx = it.GetMemberIndex(); + CompiledMethod* compiled_method = + compiler_driver_->GetCompiledMethod(MethodReference(dex_file, method_idx)); + compiled_methods->push_back(compiled_method); + if (compiled_method != NULL) { + num_non_null_compiled_methods++; + } + class_def_method_index++; + it.Next(); + } } ClassReference class_ref(dex_file, class_def_index); @@ -161,7 +200,8 @@ size_t OatWriter::InitOatClasses(size_t offset) { status = mirror::Class::kStatusNotReady; } - OatClass* oat_class = new OatClass(offset, status, num_methods); + OatClass* oat_class = new OatClass(offset, compiled_methods.release(), + num_non_null_compiled_methods, status); oat_classes_.push_back(oat_class); offset += oat_class->SizeOf(); } @@ -212,20 +252,20 @@ size_t OatWriter::InitOatCodeDexFiles(size_t offset) { for (size_t i = 0; i != dex_files_->size(); ++i) { const DexFile* dex_file = (*dex_files_)[i]; CHECK(dex_file != NULL); - offset = InitOatCodeDexFile(offset, oat_class_index, *dex_file); + offset = InitOatCodeDexFile(offset, &oat_class_index, *dex_file); } return offset; } size_t OatWriter::InitOatCodeDexFile(size_t offset, - size_t& oat_class_index, + size_t* oat_class_index, const DexFile& dex_file) { for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); - class_def_index++, oat_class_index++) { + class_def_index++, (*oat_class_index)++) { const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); - offset = InitOatCodeClassDef(offset, oat_class_index, class_def_index, dex_file, class_def); - oat_classes_[oat_class_index]->UpdateChecksum(*oat_header_); + offset = InitOatCodeClassDef(offset, *oat_class_index, class_def_index, dex_file, class_def); + oat_classes_[*oat_class_index]->UpdateChecksum(*oat_header_); } return offset; } @@ -240,7 +280,7 @@ size_t OatWriter::InitOatCodeClassDef(size_t offset, return offset; } ClassDataItemIterator it(dex_file, class_data); - CHECK_EQ(oat_classes_[oat_class_index]->method_offsets_.size(), + CHECK_LE(oat_classes_[oat_class_index]->method_offsets_.size(), it.NumDirectMethods() + it.NumVirtualMethods()); // Skip fields while (it.HasNextStaticField()) { @@ -251,32 +291,35 @@ size_t OatWriter::InitOatCodeClassDef(size_t offset, } // Process methods size_t class_def_method_index = 0; + size_t method_offsets_index = 0; while (it.HasNextDirectMethod()) { bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0; offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index, - is_native, it.GetMethodInvokeType(class_def), it.GetMemberIndex(), - &dex_file); + &method_offsets_index, is_native, + it.GetMethodInvokeType(class_def), it.GetMemberIndex(), dex_file); class_def_method_index++; it.Next(); } while (it.HasNextVirtualMethod()) { bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0; offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index, - is_native, it.GetMethodInvokeType(class_def), it.GetMemberIndex(), - &dex_file); + &method_offsets_index, is_native, + it.GetMethodInvokeType(class_def), it.GetMemberIndex(), dex_file); class_def_method_index++; it.Next(); } DCHECK(!it.HasNext()); + CHECK_LE(method_offsets_index, class_def_method_index); return offset; } size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, size_t __attribute__((unused)) class_def_index, size_t class_def_method_index, + size_t* method_offsets_index, bool __attribute__((unused)) is_native, InvokeType invoke_type, - uint32_t method_idx, const DexFile* dex_file) { + uint32_t method_idx, const DexFile& dex_file) { // derived from CompiledMethod if available uint32_t code_offset = 0; uint32_t frame_size_in_bytes = kStackAlignment; @@ -292,8 +335,7 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, oat_class->GetOatMethodOffsetsOffsetFromOatHeader(class_def_method_index); #endif - CompiledMethod* compiled_method = - compiler_driver_->GetCompiledMethod(MethodReference(dex_file, method_idx)); + CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); if (compiled_method != NULL) { #if defined(ART_USE_PORTABLE_COMPILER) compiled_method->AddOatdataOffsetToCompliledCodeOffset( @@ -358,7 +400,7 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, #if !defined(NDEBUG) // We expect GC maps except when the class hasn't been verified or the method is native - ClassReference class_ref(dex_file, class_def_index); + ClassReference class_ref(&dex_file, class_def_index); CompiledClass* compiled_class = compiler_driver_->GetCompiledClass(class_ref); mirror::Class::Status status; if (compiled_class != NULL) { @@ -371,7 +413,7 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified) << &gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " " << (status < mirror::Class::kStatusVerified) << " " << status << " " - << PrettyMethod(method_idx, *dex_file); + << PrettyMethod(method_idx, dex_file); #endif // Deduplicate GC maps @@ -384,24 +426,26 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, offset += gc_map_size; oat_header_->UpdateChecksum(&gc_map[0], gc_map_size); } + + oat_class->method_offsets_[*method_offsets_index] = + OatMethodOffsets(code_offset, + frame_size_in_bytes, + core_spill_mask, + fp_spill_mask, + mapping_table_offset, + vmap_table_offset, + gc_map_offset); + (*method_offsets_index)++; } - oat_class->method_offsets_[class_def_method_index] = - OatMethodOffsets(code_offset, - frame_size_in_bytes, - core_spill_mask, - fp_spill_mask, - mapping_table_offset, - vmap_table_offset, - gc_map_offset); if (compiler_driver_->IsImage()) { ClassLinker* linker = Runtime::Current()->GetClassLinker(); - mirror::DexCache* dex_cache = linker->FindDexCache(*dex_file); + mirror::DexCache* dex_cache = linker->FindDexCache(dex_file); // Unchecked as we hold mutator_lock_ on entry. ScopedObjectAccessUnchecked soa(Thread::Current()); - mirror::ArtMethod* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, - NULL, NULL, invoke_type); + mirror::ArtMethod* method = linker->ResolveMethod(dex_file, method_idx, dex_cache, + NULL, NULL, invoke_type); CHECK(method != NULL); method->SetFrameSizeInBytes(frame_size_in_bytes); method->SetCoreSpillMask(core_spill_mask); @@ -491,7 +535,9 @@ bool OatWriter::Write(OutputStream& out) { DO_STAT(size_oat_dex_file_location_checksum_); DO_STAT(size_oat_dex_file_offset_); DO_STAT(size_oat_dex_file_methods_offsets_); + DO_STAT(size_oat_class_type_); DO_STAT(size_oat_class_status_); + DO_STAT(size_oat_class_method_bitmaps_); DO_STAT(size_oat_class_method_offsets_); #undef DO_STAT @@ -586,7 +632,7 @@ size_t OatWriter::WriteCodeDexFiles(OutputStream& out, for (size_t i = 0; i != oat_dex_files_.size(); ++i) { const DexFile* dex_file = (*dex_files_)[i]; CHECK(dex_file != NULL); - relative_offset = WriteCodeDexFile(out, file_offset, relative_offset, oat_class_index, + relative_offset = WriteCodeDexFile(out, file_offset, relative_offset, &oat_class_index, *dex_file); if (relative_offset == 0) { return 0; @@ -596,12 +642,12 @@ size_t OatWriter::WriteCodeDexFiles(OutputStream& out, } size_t OatWriter::WriteCodeDexFile(OutputStream& out, const size_t file_offset, - size_t relative_offset, size_t& oat_class_index, + size_t relative_offset, size_t* oat_class_index, const DexFile& dex_file) { for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); - class_def_index++, oat_class_index++) { + class_def_index++, (*oat_class_index)++) { const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); - relative_offset = WriteCodeClassDef(out, file_offset, relative_offset, oat_class_index, + relative_offset = WriteCodeClassDef(out, file_offset, relative_offset, *oat_class_index, dex_file, class_def); if (relative_offset == 0) { return 0; @@ -637,11 +683,12 @@ size_t OatWriter::WriteCodeClassDef(OutputStream& out, } // Process methods size_t class_def_method_index = 0; + size_t method_offsets_index = 0; while (it.HasNextDirectMethod()) { bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0; relative_offset = WriteCodeMethod(out, file_offset, relative_offset, oat_class_index, - class_def_method_index, is_static, it.GetMemberIndex(), - dex_file); + class_def_method_index, &method_offsets_index, is_static, + it.GetMemberIndex(), dex_file); if (relative_offset == 0) { return 0; } @@ -650,28 +697,30 @@ size_t OatWriter::WriteCodeClassDef(OutputStream& out, } while (it.HasNextVirtualMethod()) { relative_offset = WriteCodeMethod(out, file_offset, relative_offset, oat_class_index, - class_def_method_index, false, it.GetMemberIndex(), dex_file); + class_def_method_index, &method_offsets_index, false, + it.GetMemberIndex(), dex_file); if (relative_offset == 0) { return 0; } class_def_method_index++; it.Next(); } + DCHECK(!it.HasNext()); + CHECK_LE(method_offsets_index, class_def_method_index); return relative_offset; } size_t OatWriter::WriteCodeMethod(OutputStream& out, const size_t file_offset, size_t relative_offset, size_t oat_class_index, - size_t class_def_method_index, bool is_static, - uint32_t method_idx, const DexFile& dex_file) { - const CompiledMethod* compiled_method = - compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, method_idx)); - - const OatMethodOffsets& method_offsets = - oat_classes_[oat_class_index]->method_offsets_[class_def_method_index]; - + size_t class_def_method_index, size_t* method_offsets_index, + bool is_static, uint32_t method_idx, const DexFile& dex_file) { + OatClass* oat_class = oat_classes_[oat_class_index]; + const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); if (compiled_method != NULL) { // ie. not an abstract method + const OatMethodOffsets method_offsets = oat_class->method_offsets_[*method_offsets_index]; + (*method_offsets_index)++; + #if !defined(ART_USE_PORTABLE_COMPILER) uint32_t aligned_offset = compiled_method->AlignCode(relative_offset); uint32_t aligned_code_delta = aligned_offset - relative_offset; @@ -854,29 +903,96 @@ bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, return true; } -OatWriter::OatClass::OatClass(size_t offset, mirror::Class::Status status, uint32_t methods_count) { +OatWriter::OatClass::OatClass(size_t offset, + std::vector<CompiledMethod*>* compiled_methods, + uint32_t num_non_null_compiled_methods, + mirror::Class::Status status) { + CHECK(compiled_methods != NULL); + uint32_t num_methods = compiled_methods->size(); + CHECK_LE(num_non_null_compiled_methods, num_methods); + offset_ = offset; + compiled_methods_ = compiled_methods; + oat_method_offsets_offsets_from_oat_class_.resize(num_methods); + + // Since both kOatClassNoneCompiled and kOatClassAllCompiled could + // apply when there are 0 methods, we just arbitrarily say that 0 + // methods means kOatClassNoneCompiled and that we won't use + // kOatClassAllCompiled unless there is at least one compiled + // method. This means in an interpretter only system, we can assert + // that all classes are kOatClassNoneCompiled. + if (num_non_null_compiled_methods == 0) { + type_ = kOatClassNoneCompiled; + } else if (num_non_null_compiled_methods == num_methods) { + type_ = kOatClassAllCompiled; + } else { + type_ = kOatClassSomeCompiled; + } + status_ = status; - method_offsets_.resize(methods_count); + method_offsets_.resize(num_non_null_compiled_methods); + + uint32_t oat_method_offsets_offset_from_oat_class = sizeof(type_) + sizeof(status_); + if (type_ == kOatClassSomeCompiled) { + method_bitmap_ = new BitVector(num_methods, false, Allocator::GetMallocAllocator()); + method_bitmap_size_ = method_bitmap_->GetSizeOf(); + oat_method_offsets_offset_from_oat_class += sizeof(method_bitmap_size_); + oat_method_offsets_offset_from_oat_class += method_bitmap_size_; + } else { + method_bitmap_ = NULL; + method_bitmap_size_ = 0; + } + + for (size_t i = 0; i < num_methods; i++) { + CompiledMethod* compiled_method = (*compiled_methods_)[i]; + if (compiled_method == NULL) { + oat_method_offsets_offsets_from_oat_class_[i] = 0; + } else { + oat_method_offsets_offsets_from_oat_class_[i] = oat_method_offsets_offset_from_oat_class; + oat_method_offsets_offset_from_oat_class += sizeof(OatMethodOffsets); + if (type_ == kOatClassSomeCompiled) { + method_bitmap_->SetBit(i); + } + } + } } +OatWriter::OatClass::~OatClass() { + delete compiled_methods_; +} + +#if defined(ART_USE_PORTABLE_COMPILER) size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatHeader( size_t class_def_method_index_) const { - return offset_ + GetOatMethodOffsetsOffsetFromOatClass(class_def_method_index_); + uint32_t method_offset = GetOatMethodOffsetsOffsetFromOatClass(class_def_method_index_); + if (method_offset == 0) { + return 0; + } + return offset_ + method_offset; } size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatClass( size_t class_def_method_index_) const { - return sizeof(status_) - + (sizeof(method_offsets_[0]) * class_def_method_index_); + return oat_method_offsets_offsets_from_oat_class_[class_def_method_index_]; } +#endif size_t OatWriter::OatClass::SizeOf() const { - return GetOatMethodOffsetsOffsetFromOatClass(method_offsets_.size()); + return sizeof(status_) + + sizeof(type_) + + ((method_bitmap_size_ == 0) ? 0 : sizeof(method_bitmap_size_)) + + method_bitmap_size_ + + (sizeof(method_offsets_[0]) * method_offsets_.size()); } void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const { oat_header.UpdateChecksum(&status_, sizeof(status_)); + oat_header.UpdateChecksum(&type_, sizeof(type_)); + if (method_bitmap_size_ != 0) { + CHECK_EQ(kOatClassSomeCompiled, type_); + oat_header.UpdateChecksum(&method_bitmap_size_, sizeof(method_bitmap_size_)); + oat_header.UpdateChecksum(method_bitmap_->GetRawStorage(), method_bitmap_size_); + } oat_header.UpdateChecksum(&method_offsets_[0], sizeof(method_offsets_[0]) * method_offsets_.size()); } @@ -890,17 +1006,30 @@ bool OatWriter::OatClass::Write(OatWriter* oat_writer, return false; } oat_writer->size_oat_class_status_ += sizeof(status_); - DCHECK_EQ(static_cast<off_t>(file_offset + GetOatMethodOffsetsOffsetFromOatHeader(0)), - out.Seek(0, kSeekCurrent)); + if (!out.WriteFully(&type_, sizeof(type_))) { + PLOG(ERROR) << "Failed to write oat class type to " << out.GetLocation(); + return false; + } + oat_writer->size_oat_class_type_ += sizeof(type_); + if (method_bitmap_size_ != 0) { + CHECK_EQ(kOatClassSomeCompiled, type_); + if (!out.WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) { + PLOG(ERROR) << "Failed to write method bitmap size to " << out.GetLocation(); + return false; + } + oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_); + if (!out.WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) { + PLOG(ERROR) << "Failed to write method bitmap to " << out.GetLocation(); + return false; + } + oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_; + } if (!out.WriteFully(&method_offsets_[0], sizeof(method_offsets_[0]) * method_offsets_.size())) { PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation(); return false; } oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size(); - DCHECK_EQ(static_cast<off_t>(file_offset + - GetOatMethodOffsetsOffsetFromOatHeader(method_offsets_.size())), - out.Seek(0, kSeekCurrent)); return true; } diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index d5f7e21a1a..e3cb0a86ed 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -30,6 +30,7 @@ namespace art { +class BitVector; class OutputStream; // OatHeader variable length with count of D OatDexFiles @@ -90,7 +91,7 @@ class OatWriter { size_t InitOatCodeDexFiles(size_t offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); size_t InitOatCodeDexFile(size_t offset, - size_t& oat_class_index, + size_t* oat_class_index, const DexFile& dex_file) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); size_t InitOatCodeClassDef(size_t offset, @@ -99,21 +100,22 @@ class OatWriter { const DexFile::ClassDef& class_def) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); size_t InitOatCodeMethod(size_t offset, size_t oat_class_index, size_t class_def_index, - size_t class_def_method_index, bool is_native, InvokeType type, - uint32_t method_idx, const DexFile*) + size_t class_def_method_index, size_t* method_offsets_index, + bool is_native, InvokeType type, uint32_t method_idx, const DexFile&) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool WriteTables(OutputStream& out, const size_t file_offset); size_t WriteCode(OutputStream& out, const size_t file_offset); size_t WriteCodeDexFiles(OutputStream& out, const size_t file_offset, size_t relative_offset); size_t WriteCodeDexFile(OutputStream& out, const size_t file_offset, size_t relative_offset, - size_t& oat_class_index, const DexFile& dex_file); + size_t* oat_class_index, const DexFile& dex_file); size_t WriteCodeClassDef(OutputStream& out, const size_t file_offset, size_t relative_offset, size_t oat_class_index, const DexFile& dex_file, const DexFile::ClassDef& class_def); size_t WriteCodeMethod(OutputStream& out, const size_t file_offset, size_t relative_offset, - size_t oat_class_index, size_t class_def_method_index, bool is_static, - uint32_t method_idx, const DexFile& dex_file); + size_t oat_class_index, size_t class_def_method_index, + size_t* method_offsets_index, bool is_static, uint32_t method_idx, + const DexFile& dex_file); void ReportWriteFailure(const char* what, uint32_t method_idx, const DexFile& dex_file, OutputStream& out) const; @@ -142,13 +144,24 @@ class OatWriter { class OatClass { public: - explicit OatClass(size_t offset, mirror::Class::Status status, uint32_t methods_count); + explicit OatClass(size_t offset, + std::vector<CompiledMethod*>* compiled_methods, + uint32_t num_non_null_compiled_methods, + mirror::Class::Status status); + ~OatClass(); +#if defined(ART_USE_PORTABLE_COMPILER) size_t GetOatMethodOffsetsOffsetFromOatHeader(size_t class_def_method_index_) const; size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const; +#endif size_t SizeOf() const; void UpdateChecksum(OatHeader& oat_header) const; bool Write(OatWriter* oat_writer, OutputStream& out, const size_t file_offset) const; + CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const { + DCHECK(compiled_methods_ != NULL); + return (*compiled_methods_)[class_def_method_index]; + } + // Offset of start of OatClass from beginning of OatHeader. It is // used to validate file position when writing. For Portable, it // is also used to calculate the position of the OatMethodOffsets @@ -156,8 +169,37 @@ class OatWriter { // patched to point to code in the Portable .o ELF objects. size_t offset_; + // CompiledMethods for each class_def_method_index, or NULL if no method is available. + std::vector<CompiledMethod*>* compiled_methods_; + + // Offset from OatClass::offset_ to the OatMethodOffsets for the + // class_def_method_index. If 0, it means the corresponding + // CompiledMethod entry in OatClass::compiled_methods_ should be + // NULL and that the OatClass::type_ should be kOatClassBitmap. + std::vector<uint32_t> oat_method_offsets_offsets_from_oat_class_; + // data to write - mirror::Class::Status status_; + + COMPILE_ASSERT(mirror::Class::Status::kStatusMax < (2 ^ 16), class_status_wont_fit_in_16bits); + int16_t status_; + + COMPILE_ASSERT(OatClassType::kOatClassMax < (2 ^ 16), oat_class_type_wont_fit_in_16bits); + uint16_t type_; + + uint32_t method_bitmap_size_; + + // bit vector indexed by ClassDef method index. When + // OatClassType::type_ is kOatClassBitmap, a set bit indicates the + // method has an OatMethodOffsets in methods_offsets_, otherwise + // the entry was ommited to save space. If OatClassType::type_ is + // not is kOatClassBitmap, the bitmap will be NULL. + BitVector* method_bitmap_; + + // OatMethodOffsets for each CompiledMethod present in the + // OatClass. Note that some may be missing if + // OatClass::compiled_methods_ contains NULL values (and + // oat_method_offsets_offsets_from_oat_class_ should contain 0 + // values in this case). std::vector<OatMethodOffsets> method_offsets_; private: @@ -214,7 +256,9 @@ class OatWriter { uint32_t size_oat_dex_file_location_checksum_; uint32_t size_oat_dex_file_offset_; uint32_t size_oat_dex_file_methods_offsets_; + uint32_t size_oat_class_type_; uint32_t size_oat_class_status_; + uint32_t size_oat_class_method_bitmaps_; uint32_t size_oat_class_method_offsets_; // Code mappings for deduplication. Deduplication is already done on a pointer basis by the diff --git a/compiler/utils/allocator.cc b/compiler/utils/allocator.cc deleted file mode 100644 index 4f7753d476..0000000000 --- a/compiler/utils/allocator.cc +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2013 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 "allocator.h" - -#include <inttypes.h> -#include <stdlib.h> - -#include "base/logging.h" - -namespace art { - -class MallocAllocator : public Allocator { - public: - explicit MallocAllocator() {} - ~MallocAllocator() {} - - virtual void* Alloc(size_t size) { - return calloc(sizeof(uint8_t), size); - } - - virtual void Free(void* p) { - free(p); - } - - private: - DISALLOW_COPY_AND_ASSIGN(MallocAllocator); -}; - -MallocAllocator g_malloc_allocator; - -class NoopAllocator : public Allocator { - public: - explicit NoopAllocator() {} - ~NoopAllocator() {} - - virtual void* Alloc(size_t size) { - LOG(FATAL) << "NoopAllocator::Alloc should not be called"; - return NULL; - } - - virtual void Free(void* p) { - // Noop. - } - - private: - DISALLOW_COPY_AND_ASSIGN(NoopAllocator); -}; - -NoopAllocator g_noop_allocator; - -Allocator* Allocator::GetMallocAllocator() { - return &g_malloc_allocator; -} - -Allocator* Allocator::GetNoopAllocator() { - return &g_noop_allocator; -} - - -} // namespace art diff --git a/compiler/utils/bit_vector.cc b/compiler/utils/bit_vector.cc deleted file mode 100644 index 81a639a050..0000000000 --- a/compiler/utils/bit_vector.cc +++ /dev/null @@ -1,155 +0,0 @@ -/* - * 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. - */ - -#include "bit_vector.h" - -namespace art { - -// TODO: profile to make sure this is still a win relative to just using shifted masks. -static uint32_t check_masks[32] = { - 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, - 0x00000020, 0x00000040, 0x00000080, 0x00000100, 0x00000200, - 0x00000400, 0x00000800, 0x00001000, 0x00002000, 0x00004000, - 0x00008000, 0x00010000, 0x00020000, 0x00040000, 0x00080000, - 0x00100000, 0x00200000, 0x00400000, 0x00800000, 0x01000000, - 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, - 0x40000000, 0x80000000 }; - -static inline uint32_t BitsToWords(unsigned int bits) { - return (bits + 31) >> 5; -} - -// TODO: replace excessive argument defaulting when we are at gcc 4.7 -// or later on host with delegating constructor support. Specifically, -// starts_bits and storage_size/storage are mutually exclusive. -BitVector::BitVector(unsigned int start_bits, - bool expandable, - Allocator* allocator, - uint32_t storage_size, - uint32_t* storage) - : allocator_(allocator), - expandable_(expandable), - storage_size_(storage_size), - storage_(storage) { - DCHECK_EQ(sizeof(storage_[0]), 4U); // Assuming 32-bit units. - if (storage_ == NULL) { - storage_size_ = BitsToWords(start_bits); - storage_ = static_cast<uint32_t*>(allocator_->Alloc(storage_size_ * sizeof(uint32_t))); - } -} - -BitVector::~BitVector() { - allocator_->Free(storage_); -} - -/* - * Determine whether or not the specified bit is set. - */ -bool BitVector::IsBitSet(unsigned int num) { - DCHECK_LT(num, storage_size_ * sizeof(uint32_t) * 8); - - unsigned int val = storage_[num >> 5] & check_masks[num & 0x1f]; - return (val != 0); -} - -// Mark all bits bit as "clear". -void BitVector::ClearAllBits() { - memset(storage_, 0, storage_size_ * sizeof(uint32_t)); -} - -// Mark the specified bit as "set". -/* - * TUNING: this could have pathologically bad growth/expand behavior. Make sure we're - * not using it badly or change resize mechanism. - */ -void BitVector::SetBit(unsigned int num) { - if (num >= storage_size_ * sizeof(uint32_t) * 8) { - DCHECK(expandable_) << "Attempted to expand a non-expandable bitmap to position " << num; - - /* Round up to word boundaries for "num+1" bits */ - unsigned int new_size = BitsToWords(num + 1); - DCHECK_GT(new_size, storage_size_); - uint32_t *new_storage = - static_cast<uint32_t*>(allocator_->Alloc(new_size * sizeof(uint32_t))); - memcpy(new_storage, storage_, storage_size_ * sizeof(uint32_t)); - // Zero out the new storage words. - memset(&new_storage[storage_size_], 0, (new_size - storage_size_) * sizeof(uint32_t)); - // TOTO: collect stats on space wasted because of resize. - storage_ = new_storage; - storage_size_ = new_size; - } - - storage_[num >> 5] |= check_masks[num & 0x1f]; -} - -// Mark the specified bit as "unset". -void BitVector::ClearBit(unsigned int num) { - DCHECK_LT(num, storage_size_ * sizeof(uint32_t) * 8); - storage_[num >> 5] &= ~check_masks[num & 0x1f]; -} - -// Intersect with another bit vector. Sizes and expandability must be the same. -void BitVector::Intersect(const BitVector* src) { - DCHECK_EQ(storage_size_, src->GetStorageSize()); - DCHECK_EQ(expandable_, src->IsExpandable()); - for (unsigned int idx = 0; idx < storage_size_; idx++) { - storage_[idx] &= src->GetRawStorageWord(idx); - } -} - -/* - * Union with another bit vector. Sizes and expandability must be the same. - */ -void BitVector::Union(const BitVector* src) { - DCHECK_EQ(storage_size_, src->GetStorageSize()); - DCHECK_EQ(expandable_, src->IsExpandable()); - for (unsigned int idx = 0; idx < storage_size_; idx++) { - storage_[idx] |= src->GetRawStorageWord(idx); - } -} - -// Count the number of bits that are set. -int BitVector::NumSetBits() { - unsigned int count = 0; - - for (unsigned int word = 0; word < storage_size_; word++) { - count += __builtin_popcount(storage_[word]); - } - return count; -} - -BitVector::Iterator* BitVector::GetIterator() { - return new (allocator_) Iterator(this); -} - -/* - * Mark specified number of bits as "set". Cannot set all bits like ClearAll - * since there might be unused bits - setting those to one will confuse the - * iterator. - */ -void BitVector::SetInitialBits(unsigned int num_bits) { - DCHECK_LE(BitsToWords(num_bits), storage_size_); - unsigned int idx; - for (idx = 0; idx < (num_bits >> 5); idx++) { - storage_[idx] = -1; - } - unsigned int rem_num_bits = num_bits & 0x1f; - if (rem_num_bits) { - storage_[idx] = (1 << rem_num_bits) - 1; - } -} - -} // namespace art diff --git a/compiler/utils/bit_vector.h b/compiler/utils/bit_vector.h deleted file mode 100644 index bf0f7c32e1..0000000000 --- a/compiler/utils/bit_vector.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2013 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_BIT_VECTOR_H_ -#define ART_COMPILER_UTILS_BIT_VECTOR_H_ - -#include <stdint.h> -#include <stddef.h> - -#include "allocator.h" -#include "base/logging.h" -#include "utils.h" - -namespace art { - -/* - * Expanding bitmap, used for tracking resources. Bits are numbered starting - * from zero. All operations on a BitVector are unsynchronized. - */ -class BitVector { - public: - class Iterator { - public: - explicit Iterator(BitVector* bit_vector) - : p_bits_(bit_vector), - bit_storage_(bit_vector->GetRawStorage()), - bit_index_(0), - bit_size_(p_bits_->storage_size_ * sizeof(uint32_t) * 8) {} - - // Return the position of the next set bit. -1 means end-of-element reached. - int32_t Next() { - // Did anything obviously change since we started? - DCHECK_EQ(bit_size_, p_bits_->GetStorageSize() * sizeof(uint32_t) * 8); - DCHECK_EQ(bit_storage_, p_bits_->GetRawStorage()); - - if (UNLIKELY(bit_index_ >= bit_size_)) return -1; - - uint32_t word_index = bit_index_ / 32; - uint32_t word = bit_storage_[word_index]; - // Mask out any bits in the first word we've already considered. - word >>= bit_index_ & 0x1f; - if (word == 0) { - bit_index_ &= ~0x1f; - do { - word_index++; - if (UNLIKELY((word_index * 32) >= bit_size_)) { - bit_index_ = bit_size_; - return -1; - } - word = bit_storage_[word_index]; - bit_index_ += 32; - } while (word == 0); - } - bit_index_ += CTZ(word) + 1; - return bit_index_ - 1; - } - - static void* operator new(size_t size, Allocator* allocator) { - return allocator->Alloc(sizeof(BitVector::Iterator)); - }; - static void operator delete(void* p) { - Iterator* it = reinterpret_cast<Iterator*>(p); - it->p_bits_->allocator_->Free(p); - } - - private: - BitVector* const p_bits_; - uint32_t* const bit_storage_; - uint32_t bit_index_; // Current index (size in bits). - const uint32_t bit_size_; // Size of vector in bits. - - friend class BitVector; - }; - - BitVector(uint32_t start_bits, - bool expandable, - Allocator* allocator, - uint32_t storage_size = 0, - uint32_t* storage = NULL); - - virtual ~BitVector(); - - void SetBit(uint32_t num); - void ClearBit(uint32_t num); - void MarkAllBits(bool set); - void DebugBitVector(char* msg, int length); - bool IsBitSet(uint32_t num); - void ClearAllBits(); - void SetInitialBits(uint32_t num_bits); - void Copy(BitVector* src) { - memcpy(storage_, src->GetRawStorage(), sizeof(uint32_t) * storage_size_); - } - void Intersect(const BitVector* src2); - void Union(const BitVector* src); - // Are we equal to another bit vector? Note: expandability attributes must also match. - bool Equal(const BitVector* src) { - return (storage_size_ == src->GetStorageSize()) && - (expandable_ == src->IsExpandable()) && - (memcmp(storage_, src->GetRawStorage(), storage_size_ * sizeof(uint32_t)) == 0); - } - int32_t NumSetBits(); - - Iterator* GetIterator(); - - uint32_t GetStorageSize() const { return storage_size_; } - bool IsExpandable() const { return expandable_; } - uint32_t GetRawStorageWord(size_t idx) const { return storage_[idx]; } - uint32_t* GetRawStorage() { return storage_; } - const uint32_t* GetRawStorage() const { return storage_; } - - private: - Allocator* const allocator_; - const bool expandable_; // expand bitmap if we run out? - uint32_t storage_size_; // current size, in 32-bit words. - uint32_t* storage_; -}; - - -} // namespace art - -#endif // ART_COMPILER_UTILS_BIT_VECTOR_H_ diff --git a/compiler/utils/bit_vector_test.cc b/compiler/utils/bit_vector_test.cc deleted file mode 100644 index 5c18ec53d3..0000000000 --- a/compiler/utils/bit_vector_test.cc +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2013 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 "common_test.h" -#include "bit_vector.h" -#include "UniquePtr.h" - -namespace art { - -TEST(BitVector, Test) { - const size_t kBits = 32; - - BitVector bv(kBits, false, Allocator::GetMallocAllocator()); - EXPECT_EQ(1U, bv.GetStorageSize()); - EXPECT_FALSE(bv.IsExpandable()); - - EXPECT_EQ(0, bv.NumSetBits()); - for (size_t i = 0; i < kBits; i++) { - EXPECT_FALSE(bv.IsBitSet(i)); - } - EXPECT_EQ(0U, bv.GetRawStorageWord(0)); - EXPECT_EQ(0U, *bv.GetRawStorage()); - - BitVector::Iterator empty_iterator(&bv); - EXPECT_EQ(-1, empty_iterator.Next()); - - UniquePtr<BitVector::Iterator> empty_iterator_on_heap(bv.GetIterator()); - EXPECT_EQ(-1, empty_iterator_on_heap->Next()); - - bv.SetBit(0); - bv.SetBit(kBits - 1); - EXPECT_EQ(2, bv.NumSetBits()); - EXPECT_TRUE(bv.IsBitSet(0)); - for (size_t i = 1; i < kBits - 1; i++) { - EXPECT_FALSE(bv.IsBitSet(i)); - } - EXPECT_TRUE(bv.IsBitSet(kBits - 1)); - EXPECT_EQ(0x80000001U, bv.GetRawStorageWord(0)); - EXPECT_EQ(0x80000001U, *bv.GetRawStorage()); - - BitVector::Iterator iterator(&bv); - EXPECT_EQ(0, iterator.Next()); - EXPECT_EQ(static_cast<int>(kBits - 1), iterator.Next()); - EXPECT_EQ(-1, iterator.Next()); -} - -TEST(BitVector, NoopAllocator) { - const uint32_t kWords = 2; - - uint32_t bits[kWords]; - memset(bits, 0, sizeof(bits)); - - BitVector bv(0U, false, Allocator::GetNoopAllocator(), kWords, bits); - EXPECT_EQ(kWords, bv.GetStorageSize()); - EXPECT_EQ(bits, bv.GetRawStorage()); - EXPECT_EQ(0, bv.NumSetBits()); - - bv.SetBit(8); - EXPECT_EQ(1, bv.NumSetBits()); - EXPECT_EQ(0x00000100U, bv.GetRawStorageWord(0)); - EXPECT_EQ(0x00000000U, bv.GetRawStorageWord(1)); - EXPECT_EQ(1, bv.NumSetBits()); - - bv.SetBit(16); - EXPECT_EQ(2, bv.NumSetBits()); - EXPECT_EQ(0x00010100U, bv.GetRawStorageWord(0)); - EXPECT_EQ(0x00000000U, bv.GetRawStorageWord(1)); - EXPECT_EQ(2, bv.NumSetBits()); - - bv.SetBit(32); - EXPECT_EQ(3, bv.NumSetBits()); - EXPECT_EQ(0x00010100U, bv.GetRawStorageWord(0)); - EXPECT_EQ(0x00000001U, bv.GetRawStorageWord(1)); - EXPECT_EQ(3, bv.NumSetBits()); - - bv.SetBit(48); - EXPECT_EQ(4, bv.NumSetBits()); - EXPECT_EQ(0x00010100U, bv.GetRawStorageWord(0)); - EXPECT_EQ(0x00010001U, bv.GetRawStorageWord(1)); - EXPECT_EQ(4, bv.NumSetBits()); -} - -} // namespace art diff --git a/compiler/utils/dedupe_set.h b/compiler/utils/dedupe_set.h index 53c1afa698..638e0ec457 100644 --- a/compiler/utils/dedupe_set.h +++ b/compiler/utils/dedupe_set.h @@ -22,6 +22,7 @@ #include "base/mutex.h" #include "base/stl_util.h" +#include "base/stringprintf.h" namespace art { diff --git a/compiler/utils/dedupe_set_test.cc b/compiler/utils/dedupe_set_test.cc index 2c6787b8a6..8abe6debc1 100644 --- a/compiler/utils/dedupe_set_test.cc +++ b/compiler/utils/dedupe_set_test.cc @@ -14,8 +14,9 @@ * limitations under the License. */ -#include "common_test.h" #include "dedupe_set.h" +#include "gtest/gtest.h" +#include "thread-inl.h" namespace art { |