blob: d588deaace61aaeab07b3367143c674727348b66 [file] [log] [blame]
Calin Juravle10e244f2015-01-26 18:54:32 +00001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "reference_type_propagation.h"
18
Andreas Gampe542451c2016-07-26 09:02:02 -070019#include "base/enums.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070020#include "class_linker-inl.h"
Calin Juravleacf735c2015-02-12 15:25:22 +000021#include "mirror/class-inl.h"
22#include "mirror/dex_cache.h"
Mathieu Chartier0795f232016-09-27 18:43:30 -070023#include "scoped_thread_state_change-inl.h"
Calin Juravleacf735c2015-02-12 15:25:22 +000024
Calin Juravle10e244f2015-01-26 18:54:32 +000025namespace art {
26
Vladimir Marko456307a2016-04-19 14:12:13 +000027static inline mirror::DexCache* FindDexCacheWithHint(Thread* self,
28 const DexFile& dex_file,
29 Handle<mirror::DexCache> hint_dex_cache)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -070030 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko456307a2016-04-19 14:12:13 +000031 if (LIKELY(hint_dex_cache->GetDexFile() == &dex_file)) {
32 return hint_dex_cache.Get();
33 } else {
34 return Runtime::Current()->GetClassLinker()->FindDexCache(self, dex_file);
35 }
36}
37
Mathieu Chartiere8a3c572016-10-11 16:52:17 -070038static inline ReferenceTypeInfo::TypeHandle GetRootHandle(VariableSizedHandleScope* handles,
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000039 ClassLinker::ClassRoot class_root,
40 ReferenceTypeInfo::TypeHandle* cache) {
41 if (!ReferenceTypeInfo::IsValidHandle(*cache)) {
42 // Mutator lock is required for NewHandle.
43 ClassLinker* linker = Runtime::Current()->GetClassLinker();
44 ScopedObjectAccess soa(Thread::Current());
45 *cache = handles->NewHandle(linker->GetClassRoot(class_root));
46 }
47 return *cache;
48}
49
50ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetObjectClassHandle() {
51 return GetRootHandle(handles_, ClassLinker::kJavaLangObject, &object_class_handle_);
52}
53
54ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetClassClassHandle() {
55 return GetRootHandle(handles_, ClassLinker::kJavaLangClass, &class_class_handle_);
56}
57
58ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetStringClassHandle() {
59 return GetRootHandle(handles_, ClassLinker::kJavaLangString, &string_class_handle_);
60}
61
62ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetThrowableClassHandle() {
63 return GetRootHandle(handles_, ClassLinker::kJavaLangThrowable, &throwable_class_handle_);
64}
65
66class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor {
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010067 public:
Calin Juravle2e768302015-07-28 14:41:11 +000068 RTPVisitor(HGraph* graph,
Vladimir Marko456307a2016-04-19 14:12:13 +000069 Handle<mirror::DexCache> hint_dex_cache,
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000070 HandleCache* handle_cache,
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +000071 ArenaVector<HInstruction*>* worklist,
72 bool is_first_run)
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010073 : HGraphDelegateVisitor(graph),
Vladimir Marko456307a2016-04-19 14:12:13 +000074 hint_dex_cache_(hint_dex_cache),
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000075 handle_cache_(handle_cache),
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +000076 worklist_(worklist),
77 is_first_run_(is_first_run) {}
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010078
79 void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
80 void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000081 void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE;
82 void VisitLoadString(HLoadString* instr) OVERRIDE;
David Brazdilbbd733e2015-08-18 17:48:17 +010083 void VisitLoadException(HLoadException* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010084 void VisitNewArray(HNewArray* instr) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000085 void VisitParameterValue(HParameterValue* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010086 void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
Mathieu Chartier3398c782016-09-30 10:27:43 -070087 void SetClassAsTypeInfo(HInstruction* instr, ObjPtr<mirror::Class> klass, bool is_exact)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -070088 REQUIRES_SHARED(Locks::mutator_lock_);
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010089 void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE;
90 void VisitStaticFieldGet(HStaticFieldGet* instr) OVERRIDE;
Calin Juravlee460d1d2015-09-29 04:52:17 +010091 void VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instr) OVERRIDE;
92 void VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010093 void VisitInvoke(HInvoke* instr) OVERRIDE;
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +010094 void VisitArrayGet(HArrayGet* instr) OVERRIDE;
Calin Juravlea5ae3c32015-07-28 14:40:50 +000095 void VisitCheckCast(HCheckCast* instr) OVERRIDE;
David Brazdilf5552582015-12-27 13:36:12 +000096 void VisitBoundType(HBoundType* instr) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000097 void VisitNullCheck(HNullCheck* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010098 void UpdateReferenceTypeInfo(HInstruction* instr,
99 uint16_t type_idx,
100 const DexFile& dex_file,
101 bool is_exact);
102
103 private:
Vladimir Marko456307a2016-04-19 14:12:13 +0000104 Handle<mirror::DexCache> hint_dex_cache_;
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000105 HandleCache* handle_cache_;
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100106 ArenaVector<HInstruction*>* worklist_;
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000107 const bool is_first_run_;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100108};
109
Calin Juravle2e768302015-07-28 14:41:11 +0000110ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph,
Vladimir Marko456307a2016-04-19 14:12:13 +0000111 Handle<mirror::DexCache> hint_dex_cache,
Mathieu Chartiere8a3c572016-10-11 16:52:17 -0700112 VariableSizedHandleScope* handles,
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000113 bool is_first_run,
Calin Juravle2e768302015-07-28 14:41:11 +0000114 const char* name)
115 : HOptimization(graph, name),
Vladimir Marko456307a2016-04-19 14:12:13 +0000116 hint_dex_cache_(hint_dex_cache),
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000117 handle_cache_(handles),
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000118 worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)),
119 is_first_run_(is_first_run) {
Calin Juravle2e768302015-07-28 14:41:11 +0000120}
121
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000122void ReferenceTypePropagation::ValidateTypes() {
123 // TODO: move this to the graph checker.
Calin Juravle2e768302015-07-28 14:41:11 +0000124 if (kIsDebugBuild) {
Calin Juravle2e768302015-07-28 14:41:11 +0000125 ScopedObjectAccess soa(Thread::Current());
Vladimir Marko2c45bc92016-10-25 16:54:12 +0100126 for (HBasicBlock* block : graph_->GetReversePostOrder()) {
Calin Juravle2e768302015-07-28 14:41:11 +0000127 for (HInstructionIterator iti(block->GetInstructions()); !iti.Done(); iti.Advance()) {
128 HInstruction* instr = iti.Current();
129 if (instr->GetType() == Primitive::kPrimNot) {
130 DCHECK(instr->GetReferenceTypeInfo().IsValid())
131 << "Invalid RTI for instruction: " << instr->DebugName();
132 if (instr->IsBoundType()) {
133 DCHECK(instr->AsBoundType()->GetUpperBound().IsValid());
134 } else if (instr->IsLoadClass()) {
Calin Juravle98893e12015-10-02 21:05:03 +0100135 HLoadClass* cls = instr->AsLoadClass();
136 DCHECK(cls->GetReferenceTypeInfo().IsExact());
137 DCHECK(!cls->GetLoadedClassRTI().IsValid() || cls->GetLoadedClassRTI().IsExact());
Calin Juravle2e768302015-07-28 14:41:11 +0000138 } else if (instr->IsNullCheck()) {
139 DCHECK(instr->GetReferenceTypeInfo().IsEqual(instr->InputAt(0)->GetReferenceTypeInfo()))
140 << "NullCheck " << instr->GetReferenceTypeInfo()
141 << "Input(0) " << instr->InputAt(0)->GetReferenceTypeInfo();
142 }
143 }
144 }
145 }
146 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000147}
148
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000149void ReferenceTypePropagation::Visit(HInstruction* instruction) {
Vladimir Marko456307a2016-04-19 14:12:13 +0000150 RTPVisitor visitor(graph_, hint_dex_cache_, &handle_cache_, &worklist_, is_first_run_);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000151 instruction->Accept(&visitor);
152}
153
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000154void ReferenceTypePropagation::Run() {
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000155 worklist_.reserve(kDefaultWorklistSize);
156
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000157 // To properly propagate type info we need to visit in the dominator-based order.
158 // Reverse post order guarantees a node's dominators are visited first.
159 // We take advantage of this order in `VisitBasicBlock`.
Vladimir Marko2c45bc92016-10-25 16:54:12 +0100160 for (HBasicBlock* block : graph_->GetReversePostOrder()) {
161 VisitBasicBlock(block);
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000162 }
163
164 ProcessWorklist();
165 ValidateTypes();
166}
167
Calin Juravleb1498f62015-02-16 13:13:29 +0000168void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
Vladimir Marko456307a2016-04-19 14:12:13 +0000169 RTPVisitor visitor(graph_, hint_dex_cache_, &handle_cache_, &worklist_, is_first_run_);
Calin Juravle2e768302015-07-28 14:41:11 +0000170 // Handle Phis first as there might be instructions in the same block who depend on them.
171 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
172 VisitPhi(it.Current()->AsPhi());
173 }
Calin Juravlebeba9302015-07-08 15:57:18 +0000174
Calin Juravle2e768302015-07-28 14:41:11 +0000175 // Handle instructions.
Calin Juravleb1498f62015-02-16 13:13:29 +0000176 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
177 HInstruction* instr = it.Current();
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100178 instr->Accept(&visitor);
Calin Juravleb1498f62015-02-16 13:13:29 +0000179 }
180
Calin Juravleb1498f62015-02-16 13:13:29 +0000181 // Add extra nodes to bound types.
Calin Juravle61d544b2015-02-23 16:46:57 +0000182 BoundTypeForIfNotNull(block);
Calin Juravleb1498f62015-02-16 13:13:29 +0000183 BoundTypeForIfInstanceOf(block);
Calin Juravle10e244f2015-01-26 18:54:32 +0000184}
185
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000186// Check if we should create a bound type for the given object at the specified
187// position. Because of inlining and the fact we run RTP more than once and we
188// might have a HBoundType already. If we do, we should not create a new one.
189// In this case we also assert that there are no other uses of the object (except
190// the bound type) dominated by the specified dominator_instr or dominator_block.
191static bool ShouldCreateBoundType(HInstruction* position,
192 HInstruction* obj,
193 ReferenceTypeInfo upper_bound,
194 HInstruction* dominator_instr,
195 HBasicBlock* dominator_block)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700196 REQUIRES_SHARED(Locks::mutator_lock_) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000197 // If the position where we should insert the bound type is not already a
198 // a bound type then we need to create one.
199 if (position == nullptr || !position->IsBoundType()) {
200 return true;
201 }
202
203 HBoundType* existing_bound_type = position->AsBoundType();
204 if (existing_bound_type->GetUpperBound().IsSupertypeOf(upper_bound)) {
205 if (kIsDebugBuild) {
206 // Check that the existing HBoundType dominates all the uses.
Vladimir Marko46817b82016-03-29 12:21:58 +0100207 for (const HUseListNode<HInstruction*>& use : obj->GetUses()) {
208 HInstruction* user = use.GetUser();
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000209 if (dominator_instr != nullptr) {
210 DCHECK(!dominator_instr->StrictlyDominates(user)
211 || user == existing_bound_type
212 || existing_bound_type->StrictlyDominates(user));
213 } else if (dominator_block != nullptr) {
214 DCHECK(!dominator_block->Dominates(user->GetBlock())
215 || user == existing_bound_type
216 || existing_bound_type->StrictlyDominates(user));
217 }
218 }
219 }
220 } else {
221 // TODO: if the current bound type is a refinement we could update the
222 // existing_bound_type with the a new upper limit. However, we also need to
223 // update its users and have access to the work list.
224 }
225 return false;
226}
227
Calin Juravle61d544b2015-02-23 16:46:57 +0000228void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100229 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
230 if (ifInstruction == nullptr) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000231 return;
232 }
Calin Juravleb3306642015-04-20 18:30:42 +0100233 HInstruction* ifInput = ifInstruction->InputAt(0);
Calin Juravle61d544b2015-02-23 16:46:57 +0000234 if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) {
235 return;
236 }
237 HInstruction* input0 = ifInput->InputAt(0);
238 HInstruction* input1 = ifInput->InputAt(1);
Calin Juravleedad8ad2015-04-23 14:34:33 +0100239 HInstruction* obj = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000240
Calin Juravleedad8ad2015-04-23 14:34:33 +0100241 if (input1->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000242 obj = input0;
Calin Juravleedad8ad2015-04-23 14:34:33 +0100243 } else if (input0->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000244 obj = input1;
245 } else {
246 return;
247 }
248
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100249 if (!obj->CanBeNull() || obj->IsNullConstant()) {
250 // Null check is dead code and will be removed by DCE.
251 return;
252 }
253 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
254
Calin Juravleb3306642015-04-20 18:30:42 +0100255 // We only need to bound the type if we have uses in the relevant block.
256 // So start with null and create the HBoundType lazily, only if it's needed.
257 HBoundType* bound_type = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000258 HBasicBlock* notNullBlock = ifInput->IsNotEqual()
Calin Juravleb3306642015-04-20 18:30:42 +0100259 ? ifInstruction->IfTrueSuccessor()
260 : ifInstruction->IfFalseSuccessor();
261
Vladimir Marko46817b82016-03-29 12:21:58 +0100262 const HUseList<HInstruction*>& uses = obj->GetUses();
263 for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
264 HInstruction* user = it->GetUser();
265 size_t index = it->GetIndex();
266 // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput().
267 ++it;
Calin Juravle61d544b2015-02-23 16:46:57 +0000268 if (notNullBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100269 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000270 ScopedObjectAccess soa(Thread::Current());
271 HInstruction* insert_point = notNullBlock->GetFirstInstruction();
Calin Juravle2e768302015-07-28 14:41:11 +0000272 ReferenceTypeInfo object_rti = ReferenceTypeInfo::Create(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000273 handle_cache_.GetObjectClassHandle(), /* is_exact */ true);
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000274 if (ShouldCreateBoundType(insert_point, obj, object_rti, nullptr, notNullBlock)) {
David Brazdilf5552582015-12-27 13:36:12 +0000275 bound_type = new (graph_->GetArena()) HBoundType(obj);
276 bound_type->SetUpperBound(object_rti, /* bound_can_be_null */ false);
Calin Juravle2e768302015-07-28 14:41:11 +0000277 if (obj->GetReferenceTypeInfo().IsValid()) {
278 bound_type->SetReferenceTypeInfo(obj->GetReferenceTypeInfo());
279 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000280 notNullBlock->InsertInstructionBefore(bound_type, insert_point);
281 } else {
282 // We already have a bound type on the position we would need to insert
283 // the new one. The existing bound type should dominate all the users
284 // (dchecked) so there's no need to continue.
285 break;
286 }
Calin Juravleb3306642015-04-20 18:30:42 +0100287 }
Vladimir Marko46817b82016-03-29 12:21:58 +0100288 user->ReplaceInput(bound_type, index);
Calin Juravle61d544b2015-02-23 16:46:57 +0000289 }
290 }
291}
292
David Brazdild9510df2015-11-04 23:30:22 +0000293// Returns true if one of the patterns below has been recognized. If so, the
294// InstanceOf instruction together with the true branch of `ifInstruction` will
295// be returned using the out parameters.
296// Recognized patterns:
297// (1) patterns equivalent to `if (obj instanceof X)`
298// (a) InstanceOf -> Equal to 1 -> If
299// (b) InstanceOf -> NotEqual to 0 -> If
300// (c) InstanceOf -> If
301// (2) patterns equivalent to `if (!(obj instanceof X))`
302// (a) InstanceOf -> Equal to 0 -> If
303// (b) InstanceOf -> NotEqual to 1 -> If
304// (c) InstanceOf -> BooleanNot -> If
305static bool MatchIfInstanceOf(HIf* ifInstruction,
306 /* out */ HInstanceOf** instanceOf,
307 /* out */ HBasicBlock** trueBranch) {
308 HInstruction* input = ifInstruction->InputAt(0);
309
310 if (input->IsEqual()) {
311 HInstruction* rhs = input->AsEqual()->GetConstantRight();
312 if (rhs != nullptr) {
313 HInstruction* lhs = input->AsEqual()->GetLeastConstantLeft();
314 if (lhs->IsInstanceOf() && rhs->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +0000315 if (rhs->AsIntConstant()->IsTrue()) {
David Brazdild9510df2015-11-04 23:30:22 +0000316 // Case (1a)
317 *trueBranch = ifInstruction->IfTrueSuccessor();
318 } else {
319 // Case (2a)
Roland Levillain1a653882016-03-18 18:05:57 +0000320 DCHECK(rhs->AsIntConstant()->IsFalse()) << rhs->AsIntConstant()->GetValue();
David Brazdild9510df2015-11-04 23:30:22 +0000321 *trueBranch = ifInstruction->IfFalseSuccessor();
322 }
323 *instanceOf = lhs->AsInstanceOf();
324 return true;
325 }
326 }
327 } else if (input->IsNotEqual()) {
328 HInstruction* rhs = input->AsNotEqual()->GetConstantRight();
329 if (rhs != nullptr) {
330 HInstruction* lhs = input->AsNotEqual()->GetLeastConstantLeft();
331 if (lhs->IsInstanceOf() && rhs->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +0000332 if (rhs->AsIntConstant()->IsFalse()) {
David Brazdild9510df2015-11-04 23:30:22 +0000333 // Case (1b)
334 *trueBranch = ifInstruction->IfTrueSuccessor();
335 } else {
336 // Case (2b)
Roland Levillain1a653882016-03-18 18:05:57 +0000337 DCHECK(rhs->AsIntConstant()->IsTrue()) << rhs->AsIntConstant()->GetValue();
David Brazdild9510df2015-11-04 23:30:22 +0000338 *trueBranch = ifInstruction->IfFalseSuccessor();
339 }
340 *instanceOf = lhs->AsInstanceOf();
341 return true;
342 }
343 }
344 } else if (input->IsInstanceOf()) {
345 // Case (1c)
346 *instanceOf = input->AsInstanceOf();
347 *trueBranch = ifInstruction->IfTrueSuccessor();
348 return true;
349 } else if (input->IsBooleanNot()) {
350 HInstruction* not_input = input->InputAt(0);
351 if (not_input->IsInstanceOf()) {
352 // Case (2c)
353 *instanceOf = not_input->AsInstanceOf();
354 *trueBranch = ifInstruction->IfFalseSuccessor();
355 return true;
356 }
357 }
358
359 return false;
360}
361
Calin Juravleb1498f62015-02-16 13:13:29 +0000362// Detects if `block` is the True block for the pattern
363// `if (x instanceof ClassX) { }`
364// If that's the case insert an HBoundType instruction to bound the type of `x`
365// to `ClassX` in the scope of the dominated blocks.
366void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100367 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
368 if (ifInstruction == nullptr) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000369 return;
370 }
David Brazdil0d13fee2015-04-17 14:52:19 +0100371
David Brazdild9510df2015-11-04 23:30:22 +0000372 // Try to recognize common `if (instanceof)` and `if (!instanceof)` patterns.
373 HInstanceOf* instanceOf = nullptr;
374 HBasicBlock* instanceOfTrueBlock = nullptr;
375 if (!MatchIfInstanceOf(ifInstruction, &instanceOf, &instanceOfTrueBlock)) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000376 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000377 }
378
Calin Juravle98893e12015-10-02 21:05:03 +0100379 HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
380 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
381 {
Calin Juravle98893e12015-10-02 21:05:03 +0100382 if (!class_rti.IsValid()) {
383 // He have loaded an unresolved class. Don't bother bounding the type.
384 return;
385 }
386 }
Calin Juravleb3306642015-04-20 18:30:42 +0100387 // We only need to bound the type if we have uses in the relevant block.
388 // So start with null and create the HBoundType lazily, only if it's needed.
389 HBoundType* bound_type = nullptr;
390
Calin Juravleb1498f62015-02-16 13:13:29 +0000391 HInstruction* obj = instanceOf->InputAt(0);
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100392 if (obj->GetReferenceTypeInfo().IsExact() && !obj->IsPhi()) {
393 // This method is being called while doing a fixed-point calculation
394 // over phis. Non-phis instruction whose type is already known do
395 // not need to be bound to another type.
396 // Not that this also prevents replacing `HLoadClass` with a `HBoundType`.
397 // `HCheckCast` and `HInstanceOf` expect a `HLoadClass` as a second
398 // input.
399 return;
400 }
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100401 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
Vladimir Marko46817b82016-03-29 12:21:58 +0100402 const HUseList<HInstruction*>& uses = obj->GetUses();
403 for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
404 HInstruction* user = it->GetUser();
405 size_t index = it->GetIndex();
406 // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput().
407 ++it;
Calin Juravleb1498f62015-02-16 13:13:29 +0000408 if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100409 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000410 ScopedObjectAccess soa(Thread::Current());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000411 HInstruction* insert_point = instanceOfTrueBlock->GetFirstInstruction();
412 if (ShouldCreateBoundType(insert_point, obj, class_rti, nullptr, instanceOfTrueBlock)) {
David Brazdilf5552582015-12-27 13:36:12 +0000413 bound_type = new (graph_->GetArena()) HBoundType(obj);
414 bound_type->SetUpperBound(class_rti, /* InstanceOf fails for null. */ false);
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000415 instanceOfTrueBlock->InsertInstructionBefore(bound_type, insert_point);
416 } else {
417 // We already have a bound type on the position we would need to insert
418 // the new one. The existing bound type should dominate all the users
419 // (dchecked) so there's no need to continue.
420 break;
Calin Juravleb3306642015-04-20 18:30:42 +0100421 }
Calin Juravleb3306642015-04-20 18:30:42 +0100422 }
Vladimir Marko46817b82016-03-29 12:21:58 +0100423 user->ReplaceInput(bound_type, index);
Calin Juravleb1498f62015-02-16 13:13:29 +0000424 }
425 }
Calin Juravleacf735c2015-02-12 15:25:22 +0000426}
427
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000428void ReferenceTypePropagation::RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
Mathieu Chartier3398c782016-09-30 10:27:43 -0700429 ObjPtr<mirror::Class> klass,
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000430 bool is_exact) {
Calin Juravle2e768302015-07-28 14:41:11 +0000431 if (instr->IsInvokeStaticOrDirect() && instr->AsInvokeStaticOrDirect()->IsStringInit()) {
432 // Calls to String.<init> are replaced with a StringFactory.
433 if (kIsDebugBuild) {
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000434 HInvoke* invoke = instr->AsInvoke();
Calin Juravle2e768302015-07-28 14:41:11 +0000435 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Vladimir Marko62977ff2016-04-20 15:06:31 +0100436 Thread* self = Thread::Current();
437 StackHandleScope<2> hs(self);
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000438 Handle<mirror::DexCache> dex_cache(
Vladimir Marko62977ff2016-04-20 15:06:31 +0100439 hs.NewHandle(FindDexCacheWithHint(self, invoke->GetDexFile(), hint_dex_cache_)));
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000440 // Use a null loader. We should probably use the compiling method's class loader,
441 // but then we would need to pass it to RTPVisitor just for this debug check. Since
442 // the method is from the String class, the null loader is good enough.
443 Handle<mirror::ClassLoader> loader;
Andreas Gampe42ef8ab2015-12-03 17:27:32 -0800444 ArtMethod* method = cl->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000445 invoke->GetDexFile(), invoke->GetDexMethodIndex(), dex_cache, loader, nullptr, kDirect);
Calin Juravle2e768302015-07-28 14:41:11 +0000446 DCHECK(method != nullptr);
447 mirror::Class* declaring_class = method->GetDeclaringClass();
448 DCHECK(declaring_class != nullptr);
449 DCHECK(declaring_class->IsStringClass())
David Sehr709b0702016-10-13 09:12:37 -0700450 << "Expected String class: " << declaring_class->PrettyDescriptor();
Calin Juravle2e768302015-07-28 14:41:11 +0000451 DCHECK(method->IsConstructor())
David Sehr709b0702016-10-13 09:12:37 -0700452 << "Expected String.<init>: " << method->PrettyMethod();
Calin Juravle2e768302015-07-28 14:41:11 +0000453 }
454 instr->SetReferenceTypeInfo(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000455 ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
Mathieu Chartier1cc62e42016-10-03 18:01:28 -0700456 } else if (IsAdmissible(klass.Ptr())) {
Aart Bikf417ff42016-04-25 12:51:37 -0700457 ReferenceTypeInfo::TypeHandle handle = handle_cache_->NewHandle(klass);
458 is_exact = is_exact || handle->CannotBeAssignedFromOtherTypes();
459 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
Calin Juravle2e768302015-07-28 14:41:11 +0000460 } else {
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000461 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100462 }
463}
464
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000465void ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
466 uint16_t type_idx,
467 const DexFile& dex_file,
468 bool is_exact) {
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100469 DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
470
Calin Juravleacf735c2015-02-12 15:25:22 +0000471 ScopedObjectAccess soa(Thread::Current());
Vladimir Marko456307a2016-04-19 14:12:13 +0000472 mirror::DexCache* dex_cache = FindDexCacheWithHint(soa.Self(), dex_file, hint_dex_cache_);
Calin Juravleacf735c2015-02-12 15:25:22 +0000473 // Get type from dex cache assuming it was populated by the verifier.
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100474 SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact);
Calin Juravleacf735c2015-02-12 15:25:22 +0000475}
476
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000477void ReferenceTypePropagation::RTPVisitor::VisitNewInstance(HNewInstance* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100478 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100479}
480
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000481void ReferenceTypePropagation::RTPVisitor::VisitNewArray(HNewArray* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100482 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100483}
484
Vladimir Marko456307a2016-04-19 14:12:13 +0000485static mirror::Class* GetClassFromDexCache(Thread* self,
486 const DexFile& dex_file,
487 uint16_t type_idx,
488 Handle<mirror::DexCache> hint_dex_cache)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700489 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko456307a2016-04-19 14:12:13 +0000490 mirror::DexCache* dex_cache = FindDexCacheWithHint(self, dex_file, hint_dex_cache);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000491 // Get type from dex cache assuming it was populated by the verifier.
492 return dex_cache->GetResolvedType(type_idx);
493}
494
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000495void ReferenceTypePropagation::RTPVisitor::VisitParameterValue(HParameterValue* instr) {
Nicolas Geoffraye418dda2015-08-11 20:03:09 -0700496 // We check if the existing type is valid: the inliner may have set it.
497 if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) {
Vladimir Marko456307a2016-04-19 14:12:13 +0000498 ScopedObjectAccess soa(Thread::Current());
499 mirror::Class* resolved_class = GetClassFromDexCache(soa.Self(),
500 instr->GetDexFile(),
501 instr->GetTypeIndex(),
502 hint_dex_cache_);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000503 SetClassAsTypeInfo(instr, resolved_class, /* is_exact */ false);
Calin Juravle2e768302015-07-28 14:41:11 +0000504 }
505}
506
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000507void ReferenceTypePropagation::RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
508 const FieldInfo& info) {
David Brazdild9510df2015-11-04 23:30:22 +0000509 if (instr->GetType() != Primitive::kPrimNot) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100510 return;
511 }
512
Vladimir Marko62977ff2016-04-20 15:06:31 +0100513 ScopedObjectAccess soa(Thread::Current());
Mathieu Chartier3398c782016-09-30 10:27:43 -0700514 ObjPtr<mirror::Class> klass;
David Brazdild9510df2015-11-04 23:30:22 +0000515
516 // The field index is unknown only during tests.
517 if (info.GetFieldIndex() != kUnknownFieldIndex) {
518 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Mathieu Chartier28357fa2016-10-18 16:27:40 -0700519 ArtField* field = cl->GetResolvedField(info.GetFieldIndex(),
520 MakeObjPtr(info.GetDexCache().Get()));
David Brazdild9510df2015-11-04 23:30:22 +0000521 // TODO: There are certain cases where we can't resolve the field.
522 // b/21914925 is open to keep track of a repro case for this issue.
523 if (field != nullptr) {
524 klass = field->GetType<false>();
525 }
526 }
527
Calin Juravle2e768302015-07-28 14:41:11 +0000528 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100529}
530
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000531void ReferenceTypePropagation::RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100532 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
533}
534
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000535void ReferenceTypePropagation::RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100536 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
537}
538
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000539void ReferenceTypePropagation::RTPVisitor::VisitUnresolvedInstanceFieldGet(
540 HUnresolvedInstanceFieldGet* instr) {
Calin Juravlee460d1d2015-09-29 04:52:17 +0100541 // TODO: Use descriptor to get the actual type.
542 if (instr->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000543 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Calin Juravlee460d1d2015-09-29 04:52:17 +0100544 }
545}
546
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000547void ReferenceTypePropagation::RTPVisitor::VisitUnresolvedStaticFieldGet(
548 HUnresolvedStaticFieldGet* instr) {
Calin Juravlee460d1d2015-09-29 04:52:17 +0100549 // TODO: Use descriptor to get the actual type.
550 if (instr->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000551 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Calin Juravlee460d1d2015-09-29 04:52:17 +0100552 }
553}
554
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000555void ReferenceTypePropagation::RTPVisitor::VisitLoadClass(HLoadClass* instr) {
Calin Juravleacf735c2015-02-12 15:25:22 +0000556 ScopedObjectAccess soa(Thread::Current());
Calin Juravleacf735c2015-02-12 15:25:22 +0000557 // Get type from dex cache assuming it was populated by the verifier.
Vladimir Marko456307a2016-04-19 14:12:13 +0000558 mirror::Class* resolved_class = GetClassFromDexCache(soa.Self(),
559 instr->GetDexFile(),
560 instr->GetTypeIndex(),
561 hint_dex_cache_);
Aart Bikf417ff42016-04-25 12:51:37 -0700562 if (IsAdmissible(resolved_class)) {
Calin Juravle98893e12015-10-02 21:05:03 +0100563 instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000564 handle_cache_->NewHandle(resolved_class), /* is_exact */ true));
Calin Juravle98893e12015-10-02 21:05:03 +0100565 }
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000566 instr->SetReferenceTypeInfo(
567 ReferenceTypeInfo::Create(handle_cache_->GetClassClassHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000568}
569
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000570void ReferenceTypePropagation::RTPVisitor::VisitClinitCheck(HClinitCheck* instr) {
Calin Juravle2e768302015-07-28 14:41:11 +0000571 instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
572}
573
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000574void ReferenceTypePropagation::RTPVisitor::VisitLoadString(HLoadString* instr) {
575 instr->SetReferenceTypeInfo(
576 ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000577}
578
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000579void ReferenceTypePropagation::RTPVisitor::VisitLoadException(HLoadException* instr) {
David Brazdilbbd733e2015-08-18 17:48:17 +0100580 DCHECK(instr->GetBlock()->IsCatchBlock());
581 TryCatchInformation* catch_info = instr->GetBlock()->GetTryCatchInformation();
582
583 if (catch_info->IsCatchAllTypeIndex()) {
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000584 instr->SetReferenceTypeInfo(
585 ReferenceTypeInfo::Create(handle_cache_->GetThrowableClassHandle(), /* is_exact */ false));
David Brazdilbbd733e2015-08-18 17:48:17 +0100586 } else {
587 UpdateReferenceTypeInfo(instr,
588 catch_info->GetCatchTypeIndex(),
589 catch_info->GetCatchDexFile(),
590 /* is_exact */ false);
591 }
592}
593
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000594void ReferenceTypePropagation::RTPVisitor::VisitNullCheck(HNullCheck* instr) {
Calin Juravle2e768302015-07-28 14:41:11 +0000595 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
David Brazdilfe860702015-12-02 09:06:57 +0000596 if (parent_rti.IsValid()) {
597 instr->SetReferenceTypeInfo(parent_rti);
598 }
Calin Juravle2e768302015-07-28 14:41:11 +0000599}
600
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000601void ReferenceTypePropagation::RTPVisitor::VisitBoundType(HBoundType* instr) {
David Brazdilf5552582015-12-27 13:36:12 +0000602 ReferenceTypeInfo class_rti = instr->GetUpperBound();
603 if (class_rti.IsValid()) {
Vladimir Marko456307a2016-04-19 14:12:13 +0000604 ScopedObjectAccess soa(Thread::Current());
David Brazdilf5552582015-12-27 13:36:12 +0000605 // Narrow the type as much as possible.
606 HInstruction* obj = instr->InputAt(0);
607 ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo();
608 if (class_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes()) {
609 instr->SetReferenceTypeInfo(
610 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ true));
David Brazdil744a1c62015-12-28 10:53:34 +0000611 } else if (obj_rti.IsValid()) {
612 if (class_rti.IsSupertypeOf(obj_rti)) {
613 // Object type is more specific.
614 instr->SetReferenceTypeInfo(obj_rti);
615 } else {
616 // Upper bound is more specific.
617 instr->SetReferenceTypeInfo(
618 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
619 }
David Brazdilf5552582015-12-27 13:36:12 +0000620 } else {
David Brazdil744a1c62015-12-28 10:53:34 +0000621 // Object not typed yet. Leave BoundType untyped for now rather than
622 // assign the type conservatively.
David Brazdilf5552582015-12-27 13:36:12 +0000623 }
624 instr->SetCanBeNull(obj->CanBeNull() && instr->GetUpperCanBeNull());
625 } else {
626 // The owner of the BoundType was already visited. If the class is unresolved,
627 // the BoundType should have been removed from the data flow and this method
628 // should remove it from the graph.
629 DCHECK(!instr->HasUses());
630 instr->GetBlock()->RemoveInstruction(instr);
631 }
632}
633
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000634void ReferenceTypePropagation::RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
Calin Juravle98893e12015-10-02 21:05:03 +0100635 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
636 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
David Brazdilf5552582015-12-27 13:36:12 +0000637 HBoundType* bound_type = check_cast->GetNext()->AsBoundType();
638 if (bound_type == nullptr || bound_type->GetUpperBound().IsValid()) {
639 // The next instruction is not an uninitialized BoundType. This must be
640 // an RTP pass after SsaBuilder and we do not need to do anything.
641 return;
Calin Juravle98893e12015-10-02 21:05:03 +0100642 }
David Brazdilf5552582015-12-27 13:36:12 +0000643 DCHECK_EQ(bound_type->InputAt(0), check_cast->InputAt(0));
644
645 if (class_rti.IsValid()) {
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000646 DCHECK(is_first_run_);
David Brazdilf5552582015-12-27 13:36:12 +0000647 // This is the first run of RTP and class is resolved.
648 bound_type->SetUpperBound(class_rti, /* CheckCast succeeds for nulls. */ true);
649 } else {
650 // This is the first run of RTP and class is unresolved. Remove the binding.
651 // The instruction itself is removed in VisitBoundType so as to not
652 // invalidate HInstructionIterator.
653 bound_type->ReplaceWith(bound_type->InputAt(0));
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000654 }
655}
656
Calin Juravleb1498f62015-02-16 13:13:29 +0000657void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
David Brazdild9510df2015-11-04 23:30:22 +0000658 if (phi->IsDead() || phi->GetType() != Primitive::kPrimNot) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000659 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000660 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000661
662 if (phi->GetBlock()->IsLoopHeader()) {
663 // Set the initial type for the phi. Use the non back edge input for reaching
664 // a fixed point faster.
David Brazdilfe860702015-12-02 09:06:57 +0000665 HInstruction* first_input = phi->InputAt(0);
666 ReferenceTypeInfo first_input_rti = first_input->GetReferenceTypeInfo();
667 if (first_input_rti.IsValid() && !first_input->IsNullConstant()) {
668 phi->SetCanBeNull(first_input->CanBeNull());
669 phi->SetReferenceTypeInfo(first_input_rti);
670 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000671 AddToWorklist(phi);
Calin Juravle10e244f2015-01-26 18:54:32 +0000672 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000673 // Eagerly compute the type of the phi, for quicker convergence. Note
674 // that we don't need to add users to the worklist because we are
675 // doing a reverse post-order visit, therefore either the phi users are
676 // non-loop phi and will be visited later in the visit, or are loop-phis,
677 // and they are already in the work list.
678 UpdateNullability(phi);
679 UpdateReferenceTypeInfo(phi);
680 }
681}
682
683ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
684 const ReferenceTypeInfo& b) {
Calin Juravle2e768302015-07-28 14:41:11 +0000685 if (!b.IsValid()) {
686 return a;
687 }
688 if (!a.IsValid()) {
689 return b;
Calin Juravle20e60712015-07-01 18:41:04 +0100690 }
691
Calin Juravle2e768302015-07-28 14:41:11 +0000692 bool is_exact = a.IsExact() && b.IsExact();
Calin Juravle52503d82015-11-11 16:58:31 +0000693 ReferenceTypeInfo::TypeHandle result_type_handle;
694 ReferenceTypeInfo::TypeHandle a_type_handle = a.GetTypeHandle();
695 ReferenceTypeInfo::TypeHandle b_type_handle = b.GetTypeHandle();
696 bool a_is_interface = a_type_handle->IsInterface();
697 bool b_is_interface = b_type_handle->IsInterface();
Calin Juravle2e768302015-07-28 14:41:11 +0000698
699 if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
Calin Juravle52503d82015-11-11 16:58:31 +0000700 result_type_handle = a_type_handle;
Calin Juravle2e768302015-07-28 14:41:11 +0000701 } else if (a.IsSupertypeOf(b)) {
Calin Juravle52503d82015-11-11 16:58:31 +0000702 result_type_handle = a_type_handle;
Calin Juravle2e768302015-07-28 14:41:11 +0000703 is_exact = false;
704 } else if (b.IsSupertypeOf(a)) {
Calin Juravle52503d82015-11-11 16:58:31 +0000705 result_type_handle = b_type_handle;
706 is_exact = false;
707 } else if (!a_is_interface && !b_is_interface) {
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000708 result_type_handle =
709 handle_cache_.NewHandle(a_type_handle->GetCommonSuperClass(b_type_handle));
Calin Juravle2e768302015-07-28 14:41:11 +0000710 is_exact = false;
711 } else {
Calin Juravle52503d82015-11-11 16:58:31 +0000712 // This can happen if:
713 // - both types are interfaces. TODO(calin): implement
714 // - one is an interface, the other a class, and the type does not implement the interface
715 // e.g:
716 // void foo(Interface i, boolean cond) {
717 // Object o = cond ? i : new Object();
718 // }
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000719 result_type_handle = handle_cache_.GetObjectClassHandle();
Calin Juravle2e768302015-07-28 14:41:11 +0000720 is_exact = false;
721 }
722
Calin Juravle52503d82015-11-11 16:58:31 +0000723 return ReferenceTypeInfo::Create(result_type_handle, is_exact);
Calin Juravle2e768302015-07-28 14:41:11 +0000724}
725
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000726void ReferenceTypePropagation::UpdateArrayGet(HArrayGet* instr, HandleCache* handle_cache) {
Calin Juravle2e768302015-07-28 14:41:11 +0000727 DCHECK_EQ(Primitive::kPrimNot, instr->GetType());
728
729 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
David Brazdilfe860702015-12-02 09:06:57 +0000730 if (!parent_rti.IsValid()) {
731 return;
732 }
Calin Juravle2e768302015-07-28 14:41:11 +0000733
734 Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
Aart Bikf417ff42016-04-25 12:51:37 -0700735 if (handle->IsObjectArrayClass() && IsAdmissible(handle->GetComponentType())) {
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000736 ReferenceTypeInfo::TypeHandle component_handle =
737 handle_cache->NewHandle(handle->GetComponentType());
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000738 bool is_exact = component_handle->CannotBeAssignedFromOtherTypes();
739 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(component_handle, is_exact));
Calin Juravle2e768302015-07-28 14:41:11 +0000740 } else {
741 // We don't know what the parent actually is, so we fallback to object.
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000742 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Calin Juravle2e768302015-07-28 14:41:11 +0000743 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000744}
745
746bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
747 ScopedObjectAccess soa(Thread::Current());
748
749 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
750 if (instr->IsBoundType()) {
751 UpdateBoundType(instr->AsBoundType());
752 } else if (instr->IsPhi()) {
753 UpdatePhi(instr->AsPhi());
Calin Juravle2e768302015-07-28 14:41:11 +0000754 } else if (instr->IsNullCheck()) {
755 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
756 if (parent_rti.IsValid()) {
757 instr->SetReferenceTypeInfo(parent_rti);
758 }
759 } else if (instr->IsArrayGet()) {
David Brazdilfe860702015-12-02 09:06:57 +0000760 // TODO: consider if it's worth "looking back" and binding the input object
Calin Juravle2e768302015-07-28 14:41:11 +0000761 // to an array type.
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000762 UpdateArrayGet(instr->AsArrayGet(), &handle_cache_);
Calin Juravleb1498f62015-02-16 13:13:29 +0000763 } else {
764 LOG(FATAL) << "Invalid instruction (should not get here)";
765 }
766
767 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
768}
769
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000770void ReferenceTypePropagation::RTPVisitor::VisitInvoke(HInvoke* instr) {
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100771 if (instr->GetType() != Primitive::kPrimNot) {
772 return;
773 }
774
775 ScopedObjectAccess soa(Thread::Current());
776 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Vladimir Marko456307a2016-04-19 14:12:13 +0000777 mirror::DexCache* dex_cache =
778 FindDexCacheWithHint(soa.Self(), instr->GetDexFile(), hint_dex_cache_);
Andreas Gampe542451c2016-07-26 09:02:02 -0700779 PointerSize pointer_size = cl->GetImagePointerSize();
Vladimir Marko05792b92015-08-03 11:56:49 +0100780 ArtMethod* method = dex_cache->GetResolvedMethod(instr->GetDexMethodIndex(), pointer_size);
781 mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false, pointer_size);
Calin Juravle2e768302015-07-28 14:41:11 +0000782 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100783}
784
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000785void ReferenceTypePropagation::RTPVisitor::VisitArrayGet(HArrayGet* instr) {
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100786 if (instr->GetType() != Primitive::kPrimNot) {
787 return;
788 }
David Brazdilfe860702015-12-02 09:06:57 +0000789
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100790 ScopedObjectAccess soa(Thread::Current());
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000791 UpdateArrayGet(instr, handle_cache_);
Calin Juravle2e768302015-07-28 14:41:11 +0000792 if (!instr->GetReferenceTypeInfo().IsValid()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100793 worklist_->push_back(instr);
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100794 }
795}
796
Calin Juravleb1498f62015-02-16 13:13:29 +0000797void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
798 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle2e768302015-07-28 14:41:11 +0000799 if (!new_rti.IsValid()) {
800 return; // No new info yet.
801 }
802
803 // Make sure that we don't go over the bounded type.
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000804 ReferenceTypeInfo upper_bound_rti = instr->GetUpperBound();
805 if (!upper_bound_rti.IsSupertypeOf(new_rti)) {
Nicolas Geoffraya90d4892016-06-01 16:30:20 +0100806 // Note that the input might be exact, in which case we know the branch leading
807 // to the bound type is dead. We play it safe by not marking the bound type as
808 // exact.
809 bool is_exact = upper_bound_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes();
810 new_rti = ReferenceTypeInfo::Create(upper_bound_rti.GetTypeHandle(), is_exact);
Calin Juravleb1498f62015-02-16 13:13:29 +0000811 }
812 instr->SetReferenceTypeInfo(new_rti);
813}
814
Calin Juravle617bd922015-11-11 14:59:46 +0000815// NullConstant inputs are ignored during merging as they do not provide any useful information.
816// If all the inputs are NullConstants then the type of the phi will be set to Object.
Calin Juravleb1498f62015-02-16 13:13:29 +0000817void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
David Brazdild9510df2015-11-04 23:30:22 +0000818 DCHECK(instr->IsLive());
819
Vladimir Markoe9004912016-06-16 16:50:52 +0100820 HInputsRef inputs = instr->GetInputs();
Calin Juravle617bd922015-11-11 14:59:46 +0000821 size_t first_input_index_not_null = 0;
Vladimir Marko372f10e2016-05-17 16:30:10 +0100822 while (first_input_index_not_null < inputs.size() &&
Vladimir Markoe9004912016-06-16 16:50:52 +0100823 inputs[first_input_index_not_null]->IsNullConstant()) {
Calin Juravle617bd922015-11-11 14:59:46 +0000824 first_input_index_not_null++;
825 }
Vladimir Marko372f10e2016-05-17 16:30:10 +0100826 if (first_input_index_not_null == inputs.size()) {
Calin Juravle617bd922015-11-11 14:59:46 +0000827 // All inputs are NullConstants, set the type to object.
828 // This may happen in the presence of inlining.
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000829 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Calin Juravle617bd922015-11-11 14:59:46 +0000830 return;
831 }
832
833 ReferenceTypeInfo new_rti = instr->InputAt(first_input_index_not_null)->GetReferenceTypeInfo();
834
Calin Juravle2e768302015-07-28 14:41:11 +0000835 if (new_rti.IsValid() && new_rti.IsObjectClass() && !new_rti.IsExact()) {
836 // Early return if we are Object and inexact.
Calin Juravleb1498f62015-02-16 13:13:29 +0000837 instr->SetReferenceTypeInfo(new_rti);
838 return;
839 }
Calin Juravle617bd922015-11-11 14:59:46 +0000840
Vladimir Marko372f10e2016-05-17 16:30:10 +0100841 for (size_t i = first_input_index_not_null + 1; i < inputs.size(); i++) {
842 if (inputs[i]->IsNullConstant()) {
Calin Juravle617bd922015-11-11 14:59:46 +0000843 continue;
844 }
Vladimir Marko372f10e2016-05-17 16:30:10 +0100845 new_rti = MergeTypes(new_rti, inputs[i]->GetReferenceTypeInfo());
Calin Juravle2e768302015-07-28 14:41:11 +0000846 if (new_rti.IsValid() && new_rti.IsObjectClass()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000847 if (!new_rti.IsExact()) {
848 break;
849 } else {
850 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000851 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000852 }
853 }
David Brazdilfe860702015-12-02 09:06:57 +0000854
855 if (new_rti.IsValid()) {
856 instr->SetReferenceTypeInfo(new_rti);
857 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000858}
859
860// Re-computes and updates the nullability of the instruction. Returns whether or
861// not the nullability was changed.
862bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
David Brazdild9510df2015-11-04 23:30:22 +0000863 DCHECK((instr->IsPhi() && instr->AsPhi()->IsLive())
Calin Juravle2e768302015-07-28 14:41:11 +0000864 || instr->IsBoundType()
865 || instr->IsNullCheck()
866 || instr->IsArrayGet());
867
868 if (!instr->IsPhi() && !instr->IsBoundType()) {
869 return false;
870 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000871
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000872 bool existing_can_be_null = instr->CanBeNull();
873 if (instr->IsPhi()) {
874 HPhi* phi = instr->AsPhi();
875 bool new_can_be_null = false;
Vladimir Marko372f10e2016-05-17 16:30:10 +0100876 for (HInstruction* input : phi->GetInputs()) {
877 if (input->CanBeNull()) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000878 new_can_be_null = true;
879 break;
880 }
881 }
882 phi->SetCanBeNull(new_can_be_null);
883 } else if (instr->IsBoundType()) {
884 HBoundType* bound_type = instr->AsBoundType();
885 bound_type->SetCanBeNull(instr->InputAt(0)->CanBeNull() && bound_type->GetUpperCanBeNull());
Calin Juravleb1498f62015-02-16 13:13:29 +0000886 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000887 return existing_can_be_null != instr->CanBeNull();
Calin Juravle10e244f2015-01-26 18:54:32 +0000888}
889
890void ReferenceTypePropagation::ProcessWorklist() {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100891 while (!worklist_.empty()) {
892 HInstruction* instruction = worklist_.back();
893 worklist_.pop_back();
Calin Juravle12617592015-10-16 16:28:46 +0100894 bool updated_nullability = UpdateNullability(instruction);
895 bool updated_reference_type = UpdateReferenceTypeInfo(instruction);
896 if (updated_nullability || updated_reference_type) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000897 AddDependentInstructionsToWorklist(instruction);
898 }
899 }
900}
901
Calin Juravleb1498f62015-02-16 13:13:29 +0000902void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
Calin Juravle2e768302015-07-28 14:41:11 +0000903 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot)
904 << instruction->DebugName() << ":" << instruction->GetType();
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100905 worklist_.push_back(instruction);
Calin Juravle10e244f2015-01-26 18:54:32 +0000906}
907
Calin Juravleb1498f62015-02-16 13:13:29 +0000908void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Vladimir Marko46817b82016-03-29 12:21:58 +0100909 for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
910 HInstruction* user = use.GetUser();
David Brazdild9510df2015-11-04 23:30:22 +0000911 if ((user->IsPhi() && user->AsPhi()->IsLive())
Calin Juravle2e768302015-07-28 14:41:11 +0000912 || user->IsBoundType()
913 || user->IsNullCheck()
914 || (user->IsArrayGet() && (user->GetType() == Primitive::kPrimNot))) {
Calin Juravlebeba9302015-07-08 15:57:18 +0000915 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000916 }
917 }
918}
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000919
Calin Juravle10e244f2015-01-26 18:54:32 +0000920} // namespace art