diff options
56 files changed, 935 insertions, 667 deletions
diff --git a/compiler/dex/arena_allocator.cc b/compiler/dex/arena_allocator.cc index 3a3e3858b3..36393e7387 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 @@ static const char* alloc_names[ArenaAllocator::kNumAllocKinds] = { "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_; - } - ArenaMemBlock *new_block = static_cast<ArenaMemBlock*>(malloc(allocation_size)); - if (new_block == NULL) { - LOG(FATAL) << "Arena allocation failure"; + madvise(Begin(), bytes_allocated_, MADV_DONTNEED); } - 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; + bytes_allocated_ = 0; + } +} + +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_; } - allocation_block = new_block; } - void* ptr = &allocation_block->ptr[allocation_block->bytes_allocated]; - allocation_block->bytes_allocated += size; - if (zero) { - memset(ptr, 0, size); + if (ret == nullptr) { + ret = new Arena(size); } - num_allocations_++; - return ptr; + ret->Reset(); + return ret; } -// Dump memory usage stats. -void ArenaAllocator::DumpMemStats(std::ostream& os) const { +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 e8e2c027d0..dda52a2ed0 100644 --- a/compiler/dex/arena_allocator.h +++ b/compiler/dex/arena_allocator.h @@ -19,64 +19,126 @@ #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 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 - }; - - explicit ArenaAllocator(size_t default_size = ARENA_DEFAULT_BLOCK_SIZE); + 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(); - void* NewMem(size_t size, bool zero, ArenaAllocKind kind); - size_t BytesAllocated() { - return malloc_bytes_; + + // 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]; - }; - - ArenaMemBlock* EmptyArenaBlock(); - - 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_; -}; // ArenaAllocator + private: + void UpdateBytesAllocated(); + + ArenaPool* pool_; + uint8_t* begin_; + uint8_t* end_; + uint8_t* ptr_; + Arena* arena_head_; + // 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: diff --git a/compiler/dex/arena_bit_vector.cc b/compiler/dex/arena_bit_vector.cc index 724fdf81c7..3fa9295276 100644 --- a/compiler/dex/arena_bit_vector.cc +++ b/compiler/dex/arena_bit_vector.cc @@ -35,8 +35,8 @@ ArenaBitVector::ArenaBitVector(ArenaAllocator* arena, unsigned int start_bits, 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 @@ void ArenaBitVector::SetBit(unsigned int num) { 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 4ec8c886ee..8bcd628dc0 100644 --- a/compiler/dex/arena_bit_vector.h +++ b/compiler/dex/arena_bit_vector.h @@ -67,8 +67,8 @@ class ArenaBitVector { } 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 @@ class ArenaBitVector { ~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 a9b5bf68fc..26d0923baa 100644 --- a/compiler/dex/compiler_ir.h +++ b/compiler/dex/compiler_ir.h @@ -43,7 +43,7 @@ class MIRGraph; class Mir2Lir; struct CompilationUnit { - CompilationUnit() + explicit CompilationUnit(ArenaPool* pool) : compiler_driver(NULL), class_linker(NULL), dex_file(NULL), @@ -66,6 +66,7 @@ struct CompilationUnit { 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 d1f7f3e2f4..23036495ce 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -119,30 +119,30 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, 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 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, 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 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, (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 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, } #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 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, 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 08a6478e97..8e2abfbaf1 100644 --- a/compiler/dex/growable_array.h +++ b/compiler/dex/growable_array.h @@ -67,7 +67,7 @@ class GrowableArray { } 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 @@ class GrowableArray { 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 @@ class GrowableArray { 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 @@ class GrowableArray { 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 c3a33ff7a8..3a73717a7b 100644 --- a/compiler/dex/mir_dataflow.cc +++ b/compiler/dex/mir_dataflow.cc @@ -954,11 +954,11 @@ void MIRGraph::DataFlowSSAFormat35C(MIR* mir) { 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 @@ void MIRGraph::DataFlowSSAFormat3RC(MIR* mir) { 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 @@ bool MIRGraph::DoSSAConversion(BasicBlock* bb) { 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 @@ bool MIRGraph::DoSSAConversion(BasicBlock* bb) { 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 @@ bool MIRGraph::DoSSAConversion(BasicBlock* bb) { 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 @@ bool MIRGraph::DoSSAConversion(BasicBlock* bb) { * 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 @@ void MIRGraph::CompilerInitializeSSAConversion() { * 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 @@ void MIRGraph::CompilerInitializeSSAConversion() { 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 86f6ee5cbd..81702e3842 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -399,8 +399,8 @@ void MIRGraph::ProcessCanSwitch(BasicBlock* cur_block, MIR* insn, int cur_offset 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 @@ BasicBlock* MIRGraph::ProcessCanThrow(BasicBlock* cur_block, MIR* insn, int cur_ 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 @@ BasicBlock* MIRGraph::ProcessCanThrow(BasicBlock* cur_block, MIR* insn, int cur_ 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 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_ 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 @@ char* MIRGraph::GetDalvikDisassembly(const MIR* mir) { 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 @@ void MIRGraph::DumpMIRGraph() { */ 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 @@ CallInfo* MIRGraph::NewMemCallInfo(BasicBlock* bb, MIR* mir, InvokeType type, } 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 @@ CallInfo* MIRGraph::NewMemCallInfo(BasicBlock* bb, MIR* mir, InvokeType type, // 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 c02deab00f..28ab2834e1 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -426,8 +426,8 @@ class MIRGraph { } 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 9f694de6a5..b7611f8f5b 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -94,8 +94,8 @@ void MIRGraph::DoConstantPropogation(BasicBlock* bb) { 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 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb) { 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 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb) { } 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::CodeLayout() { 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 90cec75039..7831cf6f7a 100644 --- a/compiler/dex/portable/mir_to_gbc.cc +++ b/compiler/dex/portable/mir_to_gbc.cc @@ -1972,7 +1972,7 @@ void MirConverter::MethodMIR2Bitcode() { ::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 2d8e24f58e..2dbe5f5c36 100644 --- a/compiler/dex/quick/arm/call_arm.cc +++ b/compiler/dex/quick/arm/call_arm.cc @@ -316,13 +316,12 @@ void ArmMir2Lir::GenSparseSwitch(MIR* mir, uint32_t table_offset, } // 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 @@ void ArmMir2Lir::GenPackedSwitch(MIR* mir, uint32_t table_offset, } // 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 @@ void ArmMir2Lir::GenFillArrayData(uint32_t table_offset, RegLocation rl_src) { 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 f1ccfa015e..291319f258 100644 --- a/compiler/dex/quick/arm/codegen_arm.h +++ b/compiler/dex/quick/arm/codegen_arm.h @@ -26,7 +26,7 @@ class ArmMir2Lir : public Mir2Lir { 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 c258019daa..f2ff58ee0a 100644 --- a/compiler/dex/quick/arm/int_arm.cc +++ b/compiler/dex/quick/arm/int_arm.cc @@ -415,7 +415,7 @@ static const MagicTable magic_table[] = { }; // 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 @@ bool ArmMir2Lir::SmallLiteralDivide(Instruction::Code dalvik_opcode, 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 47d3d974ef..6cc3052da1 100644 --- a/compiler/dex/quick/arm/target_arm.cc +++ b/compiler/dex/quick/arm/target_arm.cc @@ -538,16 +538,14 @@ void ArmMir2Lir::CompilerInitializeRegAlloc() { 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 5f6f3d51e9..d89f1ed227 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -321,7 +321,7 @@ LIR* Mir2Lir::ScanLiteralPoolWide(LIR* data_target, int val_lo, int val_hi) { 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 @@ LIR* Mir2Lir::InsertCaseLabel(int vaddr, int keyVal) { 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 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena 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 e5c7fb150e..f018c61819 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -1358,25 +1358,23 @@ static int LowestSetBit(unsigned int x) { // 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 @@ void Mir2Lir::GenArithOpIntLit(Instruction::Code opcode, RegLocation rl_dest, Re 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 2e9c845d05..630e990733 100644 --- a/compiler/dex/quick/local_optimizations.cc +++ b/compiler/dex/quick/local_optimizations.cc @@ -249,7 +249,7 @@ void Mir2Lir::ApplyLoadStoreElimination(LIR* head_lir, LIR* tail_lir) { /* 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 @@ void Mir2Lir::ApplyLoadHoisting(LIR* head_lir, LIR* tail_lir) { 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 eaae0e1964..d53c012466 100644 --- a/compiler/dex/quick/mips/call_mips.cc +++ b/compiler/dex/quick/mips/call_mips.cc @@ -67,13 +67,12 @@ void MipsMir2Lir::GenSparseSwitch(MIR* mir, uint32_t table_offset, } // 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 @@ void MipsMir2Lir::GenPackedSwitch(MIR* mir, uint32_t table_offset, } // 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 @@ void MipsMir2Lir::GenFillArrayData(uint32_t table_offset, RegLocation rl_src) { 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 6100396e5f..b9cb720962 100644 --- a/compiler/dex/quick/mips/codegen_mips.h +++ b/compiler/dex/quick/mips/codegen_mips.h @@ -27,7 +27,7 @@ class MipsMir2Lir : public Mir2Lir { 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 4a48c87ed9..6ce5750a5f 100644 --- a/compiler/dex/quick/mips/int_mips.cc +++ b/compiler/dex/quick/mips/int_mips.cc @@ -314,7 +314,7 @@ LIR* MipsMir2Lir::OpDecAndBranch(ConditionCode c_code, int reg, LIR* target) { 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 7a9e91a994..4ee5b23eb9 100644 --- a/compiler/dex/quick/mips/target_mips.cc +++ b/compiler/dex/quick/mips/target_mips.cc @@ -462,16 +462,14 @@ void MipsMir2Lir::CompilerInitializeRegAlloc() { 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 d9aef5d968..440df2afa6 100644 --- a/compiler/dex/quick/mir_to_lir-inl.h +++ b/compiler/dex/quick/mir_to_lir-inl.h @@ -40,7 +40,7 @@ inline void Mir2Lir::ClobberBody(RegisterInfo* p) { 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 862c1d74c6..c41feb1348 100644 --- a/compiler/dex/quick/mir_to_lir.cc +++ b/compiler/dex/quick/mir_to_lir.cc @@ -812,8 +812,8 @@ void Mir2Lir::SpecialMIR2LIR(SpecialCaseHandler special_case) { 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 517fc66a00..a37ebd173f 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -376,7 +376,7 @@ class Mir2Lir : public Backend { 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 @@ class Mir2Lir : public Backend { // 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 d59c986dda..71b74a4a68 100644 --- a/compiler/dex/quick/ralloc_util.cc +++ b/compiler/dex/quick/ralloc_util.cc @@ -931,7 +931,12 @@ void Mir2Lir::CountRefs(RefCounts* core_counts, RefCounts* fp_counts) { 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 @@ void Mir2Lir::DoPromotion() { * 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 6e3e55fc4e..2be2aa9a0e 100644 --- a/compiler/dex/quick/x86/call_x86.cc +++ b/compiler/dex/quick/x86/call_x86.cc @@ -74,13 +74,12 @@ void X86Mir2Lir::GenPackedSwitch(MIR* mir, uint32_t table_offset, } // 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 @@ void X86Mir2Lir::GenFillArrayData(uint32_t table_offset, RegLocation rl_src) { 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 21328d5440..478654d0b4 100644 --- a/compiler/dex/quick/x86/codegen_x86.h +++ b/compiler/dex/quick/x86/codegen_x86.h @@ -27,7 +27,7 @@ class X86Mir2Lir : public Mir2Lir { 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 377d134c80..14be7dde90 100644 --- a/compiler/dex/quick/x86/int_x86.cc +++ b/compiler/dex/quick/x86/int_x86.cc @@ -295,7 +295,7 @@ LIR* X86Mir2Lir::OpDecAndBranch(ConditionCode c_code, int reg, LIR* target) { 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 699f3ae5bb..26accab360 100644 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -438,16 +438,16 @@ void X86Mir2Lir::CompilerInitializeRegAlloc() { 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 18d8e93b1b..cd1602f674 100644 --- a/compiler/dex/ssa_transformation.cc +++ b/compiler/dex/ssa_transformation.cc @@ -136,8 +136,8 @@ void MIRGraph::ComputeDefBlockMatrix() { 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 @@ void MIRGraph::ComputeDominators() { /* 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 @@ void MIRGraph::InsertPhiNodes() { 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 @@ bool MIRGraph::InsertPhiNodeOperands(BasicBlock* bb) { 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 @@ void MIRGraph::DoDFSPreOrderSSARename(BasicBlock* block) { /* 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 5ee675306d..07f37bbbbb 100644 --- a/compiler/dex/vreg_analysis.cc +++ b/compiler/dex/vreg_analysis.cc @@ -374,8 +374,8 @@ static const RegLocation fresh_loc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0, */ 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 c079e5209c..634d3bc9c0 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -473,7 +473,7 @@ void CompilerDriver::CompileAll(jobject class_loader, 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 @@ void CompilerDriver::CompileOne(const mirror::ArtMethod* method, base::TimingLog 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 @@ class ParallelCompilationManager { 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 @@ class ParallelCompilationManager { 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 @@ class ParallelCompilationManager { 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 @@ class ParallelCompilationManager { } 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 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl 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 22a510b86b..fa1b8f9854 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 @@ class CompilerDriver { 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 @@ class CompilerDriver { 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 60c8f076de..04342fdb6f 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -596,7 +596,7 @@ bool ElfWriterQuick::Write(OatWriter& oat_writer, << " 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 dcafc193dd..106ef9ac86 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -152,7 +152,7 @@ TEST_F(ImageTest, WriteRead) { // 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 139100bee9..aa439ccbae 100644 --- a/compiler/llvm/llvm_compilation_unit.cc +++ b/compiler/llvm/llvm_compilation_unit.cc @@ -214,6 +214,7 @@ bool LlvmCompilationUnit::MaterializeToRawOStream(::llvm::raw_ostream& out_strea ::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 @@ bool LlvmCompilationUnit::MaterializeToRawOStream(::llvm::raw_ostream& out_strea ::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 @@ bool LlvmCompilationUnit::MaterializeToRawOStream(::llvm::raw_ostream& out_strea // 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 8bc787745b..02273817c9 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -506,7 +506,7 @@ class OatDumper { 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 @@ class OatDumper { 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 @@ class ImageDumper { 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 62088cc183..91b83f61dc 100644 --- a/runtime/base/stringpiece.h +++ b/runtime/base/stringpiece.h @@ -208,19 +208,6 @@ inline bool operator>=(const StringPiece& x, const StringPiece& y) { 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 3387a70915..cd4a720e24 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -187,6 +187,8 @@ ClassLinker* ClassLinker::CreateFromImage(InternTable* intern_table) { 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 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class 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 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class 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 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class 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 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class 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 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class 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 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class 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 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class 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 @@ const OatFile* ClassLinker::FindOatFileFromOatLocationLocked(const std::string& 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 InitFromImageCallbackCommon(mirror::Object* obj, ClassLinker* class_ } } -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 @@ void ClassLinker::InitFromImage() { 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 @@ void ClassLinker::InitFromImage() { // 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 @@ void ClassLinker::VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty) { 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::VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty) } } -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 @@ static bool GetClassesVisitor(mirror::Class* c, void* arg) { 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 @@ static mirror::Class* EnsureResolved(Thread* self, mirror::Class* klass) // 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 @@ mirror::Class* ClassLinker::FindClass(const char* descriptor, mirror::ClassLoade 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 @@ mirror::Class* ClassLinker::DefineClass(const StringPiece& descriptor, 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 @@ void ClassLinker::LoadClass(const DexFile& dex_file, 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::CreatePrimitiveClass(Thread* self, Primitive::Type t 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 @@ mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_cl // 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 @@ mirror::Class* ClassLinker::CreateArrayClass(const std::string& descriptor, // 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 @@ mirror::Class* ClassLinker::CreateArrayClass(const std::string& descriptor, // 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 @@ mirror::Class* ClassLinker::CreateArrayClass(const std::string& descriptor, 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 @@ mirror::Class* ClassLinker::CreateArrayClass(const std::string& descriptor, 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 @@ mirror::Class* ClassLinker::FindPrimitiveClass(char type) { 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 @@ mirror::Class* ClassLinker::InsertClass(const StringPiece& descriptor, mirror::C } 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 @@ mirror::Class* ClassLinker::InsertClass(const StringPiece& descriptor, mirror::C 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 @@ bool ClassLinker::RemoveClass(const char* descriptor, const mirror::ClassLoader* 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 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { } 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 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { 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 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { << 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 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { // 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 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { // 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 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { << " 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* ClassLinker::CreateProxyClass(mirror::String* name, 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 @@ mirror::Class* ClassLinker::CreateProxyClass(mirror::String* name, } 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 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, } if (!ValidateSuperClassDescriptors(klass)) { - klass->SetStatus(mirror::Class::kStatusError); + klass->SetStatus(mirror::Class::kStatusError, self); return false; } @@ -2815,7 +2878,7 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, // 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 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, << (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 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, 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 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, 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 @@ bool ClassLinker::WaitForInitializeClass(mirror::Class* klass, Thread* self, Obj // "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 @@ void ClassLinker::ConstructFieldMap(const DexFile& dex_file, const DexFile::Clas } 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 @@ bool ClassLinker::LinkClass(SirtRef<mirror::Class>& klass, 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 @@ bool ClassLinker::LoadSuperAndInterfaces(SirtRef<mirror::Class>& klass, const De } } // Mark the class as loaded. - klass->SetStatus(mirror::Class::kStatusLoaded); + klass->SetStatus(mirror::Class::kStatusLoaded, NULL); return true; } @@ -3175,13 +3236,13 @@ bool ClassLinker::LinkSuperClass(SirtRef<mirror::Class>& klass) { 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 @@ const char* ClassLinker::MethodShorty(uint32_t method_idx, mirror::ArtMethod* re 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::DumpAllClasses(int flags) const { } } -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 5ef6d8f006..c5fb72c020 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -73,7 +73,7 @@ class ClassLinker { 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 @@ class ClassLinker { 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 @@ class ClassLinker { 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 @@ class ClassLinker { // 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 @@ class ClassLinker { 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 @@ class ClassLinker { 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 @@ class ClassLinker { // 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_); + + // 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* 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_); + 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 09fa19e4d5..6e8736ade0 100644 --- a/runtime/dex_instruction.cc +++ b/runtime/dex_instruction.cc @@ -529,7 +529,20 @@ std::string Instruction::DumpString(const DexFile* file) const { 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 d7398caa57..e3a75cf3f9 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 @@ size_t InternTable::Size() const { 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 @@ void InternTable::VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty) 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 @@ mirror::String* InternTable::Lookup(Table& table, mirror::String* s, uint32_t ha 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 @@ void InternTable::Remove(Table& table, const mirror::String* s, uint32_t hash_co } } +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 @@ mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) { 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 @@ mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) { 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 @@ mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) { 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 @@ mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) { 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 5031ce3c5a..a804d1f30e 100644 --- a/runtime/intern_table.h +++ b/runtime/intern_table.h @@ -55,10 +55,6 @@ class InternTable { // 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 @@ class InternTable { 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 19e134fdfe..5e8b82793a 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -50,24 +50,26 @@ void Class::ResetClass() { 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 || 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 > kStatusResolved) { - CHECK_EQ(GetThinLockId(), Thread::Current()->GetThinLockId()) - << "Attempt to change status of class while not holding its lock " << PrettyClass(this); } 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 @@ void Class::SetStatus(Status new_status) { 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 638b67f485..99f3850b9b 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -125,10 +125,10 @@ class MANAGED Class : public StaticStorageBase { 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 ff193c9534..66c51e6eb6 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -792,6 +792,8 @@ void Monitor::Notify(Thread* self, mirror::Object *obj) { 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 @@ void Monitor::NotifyAll(Thread* self, mirror::Object *obj) { 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 @@ void Monitor::VisitLocks(StackVisitor* stack_visitor, void (*callback)(mirror::O } } +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 02c10a7a10..66517683c2 100644 --- a/runtime/monitor.h +++ b/runtime/monitor.h @@ -100,6 +100,8 @@ class Monitor { void* callback_context) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + static bool IsValidLockWord(int32_t lock_word); + mirror::Object* GetObject(); private: @@ -188,6 +190,7 @@ class MonitorList { 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 4ee353359b..2f4e427bb6 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -158,7 +158,8 @@ static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, j 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 e3ec3bcbb0..ae45701a53 100644 --- a/runtime/native/dalvik_system_VMDebug.cc +++ b/runtime/native/dalvik_system_VMDebug.cc @@ -37,6 +37,7 @@ static jobjectArray VMDebug_getVmFeatureList(JNIEnv* env, jclass) { 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 @@ static void VMDebug_resetAllocCount(JNIEnv*, jclass, jint kinds) { 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 @@ static void VMDebug_startMethodTracingFd(JNIEnv* env, jclass, jstring javaTraceF 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 @@ static void VMDebug_startMethodTracingFilename(JNIEnv* env, jclass, jstring java 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 @@ static void VMDebug_printLoadedClasses(JNIEnv* env, jclass, jint flags) { 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 @@ static JNINativeMethod gMethods[] = { 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 51a67c1bf4..5679d4ea83 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -925,7 +925,8 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) { 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 4c092fd8b5..6d040e15dc 100644 --- a/runtime/trace.cc +++ b/runtime/trace.cc @@ -122,9 +122,6 @@ ProfilerClockSource Trace::default_clock_source_ = kProfilerClockSourceWall; #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::CompareAndUpdateStackTrace(Thread* thread, 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::RunSamplingThread(void* arg) { } 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 @@ void Trace::Start(const char* trace_filename, int trace_fd, int buffer_size, int 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 @@ void Trace::Stop() { 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 @@ void Trace::Stop() { } 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 @@ bool Trace::IsMethodTracingActive() { 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 @@ Trace::Trace(File* trace_file, int buffer_size, int flags) 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 6fc3790a23..06cb6a6d5b 100644 --- a/runtime/trace.h +++ b/runtime/trace.h @@ -51,7 +51,7 @@ class Trace : public instrumentation::InstrumentationListener { 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 @@ class Trace : public instrumentation::InstrumentationListener { // 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 @@ class Trace : public instrumentation::InstrumentationListener { // 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 @@ class Trace : public instrumentation::InstrumentationListener { // 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 7d919635fc..0b7ac3d3ce 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 430686302a..01cbf18c6d 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); } } } |