blob: 3b782647274d6776bae91f1f234f47ce8e56714a [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 Juravlecdfed3d2015-10-26 14:05:01 +0000102void ReferenceTypePropagation::ValidateTypes() {
103 // TODO: move this to the graph checker.
Calin Juravle2e768302015-07-28 14:41:11 +0000104 if (kIsDebugBuild) {
Calin Juravle2e768302015-07-28 14:41:11 +0000105 ScopedObjectAccess soa(Thread::Current());
106 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
107 HBasicBlock* block = it.Current();
108 for (HInstructionIterator iti(block->GetInstructions()); !iti.Done(); iti.Advance()) {
109 HInstruction* instr = iti.Current();
110 if (instr->GetType() == Primitive::kPrimNot) {
111 DCHECK(instr->GetReferenceTypeInfo().IsValid())
112 << "Invalid RTI for instruction: " << instr->DebugName();
113 if (instr->IsBoundType()) {
114 DCHECK(instr->AsBoundType()->GetUpperBound().IsValid());
115 } else if (instr->IsLoadClass()) {
Calin Juravle98893e12015-10-02 21:05:03 +0100116 HLoadClass* cls = instr->AsLoadClass();
117 DCHECK(cls->GetReferenceTypeInfo().IsExact());
118 DCHECK(!cls->GetLoadedClassRTI().IsValid() || cls->GetLoadedClassRTI().IsExact());
Calin Juravle2e768302015-07-28 14:41:11 +0000119 } else if (instr->IsNullCheck()) {
120 DCHECK(instr->GetReferenceTypeInfo().IsEqual(instr->InputAt(0)->GetReferenceTypeInfo()))
121 << "NullCheck " << instr->GetReferenceTypeInfo()
122 << "Input(0) " << instr->InputAt(0)->GetReferenceTypeInfo();
123 }
124 }
125 }
126 }
127 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000128}
129
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000130void ReferenceTypePropagation::Run() {
131 // To properly propagate type info we need to visit in the dominator-based order.
132 // Reverse post order guarantees a node's dominators are visited first.
133 // We take advantage of this order in `VisitBasicBlock`.
134 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
135 VisitBasicBlock(it.Current());
136 }
137
138 ProcessWorklist();
139 ValidateTypes();
140}
141
Calin Juravleb1498f62015-02-16 13:13:29 +0000142void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
Calin Juravle2e768302015-07-28 14:41:11 +0000143 RTPVisitor visitor(graph_,
144 handles_,
145 &worklist_,
146 object_class_handle_,
147 class_class_handle_,
David Brazdilbbd733e2015-08-18 17:48:17 +0100148 string_class_handle_,
149 throwable_class_handle_);
Calin Juravle2e768302015-07-28 14:41:11 +0000150 // Handle Phis first as there might be instructions in the same block who depend on them.
151 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
152 VisitPhi(it.Current()->AsPhi());
153 }
Calin Juravlebeba9302015-07-08 15:57:18 +0000154
Calin Juravle2e768302015-07-28 14:41:11 +0000155 // Handle instructions.
Calin Juravleb1498f62015-02-16 13:13:29 +0000156 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
157 HInstruction* instr = it.Current();
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100158 instr->Accept(&visitor);
Calin Juravleb1498f62015-02-16 13:13:29 +0000159 }
160
Calin Juravleb1498f62015-02-16 13:13:29 +0000161 // Add extra nodes to bound types.
Calin Juravle61d544b2015-02-23 16:46:57 +0000162 BoundTypeForIfNotNull(block);
Calin Juravleb1498f62015-02-16 13:13:29 +0000163 BoundTypeForIfInstanceOf(block);
Calin Juravle10e244f2015-01-26 18:54:32 +0000164}
165
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000166// Create a bound type for the given object narrowing the type as much as possible.
167// The BoundType upper values for the super type and can_be_null will be taken from
168// load_class.GetLoadedClassRTI() and upper_can_be_null.
169static HBoundType* CreateBoundType(ArenaAllocator* arena,
170 HInstruction* obj,
171 HLoadClass* load_class,
172 bool upper_can_be_null)
173 SHARED_REQUIRES(Locks::mutator_lock_) {
174 ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo();
175 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
Calin Juravle98893e12015-10-02 21:05:03 +0100176 DCHECK(class_rti.IsValid());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000177 HBoundType* bound_type = new (arena) HBoundType(obj, class_rti, upper_can_be_null);
178 // Narrow the type as much as possible.
David Brazdilbaf89b82015-09-15 11:36:54 +0100179 if (class_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes()) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000180 bound_type->SetReferenceTypeInfo(
181 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000182 } else if (obj_rti.IsValid() && class_rti.IsSupertypeOf(obj_rti)) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000183 bound_type->SetReferenceTypeInfo(obj_rti);
184 } else {
185 bound_type->SetReferenceTypeInfo(
186 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
187 }
Nicolas Geoffrayefa84682015-08-12 18:28:14 -0700188 if (upper_can_be_null) {
189 bound_type->SetCanBeNull(obj->CanBeNull());
190 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000191 return bound_type;
192}
193
194// Check if we should create a bound type for the given object at the specified
195// position. Because of inlining and the fact we run RTP more than once and we
196// might have a HBoundType already. If we do, we should not create a new one.
197// In this case we also assert that there are no other uses of the object (except
198// the bound type) dominated by the specified dominator_instr or dominator_block.
199static bool ShouldCreateBoundType(HInstruction* position,
200 HInstruction* obj,
201 ReferenceTypeInfo upper_bound,
202 HInstruction* dominator_instr,
203 HBasicBlock* dominator_block)
204 SHARED_REQUIRES(Locks::mutator_lock_) {
205 // If the position where we should insert the bound type is not already a
206 // a bound type then we need to create one.
207 if (position == nullptr || !position->IsBoundType()) {
208 return true;
209 }
210
211 HBoundType* existing_bound_type = position->AsBoundType();
212 if (existing_bound_type->GetUpperBound().IsSupertypeOf(upper_bound)) {
213 if (kIsDebugBuild) {
214 // Check that the existing HBoundType dominates all the uses.
215 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
216 HInstruction* user = it.Current()->GetUser();
217 if (dominator_instr != nullptr) {
218 DCHECK(!dominator_instr->StrictlyDominates(user)
219 || user == existing_bound_type
220 || existing_bound_type->StrictlyDominates(user));
221 } else if (dominator_block != nullptr) {
222 DCHECK(!dominator_block->Dominates(user->GetBlock())
223 || user == existing_bound_type
224 || existing_bound_type->StrictlyDominates(user));
225 }
226 }
227 }
228 } else {
229 // TODO: if the current bound type is a refinement we could update the
230 // existing_bound_type with the a new upper limit. However, we also need to
231 // update its users and have access to the work list.
232 }
233 return false;
234}
235
Calin Juravle61d544b2015-02-23 16:46:57 +0000236void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100237 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
238 if (ifInstruction == nullptr) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000239 return;
240 }
Calin Juravleb3306642015-04-20 18:30:42 +0100241 HInstruction* ifInput = ifInstruction->InputAt(0);
Calin Juravle61d544b2015-02-23 16:46:57 +0000242 if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) {
243 return;
244 }
245 HInstruction* input0 = ifInput->InputAt(0);
246 HInstruction* input1 = ifInput->InputAt(1);
Calin Juravleedad8ad2015-04-23 14:34:33 +0100247 HInstruction* obj = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000248
Calin Juravleedad8ad2015-04-23 14:34:33 +0100249 if (input1->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000250 obj = input0;
Calin Juravleedad8ad2015-04-23 14:34:33 +0100251 } else if (input0->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000252 obj = input1;
253 } else {
254 return;
255 }
256
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100257 if (!obj->CanBeNull() || obj->IsNullConstant()) {
258 // Null check is dead code and will be removed by DCE.
259 return;
260 }
261 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
262
Calin Juravleb3306642015-04-20 18:30:42 +0100263 // We only need to bound the type if we have uses in the relevant block.
264 // So start with null and create the HBoundType lazily, only if it's needed.
265 HBoundType* bound_type = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000266 HBasicBlock* notNullBlock = ifInput->IsNotEqual()
Calin Juravleb3306642015-04-20 18:30:42 +0100267 ? ifInstruction->IfTrueSuccessor()
268 : ifInstruction->IfFalseSuccessor();
269
Calin Juravle61d544b2015-02-23 16:46:57 +0000270 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
271 HInstruction* user = it.Current()->GetUser();
272 if (notNullBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100273 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000274 ScopedObjectAccess soa(Thread::Current());
275 HInstruction* insert_point = notNullBlock->GetFirstInstruction();
Calin Juravle2e768302015-07-28 14:41:11 +0000276 ReferenceTypeInfo object_rti = ReferenceTypeInfo::Create(
277 object_class_handle_, /* is_exact */ true);
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000278 if (ShouldCreateBoundType(insert_point, obj, object_rti, nullptr, notNullBlock)) {
279 bound_type = new (graph_->GetArena()) HBoundType(
280 obj, object_rti, /* bound_can_be_null */ false);
Calin Juravle2e768302015-07-28 14:41:11 +0000281 if (obj->GetReferenceTypeInfo().IsValid()) {
282 bound_type->SetReferenceTypeInfo(obj->GetReferenceTypeInfo());
283 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000284 notNullBlock->InsertInstructionBefore(bound_type, insert_point);
285 } else {
286 // We already have a bound type on the position we would need to insert
287 // the new one. The existing bound type should dominate all the users
288 // (dchecked) so there's no need to continue.
289 break;
290 }
Calin Juravleb3306642015-04-20 18:30:42 +0100291 }
Calin Juravle61d544b2015-02-23 16:46:57 +0000292 user->ReplaceInput(bound_type, it.Current()->GetIndex());
293 }
294 }
295}
296
Calin Juravleb1498f62015-02-16 13:13:29 +0000297// Detects if `block` is the True block for the pattern
298// `if (x instanceof ClassX) { }`
299// If that's the case insert an HBoundType instruction to bound the type of `x`
300// to `ClassX` in the scope of the dominated blocks.
301void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100302 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
303 if (ifInstruction == nullptr) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000304 return;
305 }
Calin Juravleb3306642015-04-20 18:30:42 +0100306 HInstruction* ifInput = ifInstruction->InputAt(0);
307 HInstruction* instanceOf = nullptr;
308 HBasicBlock* instanceOfTrueBlock = nullptr;
David Brazdil0d13fee2015-04-17 14:52:19 +0100309
Calin Juravleb3306642015-04-20 18:30:42 +0100310 // The instruction simplifier has transformed:
311 // - `if (a instanceof A)` into an HIf with an HInstanceOf input
312 // - `if (!(a instanceof A)` into an HIf with an HBooleanNot input (which in turn
313 // has an HInstanceOf input)
314 // So we should not see the usual HEqual here.
David Brazdil0d13fee2015-04-17 14:52:19 +0100315 if (ifInput->IsInstanceOf()) {
316 instanceOf = ifInput;
Calin Juravleb3306642015-04-20 18:30:42 +0100317 instanceOfTrueBlock = ifInstruction->IfTrueSuccessor();
David Brazdil0d13fee2015-04-17 14:52:19 +0100318 } else if (ifInput->IsBooleanNot() && ifInput->InputAt(0)->IsInstanceOf()) {
319 instanceOf = ifInput->InputAt(0);
Calin Juravleb3306642015-04-20 18:30:42 +0100320 instanceOfTrueBlock = ifInstruction->IfFalseSuccessor();
David Brazdil0d13fee2015-04-17 14:52:19 +0100321 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000322 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000323 }
324
Calin Juravle98893e12015-10-02 21:05:03 +0100325 HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
326 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
327 {
328 ScopedObjectAccess soa(Thread::Current());
329 if (!class_rti.IsValid()) {
330 // He have loaded an unresolved class. Don't bother bounding the type.
331 return;
332 }
333 }
Calin Juravleb3306642015-04-20 18:30:42 +0100334 // We only need to bound the type if we have uses in the relevant block.
335 // So start with null and create the HBoundType lazily, only if it's needed.
336 HBoundType* bound_type = nullptr;
337
Calin Juravleb1498f62015-02-16 13:13:29 +0000338 HInstruction* obj = instanceOf->InputAt(0);
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100339 if (obj->GetReferenceTypeInfo().IsExact() && !obj->IsPhi()) {
340 // This method is being called while doing a fixed-point calculation
341 // over phis. Non-phis instruction whose type is already known do
342 // not need to be bound to another type.
343 // Not that this also prevents replacing `HLoadClass` with a `HBoundType`.
344 // `HCheckCast` and `HInstanceOf` expect a `HLoadClass` as a second
345 // input.
346 return;
347 }
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100348 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
Calin Juravleb1498f62015-02-16 13:13:29 +0000349 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
350 HInstruction* user = it.Current()->GetUser();
351 if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100352 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000353 ScopedObjectAccess soa(Thread::Current());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000354 HInstruction* insert_point = instanceOfTrueBlock->GetFirstInstruction();
355 if (ShouldCreateBoundType(insert_point, obj, class_rti, nullptr, instanceOfTrueBlock)) {
356 bound_type = CreateBoundType(
357 graph_->GetArena(),
358 obj,
359 load_class,
360 false /* InstanceOf ensures the object is not null. */);
361 instanceOfTrueBlock->InsertInstructionBefore(bound_type, insert_point);
362 } else {
363 // We already have a bound type on the position we would need to insert
364 // the new one. The existing bound type should dominate all the users
365 // (dchecked) so there's no need to continue.
366 break;
Calin Juravleb3306642015-04-20 18:30:42 +0100367 }
Calin Juravleb3306642015-04-20 18:30:42 +0100368 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000369 user->ReplaceInput(bound_type, it.Current()->GetIndex());
370 }
371 }
Calin Juravleacf735c2015-02-12 15:25:22 +0000372}
373
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100374void RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
375 mirror::Class* klass,
376 bool is_exact) {
Calin Juravle2e768302015-07-28 14:41:11 +0000377 if (instr->IsInvokeStaticOrDirect() && instr->AsInvokeStaticOrDirect()->IsStringInit()) {
378 // Calls to String.<init> are replaced with a StringFactory.
379 if (kIsDebugBuild) {
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000380 HInvoke* invoke = instr->AsInvoke();
Calin Juravle2e768302015-07-28 14:41:11 +0000381 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000382 ScopedObjectAccess soa(Thread::Current());
383 StackHandleScope<2> hs(soa.Self());
384 Handle<mirror::DexCache> dex_cache(
385 hs.NewHandle(cl->FindDexCache(soa.Self(), invoke->GetDexFile(), false)));
386 // Use a null loader. We should probably use the compiling method's class loader,
387 // but then we would need to pass it to RTPVisitor just for this debug check. Since
388 // the method is from the String class, the null loader is good enough.
389 Handle<mirror::ClassLoader> loader;
390 ArtMethod* method = cl->ResolveMethod(
391 invoke->GetDexFile(), invoke->GetDexMethodIndex(), dex_cache, loader, nullptr, kDirect);
Calin Juravle2e768302015-07-28 14:41:11 +0000392 DCHECK(method != nullptr);
393 mirror::Class* declaring_class = method->GetDeclaringClass();
394 DCHECK(declaring_class != nullptr);
395 DCHECK(declaring_class->IsStringClass())
396 << "Expected String class: " << PrettyDescriptor(declaring_class);
397 DCHECK(method->IsConstructor())
398 << "Expected String.<init>: " << PrettyMethod(method);
399 }
400 instr->SetReferenceTypeInfo(
401 ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
402 } else if (klass != nullptr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100403 ScopedObjectAccess soa(Thread::Current());
Calin Juravle2e768302015-07-28 14:41:11 +0000404 ReferenceTypeInfo::TypeHandle handle = handles_->NewHandle(klass);
David Brazdilbaf89b82015-09-15 11:36:54 +0100405 is_exact = is_exact || klass->CannotBeAssignedFromOtherTypes();
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100406 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
Calin Juravle2e768302015-07-28 14:41:11 +0000407 } else {
408 instr->SetReferenceTypeInfo(
409 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100410 }
411}
412
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100413void RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
414 uint16_t type_idx,
415 const DexFile& dex_file,
416 bool is_exact) {
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100417 DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
418
Calin Juravleacf735c2015-02-12 15:25:22 +0000419 ScopedObjectAccess soa(Thread::Current());
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700420 mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(
421 soa.Self(), dex_file, false);
Calin Juravleacf735c2015-02-12 15:25:22 +0000422 // Get type from dex cache assuming it was populated by the verifier.
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100423 SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact);
Calin Juravleacf735c2015-02-12 15:25:22 +0000424}
425
Calin Juravle2e768302015-07-28 14:41:11 +0000426void RTPVisitor::VisitNullConstant(HNullConstant* instr) {
427 // TODO: The null constant could be bound contextually (e.g. based on return statements)
428 // to a more precise type.
429 instr->SetReferenceTypeInfo(
430 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
431}
432
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100433void RTPVisitor::VisitNewInstance(HNewInstance* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100434 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100435}
436
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100437void RTPVisitor::VisitNewArray(HNewArray* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100438 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100439}
440
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000441static mirror::Class* GetClassFromDexCache(Thread* self, const DexFile& dex_file, uint16_t type_idx)
442 SHARED_REQUIRES(Locks::mutator_lock_) {
443 mirror::DexCache* dex_cache =
444 Runtime::Current()->GetClassLinker()->FindDexCache(self, dex_file, false);
445 // Get type from dex cache assuming it was populated by the verifier.
446 return dex_cache->GetResolvedType(type_idx);
447}
448
Calin Juravle2e768302015-07-28 14:41:11 +0000449void RTPVisitor::VisitParameterValue(HParameterValue* instr) {
Nicolas Geoffraye418dda2015-08-11 20:03:09 -0700450 ScopedObjectAccess soa(Thread::Current());
451 // We check if the existing type is valid: the inliner may have set it.
452 if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) {
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000453 mirror::Class* resolved_class =
454 GetClassFromDexCache(soa.Self(), instr->GetDexFile(), instr->GetTypeIndex());
455 SetClassAsTypeInfo(instr, resolved_class, /* is_exact */ false);
Calin Juravle2e768302015-07-28 14:41:11 +0000456 }
457}
458
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100459void RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
460 const FieldInfo& info) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100461 // The field index is unknown only during tests.
462 if (instr->GetType() != Primitive::kPrimNot || info.GetFieldIndex() == kUnknownFieldIndex) {
463 return;
464 }
465
466 ScopedObjectAccess soa(Thread::Current());
467 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Mathieu Chartier736b5602015-09-02 14:54:11 -0700468 ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), info.GetDexCache().Get());
Calin Juravle2e768302015-07-28 14:41:11 +0000469 // TODO: There are certain cases where we can't resolve the field.
470 // b/21914925 is open to keep track of a repro case for this issue.
471 mirror::Class* klass = (field == nullptr) ? nullptr : field->GetType<false>();
472 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100473}
474
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100475void RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100476 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
477}
478
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100479void RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100480 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
481}
482
Calin Juravlee460d1d2015-09-29 04:52:17 +0100483void RTPVisitor::VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instr) {
484 // TODO: Use descriptor to get the actual type.
485 if (instr->GetFieldType() == Primitive::kPrimNot) {
486 instr->SetReferenceTypeInfo(
487 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
488 }
489}
490
491void RTPVisitor::VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet* instr) {
492 // TODO: Use descriptor to get the actual type.
493 if (instr->GetFieldType() == Primitive::kPrimNot) {
494 instr->SetReferenceTypeInfo(
495 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
496 }
497}
498
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100499void RTPVisitor::VisitLoadClass(HLoadClass* instr) {
Calin Juravleacf735c2015-02-12 15:25:22 +0000500 ScopedObjectAccess soa(Thread::Current());
Calin Juravleacf735c2015-02-12 15:25:22 +0000501 // Get type from dex cache assuming it was populated by the verifier.
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000502 mirror::Class* resolved_class =
503 GetClassFromDexCache(soa.Self(), instr->GetDexFile(), instr->GetTypeIndex());
Calin Juravle98893e12015-10-02 21:05:03 +0100504 if (resolved_class != nullptr) {
505 instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(
506 handles_->NewHandle(resolved_class), /* is_exact */ true));
507 }
Calin Juravle2e768302015-07-28 14:41:11 +0000508 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(class_class_handle_, /* is_exact */ true));
509}
510
511void RTPVisitor::VisitClinitCheck(HClinitCheck* instr) {
512 instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
513}
514
515void RTPVisitor::VisitLoadString(HLoadString* instr) {
516 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
517}
518
David Brazdilbbd733e2015-08-18 17:48:17 +0100519void RTPVisitor::VisitLoadException(HLoadException* instr) {
520 DCHECK(instr->GetBlock()->IsCatchBlock());
521 TryCatchInformation* catch_info = instr->GetBlock()->GetTryCatchInformation();
522
523 if (catch_info->IsCatchAllTypeIndex()) {
524 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(throwable_class_handle_,
David Brazdilb4edcf32015-08-20 17:05:49 +0100525 /* is_exact */ false));
David Brazdilbbd733e2015-08-18 17:48:17 +0100526 } else {
527 UpdateReferenceTypeInfo(instr,
528 catch_info->GetCatchTypeIndex(),
529 catch_info->GetCatchDexFile(),
530 /* is_exact */ false);
531 }
532}
533
Calin Juravle2e768302015-07-28 14:41:11 +0000534void RTPVisitor::VisitNullCheck(HNullCheck* instr) {
535 ScopedObjectAccess soa(Thread::Current());
536 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
537 DCHECK(parent_rti.IsValid());
538 instr->SetReferenceTypeInfo(parent_rti);
539}
540
541void RTPVisitor::VisitFakeString(HFakeString* instr) {
542 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
Calin Juravleacf735c2015-02-12 15:25:22 +0000543}
Calin Juravle10e244f2015-01-26 18:54:32 +0000544
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000545void RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
Calin Juravle98893e12015-10-02 21:05:03 +0100546 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
547 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
548 {
549 ScopedObjectAccess soa(Thread::Current());
550 if (!class_rti.IsValid()) {
551 // He have loaded an unresolved class. Don't bother bounding the type.
552 return;
553 }
554 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000555 HInstruction* obj = check_cast->InputAt(0);
556 HBoundType* bound_type = nullptr;
557 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
558 HInstruction* user = it.Current()->GetUser();
559 if (check_cast->StrictlyDominates(user)) {
560 if (bound_type == nullptr) {
561 ScopedObjectAccess soa(Thread::Current());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000562 if (ShouldCreateBoundType(check_cast->GetNext(), obj, class_rti, check_cast, nullptr)) {
563 bound_type = CreateBoundType(
564 GetGraph()->GetArena(),
565 obj,
566 load_class,
567 true /* CheckCast succeeds for nulls. */);
568 check_cast->GetBlock()->InsertInstructionAfter(bound_type, check_cast);
569 } else {
Nicolas Geoffrayefa84682015-08-12 18:28:14 -0700570 // Update nullability of the existing bound type, which may not have known
571 // that its input was not null when it was being created.
572 bound_type = check_cast->GetNext()->AsBoundType();
573 bound_type->SetCanBeNull(obj->CanBeNull());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000574 // We already have a bound type on the position we would need to insert
575 // the new one. The existing bound type should dominate all the users
576 // (dchecked) so there's no need to continue.
577 break;
578 }
579 }
580 user->ReplaceInput(bound_type, it.Current()->GetIndex());
581 }
582 }
583}
584
Calin Juravleb1498f62015-02-16 13:13:29 +0000585void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
586 if (phi->GetType() != Primitive::kPrimNot) {
587 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000588 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000589
590 if (phi->GetBlock()->IsLoopHeader()) {
591 // Set the initial type for the phi. Use the non back edge input for reaching
592 // a fixed point faster.
593 AddToWorklist(phi);
594 phi->SetCanBeNull(phi->InputAt(0)->CanBeNull());
595 phi->SetReferenceTypeInfo(phi->InputAt(0)->GetReferenceTypeInfo());
Calin Juravle10e244f2015-01-26 18:54:32 +0000596 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000597 // Eagerly compute the type of the phi, for quicker convergence. Note
598 // that we don't need to add users to the worklist because we are
599 // doing a reverse post-order visit, therefore either the phi users are
600 // non-loop phi and will be visited later in the visit, or are loop-phis,
601 // and they are already in the work list.
602 UpdateNullability(phi);
603 UpdateReferenceTypeInfo(phi);
604 }
605}
606
607ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
608 const ReferenceTypeInfo& b) {
Calin Juravle2e768302015-07-28 14:41:11 +0000609 if (!b.IsValid()) {
610 return a;
611 }
612 if (!a.IsValid()) {
613 return b;
Calin Juravle20e60712015-07-01 18:41:04 +0100614 }
615
Calin Juravle2e768302015-07-28 14:41:11 +0000616 bool is_exact = a.IsExact() && b.IsExact();
617 Handle<mirror::Class> type_handle;
618
619 if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
620 type_handle = a.GetTypeHandle();
621 } else if (a.IsSupertypeOf(b)) {
622 type_handle = a.GetTypeHandle();
623 is_exact = false;
624 } else if (b.IsSupertypeOf(a)) {
625 type_handle = b.GetTypeHandle();
626 is_exact = false;
627 } else {
628 // TODO: Find the first common super class.
629 type_handle = object_class_handle_;
630 is_exact = false;
631 }
632
633 return ReferenceTypeInfo::Create(type_handle, is_exact);
634}
635
636static void UpdateArrayGet(HArrayGet* instr,
637 StackHandleScopeCollection* handles,
638 ReferenceTypeInfo::TypeHandle object_class_handle)
639 SHARED_REQUIRES(Locks::mutator_lock_) {
640 DCHECK_EQ(Primitive::kPrimNot, instr->GetType());
641
642 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
643 DCHECK(parent_rti.IsValid());
644
645 Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
646 if (handle->IsObjectArrayClass()) {
647 ReferenceTypeInfo::TypeHandle component_handle = handles->NewHandle(handle->GetComponentType());
648 instr->SetReferenceTypeInfo(
649 ReferenceTypeInfo::Create(component_handle, /* is_exact */ false));
650 } else {
651 // We don't know what the parent actually is, so we fallback to object.
652 instr->SetReferenceTypeInfo(
653 ReferenceTypeInfo::Create(object_class_handle, /* is_exact */ false));
654 }
655
656 return;
Calin Juravleb1498f62015-02-16 13:13:29 +0000657}
658
659bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
660 ScopedObjectAccess soa(Thread::Current());
661
662 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
663 if (instr->IsBoundType()) {
664 UpdateBoundType(instr->AsBoundType());
665 } else if (instr->IsPhi()) {
666 UpdatePhi(instr->AsPhi());
Calin Juravle2e768302015-07-28 14:41:11 +0000667 } else if (instr->IsNullCheck()) {
668 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
669 if (parent_rti.IsValid()) {
670 instr->SetReferenceTypeInfo(parent_rti);
671 }
672 } else if (instr->IsArrayGet()) {
673 // TODO: consider if it's worth "looking back" and bounding the input object
674 // to an array type.
675 UpdateArrayGet(instr->AsArrayGet(), handles_, object_class_handle_);
Calin Juravleb1498f62015-02-16 13:13:29 +0000676 } else {
677 LOG(FATAL) << "Invalid instruction (should not get here)";
678 }
679
680 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
681}
682
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100683void RTPVisitor::VisitInvoke(HInvoke* instr) {
684 if (instr->GetType() != Primitive::kPrimNot) {
685 return;
686 }
687
688 ScopedObjectAccess soa(Thread::Current());
689 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700690 mirror::DexCache* dex_cache = cl->FindDexCache(soa.Self(), instr->GetDexFile());
Vladimir Marko05792b92015-08-03 11:56:49 +0100691 size_t pointer_size = cl->GetImagePointerSize();
692 ArtMethod* method = dex_cache->GetResolvedMethod(instr->GetDexMethodIndex(), pointer_size);
693 mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false, pointer_size);
Calin Juravle2e768302015-07-28 14:41:11 +0000694 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100695}
696
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100697void RTPVisitor::VisitArrayGet(HArrayGet* instr) {
698 if (instr->GetType() != Primitive::kPrimNot) {
699 return;
700 }
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100701 ScopedObjectAccess soa(Thread::Current());
Calin Juravle2e768302015-07-28 14:41:11 +0000702 UpdateArrayGet(instr, handles_, object_class_handle_);
703 if (!instr->GetReferenceTypeInfo().IsValid()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100704 worklist_->push_back(instr);
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100705 }
706}
707
Calin Juravleb1498f62015-02-16 13:13:29 +0000708void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
709 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle2e768302015-07-28 14:41:11 +0000710 if (!new_rti.IsValid()) {
711 return; // No new info yet.
712 }
713
714 // Make sure that we don't go over the bounded type.
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000715 ReferenceTypeInfo upper_bound_rti = instr->GetUpperBound();
716 if (!upper_bound_rti.IsSupertypeOf(new_rti)) {
717 new_rti = upper_bound_rti;
Calin Juravleb1498f62015-02-16 13:13:29 +0000718 }
719 instr->SetReferenceTypeInfo(new_rti);
720}
721
Calin Juravle617bd922015-11-11 14:59:46 +0000722// NullConstant inputs are ignored during merging as they do not provide any useful information.
723// If all the inputs are NullConstants then the type of the phi will be set to Object.
Calin Juravleb1498f62015-02-16 13:13:29 +0000724void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
Calin Juravle617bd922015-11-11 14:59:46 +0000725 size_t input_count = instr->InputCount();
726 size_t first_input_index_not_null = 0;
727 while (first_input_index_not_null < input_count &&
728 instr->InputAt(first_input_index_not_null)->IsNullConstant()) {
729 first_input_index_not_null++;
730 }
731 if (first_input_index_not_null == input_count) {
732 // All inputs are NullConstants, set the type to object.
733 // This may happen in the presence of inlining.
734 instr->SetReferenceTypeInfo(
735 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
736 return;
737 }
738
739 ReferenceTypeInfo new_rti = instr->InputAt(first_input_index_not_null)->GetReferenceTypeInfo();
740
Calin Juravle2e768302015-07-28 14:41:11 +0000741 if (new_rti.IsValid() && new_rti.IsObjectClass() && !new_rti.IsExact()) {
742 // Early return if we are Object and inexact.
Calin Juravleb1498f62015-02-16 13:13:29 +0000743 instr->SetReferenceTypeInfo(new_rti);
744 return;
745 }
Calin Juravle617bd922015-11-11 14:59:46 +0000746
747 for (size_t i = first_input_index_not_null + 1; i < input_count; i++) {
748 if (instr->InputAt(i)->IsNullConstant()) {
749 continue;
750 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000751 new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo());
Calin Juravle2e768302015-07-28 14:41:11 +0000752 if (new_rti.IsValid() && new_rti.IsObjectClass()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000753 if (!new_rti.IsExact()) {
754 break;
755 } else {
756 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000757 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000758 }
759 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000760 instr->SetReferenceTypeInfo(new_rti);
761}
762
763// Re-computes and updates the nullability of the instruction. Returns whether or
764// not the nullability was changed.
765bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
Calin Juravle2e768302015-07-28 14:41:11 +0000766 DCHECK(instr->IsPhi()
767 || instr->IsBoundType()
768 || instr->IsNullCheck()
769 || instr->IsArrayGet());
770
771 if (!instr->IsPhi() && !instr->IsBoundType()) {
772 return false;
773 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000774
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000775 bool existing_can_be_null = instr->CanBeNull();
776 if (instr->IsPhi()) {
777 HPhi* phi = instr->AsPhi();
778 bool new_can_be_null = false;
779 for (size_t i = 0; i < phi->InputCount(); i++) {
780 if (phi->InputAt(i)->CanBeNull()) {
781 new_can_be_null = true;
782 break;
783 }
784 }
785 phi->SetCanBeNull(new_can_be_null);
786 } else if (instr->IsBoundType()) {
787 HBoundType* bound_type = instr->AsBoundType();
788 bound_type->SetCanBeNull(instr->InputAt(0)->CanBeNull() && bound_type->GetUpperCanBeNull());
Calin Juravleb1498f62015-02-16 13:13:29 +0000789 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000790 return existing_can_be_null != instr->CanBeNull();
Calin Juravle10e244f2015-01-26 18:54:32 +0000791}
792
793void ReferenceTypePropagation::ProcessWorklist() {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100794 while (!worklist_.empty()) {
795 HInstruction* instruction = worklist_.back();
796 worklist_.pop_back();
Calin Juravle12617592015-10-16 16:28:46 +0100797 bool updated_nullability = UpdateNullability(instruction);
798 bool updated_reference_type = UpdateReferenceTypeInfo(instruction);
799 if (updated_nullability || updated_reference_type) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000800 AddDependentInstructionsToWorklist(instruction);
801 }
802 }
803}
804
Calin Juravleb1498f62015-02-16 13:13:29 +0000805void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
Calin Juravle2e768302015-07-28 14:41:11 +0000806 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot)
807 << instruction->DebugName() << ":" << instruction->GetType();
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100808 worklist_.push_back(instruction);
Calin Juravle10e244f2015-01-26 18:54:32 +0000809}
810
Calin Juravleb1498f62015-02-16 13:13:29 +0000811void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000812 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000813 HInstruction* user = it.Current()->GetUser();
Calin Juravle2e768302015-07-28 14:41:11 +0000814 if (user->IsPhi()
815 || user->IsBoundType()
816 || user->IsNullCheck()
817 || (user->IsArrayGet() && (user->GetType() == Primitive::kPrimNot))) {
Calin Juravlebeba9302015-07-08 15:57:18 +0000818 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000819 }
820 }
821}
Calin Juravle10e244f2015-01-26 18:54:32 +0000822} // namespace art