blob: abfbcacef75993f323323e36a08f6c0815eb5b77 [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 Juravlee6e3bea2015-10-14 13:53:10 +0000431static mirror::Class* GetClassFromDexCache(Thread* self, const DexFile& dex_file, uint16_t type_idx)
432 SHARED_REQUIRES(Locks::mutator_lock_) {
433 mirror::DexCache* dex_cache =
434 Runtime::Current()->GetClassLinker()->FindDexCache(self, dex_file, false);
435 // Get type from dex cache assuming it was populated by the verifier.
436 return dex_cache->GetResolvedType(type_idx);
437}
438
Calin Juravle2e768302015-07-28 14:41:11 +0000439void RTPVisitor::VisitParameterValue(HParameterValue* instr) {
Nicolas Geoffraye418dda2015-08-11 20:03:09 -0700440 ScopedObjectAccess soa(Thread::Current());
441 // We check if the existing type is valid: the inliner may have set it.
442 if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) {
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000443 mirror::Class* resolved_class =
444 GetClassFromDexCache(soa.Self(), instr->GetDexFile(), instr->GetTypeIndex());
445 SetClassAsTypeInfo(instr, resolved_class, /* is_exact */ false);
Calin Juravle2e768302015-07-28 14:41:11 +0000446 }
447}
448
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100449void RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
450 const FieldInfo& info) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100451 // The field index is unknown only during tests.
452 if (instr->GetType() != Primitive::kPrimNot || info.GetFieldIndex() == kUnknownFieldIndex) {
453 return;
454 }
455
456 ScopedObjectAccess soa(Thread::Current());
457 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Mathieu Chartier736b5602015-09-02 14:54:11 -0700458 ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), info.GetDexCache().Get());
Calin Juravle2e768302015-07-28 14:41:11 +0000459 // TODO: There are certain cases where we can't resolve the field.
460 // b/21914925 is open to keep track of a repro case for this issue.
461 mirror::Class* klass = (field == nullptr) ? nullptr : field->GetType<false>();
462 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100463}
464
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100465void RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100466 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
467}
468
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100469void RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100470 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
471}
472
Calin Juravlee460d1d2015-09-29 04:52:17 +0100473void RTPVisitor::VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instr) {
474 // TODO: Use descriptor to get the actual type.
475 if (instr->GetFieldType() == Primitive::kPrimNot) {
476 instr->SetReferenceTypeInfo(
477 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
478 }
479}
480
481void RTPVisitor::VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet* instr) {
482 // TODO: Use descriptor to get the actual type.
483 if (instr->GetFieldType() == Primitive::kPrimNot) {
484 instr->SetReferenceTypeInfo(
485 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
486 }
487}
488
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100489void RTPVisitor::VisitLoadClass(HLoadClass* instr) {
Calin Juravleacf735c2015-02-12 15:25:22 +0000490 ScopedObjectAccess soa(Thread::Current());
Calin Juravleacf735c2015-02-12 15:25:22 +0000491 // Get type from dex cache assuming it was populated by the verifier.
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000492 mirror::Class* resolved_class =
493 GetClassFromDexCache(soa.Self(), instr->GetDexFile(), instr->GetTypeIndex());
Calin Juravle98893e12015-10-02 21:05:03 +0100494 if (resolved_class != nullptr) {
495 instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(
496 handles_->NewHandle(resolved_class), /* is_exact */ true));
497 }
Calin Juravle2e768302015-07-28 14:41:11 +0000498 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(class_class_handle_, /* is_exact */ true));
499}
500
501void RTPVisitor::VisitClinitCheck(HClinitCheck* instr) {
502 instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
503}
504
505void RTPVisitor::VisitLoadString(HLoadString* instr) {
506 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
507}
508
David Brazdilbbd733e2015-08-18 17:48:17 +0100509void RTPVisitor::VisitLoadException(HLoadException* instr) {
510 DCHECK(instr->GetBlock()->IsCatchBlock());
511 TryCatchInformation* catch_info = instr->GetBlock()->GetTryCatchInformation();
512
513 if (catch_info->IsCatchAllTypeIndex()) {
514 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(throwable_class_handle_,
David Brazdilb4edcf32015-08-20 17:05:49 +0100515 /* is_exact */ false));
David Brazdilbbd733e2015-08-18 17:48:17 +0100516 } else {
517 UpdateReferenceTypeInfo(instr,
518 catch_info->GetCatchTypeIndex(),
519 catch_info->GetCatchDexFile(),
520 /* is_exact */ false);
521 }
522}
523
Calin Juravle2e768302015-07-28 14:41:11 +0000524void RTPVisitor::VisitNullCheck(HNullCheck* instr) {
525 ScopedObjectAccess soa(Thread::Current());
526 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
527 DCHECK(parent_rti.IsValid());
528 instr->SetReferenceTypeInfo(parent_rti);
529}
530
531void RTPVisitor::VisitFakeString(HFakeString* instr) {
532 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
Calin Juravleacf735c2015-02-12 15:25:22 +0000533}
Calin Juravle10e244f2015-01-26 18:54:32 +0000534
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000535void RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
Calin Juravle98893e12015-10-02 21:05:03 +0100536 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
537 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
538 {
539 ScopedObjectAccess soa(Thread::Current());
540 if (!class_rti.IsValid()) {
541 // He have loaded an unresolved class. Don't bother bounding the type.
542 return;
543 }
544 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000545 HInstruction* obj = check_cast->InputAt(0);
546 HBoundType* bound_type = nullptr;
547 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
548 HInstruction* user = it.Current()->GetUser();
549 if (check_cast->StrictlyDominates(user)) {
550 if (bound_type == nullptr) {
551 ScopedObjectAccess soa(Thread::Current());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000552 if (ShouldCreateBoundType(check_cast->GetNext(), obj, class_rti, check_cast, nullptr)) {
553 bound_type = CreateBoundType(
554 GetGraph()->GetArena(),
555 obj,
556 load_class,
557 true /* CheckCast succeeds for nulls. */);
558 check_cast->GetBlock()->InsertInstructionAfter(bound_type, check_cast);
559 } else {
Nicolas Geoffrayefa84682015-08-12 18:28:14 -0700560 // Update nullability of the existing bound type, which may not have known
561 // that its input was not null when it was being created.
562 bound_type = check_cast->GetNext()->AsBoundType();
563 bound_type->SetCanBeNull(obj->CanBeNull());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000564 // We already have a bound type on the position we would need to insert
565 // the new one. The existing bound type should dominate all the users
566 // (dchecked) so there's no need to continue.
567 break;
568 }
569 }
570 user->ReplaceInput(bound_type, it.Current()->GetIndex());
571 }
572 }
573}
574
Calin Juravleb1498f62015-02-16 13:13:29 +0000575void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
576 if (phi->GetType() != Primitive::kPrimNot) {
577 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000578 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000579
580 if (phi->GetBlock()->IsLoopHeader()) {
581 // Set the initial type for the phi. Use the non back edge input for reaching
582 // a fixed point faster.
583 AddToWorklist(phi);
584 phi->SetCanBeNull(phi->InputAt(0)->CanBeNull());
585 phi->SetReferenceTypeInfo(phi->InputAt(0)->GetReferenceTypeInfo());
Calin Juravle10e244f2015-01-26 18:54:32 +0000586 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000587 // Eagerly compute the type of the phi, for quicker convergence. Note
588 // that we don't need to add users to the worklist because we are
589 // doing a reverse post-order visit, therefore either the phi users are
590 // non-loop phi and will be visited later in the visit, or are loop-phis,
591 // and they are already in the work list.
592 UpdateNullability(phi);
593 UpdateReferenceTypeInfo(phi);
594 }
595}
596
597ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
598 const ReferenceTypeInfo& b) {
Calin Juravle2e768302015-07-28 14:41:11 +0000599 if (!b.IsValid()) {
600 return a;
601 }
602 if (!a.IsValid()) {
603 return b;
Calin Juravle20e60712015-07-01 18:41:04 +0100604 }
605
Calin Juravle2e768302015-07-28 14:41:11 +0000606 bool is_exact = a.IsExact() && b.IsExact();
607 Handle<mirror::Class> type_handle;
608
609 if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
610 type_handle = a.GetTypeHandle();
611 } else if (a.IsSupertypeOf(b)) {
612 type_handle = a.GetTypeHandle();
613 is_exact = false;
614 } else if (b.IsSupertypeOf(a)) {
615 type_handle = b.GetTypeHandle();
616 is_exact = false;
617 } else {
618 // TODO: Find the first common super class.
619 type_handle = object_class_handle_;
620 is_exact = false;
621 }
622
623 return ReferenceTypeInfo::Create(type_handle, is_exact);
624}
625
626static void UpdateArrayGet(HArrayGet* instr,
627 StackHandleScopeCollection* handles,
628 ReferenceTypeInfo::TypeHandle object_class_handle)
629 SHARED_REQUIRES(Locks::mutator_lock_) {
630 DCHECK_EQ(Primitive::kPrimNot, instr->GetType());
631
632 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
633 DCHECK(parent_rti.IsValid());
634
635 Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
636 if (handle->IsObjectArrayClass()) {
637 ReferenceTypeInfo::TypeHandle component_handle = handles->NewHandle(handle->GetComponentType());
638 instr->SetReferenceTypeInfo(
639 ReferenceTypeInfo::Create(component_handle, /* is_exact */ false));
640 } else {
641 // We don't know what the parent actually is, so we fallback to object.
642 instr->SetReferenceTypeInfo(
643 ReferenceTypeInfo::Create(object_class_handle, /* is_exact */ false));
644 }
645
646 return;
Calin Juravleb1498f62015-02-16 13:13:29 +0000647}
648
649bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
650 ScopedObjectAccess soa(Thread::Current());
651
652 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
653 if (instr->IsBoundType()) {
654 UpdateBoundType(instr->AsBoundType());
655 } else if (instr->IsPhi()) {
656 UpdatePhi(instr->AsPhi());
Calin Juravle2e768302015-07-28 14:41:11 +0000657 } else if (instr->IsNullCheck()) {
658 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
659 if (parent_rti.IsValid()) {
660 instr->SetReferenceTypeInfo(parent_rti);
661 }
662 } else if (instr->IsArrayGet()) {
663 // TODO: consider if it's worth "looking back" and bounding the input object
664 // to an array type.
665 UpdateArrayGet(instr->AsArrayGet(), handles_, object_class_handle_);
Calin Juravleb1498f62015-02-16 13:13:29 +0000666 } else {
667 LOG(FATAL) << "Invalid instruction (should not get here)";
668 }
669
670 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
671}
672
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100673void RTPVisitor::VisitInvoke(HInvoke* instr) {
674 if (instr->GetType() != Primitive::kPrimNot) {
675 return;
676 }
677
678 ScopedObjectAccess soa(Thread::Current());
679 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700680 mirror::DexCache* dex_cache = cl->FindDexCache(soa.Self(), instr->GetDexFile());
Vladimir Marko05792b92015-08-03 11:56:49 +0100681 size_t pointer_size = cl->GetImagePointerSize();
682 ArtMethod* method = dex_cache->GetResolvedMethod(instr->GetDexMethodIndex(), pointer_size);
683 mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false, pointer_size);
Calin Juravle2e768302015-07-28 14:41:11 +0000684 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100685}
686
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100687void RTPVisitor::VisitArrayGet(HArrayGet* instr) {
688 if (instr->GetType() != Primitive::kPrimNot) {
689 return;
690 }
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100691 ScopedObjectAccess soa(Thread::Current());
Calin Juravle2e768302015-07-28 14:41:11 +0000692 UpdateArrayGet(instr, handles_, object_class_handle_);
693 if (!instr->GetReferenceTypeInfo().IsValid()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100694 worklist_->push_back(instr);
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100695 }
696}
697
Calin Juravleb1498f62015-02-16 13:13:29 +0000698void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
699 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle2e768302015-07-28 14:41:11 +0000700 if (!new_rti.IsValid()) {
701 return; // No new info yet.
702 }
703
704 // Make sure that we don't go over the bounded type.
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000705 ReferenceTypeInfo upper_bound_rti = instr->GetUpperBound();
706 if (!upper_bound_rti.IsSupertypeOf(new_rti)) {
707 new_rti = upper_bound_rti;
Calin Juravleb1498f62015-02-16 13:13:29 +0000708 }
709 instr->SetReferenceTypeInfo(new_rti);
710}
711
712void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
713 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle2e768302015-07-28 14:41:11 +0000714 if (new_rti.IsValid() && new_rti.IsObjectClass() && !new_rti.IsExact()) {
715 // Early return if we are Object and inexact.
Calin Juravleb1498f62015-02-16 13:13:29 +0000716 instr->SetReferenceTypeInfo(new_rti);
717 return;
718 }
719 for (size_t i = 1; i < instr->InputCount(); i++) {
720 new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo());
Calin Juravle2e768302015-07-28 14:41:11 +0000721 if (new_rti.IsValid() && new_rti.IsObjectClass()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000722 if (!new_rti.IsExact()) {
723 break;
724 } else {
725 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000726 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000727 }
728 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000729 instr->SetReferenceTypeInfo(new_rti);
730}
731
732// Re-computes and updates the nullability of the instruction. Returns whether or
733// not the nullability was changed.
734bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
Calin Juravle2e768302015-07-28 14:41:11 +0000735 DCHECK(instr->IsPhi()
736 || instr->IsBoundType()
737 || instr->IsNullCheck()
738 || instr->IsArrayGet());
739
740 if (!instr->IsPhi() && !instr->IsBoundType()) {
741 return false;
742 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000743
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000744 bool existing_can_be_null = instr->CanBeNull();
745 if (instr->IsPhi()) {
746 HPhi* phi = instr->AsPhi();
747 bool new_can_be_null = false;
748 for (size_t i = 0; i < phi->InputCount(); i++) {
749 if (phi->InputAt(i)->CanBeNull()) {
750 new_can_be_null = true;
751 break;
752 }
753 }
754 phi->SetCanBeNull(new_can_be_null);
755 } else if (instr->IsBoundType()) {
756 HBoundType* bound_type = instr->AsBoundType();
757 bound_type->SetCanBeNull(instr->InputAt(0)->CanBeNull() && bound_type->GetUpperCanBeNull());
Calin Juravleb1498f62015-02-16 13:13:29 +0000758 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000759 return existing_can_be_null != instr->CanBeNull();
Calin Juravle10e244f2015-01-26 18:54:32 +0000760}
761
762void ReferenceTypePropagation::ProcessWorklist() {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100763 while (!worklist_.empty()) {
764 HInstruction* instruction = worklist_.back();
765 worklist_.pop_back();
Calin Juravleacf735c2015-02-12 15:25:22 +0000766 if (UpdateNullability(instruction) || UpdateReferenceTypeInfo(instruction)) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000767 AddDependentInstructionsToWorklist(instruction);
768 }
769 }
770}
771
Calin Juravleb1498f62015-02-16 13:13:29 +0000772void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
Calin Juravle2e768302015-07-28 14:41:11 +0000773 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot)
774 << instruction->DebugName() << ":" << instruction->GetType();
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100775 worklist_.push_back(instruction);
Calin Juravle10e244f2015-01-26 18:54:32 +0000776}
777
Calin Juravleb1498f62015-02-16 13:13:29 +0000778void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000779 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000780 HInstruction* user = it.Current()->GetUser();
Calin Juravle2e768302015-07-28 14:41:11 +0000781 if (user->IsPhi()
782 || user->IsBoundType()
783 || user->IsNullCheck()
784 || (user->IsArrayGet() && (user->GetType() == Primitive::kPrimNot))) {
Calin Juravlebeba9302015-07-08 15:57:18 +0000785 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000786 }
787 }
788}
Calin Juravle10e244f2015-01-26 18:54:32 +0000789} // namespace art