blob: 68316c26184c37ba7a87ec0e58f922d77d1c6293 [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
Mathieu Chartiere401d142015-04-22 13:56:20 -070019#include "class_linker-inl.h"
Calin Juravleacf735c2015-02-12 15:25:22 +000020#include "mirror/class-inl.h"
21#include "mirror/dex_cache.h"
22#include "scoped_thread_state_change.h"
23
Calin Juravle10e244f2015-01-26 18:54:32 +000024namespace art {
25
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010026class RTPVisitor : public HGraphDelegateVisitor {
27 public:
28 RTPVisitor(HGraph* graph, StackHandleScopeCollection* handles)
29 : HGraphDelegateVisitor(graph),
30 handles_(handles) {}
31
32 void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
33 void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
34 void VisitNewArray(HNewArray* instr) OVERRIDE;
35 void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
36 void SetClassAsTypeInfo(HInstruction* instr, mirror::Class* klass, bool is_exact);
37 void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE;
38 void VisitStaticFieldGet(HStaticFieldGet* instr) OVERRIDE;
39 void VisitInvoke(HInvoke* instr) OVERRIDE;
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +010040 void VisitArrayGet(HArrayGet* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010041 void UpdateReferenceTypeInfo(HInstruction* instr,
42 uint16_t type_idx,
43 const DexFile& dex_file,
44 bool is_exact);
45
46 private:
47 StackHandleScopeCollection* handles_;
48};
49
Calin Juravleacf735c2015-02-12 15:25:22 +000050void ReferenceTypePropagation::Run() {
51 // To properly propagate type info we need to visit in the dominator-based order.
Calin Juravle10e244f2015-01-26 18:54:32 +000052 // Reverse post order guarantees a node's dominators are visited first.
53 // We take advantage of this order in `VisitBasicBlock`.
Calin Juravle6c0c4f22015-06-12 15:40:42 +000054 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
Calin Juravle10e244f2015-01-26 18:54:32 +000055 VisitBasicBlock(it.Current());
56 }
57 ProcessWorklist();
58}
59
Calin Juravleb1498f62015-02-16 13:13:29 +000060void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
61 // TODO: handle other instructions that give type info
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010062 // (array accesses)
Calin Juravle10e244f2015-01-26 18:54:32 +000063
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010064 RTPVisitor visitor(graph_, handles_);
Calin Juravleb1498f62015-02-16 13:13:29 +000065 // Initialize exact types first for faster convergence.
66 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
67 HInstruction* instr = it.Current();
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010068 instr->Accept(&visitor);
Calin Juravleb1498f62015-02-16 13:13:29 +000069 }
70
71 // Handle Phis.
72 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
73 VisitPhi(it.Current()->AsPhi());
74 }
75
76 // Add extra nodes to bound types.
Calin Juravle61d544b2015-02-23 16:46:57 +000077 BoundTypeForIfNotNull(block);
Calin Juravleb1498f62015-02-16 13:13:29 +000078 BoundTypeForIfInstanceOf(block);
Calin Juravle10e244f2015-01-26 18:54:32 +000079}
80
Calin Juravle61d544b2015-02-23 16:46:57 +000081void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +010082 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
83 if (ifInstruction == nullptr) {
Calin Juravle61d544b2015-02-23 16:46:57 +000084 return;
85 }
Calin Juravleb3306642015-04-20 18:30:42 +010086 HInstruction* ifInput = ifInstruction->InputAt(0);
Calin Juravle61d544b2015-02-23 16:46:57 +000087 if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) {
88 return;
89 }
90 HInstruction* input0 = ifInput->InputAt(0);
91 HInstruction* input1 = ifInput->InputAt(1);
Calin Juravleedad8ad2015-04-23 14:34:33 +010092 HInstruction* obj = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +000093
Calin Juravleedad8ad2015-04-23 14:34:33 +010094 if (input1->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +000095 obj = input0;
Calin Juravleedad8ad2015-04-23 14:34:33 +010096 } else if (input0->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +000097 obj = input1;
98 } else {
99 return;
100 }
101
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100102 if (!obj->CanBeNull() || obj->IsNullConstant()) {
103 // Null check is dead code and will be removed by DCE.
104 return;
105 }
106 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
107
Calin Juravleb3306642015-04-20 18:30:42 +0100108 // We only need to bound the type if we have uses in the relevant block.
109 // So start with null and create the HBoundType lazily, only if it's needed.
110 HBoundType* bound_type = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000111 HBasicBlock* notNullBlock = ifInput->IsNotEqual()
Calin Juravleb3306642015-04-20 18:30:42 +0100112 ? ifInstruction->IfTrueSuccessor()
113 : ifInstruction->IfFalseSuccessor();
114
Calin Juravle61d544b2015-02-23 16:46:57 +0000115 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
116 HInstruction* user = it.Current()->GetUser();
117 if (notNullBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100118 if (bound_type == nullptr) {
Calin Juravle6c0c4f22015-06-12 15:40:42 +0000119 bound_type = new (graph_->GetArena()) HBoundType(obj, ReferenceTypeInfo::CreateTop(false));
Calin Juravleb3306642015-04-20 18:30:42 +0100120 notNullBlock->InsertInstructionBefore(bound_type, notNullBlock->GetFirstInstruction());
121 }
Calin Juravle61d544b2015-02-23 16:46:57 +0000122 user->ReplaceInput(bound_type, it.Current()->GetIndex());
123 }
124 }
125}
126
Calin Juravleb1498f62015-02-16 13:13:29 +0000127// Detects if `block` is the True block for the pattern
128// `if (x instanceof ClassX) { }`
129// If that's the case insert an HBoundType instruction to bound the type of `x`
130// to `ClassX` in the scope of the dominated blocks.
131void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100132 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
133 if (ifInstruction == nullptr) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000134 return;
135 }
Calin Juravleb3306642015-04-20 18:30:42 +0100136 HInstruction* ifInput = ifInstruction->InputAt(0);
137 HInstruction* instanceOf = nullptr;
138 HBasicBlock* instanceOfTrueBlock = nullptr;
David Brazdil0d13fee2015-04-17 14:52:19 +0100139
Calin Juravleb3306642015-04-20 18:30:42 +0100140 // The instruction simplifier has transformed:
141 // - `if (a instanceof A)` into an HIf with an HInstanceOf input
142 // - `if (!(a instanceof A)` into an HIf with an HBooleanNot input (which in turn
143 // has an HInstanceOf input)
144 // So we should not see the usual HEqual here.
David Brazdil0d13fee2015-04-17 14:52:19 +0100145 if (ifInput->IsInstanceOf()) {
146 instanceOf = ifInput;
Calin Juravleb3306642015-04-20 18:30:42 +0100147 instanceOfTrueBlock = ifInstruction->IfTrueSuccessor();
David Brazdil0d13fee2015-04-17 14:52:19 +0100148 } else if (ifInput->IsBooleanNot() && ifInput->InputAt(0)->IsInstanceOf()) {
149 instanceOf = ifInput->InputAt(0);
Calin Juravleb3306642015-04-20 18:30:42 +0100150 instanceOfTrueBlock = ifInstruction->IfFalseSuccessor();
David Brazdil0d13fee2015-04-17 14:52:19 +0100151 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000152 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000153 }
154
Calin Juravleb3306642015-04-20 18:30:42 +0100155 // We only need to bound the type if we have uses in the relevant block.
156 // So start with null and create the HBoundType lazily, only if it's needed.
157 HBoundType* bound_type = nullptr;
158
Calin Juravleb1498f62015-02-16 13:13:29 +0000159 HInstruction* obj = instanceOf->InputAt(0);
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100160 if (obj->GetReferenceTypeInfo().IsExact() && !obj->IsPhi()) {
161 // This method is being called while doing a fixed-point calculation
162 // over phis. Non-phis instruction whose type is already known do
163 // not need to be bound to another type.
164 // Not that this also prevents replacing `HLoadClass` with a `HBoundType`.
165 // `HCheckCast` and `HInstanceOf` expect a `HLoadClass` as a second
166 // input.
167 return;
168 }
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100169 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
Calin Juravleb1498f62015-02-16 13:13:29 +0000170 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
171 HInstruction* user = it.Current()->GetUser();
172 if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100173 if (bound_type == nullptr) {
174 HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
175
176 ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo();
177 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
Calin Juravle6c0c4f22015-06-12 15:40:42 +0000178 bound_type = new (graph_->GetArena()) HBoundType(obj, class_rti);
Calin Juravleb3306642015-04-20 18:30:42 +0100179
180 // Narrow the type as much as possible.
181 {
182 ScopedObjectAccess soa(Thread::Current());
183 if (!load_class->IsResolved() || class_rti.IsSupertypeOf(obj_rti)) {
184 bound_type->SetReferenceTypeInfo(obj_rti);
185 } else {
186 bound_type->SetReferenceTypeInfo(
187 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
188 }
189 }
190
191 instanceOfTrueBlock->InsertInstructionBefore(
192 bound_type, instanceOfTrueBlock->GetFirstInstruction());
193 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000194 user->ReplaceInput(bound_type, it.Current()->GetIndex());
195 }
196 }
Calin Juravleacf735c2015-02-12 15:25:22 +0000197}
198
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100199void RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
200 mirror::Class* klass,
201 bool is_exact) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100202 if (klass != nullptr) {
203 ScopedObjectAccess soa(Thread::Current());
204 MutableHandle<mirror::Class> handle = handles_->NewHandle(klass);
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100205 is_exact = is_exact || klass->IsFinal();
206 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100207 }
208}
209
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100210void RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
211 uint16_t type_idx,
212 const DexFile& dex_file,
213 bool is_exact) {
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100214 DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
215
Calin Juravleacf735c2015-02-12 15:25:22 +0000216 ScopedObjectAccess soa(Thread::Current());
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100217 mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
Calin Juravleacf735c2015-02-12 15:25:22 +0000218 // Get type from dex cache assuming it was populated by the verifier.
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100219 SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact);
Calin Juravleacf735c2015-02-12 15:25:22 +0000220}
221
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100222void RTPVisitor::VisitNewInstance(HNewInstance* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100223 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100224}
225
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100226void RTPVisitor::VisitNewArray(HNewArray* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100227 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100228}
229
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100230void RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
231 const FieldInfo& info) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100232 // The field index is unknown only during tests.
233 if (instr->GetType() != Primitive::kPrimNot || info.GetFieldIndex() == kUnknownFieldIndex) {
234 return;
235 }
236
237 ScopedObjectAccess soa(Thread::Current());
238 ClassLinker* cl = Runtime::Current()->GetClassLinker();
239 mirror::DexCache* dex_cache = cl->FindDexCache(info.GetDexFile());
240 ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), dex_cache);
Calin Juravle183617a2015-06-18 18:38:29 +0100241 if (field != nullptr) {
242 mirror::Class* klass = field->GetType<false>();
243 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
244 }
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100245}
246
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100247void RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100248 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
249}
250
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100251void RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100252 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
253}
254
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100255void RTPVisitor::VisitLoadClass(HLoadClass* instr) {
Calin Juravleacf735c2015-02-12 15:25:22 +0000256 ScopedObjectAccess soa(Thread::Current());
Nicolas Geoffrayd5111bf2015-05-22 15:37:09 +0100257 mirror::DexCache* dex_cache =
258 Runtime::Current()->GetClassLinker()->FindDexCache(instr->GetDexFile());
Calin Juravleacf735c2015-02-12 15:25:22 +0000259 // Get type from dex cache assuming it was populated by the verifier.
260 mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
261 if (resolved_class != nullptr) {
262 Handle<mirror::Class> handle = handles_->NewHandle(resolved_class);
Calin Juravleb1498f62015-02-16 13:13:29 +0000263 instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(handle, /* is_exact */ true));
Calin Juravleacf735c2015-02-12 15:25:22 +0000264 }
265 Handle<mirror::Class> class_handle = handles_->NewHandle(mirror::Class::GetJavaLangClass());
Calin Juravleb1498f62015-02-16 13:13:29 +0000266 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(class_handle, /* is_exact */ true));
Calin Juravleacf735c2015-02-12 15:25:22 +0000267}
Calin Juravle10e244f2015-01-26 18:54:32 +0000268
Calin Juravleb1498f62015-02-16 13:13:29 +0000269void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
270 if (phi->GetType() != Primitive::kPrimNot) {
271 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000272 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000273
274 if (phi->GetBlock()->IsLoopHeader()) {
275 // Set the initial type for the phi. Use the non back edge input for reaching
276 // a fixed point faster.
277 AddToWorklist(phi);
278 phi->SetCanBeNull(phi->InputAt(0)->CanBeNull());
279 phi->SetReferenceTypeInfo(phi->InputAt(0)->GetReferenceTypeInfo());
Calin Juravle10e244f2015-01-26 18:54:32 +0000280 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000281 // Eagerly compute the type of the phi, for quicker convergence. Note
282 // that we don't need to add users to the worklist because we are
283 // doing a reverse post-order visit, therefore either the phi users are
284 // non-loop phi and will be visited later in the visit, or are loop-phis,
285 // and they are already in the work list.
286 UpdateNullability(phi);
287 UpdateReferenceTypeInfo(phi);
288 }
289}
290
291ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
292 const ReferenceTypeInfo& b) {
293 bool is_exact = a.IsExact() && b.IsExact();
294 bool is_top = a.IsTop() || b.IsTop();
295 Handle<mirror::Class> type_handle;
296
297 if (!is_top) {
298 if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
299 type_handle = a.GetTypeHandle();
300 } else if (a.IsSupertypeOf(b)) {
301 type_handle = a.GetTypeHandle();
302 is_exact = false;
303 } else if (b.IsSupertypeOf(a)) {
304 type_handle = b.GetTypeHandle();
305 is_exact = false;
306 } else {
307 // TODO: Find a common super class.
308 is_top = true;
309 is_exact = false;
310 }
311 }
312
313 return is_top
314 ? ReferenceTypeInfo::CreateTop(is_exact)
315 : ReferenceTypeInfo::Create(type_handle, is_exact);
316}
317
318bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
319 ScopedObjectAccess soa(Thread::Current());
320
321 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
322 if (instr->IsBoundType()) {
323 UpdateBoundType(instr->AsBoundType());
324 } else if (instr->IsPhi()) {
325 UpdatePhi(instr->AsPhi());
326 } else {
327 LOG(FATAL) << "Invalid instruction (should not get here)";
328 }
329
330 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
331}
332
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100333void RTPVisitor::VisitInvoke(HInvoke* instr) {
334 if (instr->GetType() != Primitive::kPrimNot) {
335 return;
336 }
337
338 ScopedObjectAccess soa(Thread::Current());
339 ClassLinker* cl = Runtime::Current()->GetClassLinker();
340 mirror::DexCache* dex_cache = cl->FindDexCache(instr->GetDexFile());
341 ArtMethod* method = dex_cache->GetResolvedMethod(
342 instr->GetDexMethodIndex(), cl->GetImagePointerSize());
Calin Juravle183617a2015-06-18 18:38:29 +0100343 if (method != nullptr) {
344 mirror::Class* klass = method->GetReturnType(false);
345 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
346 }
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100347}
348
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100349void RTPVisitor::VisitArrayGet(HArrayGet* instr) {
350 if (instr->GetType() != Primitive::kPrimNot) {
351 return;
352 }
353
354 HInstruction* parent = instr->InputAt(0);
355 ScopedObjectAccess soa(Thread::Current());
356 Handle<mirror::Class> handle = parent->GetReferenceTypeInfo().GetTypeHandle();
357 if (handle.GetReference() != nullptr && handle->IsObjectArrayClass()) {
358 SetClassAsTypeInfo(instr, handle->GetComponentType(), /* is_exact */ false);
359 }
360}
361
Calin Juravleb1498f62015-02-16 13:13:29 +0000362void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
363 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
364 // Be sure that we don't go over the bounded type.
365 ReferenceTypeInfo bound_rti = instr->GetBoundType();
366 if (!bound_rti.IsSupertypeOf(new_rti)) {
367 new_rti = bound_rti;
368 }
369 instr->SetReferenceTypeInfo(new_rti);
370}
371
372void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
373 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
374 if (new_rti.IsTop() && !new_rti.IsExact()) {
375 // Early return if we are Top and inexact.
376 instr->SetReferenceTypeInfo(new_rti);
377 return;
378 }
379 for (size_t i = 1; i < instr->InputCount(); i++) {
380 new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo());
381 if (new_rti.IsTop()) {
382 if (!new_rti.IsExact()) {
383 break;
384 } else {
385 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000386 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000387 }
388 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000389 instr->SetReferenceTypeInfo(new_rti);
390}
391
392// Re-computes and updates the nullability of the instruction. Returns whether or
393// not the nullability was changed.
394bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
395 DCHECK(instr->IsPhi() || instr->IsBoundType());
396
397 if (!instr->IsPhi()) {
398 return false;
399 }
400
401 HPhi* phi = instr->AsPhi();
402 bool existing_can_be_null = phi->CanBeNull();
403 bool new_can_be_null = false;
404 for (size_t i = 0; i < phi->InputCount(); i++) {
405 new_can_be_null |= phi->InputAt(i)->CanBeNull();
406 }
407 phi->SetCanBeNull(new_can_be_null);
408
409 return existing_can_be_null != new_can_be_null;
Calin Juravle10e244f2015-01-26 18:54:32 +0000410}
411
412void ReferenceTypePropagation::ProcessWorklist() {
413 while (!worklist_.IsEmpty()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000414 HInstruction* instruction = worklist_.Pop();
Calin Juravleacf735c2015-02-12 15:25:22 +0000415 if (UpdateNullability(instruction) || UpdateReferenceTypeInfo(instruction)) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000416 AddDependentInstructionsToWorklist(instruction);
417 }
418 }
419}
420
Calin Juravleb1498f62015-02-16 13:13:29 +0000421void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
422 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot) << instruction->GetType();
Calin Juravle10e244f2015-01-26 18:54:32 +0000423 worklist_.Add(instruction);
424}
425
Calin Juravleb1498f62015-02-16 13:13:29 +0000426void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000427 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000428 HInstruction* user = it.Current()->GetUser();
429 if (user->IsPhi() || user->IsBoundType()) {
430 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000431 }
432 }
433}
Calin Juravle10e244f2015-01-26 18:54:32 +0000434} // namespace art