110e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle/* 210e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle * Copyright (C) 2015 The Android Open Source Project 310e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle * 410e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle * Licensed under the Apache License, Version 2.0 (the "License"); 510e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle * you may not use this file except in compliance with the License. 610e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle * You may obtain a copy of the License at 710e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle * 810e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle * http://www.apache.org/licenses/LICENSE-2.0 910e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle * 1010e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle * Unless required by applicable law or agreed to in writing, software 1110e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle * distributed under the License is distributed on an "AS IS" BASIS, 1210e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1310e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle * See the License for the specific language governing permissions and 1410e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle * limitations under the License. 1510e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle */ 1610e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle 1710e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle#include "reference_type_propagation.h" 1810e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle 19e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier#include "class_linker-inl.h" 20acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle#include "mirror/class-inl.h" 21acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle#include "mirror/dex_cache.h" 22acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle#include "scoped_thread_state_change.h" 23acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle 2410e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravlenamespace art { 2510e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle 26a4336d253b88f95c49891a8084579a4599785e90Vladimir Markostatic inline mirror::DexCache* FindDexCacheWithHint(Thread* self, 27a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko const DexFile& dex_file, 28a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko Handle<mirror::DexCache> hint_dex_cache) 29a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko SHARED_REQUIRES(Locks::mutator_lock_) { 30a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko if (LIKELY(hint_dex_cache->GetDexFile() == &dex_file)) { 31a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko return hint_dex_cache.Get(); 32a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko } else { 33a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko return Runtime::Current()->GetClassLinker()->FindDexCache(self, dex_file); 34a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko } 35a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko} 36a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko 377d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markostatic inline ReferenceTypeInfo::TypeHandle GetRootHandle(StackHandleScopeCollection* handles, 387d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko ClassLinker::ClassRoot class_root, 397d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko ReferenceTypeInfo::TypeHandle* cache) { 407d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko if (!ReferenceTypeInfo::IsValidHandle(*cache)) { 417d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko // Mutator lock is required for NewHandle. 427d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko ClassLinker* linker = Runtime::Current()->GetClassLinker(); 437d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko ScopedObjectAccess soa(Thread::Current()); 447d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko *cache = handles->NewHandle(linker->GetClassRoot(class_root)); 457d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko } 467d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko return *cache; 477d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko} 487d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko 49f7d994622aabcc689f62253a9253e0c67d9e787eNicolas Geoffray// Returns true if klass is admissible to the propagation: non-null and resolved. 50d1d7c40c8004303d1131ebb1956fd0ade54f8404Aart Bik// For an array type, we also check if the component type is admissible. 51d1d7c40c8004303d1131ebb1956fd0ade54f8404Aart Bikstatic bool IsAdmissible(mirror::Class* klass) SHARED_REQUIRES(Locks::mutator_lock_) { 52f7d994622aabcc689f62253a9253e0c67d9e787eNicolas Geoffray return klass != nullptr && klass->IsResolved() && 53d1d7c40c8004303d1131ebb1956fd0ade54f8404Aart Bik (!klass->IsArrayClass() || IsAdmissible(klass->GetComponentType())); 54d1d7c40c8004303d1131ebb1956fd0ade54f8404Aart Bik} 55d1d7c40c8004303d1131ebb1956fd0ade54f8404Aart Bik 567d1fbf38412078090e81e9d9fa502635d8541707Vladimir MarkoReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetObjectClassHandle() { 577d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko return GetRootHandle(handles_, ClassLinker::kJavaLangObject, &object_class_handle_); 587d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko} 597d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko 607d1fbf38412078090e81e9d9fa502635d8541707Vladimir MarkoReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetClassClassHandle() { 617d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko return GetRootHandle(handles_, ClassLinker::kJavaLangClass, &class_class_handle_); 627d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko} 637d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko 647d1fbf38412078090e81e9d9fa502635d8541707Vladimir MarkoReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetStringClassHandle() { 657d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko return GetRootHandle(handles_, ClassLinker::kJavaLangString, &string_class_handle_); 667d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko} 677d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko 687d1fbf38412078090e81e9d9fa502635d8541707Vladimir MarkoReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetThrowableClassHandle() { 697d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko return GetRootHandle(handles_, ClassLinker::kJavaLangThrowable, &throwable_class_handle_); 707d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko} 717d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko 727d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markoclass ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor { 73ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez public: 742e76830f0b3f23825677436c0633714402715099Calin Juravle RTPVisitor(HGraph* graph, 75a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko Handle<mirror::DexCache> hint_dex_cache, 767d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko HandleCache* handle_cache, 77d9994f069dfeaa32ba929ca78816b5b83e2a4134Nicolas Geoffray ArenaVector<HInstruction*>* worklist, 78d9994f069dfeaa32ba929ca78816b5b83e2a4134Nicolas Geoffray bool is_first_run) 79ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez : HGraphDelegateVisitor(graph), 80a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko hint_dex_cache_(hint_dex_cache), 817d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko handle_cache_(handle_cache), 82d9994f069dfeaa32ba929ca78816b5b83e2a4134Nicolas Geoffray worklist_(worklist), 83d9994f069dfeaa32ba929ca78816b5b83e2a4134Nicolas Geoffray is_first_run_(is_first_run) {} 84ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez 85ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez void VisitNewInstance(HNewInstance* new_instance) OVERRIDE; 86ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez void VisitLoadClass(HLoadClass* load_class) OVERRIDE; 872e76830f0b3f23825677436c0633714402715099Calin Juravle void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE; 882e76830f0b3f23825677436c0633714402715099Calin Juravle void VisitLoadString(HLoadString* instr) OVERRIDE; 89bbd733e4ef277eff19bf9a6601032da081e9b68fDavid Brazdil void VisitLoadException(HLoadException* instr) OVERRIDE; 90ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez void VisitNewArray(HNewArray* instr) OVERRIDE; 912e76830f0b3f23825677436c0633714402715099Calin Juravle void VisitParameterValue(HParameterValue* instr) OVERRIDE; 92ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info); 93a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko void SetClassAsTypeInfo(HInstruction* instr, mirror::Class* klass, bool is_exact) 94a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko SHARED_REQUIRES(Locks::mutator_lock_); 95ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE; 96ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez void VisitStaticFieldGet(HStaticFieldGet* instr) OVERRIDE; 97e460d1df1f789c7c8bb97024a8efbd713ac175e9Calin Juravle void VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instr) OVERRIDE; 98e460d1df1f789c7c8bb97024a8efbd713ac175e9Calin Juravle void VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet* instr) OVERRIDE; 99ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez void VisitInvoke(HInvoke* instr) OVERRIDE; 10072a5eb5d6784b318750c36e0da25c7338557ce44Guillaume "Vermeille" Sanchez void VisitArrayGet(HArrayGet* instr) OVERRIDE; 101a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle void VisitCheckCast(HCheckCast* instr) OVERRIDE; 102f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil void VisitBoundType(HBoundType* instr) OVERRIDE; 1032e76830f0b3f23825677436c0633714402715099Calin Juravle void VisitNullCheck(HNullCheck* instr) OVERRIDE; 104ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez void UpdateReferenceTypeInfo(HInstruction* instr, 105ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez uint16_t type_idx, 106ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez const DexFile& dex_file, 107ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez bool is_exact); 108ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez 109ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez private: 110a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko Handle<mirror::DexCache> hint_dex_cache_; 1117d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko HandleCache* handle_cache_; 1122aaa4b5532d30c4e65d8892b556400bb61f9dc8cVladimir Marko ArenaVector<HInstruction*>* worklist_; 113d9994f069dfeaa32ba929ca78816b5b83e2a4134Nicolas Geoffray const bool is_first_run_; 114ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez}; 115ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez 1162e76830f0b3f23825677436c0633714402715099Calin JuravleReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph, 117a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko Handle<mirror::DexCache> hint_dex_cache, 1182e76830f0b3f23825677436c0633714402715099Calin Juravle StackHandleScopeCollection* handles, 119d9994f069dfeaa32ba929ca78816b5b83e2a4134Nicolas Geoffray bool is_first_run, 1202e76830f0b3f23825677436c0633714402715099Calin Juravle const char* name) 1212e76830f0b3f23825677436c0633714402715099Calin Juravle : HOptimization(graph, name), 122a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko hint_dex_cache_(hint_dex_cache), 1237d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko handle_cache_(handles), 124d9994f069dfeaa32ba929ca78816b5b83e2a4134Nicolas Geoffray worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)), 125d9994f069dfeaa32ba929ca78816b5b83e2a4134Nicolas Geoffray is_first_run_(is_first_run) { 1262e76830f0b3f23825677436c0633714402715099Calin Juravle} 1272e76830f0b3f23825677436c0633714402715099Calin Juravle 128cdfed3dc422d0e1a9a0a948863308e58c39d01baCalin Juravlevoid ReferenceTypePropagation::ValidateTypes() { 129cdfed3dc422d0e1a9a0a948863308e58c39d01baCalin Juravle // TODO: move this to the graph checker. 1302e76830f0b3f23825677436c0633714402715099Calin Juravle if (kIsDebugBuild) { 1312e76830f0b3f23825677436c0633714402715099Calin Juravle ScopedObjectAccess soa(Thread::Current()); 1322e76830f0b3f23825677436c0633714402715099Calin Juravle for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) { 1332e76830f0b3f23825677436c0633714402715099Calin Juravle HBasicBlock* block = it.Current(); 1342e76830f0b3f23825677436c0633714402715099Calin Juravle for (HInstructionIterator iti(block->GetInstructions()); !iti.Done(); iti.Advance()) { 1352e76830f0b3f23825677436c0633714402715099Calin Juravle HInstruction* instr = iti.Current(); 1362e76830f0b3f23825677436c0633714402715099Calin Juravle if (instr->GetType() == Primitive::kPrimNot) { 1372e76830f0b3f23825677436c0633714402715099Calin Juravle DCHECK(instr->GetReferenceTypeInfo().IsValid()) 1382e76830f0b3f23825677436c0633714402715099Calin Juravle << "Invalid RTI for instruction: " << instr->DebugName(); 1392e76830f0b3f23825677436c0633714402715099Calin Juravle if (instr->IsBoundType()) { 1402e76830f0b3f23825677436c0633714402715099Calin Juravle DCHECK(instr->AsBoundType()->GetUpperBound().IsValid()); 1412e76830f0b3f23825677436c0633714402715099Calin Juravle } else if (instr->IsLoadClass()) { 14298893e146b0ff0e1fd1d7c29252f1d1e75a163f2Calin Juravle HLoadClass* cls = instr->AsLoadClass(); 14398893e146b0ff0e1fd1d7c29252f1d1e75a163f2Calin Juravle DCHECK(cls->GetReferenceTypeInfo().IsExact()); 14498893e146b0ff0e1fd1d7c29252f1d1e75a163f2Calin Juravle DCHECK(!cls->GetLoadedClassRTI().IsValid() || cls->GetLoadedClassRTI().IsExact()); 1452e76830f0b3f23825677436c0633714402715099Calin Juravle } else if (instr->IsNullCheck()) { 1462e76830f0b3f23825677436c0633714402715099Calin Juravle DCHECK(instr->GetReferenceTypeInfo().IsEqual(instr->InputAt(0)->GetReferenceTypeInfo())) 1472e76830f0b3f23825677436c0633714402715099Calin Juravle << "NullCheck " << instr->GetReferenceTypeInfo() 1482e76830f0b3f23825677436c0633714402715099Calin Juravle << "Input(0) " << instr->InputAt(0)->GetReferenceTypeInfo(); 1492e76830f0b3f23825677436c0633714402715099Calin Juravle } 1502e76830f0b3f23825677436c0633714402715099Calin Juravle } 1512e76830f0b3f23825677436c0633714402715099Calin Juravle } 1522e76830f0b3f23825677436c0633714402715099Calin Juravle } 1532e76830f0b3f23825677436c0633714402715099Calin Juravle } 15410e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle} 15510e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle 156be10e8e99a78caae01fb65769218800d465144aeVladimir Markovoid ReferenceTypePropagation::Visit(HInstruction* instruction) { 157a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko RTPVisitor visitor(graph_, hint_dex_cache_, &handle_cache_, &worklist_, is_first_run_); 158be10e8e99a78caae01fb65769218800d465144aeVladimir Marko instruction->Accept(&visitor); 159be10e8e99a78caae01fb65769218800d465144aeVladimir Marko} 160be10e8e99a78caae01fb65769218800d465144aeVladimir Marko 161cdfed3dc422d0e1a9a0a948863308e58c39d01baCalin Juravlevoid ReferenceTypePropagation::Run() { 162be10e8e99a78caae01fb65769218800d465144aeVladimir Marko worklist_.reserve(kDefaultWorklistSize); 163be10e8e99a78caae01fb65769218800d465144aeVladimir Marko 164cdfed3dc422d0e1a9a0a948863308e58c39d01baCalin Juravle // To properly propagate type info we need to visit in the dominator-based order. 165cdfed3dc422d0e1a9a0a948863308e58c39d01baCalin Juravle // Reverse post order guarantees a node's dominators are visited first. 166cdfed3dc422d0e1a9a0a948863308e58c39d01baCalin Juravle // We take advantage of this order in `VisitBasicBlock`. 167cdfed3dc422d0e1a9a0a948863308e58c39d01baCalin Juravle for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) { 168cdfed3dc422d0e1a9a0a948863308e58c39d01baCalin Juravle VisitBasicBlock(it.Current()); 169cdfed3dc422d0e1a9a0a948863308e58c39d01baCalin Juravle } 170cdfed3dc422d0e1a9a0a948863308e58c39d01baCalin Juravle 171cdfed3dc422d0e1a9a0a948863308e58c39d01baCalin Juravle ProcessWorklist(); 172cdfed3dc422d0e1a9a0a948863308e58c39d01baCalin Juravle ValidateTypes(); 173cdfed3dc422d0e1a9a0a948863308e58c39d01baCalin Juravle} 174cdfed3dc422d0e1a9a0a948863308e58c39d01baCalin Juravle 175b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravlevoid ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) { 176a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko RTPVisitor visitor(graph_, hint_dex_cache_, &handle_cache_, &worklist_, is_first_run_); 1772e76830f0b3f23825677436c0633714402715099Calin Juravle // Handle Phis first as there might be instructions in the same block who depend on them. 1782e76830f0b3f23825677436c0633714402715099Calin Juravle for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { 1792e76830f0b3f23825677436c0633714402715099Calin Juravle VisitPhi(it.Current()->AsPhi()); 1802e76830f0b3f23825677436c0633714402715099Calin Juravle } 181beba9302bec33d72beb582970bf23d056f62641fCalin Juravle 1822e76830f0b3f23825677436c0633714402715099Calin Juravle // Handle instructions. 183b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { 184b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle HInstruction* instr = it.Current(); 185ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez instr->Accept(&visitor); 186b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle } 18710e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle 188b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle // Add extra nodes to bound types. 18961d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle BoundTypeForIfNotNull(block); 190b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle BoundTypeForIfInstanceOf(block); 191b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle} 192acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle 193a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle// Check if we should create a bound type for the given object at the specified 194a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle// position. Because of inlining and the fact we run RTP more than once and we 195a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle// might have a HBoundType already. If we do, we should not create a new one. 196a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle// In this case we also assert that there are no other uses of the object (except 197a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle// the bound type) dominated by the specified dominator_instr or dominator_block. 198a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravlestatic bool ShouldCreateBoundType(HInstruction* position, 199a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle HInstruction* obj, 200a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle ReferenceTypeInfo upper_bound, 201a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle HInstruction* dominator_instr, 202a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle HBasicBlock* dominator_block) 203a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle SHARED_REQUIRES(Locks::mutator_lock_) { 204a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle // If the position where we should insert the bound type is not already a 205a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle // a bound type then we need to create one. 206a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle if (position == nullptr || !position->IsBoundType()) { 207a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle return true; 208a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle } 209a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle 210a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle HBoundType* existing_bound_type = position->AsBoundType(); 211a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle if (existing_bound_type->GetUpperBound().IsSupertypeOf(upper_bound)) { 212a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle if (kIsDebugBuild) { 213a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle // Check that the existing HBoundType dominates all the uses. 214d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko for (const HUseListNode<HInstruction*>& use : obj->GetUses()) { 215d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko HInstruction* user = use.GetUser(); 216a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle if (dominator_instr != nullptr) { 217a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle DCHECK(!dominator_instr->StrictlyDominates(user) 218a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle || user == existing_bound_type 219a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle || existing_bound_type->StrictlyDominates(user)); 220a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle } else if (dominator_block != nullptr) { 221a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle DCHECK(!dominator_block->Dominates(user->GetBlock()) 222a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle || user == existing_bound_type 223a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle || existing_bound_type->StrictlyDominates(user)); 224a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle } 225a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle } 226a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle } 227a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle } else { 228a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle // TODO: if the current bound type is a refinement we could update the 229a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle // existing_bound_type with the a new upper limit. However, we also need to 230a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle // update its users and have access to the work list. 231a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle } 232a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle return false; 233a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle} 234a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle 23561d544bfb812d79f5c9ddad171198836cea719dbCalin Juravlevoid ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) { 236b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle HIf* ifInstruction = block->GetLastInstruction()->AsIf(); 237b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle if (ifInstruction == nullptr) { 23861d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle return; 23961d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle } 240b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle HInstruction* ifInput = ifInstruction->InputAt(0); 24161d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) { 24261d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle return; 24361d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle } 24461d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle HInstruction* input0 = ifInput->InputAt(0); 24561d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle HInstruction* input1 = ifInput->InputAt(1); 246edad8add1f1216850cb3f179ba6f57b0d885b016Calin Juravle HInstruction* obj = nullptr; 24761d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle 248edad8add1f1216850cb3f179ba6f57b0d885b016Calin Juravle if (input1->IsNullConstant()) { 24961d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle obj = input0; 250edad8add1f1216850cb3f179ba6f57b0d885b016Calin Juravle } else if (input0->IsNullConstant()) { 25161d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle obj = input1; 25261d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle } else { 25361d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle return; 25461d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle } 25561d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle 2567d5ea03b2a7d886325b3ad97942038c2336aa855Nicolas Geoffray if (!obj->CanBeNull() || obj->IsNullConstant()) { 2577d5ea03b2a7d886325b3ad97942038c2336aa855Nicolas Geoffray // Null check is dead code and will be removed by DCE. 2587d5ea03b2a7d886325b3ad97942038c2336aa855Nicolas Geoffray return; 2597d5ea03b2a7d886325b3ad97942038c2336aa855Nicolas Geoffray } 2607d5ea03b2a7d886325b3ad97942038c2336aa855Nicolas Geoffray DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions"; 2617d5ea03b2a7d886325b3ad97942038c2336aa855Nicolas Geoffray 262b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle // We only need to bound the type if we have uses in the relevant block. 263b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle // So start with null and create the HBoundType lazily, only if it's needed. 264b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle HBoundType* bound_type = nullptr; 26561d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle HBasicBlock* notNullBlock = ifInput->IsNotEqual() 266b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle ? ifInstruction->IfTrueSuccessor() 267b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle : ifInstruction->IfFalseSuccessor(); 268b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle 269d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko const HUseList<HInstruction*>& uses = obj->GetUses(); 270d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) { 271d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko HInstruction* user = it->GetUser(); 272d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko size_t index = it->GetIndex(); 273d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput(). 274d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko ++it; 27561d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle if (notNullBlock->Dominates(user->GetBlock())) { 276b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle if (bound_type == nullptr) { 277a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle ScopedObjectAccess soa(Thread::Current()); 278a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle HInstruction* insert_point = notNullBlock->GetFirstInstruction(); 2792e76830f0b3f23825677436c0633714402715099Calin Juravle ReferenceTypeInfo object_rti = ReferenceTypeInfo::Create( 2807d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko handle_cache_.GetObjectClassHandle(), /* is_exact */ true); 281a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle if (ShouldCreateBoundType(insert_point, obj, object_rti, nullptr, notNullBlock)) { 282f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil bound_type = new (graph_->GetArena()) HBoundType(obj); 283f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil bound_type->SetUpperBound(object_rti, /* bound_can_be_null */ false); 2842e76830f0b3f23825677436c0633714402715099Calin Juravle if (obj->GetReferenceTypeInfo().IsValid()) { 2852e76830f0b3f23825677436c0633714402715099Calin Juravle bound_type->SetReferenceTypeInfo(obj->GetReferenceTypeInfo()); 2862e76830f0b3f23825677436c0633714402715099Calin Juravle } 287a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle notNullBlock->InsertInstructionBefore(bound_type, insert_point); 288a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle } else { 289a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle // We already have a bound type on the position we would need to insert 290a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle // the new one. The existing bound type should dominate all the users 291a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle // (dchecked) so there's no need to continue. 292a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle break; 293a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle } 294b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle } 295d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko user->ReplaceInput(bound_type, index); 29661d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle } 29761d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle } 29861d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle} 29961d544bfb812d79f5c9ddad171198836cea719dbCalin Juravle 300d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil// Returns true if one of the patterns below has been recognized. If so, the 301d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil// InstanceOf instruction together with the true branch of `ifInstruction` will 302d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil// be returned using the out parameters. 303d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil// Recognized patterns: 304d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil// (1) patterns equivalent to `if (obj instanceof X)` 305d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil// (a) InstanceOf -> Equal to 1 -> If 306d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil// (b) InstanceOf -> NotEqual to 0 -> If 307d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil// (c) InstanceOf -> If 308d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil// (2) patterns equivalent to `if (!(obj instanceof X))` 309d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil// (a) InstanceOf -> Equal to 0 -> If 310d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil// (b) InstanceOf -> NotEqual to 1 -> If 311d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil// (c) InstanceOf -> BooleanNot -> If 312d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdilstatic bool MatchIfInstanceOf(HIf* ifInstruction, 313d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil /* out */ HInstanceOf** instanceOf, 314d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil /* out */ HBasicBlock** trueBranch) { 315d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil HInstruction* input = ifInstruction->InputAt(0); 316d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil 317d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil if (input->IsEqual()) { 318d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil HInstruction* rhs = input->AsEqual()->GetConstantRight(); 319d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil if (rhs != nullptr) { 320d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil HInstruction* lhs = input->AsEqual()->GetLeastConstantLeft(); 321d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil if (lhs->IsInstanceOf() && rhs->IsIntConstant()) { 3221a65388f1d86bb232c2e44fecb44cebe13105d2eRoland Levillain if (rhs->AsIntConstant()->IsTrue()) { 323d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil // Case (1a) 324d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil *trueBranch = ifInstruction->IfTrueSuccessor(); 325d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil } else { 326d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil // Case (2a) 3271a65388f1d86bb232c2e44fecb44cebe13105d2eRoland Levillain DCHECK(rhs->AsIntConstant()->IsFalse()) << rhs->AsIntConstant()->GetValue(); 328d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil *trueBranch = ifInstruction->IfFalseSuccessor(); 329d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil } 330d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil *instanceOf = lhs->AsInstanceOf(); 331d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil return true; 332d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil } 333d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil } 334d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil } else if (input->IsNotEqual()) { 335d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil HInstruction* rhs = input->AsNotEqual()->GetConstantRight(); 336d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil if (rhs != nullptr) { 337d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil HInstruction* lhs = input->AsNotEqual()->GetLeastConstantLeft(); 338d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil if (lhs->IsInstanceOf() && rhs->IsIntConstant()) { 3391a65388f1d86bb232c2e44fecb44cebe13105d2eRoland Levillain if (rhs->AsIntConstant()->IsFalse()) { 340d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil // Case (1b) 341d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil *trueBranch = ifInstruction->IfTrueSuccessor(); 342d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil } else { 343d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil // Case (2b) 3441a65388f1d86bb232c2e44fecb44cebe13105d2eRoland Levillain DCHECK(rhs->AsIntConstant()->IsTrue()) << rhs->AsIntConstant()->GetValue(); 345d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil *trueBranch = ifInstruction->IfFalseSuccessor(); 346d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil } 347d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil *instanceOf = lhs->AsInstanceOf(); 348d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil return true; 349d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil } 350d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil } 351d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil } else if (input->IsInstanceOf()) { 352d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil // Case (1c) 353d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil *instanceOf = input->AsInstanceOf(); 354d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil *trueBranch = ifInstruction->IfTrueSuccessor(); 355d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil return true; 356d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil } else if (input->IsBooleanNot()) { 357d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil HInstruction* not_input = input->InputAt(0); 358d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil if (not_input->IsInstanceOf()) { 359d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil // Case (2c) 360d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil *instanceOf = not_input->AsInstanceOf(); 361d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil *trueBranch = ifInstruction->IfFalseSuccessor(); 362d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil return true; 363d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil } 364d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil } 365d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil 366d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil return false; 367d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil} 368d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil 369b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle// Detects if `block` is the True block for the pattern 370b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle// `if (x instanceof ClassX) { }` 371b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle// If that's the case insert an HBoundType instruction to bound the type of `x` 372b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle// to `ClassX` in the scope of the dominated blocks. 373b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravlevoid ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) { 374b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle HIf* ifInstruction = block->GetLastInstruction()->AsIf(); 375b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle if (ifInstruction == nullptr) { 376b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle return; 377b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle } 378b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle 379d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil // Try to recognize common `if (instanceof)` and `if (!instanceof)` patterns. 380d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil HInstanceOf* instanceOf = nullptr; 381d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil HBasicBlock* instanceOfTrueBlock = nullptr; 382d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil if (!MatchIfInstanceOf(ifInstruction, &instanceOf, &instanceOfTrueBlock)) { 383b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle return; 384acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle } 385acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle 38698893e146b0ff0e1fd1d7c29252f1d1e75a163f2Calin Juravle HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass(); 38798893e146b0ff0e1fd1d7c29252f1d1e75a163f2Calin Juravle ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI(); 38898893e146b0ff0e1fd1d7c29252f1d1e75a163f2Calin Juravle { 38998893e146b0ff0e1fd1d7c29252f1d1e75a163f2Calin Juravle if (!class_rti.IsValid()) { 39098893e146b0ff0e1fd1d7c29252f1d1e75a163f2Calin Juravle // He have loaded an unresolved class. Don't bother bounding the type. 39198893e146b0ff0e1fd1d7c29252f1d1e75a163f2Calin Juravle return; 39298893e146b0ff0e1fd1d7c29252f1d1e75a163f2Calin Juravle } 39398893e146b0ff0e1fd1d7c29252f1d1e75a163f2Calin Juravle } 394b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle // We only need to bound the type if we have uses in the relevant block. 395b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle // So start with null and create the HBoundType lazily, only if it's needed. 396b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle HBoundType* bound_type = nullptr; 397acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle 398b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle HInstruction* obj = instanceOf->InputAt(0); 399f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray if (obj->GetReferenceTypeInfo().IsExact() && !obj->IsPhi()) { 400f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray // This method is being called while doing a fixed-point calculation 401f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray // over phis. Non-phis instruction whose type is already known do 402f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray // not need to be bound to another type. 403f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray // Not that this also prevents replacing `HLoadClass` with a `HBoundType`. 404f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray // `HCheckCast` and `HInstanceOf` expect a `HLoadClass` as a second 405f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray // input. 406f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray return; 407f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray } 4087d5ea03b2a7d886325b3ad97942038c2336aa855Nicolas Geoffray DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions"; 409d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko const HUseList<HInstruction*>& uses = obj->GetUses(); 410d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) { 411d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko HInstruction* user = it->GetUser(); 412d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko size_t index = it->GetIndex(); 413d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput(). 414d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko ++it; 415b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle if (instanceOfTrueBlock->Dominates(user->GetBlock())) { 416b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle if (bound_type == nullptr) { 417a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle ScopedObjectAccess soa(Thread::Current()); 418a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle HInstruction* insert_point = instanceOfTrueBlock->GetFirstInstruction(); 419a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle if (ShouldCreateBoundType(insert_point, obj, class_rti, nullptr, instanceOfTrueBlock)) { 420f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil bound_type = new (graph_->GetArena()) HBoundType(obj); 421f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil bound_type->SetUpperBound(class_rti, /* InstanceOf fails for null. */ false); 422a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle instanceOfTrueBlock->InsertInstructionBefore(bound_type, insert_point); 423a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle } else { 424a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle // We already have a bound type on the position we would need to insert 425a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle // the new one. The existing bound type should dominate all the users 426a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle // (dchecked) so there's no need to continue. 427a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle break; 428b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle } 429b3306642f42d47ddb4d021a2f48ce9b1bd235857Calin Juravle } 430d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko user->ReplaceInput(bound_type, index); 431acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle } 432acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle } 433acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle} 434acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle 4357d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::SetClassAsTypeInfo(HInstruction* instr, 4367d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko mirror::Class* klass, 4377d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko bool is_exact) { 4382e76830f0b3f23825677436c0633714402715099Calin Juravle if (instr->IsInvokeStaticOrDirect() && instr->AsInvokeStaticOrDirect()->IsStringInit()) { 4392e76830f0b3f23825677436c0633714402715099Calin Juravle // Calls to String.<init> are replaced with a StringFactory. 4402e76830f0b3f23825677436c0633714402715099Calin Juravle if (kIsDebugBuild) { 441c89715ccaf4c8a8ce298ce2c0c1da479de4c63e7Nicolas Geoffray HInvoke* invoke = instr->AsInvoke(); 4422e76830f0b3f23825677436c0633714402715099Calin Juravle ClassLinker* cl = Runtime::Current()->GetClassLinker(); 443a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko Thread* self = Thread::Current(); 444a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko StackHandleScope<2> hs(self); 445c89715ccaf4c8a8ce298ce2c0c1da479de4c63e7Nicolas Geoffray Handle<mirror::DexCache> dex_cache( 446a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko hs.NewHandle(FindDexCacheWithHint(self, invoke->GetDexFile(), hint_dex_cache_))); 447c89715ccaf4c8a8ce298ce2c0c1da479de4c63e7Nicolas Geoffray // Use a null loader. We should probably use the compiling method's class loader, 448c89715ccaf4c8a8ce298ce2c0c1da479de4c63e7Nicolas Geoffray // but then we would need to pass it to RTPVisitor just for this debug check. Since 449c89715ccaf4c8a8ce298ce2c0c1da479de4c63e7Nicolas Geoffray // the method is from the String class, the null loader is good enough. 450c89715ccaf4c8a8ce298ce2c0c1da479de4c63e7Nicolas Geoffray Handle<mirror::ClassLoader> loader; 45142ef8ab151a3d0cbb42cb43f6841c3708d65fca3Andreas Gampe ArtMethod* method = cl->ResolveMethod<ClassLinker::kNoICCECheckForCache>( 452c89715ccaf4c8a8ce298ce2c0c1da479de4c63e7Nicolas Geoffray invoke->GetDexFile(), invoke->GetDexMethodIndex(), dex_cache, loader, nullptr, kDirect); 4532e76830f0b3f23825677436c0633714402715099Calin Juravle DCHECK(method != nullptr); 4542e76830f0b3f23825677436c0633714402715099Calin Juravle mirror::Class* declaring_class = method->GetDeclaringClass(); 4552e76830f0b3f23825677436c0633714402715099Calin Juravle DCHECK(declaring_class != nullptr); 4562e76830f0b3f23825677436c0633714402715099Calin Juravle DCHECK(declaring_class->IsStringClass()) 4572e76830f0b3f23825677436c0633714402715099Calin Juravle << "Expected String class: " << PrettyDescriptor(declaring_class); 4582e76830f0b3f23825677436c0633714402715099Calin Juravle DCHECK(method->IsConstructor()) 4592e76830f0b3f23825677436c0633714402715099Calin Juravle << "Expected String.<init>: " << PrettyMethod(method); 4602e76830f0b3f23825677436c0633714402715099Calin Juravle } 4612e76830f0b3f23825677436c0633714402715099Calin Juravle instr->SetReferenceTypeInfo( 4627d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true)); 463d1d7c40c8004303d1131ebb1956fd0ade54f8404Aart Bik } else if (IsAdmissible(klass)) { 464d1d7c40c8004303d1131ebb1956fd0ade54f8404Aart Bik ReferenceTypeInfo::TypeHandle handle = handle_cache_->NewHandle(klass); 465d1d7c40c8004303d1131ebb1956fd0ade54f8404Aart Bik is_exact = is_exact || handle->CannotBeAssignedFromOtherTypes(); 466d1d7c40c8004303d1131ebb1956fd0ade54f8404Aart Bik instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact)); 4672e76830f0b3f23825677436c0633714402715099Calin Juravle } else { 46818401b748a3180f52e42547ede22d1b184fe8c43Nicolas Geoffray instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti()); 469104fd8a3f30ddcf07831250571aa2a233cd5c04dGuillaume "Vermeille" Sanchez } 470104fd8a3f30ddcf07831250571aa2a233cd5c04dGuillaume "Vermeille" Sanchez} 471104fd8a3f30ddcf07831250571aa2a233cd5c04dGuillaume "Vermeille" Sanchez 4727d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr, 4737d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko uint16_t type_idx, 4747d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko const DexFile& dex_file, 4757d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko bool is_exact) { 47681d804a51d4fc415e1544a5a09505db049f4eda6Guillaume "Vermeille" Sanchez DCHECK_EQ(instr->GetType(), Primitive::kPrimNot); 47781d804a51d4fc415e1544a5a09505db049f4eda6Guillaume "Vermeille" Sanchez 478acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle ScopedObjectAccess soa(Thread::Current()); 479a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko mirror::DexCache* dex_cache = FindDexCacheWithHint(soa.Self(), dex_file, hint_dex_cache_); 480acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle // Get type from dex cache assuming it was populated by the verifier. 481222862ceaeed48528020412ef4f7b1cdaecf8789Guillaume Sanchez SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact); 482acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle} 483acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle 4847d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::VisitNewInstance(HNewInstance* instr) { 485222862ceaeed48528020412ef4f7b1cdaecf8789Guillaume Sanchez UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true); 48681d804a51d4fc415e1544a5a09505db049f4eda6Guillaume "Vermeille" Sanchez} 48781d804a51d4fc415e1544a5a09505db049f4eda6Guillaume "Vermeille" Sanchez 4887d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::VisitNewArray(HNewArray* instr) { 489222862ceaeed48528020412ef4f7b1cdaecf8789Guillaume Sanchez UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true); 49081d804a51d4fc415e1544a5a09505db049f4eda6Guillaume "Vermeille" Sanchez} 49181d804a51d4fc415e1544a5a09505db049f4eda6Guillaume "Vermeille" Sanchez 492a4336d253b88f95c49891a8084579a4599785e90Vladimir Markostatic mirror::Class* GetClassFromDexCache(Thread* self, 493a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko const DexFile& dex_file, 494a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko uint16_t type_idx, 495a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko Handle<mirror::DexCache> hint_dex_cache) 496e6e3beaf2d35d18a79f5e7b60a21e75fac9fd15dCalin Juravle SHARED_REQUIRES(Locks::mutator_lock_) { 497a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko mirror::DexCache* dex_cache = FindDexCacheWithHint(self, dex_file, hint_dex_cache); 498e6e3beaf2d35d18a79f5e7b60a21e75fac9fd15dCalin Juravle // Get type from dex cache assuming it was populated by the verifier. 499e6e3beaf2d35d18a79f5e7b60a21e75fac9fd15dCalin Juravle return dex_cache->GetResolvedType(type_idx); 500e6e3beaf2d35d18a79f5e7b60a21e75fac9fd15dCalin Juravle} 501e6e3beaf2d35d18a79f5e7b60a21e75fac9fd15dCalin Juravle 5027d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::VisitParameterValue(HParameterValue* instr) { 503e418dda75998e0186f7580c2c54705767c3c8f1fNicolas Geoffray // We check if the existing type is valid: the inliner may have set it. 504e418dda75998e0186f7580c2c54705767c3c8f1fNicolas Geoffray if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) { 505a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko ScopedObjectAccess soa(Thread::Current()); 506a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko mirror::Class* resolved_class = GetClassFromDexCache(soa.Self(), 507a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko instr->GetDexFile(), 508a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko instr->GetTypeIndex(), 509a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko hint_dex_cache_); 510e6e3beaf2d35d18a79f5e7b60a21e75fac9fd15dCalin Juravle SetClassAsTypeInfo(instr, resolved_class, /* is_exact */ false); 5112e76830f0b3f23825677436c0633714402715099Calin Juravle } 5122e76830f0b3f23825677436c0633714402715099Calin Juravle} 5132e76830f0b3f23825677436c0633714402715099Calin Juravle 5147d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr, 5157d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko const FieldInfo& info) { 516d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil if (instr->GetType() != Primitive::kPrimNot) { 517104fd8a3f30ddcf07831250571aa2a233cd5c04dGuillaume "Vermeille" Sanchez return; 518104fd8a3f30ddcf07831250571aa2a233cd5c04dGuillaume "Vermeille" Sanchez } 519104fd8a3f30ddcf07831250571aa2a233cd5c04dGuillaume "Vermeille" Sanchez 520104fd8a3f30ddcf07831250571aa2a233cd5c04dGuillaume "Vermeille" Sanchez ScopedObjectAccess soa(Thread::Current()); 521d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil mirror::Class* klass = nullptr; 522d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil 523d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil // The field index is unknown only during tests. 524d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil if (info.GetFieldIndex() != kUnknownFieldIndex) { 525d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil ClassLinker* cl = Runtime::Current()->GetClassLinker(); 526d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), info.GetDexCache().Get()); 527d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil // TODO: There are certain cases where we can't resolve the field. 528d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil // b/21914925 is open to keep track of a repro case for this issue. 529d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil if (field != nullptr) { 530d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil klass = field->GetType<false>(); 531d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil } 532d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil } 533d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil 5342e76830f0b3f23825677436c0633714402715099Calin Juravle SetClassAsTypeInfo(instr, klass, /* is_exact */ false); 535104fd8a3f30ddcf07831250571aa2a233cd5c04dGuillaume "Vermeille" Sanchez} 536104fd8a3f30ddcf07831250571aa2a233cd5c04dGuillaume "Vermeille" Sanchez 5377d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) { 538104fd8a3f30ddcf07831250571aa2a233cd5c04dGuillaume "Vermeille" Sanchez UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo()); 539104fd8a3f30ddcf07831250571aa2a233cd5c04dGuillaume "Vermeille" Sanchez} 540104fd8a3f30ddcf07831250571aa2a233cd5c04dGuillaume "Vermeille" Sanchez 5417d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) { 542104fd8a3f30ddcf07831250571aa2a233cd5c04dGuillaume "Vermeille" Sanchez UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo()); 543104fd8a3f30ddcf07831250571aa2a233cd5c04dGuillaume "Vermeille" Sanchez} 544104fd8a3f30ddcf07831250571aa2a233cd5c04dGuillaume "Vermeille" Sanchez 5457d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::VisitUnresolvedInstanceFieldGet( 5467d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko HUnresolvedInstanceFieldGet* instr) { 547e460d1df1f789c7c8bb97024a8efbd713ac175e9Calin Juravle // TODO: Use descriptor to get the actual type. 548e460d1df1f789c7c8bb97024a8efbd713ac175e9Calin Juravle if (instr->GetFieldType() == Primitive::kPrimNot) { 54918401b748a3180f52e42547ede22d1b184fe8c43Nicolas Geoffray instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti()); 550e460d1df1f789c7c8bb97024a8efbd713ac175e9Calin Juravle } 551e460d1df1f789c7c8bb97024a8efbd713ac175e9Calin Juravle} 552e460d1df1f789c7c8bb97024a8efbd713ac175e9Calin Juravle 5537d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::VisitUnresolvedStaticFieldGet( 5547d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko HUnresolvedStaticFieldGet* instr) { 555e460d1df1f789c7c8bb97024a8efbd713ac175e9Calin Juravle // TODO: Use descriptor to get the actual type. 556e460d1df1f789c7c8bb97024a8efbd713ac175e9Calin Juravle if (instr->GetFieldType() == Primitive::kPrimNot) { 55718401b748a3180f52e42547ede22d1b184fe8c43Nicolas Geoffray instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti()); 558e460d1df1f789c7c8bb97024a8efbd713ac175e9Calin Juravle } 559e460d1df1f789c7c8bb97024a8efbd713ac175e9Calin Juravle} 560e460d1df1f789c7c8bb97024a8efbd713ac175e9Calin Juravle 5617d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::VisitLoadClass(HLoadClass* instr) { 562acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle ScopedObjectAccess soa(Thread::Current()); 563acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle // Get type from dex cache assuming it was populated by the verifier. 564a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko mirror::Class* resolved_class = GetClassFromDexCache(soa.Self(), 565a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko instr->GetDexFile(), 566a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko instr->GetTypeIndex(), 567a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko hint_dex_cache_); 568d1d7c40c8004303d1131ebb1956fd0ade54f8404Aart Bik if (IsAdmissible(resolved_class)) { 56998893e146b0ff0e1fd1d7c29252f1d1e75a163f2Calin Juravle instr->SetLoadedClassRTI(ReferenceTypeInfo::Create( 5707d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko handle_cache_->NewHandle(resolved_class), /* is_exact */ true)); 57198893e146b0ff0e1fd1d7c29252f1d1e75a163f2Calin Juravle } 5727d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko instr->SetReferenceTypeInfo( 5737d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko ReferenceTypeInfo::Create(handle_cache_->GetClassClassHandle(), /* is_exact */ true)); 5742e76830f0b3f23825677436c0633714402715099Calin Juravle} 5752e76830f0b3f23825677436c0633714402715099Calin Juravle 5767d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::VisitClinitCheck(HClinitCheck* instr) { 5772e76830f0b3f23825677436c0633714402715099Calin Juravle instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo()); 5782e76830f0b3f23825677436c0633714402715099Calin Juravle} 5792e76830f0b3f23825677436c0633714402715099Calin Juravle 5807d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::VisitLoadString(HLoadString* instr) { 5817d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko instr->SetReferenceTypeInfo( 5827d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true)); 5832e76830f0b3f23825677436c0633714402715099Calin Juravle} 5842e76830f0b3f23825677436c0633714402715099Calin Juravle 5857d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::VisitLoadException(HLoadException* instr) { 586bbd733e4ef277eff19bf9a6601032da081e9b68fDavid Brazdil DCHECK(instr->GetBlock()->IsCatchBlock()); 587bbd733e4ef277eff19bf9a6601032da081e9b68fDavid Brazdil TryCatchInformation* catch_info = instr->GetBlock()->GetTryCatchInformation(); 588bbd733e4ef277eff19bf9a6601032da081e9b68fDavid Brazdil 589bbd733e4ef277eff19bf9a6601032da081e9b68fDavid Brazdil if (catch_info->IsCatchAllTypeIndex()) { 5907d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko instr->SetReferenceTypeInfo( 5917d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko ReferenceTypeInfo::Create(handle_cache_->GetThrowableClassHandle(), /* is_exact */ false)); 592bbd733e4ef277eff19bf9a6601032da081e9b68fDavid Brazdil } else { 593bbd733e4ef277eff19bf9a6601032da081e9b68fDavid Brazdil UpdateReferenceTypeInfo(instr, 594bbd733e4ef277eff19bf9a6601032da081e9b68fDavid Brazdil catch_info->GetCatchTypeIndex(), 595bbd733e4ef277eff19bf9a6601032da081e9b68fDavid Brazdil catch_info->GetCatchDexFile(), 596bbd733e4ef277eff19bf9a6601032da081e9b68fDavid Brazdil /* is_exact */ false); 597bbd733e4ef277eff19bf9a6601032da081e9b68fDavid Brazdil } 598bbd733e4ef277eff19bf9a6601032da081e9b68fDavid Brazdil} 599bbd733e4ef277eff19bf9a6601032da081e9b68fDavid Brazdil 6007d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::VisitNullCheck(HNullCheck* instr) { 6012e76830f0b3f23825677436c0633714402715099Calin Juravle ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo(); 602fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil if (parent_rti.IsValid()) { 603fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil instr->SetReferenceTypeInfo(parent_rti); 604fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil } 6052e76830f0b3f23825677436c0633714402715099Calin Juravle} 6062e76830f0b3f23825677436c0633714402715099Calin Juravle 6077d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::VisitBoundType(HBoundType* instr) { 608f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil ReferenceTypeInfo class_rti = instr->GetUpperBound(); 609f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil if (class_rti.IsValid()) { 610a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko ScopedObjectAccess soa(Thread::Current()); 611f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil // Narrow the type as much as possible. 612f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil HInstruction* obj = instr->InputAt(0); 613f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo(); 614f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil if (class_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes()) { 615f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil instr->SetReferenceTypeInfo( 616f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ true)); 617744a1c687fb92050828e188838b0ce5e0474f94aDavid Brazdil } else if (obj_rti.IsValid()) { 618744a1c687fb92050828e188838b0ce5e0474f94aDavid Brazdil if (class_rti.IsSupertypeOf(obj_rti)) { 619744a1c687fb92050828e188838b0ce5e0474f94aDavid Brazdil // Object type is more specific. 620744a1c687fb92050828e188838b0ce5e0474f94aDavid Brazdil instr->SetReferenceTypeInfo(obj_rti); 621744a1c687fb92050828e188838b0ce5e0474f94aDavid Brazdil } else { 622744a1c687fb92050828e188838b0ce5e0474f94aDavid Brazdil // Upper bound is more specific. 623744a1c687fb92050828e188838b0ce5e0474f94aDavid Brazdil instr->SetReferenceTypeInfo( 624744a1c687fb92050828e188838b0ce5e0474f94aDavid Brazdil ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false)); 625744a1c687fb92050828e188838b0ce5e0474f94aDavid Brazdil } 626f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil } else { 627744a1c687fb92050828e188838b0ce5e0474f94aDavid Brazdil // Object not typed yet. Leave BoundType untyped for now rather than 628744a1c687fb92050828e188838b0ce5e0474f94aDavid Brazdil // assign the type conservatively. 629f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil } 630f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil instr->SetCanBeNull(obj->CanBeNull() && instr->GetUpperCanBeNull()); 631f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil } else { 632f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil // The owner of the BoundType was already visited. If the class is unresolved, 633f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil // the BoundType should have been removed from the data flow and this method 634f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil // should remove it from the graph. 635f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil DCHECK(!instr->HasUses()); 636f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil instr->GetBlock()->RemoveInstruction(instr); 637f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil } 638f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil} 639f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil 6407d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::VisitCheckCast(HCheckCast* check_cast) { 64198893e146b0ff0e1fd1d7c29252f1d1e75a163f2Calin Juravle HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass(); 64298893e146b0ff0e1fd1d7c29252f1d1e75a163f2Calin Juravle ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI(); 643f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil HBoundType* bound_type = check_cast->GetNext()->AsBoundType(); 644f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil if (bound_type == nullptr || bound_type->GetUpperBound().IsValid()) { 645f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil // The next instruction is not an uninitialized BoundType. This must be 646f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil // an RTP pass after SsaBuilder and we do not need to do anything. 647f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil return; 64898893e146b0ff0e1fd1d7c29252f1d1e75a163f2Calin Juravle } 649f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil DCHECK_EQ(bound_type->InputAt(0), check_cast->InputAt(0)); 650f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil 651f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil if (class_rti.IsValid()) { 652d9994f069dfeaa32ba929ca78816b5b83e2a4134Nicolas Geoffray DCHECK(is_first_run_); 653f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil // This is the first run of RTP and class is resolved. 654f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil bound_type->SetUpperBound(class_rti, /* CheckCast succeeds for nulls. */ true); 655f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil } else { 656f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil // This is the first run of RTP and class is unresolved. Remove the binding. 657f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil // The instruction itself is removed in VisitBoundType so as to not 658f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil // invalidate HInstructionIterator. 659f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil bound_type->ReplaceWith(bound_type->InputAt(0)); 660a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle } 661a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle} 662a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle 663b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravlevoid ReferenceTypePropagation::VisitPhi(HPhi* phi) { 664d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil if (phi->IsDead() || phi->GetType() != Primitive::kPrimNot) { 665b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle return; 666acf735c13998ad2a175f5a17e7bfce220073279dCalin Juravle } 667b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle 668b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle if (phi->GetBlock()->IsLoopHeader()) { 669b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle // Set the initial type for the phi. Use the non back edge input for reaching 670b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle // a fixed point faster. 671fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil HInstruction* first_input = phi->InputAt(0); 672fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil ReferenceTypeInfo first_input_rti = first_input->GetReferenceTypeInfo(); 673fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil if (first_input_rti.IsValid() && !first_input->IsNullConstant()) { 674fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil phi->SetCanBeNull(first_input->CanBeNull()); 675fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil phi->SetReferenceTypeInfo(first_input_rti); 676fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil } 677b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle AddToWorklist(phi); 678b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle } else { 679b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle // Eagerly compute the type of the phi, for quicker convergence. Note 680b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle // that we don't need to add users to the worklist because we are 681b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle // doing a reverse post-order visit, therefore either the phi users are 682b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle // non-loop phi and will be visited later in the visit, or are loop-phis, 683b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle // and they are already in the work list. 684b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle UpdateNullability(phi); 685b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle UpdateReferenceTypeInfo(phi); 686b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle } 687b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle} 688b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle 689b1498f67b444c897fa8f1530777ef118e05aa631Calin JuravleReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a, 690b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle const ReferenceTypeInfo& b) { 6912e76830f0b3f23825677436c0633714402715099Calin Juravle if (!b.IsValid()) { 6922e76830f0b3f23825677436c0633714402715099Calin Juravle return a; 6932e76830f0b3f23825677436c0633714402715099Calin Juravle } 6942e76830f0b3f23825677436c0633714402715099Calin Juravle if (!a.IsValid()) { 6952e76830f0b3f23825677436c0633714402715099Calin Juravle return b; 6962e76830f0b3f23825677436c0633714402715099Calin Juravle } 6972e76830f0b3f23825677436c0633714402715099Calin Juravle 698b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle bool is_exact = a.IsExact() && b.IsExact(); 69952503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle ReferenceTypeInfo::TypeHandle result_type_handle; 70052503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle ReferenceTypeInfo::TypeHandle a_type_handle = a.GetTypeHandle(); 70152503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle ReferenceTypeInfo::TypeHandle b_type_handle = b.GetTypeHandle(); 70252503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle bool a_is_interface = a_type_handle->IsInterface(); 70352503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle bool b_is_interface = b_type_handle->IsInterface(); 704b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle 7052e76830f0b3f23825677436c0633714402715099Calin Juravle if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) { 70652503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle result_type_handle = a_type_handle; 7072e76830f0b3f23825677436c0633714402715099Calin Juravle } else if (a.IsSupertypeOf(b)) { 70852503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle result_type_handle = a_type_handle; 7092e76830f0b3f23825677436c0633714402715099Calin Juravle is_exact = false; 7102e76830f0b3f23825677436c0633714402715099Calin Juravle } else if (b.IsSupertypeOf(a)) { 71152503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle result_type_handle = b_type_handle; 71252503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle is_exact = false; 71352503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle } else if (!a_is_interface && !b_is_interface) { 7147d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko result_type_handle = 7157d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko handle_cache_.NewHandle(a_type_handle->GetCommonSuperClass(b_type_handle)); 7162e76830f0b3f23825677436c0633714402715099Calin Juravle is_exact = false; 7172e76830f0b3f23825677436c0633714402715099Calin Juravle } else { 71852503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle // This can happen if: 71952503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle // - both types are interfaces. TODO(calin): implement 72052503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle // - one is an interface, the other a class, and the type does not implement the interface 72152503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle // e.g: 72252503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle // void foo(Interface i, boolean cond) { 72352503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle // Object o = cond ? i : new Object(); 72452503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle // } 7257d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko result_type_handle = handle_cache_.GetObjectClassHandle(); 7262e76830f0b3f23825677436c0633714402715099Calin Juravle is_exact = false; 7272e76830f0b3f23825677436c0633714402715099Calin Juravle } 7282e76830f0b3f23825677436c0633714402715099Calin Juravle 72952503d83d057c66ea50eed491290e267b80e1fd3Calin Juravle return ReferenceTypeInfo::Create(result_type_handle, is_exact); 7302e76830f0b3f23825677436c0633714402715099Calin Juravle} 7312e76830f0b3f23825677436c0633714402715099Calin Juravle 7327d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::UpdateArrayGet(HArrayGet* instr, HandleCache* handle_cache) { 7332e76830f0b3f23825677436c0633714402715099Calin Juravle DCHECK_EQ(Primitive::kPrimNot, instr->GetType()); 7342e76830f0b3f23825677436c0633714402715099Calin Juravle 7352e76830f0b3f23825677436c0633714402715099Calin Juravle ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo(); 736fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil if (!parent_rti.IsValid()) { 737fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil return; 738fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil } 7392e76830f0b3f23825677436c0633714402715099Calin Juravle 7402e76830f0b3f23825677436c0633714402715099Calin Juravle Handle<mirror::Class> handle = parent_rti.GetTypeHandle(); 741d1d7c40c8004303d1131ebb1956fd0ade54f8404Aart Bik if (handle->IsObjectArrayClass() && IsAdmissible(handle->GetComponentType())) { 7427d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko ReferenceTypeInfo::TypeHandle component_handle = 7437d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko handle_cache->NewHandle(handle->GetComponentType()); 74418401b748a3180f52e42547ede22d1b184fe8c43Nicolas Geoffray bool is_exact = component_handle->CannotBeAssignedFromOtherTypes(); 74518401b748a3180f52e42547ede22d1b184fe8c43Nicolas Geoffray instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(component_handle, is_exact)); 7462e76830f0b3f23825677436c0633714402715099Calin Juravle } else { 7472e76830f0b3f23825677436c0633714402715099Calin Juravle // We don't know what the parent actually is, so we fallback to object. 74818401b748a3180f52e42547ede22d1b184fe8c43Nicolas Geoffray instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti()); 74920e6071362b84a9782b633a893c29ebde458205eCalin Juravle } 750b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle} 751b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle 752b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravlebool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) { 753b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle ScopedObjectAccess soa(Thread::Current()); 754b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle 755b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo(); 756b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle if (instr->IsBoundType()) { 757b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle UpdateBoundType(instr->AsBoundType()); 758b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle } else if (instr->IsPhi()) { 759b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle UpdatePhi(instr->AsPhi()); 7602e76830f0b3f23825677436c0633714402715099Calin Juravle } else if (instr->IsNullCheck()) { 7612e76830f0b3f23825677436c0633714402715099Calin Juravle ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo(); 7622e76830f0b3f23825677436c0633714402715099Calin Juravle if (parent_rti.IsValid()) { 7632e76830f0b3f23825677436c0633714402715099Calin Juravle instr->SetReferenceTypeInfo(parent_rti); 7642e76830f0b3f23825677436c0633714402715099Calin Juravle } 7652e76830f0b3f23825677436c0633714402715099Calin Juravle } else if (instr->IsArrayGet()) { 766fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil // TODO: consider if it's worth "looking back" and binding the input object 7672e76830f0b3f23825677436c0633714402715099Calin Juravle // to an array type. 7687d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko UpdateArrayGet(instr->AsArrayGet(), &handle_cache_); 76910e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle } else { 770b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle LOG(FATAL) << "Invalid instruction (should not get here)"; 771b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle } 772b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle 773b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle return !previous_rti.IsEqual(instr->GetReferenceTypeInfo()); 774b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle} 775b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle 7767d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::VisitInvoke(HInvoke* instr) { 777ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez if (instr->GetType() != Primitive::kPrimNot) { 778ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez return; 779ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez } 780ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez 781ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez ScopedObjectAccess soa(Thread::Current()); 782ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez ClassLinker* cl = Runtime::Current()->GetClassLinker(); 783a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko mirror::DexCache* dex_cache = 784a4336d253b88f95c49891a8084579a4599785e90Vladimir Marko FindDexCacheWithHint(soa.Self(), instr->GetDexFile(), hint_dex_cache_); 78505792b98980741111b4d0a24d68cff2a8e070a3aVladimir Marko size_t pointer_size = cl->GetImagePointerSize(); 78605792b98980741111b4d0a24d68cff2a8e070a3aVladimir Marko ArtMethod* method = dex_cache->GetResolvedMethod(instr->GetDexMethodIndex(), pointer_size); 78705792b98980741111b4d0a24d68cff2a8e070a3aVladimir Marko mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false, pointer_size); 7882e76830f0b3f23825677436c0633714402715099Calin Juravle SetClassAsTypeInfo(instr, klass, /* is_exact */ false); 789ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez} 790ae09d2d244cf2f506822b3e14731b81c3b278f9dGuillaume "Vermeille" Sanchez 7917d1fbf38412078090e81e9d9fa502635d8541707Vladimir Markovoid ReferenceTypePropagation::RTPVisitor::VisitArrayGet(HArrayGet* instr) { 79272a5eb5d6784b318750c36e0da25c7338557ce44Guillaume "Vermeille" Sanchez if (instr->GetType() != Primitive::kPrimNot) { 79372a5eb5d6784b318750c36e0da25c7338557ce44Guillaume "Vermeille" Sanchez return; 79472a5eb5d6784b318750c36e0da25c7338557ce44Guillaume "Vermeille" Sanchez } 795fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil 79672a5eb5d6784b318750c36e0da25c7338557ce44Guillaume "Vermeille" Sanchez ScopedObjectAccess soa(Thread::Current()); 7977d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko UpdateArrayGet(instr, handle_cache_); 7982e76830f0b3f23825677436c0633714402715099Calin Juravle if (!instr->GetReferenceTypeInfo().IsValid()) { 7992aaa4b5532d30c4e65d8892b556400bb61f9dc8cVladimir Marko worklist_->push_back(instr); 80072a5eb5d6784b318750c36e0da25c7338557ce44Guillaume "Vermeille" Sanchez } 80172a5eb5d6784b318750c36e0da25c7338557ce44Guillaume "Vermeille" Sanchez} 80272a5eb5d6784b318750c36e0da25c7338557ce44Guillaume "Vermeille" Sanchez 803b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravlevoid ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) { 804b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo(); 8052e76830f0b3f23825677436c0633714402715099Calin Juravle if (!new_rti.IsValid()) { 8062e76830f0b3f23825677436c0633714402715099Calin Juravle return; // No new info yet. 8072e76830f0b3f23825677436c0633714402715099Calin Juravle } 8082e76830f0b3f23825677436c0633714402715099Calin Juravle 8092e76830f0b3f23825677436c0633714402715099Calin Juravle // Make sure that we don't go over the bounded type. 810a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle ReferenceTypeInfo upper_bound_rti = instr->GetUpperBound(); 811a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle if (!upper_bound_rti.IsSupertypeOf(new_rti)) { 812e1dfa0c120c8aaa3794d9712e37231b4295d7c46Nicolas Geoffray // Note that the input might be exact, in which case we know the branch leading 813e1dfa0c120c8aaa3794d9712e37231b4295d7c46Nicolas Geoffray // to the bound type is dead. We play it safe by not marking the bound type as 814e1dfa0c120c8aaa3794d9712e37231b4295d7c46Nicolas Geoffray // exact. 815e1dfa0c120c8aaa3794d9712e37231b4295d7c46Nicolas Geoffray bool is_exact = upper_bound_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes(); 816e1dfa0c120c8aaa3794d9712e37231b4295d7c46Nicolas Geoffray new_rti = ReferenceTypeInfo::Create(upper_bound_rti.GetTypeHandle(), is_exact); 817b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle } 818b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle instr->SetReferenceTypeInfo(new_rti); 819b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle} 820b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle 821617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle// NullConstant inputs are ignored during merging as they do not provide any useful information. 822617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle// If all the inputs are NullConstants then the type of the phi will be set to Object. 823b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravlevoid ReferenceTypePropagation::UpdatePhi(HPhi* instr) { 824d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil DCHECK(instr->IsLive()); 825d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil 826617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle size_t input_count = instr->InputCount(); 827617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle size_t first_input_index_not_null = 0; 828617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle while (first_input_index_not_null < input_count && 829617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle instr->InputAt(first_input_index_not_null)->IsNullConstant()) { 830617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle first_input_index_not_null++; 831617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle } 832617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle if (first_input_index_not_null == input_count) { 833617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle // All inputs are NullConstants, set the type to object. 834617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle // This may happen in the presence of inlining. 83518401b748a3180f52e42547ede22d1b184fe8c43Nicolas Geoffray instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti()); 836617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle return; 837617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle } 838617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle 839617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle ReferenceTypeInfo new_rti = instr->InputAt(first_input_index_not_null)->GetReferenceTypeInfo(); 840617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle 8412e76830f0b3f23825677436c0633714402715099Calin Juravle if (new_rti.IsValid() && new_rti.IsObjectClass() && !new_rti.IsExact()) { 8422e76830f0b3f23825677436c0633714402715099Calin Juravle // Early return if we are Object and inexact. 843b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle instr->SetReferenceTypeInfo(new_rti); 844b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle return; 845b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle } 846617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle 847617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle for (size_t i = first_input_index_not_null + 1; i < input_count; i++) { 848617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle if (instr->InputAt(i)->IsNullConstant()) { 849617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle continue; 850617bd9255bbdb9890e9d80462d293b94ba41c1f2Calin Juravle } 851b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo()); 8522e76830f0b3f23825677436c0633714402715099Calin Juravle if (new_rti.IsValid() && new_rti.IsObjectClass()) { 853b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle if (!new_rti.IsExact()) { 854b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle break; 855b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle } else { 856b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle continue; 857d6138ef1ea13d07ae555542f8898b30d89e9ac9aNicolas Geoffray } 85810e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle } 85910e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle } 860fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil 861fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil if (new_rti.IsValid()) { 862fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil instr->SetReferenceTypeInfo(new_rti); 863fe86070bcbe938a5c8dec02b5a7d5efb632deed1David Brazdil } 864b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle} 865b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle 866b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle// Re-computes and updates the nullability of the instruction. Returns whether or 867b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle// not the nullability was changed. 868b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravlebool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) { 869d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil DCHECK((instr->IsPhi() && instr->AsPhi()->IsLive()) 8702e76830f0b3f23825677436c0633714402715099Calin Juravle || instr->IsBoundType() 8712e76830f0b3f23825677436c0633714402715099Calin Juravle || instr->IsNullCheck() 8722e76830f0b3f23825677436c0633714402715099Calin Juravle || instr->IsArrayGet()); 8732e76830f0b3f23825677436c0633714402715099Calin Juravle 8742e76830f0b3f23825677436c0633714402715099Calin Juravle if (!instr->IsPhi() && !instr->IsBoundType()) { 8752e76830f0b3f23825677436c0633714402715099Calin Juravle return false; 8762e76830f0b3f23825677436c0633714402715099Calin Juravle } 877b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle 878a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle bool existing_can_be_null = instr->CanBeNull(); 879a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle if (instr->IsPhi()) { 880a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle HPhi* phi = instr->AsPhi(); 881a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle bool new_can_be_null = false; 882a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle for (size_t i = 0; i < phi->InputCount(); i++) { 883a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle if (phi->InputAt(i)->CanBeNull()) { 884a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle new_can_be_null = true; 885a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle break; 886a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle } 887a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle } 888a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle phi->SetCanBeNull(new_can_be_null); 889a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle } else if (instr->IsBoundType()) { 890a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle HBoundType* bound_type = instr->AsBoundType(); 891a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle bound_type->SetCanBeNull(instr->InputAt(0)->CanBeNull() && bound_type->GetUpperCanBeNull()); 892b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravle } 893a5ae3c3f468ffe3a317b498d7fde1f8e9325346aCalin Juravle return existing_can_be_null != instr->CanBeNull(); 89410e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle} 89510e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle 89610e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravlevoid ReferenceTypePropagation::ProcessWorklist() { 8972aaa4b5532d30c4e65d8892b556400bb61f9dc8cVladimir Marko while (!worklist_.empty()) { 8982aaa4b5532d30c4e65d8892b556400bb61f9dc8cVladimir Marko HInstruction* instruction = worklist_.back(); 8992aaa4b5532d30c4e65d8892b556400bb61f9dc8cVladimir Marko worklist_.pop_back(); 90012617599757b625bd59e6c62e022c30735073622Calin Juravle bool updated_nullability = UpdateNullability(instruction); 90112617599757b625bd59e6c62e022c30735073622Calin Juravle bool updated_reference_type = UpdateReferenceTypeInfo(instruction); 90212617599757b625bd59e6c62e022c30735073622Calin Juravle if (updated_nullability || updated_reference_type) { 90310e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle AddDependentInstructionsToWorklist(instruction); 90410e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle } 90510e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle } 90610e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle} 90710e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle 908b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravlevoid ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) { 9092e76830f0b3f23825677436c0633714402715099Calin Juravle DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot) 9102e76830f0b3f23825677436c0633714402715099Calin Juravle << instruction->DebugName() << ":" << instruction->GetType(); 9112aaa4b5532d30c4e65d8892b556400bb61f9dc8cVladimir Marko worklist_.push_back(instruction); 91210e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle} 91310e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle 914b1498f67b444c897fa8f1530777ef118e05aa631Calin Juravlevoid ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) { 915d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) { 916d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko HInstruction* user = use.GetUser(); 917d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil if ((user->IsPhi() && user->AsPhi()->IsLive()) 9182e76830f0b3f23825677436c0633714402715099Calin Juravle || user->IsBoundType() 9192e76830f0b3f23825677436c0633714402715099Calin Juravle || user->IsNullCheck() 9202e76830f0b3f23825677436c0633714402715099Calin Juravle || (user->IsArrayGet() && (user->GetType() == Primitive::kPrimNot))) { 921beba9302bec33d72beb582970bf23d056f62641fCalin Juravle AddToWorklist(user); 92210e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle } 92310e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle } 92410e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle} 9257d1fbf38412078090e81e9d9fa502635d8541707Vladimir Marko 92610e244f9e7f6d96a95c910a2bedef5bd3810c637Calin Juravle} // namespace art 927