summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/dex/quick/codegen_util.cc4
-rw-r--r--compiler/dex/verification_results.cc9
-rw-r--r--compiler/dex/verification_results.h1
-rw-r--r--compiler/driver/compiler_driver.cc42
-rw-r--r--compiler/driver/compiler_driver.h4
-rw-r--r--compiler/driver/dex_compilation_unit.h6
-rw-r--r--compiler/image_writer.cc7
-rw-r--r--compiler/optimizing/builder.cc5
-rw-r--r--compiler/optimizing/code_generator.h3
-rw-r--r--compiler/optimizing/code_generator_arm.cc16
-rw-r--r--compiler/optimizing/code_generator_x86.cc32
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc32
-rw-r--r--compiler/optimizing/nodes.cc57
-rw-r--r--compiler/optimizing/nodes.h1
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_;