1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "dex_cache_array_fixups_arm.h" 18 19#include "base/arena_containers.h" 20#ifdef ART_USE_OLD_ARM_BACKEND 21#include "code_generator_arm.h" 22#include "intrinsics_arm.h" 23#else 24#include "code_generator_arm_vixl.h" 25#include "intrinsics_arm_vixl.h" 26#endif 27#include "utils/dex_cache_arrays_layout-inl.h" 28 29namespace art { 30namespace arm { 31#ifdef ART_USE_OLD_ARM_BACKEND 32typedef CodeGeneratorARM CodeGeneratorARMType; 33typedef IntrinsicLocationsBuilderARM IntrinsicLocationsBuilderARMType; 34#else 35typedef CodeGeneratorARMVIXL CodeGeneratorARMType; 36typedef IntrinsicLocationsBuilderARMVIXL IntrinsicLocationsBuilderARMType; 37#endif 38 39/** 40 * Finds instructions that need the dex cache arrays base as an input. 41 */ 42class DexCacheArrayFixupsVisitor : public HGraphVisitor { 43 public: 44 DexCacheArrayFixupsVisitor(HGraph* graph, CodeGenerator* codegen) 45 : HGraphVisitor(graph), 46 codegen_(down_cast<CodeGeneratorARMType*>(codegen)), 47 dex_cache_array_bases_(std::less<const DexFile*>(), 48 // Attribute memory use to code generator. 49 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {} 50 51 void MoveBasesIfNeeded() { 52 for (const auto& entry : dex_cache_array_bases_) { 53 // Bring the base closer to the first use (previously, it was in the 54 // entry block) and relieve some pressure on the register allocator 55 // while avoiding recalculation of the base in a loop. 56 HArmDexCacheArraysBase* base = entry.second; 57 base->MoveBeforeFirstUserAndOutOfLoops(); 58 } 59 } 60 61 private: 62 void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE { 63 // If this is an invoke with PC-relative access to the dex cache methods array, 64 // we need to add the dex cache arrays base as the special input. 65 if (invoke->HasPcRelativeDexCache() && 66 !IsCallFreeIntrinsic<IntrinsicLocationsBuilderARMType>(invoke, codegen_)) { 67 HArmDexCacheArraysBase* base = 68 GetOrCreateDexCacheArrayBase(invoke, invoke->GetDexFileForPcRelativeDexCache()); 69 // Update the element offset in base. 70 DexCacheArraysLayout layout(kArmPointerSize, &invoke->GetDexFileForPcRelativeDexCache()); 71 base->UpdateElementOffset(layout.MethodOffset(invoke->GetDexMethodIndex())); 72 // Add the special argument base to the method. 73 DCHECK(!invoke->HasCurrentMethodInput()); 74 invoke->AddSpecialInput(base); 75 } 76 } 77 78 HArmDexCacheArraysBase* GetOrCreateDexCacheArrayBase(HInstruction* cursor, 79 const DexFile& dex_file) { 80 if (GetGraph()->HasIrreducibleLoops()) { 81 HArmDexCacheArraysBase* base = new (GetGraph()->GetArena()) HArmDexCacheArraysBase(dex_file); 82 cursor->GetBlock()->InsertInstructionBefore(base, cursor); 83 return base; 84 } else { 85 // Ensure we only initialize the pointer once for each dex file. 86 auto lb = dex_cache_array_bases_.lower_bound(&dex_file); 87 if (lb != dex_cache_array_bases_.end() && 88 !dex_cache_array_bases_.key_comp()(&dex_file, lb->first)) { 89 return lb->second; 90 } 91 92 // Insert the base at the start of the entry block, move it to a better 93 // position later in MoveBaseIfNeeded(). 94 HArmDexCacheArraysBase* base = new (GetGraph()->GetArena()) HArmDexCacheArraysBase(dex_file); 95 HBasicBlock* entry_block = GetGraph()->GetEntryBlock(); 96 entry_block->InsertInstructionBefore(base, entry_block->GetFirstInstruction()); 97 dex_cache_array_bases_.PutBefore(lb, &dex_file, base); 98 return base; 99 } 100 } 101 102 CodeGeneratorARMType* codegen_; 103 104 using DexCacheArraysBaseMap = 105 ArenaSafeMap<const DexFile*, HArmDexCacheArraysBase*, std::less<const DexFile*>>; 106 DexCacheArraysBaseMap dex_cache_array_bases_; 107}; 108 109void DexCacheArrayFixups::Run() { 110 DexCacheArrayFixupsVisitor visitor(graph_, codegen_); 111 visitor.VisitInsertionOrder(); 112 visitor.MoveBasesIfNeeded(); 113} 114 115} // namespace arm 116} // namespace art 117