blob: f7a7e420bb39b7bea7d6b35d34eed4f2250aaa05 [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;
Calin Juravlee460d1d2015-09-29 04:52:17 +010055 void VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instr) OVERRIDE;
56 void VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010057 void VisitInvoke(HInvoke* instr) OVERRIDE;
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +010058 void VisitArrayGet(HArrayGet* instr) OVERRIDE;
Calin Juravlea5ae3c32015-07-28 14:40:50 +000059 void VisitCheckCast(HCheckCast* instr) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000060 void VisitNullCheck(HNullCheck* instr) OVERRIDE;
61 void VisitFakeString(HFakeString* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010062 void UpdateReferenceTypeInfo(HInstruction* instr,
63 uint16_t type_idx,
64 const DexFile& dex_file,
65 bool is_exact);
66
67 private:
68 StackHandleScopeCollection* handles_;
Calin Juravle2e768302015-07-28 14:41:11 +000069 ReferenceTypeInfo::TypeHandle object_class_handle_;
70 ReferenceTypeInfo::TypeHandle class_class_handle_;
71 ReferenceTypeInfo::TypeHandle string_class_handle_;
David Brazdilbbd733e2015-08-18 17:48:17 +010072 ReferenceTypeInfo::TypeHandle throwable_class_handle_;
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010073 ArenaVector<HInstruction*>* worklist_;
Calin Juravle2e768302015-07-28 14:41:11 +000074
75 static constexpr size_t kDefaultWorklistSize = 8;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010076};
77
Calin Juravle2e768302015-07-28 14:41:11 +000078ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph,
79 StackHandleScopeCollection* handles,
80 const char* name)
81 : HOptimization(graph, name),
82 handles_(handles),
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010083 worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)) {
84 worklist_.reserve(kDefaultWorklistSize);
Andreas Gampe9393c692015-08-28 10:56:38 -070085 // Mutator lock is required for NewHandle, but annotalysis ignores constructors.
86 ScopedObjectAccess soa(Thread::Current());
Calin Juravle2e768302015-07-28 14:41:11 +000087 ClassLinker* linker = Runtime::Current()->GetClassLinker();
88 object_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangObject));
89 string_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangString));
90 class_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangClass));
David Brazdilbbd733e2015-08-18 17:48:17 +010091 throwable_class_handle_ =
92 handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangThrowable));
Calin Juravle2e768302015-07-28 14:41:11 +000093
94 if (kIsDebugBuild) {
Calin Juravle2e768302015-07-28 14:41:11 +000095 DCHECK(ReferenceTypeInfo::IsValidHandle(object_class_handle_));
96 DCHECK(ReferenceTypeInfo::IsValidHandle(class_class_handle_));
97 DCHECK(ReferenceTypeInfo::IsValidHandle(string_class_handle_));
David Brazdilbbd733e2015-08-18 17:48:17 +010098 DCHECK(ReferenceTypeInfo::IsValidHandle(throwable_class_handle_));
Calin Juravle2e768302015-07-28 14:41:11 +000099 }
100}
101
Calin Juravleacf735c2015-02-12 15:25:22 +0000102void ReferenceTypePropagation::Run() {
103 // To properly propagate type info we need to visit in the dominator-based order.
Calin Juravle10e244f2015-01-26 18:54:32 +0000104 // Reverse post order guarantees a node's dominators are visited first.
105 // We take advantage of this order in `VisitBasicBlock`.
Calin Juravle6c0c4f22015-06-12 15:40:42 +0000106 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000107 VisitBasicBlock(it.Current());
108 }
109 ProcessWorklist();
Calin Juravle2e768302015-07-28 14:41:11 +0000110
111 if (kIsDebugBuild) {
112 // TODO: move this to the graph checker.
113 ScopedObjectAccess soa(Thread::Current());
114 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
115 HBasicBlock* block = it.Current();
116 for (HInstructionIterator iti(block->GetInstructions()); !iti.Done(); iti.Advance()) {
117 HInstruction* instr = iti.Current();
118 if (instr->GetType() == Primitive::kPrimNot) {
119 DCHECK(instr->GetReferenceTypeInfo().IsValid())
120 << "Invalid RTI for instruction: " << instr->DebugName();
121 if (instr->IsBoundType()) {
122 DCHECK(instr->AsBoundType()->GetUpperBound().IsValid());
123 } else if (instr->IsLoadClass()) {
Calin Juravle98893e12015-10-02 21:05:03 +0100124 HLoadClass* cls = instr->AsLoadClass();
125 DCHECK(cls->GetReferenceTypeInfo().IsExact());
126 DCHECK(!cls->GetLoadedClassRTI().IsValid() || cls->GetLoadedClassRTI().IsExact());
Calin Juravle2e768302015-07-28 14:41:11 +0000127 } else if (instr->IsNullCheck()) {
128 DCHECK(instr->GetReferenceTypeInfo().IsEqual(instr->InputAt(0)->GetReferenceTypeInfo()))
129 << "NullCheck " << instr->GetReferenceTypeInfo()
130 << "Input(0) " << instr->InputAt(0)->GetReferenceTypeInfo();
131 }
132 }
133 }
134 }
135 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000136}
137
Calin Juravleb1498f62015-02-16 13:13:29 +0000138void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
Calin Juravle2e768302015-07-28 14:41:11 +0000139 RTPVisitor visitor(graph_,
140 handles_,
141 &worklist_,
142 object_class_handle_,
143 class_class_handle_,
David Brazdilbbd733e2015-08-18 17:48:17 +0100144 string_class_handle_,
145 throwable_class_handle_);
Calin Juravle2e768302015-07-28 14:41:11 +0000146 // Handle Phis first as there might be instructions in the same block who depend on them.
147 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
148 VisitPhi(it.Current()->AsPhi());
149 }
Calin Juravlebeba9302015-07-08 15:57:18 +0000150
Calin Juravle2e768302015-07-28 14:41:11 +0000151 // Handle instructions.
Calin Juravleb1498f62015-02-16 13:13:29 +0000152 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
153 HInstruction* instr = it.Current();
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100154 instr->Accept(&visitor);
Calin Juravleb1498f62015-02-16 13:13:29 +0000155 }
156
Calin Juravleb1498f62015-02-16 13:13:29 +0000157 // Add extra nodes to bound types.
Calin Juravle61d544b2015-02-23 16:46:57 +0000158 BoundTypeForIfNotNull(block);
Calin Juravleb1498f62015-02-16 13:13:29 +0000159 BoundTypeForIfInstanceOf(block);
Calin Juravle10e244f2015-01-26 18:54:32 +0000160}
161
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000162// Create a bound type for the given object narrowing the type as much as possible.
163// The BoundType upper values for the super type and can_be_null will be taken from
164// load_class.GetLoadedClassRTI() and upper_can_be_null.
165static HBoundType* CreateBoundType(ArenaAllocator* arena,
166 HInstruction* obj,
167 HLoadClass* load_class,
168 bool upper_can_be_null)
169 SHARED_REQUIRES(Locks::mutator_lock_) {
170 ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo();
171 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
Calin Juravle98893e12015-10-02 21:05:03 +0100172 DCHECK(class_rti.IsValid());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000173 HBoundType* bound_type = new (arena) HBoundType(obj, class_rti, upper_can_be_null);
174 // Narrow the type as much as possible.
David Brazdilbaf89b82015-09-15 11:36:54 +0100175 if (class_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes()) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000176 bound_type->SetReferenceTypeInfo(
177 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000178 } else if (obj_rti.IsValid() && class_rti.IsSupertypeOf(obj_rti)) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000179 bound_type->SetReferenceTypeInfo(obj_rti);
180 } else {
181 bound_type->SetReferenceTypeInfo(
182 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
183 }
Nicolas Geoffrayefa84682015-08-12 18:28:14 -0700184 if (upper_can_be_null) {
185 bound_type->SetCanBeNull(obj->CanBeNull());
186 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000187 return bound_type;
188}
189
190// Check if we should create a bound type for the given object at the specified
191// position. Because of inlining and the fact we run RTP more than once and we
192// might have a HBoundType already. If we do, we should not create a new one.
193// In this case we also assert that there are no other uses of the object (except
194// the bound type) dominated by the specified dominator_instr or dominator_block.
195static bool ShouldCreateBoundType(HInstruction* position,
196 HInstruction* obj,
197 ReferenceTypeInfo upper_bound,
198 HInstruction* dominator_instr,
199 HBasicBlock* dominator_block)
200 SHARED_REQUIRES(Locks::mutator_lock_) {
201 // If the position where we should insert the bound type is not already a
202 // a bound type then we need to create one.
203 if (position == nullptr || !position->IsBoundType()) {
204 return true;
205 }
206
207 HBoundType* existing_bound_type = position->AsBoundType();
208 if (existing_bound_type->GetUpperBound().IsSupertypeOf(upper_bound)) {
209 if (kIsDebugBuild) {
210 // Check that the existing HBoundType dominates all the uses.
211 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
212 HInstruction* user = it.Current()->GetUser();
213 if (dominator_instr != nullptr) {
214 DCHECK(!dominator_instr->StrictlyDominates(user)
215 || user == existing_bound_type
216 || existing_bound_type->StrictlyDominates(user));
217 } else if (dominator_block != nullptr) {
218 DCHECK(!dominator_block->Dominates(user->GetBlock())
219 || user == existing_bound_type
220 || existing_bound_type->StrictlyDominates(user));
221 }
222 }
223 }
224 } else {
225 // TODO: if the current bound type is a refinement we could update the
226 // existing_bound_type with the a new upper limit. However, we also need to
227 // update its users and have access to the work list.
228 }
229 return false;
230}
231
Calin Juravle61d544b2015-02-23 16:46:57 +0000232void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100233 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
234 if (ifInstruction == nullptr) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000235 return;
236 }
Calin Juravleb3306642015-04-20 18:30:42 +0100237 HInstruction* ifInput = ifInstruction->InputAt(0);
Calin Juravle61d544b2015-02-23 16:46:57 +0000238 if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) {
239 return;
240 }
241 HInstruction* input0 = ifInput->InputAt(0);
242 HInstruction* input1 = ifInput->InputAt(1);
Calin Juravleedad8ad2015-04-23 14:34:33 +0100243 HInstruction* obj = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000244
Calin Juravleedad8ad2015-04-23 14:34:33 +0100245 if (input1->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000246 obj = input0;
Calin Juravleedad8ad2015-04-23 14:34:33 +0100247 } else if (input0->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000248 obj = input1;
249 } else {
250 return;
251 }
252
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100253 if (!obj->CanBeNull() || obj->IsNullConstant()) {
254 // Null check is dead code and will be removed by DCE.
255 return;
256 }
257 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
258
Calin Juravleb3306642015-04-20 18:30:42 +0100259 // We only need to bound the type if we have uses in the relevant block.
260 // So start with null and create the HBoundType lazily, only if it's needed.
261 HBoundType* bound_type = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000262 HBasicBlock* notNullBlock = ifInput->IsNotEqual()
Calin Juravleb3306642015-04-20 18:30:42 +0100263 ? ifInstruction->IfTrueSuccessor()
264 : ifInstruction->IfFalseSuccessor();
265
Calin Juravle61d544b2015-02-23 16:46:57 +0000266 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
267 HInstruction* user = it.Current()->GetUser();
268 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(
273 object_class_handle_, /* is_exact */ true);
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000274 if (ShouldCreateBoundType(insert_point, obj, object_rti, nullptr, notNullBlock)) {
275 bound_type = new (graph_->GetArena()) HBoundType(
276 obj, 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 }
Calin Juravle61d544b2015-02-23 16:46:57 +0000288 user->ReplaceInput(bound_type, it.Current()->GetIndex());
289 }
290 }
291}
292
Calin Juravleb1498f62015-02-16 13:13:29 +0000293// Detects if `block` is the True block for the pattern
294// `if (x instanceof ClassX) { }`
295// If that's the case insert an HBoundType instruction to bound the type of `x`
296// to `ClassX` in the scope of the dominated blocks.
297void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100298 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
299 if (ifInstruction == nullptr) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000300 return;
301 }
Calin Juravleb3306642015-04-20 18:30:42 +0100302 HInstruction* ifInput = ifInstruction->InputAt(0);
303 HInstruction* instanceOf = nullptr;
304 HBasicBlock* instanceOfTrueBlock = nullptr;
David Brazdil0d13fee2015-04-17 14:52:19 +0100305
Calin Juravleb3306642015-04-20 18:30:42 +0100306 // The instruction simplifier has transformed:
307 // - `if (a instanceof A)` into an HIf with an HInstanceOf input
308 // - `if (!(a instanceof A)` into an HIf with an HBooleanNot input (which in turn
309 // has an HInstanceOf input)
310 // So we should not see the usual HEqual here.
David Brazdil0d13fee2015-04-17 14:52:19 +0100311 if (ifInput->IsInstanceOf()) {
312 instanceOf = ifInput;
Calin Juravleb3306642015-04-20 18:30:42 +0100313 instanceOfTrueBlock = ifInstruction->IfTrueSuccessor();
David Brazdil0d13fee2015-04-17 14:52:19 +0100314 } else if (ifInput->IsBooleanNot() && ifInput->InputAt(0)->IsInstanceOf()) {
315 instanceOf = ifInput->InputAt(0);
Calin Juravleb3306642015-04-20 18:30:42 +0100316 instanceOfTrueBlock = ifInstruction->IfFalseSuccessor();
David Brazdil0d13fee2015-04-17 14:52:19 +0100317 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000318 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000319 }
320
Calin Juravle98893e12015-10-02 21:05:03 +0100321 HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
322 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
323 {
324 ScopedObjectAccess soa(Thread::Current());
325 if (!class_rti.IsValid()) {
326 // He have loaded an unresolved class. Don't bother bounding the type.
327 return;
328 }
329 }
Calin Juravleb3306642015-04-20 18:30:42 +0100330 // We only need to bound the type if we have uses in the relevant block.
331 // So start with null and create the HBoundType lazily, only if it's needed.
332 HBoundType* bound_type = nullptr;
333
Calin Juravleb1498f62015-02-16 13:13:29 +0000334 HInstruction* obj = instanceOf->InputAt(0);
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100335 if (obj->GetReferenceTypeInfo().IsExact() && !obj->IsPhi()) {
336 // This method is being called while doing a fixed-point calculation
337 // over phis. Non-phis instruction whose type is already known do
338 // not need to be bound to another type.
339 // Not that this also prevents replacing `HLoadClass` with a `HBoundType`.
340 // `HCheckCast` and `HInstanceOf` expect a `HLoadClass` as a second
341 // input.
342 return;
343 }
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100344 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
Calin Juravleb1498f62015-02-16 13:13:29 +0000345 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
346 HInstruction* user = it.Current()->GetUser();
347 if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100348 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000349 ScopedObjectAccess soa(Thread::Current());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000350 HInstruction* insert_point = instanceOfTrueBlock->GetFirstInstruction();
351 if (ShouldCreateBoundType(insert_point, obj, class_rti, nullptr, instanceOfTrueBlock)) {
352 bound_type = CreateBoundType(
353 graph_->GetArena(),
354 obj,
355 load_class,
356 false /* InstanceOf ensures the object is not null. */);
357 instanceOfTrueBlock->InsertInstructionBefore(bound_type, insert_point);
358 } else {
359 // We already have a bound type on the position we would need to insert
360 // the new one. The existing bound type should dominate all the users
361 // (dchecked) so there's no need to continue.
362 break;
Calin Juravleb3306642015-04-20 18:30:42 +0100363 }
Calin Juravleb3306642015-04-20 18:30:42 +0100364 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000365 user->ReplaceInput(bound_type, it.Current()->GetIndex());
366 }
367 }
Calin Juravleacf735c2015-02-12 15:25:22 +0000368}
369
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100370void RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
371 mirror::Class* klass,
372 bool is_exact) {
Calin Juravle2e768302015-07-28 14:41:11 +0000373 if (instr->IsInvokeStaticOrDirect() && instr->AsInvokeStaticOrDirect()->IsStringInit()) {
374 // Calls to String.<init> are replaced with a StringFactory.
375 if (kIsDebugBuild) {
376 ScopedObjectAccess soa(Thread::Current());
377 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700378 mirror::DexCache* dex_cache = cl->FindDexCache(
379 soa.Self(), instr->AsInvoke()->GetDexFile(), false);
Calin Juravle2e768302015-07-28 14:41:11 +0000380 ArtMethod* method = dex_cache->GetResolvedMethod(
381 instr->AsInvoke()->GetDexMethodIndex(), cl->GetImagePointerSize());
382 DCHECK(method != nullptr);
383 mirror::Class* declaring_class = method->GetDeclaringClass();
384 DCHECK(declaring_class != nullptr);
385 DCHECK(declaring_class->IsStringClass())
386 << "Expected String class: " << PrettyDescriptor(declaring_class);
387 DCHECK(method->IsConstructor())
388 << "Expected String.<init>: " << PrettyMethod(method);
389 }
390 instr->SetReferenceTypeInfo(
391 ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
392 } else if (klass != nullptr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100393 ScopedObjectAccess soa(Thread::Current());
Calin Juravle2e768302015-07-28 14:41:11 +0000394 ReferenceTypeInfo::TypeHandle handle = handles_->NewHandle(klass);
David Brazdilbaf89b82015-09-15 11:36:54 +0100395 is_exact = is_exact || klass->CannotBeAssignedFromOtherTypes();
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100396 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
Calin Juravle2e768302015-07-28 14:41:11 +0000397 } else {
398 instr->SetReferenceTypeInfo(
399 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100400 }
401}
402
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100403void RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
404 uint16_t type_idx,
405 const DexFile& dex_file,
406 bool is_exact) {
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100407 DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
408
Calin Juravleacf735c2015-02-12 15:25:22 +0000409 ScopedObjectAccess soa(Thread::Current());
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700410 mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(
411 soa.Self(), dex_file, false);
Calin Juravleacf735c2015-02-12 15:25:22 +0000412 // Get type from dex cache assuming it was populated by the verifier.
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100413 SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact);
Calin Juravleacf735c2015-02-12 15:25:22 +0000414}
415
Calin Juravle2e768302015-07-28 14:41:11 +0000416void RTPVisitor::VisitNullConstant(HNullConstant* instr) {
417 // TODO: The null constant could be bound contextually (e.g. based on return statements)
418 // to a more precise type.
419 instr->SetReferenceTypeInfo(
420 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
421}
422
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100423void RTPVisitor::VisitNewInstance(HNewInstance* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100424 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100425}
426
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100427void RTPVisitor::VisitNewArray(HNewArray* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100428 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100429}
430
Calin Juravle2e768302015-07-28 14:41:11 +0000431void RTPVisitor::VisitParameterValue(HParameterValue* instr) {
Nicolas Geoffraye418dda2015-08-11 20:03:09 -0700432 ScopedObjectAccess soa(Thread::Current());
433 // We check if the existing type is valid: the inliner may have set it.
434 if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) {
Calin Juravle2e768302015-07-28 14:41:11 +0000435 // TODO: parse the signature and add precise types for the parameters.
436 SetClassAsTypeInfo(instr, nullptr, /* is_exact */ false);
437 }
438}
439
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100440void RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
441 const FieldInfo& info) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100442 // The field index is unknown only during tests.
443 if (instr->GetType() != Primitive::kPrimNot || info.GetFieldIndex() == kUnknownFieldIndex) {
444 return;
445 }
446
447 ScopedObjectAccess soa(Thread::Current());
448 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Mathieu Chartier736b5602015-09-02 14:54:11 -0700449 ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), info.GetDexCache().Get());
Calin Juravle2e768302015-07-28 14:41:11 +0000450 // TODO: There are certain cases where we can't resolve the field.
451 // b/21914925 is open to keep track of a repro case for this issue.
452 mirror::Class* klass = (field == nullptr) ? nullptr : field->GetType<false>();
453 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100454}
455
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100456void RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100457 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
458}
459
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100460void RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100461 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
462}
463
Calin Juravlee460d1d2015-09-29 04:52:17 +0100464void RTPVisitor::VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instr) {
465 // TODO: Use descriptor to get the actual type.
466 if (instr->GetFieldType() == Primitive::kPrimNot) {
467 instr->SetReferenceTypeInfo(
468 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
469 }
470}
471
472void RTPVisitor::VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet* instr) {
473 // TODO: Use descriptor to get the actual type.
474 if (instr->GetFieldType() == Primitive::kPrimNot) {
475 instr->SetReferenceTypeInfo(
476 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
477 }
478}
479
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100480void RTPVisitor::VisitLoadClass(HLoadClass* instr) {
Calin Juravleacf735c2015-02-12 15:25:22 +0000481 ScopedObjectAccess soa(Thread::Current());
Nicolas Geoffrayd5111bf2015-05-22 15:37:09 +0100482 mirror::DexCache* dex_cache =
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700483 Runtime::Current()->GetClassLinker()->FindDexCache(soa.Self(), instr->GetDexFile(), false);
Calin Juravleacf735c2015-02-12 15:25:22 +0000484 // Get type from dex cache assuming it was populated by the verifier.
485 mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
Calin Juravle51d135f2015-07-29 19:25:24 +0100486 // TODO: investigating why we are still getting unresolved classes: b/22821472.
Calin Juravle98893e12015-10-02 21:05:03 +0100487 if (resolved_class != nullptr) {
488 instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(
489 handles_->NewHandle(resolved_class), /* is_exact */ true));
490 }
Calin Juravle2e768302015-07-28 14:41:11 +0000491 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(class_class_handle_, /* is_exact */ true));
492}
493
494void RTPVisitor::VisitClinitCheck(HClinitCheck* instr) {
495 instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
496}
497
498void RTPVisitor::VisitLoadString(HLoadString* instr) {
499 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
500}
501
David Brazdilbbd733e2015-08-18 17:48:17 +0100502void RTPVisitor::VisitLoadException(HLoadException* instr) {
503 DCHECK(instr->GetBlock()->IsCatchBlock());
504 TryCatchInformation* catch_info = instr->GetBlock()->GetTryCatchInformation();
505
506 if (catch_info->IsCatchAllTypeIndex()) {
507 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(throwable_class_handle_,
David Brazdilb4edcf32015-08-20 17:05:49 +0100508 /* is_exact */ false));
David Brazdilbbd733e2015-08-18 17:48:17 +0100509 } else {
510 UpdateReferenceTypeInfo(instr,
511 catch_info->GetCatchTypeIndex(),
512 catch_info->GetCatchDexFile(),
513 /* is_exact */ false);
514 }
515}
516
Calin Juravle2e768302015-07-28 14:41:11 +0000517void RTPVisitor::VisitNullCheck(HNullCheck* instr) {
518 ScopedObjectAccess soa(Thread::Current());
519 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
520 DCHECK(parent_rti.IsValid());
521 instr->SetReferenceTypeInfo(parent_rti);
522}
523
524void RTPVisitor::VisitFakeString(HFakeString* instr) {
525 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
Calin Juravleacf735c2015-02-12 15:25:22 +0000526}
Calin Juravle10e244f2015-01-26 18:54:32 +0000527
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000528void RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
Calin Juravle98893e12015-10-02 21:05:03 +0100529 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
530 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
531 {
532 ScopedObjectAccess soa(Thread::Current());
533 if (!class_rti.IsValid()) {
534 // He have loaded an unresolved class. Don't bother bounding the type.
535 return;
536 }
537 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000538 HInstruction* obj = check_cast->InputAt(0);
539 HBoundType* bound_type = nullptr;
540 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
541 HInstruction* user = it.Current()->GetUser();
542 if (check_cast->StrictlyDominates(user)) {
543 if (bound_type == nullptr) {
544 ScopedObjectAccess soa(Thread::Current());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000545 if (ShouldCreateBoundType(check_cast->GetNext(), obj, class_rti, check_cast, nullptr)) {
546 bound_type = CreateBoundType(
547 GetGraph()->GetArena(),
548 obj,
549 load_class,
550 true /* CheckCast succeeds for nulls. */);
551 check_cast->GetBlock()->InsertInstructionAfter(bound_type, check_cast);
552 } else {
Nicolas Geoffrayefa84682015-08-12 18:28:14 -0700553 // Update nullability of the existing bound type, which may not have known
554 // that its input was not null when it was being created.
555 bound_type = check_cast->GetNext()->AsBoundType();
556 bound_type->SetCanBeNull(obj->CanBeNull());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000557 // We already have a bound type on the position we would need to insert
558 // the new one. The existing bound type should dominate all the users
559 // (dchecked) so there's no need to continue.
560 break;
561 }
562 }
563 user->ReplaceInput(bound_type, it.Current()->GetIndex());
564 }
565 }
566}
567
Calin Juravleb1498f62015-02-16 13:13:29 +0000568void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
569 if (phi->GetType() != Primitive::kPrimNot) {
570 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000571 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000572
573 if (phi->GetBlock()->IsLoopHeader()) {
574 // Set the initial type for the phi. Use the non back edge input for reaching
575 // a fixed point faster.
576 AddToWorklist(phi);
577 phi->SetCanBeNull(phi->InputAt(0)->CanBeNull());
578 phi->SetReferenceTypeInfo(phi->InputAt(0)->GetReferenceTypeInfo());
Calin Juravle10e244f2015-01-26 18:54:32 +0000579 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000580 // Eagerly compute the type of the phi, for quicker convergence. Note
581 // that we don't need to add users to the worklist because we are
582 // doing a reverse post-order visit, therefore either the phi users are
583 // non-loop phi and will be visited later in the visit, or are loop-phis,
584 // and they are already in the work list.
585 UpdateNullability(phi);
586 UpdateReferenceTypeInfo(phi);
587 }
588}
589
590ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
591 const ReferenceTypeInfo& b) {
Calin Juravle2e768302015-07-28 14:41:11 +0000592 if (!b.IsValid()) {
593 return a;
594 }
595 if (!a.IsValid()) {
596 return b;
Calin Juravle20e60712015-07-01 18:41:04 +0100597 }
598
Calin Juravle2e768302015-07-28 14:41:11 +0000599 bool is_exact = a.IsExact() && b.IsExact();
600 Handle<mirror::Class> type_handle;
601
602 if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
603 type_handle = a.GetTypeHandle();
604 } else if (a.IsSupertypeOf(b)) {
605 type_handle = a.GetTypeHandle();
606 is_exact = false;
607 } else if (b.IsSupertypeOf(a)) {
608 type_handle = b.GetTypeHandle();
609 is_exact = false;
610 } else {
611 // TODO: Find the first common super class.
612 type_handle = object_class_handle_;
613 is_exact = false;
614 }
615
616 return ReferenceTypeInfo::Create(type_handle, is_exact);
617}
618
619static void UpdateArrayGet(HArrayGet* instr,
620 StackHandleScopeCollection* handles,
621 ReferenceTypeInfo::TypeHandle object_class_handle)
622 SHARED_REQUIRES(Locks::mutator_lock_) {
623 DCHECK_EQ(Primitive::kPrimNot, instr->GetType());
624
625 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
626 DCHECK(parent_rti.IsValid());
627
628 Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
629 if (handle->IsObjectArrayClass()) {
630 ReferenceTypeInfo::TypeHandle component_handle = handles->NewHandle(handle->GetComponentType());
631 instr->SetReferenceTypeInfo(
632 ReferenceTypeInfo::Create(component_handle, /* is_exact */ false));
633 } else {
634 // We don't know what the parent actually is, so we fallback to object.
635 instr->SetReferenceTypeInfo(
636 ReferenceTypeInfo::Create(object_class_handle, /* is_exact */ false));
637 }
638
639 return;
Calin Juravleb1498f62015-02-16 13:13:29 +0000640}
641
642bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
643 ScopedObjectAccess soa(Thread::Current());
644
645 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
646 if (instr->IsBoundType()) {
647 UpdateBoundType(instr->AsBoundType());
648 } else if (instr->IsPhi()) {
649 UpdatePhi(instr->AsPhi());
Calin Juravle2e768302015-07-28 14:41:11 +0000650 } else if (instr->IsNullCheck()) {
651 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
652 if (parent_rti.IsValid()) {
653 instr->SetReferenceTypeInfo(parent_rti);
654 }
655 } else if (instr->IsArrayGet()) {
656 // TODO: consider if it's worth "looking back" and bounding the input object
657 // to an array type.
658 UpdateArrayGet(instr->AsArrayGet(), handles_, object_class_handle_);
Calin Juravleb1498f62015-02-16 13:13:29 +0000659 } else {
660 LOG(FATAL) << "Invalid instruction (should not get here)";
661 }
662
663 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
664}
665
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100666void RTPVisitor::VisitInvoke(HInvoke* instr) {
667 if (instr->GetType() != Primitive::kPrimNot) {
668 return;
669 }
670
671 ScopedObjectAccess soa(Thread::Current());
672 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700673 mirror::DexCache* dex_cache = cl->FindDexCache(soa.Self(), instr->GetDexFile());
Vladimir Marko05792b92015-08-03 11:56:49 +0100674 size_t pointer_size = cl->GetImagePointerSize();
675 ArtMethod* method = dex_cache->GetResolvedMethod(instr->GetDexMethodIndex(), pointer_size);
676 mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false, pointer_size);
Calin Juravle2e768302015-07-28 14:41:11 +0000677 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100678}
679
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100680void RTPVisitor::VisitArrayGet(HArrayGet* instr) {
681 if (instr->GetType() != Primitive::kPrimNot) {
682 return;
683 }
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100684 ScopedObjectAccess soa(Thread::Current());
Calin Juravle2e768302015-07-28 14:41:11 +0000685 UpdateArrayGet(instr, handles_, object_class_handle_);
686 if (!instr->GetReferenceTypeInfo().IsValid()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100687 worklist_->push_back(instr);
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100688 }
689}
690
Calin Juravleb1498f62015-02-16 13:13:29 +0000691void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
692 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle2e768302015-07-28 14:41:11 +0000693 if (!new_rti.IsValid()) {
694 return; // No new info yet.
695 }
696
697 // Make sure that we don't go over the bounded type.
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000698 ReferenceTypeInfo upper_bound_rti = instr->GetUpperBound();
699 if (!upper_bound_rti.IsSupertypeOf(new_rti)) {
700 new_rti = upper_bound_rti;
Calin Juravleb1498f62015-02-16 13:13:29 +0000701 }
702 instr->SetReferenceTypeInfo(new_rti);
703}
704
705void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
706 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle2e768302015-07-28 14:41:11 +0000707 if (new_rti.IsValid() && new_rti.IsObjectClass() && !new_rti.IsExact()) {
708 // Early return if we are Object and inexact.
Calin Juravleb1498f62015-02-16 13:13:29 +0000709 instr->SetReferenceTypeInfo(new_rti);
710 return;
711 }
712 for (size_t i = 1; i < instr->InputCount(); i++) {
713 new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo());
Calin Juravle2e768302015-07-28 14:41:11 +0000714 if (new_rti.IsValid() && new_rti.IsObjectClass()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000715 if (!new_rti.IsExact()) {
716 break;
717 } else {
718 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000719 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000720 }
721 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000722 instr->SetReferenceTypeInfo(new_rti);
723}
724
725// Re-computes and updates the nullability of the instruction. Returns whether or
726// not the nullability was changed.
727bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
Calin Juravle2e768302015-07-28 14:41:11 +0000728 DCHECK(instr->IsPhi()
729 || instr->IsBoundType()
730 || instr->IsNullCheck()
731 || instr->IsArrayGet());
732
733 if (!instr->IsPhi() && !instr->IsBoundType()) {
734 return false;
735 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000736
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000737 bool existing_can_be_null = instr->CanBeNull();
738 if (instr->IsPhi()) {
739 HPhi* phi = instr->AsPhi();
740 bool new_can_be_null = false;
741 for (size_t i = 0; i < phi->InputCount(); i++) {
742 if (phi->InputAt(i)->CanBeNull()) {
743 new_can_be_null = true;
744 break;
745 }
746 }
747 phi->SetCanBeNull(new_can_be_null);
748 } else if (instr->IsBoundType()) {
749 HBoundType* bound_type = instr->AsBoundType();
750 bound_type->SetCanBeNull(instr->InputAt(0)->CanBeNull() && bound_type->GetUpperCanBeNull());
Calin Juravleb1498f62015-02-16 13:13:29 +0000751 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000752 return existing_can_be_null != instr->CanBeNull();
Calin Juravle10e244f2015-01-26 18:54:32 +0000753}
754
755void ReferenceTypePropagation::ProcessWorklist() {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100756 while (!worklist_.empty()) {
757 HInstruction* instruction = worklist_.back();
758 worklist_.pop_back();
Calin Juravleacf735c2015-02-12 15:25:22 +0000759 if (UpdateNullability(instruction) || UpdateReferenceTypeInfo(instruction)) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000760 AddDependentInstructionsToWorklist(instruction);
761 }
762 }
763}
764
Calin Juravleb1498f62015-02-16 13:13:29 +0000765void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
Calin Juravle2e768302015-07-28 14:41:11 +0000766 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot)
767 << instruction->DebugName() << ":" << instruction->GetType();
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100768 worklist_.push_back(instruction);
Calin Juravle10e244f2015-01-26 18:54:32 +0000769}
770
Calin Juravleb1498f62015-02-16 13:13:29 +0000771void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000772 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000773 HInstruction* user = it.Current()->GetUser();
Calin Juravle2e768302015-07-28 14:41:11 +0000774 if (user->IsPhi()
775 || user->IsBoundType()
776 || user->IsNullCheck()
777 || (user->IsArrayGet() && (user->GetType() == Primitive::kPrimNot))) {
Calin Juravlebeba9302015-07-08 15:57:18 +0000778 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000779 }
780 }
781}
Calin Juravle10e244f2015-01-26 18:54:32 +0000782} // namespace art