Optimizing: Tag Arena allocations with their source.
This adds the ability to track where we allocate memory
when the kArenaAllocatorCountAllocations flag is turned on.
Also move some allocations from native heap to the Arena
and remove some unnecessary utilities.
Bug: 23736311
Change-Id: I1aaef3fd405d1de444fe9e618b1ce7ecef07ade3
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 7c60026..3f69270 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -585,7 +585,7 @@
}
void CodeGenerator::BuildNativeGCMap(
- std::vector<uint8_t>* data, const DexCompilationUnit& dex_compilation_unit) const {
+ ArenaVector<uint8_t>* data, const DexCompilationUnit& dex_compilation_unit) const {
const std::vector<uint8_t>& gc_map_raw =
dex_compilation_unit.GetVerifiedMethod()->GetDexGcMap();
verifier::DexPcToReferenceMap dex_gc_map(&(gc_map_raw)[0]);
@@ -613,7 +613,7 @@
}
}
-void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data) const {
+void CodeGenerator::BuildMappingTable(ArenaVector<uint8_t>* data) const {
uint32_t pc2dex_data_size = 0u;
uint32_t pc2dex_entries = stack_map_stream_.GetNumberOfStackMaps();
uint32_t pc2dex_offset = 0u;
@@ -712,18 +712,16 @@
}
}
-void CodeGenerator::BuildVMapTable(std::vector<uint8_t>* data) const {
- Leb128EncodingVector vmap_encoder;
+void CodeGenerator::BuildVMapTable(ArenaVector<uint8_t>* data) const {
+ Leb128Encoder<ArenaAllocatorAdapter<uint8_t>> vmap_encoder(data);
// We currently don't use callee-saved registers.
size_t size = 0 + 1 /* marker */ + 0;
vmap_encoder.Reserve(size + 1u); // All values are likely to be one byte in ULEB128 (<128).
vmap_encoder.PushBackUnsigned(size);
vmap_encoder.PushBackUnsigned(VmapTable::kAdjustedFpMarker);
-
- *data = vmap_encoder.GetData();
}
-void CodeGenerator::BuildStackMaps(std::vector<uint8_t>* data) {
+void CodeGenerator::BuildStackMaps(ArenaVector<uint8_t>* data) {
uint32_t size = stack_map_stream_.PrepareForFillIn();
data->resize(size);
MemoryRegion region(data->data(), size);
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index cdd4675..754b5ec 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -19,6 +19,8 @@
#include "arch/instruction_set.h"
#include "arch/instruction_set_features.h"
+#include "base/arena_containers.h"
+#include "base/arena_object.h"
#include "base/bit_field.h"
#include "driver/compiler_options.h"
#include "globals.h"
@@ -236,11 +238,11 @@
}
void BuildSourceMap(DefaultSrcMap* src_map) const;
- void BuildMappingTable(std::vector<uint8_t>* vector) const;
- void BuildVMapTable(std::vector<uint8_t>* vector) const;
+ void BuildMappingTable(ArenaVector<uint8_t>* vector) const;
+ void BuildVMapTable(ArenaVector<uint8_t>* vector) const;
void BuildNativeGCMap(
- std::vector<uint8_t>* vector, const DexCompilationUnit& dex_compilation_unit) const;
- void BuildStackMaps(std::vector<uint8_t>* vector);
+ ArenaVector<uint8_t>* vector, const DexCompilationUnit& dex_compilation_unit) const;
+ void BuildStackMaps(ArenaVector<uint8_t>* vector);
bool IsBaseline() const {
return is_baseline_;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 2ed2d9a..ee82fda 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -17,6 +17,7 @@
#ifndef ART_COMPILER_OPTIMIZING_NODES_H_
#define ART_COMPILER_OPTIMIZING_NODES_H_
+#include <array>
#include <type_traits>
#include "base/arena_containers.h"
@@ -81,7 +82,7 @@
kCondGE,
};
-class HInstructionList {
+class HInstructionList : public ValueObject {
public:
HInstructionList() : first_instruction_(nullptr), last_instruction_(nullptr) {}
@@ -127,7 +128,7 @@
};
// Control-flow graph of a method. Contains a list of basic blocks.
-class HGraph : public ArenaObject<kArenaAllocMisc> {
+class HGraph : public ArenaObject<kArenaAllocGraph> {
public:
HGraph(ArenaAllocator* arena,
const DexFile& dex_file,
@@ -464,7 +465,7 @@
DISALLOW_COPY_AND_ASSIGN(HGraph);
};
-class HLoopInformation : public ArenaObject<kArenaAllocMisc> {
+class HLoopInformation : public ArenaObject<kArenaAllocLoopInfo> {
public:
HLoopInformation(HBasicBlock* header, HGraph* graph)
: header_(header),
@@ -562,7 +563,7 @@
// Stores try/catch information for basic blocks.
// Note that HGraph is constructed so that catch blocks cannot simultaneously
// be try blocks.
-class TryCatchInformation : public ArenaObject<kArenaAllocMisc> {
+class TryCatchInformation : public ArenaObject<kArenaAllocTryCatchInfo> {
public:
// Try block information constructor.
explicit TryCatchInformation(const HTryBoundary& try_entry)
@@ -619,7 +620,7 @@
// as a double linked list. Each block knows its predecessors and
// successors.
-class HBasicBlock : public ArenaObject<kArenaAllocMisc> {
+class HBasicBlock : public ArenaObject<kArenaAllocBasicBlock> {
public:
explicit HBasicBlock(HGraph* graph, uint32_t dex_pc = kNoDexPc)
: graph_(graph),
@@ -1107,7 +1108,7 @@
template <typename T> class HUseList;
template <typename T>
-class HUseListNode : public ArenaObject<kArenaAllocMisc> {
+class HUseListNode : public ArenaObject<kArenaAllocUseListNode> {
public:
HUseListNode* GetPrevious() const { return prev_; }
HUseListNode* GetNext() const { return next_; }
@@ -1492,7 +1493,7 @@
};
// A HEnvironment object contains the values of virtual registers at a given location.
-class HEnvironment : public ArenaObject<kArenaAllocMisc> {
+class HEnvironment : public ArenaObject<kArenaAllocEnvironment> {
public:
HEnvironment(ArenaAllocator* arena,
size_t number_of_vregs,
@@ -1682,7 +1683,7 @@
std::ostream& operator<<(std::ostream& os, const ReferenceTypeInfo& rhs);
-class HInstruction : public ArenaObject<kArenaAllocMisc> {
+class HInstruction : public ArenaObject<kArenaAllocInstruction> {
public:
explicit HInstruction(SideEffects side_effects)
: previous_(nullptr),
@@ -2038,54 +2039,7 @@
DISALLOW_COPY_AND_ASSIGN(HBackwardInstructionIterator);
};
-// An embedded container with N elements of type T. Used (with partial
-// specialization for N=0) because embedded arrays cannot have size 0.
-template<typename T, intptr_t N>
-class EmbeddedArray {
- public:
- EmbeddedArray() : elements_() {}
-
- intptr_t GetLength() const { return N; }
-
- const T& operator[](intptr_t i) const {
- DCHECK_LT(i, GetLength());
- return elements_[i];
- }
-
- T& operator[](intptr_t i) {
- DCHECK_LT(i, GetLength());
- return elements_[i];
- }
-
- const T& At(intptr_t i) const {
- return (*this)[i];
- }
-
- void SetAt(intptr_t i, const T& val) {
- (*this)[i] = val;
- }
-
- private:
- T elements_[N];
-};
-
-template<typename T>
-class EmbeddedArray<T, 0> {
- public:
- intptr_t length() const { return 0; }
- const T& operator[](intptr_t i) const {
- UNUSED(i);
- LOG(FATAL) << "Unreachable";
- UNREACHABLE();
- }
- T& operator[](intptr_t i) {
- UNUSED(i);
- LOG(FATAL) << "Unreachable";
- UNREACHABLE();
- }
-};
-
-template<intptr_t N>
+template<size_t N>
class HTemplateInstruction: public HInstruction {
public:
HTemplateInstruction<N>(SideEffects side_effects)
@@ -2095,18 +2049,47 @@
size_t InputCount() const OVERRIDE { return N; }
protected:
- const HUserRecord<HInstruction*> InputRecordAt(size_t i) const OVERRIDE { return inputs_[i]; }
+ const HUserRecord<HInstruction*> InputRecordAt(size_t i) const OVERRIDE {
+ DCHECK_LT(i, N);
+ return inputs_[i];
+ }
void SetRawInputRecordAt(size_t i, const HUserRecord<HInstruction*>& input) OVERRIDE {
+ DCHECK_LT(i, N);
inputs_[i] = input;
}
private:
- EmbeddedArray<HUserRecord<HInstruction*>, N> inputs_;
+ std::array<HUserRecord<HInstruction*>, N> inputs_;
friend class SsaBuilder;
};
+// HTemplateInstruction specialization for N=0.
+template<>
+class HTemplateInstruction<0>: public HInstruction {
+ public:
+ explicit HTemplateInstruction(SideEffects side_effects) : HInstruction(side_effects) {}
+ virtual ~HTemplateInstruction() {}
+
+ size_t InputCount() const OVERRIDE { return 0; }
+
+ protected:
+ const HUserRecord<HInstruction*> InputRecordAt(size_t i ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << "Unreachable";
+ UNREACHABLE();
+ }
+
+ void SetRawInputRecordAt(size_t i ATTRIBUTE_UNUSED,
+ const HUserRecord<HInstruction*>& input ATTRIBUTE_UNUSED) OVERRIDE {
+ LOG(FATAL) << "Unreachable";
+ UNREACHABLE();
+ }
+
+ private:
+ friend class SsaBuilder;
+};
+
template<intptr_t N>
class HExpression : public HTemplateInstruction<N> {
public:
@@ -4833,7 +4816,7 @@
DISALLOW_COPY_AND_ASSIGN(HFakeString);
};
-class MoveOperands : public ArenaObject<kArenaAllocMisc> {
+class MoveOperands : public ArenaObject<kArenaAllocMoveOperands> {
public:
MoveOperands(Location source,
Location destination,
diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h
index f793a65..2f59d4c 100644
--- a/compiler/optimizing/optimization.h
+++ b/compiler/optimizing/optimization.h
@@ -26,7 +26,7 @@
/**
* Abstraction to implement an optimization pass.
*/
-class HOptimization : public ArenaObject<kArenaAllocMisc> {
+class HOptimization : public ArenaObject<kArenaAllocOptimization> {
public:
HOptimization(HGraph* graph,
const char* pass_name,
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 6f251e8..898b656 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -25,6 +25,7 @@
#include "art_method-inl.h"
#include "base/arena_allocator.h"
+#include "base/arena_containers.h"
#include "base/dumpable.h"
#include "base/timing_logger.h"
#include "boolean_simplifier.h"
@@ -68,7 +69,9 @@
*/
class CodeVectorAllocator FINAL : public CodeAllocator {
public:
- CodeVectorAllocator() : size_(0) {}
+ explicit CodeVectorAllocator(ArenaAllocator* arena)
+ : memory_(arena->Adapter(kArenaAllocCodeBuffer)),
+ size_(0) {}
virtual uint8_t* Allocate(size_t size) {
size_ = size;
@@ -77,10 +80,10 @@
}
size_t GetSize() const { return size_; }
- const std::vector<uint8_t>& GetMemory() const { return memory_; }
+ const ArenaVector<uint8_t>& GetMemory() const { return memory_; }
private:
- std::vector<uint8_t> memory_;
+ ArenaVector<uint8_t> memory_;
size_t size_;
DISALLOW_COPY_AND_ASSIGN(CodeVectorAllocator);
@@ -498,7 +501,7 @@
// The stack map we generate must be 4-byte aligned on ARM. Since existing
// maps are generated alongside these stack maps, we must also align them.
-static ArrayRef<const uint8_t> AlignVectorSize(std::vector<uint8_t>& vector) {
+static ArrayRef<const uint8_t> AlignVectorSize(ArenaVector<uint8_t>& vector) {
size_t size = vector.size();
size_t aligned_size = RoundUp(size, 4);
for (; size < aligned_size; ++size) {
@@ -553,7 +556,8 @@
AllocateRegisters(graph, codegen, pass_observer);
- CodeVectorAllocator allocator;
+ ArenaAllocator* arena = graph->GetArena();
+ CodeVectorAllocator allocator(arena);
codegen->CompileOptimized(&allocator);
ArenaVector<LinkerPatch> linker_patches = EmitAndSortLinkerPatches(codegen);
@@ -563,7 +567,7 @@
codegen->BuildSourceMap(&src_mapping_table);
}
- std::vector<uint8_t> stack_map;
+ ArenaVector<uint8_t> stack_map(arena->Adapter(kArenaAllocStackMaps));
codegen->BuildStackMaps(&stack_map);
MaybeRecordStat(MethodCompilationStat::kCompiledOptimized);
@@ -595,20 +599,21 @@
CompilerDriver* compiler_driver,
const DexCompilationUnit& dex_compilation_unit,
PassObserver* pass_observer) const {
- CodeVectorAllocator allocator;
+ ArenaAllocator* arena = codegen->GetGraph()->GetArena();
+ CodeVectorAllocator allocator(arena);
codegen->CompileBaseline(&allocator);
ArenaVector<LinkerPatch> linker_patches = EmitAndSortLinkerPatches(codegen);
- std::vector<uint8_t> mapping_table;
+ ArenaVector<uint8_t> mapping_table(arena->Adapter(kArenaAllocBaselineMaps));
codegen->BuildMappingTable(&mapping_table);
DefaultSrcMap src_mapping_table;
if (compiler_driver->GetCompilerOptions().GetGenerateDebugInfo()) {
codegen->BuildSourceMap(&src_mapping_table);
}
- std::vector<uint8_t> vmap_table;
+ ArenaVector<uint8_t> vmap_table(arena->Adapter(kArenaAllocBaselineMaps));
codegen->BuildVMapTable(&vmap_table);
- std::vector<uint8_t> gc_map;
+ ArenaVector<uint8_t> gc_map(arena->Adapter(kArenaAllocBaselineMaps));
codegen->BuildNativeGCMap(&gc_map, dex_compilation_unit);
MaybeRecordStat(MethodCompilationStat::kCompiledBaseline);
@@ -752,6 +757,7 @@
// or the debuggable flag). If it is set, we can run baseline. Otherwise, we fall back
// to Quick.
bool can_use_baseline = !run_optimizations_ && builder.CanUseBaselineForStringInit();
+ CompiledMethod* compiled_method = nullptr;
if (run_optimizations_ && can_allocate_registers) {
VLOG(compiler) << "Optimizing " << method_name;
@@ -766,11 +772,11 @@
}
}
- return CompileOptimized(graph,
- codegen.get(),
- compiler_driver,
- dex_compilation_unit,
- &pass_observer);
+ compiled_method = CompileOptimized(graph,
+ codegen.get(),
+ compiler_driver,
+ dex_compilation_unit,
+ &pass_observer);
} else if (shouldOptimize && can_allocate_registers) {
LOG(FATAL) << "Could not allocate registers in optimizing compiler";
UNREACHABLE();
@@ -783,13 +789,20 @@
MaybeRecordStat(MethodCompilationStat::kNotOptimizedRegisterAllocator);
}
- return CompileBaseline(codegen.get(),
- compiler_driver,
- dex_compilation_unit,
- &pass_observer);
- } else {
- return nullptr;
+ compiled_method = CompileBaseline(codegen.get(),
+ compiler_driver,
+ dex_compilation_unit,
+ &pass_observer);
}
+
+ if (kArenaAllocatorCountAllocations) {
+ if (arena.BytesAllocated() > 4 * MB) {
+ MemStats mem_stats(arena.GetMemStats());
+ LOG(INFO) << PrettyMethod(method_idx, dex_file) << " " << Dumpable<MemStats>(mem_stats);
+ }
+ }
+
+ return compiled_method;
}
CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,