diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/dex/quick/codegen_util.cc | 4 | ||||
| -rw-r--r-- | compiler/dex/verification_results.cc | 9 | ||||
| -rw-r--r-- | compiler/dex/verification_results.h | 1 | ||||
| -rw-r--r-- | compiler/driver/compiler_driver.cc | 42 | ||||
| -rw-r--r-- | compiler/driver/compiler_driver.h | 4 | ||||
| -rw-r--r-- | compiler/driver/dex_compilation_unit.h | 6 | ||||
| -rw-r--r-- | compiler/image_writer.cc | 7 | ||||
| -rw-r--r-- | compiler/optimizing/builder.cc | 5 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator.h | 3 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 16 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 32 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 32 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.cc | 57 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 1 |
14 files changed, 189 insertions, 30 deletions
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 58bcee2124..00217549b0 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -775,6 +775,10 @@ void Mir2Lir::CreateNativeGcMap() { ": " << PrettyMethod(cu_->method_idx, *cu_->dex_file); native_gc_map_builder.AddEntry(native_offset, references); } + + // Maybe not necessary, but this could help prevent errors where we access the verified method + // after it has been deleted. + mir_graph_->GetCurrentDexCompilationUnit()->ClearVerifiedMethod(); } /* Determine the offset of each literal field */ diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc index 4929b5b2b0..932a532e56 100644 --- a/compiler/dex/verification_results.cc +++ b/compiler/dex/verification_results.cc @@ -84,6 +84,15 @@ const VerifiedMethod* VerificationResults::GetVerifiedMethod(MethodReference ref return (it != verified_methods_.end()) ? it->second : nullptr; } +void VerificationResults::RemoveVerifiedMethod(MethodReference ref) { + WriterMutexLock mu(Thread::Current(), verified_methods_lock_); + auto it = verified_methods_.find(ref); + if (it != verified_methods_.end()) { + delete it->second; + verified_methods_.erase(it); + } +} + void VerificationResults::AddRejectedClass(ClassReference ref) { { WriterMutexLock mu(Thread::Current(), rejected_classes_lock_); diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h index 0e7923fbc3..7fc2a2363d 100644 --- a/compiler/dex/verification_results.h +++ b/compiler/dex/verification_results.h @@ -48,6 +48,7 @@ class VerificationResults { const VerifiedMethod* GetVerifiedMethod(MethodReference ref) LOCKS_EXCLUDED(verified_methods_lock_); + void RemoveVerifiedMethod(MethodReference ref) LOCKS_EXCLUDED(verified_methods_lock_); void AddRejectedClass(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_); bool IsClassRejected(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_); diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index ab9f41a4b3..e4274712d4 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -23,6 +23,10 @@ #include <vector> #include <unistd.h> +#ifndef __APPLE__ +#include <malloc.h> // For mallinfo +#endif + #include "base/stl_util.h" #include "base/timing_logger.h" #include "class_linker.h" @@ -497,6 +501,7 @@ void CompilerDriver::CompileAll(jobject class_loader, TimingLogger* timings) { DCHECK(!Runtime::Current()->IsStarted()); std::unique_ptr<ThreadPool> thread_pool(new ThreadPool("Compiler driver thread pool", thread_count_ - 1)); + VLOG(compiler) << "Before precompile " << GetMemoryUsageString(); PreCompile(class_loader, dex_files, thread_pool.get(), timings); Compile(class_loader, dex_files, thread_pool.get(), timings); if (dump_stats_) { @@ -593,20 +598,25 @@ void CompilerDriver::Resolve(jobject class_loader, const std::vector<const DexFi void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files, ThreadPool* thread_pool, TimingLogger* timings) { LoadImageClasses(timings); + VLOG(compiler) << "LoadImageClasses: " << GetMemoryUsageString(); Resolve(class_loader, dex_files, thread_pool, timings); + VLOG(compiler) << "Resolve: " << GetMemoryUsageString(); if (!compiler_options_->IsVerificationEnabled()) { - LOG(INFO) << "Verify none mode specified, skipping verification."; + VLOG(compiler) << "Verify none mode specified, skipping verification."; SetVerified(class_loader, dex_files, thread_pool, timings); return; } Verify(class_loader, dex_files, thread_pool, timings); + VLOG(compiler) << "Verify: " << GetMemoryUsageString(); InitializeClasses(class_loader, dex_files, thread_pool, timings); + VLOG(compiler) << "InitializeClasses: " << GetMemoryUsageString(); UpdateImageClasses(timings); + VLOG(compiler) << "UpdateImageClasses: " << GetMemoryUsageString(); } bool CompilerDriver::IsImageClass(const char* descriptor) const { @@ -2002,6 +2012,7 @@ void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFi CHECK(dex_file != nullptr); CompileDexFile(class_loader, *dex_file, dex_files, thread_pool, timings); } + VLOG(compiler) << "Compile: " << GetMemoryUsageString(); } void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, size_t class_def_index) { @@ -2128,6 +2139,7 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t bool compilation_enabled) { CompiledMethod* compiled_method = nullptr; uint64_t start_ns = kTimeCompileMethod ? NanoTime() : 0; + MethodReference method_ref(&dex_file, method_idx); if ((access_flags & kAccNative) != 0) { // Are we interpreting only and have support for generic JNI down calls? @@ -2141,7 +2153,6 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t } else if ((access_flags & kAccAbstract) != 0) { // Abstract methods don't have code. } else { - MethodReference method_ref(&dex_file, method_idx); bool compile = compilation_enabled && verification_results_->IsCandidateForCompilation(method_ref, access_flags); if (compile) { @@ -2178,16 +2189,18 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t // When compiling with PIC, there should be zero non-relative linker patches CHECK(!compile_pic || non_relative_linker_patch_count == 0u); - MethodReference ref(&dex_file, method_idx); - DCHECK(GetCompiledMethod(ref) == nullptr) << PrettyMethod(method_idx, dex_file); + DCHECK(GetCompiledMethod(method_ref) == nullptr) << PrettyMethod(method_idx, dex_file); { MutexLock mu(self, compiled_methods_lock_); - compiled_methods_.Put(ref, compiled_method); + compiled_methods_.Put(method_ref, compiled_method); non_relative_linker_patch_count_ += non_relative_linker_patch_count; } - DCHECK(GetCompiledMethod(ref) != nullptr) << PrettyMethod(method_idx, dex_file); + DCHECK(GetCompiledMethod(method_ref) != nullptr) << PrettyMethod(method_idx, dex_file); } + // Done compiling, delete the verified method to reduce native memory usage. + verification_results_->RemoveVerifiedMethod(method_ref); + if (self->IsExceptionPending()) { ScopedObjectAccess soa(self); LOG(FATAL) << "Unexpected exception compiling: " << PrettyMethod(method_idx, dex_file) << "\n" @@ -2337,4 +2350,21 @@ bool CompilerDriver::SkipCompilation(const std::string& method_name) { } return !compile; } + +std::string CompilerDriver::GetMemoryUsageString() const { + std::ostringstream oss; + const ArenaPool* arena_pool = GetArenaPool(); + gc::Heap* heap = Runtime::Current()->GetHeap(); + oss << "arena alloc=" << PrettySize(arena_pool->GetBytesAllocated()); + oss << " java alloc=" << PrettySize(heap->GetBytesAllocated()); +#ifdef HAVE_MALLOC_H + struct mallinfo info = mallinfo(); + const size_t allocated_space = static_cast<size_t>(info.uordblks); + const size_t free_space = static_cast<size_t>(info.fordblks); + oss << " native alloc=" << PrettySize(allocated_space) << " free=" + << PrettySize(free_space); +#endif + return oss.str(); +} + } // namespace art diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index d837dbc9cd..615e0d0db4 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -39,6 +39,7 @@ #include "thread_pool.h" #include "utils/arena_allocator.h" #include "utils/dedupe_set.h" +#include "dex/verified_method.h" namespace art { @@ -398,6 +399,9 @@ class CompilerDriver { // Should the compiler run on this method given profile information? bool SkipCompilation(const std::string& method_name); + // Get memory usage during compilation. + std::string GetMemoryUsageString() const; + private: // These flags are internal to CompilerDriver for collecting INVOKE resolution statistics. // The only external contract is that unresolved method has flags 0 and resolved non-0. diff --git a/compiler/driver/dex_compilation_unit.h b/compiler/driver/dex_compilation_unit.h index 84f57991c3..03ae489da1 100644 --- a/compiler/driver/dex_compilation_unit.h +++ b/compiler/driver/dex_compilation_unit.h @@ -102,6 +102,10 @@ class DexCompilationUnit { return verified_method_; } + void ClearVerifiedMethod() { + verified_method_ = nullptr; + } + const std::string& GetSymbol(); private: @@ -117,7 +121,7 @@ class DexCompilationUnit { const uint16_t class_def_idx_; const uint32_t dex_method_idx_; const uint32_t access_flags_; - const VerifiedMethod* const verified_method_; + const VerifiedMethod* verified_method_; std::string symbol_; }; diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 3b1d914f6e..ab5c6c77de 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -77,6 +77,7 @@ bool ImageWriter::PrepareImageAddressSpace() { Thread::Current()->TransitionFromSuspendedToRunnable(); PruneNonImageClasses(); // Remove junk ComputeLazyFieldsForImageClasses(); // Add useful information + ProcessStrings(); Thread::Current()->TransitionFromRunnableToSuspended(kNative); } gc::Heap* heap = Runtime::Current()->GetHeap(); @@ -561,9 +562,9 @@ void ImageWriter::ProcessStrings() { bool is_prefix = false; if (it != existing_strings.end()) { CHECK_LE(length, it->second); - is_prefix = std::equal(combined_chars.begin() + it->first, - combined_chars.begin() + it->first + it->second, - combined_chars.begin() + new_string.first); + is_prefix = std::equal(combined_chars.begin() + new_string.first, + combined_chars.begin() + new_string.first + new_string.second, + combined_chars.begin() + it->first); } if (is_prefix) { // Shares a prefix, set the offset to where the new offset will be. diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 23c3b390c0..eb6181c711 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -1108,6 +1108,11 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::FLOAT_TO_INT: { + Conversion_12x(instruction, Primitive::kPrimFloat, Primitive::kPrimInt); + break; + } + case Instruction::INT_TO_BYTE: { Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimByte); break; diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index 4c0d3ea960..7c8f6a2d29 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -35,6 +35,9 @@ static int64_t constexpr k2Pow32EncodingForDouble = INT64_C(0x41F0000000000000); // Binary encoding of 2^31 for type double. static int64_t constexpr k2Pow31EncodingForDouble = INT64_C(0x41E0000000000000); +// Maximum value for a primitive integer. +static int32_t constexpr kPrimIntMax = 0x7fffffff; + class Assembler; class CodeGenerator; class DexCompilationUnit; diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 5b2be2e9a1..448a5a0707 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -1406,6 +1406,12 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { break; case Primitive::kPrimFloat: + // Processing a Dex `float-to-int' instruction. + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresFpuRegister()); + break; + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; @@ -1580,7 +1586,15 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio } break; - case Primitive::kPrimFloat: + case Primitive::kPrimFloat: { + // Processing a Dex `float-to-int' instruction. + SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>(); + __ vmovs(temp, in.AsFpuRegister<SRegister>()); + __ vcvtis(temp, temp); + __ vmovrs(out.AsRegister<Register>(), temp); + break; + } + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index fd794f95d1..6f83d9faf4 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1373,6 +1373,12 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { break; case Primitive::kPrimFloat: + // Processing a Dex `float-to-int' instruction. + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresFpuRegister()); + break; + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; @@ -1559,7 +1565,31 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio } break; - case Primitive::kPrimFloat: + case Primitive::kPrimFloat: { + // Processing a Dex `float-to-int' instruction. + XmmRegister input = in.AsFpuRegister<XmmRegister>(); + Register output = out.AsRegister<Register>(); + XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); + Label done, nan; + + __ movl(output, Immediate(kPrimIntMax)); + // temp = int-to-float(output) + __ cvtsi2ss(temp, output); + // if input >= temp goto done + __ comiss(input, temp); + __ j(kAboveEqual, &done); + // if input == NaN goto nan + __ j(kUnordered, &nan); + // output = float-to-int-truncate(input) + __ cvttss2si(output, input); + __ jmp(&done); + __ Bind(&nan); + // output = 0 + __ xorl(output, output); + __ Bind(&done); + break; + } + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 4d70efcf38..47fd304969 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1363,6 +1363,12 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) { break; case Primitive::kPrimFloat: + // Processing a Dex `float-to-int' instruction. + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresFpuRegister()); + break; + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; @@ -1550,7 +1556,31 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver } break; - case Primitive::kPrimFloat: + case Primitive::kPrimFloat: { + // Processing a Dex `float-to-int' instruction. + XmmRegister input = in.AsFpuRegister<XmmRegister>(); + CpuRegister output = out.AsRegister<CpuRegister>(); + XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); + Label done, nan; + + __ movl(output, Immediate(kPrimIntMax)); + // temp = int-to-float(output) + __ cvtsi2ss(temp, output); + // if input >= temp goto done + __ comiss(input, temp); + __ j(kAboveEqual, &done); + // if input == NaN goto nan + __ j(kUnordered, &nan); + // output = float-to-int-truncate(input) + __ cvttss2si(output, input); + __ jmp(&done); + __ Bind(&nan); + // output = 0 + __ xorl(output, output); + __ Bind(&done); + break; + } + case Primitive::kPrimDouble: LOG(FATAL) << "Type conversion from " << input_type << " to " << result_type << " not yet implemented"; diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 7584f1bac1..ba4dccf598 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -30,6 +30,36 @@ void HGraph::FindBackEdges(ArenaBitVector* visited) { VisitBlockForBackEdges(entry_block_, visited, &visiting); } +static void RemoveAsUser(HInstruction* instruction) { + for (size_t i = 0; i < instruction->InputCount(); i++) { + instruction->InputAt(i)->RemoveUser(instruction, i); + } + + HEnvironment* environment = instruction->GetEnvironment(); + if (environment != nullptr) { + for (size_t i = 0, e = environment->Size(); i < e; ++i) { + HInstruction* vreg = environment->GetInstructionAt(i); + if (vreg != nullptr) { + vreg->RemoveEnvironmentUser(environment, i); + } + } + } +} + +void HGraph::RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const { + for (size_t i = 0; i < blocks_.Size(); ++i) { + if (!visited.IsBitSet(i)) { + HBasicBlock* block = blocks_.Get(i); + for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { + RemoveAsUser(it.Current()); + } + for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { + RemoveAsUser(it.Current()); + } + } + } +} + void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) const { for (size_t i = 0; i < blocks_.Size(); ++i) { if (!visited.IsBitSet(i)) { @@ -72,16 +102,21 @@ void HGraph::BuildDominatorTree() { // (1) Find the back edges in the graph doing a DFS traversal. FindBackEdges(&visited); - // (2) Remove blocks not visited during the initial DFS. - // Step (3) requires dead blocks to be removed from the + // (2) Remove instructions and phis from blocks not visited during + // the initial DFS as users from other instructions, so that + // users can be safely removed before uses later. + RemoveInstructionsAsUsersFromDeadBlocks(visited); + + // (3) Remove blocks not visited during the initial DFS. + // Step (4) requires dead blocks to be removed from the // predecessors list of live blocks. RemoveDeadBlocks(visited); - // (3) Simplify the CFG now, so that we don't need to recompute + // (4) Simplify the CFG now, so that we don't need to recompute // dominators and the reverse post order. SimplifyCFG(); - // (4) Compute the immediate dominator of each block. We visit + // (5) Compute the immediate dominator of each block. We visit // the successors of a block only when all its forward branches // have been processed. GrowableArray<size_t> visits(arena_, blocks_.Size()); @@ -391,19 +426,7 @@ static void Remove(HInstructionList* instruction_list, instruction->SetBlock(nullptr); instruction_list->RemoveInstruction(instruction); - for (size_t i = 0; i < instruction->InputCount(); i++) { - instruction->InputAt(i)->RemoveUser(instruction, i); - } - - HEnvironment* environment = instruction->GetEnvironment(); - if (environment != nullptr) { - for (size_t i = 0, e = environment->Size(); i < e; ++i) { - HInstruction* vreg = environment->GetInstructionAt(i); - if (vreg != nullptr) { - vreg->RemoveEnvironmentUser(environment, i); - } - } - } + RemoveAsUser(instruction); } void HBasicBlock::RemoveInstruction(HInstruction* instruction) { diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 4706b3beab..3908a61910 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -173,6 +173,7 @@ class HGraph : public ArenaObject<kArenaAllocMisc> { void VisitBlockForBackEdges(HBasicBlock* block, ArenaBitVector* visited, ArenaBitVector* visiting); + void RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const; void RemoveDeadBlocks(const ArenaBitVector& visited) const; ArenaAllocator* const arena_; |