am 2cea26c1: am c6dfdace: Add buffering to ELF file generation
* commit '2cea26c18f01a2b0bb7bcbf8ded7ec7f9930eb85':
Add buffering to ELF file generation
diff --git a/compiler/dex/arena_allocator.cc b/compiler/dex/arena_allocator.cc
index 3a3e385..36393e7 100644
--- a/compiler/dex/arena_allocator.cc
+++ b/compiler/dex/arena_allocator.cc
@@ -18,9 +18,14 @@
#include "dex_file-inl.h"
#include "arena_allocator.h"
#include "base/logging.h"
+#include "base/mutex.h"
namespace art {
+// Memmap is a bit slower than malloc according to my measurements.
+static constexpr bool kUseMemMap = false;
+static constexpr bool kUseMemSet = true && kUseMemMap;
+
static const char* alloc_names[ArenaAllocator::kNumAllocKinds] = {
"Misc ",
"BasicBlock ",
@@ -37,108 +42,144 @@
"Preds ",
};
-ArenaAllocator::ArenaAllocator(size_t default_size)
- : default_size_(default_size),
- block_size_(default_size - sizeof(ArenaMemBlock)),
- arena_head_(NULL),
- current_block_(NULL),
- num_arena_blocks_(0),
- malloc_bytes_(0),
- lost_bytes_(0),
- num_allocations_(0) {
- memset(&alloc_stats_[0], 0, sizeof(alloc_stats_));
- // Start with an empty arena.
- arena_head_ = current_block_ = EmptyArenaBlock();
- num_arena_blocks_++;
-}
-
-ArenaAllocator::~ArenaAllocator() {
- // Reclaim all the arena blocks allocated so far.
- ArenaMemBlock* head = arena_head_;
- while (head != NULL) {
- ArenaMemBlock* p = head;
- head = head->next;
- free(p);
+Arena::Arena(size_t size)
+ : bytes_allocated_(0),
+ map_(nullptr),
+ next_(nullptr) {
+ if (kUseMemMap) {
+ map_ = MemMap::MapAnonymous("dalvik-arena", NULL, size, PROT_READ | PROT_WRITE);
+ memory_ = map_->Begin();
+ size_ = map_->Size();
+ } else {
+ memory_ = reinterpret_cast<uint8_t*>(calloc(1, size));
+ size_ = size;
}
- arena_head_ = NULL;
- num_arena_blocks_ = 0;
}
-// Return an arena with no storage for use as a sentinal.
-ArenaAllocator::ArenaMemBlock* ArenaAllocator::EmptyArenaBlock() {
- ArenaMemBlock* res = static_cast<ArenaMemBlock*>(malloc(sizeof(ArenaMemBlock)));
- malloc_bytes_ += sizeof(ArenaMemBlock);
- res->block_size = 0;
- res->bytes_allocated = 0;
- res->next = NULL;
- return res;
+Arena::~Arena() {
+ if (kUseMemMap) {
+ delete map_;
+ } else {
+ free(reinterpret_cast<void*>(memory_));
+ }
}
-// Arena-based malloc for compilation tasks.
-void* ArenaAllocator::NewMem(size_t size, bool zero, ArenaAllocKind kind) {
- DCHECK(current_block_ != NULL);
- DCHECK(arena_head_ != NULL);
- size = (size + 3) & ~3;
- alloc_stats_[kind] += size;
- ArenaMemBlock* allocation_block = current_block_; // Assume we'll fit.
- size_t remaining_space = current_block_->block_size - current_block_->bytes_allocated;
- if (remaining_space < size) {
- /*
- * Time to allocate a new block. If this is a large allocation or we have
- * significant space remaining in the current block then fulfill the allocation
- * request with a custom-sized malloc() - otherwise grab a new standard block.
- */
- size_t allocation_size = sizeof(ArenaMemBlock);
- if ((remaining_space >= ARENA_HIGH_WATER) || (size > block_size_)) {
- allocation_size += size;
+void Arena::Reset() {
+ if (bytes_allocated_) {
+ if (kUseMemSet || !kUseMemMap) {
+ memset(Begin(), 0, bytes_allocated_);
} else {
- allocation_size += block_size_;
+ madvise(Begin(), bytes_allocated_, MADV_DONTNEED);
}
- ArenaMemBlock *new_block = static_cast<ArenaMemBlock*>(malloc(allocation_size));
- if (new_block == NULL) {
- LOG(FATAL) << "Arena allocation failure";
- }
- malloc_bytes_ += allocation_size;
- new_block->block_size = allocation_size - sizeof(ArenaMemBlock);
- new_block->bytes_allocated = 0;
- new_block->next = NULL;
- num_arena_blocks_++;
- /*
- * If the new block is completely full, insert it into the head of the list so we don't
- * bother trying to fit more and won't hide the potentially allocatable space on the
- * last (current_block_) block. TUNING: if we move to a mark scheme, revisit
- * this code to keep allocation order intact.
- */
- if (new_block->block_size == size) {
- new_block->next = arena_head_;
- arena_head_ = new_block;
- } else {
- int lost = (current_block_->block_size - current_block_->bytes_allocated);
- lost_bytes_ += lost;
- current_block_->next = new_block;
- current_block_ = new_block;
- }
- allocation_block = new_block;
+ bytes_allocated_ = 0;
}
- void* ptr = &allocation_block->ptr[allocation_block->bytes_allocated];
- allocation_block->bytes_allocated += size;
- if (zero) {
- memset(ptr, 0, size);
- }
- num_allocations_++;
- return ptr;
}
-// Dump memory usage stats.
-void ArenaAllocator::DumpMemStats(std::ostream& os) const {
+ArenaPool::ArenaPool()
+ : lock_("Arena pool lock"),
+ free_arenas_(nullptr) {
+}
+
+ArenaPool::~ArenaPool() {
+ while (free_arenas_ != nullptr) {
+ auto* arena = free_arenas_;
+ free_arenas_ = free_arenas_->next_;
+ delete arena;
+ }
+}
+
+Arena* ArenaPool::AllocArena(size_t size) {
+ Thread* self = Thread::Current();
+ Arena* ret = nullptr;
+ {
+ MutexLock lock(self, lock_);
+ if (free_arenas_ != nullptr && LIKELY(free_arenas_->Size() >= size)) {
+ ret = free_arenas_;
+ free_arenas_ = free_arenas_->next_;
+ }
+ }
+ if (ret == nullptr) {
+ ret = new Arena(size);
+ }
+ ret->Reset();
+ return ret;
+}
+
+void ArenaPool::FreeArena(Arena* arena) {
+ Thread* self = Thread::Current();
+ {
+ MutexLock lock(self, lock_);
+ arena->next_ = free_arenas_;
+ free_arenas_ = arena;
+ }
+}
+
+size_t ArenaAllocator::BytesAllocated() const {
size_t total = 0;
for (int i = 0; i < kNumAllocKinds; i++) {
total += alloc_stats_[i];
}
- os << " MEM: used: " << total << ", allocated: " << malloc_bytes_
- << ", lost: " << lost_bytes_ << "\n";
- os << "Number of blocks allocated: " << num_arena_blocks_ << ", Number of allocations: "
- << num_allocations_ << ", avg: " << total / num_allocations_ << "\n";
+ return total;
+}
+
+ArenaAllocator::ArenaAllocator(ArenaPool* pool)
+ : pool_(pool),
+ begin_(nullptr),
+ end_(nullptr),
+ ptr_(nullptr),
+ arena_head_(nullptr),
+ num_allocations_(0) {
+ memset(&alloc_stats_[0], 0, sizeof(alloc_stats_));
+}
+
+void ArenaAllocator::UpdateBytesAllocated() {
+ if (arena_head_ != nullptr) {
+ // Update how many bytes we have allocated into the arena so that the arena pool knows how
+ // much memory to zero out.
+ arena_head_->bytes_allocated_ = ptr_ - begin_;
+ }
+}
+
+ArenaAllocator::~ArenaAllocator() {
+ // Reclaim all the arenas by giving them back to the thread pool.
+ UpdateBytesAllocated();
+ while (arena_head_ != nullptr) {
+ Arena* arena = arena_head_;
+ arena_head_ = arena_head_->next_;
+ pool_->FreeArena(arena);
+ }
+}
+
+void ArenaAllocator::ObtainNewArenaForAllocation(size_t allocation_size) {
+ UpdateBytesAllocated();
+ Arena* new_arena = pool_->AllocArena(std::max(Arena::kDefaultSize, allocation_size));
+ new_arena->next_ = arena_head_;
+ arena_head_ = new_arena;
+ // Update our internal data structures.
+ ptr_ = begin_ = new_arena->Begin();
+ end_ = new_arena->End();
+}
+
+// Dump memory usage stats.
+void ArenaAllocator::DumpMemStats(std::ostream& os) const {
+ size_t malloc_bytes = 0;
+ // Start out with how many lost bytes we have in the arena we are currently allocating into.
+ size_t lost_bytes(end_ - ptr_);
+ size_t num_arenas = 0;
+ for (Arena* arena = arena_head_; arena != nullptr; arena = arena->next_) {
+ malloc_bytes += arena->Size();
+ if (arena != arena_head_) {
+ lost_bytes += arena->RemainingSpace();
+ }
+ ++num_arenas;
+ }
+ const size_t bytes_allocated = BytesAllocated();
+ os << " MEM: used: " << bytes_allocated << ", allocated: " << malloc_bytes
+ << ", lost: " << lost_bytes << "\n";
+ if (num_allocations_ != 0) {
+ os << "Number of arenas allocated: " << num_arenas << ", Number of allocations: "
+ << num_allocations_ << ", avg size: " << bytes_allocated / num_allocations_ << "\n";
+ }
os << "===== Allocation by kind\n";
for (int i = 0; i < kNumAllocKinds; i++) {
os << alloc_names[i] << std::setw(10) << alloc_stats_[i] << "\n";
diff --git a/compiler/dex/arena_allocator.h b/compiler/dex/arena_allocator.h
index e8e2c02..dda52a2 100644
--- a/compiler/dex/arena_allocator.h
+++ b/compiler/dex/arena_allocator.h
@@ -19,65 +19,127 @@
#include <stdint.h>
#include <stddef.h>
+
+#include "base/mutex.h"
#include "compiler_enums.h"
+#include "mem_map.h"
namespace art {
-#define ARENA_DEFAULT_BLOCK_SIZE (256 * 1024)
-#define ARENA_HIGH_WATER (16 * 1024)
+class Arena;
+class ArenaPool;
+class ArenaAllocator;
-class ArenaAllocator {
- public:
- // Type of allocation for memory tuning.
- enum ArenaAllocKind {
- kAllocMisc,
- kAllocBB,
- kAllocLIR,
- kAllocMIR,
- kAllocDFInfo,
- kAllocGrowableArray,
- kAllocGrowableBitMap,
- kAllocDalvikToSSAMap,
- kAllocDebugInfo,
- kAllocSuccessor,
- kAllocRegAlloc,
- kAllocData,
- kAllocPredecessors,
- kNumAllocKinds
- };
-
- explicit ArenaAllocator(size_t default_size = ARENA_DEFAULT_BLOCK_SIZE);
- ~ArenaAllocator();
- void* NewMem(size_t size, bool zero, ArenaAllocKind kind);
- size_t BytesAllocated() {
- return malloc_bytes_;
+class Arena {
+ public:
+ static constexpr size_t kDefaultSize = 128 * KB;
+ explicit Arena(size_t size = kDefaultSize);
+ ~Arena();
+ void Reset();
+ uint8_t* Begin() {
+ return memory_;
}
+ uint8_t* End() {
+ return memory_ + size_;
+ }
+
+ size_t Size() const {
+ return size_;
+ }
+
+ size_t RemainingSpace() const {
+ return Size() - bytes_allocated_;
+ }
+
+ private:
+ size_t bytes_allocated_;
+ uint8_t* memory_;
+ size_t size_;
+ MemMap* map_;
+ Arena* next_;
+ friend class ArenaPool;
+ friend class ArenaAllocator;
+ DISALLOW_COPY_AND_ASSIGN(Arena);
+};
+
+class ArenaPool {
+ public:
+ ArenaPool();
+ ~ArenaPool();
+ Arena* AllocArena(size_t size);
+ void FreeArena(Arena* arena);
+
+ private:
+ Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ Arena* free_arenas_ GUARDED_BY(lock_);
+ DISALLOW_COPY_AND_ASSIGN(ArenaPool);
+};
+
+class ArenaAllocator {
+ public:
+ // Type of allocation for memory tuning.
+ enum ArenaAllocKind {
+ kAllocMisc,
+ kAllocBB,
+ kAllocLIR,
+ kAllocMIR,
+ kAllocDFInfo,
+ kAllocGrowableArray,
+ kAllocGrowableBitMap,
+ kAllocDalvikToSSAMap,
+ kAllocDebugInfo,
+ kAllocSuccessor,
+ kAllocRegAlloc,
+ kAllocData,
+ kAllocPredecessors,
+ kNumAllocKinds
+ };
+
+ static constexpr bool kCountAllocations = false;
+
+ explicit ArenaAllocator(ArenaPool* pool);
+ ~ArenaAllocator();
+
+ // Returns zeroed memory.
+ void* Alloc(size_t bytes, ArenaAllocKind kind) ALWAYS_INLINE {
+ bytes = (bytes + 3) & ~3;
+ if (UNLIKELY(ptr_ + bytes > end_)) {
+ // Obtain a new block.
+ ObtainNewArenaForAllocation(bytes);
+ if (UNLIKELY(ptr_ == nullptr)) {
+ return nullptr;
+ }
+ }
+ if (kCountAllocations) {
+ alloc_stats_[kind] += bytes;
+ ++num_allocations_;
+ }
+ uint8_t* ret = ptr_;
+ ptr_ += bytes;
+ return ret;
+ }
+
+ void ObtainNewArenaForAllocation(size_t allocation_size);
+ size_t BytesAllocated() const;
void DumpMemStats(std::ostream& os) const;
- private:
- // Variable-length allocation block.
- struct ArenaMemBlock {
- size_t block_size;
- size_t bytes_allocated;
- ArenaMemBlock *next;
- char ptr[0];
- };
+ private:
+ void UpdateBytesAllocated();
- ArenaMemBlock* EmptyArenaBlock();
+ ArenaPool* pool_;
+ uint8_t* begin_;
+ uint8_t* end_;
+ uint8_t* ptr_;
+ Arena* arena_head_;
- size_t default_size_; // Smallest size of new allocation block.
- size_t block_size_; // Amount of allocatable bytes on a default block.
- ArenaMemBlock* arena_head_; // Head of linked list of allocation blocks.
- ArenaMemBlock* current_block_; // NOTE: code assumes there's always at least 1 block.
- int num_arena_blocks_;
- uint32_t malloc_bytes_; // Number of actual bytes malloc'd
- uint32_t alloc_stats_[kNumAllocKinds]; // Bytes used by various allocation kinds.
- uint32_t lost_bytes_; // Lost memory at end of too-small region
- uint32_t num_allocations_;
+ // Statistics.
+ size_t num_allocations_;
+ size_t alloc_stats_[kNumAllocKinds]; // Bytes used by various allocation kinds.
+
+ DISALLOW_COPY_AND_ASSIGN(ArenaAllocator);
}; // ArenaAllocator
-
struct MemStats {
public:
void Dump(std::ostream& os) const {
diff --git a/compiler/dex/arena_bit_vector.cc b/compiler/dex/arena_bit_vector.cc
index 724fdf8..3fa9295 100644
--- a/compiler/dex/arena_bit_vector.cc
+++ b/compiler/dex/arena_bit_vector.cc
@@ -35,8 +35,8 @@
expandable_(expandable),
kind_(kind),
storage_size_((start_bits + 31) >> 5),
- storage_(static_cast<uint32_t*>(arena_->NewMem(storage_size_ * sizeof(uint32_t), true,
- ArenaAllocator::kAllocGrowableBitMap))) {
+ storage_(static_cast<uint32_t*>(arena_->Alloc(storage_size_ * sizeof(uint32_t),
+ ArenaAllocator::kAllocGrowableBitMap))) {
DCHECK_EQ(sizeof(storage_[0]), 4U); // Assuming 32-bit units.
}
@@ -68,8 +68,8 @@
unsigned int new_size = (num + 1 + 31) >> 5;
DCHECK_GT(new_size, storage_size_);
uint32_t *new_storage =
- static_cast<uint32_t*>(arena_->NewMem(new_size * sizeof(uint32_t), false,
- ArenaAllocator::kAllocGrowableBitMap));
+ static_cast<uint32_t*>(arena_->Alloc(new_size * sizeof(uint32_t),
+ ArenaAllocator::kAllocGrowableBitMap));
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));
diff --git a/compiler/dex/arena_bit_vector.h b/compiler/dex/arena_bit_vector.h
index 4ec8c88..8bcd628 100644
--- a/compiler/dex/arena_bit_vector.h
+++ b/compiler/dex/arena_bit_vector.h
@@ -67,8 +67,8 @@
}
static void* operator new(size_t size, ArenaAllocator* arena) {
- return arena->NewMem(sizeof(ArenaBitVector::Iterator), true,
- ArenaAllocator::kAllocGrowableBitMap);
+ return arena->Alloc(sizeof(ArenaBitVector::Iterator),
+ ArenaAllocator::kAllocGrowableBitMap);
};
static void operator delete(void* p) {} // Nop.
@@ -84,7 +84,7 @@
~ArenaBitVector() {}
static void* operator new(size_t size, ArenaAllocator* arena) {
- return arena->NewMem(sizeof(ArenaBitVector), true, ArenaAllocator::kAllocGrowableBitMap);
+ return arena->Alloc(sizeof(ArenaBitVector), ArenaAllocator::kAllocGrowableBitMap);
}
static void operator delete(void* p) {} // Nop.
diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h
index a9b5bf6..26d0923 100644
--- a/compiler/dex/compiler_ir.h
+++ b/compiler/dex/compiler_ir.h
@@ -43,7 +43,7 @@
class Mir2Lir;
struct CompilationUnit {
- CompilationUnit()
+ explicit CompilationUnit(ArenaPool* pool)
: compiler_driver(NULL),
class_linker(NULL),
dex_file(NULL),
@@ -66,6 +66,7 @@
num_regs(0),
num_compiler_temps(0),
compiler_flip_match(false),
+ arena(pool),
mir_graph(NULL),
cg(NULL) {}
/*
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index d1f7f3e..2303649 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -119,30 +119,30 @@
VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- UniquePtr<CompilationUnit> cu(new CompilationUnit);
+ CompilationUnit cu(&compiler.GetArenaPool());
- cu->compiler_driver = &compiler;
- cu->class_linker = class_linker;
- cu->instruction_set = compiler.GetInstructionSet();
- cu->compiler_backend = compiler_backend;
- DCHECK((cu->instruction_set == kThumb2) ||
- (cu->instruction_set == kX86) ||
- (cu->instruction_set == kMips));
+ cu.compiler_driver = &compiler;
+ cu.class_linker = class_linker;
+ cu.instruction_set = compiler.GetInstructionSet();
+ cu.compiler_backend = compiler_backend;
+ DCHECK((cu.instruction_set == kThumb2) ||
+ (cu.instruction_set == kX86) ||
+ (cu.instruction_set == kMips));
/* Adjust this value accordingly once inlining is performed */
- cu->num_dalvik_registers = code_item->registers_size_;
+ cu.num_dalvik_registers = code_item->registers_size_;
// TODO: set this from command line
- cu->compiler_flip_match = false;
- bool use_match = !cu->compiler_method_match.empty();
- bool match = use_match && (cu->compiler_flip_match ^
- (PrettyMethod(method_idx, dex_file).find(cu->compiler_method_match) !=
+ cu.compiler_flip_match = false;
+ bool use_match = !cu.compiler_method_match.empty();
+ bool match = use_match && (cu.compiler_flip_match ^
+ (PrettyMethod(method_idx, dex_file).find(cu.compiler_method_match) !=
std::string::npos));
if (!use_match || match) {
- cu->disable_opt = kCompilerOptimizerDisableFlags;
- cu->enable_debug = kCompilerDebugFlags;
- cu->verbose = VLOG_IS_ON(compiler) ||
- (cu->enable_debug & (1 << kDebugVerbose));
+ cu.disable_opt = kCompilerOptimizerDisableFlags;
+ cu.enable_debug = kCompilerDebugFlags;
+ cu.verbose = VLOG_IS_ON(compiler) ||
+ (cu.enable_debug & (1 << kDebugVerbose));
}
/*
@@ -152,12 +152,12 @@
if (compiler_backend == kPortable) {
// Fused long branches not currently usseful in bitcode.
- cu->disable_opt |= (1 << kBranchFusing);
+ cu.disable_opt |= (1 << kBranchFusing);
}
- if (cu->instruction_set == kMips) {
+ if (cu.instruction_set == kMips) {
// Disable some optimizations for mips for now
- cu->disable_opt |= (
+ cu.disable_opt |= (
(1 << kLoadStoreElimination) |
(1 << kLoadHoisting) |
(1 << kSuppressLoads) |
@@ -170,72 +170,71 @@
(1 << kPromoteCompilerTemps));
}
- cu->mir_graph.reset(new MIRGraph(cu.get(), &cu->arena));
+ cu.mir_graph.reset(new MIRGraph(&cu, &cu.arena));
/* Gathering opcode stats? */
if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) {
- cu->mir_graph->EnableOpcodeCounting();
+ cu.mir_graph->EnableOpcodeCounting();
}
/* Build the raw MIR graph */
- cu->mir_graph->InlineMethod(code_item, access_flags, invoke_type, class_def_idx, method_idx,
+ cu.mir_graph->InlineMethod(code_item, access_flags, invoke_type, class_def_idx, method_idx,
class_loader, dex_file);
#if !defined(ART_USE_PORTABLE_COMPILER)
- if (cu->mir_graph->SkipCompilation(Runtime::Current()->GetCompilerFilter())) {
+ if (cu.mir_graph->SkipCompilation(Runtime::Current()->GetCompilerFilter())) {
return NULL;
}
#endif
/* Do a code layout pass */
- cu->mir_graph->CodeLayout();
+ cu.mir_graph->CodeLayout();
/* Perform SSA transformation for the whole method */
- cu->mir_graph->SSATransformation();
+ cu.mir_graph->SSATransformation();
/* Do constant propagation */
- cu->mir_graph->PropagateConstants();
+ cu.mir_graph->PropagateConstants();
/* Count uses */
- cu->mir_graph->MethodUseCount();
+ cu.mir_graph->MethodUseCount();
/* Perform null check elimination */
- cu->mir_graph->NullCheckElimination();
+ cu.mir_graph->NullCheckElimination();
/* Combine basic blocks where possible */
- cu->mir_graph->BasicBlockCombine();
+ cu.mir_graph->BasicBlockCombine();
/* Do some basic block optimizations */
- cu->mir_graph->BasicBlockOptimization();
+ cu.mir_graph->BasicBlockOptimization();
- if (cu->enable_debug & (1 << kDebugDumpCheckStats)) {
- cu->mir_graph->DumpCheckStats();
+ if (cu.enable_debug & (1 << kDebugDumpCheckStats)) {
+ cu.mir_graph->DumpCheckStats();
}
if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) {
- cu->mir_graph->ShowOpcodeStats();
+ cu.mir_graph->ShowOpcodeStats();
}
/* Set up regLocation[] array to describe values - one for each ssa_name. */
- cu->mir_graph->BuildRegLocations();
+ cu.mir_graph->BuildRegLocations();
CompiledMethod* result = NULL;
#if defined(ART_USE_PORTABLE_COMPILER)
if (compiler_backend == kPortable) {
- cu->cg.reset(PortableCodeGenerator(cu.get(), cu->mir_graph.get(), &cu->arena,
- llvm_compilation_unit));
+ cu.cg.reset(PortableCodeGenerator(&cu, cu.mir_graph.get(), &cu.arena, llvm_compilation_unit));
} else {
#endif
switch (compiler.GetInstructionSet()) {
case kThumb2:
- cu->cg.reset(ArmCodeGenerator(cu.get(), cu->mir_graph.get(), &cu->arena));
+ cu.cg.reset(ArmCodeGenerator(&cu, cu.mir_graph.get(), &cu.arena));
break;
case kMips:
- cu->cg.reset(MipsCodeGenerator(cu.get(), cu->mir_graph.get(), &cu->arena));
+ cu.cg.reset(MipsCodeGenerator(&cu, cu.mir_graph.get(), &cu.arena));
break;
case kX86:
- cu->cg.reset(X86CodeGenerator(cu.get(), cu->mir_graph.get(), &cu->arena));
+ cu.cg.reset(X86CodeGenerator(&cu, cu.mir_graph.get(), &cu.arena));
break;
default:
LOG(FATAL) << "Unexpected instruction set: " << compiler.GetInstructionSet();
@@ -244,9 +243,9 @@
}
#endif
- cu->cg->Materialize();
+ cu.cg->Materialize();
- result = cu->cg->GetCompiledMethod();
+ result = cu.cg->GetCompiledMethod();
if (result) {
VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file);
@@ -254,15 +253,15 @@
VLOG(compiler) << "Deferred " << PrettyMethod(method_idx, dex_file);
}
- if (cu->enable_debug & (1 << kDebugShowMemoryUsage)) {
- if (cu->arena.BytesAllocated() > (5 * 1024 *1024)) {
- MemStats mem_stats(cu->arena);
+ if (cu.enable_debug & (1 << kDebugShowMemoryUsage)) {
+ if (cu.arena.BytesAllocated() > (5 * 1024 *1024)) {
+ MemStats mem_stats(cu.arena);
LOG(INFO) << PrettyMethod(method_idx, dex_file) << " " << Dumpable<MemStats>(mem_stats);
}
}
- if (cu->enable_debug & (1 << kDebugShowSummaryMemoryUsage)) {
- LOG(INFO) << "MEMINFO " << cu->arena.BytesAllocated() << " " << cu->mir_graph->GetNumBlocks()
+ if (cu.enable_debug & (1 << kDebugShowSummaryMemoryUsage)) {
+ LOG(INFO) << "MEMINFO " << cu.arena.BytesAllocated() << " " << cu.mir_graph->GetNumBlocks()
<< " " << PrettyMethod(method_idx, dex_file);
}
diff --git a/compiler/dex/growable_array.h b/compiler/dex/growable_array.h
index 08a6478..8e2abfb 100644
--- a/compiler/dex/growable_array.h
+++ b/compiler/dex/growable_array.h
@@ -67,7 +67,7 @@
}
static void* operator new(size_t size, ArenaAllocator* arena) {
- return arena->NewMem(sizeof(GrowableArray::Iterator), true, ArenaAllocator::kAllocGrowableArray);
+ return arena->Alloc(sizeof(GrowableArray::Iterator), ArenaAllocator::kAllocGrowableArray);
};
static void operator delete(void* p) {} // Nop.
@@ -81,8 +81,8 @@
num_allocated_(init_length),
num_used_(0),
kind_(kind) {
- elem_list_ = static_cast<T*>(arena_->NewMem(sizeof(T) * init_length, true,
- ArenaAllocator::kAllocGrowableArray));
+ elem_list_ = static_cast<T*>(arena_->Alloc(sizeof(T) * init_length,
+ ArenaAllocator::kAllocGrowableArray));
};
@@ -95,8 +95,8 @@
if (new_length > target_length) {
target_length = new_length;
}
- T* new_array = static_cast<T*>(arena_->NewMem(sizeof(T) * target_length, true,
- ArenaAllocator::kAllocGrowableArray));
+ T* new_array = static_cast<T*>(arena_->Alloc(sizeof(T) * target_length,
+ ArenaAllocator::kAllocGrowableArray));
memcpy(new_array, elem_list_, sizeof(T) * num_allocated_);
num_allocated_ = target_length;
elem_list_ = new_array;
@@ -153,7 +153,7 @@
T* GetRawStorage() const { return elem_list_; }
static void* operator new(size_t size, ArenaAllocator* arena) {
- return arena->NewMem(sizeof(GrowableArray<T>), true, ArenaAllocator::kAllocGrowableArray);
+ return arena->Alloc(sizeof(GrowableArray<T>), ArenaAllocator::kAllocGrowableArray);
};
static void operator delete(void* p) {} // Nop.
diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc
index c3a33ff..3a73717 100644
--- a/compiler/dex/mir_dataflow.cc
+++ b/compiler/dex/mir_dataflow.cc
@@ -954,11 +954,11 @@
int i;
mir->ssa_rep->num_uses = num_uses;
- mir->ssa_rep->uses = static_cast<int*>(arena_->NewMem(sizeof(int) * num_uses, true,
- ArenaAllocator::kAllocDFInfo));
+ mir->ssa_rep->uses = static_cast<int*>(arena_->Alloc(sizeof(int) * num_uses,
+ ArenaAllocator::kAllocDFInfo));
// NOTE: will be filled in during type & size inference pass
- mir->ssa_rep->fp_use = static_cast<bool*>(arena_->NewMem(sizeof(bool) * num_uses, true,
- ArenaAllocator::kAllocDFInfo));
+ mir->ssa_rep->fp_use = static_cast<bool*>(arena_->Alloc(sizeof(bool) * num_uses,
+ ArenaAllocator::kAllocDFInfo));
for (i = 0; i < num_uses; i++) {
HandleSSAUse(mir->ssa_rep->uses, d_insn->arg[i], i);
@@ -972,11 +972,11 @@
int i;
mir->ssa_rep->num_uses = num_uses;
- mir->ssa_rep->uses = static_cast<int*>(arena_->NewMem(sizeof(int) * num_uses, true,
- ArenaAllocator::kAllocDFInfo));
+ mir->ssa_rep->uses = static_cast<int*>(arena_->Alloc(sizeof(int) * num_uses,
+ ArenaAllocator::kAllocDFInfo));
// NOTE: will be filled in during type & size inference pass
- mir->ssa_rep->fp_use = static_cast<bool*>(arena_->NewMem(sizeof(bool) * num_uses, true,
- ArenaAllocator::kAllocDFInfo));
+ mir->ssa_rep->fp_use = static_cast<bool*>(arena_->Alloc(sizeof(bool) * num_uses,
+ ArenaAllocator::kAllocDFInfo));
for (i = 0; i < num_uses; i++) {
HandleSSAUse(mir->ssa_rep->uses, d_insn->vC+i, i);
@@ -991,8 +991,8 @@
for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
mir->ssa_rep =
- static_cast<struct SSARepresentation *>(arena_->NewMem(sizeof(SSARepresentation), true,
- ArenaAllocator::kAllocDFInfo));
+ static_cast<struct SSARepresentation *>(arena_->Alloc(sizeof(SSARepresentation),
+ ArenaAllocator::kAllocDFInfo));
int df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
@@ -1041,10 +1041,10 @@
if (num_uses) {
mir->ssa_rep->num_uses = num_uses;
- mir->ssa_rep->uses = static_cast<int*>(arena_->NewMem(sizeof(int) * num_uses, false,
- ArenaAllocator::kAllocDFInfo));
- mir->ssa_rep->fp_use = static_cast<bool*>(arena_->NewMem(sizeof(bool) * num_uses, false,
- ArenaAllocator::kAllocDFInfo));
+ mir->ssa_rep->uses = static_cast<int*>(arena_->Alloc(sizeof(int) * num_uses,
+ ArenaAllocator::kAllocDFInfo));
+ mir->ssa_rep->fp_use = static_cast<bool*>(arena_->Alloc(sizeof(bool) * num_uses,
+ ArenaAllocator::kAllocDFInfo));
}
int num_defs = 0;
@@ -1058,10 +1058,10 @@
if (num_defs) {
mir->ssa_rep->num_defs = num_defs;
- mir->ssa_rep->defs = static_cast<int*>(arena_->NewMem(sizeof(int) * num_defs, false,
- ArenaAllocator::kAllocDFInfo));
- mir->ssa_rep->fp_def = static_cast<bool*>(arena_->NewMem(sizeof(bool) * num_defs, false,
- ArenaAllocator::kAllocDFInfo));
+ mir->ssa_rep->defs = static_cast<int*>(arena_->Alloc(sizeof(int) * num_defs,
+ ArenaAllocator::kAllocDFInfo));
+ mir->ssa_rep->fp_def = static_cast<bool*>(arena_->Alloc(sizeof(bool) * num_defs,
+ ArenaAllocator::kAllocDFInfo));
}
DecodedInstruction *d_insn = &mir->dalvikInsn;
@@ -1109,8 +1109,8 @@
* predecessor blocks.
*/
bb->data_flow_info->vreg_to_ssa_map =
- static_cast<int*>(arena_->NewMem(sizeof(int) * cu_->num_dalvik_registers, false,
- ArenaAllocator::kAllocDFInfo));
+ static_cast<int*>(arena_->Alloc(sizeof(int) * cu_->num_dalvik_registers,
+ ArenaAllocator::kAllocDFInfo));
memcpy(bb->data_flow_info->vreg_to_ssa_map, vreg_to_ssa_map_,
sizeof(int) * cu_->num_dalvik_registers);
@@ -1146,12 +1146,12 @@
* Dalvik register, and the SSA names for those are the same.
*/
vreg_to_ssa_map_ =
- static_cast<int*>(arena_->NewMem(sizeof(int) * num_dalvik_reg, false,
- ArenaAllocator::kAllocDFInfo));
+ static_cast<int*>(arena_->Alloc(sizeof(int) * num_dalvik_reg,
+ ArenaAllocator::kAllocDFInfo));
/* Keep track of the higest def for each dalvik reg */
ssa_last_defs_ =
- static_cast<int*>(arena_->NewMem(sizeof(int) * num_dalvik_reg, false,
- ArenaAllocator::kAllocDFInfo));
+ static_cast<int*>(arena_->Alloc(sizeof(int) * num_dalvik_reg,
+ ArenaAllocator::kAllocDFInfo));
for (unsigned int i = 0; i < num_dalvik_reg; i++) {
vreg_to_ssa_map_[i] = i;
@@ -1174,8 +1174,8 @@
bb->block_type == kEntryBlock ||
bb->block_type == kExitBlock) {
bb->data_flow_info =
- static_cast<BasicBlockDataFlow*>(arena_->NewMem(sizeof(BasicBlockDataFlow), true,
- ArenaAllocator::kAllocDFInfo));
+ static_cast<BasicBlockDataFlow*>(arena_->Alloc(sizeof(BasicBlockDataFlow),
+ ArenaAllocator::kAllocDFInfo));
}
}
}
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index 86f6ee5..81702e3 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -399,8 +399,8 @@
BasicBlock *case_block = FindBlock(cur_offset + target_table[i], /* split */ true,
/* create */ true, /* immed_pred_block_p */ &cur_block);
SuccessorBlockInfo *successor_block_info =
- static_cast<SuccessorBlockInfo*>(arena_->NewMem(sizeof(SuccessorBlockInfo), false,
- ArenaAllocator::kAllocSuccessor));
+ static_cast<SuccessorBlockInfo*>(arena_->Alloc(sizeof(SuccessorBlockInfo),
+ ArenaAllocator::kAllocSuccessor));
successor_block_info->block = case_block;
successor_block_info->key =
(insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) ?
@@ -444,7 +444,7 @@
catches_.insert(catch_block->start_offset);
}
SuccessorBlockInfo *successor_block_info = reinterpret_cast<SuccessorBlockInfo*>
- (arena_->NewMem(sizeof(SuccessorBlockInfo), false, ArenaAllocator::kAllocSuccessor));
+ (arena_->Alloc(sizeof(SuccessorBlockInfo), ArenaAllocator::kAllocSuccessor));
successor_block_info->block = catch_block;
successor_block_info->key = iterator.GetHandlerTypeIndex();
cur_block->successor_block_list.blocks->Insert(successor_block_info);
@@ -490,7 +490,7 @@
new_block->start_offset = insn->offset;
cur_block->fall_through = new_block;
new_block->predecessors->Insert(cur_block);
- MIR* new_insn = static_cast<MIR*>(arena_->NewMem(sizeof(MIR), true, ArenaAllocator::kAllocMIR));
+ MIR* new_insn = static_cast<MIR*>(arena_->Alloc(sizeof(MIR), ArenaAllocator::kAllocMIR));
*new_insn = *insn;
insn->dalvikInsn.opcode =
static_cast<Instruction::Code>(kMirOpCheck);
@@ -571,13 +571,12 @@
int num_patterns = sizeof(special_patterns)/sizeof(special_patterns[0]);
bool live_pattern = (num_patterns > 0) && !(cu_->disable_opt & (1 << kMatch));
bool* dead_pattern =
- static_cast<bool*>(arena_->NewMem(sizeof(bool) * num_patterns, true,
- ArenaAllocator::kAllocMisc));
+ static_cast<bool*>(arena_->Alloc(sizeof(bool) * num_patterns, ArenaAllocator::kAllocMisc));
int pattern_pos = 0;
/* Parse all instructions and put them into containing basic blocks */
while (code_ptr < code_end) {
- MIR *insn = static_cast<MIR *>(arena_->NewMem(sizeof(MIR), true, ArenaAllocator::kAllocMIR));
+ MIR *insn = static_cast<MIR *>(arena_->Alloc(sizeof(MIR), ArenaAllocator::kAllocMIR));
insn->offset = current_offset_;
insn->m_unit_index = current_method_;
int width = ParseInsn(code_ptr, &insn->dalvikInsn);
@@ -1002,7 +1001,7 @@
str.append("]--optimized away");
}
int length = str.length() + 1;
- ret = static_cast<char*>(arena_->NewMem(length, false, ArenaAllocator::kAllocDFInfo));
+ ret = static_cast<char*>(arena_->Alloc(length, ArenaAllocator::kAllocDFInfo));
strncpy(ret, str.c_str(), length);
return ret;
}
@@ -1115,8 +1114,8 @@
*/
CallInfo* MIRGraph::NewMemCallInfo(BasicBlock* bb, MIR* mir, InvokeType type,
bool is_range) {
- CallInfo* info = static_cast<CallInfo*>(arena_->NewMem(sizeof(CallInfo), true,
- ArenaAllocator::kAllocMisc));
+ CallInfo* info = static_cast<CallInfo*>(arena_->Alloc(sizeof(CallInfo),
+ ArenaAllocator::kAllocMisc));
MIR* move_result_mir = FindMoveResult(bb, mir);
if (move_result_mir == NULL) {
info->result.location = kLocInvalid;
@@ -1127,8 +1126,7 @@
}
info->num_arg_words = mir->ssa_rep->num_uses;
info->args = (info->num_arg_words == 0) ? NULL : static_cast<RegLocation*>
- (arena_->NewMem(sizeof(RegLocation) * info->num_arg_words, false,
- ArenaAllocator::kAllocMisc));
+ (arena_->Alloc(sizeof(RegLocation) * info->num_arg_words, ArenaAllocator::kAllocMisc));
for (int i = 0; i < info->num_arg_words; i++) {
info->args[i] = GetRawSrc(mir, i);
}
@@ -1142,8 +1140,8 @@
// Allocate a new basic block.
BasicBlock* MIRGraph::NewMemBB(BBType block_type, int block_id) {
- BasicBlock* bb = static_cast<BasicBlock*>(arena_->NewMem(sizeof(BasicBlock), true,
- ArenaAllocator::kAllocBB));
+ BasicBlock* bb = static_cast<BasicBlock*>(arena_->Alloc(sizeof(BasicBlock),
+ ArenaAllocator::kAllocBB));
bb->block_type = block_type;
bb->id = block_id;
// TUNING: better estimate of the exit block predecessors?
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index c02deab..28ab283 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -426,8 +426,8 @@
}
void EnableOpcodeCounting() {
- opcode_count_ = static_cast<int*>(arena_->NewMem(kNumPackedOpcodes * sizeof(int), true,
- ArenaAllocator::kAllocMisc));
+ opcode_count_ = static_cast<int*>(arena_->Alloc(kNumPackedOpcodes * sizeof(int),
+ ArenaAllocator::kAllocMisc));
}
void ShowOpcodeStats();
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index 9f694de..b7611f8 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -94,8 +94,8 @@
void MIRGraph::PropagateConstants() {
is_constant_v_ = new (arena_) ArenaBitVector(arena_, GetNumSSARegs(), false);
- constant_values_ = static_cast<int*>(arena_->NewMem(sizeof(int) * GetNumSSARegs(), true,
- ArenaAllocator::kAllocDFInfo));
+ constant_values_ = static_cast<int*>(arena_->Alloc(sizeof(int) * GetNumSSARegs(),
+ ArenaAllocator::kAllocDFInfo));
AllNodesIterator iter(this, false /* not iterative */);
for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
DoConstantPropogation(bb);
@@ -399,8 +399,7 @@
DCHECK_EQ(SelectKind(if_true), kSelectMove);
DCHECK_EQ(SelectKind(if_false), kSelectMove);
int* src_ssa =
- static_cast<int*>(arena_->NewMem(sizeof(int) * 3, false,
- ArenaAllocator::kAllocDFInfo));
+ static_cast<int*>(arena_->Alloc(sizeof(int) * 3, ArenaAllocator::kAllocDFInfo));
src_ssa[0] = mir->ssa_rep->uses[0];
src_ssa[1] = if_true->ssa_rep->uses[0];
src_ssa[2] = if_false->ssa_rep->uses[0];
@@ -409,16 +408,14 @@
}
mir->ssa_rep->num_defs = 1;
mir->ssa_rep->defs =
- static_cast<int*>(arena_->NewMem(sizeof(int) * 1, false,
- ArenaAllocator::kAllocDFInfo));
+ static_cast<int*>(arena_->Alloc(sizeof(int) * 1, ArenaAllocator::kAllocDFInfo));
mir->ssa_rep->fp_def =
- static_cast<bool*>(arena_->NewMem(sizeof(bool) * 1, false,
- ArenaAllocator::kAllocDFInfo));
+ static_cast<bool*>(arena_->Alloc(sizeof(bool) * 1, ArenaAllocator::kAllocDFInfo));
mir->ssa_rep->fp_def[0] = if_true->ssa_rep->fp_def[0];
// Match type of uses to def.
mir->ssa_rep->fp_use =
- static_cast<bool*>(arena_->NewMem(sizeof(bool) * mir->ssa_rep->num_uses, false,
- ArenaAllocator::kAllocDFInfo));
+ static_cast<bool*>(arena_->Alloc(sizeof(bool) * mir->ssa_rep->num_uses,
+ ArenaAllocator::kAllocDFInfo));
for (int i = 0; i < mir->ssa_rep->num_uses; i++) {
mir->ssa_rep->fp_use[i] = mir->ssa_rep->fp_def[0];
}
@@ -805,8 +802,7 @@
void MIRGraph::DumpCheckStats() {
Checkstats* stats =
- static_cast<Checkstats*>(arena_->NewMem(sizeof(Checkstats), true,
- ArenaAllocator::kAllocDFInfo));
+ static_cast<Checkstats*>(arena_->Alloc(sizeof(Checkstats), ArenaAllocator::kAllocDFInfo));
checkstats_ = stats;
AllNodesIterator iter(this, false /* not iterative */);
for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc
index 90cec75..7831cf6 100644
--- a/compiler/dex/portable/mir_to_gbc.cc
+++ b/compiler/dex/portable/mir_to_gbc.cc
@@ -1972,7 +1972,7 @@
::llvm::OwningPtr< ::llvm::tool_output_file> out_file(
new ::llvm::tool_output_file(fname.c_str(), errmsg,
- ::llvm::sys::fs::F_Binary));
+ ::llvm::raw_fd_ostream::F_Binary));
if (!errmsg.empty()) {
LOG(ERROR) << "Failed to create bitcode output file: " << errmsg;
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 2d8e24f..2dbe5f5 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -316,13 +316,12 @@
}
// Add the table to the list - we'll process it later
SwitchTable *tab_rec =
- static_cast<SwitchTable*>(arena_->NewMem(sizeof(SwitchTable), true,
- ArenaAllocator::kAllocData));
+ static_cast<SwitchTable*>(arena_->Alloc(sizeof(SwitchTable), ArenaAllocator::kAllocData));
tab_rec->table = table;
tab_rec->vaddr = current_dalvik_offset_;
int size = table[1];
- tab_rec->targets = static_cast<LIR**>(arena_->NewMem(size * sizeof(LIR*), true,
- ArenaAllocator::kAllocLIR));
+ tab_rec->targets = static_cast<LIR**>(arena_->Alloc(size * sizeof(LIR*),
+ ArenaAllocator::kAllocLIR));
switch_tables_.Insert(tab_rec);
// Get the switch value
@@ -365,13 +364,12 @@
}
// Add the table to the list - we'll process it later
SwitchTable *tab_rec =
- static_cast<SwitchTable*>(arena_->NewMem(sizeof(SwitchTable), true,
- ArenaAllocator::kAllocData));
+ static_cast<SwitchTable*>(arena_->Alloc(sizeof(SwitchTable), ArenaAllocator::kAllocData));
tab_rec->table = table;
tab_rec->vaddr = current_dalvik_offset_;
int size = table[1];
tab_rec->targets =
- static_cast<LIR**>(arena_->NewMem(size * sizeof(LIR*), true, ArenaAllocator::kAllocLIR));
+ static_cast<LIR**>(arena_->Alloc(size * sizeof(LIR*), ArenaAllocator::kAllocLIR));
switch_tables_.Insert(tab_rec);
// Get the switch value
@@ -419,8 +417,7 @@
const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset;
// Add the table to the list - we'll process it later
FillArrayData *tab_rec =
- static_cast<FillArrayData*>(arena_->NewMem(sizeof(FillArrayData), true,
- ArenaAllocator::kAllocData));
+ static_cast<FillArrayData*>(arena_->Alloc(sizeof(FillArrayData), ArenaAllocator::kAllocData));
tab_rec->table = table;
tab_rec->vaddr = current_dalvik_offset_;
uint16_t width = tab_rec->table[1];
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index f1ccfa0..291319f 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -26,7 +26,7 @@
ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
// Required for target - codegen helpers.
- bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
+ bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src,
RegLocation rl_dest, int lit);
int LoadHelper(ThreadOffset offset);
LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index c258019..f2ff58e 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -415,7 +415,7 @@
};
// Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
-bool ArmMir2Lir::SmallLiteralDivide(Instruction::Code dalvik_opcode,
+bool ArmMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
RegLocation rl_src, RegLocation rl_dest, int lit) {
if ((lit < 0) || (lit >= static_cast<int>(sizeof(magic_table)/sizeof(magic_table[0])))) {
return false;
@@ -425,7 +425,7 @@
return false;
}
// Tuning: add rem patterns
- if (dalvik_opcode != Instruction::DIV_INT_LIT8) {
+ if (!is_div) {
return false;
}
diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc
index 47d3d97..6cc3052 100644
--- a/compiler/dex/quick/arm/target_arm.cc
+++ b/compiler/dex/quick/arm/target_arm.cc
@@ -538,16 +538,14 @@
int num_temps = sizeof(core_temps)/sizeof(*core_temps);
int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
- reg_pool_ = static_cast<RegisterPool*>(arena_->NewMem(sizeof(*reg_pool_), true,
- ArenaAllocator::kAllocRegAlloc));
+ reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
+ ArenaAllocator::kAllocRegAlloc));
reg_pool_->num_core_regs = num_regs;
reg_pool_->core_regs = reinterpret_cast<RegisterInfo*>
- (arena_->NewMem(num_regs * sizeof(*reg_pool_->core_regs), true,
- ArenaAllocator::kAllocRegAlloc));
+ (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), ArenaAllocator::kAllocRegAlloc));
reg_pool_->num_fp_regs = num_fp_regs;
reg_pool_->FPRegs = static_cast<RegisterInfo*>
- (arena_->NewMem(num_fp_regs * sizeof(*reg_pool_->FPRegs), true,
- ArenaAllocator::kAllocRegAlloc));
+ (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), ArenaAllocator::kAllocRegAlloc));
CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
// Keep special registers from being allocated
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 5f6f3d5..d89f1ed 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -321,7 +321,7 @@
LIR* Mir2Lir::AddWordData(LIR* *constant_list_p, int value) {
/* Add the constant to the literal pool */
if (constant_list_p) {
- LIR* new_value = static_cast<LIR*>(arena_->NewMem(sizeof(LIR), true, ArenaAllocator::kAllocData));
+ LIR* new_value = static_cast<LIR*>(arena_->Alloc(sizeof(LIR), ArenaAllocator::kAllocData));
new_value->operands[0] = value;
new_value->next = *constant_list_p;
*constant_list_p = new_value;
@@ -793,7 +793,7 @@
if (it == boundary_map_.end()) {
LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr;
}
- LIR* new_label = static_cast<LIR*>(arena_->NewMem(sizeof(LIR), true, ArenaAllocator::kAllocLIR));
+ LIR* new_label = static_cast<LIR*>(arena_->Alloc(sizeof(LIR), ArenaAllocator::kAllocLIR));
new_label->dalvik_offset = vaddr;
new_label->opcode = kPseudoCaseLabel;
new_label->operands[0] = keyVal;
@@ -961,8 +961,8 @@
first_lir_insn_(NULL),
last_lir_insn_(NULL) {
promotion_map_ = static_cast<PromotionMap*>
- (arena_->NewMem((cu_->num_dalvik_registers + cu_->num_compiler_temps + 1) *
- sizeof(promotion_map_[0]), true, ArenaAllocator::kAllocRegAlloc));
+ (arena_->Alloc((cu_->num_dalvik_registers + cu_->num_compiler_temps + 1) *
+ sizeof(promotion_map_[0]), ArenaAllocator::kAllocRegAlloc));
}
void Mir2Lir::Materialize() {
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index e5c7fb1..f018c61 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -1358,25 +1358,23 @@
// Returns true if it added instructions to 'cu' to divide 'rl_src' by 'lit'
// and store the result in 'rl_dest'.
-bool Mir2Lir::HandleEasyDivide(Instruction::Code dalvik_opcode,
+bool Mir2Lir::HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div,
RegLocation rl_src, RegLocation rl_dest, int lit) {
if ((lit < 2) || ((cu_->instruction_set != kThumb2) && !IsPowerOfTwo(lit))) {
return false;
}
// No divide instruction for Arm, so check for more special cases
if ((cu_->instruction_set == kThumb2) && !IsPowerOfTwo(lit)) {
- return SmallLiteralDivide(dalvik_opcode, rl_src, rl_dest, lit);
+ return SmallLiteralDivRem(dalvik_opcode, is_div, rl_src, rl_dest, lit);
}
int k = LowestSetBit(lit);
if (k >= 30) {
// Avoid special cases.
return false;
}
- bool div = (dalvik_opcode == Instruction::DIV_INT_LIT8 ||
- dalvik_opcode == Instruction::DIV_INT_LIT16);
rl_src = LoadValue(rl_src, kCoreReg);
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
- if (div) {
+ if (is_div) {
int t_reg = AllocTemp();
if (lit == 2) {
// Division by 2 is by far the most common division by constant.
@@ -1544,17 +1542,17 @@
GenImmedCheck(kCondAl, 0, 0, kThrowDivZero);
return;
}
- if (HandleEasyDivide(opcode, rl_src, rl_dest, lit)) {
- return;
- }
- if ((opcode == Instruction::DIV_INT_LIT8) ||
- (opcode == Instruction::DIV_INT) ||
+ if ((opcode == Instruction::DIV_INT) ||
(opcode == Instruction::DIV_INT_2ADDR) ||
+ (opcode == Instruction::DIV_INT_LIT8) ||
(opcode == Instruction::DIV_INT_LIT16)) {
is_div = true;
} else {
is_div = false;
}
+ if (HandleEasyDivRem(opcode, is_div, rl_src, rl_dest, lit)) {
+ return;
+ }
if (cu_->instruction_set == kMips) {
rl_src = LoadValue(rl_src, kCoreReg);
rl_result = GenDivRemLit(rl_dest, rl_src.low_reg, lit, is_div);
diff --git a/compiler/dex/quick/local_optimizations.cc b/compiler/dex/quick/local_optimizations.cc
index 2e9c845..630e990 100644
--- a/compiler/dex/quick/local_optimizations.cc
+++ b/compiler/dex/quick/local_optimizations.cc
@@ -249,7 +249,7 @@
/* Only sink store instructions */
if (sink_distance && !is_this_lir_load) {
LIR* new_store_lir =
- static_cast<LIR*>(arena_->NewMem(sizeof(LIR), true, ArenaAllocator::kAllocLIR));
+ static_cast<LIR*>(arena_->Alloc(sizeof(LIR), ArenaAllocator::kAllocLIR));
*new_store_lir = *this_lir;
/*
* Stop point found - insert *before* the check_lir
@@ -446,7 +446,7 @@
if (slot >= 0) {
LIR* cur_lir = prev_inst_list[slot];
LIR* new_load_lir =
- static_cast<LIR*>(arena_->NewMem(sizeof(LIR), true, ArenaAllocator::kAllocLIR));
+ static_cast<LIR*>(arena_->Alloc(sizeof(LIR), ArenaAllocator::kAllocLIR));
*new_load_lir = *this_lir;
/*
* Insertion is guaranteed to succeed since check_lir
diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc
index eaae0e1..d53c012 100644
--- a/compiler/dex/quick/mips/call_mips.cc
+++ b/compiler/dex/quick/mips/call_mips.cc
@@ -67,13 +67,12 @@
}
// Add the table to the list - we'll process it later
SwitchTable *tab_rec =
- static_cast<SwitchTable*>(arena_->NewMem(sizeof(SwitchTable), true,
- ArenaAllocator::kAllocData));
+ static_cast<SwitchTable*>(arena_->Alloc(sizeof(SwitchTable), ArenaAllocator::kAllocData));
tab_rec->table = table;
tab_rec->vaddr = current_dalvik_offset_;
int elements = table[1];
tab_rec->targets =
- static_cast<LIR**>(arena_->NewMem(elements * sizeof(LIR*), true, ArenaAllocator::kAllocLIR));
+ static_cast<LIR**>(arena_->Alloc(elements * sizeof(LIR*), ArenaAllocator::kAllocLIR));
switch_tables_.Insert(tab_rec);
// The table is composed of 8-byte key/disp pairs
@@ -147,12 +146,11 @@
}
// Add the table to the list - we'll process it later
SwitchTable *tab_rec =
- static_cast<SwitchTable*>(arena_->NewMem(sizeof(SwitchTable), true,
- ArenaAllocator::kAllocData));
+ static_cast<SwitchTable*>(arena_->Alloc(sizeof(SwitchTable), ArenaAllocator::kAllocData));
tab_rec->table = table;
tab_rec->vaddr = current_dalvik_offset_;
int size = table[1];
- tab_rec->targets = static_cast<LIR**>(arena_->NewMem(size * sizeof(LIR*), true,
+ tab_rec->targets = static_cast<LIR**>(arena_->Alloc(size * sizeof(LIR*),
ArenaAllocator::kAllocLIR));
switch_tables_.Insert(tab_rec);
@@ -228,8 +226,8 @@
const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset;
// Add the table to the list - we'll process it later
FillArrayData *tab_rec =
- reinterpret_cast<FillArrayData*>(arena_->NewMem(sizeof(FillArrayData), true,
- ArenaAllocator::kAllocData));
+ reinterpret_cast<FillArrayData*>(arena_->Alloc(sizeof(FillArrayData),
+ ArenaAllocator::kAllocData));
tab_rec->table = table;
tab_rec->vaddr = current_dalvik_offset_;
uint16_t width = tab_rec->table[1];
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 6100396..b9cb720 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -27,7 +27,7 @@
MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
// Required for target - codegen utilities.
- bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
+ bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src,
RegLocation rl_dest, int lit);
int LoadHelper(ThreadOffset offset);
LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index 4a48c87..6ce5750 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -314,7 +314,7 @@
return OpCmpImmBranch(c_code, reg, 0, target);
}
-bool MipsMir2Lir::SmallLiteralDivide(Instruction::Code dalvik_opcode,
+bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
RegLocation rl_src, RegLocation rl_dest, int lit) {
LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips";
return false;
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 7a9e91a..4ee5b23 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -462,16 +462,14 @@
int num_temps = sizeof(core_temps)/sizeof(*core_temps);
int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
- reg_pool_ = static_cast<RegisterPool*>(arena_->NewMem(sizeof(*reg_pool_), true,
- ArenaAllocator::kAllocRegAlloc));
+ reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
+ ArenaAllocator::kAllocRegAlloc));
reg_pool_->num_core_regs = num_regs;
reg_pool_->core_regs = static_cast<RegisterInfo*>
- (arena_->NewMem(num_regs * sizeof(*reg_pool_->core_regs), true,
- ArenaAllocator::kAllocRegAlloc));
+ (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), ArenaAllocator::kAllocRegAlloc));
reg_pool_->num_fp_regs = num_fp_regs;
reg_pool_->FPRegs = static_cast<RegisterInfo*>
- (arena_->NewMem(num_fp_regs * sizeof(*reg_pool_->FPRegs), true,
- ArenaAllocator::kAllocRegAlloc));
+ (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), ArenaAllocator::kAllocRegAlloc));
CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
// Keep special registers from being allocated
diff --git a/compiler/dex/quick/mir_to_lir-inl.h b/compiler/dex/quick/mir_to_lir-inl.h
index d9aef5d..440df2a 100644
--- a/compiler/dex/quick/mir_to_lir-inl.h
+++ b/compiler/dex/quick/mir_to_lir-inl.h
@@ -40,7 +40,7 @@
inline LIR* Mir2Lir::RawLIR(int dalvik_offset, int opcode, int op0,
int op1, int op2, int op3, int op4, LIR* target) {
- LIR* insn = static_cast<LIR*>(arena_->NewMem(sizeof(LIR), true, ArenaAllocator::kAllocLIR));
+ LIR* insn = static_cast<LIR*>(arena_->Alloc(sizeof(LIR), ArenaAllocator::kAllocLIR));
insn->dalvik_offset = dalvik_offset;
insn->opcode = opcode;
insn->operands[0] = op0;
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 862c1d7..c41feb1 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -812,8 +812,8 @@
void Mir2Lir::MethodMIR2LIR() {
// Hold the labels of each block.
block_label_list_ =
- static_cast<LIR*>(arena_->NewMem(sizeof(LIR) * mir_graph_->GetNumBlocks(), true,
- ArenaAllocator::kAllocLIR));
+ static_cast<LIR*>(arena_->Alloc(sizeof(LIR) * mir_graph_->GetNumBlocks(),
+ ArenaAllocator::kAllocLIR));
PreOrderDfsIterator iter(mir_graph_, false /* not iterative */);
for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 517fc66..a37ebd1 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -376,7 +376,7 @@
RegLocation GetReturn(bool is_float);
// Shared by all targets - implemented in gen_common.cc.
- bool HandleEasyDivide(Instruction::Code dalvik_opcode,
+ bool HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div,
RegLocation rl_src, RegLocation rl_dest, int lit);
bool HandleEasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit);
void HandleSuspendLaunchPads();
@@ -525,7 +525,7 @@
// Required for target - codegen helpers.
- virtual bool SmallLiteralDivide(Instruction::Code dalvik_opcode,
+ virtual bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
RegLocation rl_src, RegLocation rl_dest, int lit) = 0;
virtual int LoadHelper(ThreadOffset offset) = 0;
virtual LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg) = 0;
diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc
index d59c986..71b74a4 100644
--- a/compiler/dex/quick/ralloc_util.cc
+++ b/compiler/dex/quick/ralloc_util.cc
@@ -931,7 +931,12 @@
static int SortCounts(const void *val1, const void *val2) {
const Mir2Lir::RefCounts* op1 = reinterpret_cast<const Mir2Lir::RefCounts*>(val1);
const Mir2Lir::RefCounts* op2 = reinterpret_cast<const Mir2Lir::RefCounts*>(val2);
- return (op1->count == op2->count) ? 0 : (op1->count < op2->count ? 1 : -1);
+ // Note that we fall back to sorting on reg so we get stable output
+ // on differing qsort implementations (such as on host and target or
+ // between local host and build servers).
+ return (op1->count == op2->count)
+ ? (op1->s_reg - op2->s_reg)
+ : (op1->count < op2->count ? 1 : -1);
}
void Mir2Lir::DumpCounts(const RefCounts* arr, int size, const char* msg) {
@@ -966,11 +971,11 @@
* to describe register live ranges for GC.
*/
RefCounts *core_regs =
- static_cast<RefCounts*>(arena_->NewMem(sizeof(RefCounts) * num_regs, true,
- ArenaAllocator::kAllocRegAlloc));
+ static_cast<RefCounts*>(arena_->Alloc(sizeof(RefCounts) * num_regs,
+ ArenaAllocator::kAllocRegAlloc));
RefCounts *FpRegs =
- static_cast<RefCounts *>(arena_->NewMem(sizeof(RefCounts) * num_regs, true,
- ArenaAllocator::kAllocRegAlloc));
+ static_cast<RefCounts *>(arena_->Alloc(sizeof(RefCounts) * num_regs,
+ ArenaAllocator::kAllocRegAlloc));
// Set ssa names for original Dalvik registers
for (int i = 0; i < dalvik_regs; i++) {
core_regs[i].s_reg = FpRegs[i].s_reg = i;
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 6e3e55f..2be2aa9 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -74,13 +74,12 @@
}
// Add the table to the list - we'll process it later
SwitchTable *tab_rec =
- static_cast<SwitchTable *>(arena_->NewMem(sizeof(SwitchTable), true,
- ArenaAllocator::kAllocData));
+ static_cast<SwitchTable *>(arena_->Alloc(sizeof(SwitchTable), ArenaAllocator::kAllocData));
tab_rec->table = table;
tab_rec->vaddr = current_dalvik_offset_;
int size = table[1];
- tab_rec->targets = static_cast<LIR**>(arena_->NewMem(size * sizeof(LIR*), true,
- ArenaAllocator::kAllocLIR));
+ tab_rec->targets = static_cast<LIR**>(arena_->Alloc(size * sizeof(LIR*),
+ ArenaAllocator::kAllocLIR));
switch_tables_.Insert(tab_rec);
// Get the switch value
@@ -131,8 +130,7 @@
const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset;
// Add the table to the list - we'll process it later
FillArrayData *tab_rec =
- static_cast<FillArrayData*>(arena_->NewMem(sizeof(FillArrayData), true,
- ArenaAllocator::kAllocData));
+ static_cast<FillArrayData*>(arena_->Alloc(sizeof(FillArrayData), ArenaAllocator::kAllocData));
tab_rec->table = table;
tab_rec->vaddr = current_dalvik_offset_;
uint16_t width = tab_rec->table[1];
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 21328d5..478654d 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -27,7 +27,7 @@
X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
// Required for target - codegen helpers.
- bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
+ bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src,
RegLocation rl_dest, int lit);
int LoadHelper(ThreadOffset offset);
LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 377d134..14be7dd 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -295,7 +295,7 @@
return OpCmpImmBranch(c_code, reg, 0, target);
}
-bool X86Mir2Lir::SmallLiteralDivide(Instruction::Code dalvik_opcode,
+bool X86Mir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
RegLocation rl_src, RegLocation rl_dest, int lit) {
LOG(FATAL) << "Unexpected use of smallLiteralDive in x86";
return false;
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 699f3ae..26accab 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -438,16 +438,16 @@
int num_temps = sizeof(core_temps)/sizeof(*core_temps);
int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
- reg_pool_ = static_cast<RegisterPool*>(arena_->NewMem(sizeof(*reg_pool_), true,
- ArenaAllocator::kAllocRegAlloc));
+ reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
+ ArenaAllocator::kAllocRegAlloc));
reg_pool_->num_core_regs = num_regs;
reg_pool_->core_regs =
- static_cast<RegisterInfo*>(arena_->NewMem(num_regs * sizeof(*reg_pool_->core_regs), true,
- ArenaAllocator::kAllocRegAlloc));
+ static_cast<RegisterInfo*>(arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs),
+ ArenaAllocator::kAllocRegAlloc));
reg_pool_->num_fp_regs = num_fp_regs;
reg_pool_->FPRegs =
- static_cast<RegisterInfo *>(arena_->NewMem(num_fp_regs * sizeof(*reg_pool_->FPRegs), true,
- ArenaAllocator::kAllocRegAlloc));
+ static_cast<RegisterInfo *>(arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs),
+ ArenaAllocator::kAllocRegAlloc));
CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
// Keep special registers from being allocated
diff --git a/compiler/dex/ssa_transformation.cc b/compiler/dex/ssa_transformation.cc
index 18d8e93..cd1602f 100644
--- a/compiler/dex/ssa_transformation.cc
+++ b/compiler/dex/ssa_transformation.cc
@@ -136,8 +136,8 @@
int num_registers = cu_->num_dalvik_registers;
/* Allocate num_dalvik_registers bit vector pointers */
def_block_matrix_ = static_cast<ArenaBitVector**>
- (arena_->NewMem(sizeof(ArenaBitVector *) * num_registers, true,
- ArenaAllocator::kAllocDFInfo));
+ (arena_->Alloc(sizeof(ArenaBitVector *) * num_registers,
+ ArenaAllocator::kAllocDFInfo));
int i;
/* Initialize num_register vectors with num_blocks bits each */
@@ -384,8 +384,8 @@
/* Initalize & Clear i_dom_list */
if (i_dom_list_ == NULL) {
- i_dom_list_ = static_cast<int*>(arena_->NewMem(sizeof(int) * num_reachable_blocks, false,
- ArenaAllocator::kAllocDFInfo));
+ i_dom_list_ = static_cast<int*>(arena_->Alloc(sizeof(int) * num_reachable_blocks,
+ ArenaAllocator::kAllocDFInfo));
}
for (int i = 0; i < num_reachable_blocks; i++) {
i_dom_list_[i] = NOTVISITED;
@@ -564,7 +564,7 @@
continue;
}
MIR *phi =
- static_cast<MIR*>(arena_->NewMem(sizeof(MIR), true, ArenaAllocator::kAllocDFInfo));
+ static_cast<MIR*>(arena_->Alloc(sizeof(MIR), ArenaAllocator::kAllocDFInfo));
phi->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpPhi);
phi->dalvikInsn.vA = dalvik_reg;
phi->offset = phi_bb->start_offset;
@@ -610,14 +610,11 @@
int num_uses = uses.size();
mir->ssa_rep->num_uses = num_uses;
mir->ssa_rep->uses =
- static_cast<int*>(arena_->NewMem(sizeof(int) * num_uses, false,
- ArenaAllocator::kAllocDFInfo));
+ static_cast<int*>(arena_->Alloc(sizeof(int) * num_uses, ArenaAllocator::kAllocDFInfo));
mir->ssa_rep->fp_use =
- static_cast<bool*>(arena_->NewMem(sizeof(bool) * num_uses, true,
- ArenaAllocator::kAllocDFInfo));
+ static_cast<bool*>(arena_->Alloc(sizeof(bool) * num_uses, ArenaAllocator::kAllocDFInfo));
int* incoming =
- static_cast<int*>(arena_->NewMem(sizeof(int) * num_uses, false,
- ArenaAllocator::kAllocDFInfo));
+ static_cast<int*>(arena_->Alloc(sizeof(int) * num_uses, ArenaAllocator::kAllocDFInfo));
// TODO: Ugly, rework (but don't burden each MIR/LIR for Phi-only needs)
mir->dalvikInsn.vB = reinterpret_cast<uintptr_t>(incoming);
@@ -644,7 +641,7 @@
/* Save SSA map snapshot */
int* saved_ssa_map =
- static_cast<int*>(arena_->NewMem(map_size, false, ArenaAllocator::kAllocDalvikToSSAMap));
+ static_cast<int*>(arena_->Alloc(map_size, ArenaAllocator::kAllocDalvikToSSAMap));
memcpy(saved_ssa_map, vreg_to_ssa_map_, map_size);
if (block->fall_through) {
diff --git a/compiler/dex/vreg_analysis.cc b/compiler/dex/vreg_analysis.cc
index 5ee6753..07f37bb 100644
--- a/compiler/dex/vreg_analysis.cc
+++ b/compiler/dex/vreg_analysis.cc
@@ -374,8 +374,8 @@
*/
void MIRGraph::BuildRegLocations() {
/* Allocate the location map */
- RegLocation* loc = static_cast<RegLocation*>(arena_->NewMem(GetNumSSARegs() * sizeof(*loc), true,
- ArenaAllocator::kAllocRegAlloc));
+ RegLocation* loc = static_cast<RegLocation*>(arena_->Alloc(GetNumSSARegs() * sizeof(*loc),
+ ArenaAllocator::kAllocRegAlloc));
for (int i = 0; i < GetNumSSARegs(); i++) {
loc[i] = fresh_loc;
loc[i].s_reg_low = i;
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index c079e52..634d3bc 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -473,7 +473,7 @@
const std::vector<const DexFile*>& dex_files,
base::TimingLogger& timings) {
DCHECK(!Runtime::Current()->IsStarted());
- UniquePtr<ThreadPool> thread_pool(new ThreadPool(thread_count_));
+ UniquePtr<ThreadPool> thread_pool(new ThreadPool(thread_count_ - 1));
PreCompile(class_loader, dex_files, *thread_pool.get(), timings);
Compile(class_loader, dex_files, *thread_pool.get(), timings);
if (dump_stats_) {
@@ -537,7 +537,7 @@
std::vector<const DexFile*> dex_files;
dex_files.push_back(dex_file);
- UniquePtr<ThreadPool> thread_pool(new ThreadPool(1U));
+ UniquePtr<ThreadPool> thread_pool(new ThreadPool(0U));
PreCompile(jclass_loader, dex_files, *thread_pool.get(), timings);
uint32_t method_idx = method->GetDexMethodIndex();
@@ -1322,7 +1322,8 @@
CompilerDriver* compiler,
const DexFile* dex_file,
ThreadPool& thread_pool)
- : class_linker_(class_linker),
+ : index_(0),
+ class_linker_(class_linker),
class_loader_(class_loader),
compiler_(compiler),
dex_file_(dex_file),
@@ -1353,8 +1354,9 @@
CHECK_GT(work_units, 0U);
std::vector<ForAllClosure*> closures(work_units);
+ index_ = begin;
for (size_t i = 0; i < work_units; ++i) {
- closures[i] = new ForAllClosure(this, begin + i, end, callback, work_units);
+ closures[i] = new ForAllClosure(this, end, callback);
thread_pool_->AddTask(self, closures[i]);
}
thread_pool_->StartWorkers(self);
@@ -1367,20 +1369,25 @@
thread_pool_->Wait(self, true, false);
}
+ size_t NextIndex() {
+ return index_.fetch_add(1);
+ }
+
private:
class ForAllClosure : public Task {
public:
- ForAllClosure(ParallelCompilationManager* manager, size_t begin, size_t end, Callback* callback,
- size_t stripe)
+ ForAllClosure(ParallelCompilationManager* manager, size_t end, Callback* callback)
: manager_(manager),
- begin_(begin),
end_(end),
- callback_(callback),
- stripe_(stripe) {}
+ callback_(callback) {}
virtual void Run(Thread* self) {
- for (size_t i = begin_; i < end_; i += stripe_) {
- callback_(manager_, i);
+ while (true) {
+ const size_t index = manager_->NextIndex();
+ if (UNLIKELY(index >= end_)) {
+ break;
+ }
+ callback_(manager_, index);
self->AssertNoPendingException();
}
}
@@ -1390,18 +1397,19 @@
}
private:
- const ParallelCompilationManager* const manager_;
- const size_t begin_;
+ ParallelCompilationManager* const manager_;
const size_t end_;
const Callback* const callback_;
- const size_t stripe_;
};
+ AtomicInteger index_;
ClassLinker* const class_linker_;
const jobject class_loader_;
CompilerDriver* const compiler_;
const DexFile* const dex_file_;
ThreadPool* const thread_pool_;
+
+ DISALLOW_COPY_AND_ASSIGN(ParallelCompilationManager);
};
// Return true if the class should be skipped during compilation. We
@@ -2094,7 +2102,7 @@
mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields();
CHECK_EQ(fields->GetLength(), 1);
fields->Get(0)->SetObj(klass, manager->GetClassLinker()->FindPrimitiveClass('V'));
- klass->SetStatus(mirror::Class::kStatusInitialized);
+ klass->SetStatus(mirror::Class::kStatusInitialized, soa.Self());
} else {
manager->GetClassLinker()->EnsureInitialized(klass, true, true);
}
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 22a510b..fa1b8f9 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -26,6 +26,7 @@
#include "compiled_class.h"
#include "compiled_method.h"
#include "dex_file.h"
+#include "dex/arena_allocator.h"
#include "instruction_set.h"
#include "invoke_type.h"
#include "method_reference.h"
@@ -213,6 +214,9 @@
support_boot_image_fixup_ = support_boot_image_fixup;
}
+ ArenaPool& GetArenaPool() {
+ return arena_pool_;
+ }
bool WriteElf(const std::string& android_root,
bool is_host,
@@ -423,6 +427,9 @@
pthread_key_t tls_key_;
+ // Arena pool used by the compiler.
+ ArenaPool arena_pool_;
+
typedef void (*CompilerEnableAutoElfLoadingFn)(CompilerDriver& driver);
CompilerEnableAutoElfLoadingFn compiler_enable_auto_elf_loading_;
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 60c8f07..04342fd 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -596,7 +596,7 @@
<< " for " << elf_file_->GetPath();
return false;
}
- if (!elf_file_->WriteFully(&dynstr[0], dynsym_size)) {
+ if (!elf_file_->WriteFully(&dynstr[0], dynstr_size)) {
PLOG(ERROR) << "Failed to write .dynsym for " << elf_file_->GetPath();
return false;
}
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index dcafc19..106ef9a 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -152,7 +152,7 @@
// non image classes should be in a space after the image.
EXPECT_GT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
}
- EXPECT_EQ(*klass->GetRawLockWordAddress(), 0); // address should have been removed from monitor
+ EXPECT_TRUE(Monitor::IsValidLockWord(*klass->GetRawLockWordAddress()));
}
}
diff --git a/compiler/llvm/llvm_compilation_unit.cc b/compiler/llvm/llvm_compilation_unit.cc
index 139100b..aa439cc 100644
--- a/compiler/llvm/llvm_compilation_unit.cc
+++ b/compiler/llvm/llvm_compilation_unit.cc
@@ -214,6 +214,7 @@
::llvm::TargetOptions target_options;
target_options.FloatABIType = ::llvm::FloatABI::Soft;
target_options.NoFramePointerElim = true;
+ target_options.NoFramePointerElimNonLeaf = true;
target_options.UseSoftFloat = false;
target_options.EnableFastISel = false;
@@ -257,7 +258,7 @@
::llvm::OwningPtr< ::llvm::tool_output_file> out_file(
new ::llvm::tool_output_file(bitcode_filename_.c_str(), errmsg,
- ::llvm::sys::fs::F_Binary));
+ ::llvm::raw_fd_ostream::F_Binary));
if (!errmsg.empty()) {
@@ -277,6 +278,7 @@
// pm_builder.Inliner = ::llvm::createAlwaysInlinerPass();
// pm_builder.Inliner = ::llvm::createPartialInliningPass();
pm_builder.OptLevel = 3;
+ pm_builder.DisableSimplifyLibCalls = 1;
pm_builder.DisableUnitAtATime = 1;
pm_builder.populateFunctionPassManager(fpm);
pm_builder.populateModulePassManager(pm);
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 8bc7877..0227381 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -506,7 +506,7 @@
typedef MappingTable::PcToDexIterator It;
for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
if (offset == cur.NativePcOffset()) {
- os << "suspend point dex PC: 0x" << cur.DexPc() << "\n";
+ os << StringPrintf("suspend point dex PC: 0x%04x\n", cur.DexPc());
return cur.DexPc();
}
}
@@ -514,7 +514,7 @@
typedef MappingTable::DexToPcIterator It;
for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
if (offset == cur.NativePcOffset()) {
- os << "catch entry dex PC: 0x" << cur.DexPc() << "\n";
+ os << StringPrintf("catch entry dex PC: 0x%04x\n", cur.DexPc());
return cur.DexPc();
}
}
@@ -917,10 +917,10 @@
os << StringPrintf("%p: java.lang.Class \"%s\" (", obj, PrettyDescriptor(klass).c_str())
<< klass->GetStatus() << ")\n";
} else if (obj->IsArtField()) {
- os << StringPrintf("%p: java.lang.reflect.Field %s\n", obj,
+ os << StringPrintf("%p: java.lang.reflect.ArtField %s\n", obj,
PrettyField(obj->AsArtField()).c_str());
} else if (obj->IsArtMethod()) {
- os << StringPrintf("%p: java.lang.reflect.Method %s\n", obj,
+ os << StringPrintf("%p: java.lang.reflect.ArtMethod %s\n", obj,
PrettyMethod(obj->AsArtMethod()).c_str());
} else if (obj_class->IsStringClass()) {
os << StringPrintf("%p: java.lang.String %s\n", obj,
diff --git a/runtime/base/stringpiece.h b/runtime/base/stringpiece.h
index 62088cc..91b83f6 100644
--- a/runtime/base/stringpiece.h
+++ b/runtime/base/stringpiece.h
@@ -208,19 +208,6 @@
extern std::ostream& operator<<(std::ostream& o, const StringPiece& piece);
-struct StringPieceHash {
- size_t operator()(const StringPiece& string_piece) const {
- size_t string_size = string_piece.size();
- const char* string_data = string_piece.data();
- // This is the java.lang.String hashcode for convenience, not interoperability.
- size_t hash = 0;
- while (string_size--) {
- hash = hash * 31 + *string_data++;
- }
- return hash;
- }
-};
-
} // namespace art
#endif // ART_RUNTIME_BASE_STRINGPIECE_H_
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 3387a70..cd4a720 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -187,6 +187,8 @@
ClassLinker::ClassLinker(InternTable* intern_table)
// dex_lock_ is recursive as it may be used in stack dumping.
: dex_lock_("ClassLinker dex lock", kDefaultMutexLevel),
+ dex_cache_image_class_lookup_required_(false),
+ failed_dex_cache_class_lookups_(0),
class_roots_(NULL),
array_iftable_(NULL),
init_done_(false),
@@ -225,7 +227,7 @@
CHECK(java_lang_Object.get() != NULL);
// backfill Object as the super class of Class.
java_lang_Class->SetSuperClass(java_lang_Object.get());
- java_lang_Object->SetStatus(mirror::Class::kStatusLoaded);
+ java_lang_Object->SetStatus(mirror::Class::kStatusLoaded, self);
// Object[] next to hold class roots.
SirtRef<mirror::Class> object_array_class(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class)));
@@ -243,7 +245,7 @@
SirtRef<mirror::Class> java_lang_String(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::StringClass)));
mirror::String::SetClass(java_lang_String.get());
java_lang_String->SetObjectSize(sizeof(mirror::String));
- java_lang_String->SetStatus(mirror::Class::kStatusResolved);
+ java_lang_String->SetStatus(mirror::Class::kStatusResolved, self);
// Create storage for root classes, save away our work so far (requires descriptors).
class_roots_ = mirror::ObjectArray<mirror::Class>::Alloc(self, object_array_class.get(), kClassRootsMax);
@@ -281,7 +283,7 @@
java_lang_DexCache(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::DexCacheClass)));
SetClassRoot(kJavaLangDexCache, java_lang_DexCache.get());
java_lang_DexCache->SetObjectSize(sizeof(mirror::DexCacheClass));
- java_lang_DexCache->SetStatus(mirror::Class::kStatusResolved);
+ java_lang_DexCache->SetStatus(mirror::Class::kStatusResolved, self);
// Constructor, Field, Method, and AbstractMethod are necessary so that FindClass can link members.
SirtRef<mirror::Class> java_lang_reflect_ArtField(self, AllocClass(self, java_lang_Class.get(),
@@ -289,7 +291,7 @@
CHECK(java_lang_reflect_ArtField.get() != NULL);
java_lang_reflect_ArtField->SetObjectSize(sizeof(mirror::ArtField));
SetClassRoot(kJavaLangReflectArtField, java_lang_reflect_ArtField.get());
- java_lang_reflect_ArtField->SetStatus(mirror::Class::kStatusResolved);
+ java_lang_reflect_ArtField->SetStatus(mirror::Class::kStatusResolved, self);
mirror::ArtField::SetClass(java_lang_reflect_ArtField.get());
SirtRef<mirror::Class> java_lang_reflect_ArtMethod(self, AllocClass(self, java_lang_Class.get(),
@@ -297,7 +299,7 @@
CHECK(java_lang_reflect_ArtMethod.get() != NULL);
java_lang_reflect_ArtMethod->SetObjectSize(sizeof(mirror::ArtMethod));
SetClassRoot(kJavaLangReflectArtMethod, java_lang_reflect_ArtMethod.get());
- java_lang_reflect_ArtMethod->SetStatus(mirror::Class::kStatusResolved);
+ java_lang_reflect_ArtMethod->SetStatus(mirror::Class::kStatusResolved, self);
mirror::ArtMethod::SetClass(java_lang_reflect_ArtMethod.get());
@@ -334,15 +336,15 @@
SetClassRoot(kPrimitiveChar, char_class.get()); // needs descriptor
// Object, String and DexCache need to be rerun through FindSystemClass to finish init
- java_lang_Object->SetStatus(mirror::Class::kStatusNotReady);
+ java_lang_Object->SetStatus(mirror::Class::kStatusNotReady, self);
mirror::Class* Object_class = FindSystemClass("Ljava/lang/Object;");
CHECK_EQ(java_lang_Object.get(), Object_class);
CHECK_EQ(java_lang_Object->GetObjectSize(), sizeof(mirror::Object));
- java_lang_String->SetStatus(mirror::Class::kStatusNotReady);
+ java_lang_String->SetStatus(mirror::Class::kStatusNotReady, self);
mirror::Class* String_class = FindSystemClass("Ljava/lang/String;");
CHECK_EQ(java_lang_String.get(), String_class);
CHECK_EQ(java_lang_String->GetObjectSize(), sizeof(mirror::String));
- java_lang_DexCache->SetStatus(mirror::Class::kStatusNotReady);
+ java_lang_DexCache->SetStatus(mirror::Class::kStatusNotReady, self);
mirror::Class* DexCache_class = FindSystemClass("Ljava/lang/DexCache;");
CHECK_EQ(java_lang_String.get(), String_class);
CHECK_EQ(java_lang_DexCache.get(), DexCache_class);
@@ -397,15 +399,15 @@
CHECK_EQ(java_lang_Cloneable, kh.GetDirectInterface(0));
CHECK_EQ(java_io_Serializable, kh.GetDirectInterface(1));
// Run Class, ArtField, and ArtMethod through FindSystemClass. This initializes their
- // dex_cache_ fields and register them in classes_.
+ // dex_cache_ fields and register them in class_table_.
mirror::Class* Class_class = FindSystemClass("Ljava/lang/Class;");
CHECK_EQ(java_lang_Class.get(), Class_class);
- java_lang_reflect_ArtMethod->SetStatus(mirror::Class::kStatusNotReady);
+ java_lang_reflect_ArtMethod->SetStatus(mirror::Class::kStatusNotReady, self);
mirror::Class* Art_method_class = FindSystemClass("Ljava/lang/reflect/ArtMethod;");
CHECK_EQ(java_lang_reflect_ArtMethod.get(), Art_method_class);
- java_lang_reflect_ArtField->SetStatus(mirror::Class::kStatusNotReady);
+ java_lang_reflect_ArtField->SetStatus(mirror::Class::kStatusNotReady, self);
mirror::Class* Art_field_class = FindSystemClass("Ljava/lang/reflect/ArtField;");
CHECK_EQ(java_lang_reflect_ArtField.get(), Art_field_class);
@@ -984,21 +986,14 @@
return oat_file;
}
-static void InitFromImageCallbackCommon(mirror::Object* obj, ClassLinker* class_linker,
- bool interpret_only_mode)
+static void InitFromImageInterpretOnlyCallback(mirror::Object* obj, void* arg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ClassLinker* class_linker = reinterpret_cast<ClassLinker*>(arg);
+
DCHECK(obj != NULL);
DCHECK(class_linker != NULL);
- if (obj->GetClass()->IsStringClass()) {
- class_linker->GetInternTable()->RegisterStrong(obj->AsString());
- } else if (obj->IsClass()) {
- // Restore class to ClassLinker::classes_ table.
- mirror::Class* klass = obj->AsClass();
- ClassHelper kh(klass, class_linker);
- mirror::Class* existing = class_linker->InsertClass(kh.GetDescriptor(), klass, true);
- DCHECK(existing == NULL) << kh.GetDescriptor();
- } else if (interpret_only_mode && obj->IsArtMethod()) {
+ if (obj->IsArtMethod()) {
mirror::ArtMethod* method = obj->AsArtMethod();
if (!method->IsNative()) {
method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
@@ -1009,24 +1004,13 @@
}
}
-static void InitFromImageCallback(mirror::Object* obj, void* arg)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- ClassLinker* class_linker = reinterpret_cast<ClassLinker*>(arg);
- InitFromImageCallbackCommon(obj, class_linker, false);
-}
-
-static void InitFromImageInterpretOnlyCallback(mirror::Object* obj, void* arg)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- ClassLinker* class_linker = reinterpret_cast<ClassLinker*>(arg);
- InitFromImageCallbackCommon(obj, class_linker, true);
-}
-
void ClassLinker::InitFromImage() {
VLOG(startup) << "ClassLinker::InitFromImage entering";
CHECK(!init_done_);
gc::Heap* heap = Runtime::Current()->GetHeap();
gc::space::ImageSpace* space = heap->GetImageSpace();
+ dex_cache_image_class_lookup_required_ = true;
CHECK(space != NULL);
OatFile& oat_file = GetImageOatFile(space);
CHECK_EQ(oat_file.GetOatHeader().GetImageFileLocationOatChecksum(), 0U);
@@ -1049,7 +1033,7 @@
CHECK_EQ(oat_file.GetOatHeader().GetDexFileCount(),
static_cast<uint32_t>(dex_caches->GetLength()));
Thread* self = Thread::Current();
- for (int i = 0; i < dex_caches->GetLength(); i++) {
+ for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
SirtRef<mirror::DexCache> dex_cache(self, dex_caches->Get(i));
const std::string& dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());
const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(dex_file_location);
@@ -1069,15 +1053,11 @@
// bitmap walk.
mirror::ArtMethod::SetClass(GetClassRoot(kJavaLangReflectArtMethod));
- // reinit clases_ table
- {
+ // Set entry point to interpreter if in InterpretOnly mode.
+ if (Runtime::Current()->GetInstrumentation()->InterpretOnly()) {
ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
heap->FlushAllocStack();
- if (Runtime::Current()->GetInstrumentation()->InterpretOnly()) {
- heap->GetLiveBitmap()->Walk(InitFromImageInterpretOnlyCallback, this);
- } else {
- heap->GetLiveBitmap()->Walk(InitFromImageCallback, this);
- }
+ heap->GetLiveBitmap()->Walk(InitFromImageInterpretOnlyCallback, this);
}
// reinit class_roots_
@@ -1120,7 +1100,7 @@
{
ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
- for (const std::pair<size_t, mirror::Class*>& it : classes_) {
+ for (const std::pair<size_t, mirror::Class*>& it : class_table_) {
visitor(it.second, arg);
}
@@ -1134,14 +1114,12 @@
}
}
-void ClassLinker::VisitClasses(ClassVisitor* visitor, void* arg) const {
- ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- for (const std::pair<size_t, mirror::Class*>& it : classes_) {
- if (!visitor(it.second, arg)) {
- return;
- }
+void ClassLinker::VisitClasses(ClassVisitor* visitor, void* arg) {
+ if (dex_cache_image_class_lookup_required_) {
+ MoveImageClassesToClassTable();
}
- for (const std::pair<size_t, mirror::Class*>& it : image_classes_) {
+ ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ for (const std::pair<size_t, mirror::Class*>& it : class_table_) {
if (!visitor(it.second, arg)) {
return;
}
@@ -1154,7 +1132,7 @@
return true;
}
-void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor, void* arg) const {
+void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor, void* arg) {
std::set<mirror::Class*> classes;
VisitClasses(GetClassesVisitor, &classes);
for (mirror::Class* klass : classes) {
@@ -1274,7 +1252,7 @@
// Check for circular dependencies between classes.
if (!klass->IsResolved() && klass->GetClinitThreadId() == self->GetTid()) {
ThrowClassCircularityError(klass);
- klass->SetStatus(mirror::Class::kStatusError);
+ klass->SetStatus(mirror::Class::kStatusError, self);
return NULL;
}
// Wait for the pending initialization to complete.
@@ -1383,26 +1361,26 @@
return NULL;
}
-mirror::Class* ClassLinker::DefineClass(const StringPiece& descriptor,
+mirror::Class* ClassLinker::DefineClass(const char* descriptor,
mirror::ClassLoader* class_loader,
const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def) {
Thread* self = Thread::Current();
SirtRef<mirror::Class> klass(self, NULL);
// Load the class from the dex file.
- if (!init_done_) {
+ if (UNLIKELY(!init_done_)) {
// finish up init of hand crafted class_roots_
- if (descriptor == "Ljava/lang/Object;") {
+ if (strcmp(descriptor, "Ljava/lang/Object;") == 0) {
klass.reset(GetClassRoot(kJavaLangObject));
- } else if (descriptor == "Ljava/lang/Class;") {
+ } else if (strcmp(descriptor, "Ljava/lang/Class;") == 0) {
klass.reset(GetClassRoot(kJavaLangClass));
- } else if (descriptor == "Ljava/lang/String;") {
+ } else if (strcmp(descriptor, "Ljava/lang/String;") == 0) {
klass.reset(GetClassRoot(kJavaLangString));
- } else if (descriptor == "Ljava/lang/DexCache;") {
+ } else if (strcmp(descriptor, "Ljava/lang/DexCache;") == 0) {
klass.reset(GetClassRoot(kJavaLangDexCache));
- } else if (descriptor == "Ljava/lang/reflect/ArtField;") {
+ } else if (strcmp(descriptor, "Ljava/lang/reflect/ArtField;") == 0) {
klass.reset(GetClassRoot(kJavaLangReflectArtField));
- } else if (descriptor == "Ljava/lang/reflect/ArtMethod;") {
+ } else if (strcmp(descriptor, "Ljava/lang/reflect/ArtMethod;") == 0) {
klass.reset(GetClassRoot(kJavaLangReflectArtMethod));
} else {
klass.reset(AllocClass(self, SizeOfClass(dex_file, dex_class_def)));
@@ -1414,32 +1392,33 @@
LoadClass(dex_file, dex_class_def, klass, class_loader);
// Check for a pending exception during load
if (self->IsExceptionPending()) {
- klass->SetStatus(mirror::Class::kStatusError);
+ klass->SetStatus(mirror::Class::kStatusError, self);
return NULL;
}
ObjectLock lock(self, klass.get());
klass->SetClinitThreadId(self->GetTid());
- // Add the newly loaded class to the loaded classes table.
- SirtRef<mirror::Class> existing(self, InsertClass(descriptor, klass.get(), false));
- if (existing.get() != NULL) {
- // We failed to insert because we raced with another thread.
- return EnsureResolved(self, existing.get());
+ {
+ // Add the newly loaded class to the loaded classes table.
+ mirror::Class* existing = InsertClass(descriptor, klass.get(), Hash(descriptor));
+ if (existing != NULL) {
+ // We failed to insert because we raced with another thread. Calling EnsureResolved may cause
+ // this thread to block.
+ return EnsureResolved(self, existing);
+ }
}
// Finish loading (if necessary) by finding parents
CHECK(!klass->IsLoaded());
if (!LoadSuperAndInterfaces(klass, dex_file)) {
// Loading failed.
- klass->SetStatus(mirror::Class::kStatusError);
- lock.NotifyAll();
+ klass->SetStatus(mirror::Class::kStatusError, self);
return NULL;
}
CHECK(klass->IsLoaded());
// Link the class (if necessary)
CHECK(!klass->IsResolved());
- if (!LinkClass(klass, NULL)) {
+ if (!LinkClass(klass, NULL, self)) {
// Linking failed.
- klass->SetStatus(mirror::Class::kStatusError);
- lock.NotifyAll();
+ klass->SetStatus(mirror::Class::kStatusError, self);
return NULL;
}
CHECK(klass->IsResolved());
@@ -1734,7 +1713,7 @@
klass->SetAccessFlags(access_flags);
klass->SetClassLoader(class_loader);
DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
- klass->SetStatus(mirror::Class::kStatusIdx);
+ klass->SetStatus(mirror::Class::kStatusIdx, NULL);
klass->SetDexTypeIndex(dex_class_def.class_idx_);
@@ -1966,11 +1945,13 @@
mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_class, Primitive::Type type) {
CHECK(primitive_class != NULL);
// Must hold lock on object when initializing.
- ObjectLock lock(Thread::Current(), primitive_class);
+ Thread* self = Thread::Current();
+ ObjectLock lock(self, primitive_class);
primitive_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
primitive_class->SetPrimitiveType(type);
- primitive_class->SetStatus(mirror::Class::kStatusInitialized);
- mirror::Class* existing = InsertClass(Primitive::Descriptor(type), primitive_class, false);
+ primitive_class->SetStatus(mirror::Class::kStatusInitialized, self);
+ const char* descriptor = Primitive::Descriptor(type);
+ mirror::Class* existing = InsertClass(descriptor, primitive_class, Hash(descriptor));
CHECK(existing == NULL) << "InitPrimitiveClass(" << type << ") failed";
return primitive_class;
}
@@ -1988,12 +1969,11 @@
// array class; that always comes from the base element class.
//
// Returns NULL with an exception raised on failure.
-mirror::Class* ClassLinker::CreateArrayClass(const std::string& descriptor,
+mirror::Class* ClassLinker::CreateArrayClass(const char* descriptor,
mirror::ClassLoader* class_loader) {
- CHECK_EQ('[', descriptor[0]);
-
// Identify the underlying component type
- mirror::Class* component_type = FindClass(descriptor.substr(1).c_str(), class_loader);
+ CHECK_EQ('[', descriptor[0]);
+ mirror::Class* component_type = FindClass(descriptor + 1, class_loader);
if (component_type == NULL) {
DCHECK(Thread::Current()->IsExceptionPending());
return NULL;
@@ -2017,7 +1997,7 @@
// class to the hash table --- necessary because of possible races with
// other threads.)
if (class_loader != component_type->GetClassLoader()) {
- mirror::Class* new_class = LookupClass(descriptor.c_str(), component_type->GetClassLoader());
+ mirror::Class* new_class = LookupClass(descriptor, component_type->GetClassLoader());
if (new_class != NULL) {
return new_class;
}
@@ -2033,21 +2013,23 @@
// link step.
Thread* self = Thread::Current();
SirtRef<mirror::Class> new_class(self, NULL);
- if (!init_done_) {
+ if (UNLIKELY(!init_done_)) {
// Classes that were hand created, ie not by FindSystemClass
- if (descriptor == "[Ljava/lang/Class;") {
+ if (strcmp(descriptor, "[Ljava/lang/Class;") == 0) {
new_class.reset(GetClassRoot(kClassArrayClass));
- } else if (descriptor == "[Ljava/lang/Object;") {
+ } else if (strcmp(descriptor, "[Ljava/lang/Object;") == 0) {
new_class.reset(GetClassRoot(kObjectArrayClass));
- } else if (descriptor == class_roots_descriptors_[kJavaLangStringArrayClass]) {
+ } else if (strcmp(descriptor, class_roots_descriptors_[kJavaLangStringArrayClass]) == 0) {
new_class.reset(GetClassRoot(kJavaLangStringArrayClass));
- } else if (descriptor == class_roots_descriptors_[kJavaLangReflectArtMethodArrayClass]) {
+ } else if (strcmp(descriptor,
+ class_roots_descriptors_[kJavaLangReflectArtMethodArrayClass]) == 0) {
new_class.reset(GetClassRoot(kJavaLangReflectArtMethodArrayClass));
- } else if (descriptor == class_roots_descriptors_[kJavaLangReflectArtFieldArrayClass]) {
+ } else if (strcmp(descriptor,
+ class_roots_descriptors_[kJavaLangReflectArtFieldArrayClass]) == 0) {
new_class.reset(GetClassRoot(kJavaLangReflectArtFieldArrayClass));
- } else if (descriptor == "[C") {
+ } else if (strcmp(descriptor, "[C") == 0) {
new_class.reset(GetClassRoot(kCharArrayClass));
- } else if (descriptor == "[I") {
+ } else if (strcmp(descriptor, "[I") == 0) {
new_class.reset(GetClassRoot(kIntArrayClass));
}
}
@@ -2065,7 +2047,7 @@
new_class->SetVTable(java_lang_Object->GetVTable());
new_class->SetPrimitiveType(Primitive::kPrimNot);
new_class->SetClassLoader(component_type->GetClassLoader());
- new_class->SetStatus(mirror::Class::kStatusInitialized);
+ new_class->SetStatus(mirror::Class::kStatusInitialized, self);
// don't need to set new_class->SetObjectSize(..)
// because Object::SizeOf delegates to Array::SizeOf
@@ -2096,7 +2078,7 @@
new_class->SetAccessFlags(access_flags);
- mirror::Class* existing = InsertClass(descriptor, new_class.get(), false);
+ mirror::Class* existing = InsertClass(descriptor, new_class.get(), Hash(descriptor));
if (existing == NULL) {
return new_class.get();
}
@@ -2137,8 +2119,8 @@
return NULL;
}
-mirror::Class* ClassLinker::InsertClass(const StringPiece& descriptor, mirror::Class* klass,
- bool image_class) {
+mirror::Class* ClassLinker::InsertClass(const char* descriptor, mirror::Class* klass,
+ size_t hash) {
if (VLOG_IS_ON(class_linker)) {
mirror::DexCache* dex_cache = klass->GetDexCache();
std::string source;
@@ -2148,21 +2130,22 @@
}
LOG(INFO) << "Loaded class " << descriptor << source;
}
- size_t hash = StringPieceHash()(descriptor);
WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- Table& classes = image_class ? image_classes_ : classes_;
mirror::Class* existing =
- LookupClassLocked(descriptor.data(), klass->GetClassLoader(), hash, classes);
-#ifndef NDEBUG
- // Check we don't have the class in the other table in error
- Table& other_classes = image_class ? classes_ : image_classes_;
- CHECK(LookupClassLocked(descriptor.data(), klass->GetClassLoader(), hash, other_classes) == NULL);
-#endif
+ LookupClassFromTableLocked(descriptor, klass->GetClassLoader(), hash);
if (existing != NULL) {
return existing;
}
+ if (kIsDebugBuild && klass->GetClassLoader() == NULL && dex_cache_image_class_lookup_required_) {
+ // Check a class loaded with the system class loader matches one in the image if the class
+ // is in the image.
+ existing = LookupClassFromImage(descriptor);
+ if (existing != NULL) {
+ CHECK(klass == existing);
+ }
+ }
Runtime::Current()->GetHeap()->VerifyObject(klass);
- classes.insert(std::make_pair(hash, klass));
+ class_table_.insert(std::make_pair(hash, klass));
Dirty();
return NULL;
}
@@ -2170,23 +2153,13 @@
bool ClassLinker::RemoveClass(const char* descriptor, const mirror::ClassLoader* class_loader) {
size_t hash = Hash(descriptor);
WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- // TODO: determine if its better to search classes_ or image_classes_ first
ClassHelper kh;
- for (auto it = classes_.lower_bound(hash), end = classes_.end(); it != end && it->first == hash;
+ for (auto it = class_table_.lower_bound(hash), end = class_table_.end(); it != end && it->first == hash;
++it) {
mirror::Class* klass = it->second;
kh.ChangeClass(klass);
if (strcmp(kh.GetDescriptor(), descriptor) == 0 && klass->GetClassLoader() == class_loader) {
- classes_.erase(it);
- return true;
- }
- }
- for (auto it = image_classes_.lower_bound(hash), end = classes_.end();
- it != end && it->first == hash; ++it) {
- mirror::Class* klass = it->second;
- kh.ChangeClass(klass);
- if (strcmp(kh.GetDescriptor(), descriptor) == 0 && klass->GetClassLoader() == class_loader) {
- image_classes_.erase(it);
+ class_table_.erase(it);
return true;
}
}
@@ -2196,64 +2169,153 @@
mirror::Class* ClassLinker::LookupClass(const char* descriptor,
const mirror::ClassLoader* class_loader) {
size_t hash = Hash(descriptor);
- ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- // TODO: determine if its better to search classes_ or image_classes_ first
- mirror::Class* klass = NULL;
- // Use image class only if the class_loader is null.
- if (class_loader == NULL) {
- klass = LookupClassLocked(descriptor, class_loader, hash, image_classes_);
+ {
+ ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ mirror::Class* result = LookupClassFromTableLocked(descriptor, class_loader, hash);
+ if (result != NULL) {
+ return result;
+ }
}
- if (klass != NULL) {
- return klass;
+ if (class_loader != NULL || !dex_cache_image_class_lookup_required_) {
+ return NULL;
+ } else {
+ // Lookup failed but need to search dex_caches_.
+ mirror::Class* result = LookupClassFromImage(descriptor);
+ if (result != NULL) {
+ InsertClass(descriptor, result, hash);
+ } else {
+ // Searching the image dex files/caches failed, we don't want to get into this situation
+ // often as map searches are faster, so after kMaxFailedDexCacheLookups move all image
+ // classes into the class table.
+ const int32_t kMaxFailedDexCacheLookups = 1000;
+ if (++failed_dex_cache_class_lookups_ > kMaxFailedDexCacheLookups) {
+ MoveImageClassesToClassTable();
+ }
+ }
+ return result;
}
- return LookupClassLocked(descriptor, class_loader, hash, classes_);
}
-mirror::Class* ClassLinker::LookupClassLocked(const char* descriptor,
- const mirror::ClassLoader* class_loader,
- size_t hash, const Table& classes) {
+mirror::Class* ClassLinker::LookupClassFromTableLocked(const char* descriptor,
+ const mirror::ClassLoader* class_loader,
+ size_t hash) {
ClassHelper kh(NULL, this);
- auto end = classes_.end();
- for (auto it = classes.lower_bound(hash); it != end && it->first == hash;
- ++it) {
+ auto end = class_table_.end();
+ for (auto it = class_table_.lower_bound(hash); it != end && it->first == hash; ++it) {
mirror::Class* klass = it->second;
kh.ChangeClass(klass);
- if (strcmp(descriptor, kh.GetDescriptor()) == 0 && klass->GetClassLoader() == class_loader) {
-#ifndef NDEBUG
- for (++it; it != end && it->first == hash; ++it) {
- mirror::Class* klass2 = it->second;
- kh.ChangeClass(klass2);
- CHECK(!(strcmp(descriptor, kh.GetDescriptor()) == 0 && klass2->GetClassLoader() == class_loader))
- << PrettyClass(klass) << " " << klass << " " << klass->GetClassLoader() << " "
- << PrettyClass(klass2) << " " << klass2 << " " << klass2->GetClassLoader();
+ if (klass->GetClassLoader() == class_loader && strcmp(descriptor, kh.GetDescriptor()) == 0) {
+ if (kIsDebugBuild) {
+ // Check for duplicates in the table.
+ for (++it; it != end && it->first == hash; ++it) {
+ mirror::Class* klass2 = it->second;
+ kh.ChangeClass(klass2);
+ CHECK(!(strcmp(descriptor, kh.GetDescriptor()) == 0 && klass2->GetClassLoader() == class_loader))
+ << PrettyClass(klass) << " " << klass << " " << klass->GetClassLoader() << " "
+ << PrettyClass(klass2) << " " << klass2 << " " << klass2->GetClassLoader();
+ }
}
-#endif
return klass;
}
}
return NULL;
}
-void ClassLinker::LookupClasses(const char* descriptor, std::vector<mirror::Class*>& classes) {
- classes.clear();
- size_t hash = Hash(descriptor);
- ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- // TODO: determine if its better to search classes_ or image_classes_ first
+static mirror::ObjectArray<mirror::DexCache>* GetImageDexCaches()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ gc::space::ImageSpace* image = Runtime::Current()->GetHeap()->GetImageSpace();
+ CHECK(image != NULL);
+ mirror::Object* root = image->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
+ return root->AsObjectArray<mirror::DexCache>();
+}
+
+void ClassLinker::MoveImageClassesToClassTable() {
+ Thread* self = Thread::Current();
+ WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
+ if (!dex_cache_image_class_lookup_required_) {
+ return; // All dex cache classes are already in the class table.
+ }
+ const char* old_no_suspend_cause =
+ self->StartAssertNoThreadSuspension("Moving image classes to class table");
+ mirror::ObjectArray<mirror::DexCache>* dex_caches = GetImageDexCaches();
ClassHelper kh(NULL, this);
- for (auto it = classes_.lower_bound(hash), end = classes_.end(); it != end && it->first == hash;
- ++it) {
- mirror::Class* klass = it->second;
- kh.ChangeClass(klass);
- if (strcmp(descriptor, kh.GetDescriptor()) == 0) {
- classes.push_back(klass);
+ for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
+ mirror::DexCache* dex_cache = dex_caches->Get(i);
+ mirror::ObjectArray<mirror::Class>* types = dex_cache->GetResolvedTypes();
+ for (int32_t j = 0; j < types->GetLength(); j++) {
+ mirror::Class* klass = types->Get(j);
+ if (klass != NULL) {
+ kh.ChangeClass(klass);
+ DCHECK(klass->GetClassLoader() == NULL);
+ const char* descriptor = kh.GetDescriptor();
+ size_t hash = Hash(descriptor);
+ mirror::Class* existing = LookupClassFromTableLocked(descriptor, NULL, hash);
+ if (existing != NULL) {
+ CHECK(existing == klass) << PrettyClassAndClassLoader(existing) << " != "
+ << PrettyClassAndClassLoader(klass);
+ } else {
+ class_table_.insert(std::make_pair(hash, klass));
+ }
+ }
}
}
- for (auto it = image_classes_.lower_bound(hash), end = classes_.end();
+ Dirty();
+ dex_cache_image_class_lookup_required_ = false;
+ self->EndAssertNoThreadSuspension(old_no_suspend_cause);
+}
+
+mirror::Class* ClassLinker::LookupClassFromImage(const char* descriptor) {
+ Thread* self = Thread::Current();
+ const char* old_no_suspend_cause =
+ self->StartAssertNoThreadSuspension("Image class lookup");
+ mirror::ObjectArray<mirror::DexCache>* dex_caches = GetImageDexCaches();
+ for (int32_t i = 0; i < dex_caches->GetLength(); ++i) {
+ mirror::DexCache* dex_cache = dex_caches->Get(i);
+ const DexFile* dex_file = dex_cache->GetDexFile();
+ // First search using the class def map, but don't bother for non-class types.
+ if (descriptor[0] == 'L') {
+ const DexFile::ClassDef* class_def = dex_file->FindClassDef(descriptor);
+ if (class_def != NULL) {
+ mirror::Class* klass = dex_cache->GetResolvedType(class_def->class_idx_);
+ if (klass != NULL) {
+ self->EndAssertNoThreadSuspension(old_no_suspend_cause);
+ return klass;
+ }
+ }
+ }
+ // Now try binary searching the string/type index.
+ const DexFile::StringId* string_id = dex_file->FindStringId(descriptor);
+ if (string_id != NULL) {
+ const DexFile::TypeId* type_id =
+ dex_file->FindTypeId(dex_file->GetIndexForStringId(*string_id));
+ if (type_id != NULL) {
+ uint16_t type_idx = dex_file->GetIndexForTypeId(*type_id);
+ mirror::Class* klass = dex_cache->GetResolvedType(type_idx);
+ if (klass != NULL) {
+ self->EndAssertNoThreadSuspension(old_no_suspend_cause);
+ return klass;
+ }
+ }
+ }
+ }
+ self->EndAssertNoThreadSuspension(old_no_suspend_cause);
+ return NULL;
+}
+
+void ClassLinker::LookupClasses(const char* descriptor, std::vector<mirror::Class*>& result) {
+ result.clear();
+ if (dex_cache_image_class_lookup_required_) {
+ MoveImageClassesToClassTable();
+ }
+ size_t hash = Hash(descriptor);
+ ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ ClassHelper kh(NULL, this);
+ for (auto it = class_table_.lower_bound(hash), end = class_table_.end();
it != end && it->first == hash; ++it) {
mirror::Class* klass = it->second;
kh.ChangeClass(klass);
if (strcmp(descriptor, kh.GetDescriptor()) == 0) {
- classes.push_back(klass);
+ result.push_back(klass);
}
}
}
@@ -2277,12 +2339,12 @@
}
if (klass->GetStatus() == mirror::Class::kStatusResolved) {
- klass->SetStatus(mirror::Class::kStatusVerifying);
+ klass->SetStatus(mirror::Class::kStatusVerifying, self);
} else {
CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime)
<< PrettyClass(klass);
CHECK(!Runtime::Current()->IsCompiler());
- klass->SetStatus(mirror::Class::kStatusVerifyingAtRuntime);
+ klass->SetStatus(mirror::Class::kStatusVerifyingAtRuntime, self);
}
// Verify super class.
@@ -2307,7 +2369,7 @@
if (cause.get() != NULL) {
self->GetException(NULL)->SetCause(cause.get());
}
- klass->SetStatus(mirror::Class::kStatusError);
+ klass->SetStatus(mirror::Class::kStatusError, self);
return;
}
}
@@ -2322,7 +2384,7 @@
<< klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
ThrowVerifyError(klass, "Rejecting class %s because it failed compile-time verification",
PrettyDescriptor(klass).c_str());
- klass->SetStatus(mirror::Class::kStatusError);
+ klass->SetStatus(mirror::Class::kStatusError, self);
return;
}
verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
@@ -2344,10 +2406,10 @@
// Even though there were no verifier failures we need to respect whether the super-class
// was verified or requiring runtime reverification.
if (super.get() == NULL || super->IsVerified()) {
- klass->SetStatus(mirror::Class::kStatusVerified);
+ klass->SetStatus(mirror::Class::kStatusVerified, self);
} else {
CHECK_EQ(super->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
- klass->SetStatus(mirror::Class::kStatusRetryVerificationAtRuntime);
+ klass->SetStatus(mirror::Class::kStatusRetryVerificationAtRuntime, self);
// Pretend a soft failure occured so that we don't consider the class verified below.
verifier_failure = verifier::MethodVerifier::kSoftFailure;
}
@@ -2357,9 +2419,9 @@
// failures at runtime will be handled by slow paths in the generated
// code. Set status accordingly.
if (Runtime::Current()->IsCompiler()) {
- klass->SetStatus(mirror::Class::kStatusRetryVerificationAtRuntime);
+ klass->SetStatus(mirror::Class::kStatusRetryVerificationAtRuntime, self);
} else {
- klass->SetStatus(mirror::Class::kStatusVerified);
+ klass->SetStatus(mirror::Class::kStatusVerified, self);
}
}
} else {
@@ -2368,7 +2430,7 @@
<< " because: " << error_msg;
self->AssertNoPendingException();
ThrowVerifyError(klass, "%s", error_msg.c_str());
- klass->SetStatus(mirror::Class::kStatusError);
+ klass->SetStatus(mirror::Class::kStatusError, self);
}
if (preverified || verifier_failure == verifier::MethodVerifier::kNoFailure) {
// Class is verified so we don't need to do any access check on its methods.
@@ -2522,7 +2584,7 @@
mirror::Class* proxy_class = GetClassRoot(kJavaLangReflectProxy);
klass->SetDexCache(proxy_class->GetDexCache());
- klass->SetStatus(mirror::Class::kStatusIdx);
+ klass->SetStatus(mirror::Class::kStatusIdx, self);
klass->SetDexTypeIndex(DexFile::kDexNoIndex16);
@@ -2555,19 +2617,20 @@
}
klass->SetSuperClass(proxy_class); // The super class is java.lang.reflect.Proxy
- klass->SetStatus(mirror::Class::kStatusLoaded); // Class is now effectively in the loaded state
+ klass->SetStatus(mirror::Class::kStatusLoaded, self); // Class is now effectively in the loaded state
self->AssertNoPendingException();
- // Link the fields and virtual methods, creating vtable and iftables
- if (!LinkClass(klass, interfaces)) {
- klass->SetStatus(mirror::Class::kStatusError);
- return NULL;
- }
{
- ObjectLock lock(self, klass.get()); // Must hold lock on object when initializing.
+ ObjectLock lock(self, klass.get()); // Must hold lock on object when resolved.
+ // Link the fields and virtual methods, creating vtable and iftables
+ if (!LinkClass(klass, interfaces, self)) {
+ klass->SetStatus(mirror::Class::kStatusError, self);
+ return NULL;
+ }
+
interfaces_sfield->SetObject(klass.get(), interfaces);
throws_sfield->SetObject(klass.get(), throws);
- klass->SetStatus(mirror::Class::kStatusInitialized);
+ klass->SetStatus(mirror::Class::kStatusInitialized, self);
}
// sanity checks
@@ -2806,7 +2869,7 @@
}
if (!ValidateSuperClassDescriptors(klass)) {
- klass->SetStatus(mirror::Class::kStatusError);
+ klass->SetStatus(mirror::Class::kStatusError, self);
return false;
}
@@ -2815,7 +2878,7 @@
// From here out other threads may observe that we're initializing and so changes of state
// require the a notification.
klass->SetClinitThreadId(self->GetTid());
- klass->SetStatus(mirror::Class::kStatusInitializing);
+ klass->SetStatus(mirror::Class::kStatusInitializing, self);
t0 = NanoTime();
}
@@ -2837,8 +2900,7 @@
<< (self->GetException(NULL) != NULL ? self->GetException(NULL)->Dump() : "");
ObjectLock lock(self, klass);
// Initialization failed because the super-class is erroneous.
- klass->SetStatus(mirror::Class::kStatusError);
- lock.NotifyAll();
+ klass->SetStatus(mirror::Class::kStatusError, self);
return false;
}
}
@@ -2884,7 +2946,7 @@
if (self->IsExceptionPending()) {
WrapExceptionInInitializer();
- klass->SetStatus(mirror::Class::kStatusError);
+ klass->SetStatus(mirror::Class::kStatusError, self);
success = false;
} else {
RuntimeStats* global_stats = Runtime::Current()->GetStats();
@@ -2894,13 +2956,12 @@
global_stats->class_init_time_ns += (t1 - t0);
thread_stats->class_init_time_ns += (t1 - t0);
// Set the class as initialized except if failed to initialize static fields.
- klass->SetStatus(mirror::Class::kStatusInitialized);
+ klass->SetStatus(mirror::Class::kStatusInitialized, self);
if (VLOG_IS_ON(class_linker)) {
ClassHelper kh(klass);
LOG(INFO) << "Initialized class " << kh.GetDescriptor() << " from " << kh.GetLocation();
}
}
- lock.NotifyAll();
}
return success;
}
@@ -2917,7 +2978,7 @@
// "interruptShouldThrow" was set), bail out.
if (self->IsExceptionPending()) {
WrapExceptionInInitializer();
- klass->SetStatus(mirror::Class::kStatusError);
+ klass->SetStatus(mirror::Class::kStatusError, self);
return false;
}
// Spurious wakeup? Go back to waiting.
@@ -3061,7 +3122,7 @@
}
bool ClassLinker::LinkClass(SirtRef<mirror::Class>& klass,
- mirror::ObjectArray<mirror::Class>* interfaces) {
+ mirror::ObjectArray<mirror::Class>* interfaces, Thread* self) {
CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
if (!LinkSuperClass(klass)) {
return false;
@@ -3078,7 +3139,7 @@
CreateReferenceInstanceOffsets(klass);
CreateReferenceStaticOffsets(klass);
CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
- klass->SetStatus(mirror::Class::kStatusResolved);
+ klass->SetStatus(mirror::Class::kStatusResolved, self);
return true;
}
@@ -3123,7 +3184,7 @@
}
}
// Mark the class as loaded.
- klass->SetStatus(mirror::Class::kStatusLoaded);
+ klass->SetStatus(mirror::Class::kStatusLoaded, NULL);
return true;
}
@@ -3175,13 +3236,13 @@
return false;
}
-#ifndef NDEBUG
- // Ensure super classes are fully resolved prior to resolving fields..
- while (super != NULL) {
- CHECK(super->IsResolved());
- super = super->GetSuperClass();
+ if (kIsDebugBuild) {
+ // Ensure super classes are fully resolved prior to resolving fields..
+ while (super != NULL) {
+ CHECK(super->IsResolved());
+ super = super->GetSuperClass();
+ }
}
-#endif
return true;
}
@@ -3992,16 +4053,16 @@
return dex_file.GetMethodShorty(method_id, length);
}
-void ClassLinker::DumpAllClasses(int flags) const {
+void ClassLinker::DumpAllClasses(int flags) {
+ if (dex_cache_image_class_lookup_required_) {
+ MoveImageClassesToClassTable();
+ }
// TODO: at the time this was written, it wasn't safe to call PrettyField with the ClassLinker
// lock held, because it might need to resolve a field's type, which would try to take the lock.
std::vector<mirror::Class*> all_classes;
{
ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- for (const std::pair<size_t, mirror::Class*>& it : classes_) {
- all_classes.push_back(it.second);
- }
- for (const std::pair<size_t, mirror::Class*>& it : image_classes_) {
+ for (const std::pair<size_t, mirror::Class*>& it : class_table_) {
all_classes.push_back(it.second);
}
}
@@ -4011,15 +4072,20 @@
}
}
-void ClassLinker::DumpForSigQuit(std::ostream& os) const {
+void ClassLinker::DumpForSigQuit(std::ostream& os) {
+ if (dex_cache_image_class_lookup_required_) {
+ MoveImageClassesToClassTable();
+ }
ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- os << "Loaded classes: " << image_classes_.size() << " image classes; "
- << classes_.size() << " allocated classes\n";
+ os << "Loaded classes: " << class_table_.size() << " allocated classes\n";
}
-size_t ClassLinker::NumLoadedClasses() const {
+size_t ClassLinker::NumLoadedClasses() {
+ if (dex_cache_image_class_lookup_required_) {
+ MoveImageClassesToClassTable();
+ }
ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- return classes_.size() + image_classes_.size();
+ return class_table_.size();
}
pid_t ClassLinker::GetClassesLockOwner() {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 5ef6d8f..c5fb72c 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -73,7 +73,7 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Define a new a class based on a ClassDef from a DexFile
- mirror::Class* DefineClass(const StringPiece& descriptor, mirror::ClassLoader* class_loader,
+ mirror::Class* DefineClass(const char* descriptor, mirror::ClassLoader* class_loader,
const DexFile& dex_file, const DexFile::ClassDef& dex_class_def)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -96,14 +96,17 @@
LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void DumpAllClasses(int flags) const
+ void DumpAllClasses(int flags)
LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void DumpForSigQuit(std::ostream& os) const
- LOCKS_EXCLUDED(Locks::classlinker_classes_lock_);
+ void DumpForSigQuit(std::ostream& os)
+ LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- size_t NumLoadedClasses() const LOCKS_EXCLUDED(Locks::classlinker_classes_lock_);
+ size_t NumLoadedClasses()
+ LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Resolve a String with the given index from the DexFile, storing the
// result in the DexCache. The referrer is used to identify the
@@ -219,12 +222,14 @@
return boot_class_path_;
}
- void VisitClasses(ClassVisitor* visitor, void* arg) const
- LOCKS_EXCLUDED(Locks::classlinker_classes_lock_);
+ void VisitClasses(ClassVisitor* visitor, void* arg)
+ LOCKS_EXCLUDED(dex_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Less efficient variant of VisitClasses that doesn't hold the classlinker_classes_lock_
// when calling the visitor.
- void VisitClassesWithoutClassesLock(ClassVisitor* visitor, void* arg) const
- LOCKS_EXCLUDED(Locks::classlinker_classes_lock_);
+ void VisitClassesWithoutClassesLock(ClassVisitor* visitor, void* arg)
+ LOCKS_EXCLUDED(dex_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty)
LOCKS_EXCLUDED(Locks::classlinker_classes_lock_, dex_lock_);
@@ -353,7 +358,7 @@
// Attempts to insert a class into a class table. Returns NULL if
// the class was inserted, otherwise returns an existing class with
// the same descriptor and ClassLoader.
- mirror::Class* InsertClass(const StringPiece& descriptor, mirror::Class* klass, bool image_class)
+ mirror::Class* InsertClass(const char* descriptor, mirror::Class* klass, size_t hash)
LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -394,7 +399,7 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- mirror::Class* CreateArrayClass(const std::string& descriptor, mirror::ClassLoader* class_loader)
+ mirror::Class* CreateArrayClass(const char* descriptor, mirror::ClassLoader* class_loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void AppendToBootClassPath(const DexFile& dex_file)
@@ -453,7 +458,8 @@
const mirror::Class* klass2)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkClass(SirtRef<mirror::Class>& klass, mirror::ObjectArray<mirror::Class>* interfaces)
+ bool LinkClass(SirtRef<mirror::Class>& klass, mirror::ObjectArray<mirror::Class>* interfaces,
+ Thread* self)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool LinkSuperClass(SirtRef<mirror::Class>& klass)
@@ -530,12 +536,23 @@
// mirror::Class* instances. Results should be compared for a matching
// Class::descriptor_ and Class::class_loader_.
typedef std::multimap<size_t, mirror::Class*> Table;
- Table image_classes_ GUARDED_BY(Locks::classlinker_classes_lock_);
- Table classes_ GUARDED_BY(Locks::classlinker_classes_lock_);
+ Table class_table_ GUARDED_BY(Locks::classlinker_classes_lock_);
- mirror::Class* LookupClassLocked(const char* descriptor, const mirror::ClassLoader* class_loader,
- size_t hash, const Table& classes)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::classlinker_classes_lock_);
+ // Do we need to search dex caches to find image classes?
+ bool dex_cache_image_class_lookup_required_;
+ // Number of times we've searched dex caches for a class. After a certain number of misses we move
+ // the classes into the class_table_ to avoid dex cache based searches.
+ AtomicInteger failed_dex_cache_class_lookups_;
+
+ mirror::Class* LookupClassFromTableLocked(const char* descriptor,
+ const mirror::ClassLoader* class_loader,
+ size_t hash)
+ SHARED_LOCKS_REQUIRED(Locks::classlinker_classes_lock_, Locks::mutator_lock_);
+
+ void MoveImageClassesToClassTable() LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ mirror::Class* LookupClassFromImage(const char* descriptor)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// indexes into class_roots_.
// needs to be kept in sync with class_roots_descriptors_.
diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc
index 09fa19e..6e8736a 100644
--- a/runtime/dex_instruction.cc
+++ b/runtime/dex_instruction.cc
@@ -529,7 +529,20 @@
case k30t: os << StringPrintf("%s %+d", opcode, VRegA_30t()); break;
case k31t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_31t(), VRegB_31t()); break;
case k31i: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_31i(), VRegB_31i()); break;
- case k31c: os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_31c(), VRegB_31c()); break;
+ case k31c:
+ if (Opcode() == CONST_STRING_JUMBO) {
+ uint32_t string_idx = VRegB_31c();
+ if (file != NULL) {
+ os << StringPrintf("%s v%d, %s // string@%d", opcode, VRegA_31c(),
+ PrintableString(file->StringDataByIdx(string_idx)).c_str(),
+ string_idx);
+ } else {
+ os << StringPrintf("%s v%d, string@%d", opcode, VRegA_31c(), string_idx);
+ }
+ } else {
+ os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_31c(), VRegB_31c()); break;
+ }
+ break;
case k35c: {
uint32_t arg[5];
GetArgs(arg);
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index d7398ca..e3a75cf 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -16,6 +16,10 @@
#include "intern_table.h"
+#include "gc/space/image_space.h"
+#include "mirror/dex_cache.h"
+#include "mirror/object_array-inl.h"
+#include "mirror/object-inl.h"
#include "mirror/string.h"
#include "thread.h"
#include "UniquePtr.h"
@@ -23,8 +27,8 @@
namespace art {
-InternTable::InternTable() : intern_table_lock_("InternTable lock"), is_dirty_(false) {
-}
+InternTable::InternTable()
+ : intern_table_lock_("InternTable lock"), is_dirty_(false) {}
size_t InternTable::Size() const {
MutexLock mu(Thread::Current(), intern_table_lock_);
@@ -34,11 +38,11 @@
void InternTable::DumpForSigQuit(std::ostream& os) const {
MutexLock mu(Thread::Current(), intern_table_lock_);
os << "Intern table: " << strong_interns_.size() << " strong; "
- << weak_interns_.size() << " weak; "
- << image_strong_interns_.size() << " image strong\n";
+ << weak_interns_.size() << " weak\n";
}
-void InternTable::VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty) {
+void InternTable::VisitRoots(RootVisitor* visitor, void* arg,
+ bool clean_dirty) {
MutexLock mu(Thread::Current(), intern_table_lock_);
for (const auto& strong_intern : strong_interns_) {
visitor(strong_intern.second, arg);
@@ -46,10 +50,12 @@
if (clean_dirty) {
is_dirty_ = false;
}
- // Note: we deliberately don't visit the weak_interns_ table and the immutable image roots.
+ // Note: we deliberately don't visit the weak_interns_ table and the immutable
+ // image roots.
}
-mirror::String* InternTable::Lookup(Table& table, mirror::String* s, uint32_t hash_code) {
+mirror::String* InternTable::Lookup(Table& table, mirror::String* s,
+ uint32_t hash_code) {
intern_table_lock_.AssertHeld(Thread::Current());
for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) {
mirror::String* existing_string = it->second;
@@ -60,18 +66,15 @@
return NULL;
}
-mirror::String* InternTable::Insert(Table& table, mirror::String* s, uint32_t hash_code) {
+mirror::String* InternTable::Insert(Table& table, mirror::String* s,
+ uint32_t hash_code) {
intern_table_lock_.AssertHeld(Thread::Current());
table.insert(std::make_pair(hash_code, s));
return s;
}
-void InternTable::RegisterStrong(mirror::String* s) {
- MutexLock mu(Thread::Current(), intern_table_lock_);
- Insert(image_strong_interns_, s, s->GetHashCode());
-}
-
-void InternTable::Remove(Table& table, const mirror::String* s, uint32_t hash_code) {
+void InternTable::Remove(Table& table, const mirror::String* s,
+ uint32_t hash_code) {
intern_table_lock_.AssertHeld(Thread::Current());
for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) {
if (it->second == s) {
@@ -81,6 +84,31 @@
}
}
+static mirror::String* LookupStringFromImage(mirror::String* s)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ gc::space::ImageSpace* image = Runtime::Current()->GetHeap()->GetImageSpace();
+ if (image == NULL) {
+ return NULL; // No image present.
+ }
+ mirror::Object* root = image->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
+ mirror::ObjectArray<mirror::DexCache>* dex_caches = root->AsObjectArray<mirror::DexCache>();
+ const std::string utf8 = s->ToModifiedUtf8();
+ for (int32_t i = 0; i < dex_caches->GetLength(); ++i) {
+ mirror::DexCache* dex_cache = dex_caches->Get(i);
+ const DexFile* dex_file = dex_cache->GetDexFile();
+ // Binary search the dex file for the string index.
+ const DexFile::StringId* string_id = dex_file->FindStringId(utf8.c_str());
+ if (string_id != NULL) {
+ uint32_t string_idx = dex_file->GetIndexForStringId(*string_id);
+ mirror::String* image = dex_cache->GetResolvedString(string_idx);
+ if (image != NULL) {
+ return image;
+ }
+ }
+ }
+ return NULL;
+}
+
mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) {
MutexLock mu(Thread::Current(), intern_table_lock_);
@@ -93,15 +121,16 @@
if (strong != NULL) {
return strong;
}
- // Check the image table for a match.
- mirror::String* image = Lookup(image_strong_interns_, s, hash_code);
- if (image != NULL) {
- return image;
- }
// Mark as dirty so that we rescan the roots.
Dirty();
+ // Check the image for a match.
+ mirror::String* image = LookupStringFromImage(s);
+ if (image != NULL) {
+ return Insert(strong_interns_, image, hash_code);
+ }
+
// There is no match in the strong table, check the weak table.
mirror::String* weak = Lookup(weak_interns_, s, hash_code);
if (weak != NULL) {
@@ -110,7 +139,8 @@
return Insert(strong_interns_, weak, hash_code);
}
- // No match in the strong table or the weak table. Insert into the strong table.
+ // No match in the strong table or the weak table. Insert into the strong
+ // table.
return Insert(strong_interns_, s, hash_code);
}
@@ -119,10 +149,10 @@
if (strong != NULL) {
return strong;
}
- // Check the image table for a match.
- mirror::String* image = Lookup(image_strong_interns_, s, hash_code);
+ // Check the image for a match.
+ mirror::String* image = LookupStringFromImage(s);
if (image != NULL) {
- return image;
+ return Insert(weak_interns_, image, hash_code);
}
// Check the weak table for a match.
mirror::String* weak = Lookup(weak_interns_, s, hash_code);
@@ -133,12 +163,15 @@
return Insert(weak_interns_, s, hash_code);
}
-mirror::String* InternTable::InternStrong(int32_t utf16_length, const char* utf8_data) {
- return InternStrong(mirror::String::AllocFromModifiedUtf8(Thread::Current(), utf16_length, utf8_data));
+mirror::String* InternTable::InternStrong(int32_t utf16_length,
+ const char* utf8_data) {
+ return InternStrong(mirror::String::AllocFromModifiedUtf8(
+ Thread::Current(), utf16_length, utf8_data));
}
mirror::String* InternTable::InternStrong(const char* utf8_data) {
- return InternStrong(mirror::String::AllocFromModifiedUtf8(Thread::Current(), utf8_data));
+ return InternStrong(
+ mirror::String::AllocFromModifiedUtf8(Thread::Current(), utf8_data));
}
mirror::String* InternTable::InternStrong(mirror::String* s) {
diff --git a/runtime/intern_table.h b/runtime/intern_table.h
index 5031ce3..a804d1f 100644
--- a/runtime/intern_table.h
+++ b/runtime/intern_table.h
@@ -55,10 +55,6 @@
// Interns a potentially new string in the 'weak' table. (See above.)
mirror::String* InternWeak(mirror::String* s) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Register a String trusting that it is safe to intern.
- // Used when reinitializing InternTable from an image.
- void RegisterStrong(mirror::String* s) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
void SweepInternTableWeaks(IsMarkedTester is_marked, void* arg)
SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
@@ -88,7 +84,6 @@
mutable Mutex intern_table_lock_;
bool is_dirty_;
- Table image_strong_interns_ GUARDED_BY(intern_table_lock_);
Table strong_interns_ GUARDED_BY(intern_table_lock_);
Table weak_interns_ GUARDED_BY(intern_table_lock_);
};
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 19e134f..5e8b827 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -50,24 +50,26 @@
java_lang_Class_ = NULL;
}
-void Class::SetStatus(Status new_status) {
- if (UNLIKELY(new_status <= GetStatus() && new_status != kStatusError)) {
- bool class_linker_initialized = Runtime::Current()->GetClassLinker() != nullptr;
- if (class_linker_initialized) {
+void Class::SetStatus(Status new_status, Thread* self) {
+ Status old_status = GetStatus();
+ bool class_linker_initialized = Runtime::Current()->GetClassLinker() != nullptr;
+ if (LIKELY(class_linker_initialized)) {
+ if (UNLIKELY(new_status <= old_status && new_status != kStatusError)) {
LOG(FATAL) << "Unexpected change back of class status for " << PrettyClass(this) << " "
- << GetStatus() << " -> " << new_status;
+ << old_status << " -> " << new_status;
}
- }
- if (new_status > kStatusResolved) {
- CHECK_EQ(GetThinLockId(), Thread::Current()->GetThinLockId())
- << "Attempt to change status of class while not holding its lock " << PrettyClass(this);
+ if (new_status >= kStatusResolved || old_status >= kStatusResolved) {
+ // When classes are being resolved the resolution code should hold the lock.
+ CHECK_EQ(GetThinLockId(), self->GetThinLockId())
+ << "Attempt to change status of class while not holding its lock: "
+ << PrettyClass(this) << " " << old_status << " -> " << new_status;
+ }
}
if (new_status == kStatusError) {
CHECK_NE(GetStatus(), kStatusError)
<< "Attempt to set as erroneous an already erroneous class " << PrettyClass(this);
// Stash current exception.
- Thread* self = Thread::Current();
SirtRef<mirror::Object> old_throw_this_object(self, NULL);
SirtRef<mirror::ArtMethod> old_throw_method(self, NULL);
SirtRef<mirror::Throwable> old_exception(self, NULL);
@@ -103,7 +105,13 @@
self->SetException(gc_safe_throw_location, old_exception.get());
}
CHECK(sizeof(Status) == sizeof(uint32_t)) << PrettyClass(this);
- return SetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status, false);
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status, false);
+ // Classes that are being resolved or initialized need to notify waiters that the class status
+ // changed. See ClassLinker::EnsureResolved and ClassLinker::WaitForInitializeClass.
+ if ((old_status >= kStatusResolved || new_status >= kStatusResolved) &&
+ class_linker_initialized) {
+ NotifyAll(self);
+ }
}
void Class::SetDexCache(DexCache* new_dex_cache) {
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 638b67f..99f3850 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -125,10 +125,10 @@
Status GetStatus() const {
DCHECK_EQ(sizeof(Status), sizeof(uint32_t));
- return static_cast<Status>(GetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), false));
+ return static_cast<Status>(GetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), true));
}
- void SetStatus(Status new_status) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void SetStatus(Status new_status, Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Returns true if the class has failed to link.
bool IsErroneous() const {
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index ff193c9..66c51e6 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -792,6 +792,8 @@
return;
}
// no-op; there are no waiters to notify.
+ // We inflate here in case the Notify is in a tight loop. Without inflation here the waiter
+ // will struggle to get in. Bug 6961405.
Inflate(self, obj);
} else {
// It's a fat lock.
@@ -811,6 +813,8 @@
return;
}
// no-op; there are no waiters to notify.
+ // We inflate here in case the NotifyAll is in a tight loop. Without inflation here the waiter
+ // will struggle to get in. Bug 6961405.
Inflate(self, obj);
} else {
// It's a fat lock.
@@ -948,6 +952,27 @@
}
}
+bool Monitor::IsValidLockWord(int32_t lock_word) {
+ if (lock_word == 0) {
+ return true;
+ } else if (LW_SHAPE(lock_word) == LW_SHAPE_FAT) {
+ Monitor* mon = LW_MONITOR(lock_word);
+ MonitorList* list = Runtime::Current()->GetMonitorList();
+ MutexLock mu(Thread::Current(), list->monitor_list_lock_);
+ bool found = false;
+ for (Monitor* list_mon : list->list_) {
+ if (mon == list_mon) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+ } else {
+ // TODO: thin lock validity checking.
+ return LW_SHAPE(lock_word) == LW_SHAPE_THIN;
+ }
+}
+
void Monitor::TranslateLocation(const mirror::ArtMethod* method, uint32_t dex_pc,
const char*& source_file, uint32_t& line_number) const {
// If method is null, location is unknown
diff --git a/runtime/monitor.h b/runtime/monitor.h
index 02c10a7..6651768 100644
--- a/runtime/monitor.h
+++ b/runtime/monitor.h
@@ -100,6 +100,8 @@
void* callback_context)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static bool IsValidLockWord(int32_t lock_word);
+
mirror::Object* GetObject();
private:
@@ -188,6 +190,7 @@
Mutex monitor_list_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
std::list<Monitor*> list_ GUARDED_BY(monitor_list_lock_);
+ friend class Monitor;
DISALLOW_COPY_AND_ASSIGN(MonitorList);
};
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 4ee3533..2f4e427 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -158,7 +158,8 @@
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
class_linker->RegisterDexFile(*dex_file);
mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(javaLoader);
- mirror::Class* result = class_linker->DefineClass(descriptor, class_loader, *dex_file, *dex_class_def);
+ mirror::Class* result = class_linker->DefineClass(descriptor.c_str(), class_loader, *dex_file,
+ *dex_class_def);
VLOG(class_linker) << "DexFile_defineClassNative returning " << result;
return soa.AddLocalReference<jclass>(result);
}
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index e3ec3bc..ae45701 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -37,6 +37,7 @@
std::vector<std::string> features;
features.push_back("method-trace-profiling");
features.push_back("method-trace-profiling-streaming");
+ features.push_back("method-sample-profiling");
features.push_back("hprof-heap-dump");
features.push_back("hprof-heap-dump-streaming");
return toStringArray(env, features);
@@ -58,8 +59,9 @@
Runtime::Current()->ResetStats(kinds);
}
-static void VMDebug_startMethodTracingDdmsImpl(JNIEnv*, jclass, jint bufferSize, jint flags) {
- Trace::Start("[DDMS]", -1, bufferSize, flags, true);
+static void VMDebug_startMethodTracingDdmsImpl(JNIEnv*, jclass, jint bufferSize, jint flags,
+ jboolean samplingEnabled, jint intervalUs) {
+ Trace::Start("[DDMS]", -1, bufferSize, flags, true, samplingEnabled, intervalUs);
}
static void VMDebug_startMethodTracingFd(JNIEnv* env, jclass, jstring javaTraceFilename,
@@ -82,7 +84,7 @@
if (traceFilename.c_str() == NULL) {
return;
}
- Trace::Start(traceFilename.c_str(), fd, bufferSize, flags, false);
+ Trace::Start(traceFilename.c_str(), fd, bufferSize, flags, false, false, 0);
}
static void VMDebug_startMethodTracingFilename(JNIEnv* env, jclass, jstring javaTraceFilename,
@@ -91,7 +93,7 @@
if (traceFilename.c_str() == NULL) {
return;
}
- Trace::Start(traceFilename.c_str(), -1, bufferSize, flags, false);
+ Trace::Start(traceFilename.c_str(), -1, bufferSize, flags, false, false, 0);
}
static jboolean VMDebug_isMethodTracingActive(JNIEnv*, jclass) {
@@ -151,7 +153,8 @@
return Runtime::Current()->GetClassLinker()->DumpAllClasses(flags);
}
-static jint VMDebug_getLoadedClassCount(JNIEnv*, jclass) {
+static jint VMDebug_getLoadedClassCount(JNIEnv* env, jclass) {
+ ScopedObjectAccess soa(env);
return Runtime::Current()->GetClassLinker()->NumLoadedClasses();
}
@@ -322,7 +325,7 @@
NATIVE_METHOD(VMDebug, startAllocCounting, "()V"),
NATIVE_METHOD(VMDebug, startEmulatorTracing, "()V"),
NATIVE_METHOD(VMDebug, startInstructionCounting, "()V"),
- NATIVE_METHOD(VMDebug, startMethodTracingDdmsImpl, "(II)V"),
+ NATIVE_METHOD(VMDebug, startMethodTracingDdmsImpl, "(IIZI)V"),
NATIVE_METHOD(VMDebug, startMethodTracingFd, "(Ljava/lang/String;Ljava/io/FileDescriptor;II)V"),
NATIVE_METHOD(VMDebug, startMethodTracingFilename, "(Ljava/lang/String;II)V"),
NATIVE_METHOD(VMDebug, stopAllocCounting, "()V"),
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 51a67c1..5679d4e 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -925,7 +925,8 @@
method_trace_file_size_ = options->method_trace_file_size_;
if (options->method_trace_) {
- Trace::Start(options->method_trace_file_.c_str(), -1, options->method_trace_file_size_, 0, false);
+ Trace::Start(options->method_trace_file_.c_str(), -1, options->method_trace_file_size_, 0,
+ false, false, 0);
}
VLOG(startup) << "Runtime::Init exiting";
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 4c092fd..6d040e1 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -122,9 +122,6 @@
#endif
Trace* volatile Trace::the_trace_ = NULL;
-// TODO: Add way to enable sampling and set interval through gui.
-bool Trace::sampling_enabled_ = true;
-uint32_t Trace::sampling_interval_us_ = 1000;
pthread_t Trace::sampling_pthread_ = 0U;
UniquePtr<std::vector<mirror::ArtMethod*> > Trace::temp_stack_trace_;
@@ -301,11 +298,12 @@
void* Trace::RunSamplingThread(void* arg) {
Runtime* runtime = Runtime::Current();
+ int interval_us = reinterpret_cast<int>(arg);
CHECK(runtime->AttachCurrentThread("Sampling Profiler", true, runtime->GetSystemThreadGroup(),
!runtime->IsCompiler()));
while (true) {
- usleep(sampling_interval_us_);
+ usleep(interval_us);
ATRACE_BEGIN("Profile sampling");
Thread* self = Thread::Current();
Trace* the_trace;
@@ -331,7 +329,7 @@
}
void Trace::Start(const char* trace_filename, int trace_fd, int buffer_size, int flags,
- bool direct_to_ddms) {
+ bool direct_to_ddms, bool sampling_enabled, int interval_us) {
Thread* self = Thread::Current();
{
MutexLock mu(self, *Locks::trace_lock_);
@@ -367,16 +365,19 @@
if (the_trace_ != NULL) {
LOG(ERROR) << "Trace already in progress, ignoring this request";
} else {
- the_trace_ = new Trace(trace_file.release(), buffer_size, flags);
+ the_trace_ = new Trace(trace_file.release(), buffer_size, flags, sampling_enabled);
// Enable count of allocs if specified in the flags.
if ((flags && kTraceCountAllocs) != 0) {
runtime->SetStatsEnabled(true);
}
- if (sampling_enabled_) {
- CHECK_PTHREAD_CALL(pthread_create, (&sampling_pthread_, NULL, &RunSamplingThread, NULL),
- "Sampling profiler thread");
+
+
+ if (sampling_enabled) {
+ CHECK_PTHREAD_CALL(pthread_create, (&sampling_pthread_, NULL, &RunSamplingThread,
+ reinterpret_cast<void*>(interval_us)),
+ "Sampling profiler thread");
} else {
runtime->GetInstrumentation()->AddListener(the_trace_,
instrumentation::Instrumentation::kMethodEntered |
@@ -407,7 +408,7 @@
if (the_trace != NULL) {
the_trace->FinishTracing();
- if (sampling_enabled_) {
+ if (the_trace->sampling_enabled_) {
MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
runtime->GetThreadList()->ForEach(ClearThreadStackTraceAndClockBase, NULL);
} else {
@@ -420,7 +421,7 @@
}
runtime->GetThreadList()->ResumeAll();
- if (sampling_enabled_ && sampling_pthread != 0U) {
+ if (sampling_pthread != 0U) {
CHECK_PTHREAD_CALL(pthread_join, (sampling_pthread, NULL), "sampling thread shutdown");
}
}
@@ -436,10 +437,10 @@
return the_trace_ != NULL;
}
-Trace::Trace(File* trace_file, int buffer_size, int flags)
+Trace::Trace(File* trace_file, int buffer_size, int flags, bool sampling_enabled)
: trace_file_(trace_file), buf_(new uint8_t[buffer_size]()), flags_(flags),
- clock_source_(default_clock_source_), buffer_size_(buffer_size), start_time_(MicroTime()),
- cur_offset_(0), overflow_(false) {
+ sampling_enabled_(sampling_enabled), clock_source_(default_clock_source_),
+ buffer_size_(buffer_size), start_time_(MicroTime()), cur_offset_(0), overflow_(false) {
// Set up the beginning of the trace.
uint16_t trace_version = GetTraceVersion(clock_source_);
memset(buf_.get(), 0, kTraceHeaderLength);
@@ -456,10 +457,6 @@
cur_offset_ = kTraceHeaderLength;
}
-Trace::~Trace() {
- CHECK_EQ(sampling_pthread_, static_cast<pthread_t>(0U));
-}
-
static void DumpBuf(uint8_t* buf, size_t buf_size, ProfilerClockSource clock_source)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
uint8_t* ptr = buf + kTraceHeaderLength;
diff --git a/runtime/trace.h b/runtime/trace.h
index 6fc3790..06cb6a6 100644
--- a/runtime/trace.h
+++ b/runtime/trace.h
@@ -51,7 +51,7 @@
static void SetDefaultClockSource(ProfilerClockSource clock_source);
static void Start(const char* trace_filename, int trace_fd, int buffer_size, int flags,
- bool direct_to_ddms)
+ bool direct_to_ddms, bool sampling_enabled, int interval_us)
LOCKS_EXCLUDED(Locks::mutator_lock_,
Locks::thread_list_lock_,
Locks::thread_suspend_count_lock_,
@@ -88,11 +88,10 @@
// Clear and store an old stack trace for later use.
static void FreeStackTrace(std::vector<mirror::ArtMethod*>* stack_trace);
- ~Trace();
-
private:
- explicit Trace(File* trace_file, int buffer_size, int flags);
+ explicit Trace(File* trace_file, int buffer_size, int flags, bool sampling_enabled);
+ // The sampling interval in microseconds is passed as an argument.
static void* RunSamplingThread(void* arg) LOCKS_EXCLUDED(Locks::trace_lock_);
void FinishTracing() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -115,12 +114,6 @@
// The default profiler clock source.
static ProfilerClockSource default_clock_source_;
- // True if traceview should sample instead of instrumenting method entry/exit.
- static bool sampling_enabled_;
-
- // Sampling interval in microseconds.
- static uint32_t sampling_interval_us_;
-
// Sampling thread, non-zero when sampling.
static pthread_t sampling_pthread_;
@@ -136,6 +129,9 @@
// Flags enabling extra tracing of things such as alloc counts.
const int flags_;
+ // True if traceview should sample instead of instrumenting method entry/exit.
+ const bool sampling_enabled_;
+
const ProfilerClockSource clock_source_;
// Size of buf_.
diff --git a/test/016-intern/expected.txt b/test/016-intern/expected.txt
index 7d91963..0b7ac3d 100644
--- a/test/016-intern/expected.txt
+++ b/test/016-intern/expected.txt
@@ -1 +1,3 @@
good! foobar
+good! foo
+good! null
diff --git a/test/016-intern/src/Main.java b/test/016-intern/src/Main.java
index 4306863..01cbf18 100644
--- a/test/016-intern/src/Main.java
+++ b/test/016-intern/src/Main.java
@@ -20,15 +20,33 @@
public class Main {
public static void main(String args[]) {
String a, b;
- String foo = "foo";
- String bar = "bar";
+ final String foo = "foo";
+ final String bar = "bar";
+ // Two interned strings should match.
a = foo.concat(bar).intern();
b = foo.concat(bar).intern();
if (a == b && foo != bar) {
System.out.println("good! " + a);
} else {
- System.out.println("bad!");
+ System.out.println("bad! " + a + " != " + b);
+ }
+
+ // An interned string should match a string literal.
+ a = ("f" + foo.substring(1,3)).intern();
+ if (a == foo) {
+ System.out.println("good! " + a);
+ } else {
+ System.out.println("bad! " + a + " != " + b);
+ }
+
+ // Check that a string literal in libcore equals one in the app.
+ a = (new java.nio.charset.IllegalCharsetNameException(null)).getMessage();
+ b = "null";
+ if (a == b) {
+ System.out.println("good! " + a);
+ } else {
+ System.out.println("bad! " + a + " != " + b);
}
}
}