blob: fe837e45453a956ba7808fa49512c623ff0ab7c4 [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:
Calin Juravle2e768302015-07-28 14:41:11 +000028 RTPVisitor(HGraph* graph,
29 StackHandleScopeCollection* handles,
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010030 ArenaVector<HInstruction*>* worklist,
Calin Juravle2e768302015-07-28 14:41:11 +000031 ReferenceTypeInfo::TypeHandle object_class_handle,
32 ReferenceTypeInfo::TypeHandle class_class_handle,
David Brazdilbbd733e2015-08-18 17:48:17 +010033 ReferenceTypeInfo::TypeHandle string_class_handle,
34 ReferenceTypeInfo::TypeHandle throwable_class_handle)
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010035 : HGraphDelegateVisitor(graph),
Calin Juravle2e768302015-07-28 14:41:11 +000036 handles_(handles),
37 object_class_handle_(object_class_handle),
38 class_class_handle_(class_class_handle),
39 string_class_handle_(string_class_handle),
David Brazdilbbd733e2015-08-18 17:48:17 +010040 throwable_class_handle_(throwable_class_handle),
Calin Juravle2e768302015-07-28 14:41:11 +000041 worklist_(worklist) {}
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010042
Calin Juravle2e768302015-07-28 14:41:11 +000043 void VisitNullConstant(HNullConstant* null_constant) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010044 void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
45 void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000046 void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE;
47 void VisitLoadString(HLoadString* instr) OVERRIDE;
David Brazdilbbd733e2015-08-18 17:48:17 +010048 void VisitLoadException(HLoadException* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010049 void VisitNewArray(HNewArray* instr) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000050 void VisitParameterValue(HParameterValue* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010051 void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
52 void SetClassAsTypeInfo(HInstruction* instr, mirror::Class* klass, bool is_exact);
53 void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE;
54 void VisitStaticFieldGet(HStaticFieldGet* instr) OVERRIDE;
55 void VisitInvoke(HInvoke* instr) OVERRIDE;
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +010056 void VisitArrayGet(HArrayGet* instr) OVERRIDE;
Calin Juravlea5ae3c32015-07-28 14:40:50 +000057 void VisitCheckCast(HCheckCast* instr) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000058 void VisitNullCheck(HNullCheck* instr) OVERRIDE;
59 void VisitFakeString(HFakeString* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010060 void UpdateReferenceTypeInfo(HInstruction* instr,
61 uint16_t type_idx,
62 const DexFile& dex_file,
63 bool is_exact);
64
65 private:
66 StackHandleScopeCollection* handles_;
Calin Juravle2e768302015-07-28 14:41:11 +000067 ReferenceTypeInfo::TypeHandle object_class_handle_;
68 ReferenceTypeInfo::TypeHandle class_class_handle_;
69 ReferenceTypeInfo::TypeHandle string_class_handle_;
David Brazdilbbd733e2015-08-18 17:48:17 +010070 ReferenceTypeInfo::TypeHandle throwable_class_handle_;
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010071 ArenaVector<HInstruction*>* worklist_;
Calin Juravle2e768302015-07-28 14:41:11 +000072
73 static constexpr size_t kDefaultWorklistSize = 8;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010074};
75
Calin Juravle2e768302015-07-28 14:41:11 +000076ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph,
77 StackHandleScopeCollection* handles,
78 const char* name)
79 : HOptimization(graph, name),
80 handles_(handles),
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010081 worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)) {
82 worklist_.reserve(kDefaultWorklistSize);
Andreas Gampe9393c692015-08-28 10:56:38 -070083 // Mutator lock is required for NewHandle, but annotalysis ignores constructors.
84 ScopedObjectAccess soa(Thread::Current());
Calin Juravle2e768302015-07-28 14:41:11 +000085 ClassLinker* linker = Runtime::Current()->GetClassLinker();
86 object_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangObject));
87 string_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangString));
88 class_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangClass));
David Brazdilbbd733e2015-08-18 17:48:17 +010089 throwable_class_handle_ =
90 handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangThrowable));
Calin Juravle2e768302015-07-28 14:41:11 +000091
92 if (kIsDebugBuild) {
Calin Juravle2e768302015-07-28 14:41:11 +000093 DCHECK(ReferenceTypeInfo::IsValidHandle(object_class_handle_));
94 DCHECK(ReferenceTypeInfo::IsValidHandle(class_class_handle_));
95 DCHECK(ReferenceTypeInfo::IsValidHandle(string_class_handle_));
David Brazdilbbd733e2015-08-18 17:48:17 +010096 DCHECK(ReferenceTypeInfo::IsValidHandle(throwable_class_handle_));
Calin Juravle2e768302015-07-28 14:41:11 +000097 }
98}
99
Calin Juravleacf735c2015-02-12 15:25:22 +0000100void ReferenceTypePropagation::Run() {
101 // To properly propagate type info we need to visit in the dominator-based order.
Calin Juravle10e244f2015-01-26 18:54:32 +0000102 // Reverse post order guarantees a node's dominators are visited first.
103 // We take advantage of this order in `VisitBasicBlock`.
Calin Juravle6c0c4f22015-06-12 15:40:42 +0000104 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000105 VisitBasicBlock(it.Current());
106 }
107 ProcessWorklist();
Calin Juravle2e768302015-07-28 14:41:11 +0000108
109 if (kIsDebugBuild) {
110 // TODO: move this to the graph checker.
111 ScopedObjectAccess soa(Thread::Current());
112 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
113 HBasicBlock* block = it.Current();
114 for (HInstructionIterator iti(block->GetInstructions()); !iti.Done(); iti.Advance()) {
115 HInstruction* instr = iti.Current();
116 if (instr->GetType() == Primitive::kPrimNot) {
117 DCHECK(instr->GetReferenceTypeInfo().IsValid())
118 << "Invalid RTI for instruction: " << instr->DebugName();
119 if (instr->IsBoundType()) {
120 DCHECK(instr->AsBoundType()->GetUpperBound().IsValid());
121 } else if (instr->IsLoadClass()) {
122 DCHECK(instr->AsLoadClass()->GetReferenceTypeInfo().IsExact());
123 DCHECK(instr->AsLoadClass()->GetLoadedClassRTI().IsValid());
124 } else if (instr->IsNullCheck()) {
125 DCHECK(instr->GetReferenceTypeInfo().IsEqual(instr->InputAt(0)->GetReferenceTypeInfo()))
126 << "NullCheck " << instr->GetReferenceTypeInfo()
127 << "Input(0) " << instr->InputAt(0)->GetReferenceTypeInfo();
128 }
129 }
130 }
131 }
132 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000133}
134
Calin Juravleb1498f62015-02-16 13:13:29 +0000135void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
Calin Juravle2e768302015-07-28 14:41:11 +0000136 RTPVisitor visitor(graph_,
137 handles_,
138 &worklist_,
139 object_class_handle_,
140 class_class_handle_,
David Brazdilbbd733e2015-08-18 17:48:17 +0100141 string_class_handle_,
142 throwable_class_handle_);
Calin Juravle2e768302015-07-28 14:41:11 +0000143 // Handle Phis first as there might be instructions in the same block who depend on them.
144 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
145 VisitPhi(it.Current()->AsPhi());
146 }
Calin Juravlebeba9302015-07-08 15:57:18 +0000147
Calin Juravle2e768302015-07-28 14:41:11 +0000148 // Handle instructions.
Calin Juravleb1498f62015-02-16 13:13:29 +0000149 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
150 HInstruction* instr = it.Current();
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100151 instr->Accept(&visitor);
Calin Juravleb1498f62015-02-16 13:13:29 +0000152 }
153
Calin Juravleb1498f62015-02-16 13:13:29 +0000154 // Add extra nodes to bound types.
Calin Juravle61d544b2015-02-23 16:46:57 +0000155 BoundTypeForIfNotNull(block);
Calin Juravleb1498f62015-02-16 13:13:29 +0000156 BoundTypeForIfInstanceOf(block);
Calin Juravle10e244f2015-01-26 18:54:32 +0000157}
158
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000159// Create a bound type for the given object narrowing the type as much as possible.
160// The BoundType upper values for the super type and can_be_null will be taken from
161// load_class.GetLoadedClassRTI() and upper_can_be_null.
162static HBoundType* CreateBoundType(ArenaAllocator* arena,
163 HInstruction* obj,
164 HLoadClass* load_class,
165 bool upper_can_be_null)
166 SHARED_REQUIRES(Locks::mutator_lock_) {
167 ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo();
168 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
169 HBoundType* bound_type = new (arena) HBoundType(obj, class_rti, upper_can_be_null);
170 // Narrow the type as much as possible.
David Brazdilbaf89b82015-09-15 11:36:54 +0100171 if (class_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes()) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000172 bound_type->SetReferenceTypeInfo(
173 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000174 } else if (obj_rti.IsValid() && class_rti.IsSupertypeOf(obj_rti)) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000175 bound_type->SetReferenceTypeInfo(obj_rti);
176 } else {
177 bound_type->SetReferenceTypeInfo(
178 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
179 }
Nicolas Geoffrayefa84682015-08-12 18:28:14 -0700180 if (upper_can_be_null) {
181 bound_type->SetCanBeNull(obj->CanBeNull());
182 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000183 return bound_type;
184}
185
186// 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)
196 SHARED_REQUIRES(Locks::mutator_lock_) {
197 // 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.
207 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
208 HInstruction* user = it.Current()->GetUser();
209 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
Calin Juravle61d544b2015-02-23 16:46:57 +0000262 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
263 HInstruction* user = it.Current()->GetUser();
264 if (notNullBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100265 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000266 ScopedObjectAccess soa(Thread::Current());
267 HInstruction* insert_point = notNullBlock->GetFirstInstruction();
Calin Juravle2e768302015-07-28 14:41:11 +0000268 ReferenceTypeInfo object_rti = ReferenceTypeInfo::Create(
269 object_class_handle_, /* is_exact */ true);
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000270 if (ShouldCreateBoundType(insert_point, obj, object_rti, nullptr, notNullBlock)) {
271 bound_type = new (graph_->GetArena()) HBoundType(
272 obj, object_rti, /* bound_can_be_null */ false);
Calin Juravle2e768302015-07-28 14:41:11 +0000273 if (obj->GetReferenceTypeInfo().IsValid()) {
274 bound_type->SetReferenceTypeInfo(obj->GetReferenceTypeInfo());
275 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000276 notNullBlock->InsertInstructionBefore(bound_type, insert_point);
277 } else {
278 // We already have a bound type on the position we would need to insert
279 // the new one. The existing bound type should dominate all the users
280 // (dchecked) so there's no need to continue.
281 break;
282 }
Calin Juravleb3306642015-04-20 18:30:42 +0100283 }
Calin Juravle61d544b2015-02-23 16:46:57 +0000284 user->ReplaceInput(bound_type, it.Current()->GetIndex());
285 }
286 }
287}
288
Calin Juravleb1498f62015-02-16 13:13:29 +0000289// Detects if `block` is the True block for the pattern
290// `if (x instanceof ClassX) { }`
291// If that's the case insert an HBoundType instruction to bound the type of `x`
292// to `ClassX` in the scope of the dominated blocks.
293void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100294 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
295 if (ifInstruction == nullptr) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000296 return;
297 }
Calin Juravleb3306642015-04-20 18:30:42 +0100298 HInstruction* ifInput = ifInstruction->InputAt(0);
299 HInstruction* instanceOf = nullptr;
300 HBasicBlock* instanceOfTrueBlock = nullptr;
David Brazdil0d13fee2015-04-17 14:52:19 +0100301
Calin Juravleb3306642015-04-20 18:30:42 +0100302 // The instruction simplifier has transformed:
303 // - `if (a instanceof A)` into an HIf with an HInstanceOf input
304 // - `if (!(a instanceof A)` into an HIf with an HBooleanNot input (which in turn
305 // has an HInstanceOf input)
306 // So we should not see the usual HEqual here.
David Brazdil0d13fee2015-04-17 14:52:19 +0100307 if (ifInput->IsInstanceOf()) {
308 instanceOf = ifInput;
Calin Juravleb3306642015-04-20 18:30:42 +0100309 instanceOfTrueBlock = ifInstruction->IfTrueSuccessor();
David Brazdil0d13fee2015-04-17 14:52:19 +0100310 } else if (ifInput->IsBooleanNot() && ifInput->InputAt(0)->IsInstanceOf()) {
311 instanceOf = ifInput->InputAt(0);
Calin Juravleb3306642015-04-20 18:30:42 +0100312 instanceOfTrueBlock = ifInstruction->IfFalseSuccessor();
David Brazdil0d13fee2015-04-17 14:52:19 +0100313 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000314 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000315 }
316
Calin Juravleb3306642015-04-20 18:30:42 +0100317 // We only need to bound the type if we have uses in the relevant block.
318 // So start with null and create the HBoundType lazily, only if it's needed.
319 HBoundType* bound_type = nullptr;
320
Calin Juravleb1498f62015-02-16 13:13:29 +0000321 HInstruction* obj = instanceOf->InputAt(0);
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100322 if (obj->GetReferenceTypeInfo().IsExact() && !obj->IsPhi()) {
323 // This method is being called while doing a fixed-point calculation
324 // over phis. Non-phis instruction whose type is already known do
325 // not need to be bound to another type.
326 // Not that this also prevents replacing `HLoadClass` with a `HBoundType`.
327 // `HCheckCast` and `HInstanceOf` expect a `HLoadClass` as a second
328 // input.
329 return;
330 }
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100331 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
Calin Juravleb1498f62015-02-16 13:13:29 +0000332 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
333 HInstruction* user = it.Current()->GetUser();
334 if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100335 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000336 ScopedObjectAccess soa(Thread::Current());
Calin Juravleb3306642015-04-20 18:30:42 +0100337 HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
Calin Juravleb3306642015-04-20 18:30:42 +0100338 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000339 HInstruction* insert_point = instanceOfTrueBlock->GetFirstInstruction();
340 if (ShouldCreateBoundType(insert_point, obj, class_rti, nullptr, instanceOfTrueBlock)) {
341 bound_type = CreateBoundType(
342 graph_->GetArena(),
343 obj,
344 load_class,
345 false /* InstanceOf ensures the object is not null. */);
346 instanceOfTrueBlock->InsertInstructionBefore(bound_type, insert_point);
347 } else {
348 // We already have a bound type on the position we would need to insert
349 // the new one. The existing bound type should dominate all the users
350 // (dchecked) so there's no need to continue.
351 break;
Calin Juravleb3306642015-04-20 18:30:42 +0100352 }
Calin Juravleb3306642015-04-20 18:30:42 +0100353 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000354 user->ReplaceInput(bound_type, it.Current()->GetIndex());
355 }
356 }
Calin Juravleacf735c2015-02-12 15:25:22 +0000357}
358
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100359void RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
360 mirror::Class* klass,
361 bool is_exact) {
Calin Juravle2e768302015-07-28 14:41:11 +0000362 if (instr->IsInvokeStaticOrDirect() && instr->AsInvokeStaticOrDirect()->IsStringInit()) {
363 // Calls to String.<init> are replaced with a StringFactory.
364 if (kIsDebugBuild) {
365 ScopedObjectAccess soa(Thread::Current());
366 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700367 mirror::DexCache* dex_cache = cl->FindDexCache(
368 soa.Self(), instr->AsInvoke()->GetDexFile(), false);
Calin Juravle2e768302015-07-28 14:41:11 +0000369 ArtMethod* method = dex_cache->GetResolvedMethod(
370 instr->AsInvoke()->GetDexMethodIndex(), cl->GetImagePointerSize());
371 DCHECK(method != nullptr);
372 mirror::Class* declaring_class = method->GetDeclaringClass();
373 DCHECK(declaring_class != nullptr);
374 DCHECK(declaring_class->IsStringClass())
375 << "Expected String class: " << PrettyDescriptor(declaring_class);
376 DCHECK(method->IsConstructor())
377 << "Expected String.<init>: " << PrettyMethod(method);
378 }
379 instr->SetReferenceTypeInfo(
380 ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
381 } else if (klass != nullptr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100382 ScopedObjectAccess soa(Thread::Current());
Calin Juravle2e768302015-07-28 14:41:11 +0000383 ReferenceTypeInfo::TypeHandle handle = handles_->NewHandle(klass);
David Brazdilbaf89b82015-09-15 11:36:54 +0100384 is_exact = is_exact || klass->CannotBeAssignedFromOtherTypes();
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100385 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
Calin Juravle2e768302015-07-28 14:41:11 +0000386 } else {
387 instr->SetReferenceTypeInfo(
388 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100389 }
390}
391
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100392void RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
393 uint16_t type_idx,
394 const DexFile& dex_file,
395 bool is_exact) {
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100396 DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
397
Calin Juravleacf735c2015-02-12 15:25:22 +0000398 ScopedObjectAccess soa(Thread::Current());
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700399 mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(
400 soa.Self(), dex_file, false);
Calin Juravleacf735c2015-02-12 15:25:22 +0000401 // Get type from dex cache assuming it was populated by the verifier.
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100402 SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact);
Calin Juravleacf735c2015-02-12 15:25:22 +0000403}
404
Calin Juravle2e768302015-07-28 14:41:11 +0000405void RTPVisitor::VisitNullConstant(HNullConstant* instr) {
406 // TODO: The null constant could be bound contextually (e.g. based on return statements)
407 // to a more precise type.
408 instr->SetReferenceTypeInfo(
409 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
410}
411
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100412void RTPVisitor::VisitNewInstance(HNewInstance* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100413 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100414}
415
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100416void RTPVisitor::VisitNewArray(HNewArray* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100417 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100418}
419
Calin Juravle2e768302015-07-28 14:41:11 +0000420void RTPVisitor::VisitParameterValue(HParameterValue* instr) {
Nicolas Geoffraye418dda2015-08-11 20:03:09 -0700421 ScopedObjectAccess soa(Thread::Current());
422 // We check if the existing type is valid: the inliner may have set it.
423 if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) {
Calin Juravle2e768302015-07-28 14:41:11 +0000424 // TODO: parse the signature and add precise types for the parameters.
425 SetClassAsTypeInfo(instr, nullptr, /* is_exact */ false);
426 }
427}
428
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100429void RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
430 const FieldInfo& info) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100431 // The field index is unknown only during tests.
432 if (instr->GetType() != Primitive::kPrimNot || info.GetFieldIndex() == kUnknownFieldIndex) {
433 return;
434 }
435
436 ScopedObjectAccess soa(Thread::Current());
437 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Mathieu Chartier736b5602015-09-02 14:54:11 -0700438 ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), info.GetDexCache().Get());
Calin Juravle2e768302015-07-28 14:41:11 +0000439 // TODO: There are certain cases where we can't resolve the field.
440 // b/21914925 is open to keep track of a repro case for this issue.
441 mirror::Class* klass = (field == nullptr) ? nullptr : field->GetType<false>();
442 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100443}
444
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100445void RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100446 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
447}
448
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100449void RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100450 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
451}
452
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100453void RTPVisitor::VisitLoadClass(HLoadClass* instr) {
Calin Juravleacf735c2015-02-12 15:25:22 +0000454 ScopedObjectAccess soa(Thread::Current());
Nicolas Geoffrayd5111bf2015-05-22 15:37:09 +0100455 mirror::DexCache* dex_cache =
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700456 Runtime::Current()->GetClassLinker()->FindDexCache(soa.Self(), instr->GetDexFile(), false);
Calin Juravleacf735c2015-02-12 15:25:22 +0000457 // Get type from dex cache assuming it was populated by the verifier.
458 mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
Calin Juravle51d135f2015-07-29 19:25:24 +0100459 // TODO: investigating why we are still getting unresolved classes: b/22821472.
460 ReferenceTypeInfo::TypeHandle handle = (resolved_class != nullptr)
461 ? handles_->NewHandle(resolved_class)
462 : object_class_handle_;
Calin Juravle2e768302015-07-28 14:41:11 +0000463 instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(handle, /* is_exact */ true));
464 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(class_class_handle_, /* is_exact */ true));
465}
466
467void RTPVisitor::VisitClinitCheck(HClinitCheck* instr) {
468 instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
469}
470
471void RTPVisitor::VisitLoadString(HLoadString* instr) {
472 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
473}
474
David Brazdilbbd733e2015-08-18 17:48:17 +0100475void RTPVisitor::VisitLoadException(HLoadException* instr) {
476 DCHECK(instr->GetBlock()->IsCatchBlock());
477 TryCatchInformation* catch_info = instr->GetBlock()->GetTryCatchInformation();
478
479 if (catch_info->IsCatchAllTypeIndex()) {
480 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(throwable_class_handle_,
David Brazdilb4edcf32015-08-20 17:05:49 +0100481 /* is_exact */ false));
David Brazdilbbd733e2015-08-18 17:48:17 +0100482 } else {
483 UpdateReferenceTypeInfo(instr,
484 catch_info->GetCatchTypeIndex(),
485 catch_info->GetCatchDexFile(),
486 /* is_exact */ false);
487 }
488}
489
Calin Juravle2e768302015-07-28 14:41:11 +0000490void RTPVisitor::VisitNullCheck(HNullCheck* instr) {
491 ScopedObjectAccess soa(Thread::Current());
492 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
493 DCHECK(parent_rti.IsValid());
494 instr->SetReferenceTypeInfo(parent_rti);
495}
496
497void RTPVisitor::VisitFakeString(HFakeString* instr) {
498 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
Calin Juravleacf735c2015-02-12 15:25:22 +0000499}
Calin Juravle10e244f2015-01-26 18:54:32 +0000500
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000501void RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
502 HInstruction* obj = check_cast->InputAt(0);
503 HBoundType* bound_type = nullptr;
504 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
505 HInstruction* user = it.Current()->GetUser();
506 if (check_cast->StrictlyDominates(user)) {
507 if (bound_type == nullptr) {
508 ScopedObjectAccess soa(Thread::Current());
509 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
510 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
511 if (ShouldCreateBoundType(check_cast->GetNext(), obj, class_rti, check_cast, nullptr)) {
512 bound_type = CreateBoundType(
513 GetGraph()->GetArena(),
514 obj,
515 load_class,
516 true /* CheckCast succeeds for nulls. */);
517 check_cast->GetBlock()->InsertInstructionAfter(bound_type, check_cast);
518 } else {
Nicolas Geoffrayefa84682015-08-12 18:28:14 -0700519 // Update nullability of the existing bound type, which may not have known
520 // that its input was not null when it was being created.
521 bound_type = check_cast->GetNext()->AsBoundType();
522 bound_type->SetCanBeNull(obj->CanBeNull());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000523 // We already have a bound type on the position we would need to insert
524 // the new one. The existing bound type should dominate all the users
525 // (dchecked) so there's no need to continue.
526 break;
527 }
528 }
529 user->ReplaceInput(bound_type, it.Current()->GetIndex());
530 }
531 }
532}
533
Calin Juravleb1498f62015-02-16 13:13:29 +0000534void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
535 if (phi->GetType() != Primitive::kPrimNot) {
536 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000537 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000538
539 if (phi->GetBlock()->IsLoopHeader()) {
540 // Set the initial type for the phi. Use the non back edge input for reaching
541 // a fixed point faster.
542 AddToWorklist(phi);
543 phi->SetCanBeNull(phi->InputAt(0)->CanBeNull());
544 phi->SetReferenceTypeInfo(phi->InputAt(0)->GetReferenceTypeInfo());
Calin Juravle10e244f2015-01-26 18:54:32 +0000545 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000546 // Eagerly compute the type of the phi, for quicker convergence. Note
547 // that we don't need to add users to the worklist because we are
548 // doing a reverse post-order visit, therefore either the phi users are
549 // non-loop phi and will be visited later in the visit, or are loop-phis,
550 // and they are already in the work list.
551 UpdateNullability(phi);
552 UpdateReferenceTypeInfo(phi);
553 }
554}
555
556ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
557 const ReferenceTypeInfo& b) {
Calin Juravle2e768302015-07-28 14:41:11 +0000558 if (!b.IsValid()) {
559 return a;
560 }
561 if (!a.IsValid()) {
562 return b;
Calin Juravle20e60712015-07-01 18:41:04 +0100563 }
564
Calin Juravle2e768302015-07-28 14:41:11 +0000565 bool is_exact = a.IsExact() && b.IsExact();
566 Handle<mirror::Class> type_handle;
567
568 if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
569 type_handle = a.GetTypeHandle();
570 } else if (a.IsSupertypeOf(b)) {
571 type_handle = a.GetTypeHandle();
572 is_exact = false;
573 } else if (b.IsSupertypeOf(a)) {
574 type_handle = b.GetTypeHandle();
575 is_exact = false;
576 } else {
577 // TODO: Find the first common super class.
578 type_handle = object_class_handle_;
579 is_exact = false;
580 }
581
582 return ReferenceTypeInfo::Create(type_handle, is_exact);
583}
584
585static void UpdateArrayGet(HArrayGet* instr,
586 StackHandleScopeCollection* handles,
587 ReferenceTypeInfo::TypeHandle object_class_handle)
588 SHARED_REQUIRES(Locks::mutator_lock_) {
589 DCHECK_EQ(Primitive::kPrimNot, instr->GetType());
590
591 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
592 DCHECK(parent_rti.IsValid());
593
594 Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
595 if (handle->IsObjectArrayClass()) {
596 ReferenceTypeInfo::TypeHandle component_handle = handles->NewHandle(handle->GetComponentType());
597 instr->SetReferenceTypeInfo(
598 ReferenceTypeInfo::Create(component_handle, /* is_exact */ false));
599 } else {
600 // We don't know what the parent actually is, so we fallback to object.
601 instr->SetReferenceTypeInfo(
602 ReferenceTypeInfo::Create(object_class_handle, /* is_exact */ false));
603 }
604
605 return;
Calin Juravleb1498f62015-02-16 13:13:29 +0000606}
607
608bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
609 ScopedObjectAccess soa(Thread::Current());
610
611 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
612 if (instr->IsBoundType()) {
613 UpdateBoundType(instr->AsBoundType());
614 } else if (instr->IsPhi()) {
615 UpdatePhi(instr->AsPhi());
Calin Juravle2e768302015-07-28 14:41:11 +0000616 } else if (instr->IsNullCheck()) {
617 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
618 if (parent_rti.IsValid()) {
619 instr->SetReferenceTypeInfo(parent_rti);
620 }
621 } else if (instr->IsArrayGet()) {
622 // TODO: consider if it's worth "looking back" and bounding the input object
623 // to an array type.
624 UpdateArrayGet(instr->AsArrayGet(), handles_, object_class_handle_);
Calin Juravleb1498f62015-02-16 13:13:29 +0000625 } else {
626 LOG(FATAL) << "Invalid instruction (should not get here)";
627 }
628
629 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
630}
631
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100632void RTPVisitor::VisitInvoke(HInvoke* instr) {
633 if (instr->GetType() != Primitive::kPrimNot) {
634 return;
635 }
636
637 ScopedObjectAccess soa(Thread::Current());
638 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700639 mirror::DexCache* dex_cache = cl->FindDexCache(soa.Self(), instr->GetDexFile());
Vladimir Marko05792b92015-08-03 11:56:49 +0100640 size_t pointer_size = cl->GetImagePointerSize();
641 ArtMethod* method = dex_cache->GetResolvedMethod(instr->GetDexMethodIndex(), pointer_size);
642 mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false, pointer_size);
Calin Juravle2e768302015-07-28 14:41:11 +0000643 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100644}
645
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100646void RTPVisitor::VisitArrayGet(HArrayGet* instr) {
647 if (instr->GetType() != Primitive::kPrimNot) {
648 return;
649 }
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100650 ScopedObjectAccess soa(Thread::Current());
Calin Juravle2e768302015-07-28 14:41:11 +0000651 UpdateArrayGet(instr, handles_, object_class_handle_);
652 if (!instr->GetReferenceTypeInfo().IsValid()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100653 worklist_->push_back(instr);
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100654 }
655}
656
Calin Juravleb1498f62015-02-16 13:13:29 +0000657void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
658 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle2e768302015-07-28 14:41:11 +0000659 if (!new_rti.IsValid()) {
660 return; // No new info yet.
661 }
662
663 // Make sure that we don't go over the bounded type.
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000664 ReferenceTypeInfo upper_bound_rti = instr->GetUpperBound();
665 if (!upper_bound_rti.IsSupertypeOf(new_rti)) {
666 new_rti = upper_bound_rti;
Calin Juravleb1498f62015-02-16 13:13:29 +0000667 }
668 instr->SetReferenceTypeInfo(new_rti);
669}
670
671void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
672 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle2e768302015-07-28 14:41:11 +0000673 if (new_rti.IsValid() && new_rti.IsObjectClass() && !new_rti.IsExact()) {
674 // Early return if we are Object and inexact.
Calin Juravleb1498f62015-02-16 13:13:29 +0000675 instr->SetReferenceTypeInfo(new_rti);
676 return;
677 }
678 for (size_t i = 1; i < instr->InputCount(); i++) {
679 new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo());
Calin Juravle2e768302015-07-28 14:41:11 +0000680 if (new_rti.IsValid() && new_rti.IsObjectClass()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000681 if (!new_rti.IsExact()) {
682 break;
683 } else {
684 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000685 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000686 }
687 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000688 instr->SetReferenceTypeInfo(new_rti);
689}
690
691// Re-computes and updates the nullability of the instruction. Returns whether or
692// not the nullability was changed.
693bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
Calin Juravle2e768302015-07-28 14:41:11 +0000694 DCHECK(instr->IsPhi()
695 || instr->IsBoundType()
696 || instr->IsNullCheck()
697 || instr->IsArrayGet());
698
699 if (!instr->IsPhi() && !instr->IsBoundType()) {
700 return false;
701 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000702
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000703 bool existing_can_be_null = instr->CanBeNull();
704 if (instr->IsPhi()) {
705 HPhi* phi = instr->AsPhi();
706 bool new_can_be_null = false;
707 for (size_t i = 0; i < phi->InputCount(); i++) {
708 if (phi->InputAt(i)->CanBeNull()) {
709 new_can_be_null = true;
710 break;
711 }
712 }
713 phi->SetCanBeNull(new_can_be_null);
714 } else if (instr->IsBoundType()) {
715 HBoundType* bound_type = instr->AsBoundType();
716 bound_type->SetCanBeNull(instr->InputAt(0)->CanBeNull() && bound_type->GetUpperCanBeNull());
Calin Juravleb1498f62015-02-16 13:13:29 +0000717 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000718 return existing_can_be_null != instr->CanBeNull();
Calin Juravle10e244f2015-01-26 18:54:32 +0000719}
720
721void ReferenceTypePropagation::ProcessWorklist() {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100722 while (!worklist_.empty()) {
723 HInstruction* instruction = worklist_.back();
724 worklist_.pop_back();
Calin Juravleacf735c2015-02-12 15:25:22 +0000725 if (UpdateNullability(instruction) || UpdateReferenceTypeInfo(instruction)) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000726 AddDependentInstructionsToWorklist(instruction);
727 }
728 }
729}
730
Calin Juravleb1498f62015-02-16 13:13:29 +0000731void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
Calin Juravle2e768302015-07-28 14:41:11 +0000732 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot)
733 << instruction->DebugName() << ":" << instruction->GetType();
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100734 worklist_.push_back(instruction);
Calin Juravle10e244f2015-01-26 18:54:32 +0000735}
736
Calin Juravleb1498f62015-02-16 13:13:29 +0000737void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000738 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000739 HInstruction* user = it.Current()->GetUser();
Calin Juravle2e768302015-07-28 14:41:11 +0000740 if (user->IsPhi()
741 || user->IsBoundType()
742 || user->IsNullCheck()
743 || (user->IsArrayGet() && (user->GetType() == Primitive::kPrimNot))) {
Calin Juravlebeba9302015-07-08 15:57:18 +0000744 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000745 }
746 }
747}
Calin Juravle10e244f2015-01-26 18:54:32 +0000748} // namespace art