1/* 2 * Copyright (C) 2014 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 "verified_method.h" 18 19#include <algorithm> 20#include <memory> 21#include <vector> 22 23#include "art_method-inl.h" 24#include "base/logging.h" 25#include "base/stl_util.h" 26#include "dex_file.h" 27#include "dex_instruction-inl.h" 28#include "dex_instruction_utils.h" 29#include "mirror/class-inl.h" 30#include "mirror/dex_cache-inl.h" 31#include "mirror/object-inl.h" 32#include "utils.h" 33#include "verifier/method_verifier-inl.h" 34#include "verifier/reg_type-inl.h" 35#include "verifier/register_line-inl.h" 36 37namespace art { 38 39VerifiedMethod::VerifiedMethod(uint32_t encountered_error_types, bool has_runtime_throw) 40 : encountered_error_types_(encountered_error_types), 41 has_runtime_throw_(has_runtime_throw) { 42} 43 44const VerifiedMethod* VerifiedMethod::Create(verifier::MethodVerifier* method_verifier, 45 bool compile) { 46 std::unique_ptr<VerifiedMethod> verified_method( 47 new VerifiedMethod(method_verifier->GetEncounteredFailureTypes(), 48 method_verifier->HasInstructionThatWillThrow())); 49 50 if (compile) { 51 // TODO: move this out when DEX-to-DEX supports devirtualization. 52 if (method_verifier->HasVirtualOrInterfaceInvokes()) { 53 verified_method->GenerateDevirtMap(method_verifier); 54 } 55 56 // Only need dequicken info for JIT so far. 57 if (Runtime::Current()->UseJitCompilation() && 58 !verified_method->GenerateDequickenMap(method_verifier)) { 59 return nullptr; 60 } 61 } 62 63 if (method_verifier->HasCheckCasts()) { 64 verified_method->GenerateSafeCastSet(method_verifier); 65 } 66 67 return verified_method.release(); 68} 69 70const MethodReference* VerifiedMethod::GetDevirtTarget(uint32_t dex_pc) const { 71 auto it = devirt_map_.find(dex_pc); 72 return (it != devirt_map_.end()) ? &it->second : nullptr; 73} 74 75const DexFileReference* VerifiedMethod::GetDequickenIndex(uint32_t dex_pc) const { 76 DCHECK(Runtime::Current()->UseJitCompilation()); 77 auto it = dequicken_map_.find(dex_pc); 78 return (it != dequicken_map_.end()) ? &it->second : nullptr; 79} 80 81bool VerifiedMethod::IsSafeCast(uint32_t pc) const { 82 return std::binary_search(safe_cast_set_.begin(), safe_cast_set_.end(), pc); 83} 84 85bool VerifiedMethod::GenerateDequickenMap(verifier::MethodVerifier* method_verifier) { 86 if (method_verifier->HasFailures()) { 87 return false; 88 } 89 const DexFile::CodeItem* code_item = method_verifier->CodeItem(); 90 const uint16_t* insns = code_item->insns_; 91 const Instruction* inst = Instruction::At(insns); 92 const Instruction* end = Instruction::At(insns + code_item->insns_size_in_code_units_); 93 for (; inst < end; inst = inst->Next()) { 94 const bool is_virtual_quick = inst->Opcode() == Instruction::INVOKE_VIRTUAL_QUICK; 95 const bool is_range_quick = inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK; 96 if (is_virtual_quick || is_range_quick) { 97 uint32_t dex_pc = inst->GetDexPc(insns); 98 verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc); 99 ArtMethod* method = 100 method_verifier->GetQuickInvokedMethod(inst, line, is_range_quick, true); 101 if (method == nullptr) { 102 // It can be null if the line wasn't verified since it was unreachable. 103 return false; 104 } 105 // The verifier must know what the type of the object was or else we would have gotten a 106 // failure. Put the dex method index in the dequicken map since we need this to get number of 107 // arguments in the compiler. 108 dequicken_map_.Put(dex_pc, DexFileReference(method->GetDexFile(), 109 method->GetDexMethodIndex())); 110 } else if (IsInstructionIGetQuickOrIPutQuick(inst->Opcode())) { 111 uint32_t dex_pc = inst->GetDexPc(insns); 112 verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc); 113 ArtField* field = method_verifier->GetQuickFieldAccess(inst, line); 114 if (field == nullptr) { 115 // It can be null if the line wasn't verified since it was unreachable. 116 return false; 117 } 118 // The verifier must know what the type of the field was or else we would have gotten a 119 // failure. Put the dex field index in the dequicken map since we need this for lowering 120 // in the compiler. 121 // TODO: Putting a field index in a method reference is gross. 122 dequicken_map_.Put(dex_pc, DexFileReference(field->GetDexFile(), field->GetDexFieldIndex())); 123 } 124 } 125 return true; 126} 127 128void VerifiedMethod::GenerateDevirtMap(verifier::MethodVerifier* method_verifier) { 129 // It is risky to rely on reg_types for sharpening in cases of soft 130 // verification, we might end up sharpening to a wrong implementation. Just abort. 131 if (method_verifier->HasFailures()) { 132 return; 133 } 134 135 const DexFile::CodeItem* code_item = method_verifier->CodeItem(); 136 const uint16_t* insns = code_item->insns_; 137 const Instruction* inst = Instruction::At(insns); 138 const Instruction* end = Instruction::At(insns + code_item->insns_size_in_code_units_); 139 140 for (; inst < end; inst = inst->Next()) { 141 const bool is_virtual = inst->Opcode() == Instruction::INVOKE_VIRTUAL || 142 inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE; 143 const bool is_interface = inst->Opcode() == Instruction::INVOKE_INTERFACE || 144 inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE; 145 146 if (!is_interface && !is_virtual) { 147 continue; 148 } 149 // Get reg type for register holding the reference to the object that will be dispatched upon. 150 uint32_t dex_pc = inst->GetDexPc(insns); 151 verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc); 152 const bool is_range = inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE || 153 inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE; 154 const verifier::RegType& 155 reg_type(line->GetRegisterType(method_verifier, 156 is_range ? inst->VRegC_3rc() : inst->VRegC_35c())); 157 158 if (!reg_type.HasClass()) { 159 // We will compute devirtualization information only when we know the Class of the reg type. 160 continue; 161 } 162 mirror::Class* reg_class = reg_type.GetClass(); 163 if (reg_class->IsInterface()) { 164 // We can't devirtualize when the known type of the register is an interface. 165 continue; 166 } 167 if (reg_class->IsAbstract() && !reg_class->IsArrayClass()) { 168 // We can't devirtualize abstract classes except on arrays of abstract classes. 169 continue; 170 } 171 auto* cl = Runtime::Current()->GetClassLinker(); 172 size_t pointer_size = cl->GetImagePointerSize(); 173 ArtMethod* abstract_method = method_verifier->GetDexCache()->GetResolvedMethod( 174 is_range ? inst->VRegB_3rc() : inst->VRegB_35c(), pointer_size); 175 if (abstract_method == nullptr) { 176 // If the method is not found in the cache this means that it was never found 177 // by ResolveMethodAndCheckAccess() called when verifying invoke_*. 178 continue; 179 } 180 // Find the concrete method. 181 ArtMethod* concrete_method = nullptr; 182 if (is_interface) { 183 concrete_method = reg_type.GetClass()->FindVirtualMethodForInterface( 184 abstract_method, pointer_size); 185 } 186 if (is_virtual) { 187 concrete_method = reg_type.GetClass()->FindVirtualMethodForVirtual( 188 abstract_method, pointer_size); 189 } 190 if (concrete_method == nullptr || !concrete_method->IsInvokable()) { 191 // In cases where concrete_method is not found, or is not invokable, continue to the next 192 // invoke. 193 continue; 194 } 195 if (reg_type.IsPreciseReference() || concrete_method->IsFinal() || 196 concrete_method->GetDeclaringClass()->IsFinal()) { 197 // If we knew exactly the class being dispatched upon, or if the target method cannot be 198 // overridden record the target to be used in the compiler driver. 199 devirt_map_.Put(dex_pc, concrete_method->ToMethodReference()); 200 } 201 } 202} 203 204void VerifiedMethod::GenerateSafeCastSet(verifier::MethodVerifier* method_verifier) { 205 /* 206 * Walks over the method code and adds any cast instructions in which 207 * the type cast is implicit to a set, which is used in the code generation 208 * to elide these casts. 209 */ 210 if (method_verifier->HasFailures()) { 211 return; 212 } 213 const DexFile::CodeItem* code_item = method_verifier->CodeItem(); 214 const Instruction* inst = Instruction::At(code_item->insns_); 215 const Instruction* end = Instruction::At(code_item->insns_ + 216 code_item->insns_size_in_code_units_); 217 218 for (; inst < end; inst = inst->Next()) { 219 Instruction::Code code = inst->Opcode(); 220 if ((code == Instruction::CHECK_CAST) || (code == Instruction::APUT_OBJECT)) { 221 uint32_t dex_pc = inst->GetDexPc(code_item->insns_); 222 if (!method_verifier->GetInstructionFlags(dex_pc).IsVisited()) { 223 // Do not attempt to quicken this instruction, it's unreachable anyway. 224 continue; 225 } 226 const verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc); 227 bool is_safe_cast = false; 228 if (code == Instruction::CHECK_CAST) { 229 const verifier::RegType& reg_type(line->GetRegisterType(method_verifier, 230 inst->VRegA_21c())); 231 const verifier::RegType& cast_type = 232 method_verifier->ResolveCheckedClass(inst->VRegB_21c()); 233 is_safe_cast = cast_type.IsStrictlyAssignableFrom(reg_type); 234 } else { 235 const verifier::RegType& array_type(line->GetRegisterType(method_verifier, 236 inst->VRegB_23x())); 237 // We only know its safe to assign to an array if the array type is precise. For example, 238 // an Object[] can have any type of object stored in it, but it may also be assigned a 239 // String[] in which case the stores need to be of Strings. 240 if (array_type.IsPreciseReference()) { 241 const verifier::RegType& value_type(line->GetRegisterType(method_verifier, 242 inst->VRegA_23x())); 243 const verifier::RegType& component_type = method_verifier->GetRegTypeCache() 244 ->GetComponentType(array_type, method_verifier->GetClassLoader()); 245 is_safe_cast = component_type.IsStrictlyAssignableFrom(value_type); 246 } 247 } 248 if (is_safe_cast) { 249 // Verify ordering for push_back() to the sorted vector. 250 DCHECK(safe_cast_set_.empty() || safe_cast_set_.back() < dex_pc); 251 safe_cast_set_.push_back(dex_pc); 252 } 253 } 254 } 255} 256 257} // namespace art 258