blob: 1c25e4824c20bd6a63c7ab88290e333802151579 [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
43 void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
44 void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000045 void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE;
46 void VisitLoadString(HLoadString* instr) OVERRIDE;
David Brazdilbbd733e2015-08-18 17:48:17 +010047 void VisitLoadException(HLoadException* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010048 void VisitNewArray(HNewArray* instr) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000049 void VisitParameterValue(HParameterValue* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010050 void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
51 void SetClassAsTypeInfo(HInstruction* instr, mirror::Class* klass, bool is_exact);
52 void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE;
53 void VisitStaticFieldGet(HStaticFieldGet* instr) OVERRIDE;
Calin Juravlee460d1d2015-09-29 04:52:17 +010054 void VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instr) OVERRIDE;
55 void VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010056 void VisitInvoke(HInvoke* instr) OVERRIDE;
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +010057 void VisitArrayGet(HArrayGet* instr) OVERRIDE;
Calin Juravlea5ae3c32015-07-28 14:40:50 +000058 void VisitCheckCast(HCheckCast* instr) OVERRIDE;
David Brazdilf5552582015-12-27 13:36:12 +000059 void VisitBoundType(HBoundType* 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_;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010074};
75
Calin Juravle2e768302015-07-28 14:41:11 +000076ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph,
77 StackHandleScopeCollection* handles,
78 const char* name)
79 : HOptimization(graph, name),
80 handles_(handles),
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010081 worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)) {
82 worklist_.reserve(kDefaultWorklistSize);
Andreas Gampe9393c692015-08-28 10:56:38 -070083 // Mutator lock is required for NewHandle, but annotalysis ignores constructors.
84 ScopedObjectAccess soa(Thread::Current());
Calin Juravle2e768302015-07-28 14:41:11 +000085 ClassLinker* linker = Runtime::Current()->GetClassLinker();
86 object_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangObject));
87 string_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangString));
88 class_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangClass));
David Brazdilbbd733e2015-08-18 17:48:17 +010089 throwable_class_handle_ =
90 handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangThrowable));
Calin Juravle2e768302015-07-28 14:41:11 +000091
92 if (kIsDebugBuild) {
Calin Juravle2e768302015-07-28 14:41:11 +000093 DCHECK(ReferenceTypeInfo::IsValidHandle(object_class_handle_));
94 DCHECK(ReferenceTypeInfo::IsValidHandle(class_class_handle_));
95 DCHECK(ReferenceTypeInfo::IsValidHandle(string_class_handle_));
David Brazdilbbd733e2015-08-18 17:48:17 +010096 DCHECK(ReferenceTypeInfo::IsValidHandle(throwable_class_handle_));
Calin Juravle2e768302015-07-28 14:41:11 +000097 }
98}
99
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000100void ReferenceTypePropagation::ValidateTypes() {
101 // TODO: move this to the graph checker.
Calin Juravle2e768302015-07-28 14:41:11 +0000102 if (kIsDebugBuild) {
Calin Juravle2e768302015-07-28 14:41:11 +0000103 ScopedObjectAccess soa(Thread::Current());
104 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
105 HBasicBlock* block = it.Current();
106 for (HInstructionIterator iti(block->GetInstructions()); !iti.Done(); iti.Advance()) {
107 HInstruction* instr = iti.Current();
108 if (instr->GetType() == Primitive::kPrimNot) {
109 DCHECK(instr->GetReferenceTypeInfo().IsValid())
110 << "Invalid RTI for instruction: " << instr->DebugName();
111 if (instr->IsBoundType()) {
112 DCHECK(instr->AsBoundType()->GetUpperBound().IsValid());
113 } else if (instr->IsLoadClass()) {
Calin Juravle98893e12015-10-02 21:05:03 +0100114 HLoadClass* cls = instr->AsLoadClass();
115 DCHECK(cls->GetReferenceTypeInfo().IsExact());
116 DCHECK(!cls->GetLoadedClassRTI().IsValid() || cls->GetLoadedClassRTI().IsExact());
Calin Juravle2e768302015-07-28 14:41:11 +0000117 } else if (instr->IsNullCheck()) {
118 DCHECK(instr->GetReferenceTypeInfo().IsEqual(instr->InputAt(0)->GetReferenceTypeInfo()))
119 << "NullCheck " << instr->GetReferenceTypeInfo()
120 << "Input(0) " << instr->InputAt(0)->GetReferenceTypeInfo();
121 }
122 }
123 }
124 }
125 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000126}
127
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000128void ReferenceTypePropagation::Run() {
129 // To properly propagate type info we need to visit in the dominator-based order.
130 // Reverse post order guarantees a node's dominators are visited first.
131 // We take advantage of this order in `VisitBasicBlock`.
132 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
133 VisitBasicBlock(it.Current());
134 }
135
136 ProcessWorklist();
137 ValidateTypes();
138}
139
Calin Juravleb1498f62015-02-16 13:13:29 +0000140void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
Calin Juravle2e768302015-07-28 14:41:11 +0000141 RTPVisitor visitor(graph_,
142 handles_,
143 &worklist_,
144 object_class_handle_,
145 class_class_handle_,
David Brazdilbbd733e2015-08-18 17:48:17 +0100146 string_class_handle_,
147 throwable_class_handle_);
Calin Juravle2e768302015-07-28 14:41:11 +0000148 // Handle Phis first as there might be instructions in the same block who depend on them.
149 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
150 VisitPhi(it.Current()->AsPhi());
151 }
Calin Juravlebeba9302015-07-08 15:57:18 +0000152
Calin Juravle2e768302015-07-28 14:41:11 +0000153 // Handle instructions.
Calin Juravleb1498f62015-02-16 13:13:29 +0000154 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
155 HInstruction* instr = it.Current();
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100156 instr->Accept(&visitor);
Calin Juravleb1498f62015-02-16 13:13:29 +0000157 }
158
Calin Juravleb1498f62015-02-16 13:13:29 +0000159 // Add extra nodes to bound types.
Calin Juravle61d544b2015-02-23 16:46:57 +0000160 BoundTypeForIfNotNull(block);
Calin Juravleb1498f62015-02-16 13:13:29 +0000161 BoundTypeForIfInstanceOf(block);
Calin Juravle10e244f2015-01-26 18:54:32 +0000162}
163
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000164// Check if we should create a bound type for the given object at the specified
165// position. Because of inlining and the fact we run RTP more than once and we
166// might have a HBoundType already. If we do, we should not create a new one.
167// In this case we also assert that there are no other uses of the object (except
168// the bound type) dominated by the specified dominator_instr or dominator_block.
169static bool ShouldCreateBoundType(HInstruction* position,
170 HInstruction* obj,
171 ReferenceTypeInfo upper_bound,
172 HInstruction* dominator_instr,
173 HBasicBlock* dominator_block)
174 SHARED_REQUIRES(Locks::mutator_lock_) {
175 // If the position where we should insert the bound type is not already a
176 // a bound type then we need to create one.
177 if (position == nullptr || !position->IsBoundType()) {
178 return true;
179 }
180
181 HBoundType* existing_bound_type = position->AsBoundType();
182 if (existing_bound_type->GetUpperBound().IsSupertypeOf(upper_bound)) {
183 if (kIsDebugBuild) {
184 // Check that the existing HBoundType dominates all the uses.
185 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
186 HInstruction* user = it.Current()->GetUser();
187 if (dominator_instr != nullptr) {
188 DCHECK(!dominator_instr->StrictlyDominates(user)
189 || user == existing_bound_type
190 || existing_bound_type->StrictlyDominates(user));
191 } else if (dominator_block != nullptr) {
192 DCHECK(!dominator_block->Dominates(user->GetBlock())
193 || user == existing_bound_type
194 || existing_bound_type->StrictlyDominates(user));
195 }
196 }
197 }
198 } else {
199 // TODO: if the current bound type is a refinement we could update the
200 // existing_bound_type with the a new upper limit. However, we also need to
201 // update its users and have access to the work list.
202 }
203 return false;
204}
205
Calin Juravle61d544b2015-02-23 16:46:57 +0000206void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100207 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
208 if (ifInstruction == nullptr) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000209 return;
210 }
Calin Juravleb3306642015-04-20 18:30:42 +0100211 HInstruction* ifInput = ifInstruction->InputAt(0);
Calin Juravle61d544b2015-02-23 16:46:57 +0000212 if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) {
213 return;
214 }
215 HInstruction* input0 = ifInput->InputAt(0);
216 HInstruction* input1 = ifInput->InputAt(1);
Calin Juravleedad8ad2015-04-23 14:34:33 +0100217 HInstruction* obj = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000218
Calin Juravleedad8ad2015-04-23 14:34:33 +0100219 if (input1->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000220 obj = input0;
Calin Juravleedad8ad2015-04-23 14:34:33 +0100221 } else if (input0->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000222 obj = input1;
223 } else {
224 return;
225 }
226
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100227 if (!obj->CanBeNull() || obj->IsNullConstant()) {
228 // Null check is dead code and will be removed by DCE.
229 return;
230 }
231 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
232
Calin Juravleb3306642015-04-20 18:30:42 +0100233 // We only need to bound the type if we have uses in the relevant block.
234 // So start with null and create the HBoundType lazily, only if it's needed.
235 HBoundType* bound_type = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000236 HBasicBlock* notNullBlock = ifInput->IsNotEqual()
Calin Juravleb3306642015-04-20 18:30:42 +0100237 ? ifInstruction->IfTrueSuccessor()
238 : ifInstruction->IfFalseSuccessor();
239
Calin Juravle61d544b2015-02-23 16:46:57 +0000240 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
241 HInstruction* user = it.Current()->GetUser();
242 if (notNullBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100243 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000244 ScopedObjectAccess soa(Thread::Current());
245 HInstruction* insert_point = notNullBlock->GetFirstInstruction();
Calin Juravle2e768302015-07-28 14:41:11 +0000246 ReferenceTypeInfo object_rti = ReferenceTypeInfo::Create(
247 object_class_handle_, /* is_exact */ true);
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000248 if (ShouldCreateBoundType(insert_point, obj, object_rti, nullptr, notNullBlock)) {
David Brazdilf5552582015-12-27 13:36:12 +0000249 bound_type = new (graph_->GetArena()) HBoundType(obj);
250 bound_type->SetUpperBound(object_rti, /* bound_can_be_null */ false);
Calin Juravle2e768302015-07-28 14:41:11 +0000251 if (obj->GetReferenceTypeInfo().IsValid()) {
252 bound_type->SetReferenceTypeInfo(obj->GetReferenceTypeInfo());
253 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000254 notNullBlock->InsertInstructionBefore(bound_type, insert_point);
255 } else {
256 // We already have a bound type on the position we would need to insert
257 // the new one. The existing bound type should dominate all the users
258 // (dchecked) so there's no need to continue.
259 break;
260 }
Calin Juravleb3306642015-04-20 18:30:42 +0100261 }
Calin Juravle61d544b2015-02-23 16:46:57 +0000262 user->ReplaceInput(bound_type, it.Current()->GetIndex());
263 }
264 }
265}
266
David Brazdild9510df2015-11-04 23:30:22 +0000267// Returns true if one of the patterns below has been recognized. If so, the
268// InstanceOf instruction together with the true branch of `ifInstruction` will
269// be returned using the out parameters.
270// Recognized patterns:
271// (1) patterns equivalent to `if (obj instanceof X)`
272// (a) InstanceOf -> Equal to 1 -> If
273// (b) InstanceOf -> NotEqual to 0 -> If
274// (c) InstanceOf -> If
275// (2) patterns equivalent to `if (!(obj instanceof X))`
276// (a) InstanceOf -> Equal to 0 -> If
277// (b) InstanceOf -> NotEqual to 1 -> If
278// (c) InstanceOf -> BooleanNot -> If
279static bool MatchIfInstanceOf(HIf* ifInstruction,
280 /* out */ HInstanceOf** instanceOf,
281 /* out */ HBasicBlock** trueBranch) {
282 HInstruction* input = ifInstruction->InputAt(0);
283
284 if (input->IsEqual()) {
285 HInstruction* rhs = input->AsEqual()->GetConstantRight();
286 if (rhs != nullptr) {
287 HInstruction* lhs = input->AsEqual()->GetLeastConstantLeft();
288 if (lhs->IsInstanceOf() && rhs->IsIntConstant()) {
289 if (rhs->AsIntConstant()->IsOne()) {
290 // Case (1a)
291 *trueBranch = ifInstruction->IfTrueSuccessor();
292 } else {
293 // Case (2a)
294 DCHECK(rhs->AsIntConstant()->IsZero());
295 *trueBranch = ifInstruction->IfFalseSuccessor();
296 }
297 *instanceOf = lhs->AsInstanceOf();
298 return true;
299 }
300 }
301 } else if (input->IsNotEqual()) {
302 HInstruction* rhs = input->AsNotEqual()->GetConstantRight();
303 if (rhs != nullptr) {
304 HInstruction* lhs = input->AsNotEqual()->GetLeastConstantLeft();
305 if (lhs->IsInstanceOf() && rhs->IsIntConstant()) {
306 if (rhs->AsIntConstant()->IsZero()) {
307 // Case (1b)
308 *trueBranch = ifInstruction->IfTrueSuccessor();
309 } else {
310 // Case (2b)
311 DCHECK(rhs->AsIntConstant()->IsOne());
312 *trueBranch = ifInstruction->IfFalseSuccessor();
313 }
314 *instanceOf = lhs->AsInstanceOf();
315 return true;
316 }
317 }
318 } else if (input->IsInstanceOf()) {
319 // Case (1c)
320 *instanceOf = input->AsInstanceOf();
321 *trueBranch = ifInstruction->IfTrueSuccessor();
322 return true;
323 } else if (input->IsBooleanNot()) {
324 HInstruction* not_input = input->InputAt(0);
325 if (not_input->IsInstanceOf()) {
326 // Case (2c)
327 *instanceOf = not_input->AsInstanceOf();
328 *trueBranch = ifInstruction->IfFalseSuccessor();
329 return true;
330 }
331 }
332
333 return false;
334}
335
Calin Juravleb1498f62015-02-16 13:13:29 +0000336// Detects if `block` is the True block for the pattern
337// `if (x instanceof ClassX) { }`
338// If that's the case insert an HBoundType instruction to bound the type of `x`
339// to `ClassX` in the scope of the dominated blocks.
340void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100341 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
342 if (ifInstruction == nullptr) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000343 return;
344 }
David Brazdil0d13fee2015-04-17 14:52:19 +0100345
David Brazdild9510df2015-11-04 23:30:22 +0000346 // Try to recognize common `if (instanceof)` and `if (!instanceof)` patterns.
347 HInstanceOf* instanceOf = nullptr;
348 HBasicBlock* instanceOfTrueBlock = nullptr;
349 if (!MatchIfInstanceOf(ifInstruction, &instanceOf, &instanceOfTrueBlock)) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000350 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000351 }
352
Calin Juravle98893e12015-10-02 21:05:03 +0100353 HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
354 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
355 {
356 ScopedObjectAccess soa(Thread::Current());
357 if (!class_rti.IsValid()) {
358 // He have loaded an unresolved class. Don't bother bounding the type.
359 return;
360 }
361 }
Calin Juravleb3306642015-04-20 18:30:42 +0100362 // We only need to bound the type if we have uses in the relevant block.
363 // So start with null and create the HBoundType lazily, only if it's needed.
364 HBoundType* bound_type = nullptr;
365
Calin Juravleb1498f62015-02-16 13:13:29 +0000366 HInstruction* obj = instanceOf->InputAt(0);
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100367 if (obj->GetReferenceTypeInfo().IsExact() && !obj->IsPhi()) {
368 // This method is being called while doing a fixed-point calculation
369 // over phis. Non-phis instruction whose type is already known do
370 // not need to be bound to another type.
371 // Not that this also prevents replacing `HLoadClass` with a `HBoundType`.
372 // `HCheckCast` and `HInstanceOf` expect a `HLoadClass` as a second
373 // input.
374 return;
375 }
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100376 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
Calin Juravleb1498f62015-02-16 13:13:29 +0000377 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
378 HInstruction* user = it.Current()->GetUser();
379 if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100380 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000381 ScopedObjectAccess soa(Thread::Current());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000382 HInstruction* insert_point = instanceOfTrueBlock->GetFirstInstruction();
383 if (ShouldCreateBoundType(insert_point, obj, class_rti, nullptr, instanceOfTrueBlock)) {
David Brazdilf5552582015-12-27 13:36:12 +0000384 bound_type = new (graph_->GetArena()) HBoundType(obj);
385 bound_type->SetUpperBound(class_rti, /* InstanceOf fails for null. */ false);
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000386 instanceOfTrueBlock->InsertInstructionBefore(bound_type, insert_point);
387 } else {
388 // We already have a bound type on the position we would need to insert
389 // the new one. The existing bound type should dominate all the users
390 // (dchecked) so there's no need to continue.
391 break;
Calin Juravleb3306642015-04-20 18:30:42 +0100392 }
Calin Juravleb3306642015-04-20 18:30:42 +0100393 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000394 user->ReplaceInput(bound_type, it.Current()->GetIndex());
395 }
396 }
Calin Juravleacf735c2015-02-12 15:25:22 +0000397}
398
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100399void RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
400 mirror::Class* klass,
401 bool is_exact) {
Calin Juravle2e768302015-07-28 14:41:11 +0000402 if (instr->IsInvokeStaticOrDirect() && instr->AsInvokeStaticOrDirect()->IsStringInit()) {
403 // Calls to String.<init> are replaced with a StringFactory.
404 if (kIsDebugBuild) {
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000405 HInvoke* invoke = instr->AsInvoke();
Calin Juravle2e768302015-07-28 14:41:11 +0000406 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000407 ScopedObjectAccess soa(Thread::Current());
408 StackHandleScope<2> hs(soa.Self());
409 Handle<mirror::DexCache> dex_cache(
410 hs.NewHandle(cl->FindDexCache(soa.Self(), invoke->GetDexFile(), false)));
411 // Use a null loader. We should probably use the compiling method's class loader,
412 // but then we would need to pass it to RTPVisitor just for this debug check. Since
413 // the method is from the String class, the null loader is good enough.
414 Handle<mirror::ClassLoader> loader;
Andreas Gampe42ef8ab2015-12-03 17:27:32 -0800415 ArtMethod* method = cl->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000416 invoke->GetDexFile(), invoke->GetDexMethodIndex(), dex_cache, loader, nullptr, kDirect);
Calin Juravle2e768302015-07-28 14:41:11 +0000417 DCHECK(method != nullptr);
418 mirror::Class* declaring_class = method->GetDeclaringClass();
419 DCHECK(declaring_class != nullptr);
420 DCHECK(declaring_class->IsStringClass())
421 << "Expected String class: " << PrettyDescriptor(declaring_class);
422 DCHECK(method->IsConstructor())
423 << "Expected String.<init>: " << PrettyMethod(method);
424 }
425 instr->SetReferenceTypeInfo(
426 ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
427 } else if (klass != nullptr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100428 ScopedObjectAccess soa(Thread::Current());
Calin Juravle2e768302015-07-28 14:41:11 +0000429 ReferenceTypeInfo::TypeHandle handle = handles_->NewHandle(klass);
David Brazdilbaf89b82015-09-15 11:36:54 +0100430 is_exact = is_exact || klass->CannotBeAssignedFromOtherTypes();
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100431 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
Calin Juravle2e768302015-07-28 14:41:11 +0000432 } else {
433 instr->SetReferenceTypeInfo(
434 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100435 }
436}
437
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100438void RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
439 uint16_t type_idx,
440 const DexFile& dex_file,
441 bool is_exact) {
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100442 DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
443
Calin Juravleacf735c2015-02-12 15:25:22 +0000444 ScopedObjectAccess soa(Thread::Current());
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700445 mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(
446 soa.Self(), dex_file, false);
Calin Juravleacf735c2015-02-12 15:25:22 +0000447 // Get type from dex cache assuming it was populated by the verifier.
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100448 SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact);
Calin Juravleacf735c2015-02-12 15:25:22 +0000449}
450
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100451void RTPVisitor::VisitNewInstance(HNewInstance* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100452 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100453}
454
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100455void RTPVisitor::VisitNewArray(HNewArray* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100456 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100457}
458
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000459static mirror::Class* GetClassFromDexCache(Thread* self, const DexFile& dex_file, uint16_t type_idx)
460 SHARED_REQUIRES(Locks::mutator_lock_) {
461 mirror::DexCache* dex_cache =
David Brazdild9510df2015-11-04 23:30:22 +0000462 Runtime::Current()->GetClassLinker()->FindDexCache(self, dex_file, /* allow_failure */ true);
463 if (dex_cache == nullptr) {
464 // Dex cache could not be found. This should only happen during gtests.
465 return nullptr;
466 }
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000467 // Get type from dex cache assuming it was populated by the verifier.
468 return dex_cache->GetResolvedType(type_idx);
469}
470
Calin Juravle2e768302015-07-28 14:41:11 +0000471void RTPVisitor::VisitParameterValue(HParameterValue* instr) {
Nicolas Geoffraye418dda2015-08-11 20:03:09 -0700472 ScopedObjectAccess soa(Thread::Current());
473 // We check if the existing type is valid: the inliner may have set it.
474 if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) {
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000475 mirror::Class* resolved_class =
476 GetClassFromDexCache(soa.Self(), instr->GetDexFile(), instr->GetTypeIndex());
477 SetClassAsTypeInfo(instr, resolved_class, /* is_exact */ false);
Calin Juravle2e768302015-07-28 14:41:11 +0000478 }
479}
480
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100481void RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
482 const FieldInfo& info) {
David Brazdild9510df2015-11-04 23:30:22 +0000483 if (instr->GetType() != Primitive::kPrimNot) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100484 return;
485 }
486
487 ScopedObjectAccess soa(Thread::Current());
David Brazdild9510df2015-11-04 23:30:22 +0000488 mirror::Class* klass = nullptr;
489
490 // The field index is unknown only during tests.
491 if (info.GetFieldIndex() != kUnknownFieldIndex) {
492 ClassLinker* cl = Runtime::Current()->GetClassLinker();
493 ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), info.GetDexCache().Get());
494 // TODO: There are certain cases where we can't resolve the field.
495 // b/21914925 is open to keep track of a repro case for this issue.
496 if (field != nullptr) {
497 klass = field->GetType<false>();
498 }
499 }
500
Calin Juravle2e768302015-07-28 14:41:11 +0000501 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100502}
503
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100504void RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100505 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
506}
507
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100508void RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100509 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
510}
511
Calin Juravlee460d1d2015-09-29 04:52:17 +0100512void RTPVisitor::VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instr) {
513 // TODO: Use descriptor to get the actual type.
514 if (instr->GetFieldType() == Primitive::kPrimNot) {
515 instr->SetReferenceTypeInfo(
516 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
517 }
518}
519
520void RTPVisitor::VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet* instr) {
521 // TODO: Use descriptor to get the actual type.
522 if (instr->GetFieldType() == Primitive::kPrimNot) {
523 instr->SetReferenceTypeInfo(
524 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
525 }
526}
527
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100528void RTPVisitor::VisitLoadClass(HLoadClass* instr) {
Calin Juravleacf735c2015-02-12 15:25:22 +0000529 ScopedObjectAccess soa(Thread::Current());
Calin Juravleacf735c2015-02-12 15:25:22 +0000530 // Get type from dex cache assuming it was populated by the verifier.
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000531 mirror::Class* resolved_class =
532 GetClassFromDexCache(soa.Self(), instr->GetDexFile(), instr->GetTypeIndex());
Calin Juravle98893e12015-10-02 21:05:03 +0100533 if (resolved_class != nullptr) {
534 instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(
535 handles_->NewHandle(resolved_class), /* is_exact */ true));
536 }
Calin Juravle2e768302015-07-28 14:41:11 +0000537 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(class_class_handle_, /* is_exact */ true));
538}
539
540void RTPVisitor::VisitClinitCheck(HClinitCheck* instr) {
541 instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
542}
543
544void RTPVisitor::VisitLoadString(HLoadString* instr) {
545 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
546}
547
David Brazdilbbd733e2015-08-18 17:48:17 +0100548void RTPVisitor::VisitLoadException(HLoadException* instr) {
549 DCHECK(instr->GetBlock()->IsCatchBlock());
550 TryCatchInformation* catch_info = instr->GetBlock()->GetTryCatchInformation();
551
552 if (catch_info->IsCatchAllTypeIndex()) {
553 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(throwable_class_handle_,
David Brazdilb4edcf32015-08-20 17:05:49 +0100554 /* is_exact */ false));
David Brazdilbbd733e2015-08-18 17:48:17 +0100555 } else {
556 UpdateReferenceTypeInfo(instr,
557 catch_info->GetCatchTypeIndex(),
558 catch_info->GetCatchDexFile(),
559 /* is_exact */ false);
560 }
561}
562
Calin Juravle2e768302015-07-28 14:41:11 +0000563void RTPVisitor::VisitNullCheck(HNullCheck* instr) {
564 ScopedObjectAccess soa(Thread::Current());
565 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
David Brazdilfe860702015-12-02 09:06:57 +0000566 if (parent_rti.IsValid()) {
567 instr->SetReferenceTypeInfo(parent_rti);
568 }
Calin Juravle2e768302015-07-28 14:41:11 +0000569}
570
571void RTPVisitor::VisitFakeString(HFakeString* instr) {
572 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
Calin Juravleacf735c2015-02-12 15:25:22 +0000573}
Calin Juravle10e244f2015-01-26 18:54:32 +0000574
David Brazdilf5552582015-12-27 13:36:12 +0000575void RTPVisitor::VisitBoundType(HBoundType* instr) {
576 ScopedObjectAccess soa(Thread::Current());
577
578 ReferenceTypeInfo class_rti = instr->GetUpperBound();
579 if (class_rti.IsValid()) {
580 // Narrow the type as much as possible.
581 HInstruction* obj = instr->InputAt(0);
582 ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo();
583 if (class_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes()) {
584 instr->SetReferenceTypeInfo(
585 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ true));
David Brazdil744a1c62015-12-28 10:53:34 +0000586 } else if (obj_rti.IsValid()) {
587 if (class_rti.IsSupertypeOf(obj_rti)) {
588 // Object type is more specific.
589 instr->SetReferenceTypeInfo(obj_rti);
590 } else {
591 // Upper bound is more specific.
592 instr->SetReferenceTypeInfo(
593 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
594 }
David Brazdilf5552582015-12-27 13:36:12 +0000595 } else {
David Brazdil744a1c62015-12-28 10:53:34 +0000596 // Object not typed yet. Leave BoundType untyped for now rather than
597 // assign the type conservatively.
David Brazdilf5552582015-12-27 13:36:12 +0000598 }
599 instr->SetCanBeNull(obj->CanBeNull() && instr->GetUpperCanBeNull());
600 } else {
601 // The owner of the BoundType was already visited. If the class is unresolved,
602 // the BoundType should have been removed from the data flow and this method
603 // should remove it from the graph.
604 DCHECK(!instr->HasUses());
605 instr->GetBlock()->RemoveInstruction(instr);
606 }
607}
608
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000609void RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
David Brazdilf5552582015-12-27 13:36:12 +0000610 ScopedObjectAccess soa(Thread::Current());
611
Calin Juravle98893e12015-10-02 21:05:03 +0100612 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
613 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
David Brazdilf5552582015-12-27 13:36:12 +0000614 HBoundType* bound_type = check_cast->GetNext()->AsBoundType();
615 if (bound_type == nullptr || bound_type->GetUpperBound().IsValid()) {
616 // The next instruction is not an uninitialized BoundType. This must be
617 // an RTP pass after SsaBuilder and we do not need to do anything.
618 return;
Calin Juravle98893e12015-10-02 21:05:03 +0100619 }
David Brazdilf5552582015-12-27 13:36:12 +0000620 DCHECK_EQ(bound_type->InputAt(0), check_cast->InputAt(0));
621
622 if (class_rti.IsValid()) {
623 // This is the first run of RTP and class is resolved.
624 bound_type->SetUpperBound(class_rti, /* CheckCast succeeds for nulls. */ true);
625 } else {
626 // This is the first run of RTP and class is unresolved. Remove the binding.
627 // The instruction itself is removed in VisitBoundType so as to not
628 // invalidate HInstructionIterator.
629 bound_type->ReplaceWith(bound_type->InputAt(0));
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000630 }
631}
632
Calin Juravleb1498f62015-02-16 13:13:29 +0000633void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
David Brazdild9510df2015-11-04 23:30:22 +0000634 if (phi->IsDead() || phi->GetType() != Primitive::kPrimNot) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000635 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000636 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000637
638 if (phi->GetBlock()->IsLoopHeader()) {
David Brazdilfe860702015-12-02 09:06:57 +0000639 ScopedObjectAccess soa(Thread::Current());
Calin Juravleb1498f62015-02-16 13:13:29 +0000640 // Set the initial type for the phi. Use the non back edge input for reaching
641 // a fixed point faster.
David Brazdilfe860702015-12-02 09:06:57 +0000642 HInstruction* first_input = phi->InputAt(0);
643 ReferenceTypeInfo first_input_rti = first_input->GetReferenceTypeInfo();
644 if (first_input_rti.IsValid() && !first_input->IsNullConstant()) {
645 phi->SetCanBeNull(first_input->CanBeNull());
646 phi->SetReferenceTypeInfo(first_input_rti);
647 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000648 AddToWorklist(phi);
Calin Juravle10e244f2015-01-26 18:54:32 +0000649 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000650 // Eagerly compute the type of the phi, for quicker convergence. Note
651 // that we don't need to add users to the worklist because we are
652 // doing a reverse post-order visit, therefore either the phi users are
653 // non-loop phi and will be visited later in the visit, or are loop-phis,
654 // and they are already in the work list.
655 UpdateNullability(phi);
656 UpdateReferenceTypeInfo(phi);
657 }
658}
659
660ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
661 const ReferenceTypeInfo& b) {
Calin Juravle2e768302015-07-28 14:41:11 +0000662 if (!b.IsValid()) {
663 return a;
664 }
665 if (!a.IsValid()) {
666 return b;
Calin Juravle20e60712015-07-01 18:41:04 +0100667 }
668
Calin Juravle2e768302015-07-28 14:41:11 +0000669 bool is_exact = a.IsExact() && b.IsExact();
Calin Juravle52503d82015-11-11 16:58:31 +0000670 ReferenceTypeInfo::TypeHandle result_type_handle;
671 ReferenceTypeInfo::TypeHandle a_type_handle = a.GetTypeHandle();
672 ReferenceTypeInfo::TypeHandle b_type_handle = b.GetTypeHandle();
673 bool a_is_interface = a_type_handle->IsInterface();
674 bool b_is_interface = b_type_handle->IsInterface();
Calin Juravle2e768302015-07-28 14:41:11 +0000675
676 if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
Calin Juravle52503d82015-11-11 16:58:31 +0000677 result_type_handle = a_type_handle;
Calin Juravle2e768302015-07-28 14:41:11 +0000678 } else if (a.IsSupertypeOf(b)) {
Calin Juravle52503d82015-11-11 16:58:31 +0000679 result_type_handle = a_type_handle;
Calin Juravle2e768302015-07-28 14:41:11 +0000680 is_exact = false;
681 } else if (b.IsSupertypeOf(a)) {
Calin Juravle52503d82015-11-11 16:58:31 +0000682 result_type_handle = b_type_handle;
683 is_exact = false;
684 } else if (!a_is_interface && !b_is_interface) {
685 result_type_handle = handles_->NewHandle(a_type_handle->GetCommonSuperClass(b_type_handle));
Calin Juravle2e768302015-07-28 14:41:11 +0000686 is_exact = false;
687 } else {
Calin Juravle52503d82015-11-11 16:58:31 +0000688 // This can happen if:
689 // - both types are interfaces. TODO(calin): implement
690 // - one is an interface, the other a class, and the type does not implement the interface
691 // e.g:
692 // void foo(Interface i, boolean cond) {
693 // Object o = cond ? i : new Object();
694 // }
695 result_type_handle = object_class_handle_;
Calin Juravle2e768302015-07-28 14:41:11 +0000696 is_exact = false;
697 }
698
Calin Juravle52503d82015-11-11 16:58:31 +0000699 return ReferenceTypeInfo::Create(result_type_handle, is_exact);
Calin Juravle2e768302015-07-28 14:41:11 +0000700}
701
702static void UpdateArrayGet(HArrayGet* instr,
703 StackHandleScopeCollection* handles,
704 ReferenceTypeInfo::TypeHandle object_class_handle)
705 SHARED_REQUIRES(Locks::mutator_lock_) {
706 DCHECK_EQ(Primitive::kPrimNot, instr->GetType());
707
708 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
David Brazdilfe860702015-12-02 09:06:57 +0000709 if (!parent_rti.IsValid()) {
710 return;
711 }
Calin Juravle2e768302015-07-28 14:41:11 +0000712
713 Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
714 if (handle->IsObjectArrayClass()) {
715 ReferenceTypeInfo::TypeHandle component_handle = handles->NewHandle(handle->GetComponentType());
716 instr->SetReferenceTypeInfo(
717 ReferenceTypeInfo::Create(component_handle, /* is_exact */ false));
718 } else {
719 // We don't know what the parent actually is, so we fallback to object.
720 instr->SetReferenceTypeInfo(
721 ReferenceTypeInfo::Create(object_class_handle, /* is_exact */ false));
722 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000723}
724
725bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
726 ScopedObjectAccess soa(Thread::Current());
727
728 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
729 if (instr->IsBoundType()) {
730 UpdateBoundType(instr->AsBoundType());
731 } else if (instr->IsPhi()) {
732 UpdatePhi(instr->AsPhi());
Calin Juravle2e768302015-07-28 14:41:11 +0000733 } else if (instr->IsNullCheck()) {
734 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
735 if (parent_rti.IsValid()) {
736 instr->SetReferenceTypeInfo(parent_rti);
737 }
738 } else if (instr->IsArrayGet()) {
David Brazdilfe860702015-12-02 09:06:57 +0000739 // TODO: consider if it's worth "looking back" and binding the input object
Calin Juravle2e768302015-07-28 14:41:11 +0000740 // to an array type.
741 UpdateArrayGet(instr->AsArrayGet(), handles_, object_class_handle_);
Calin Juravleb1498f62015-02-16 13:13:29 +0000742 } else {
743 LOG(FATAL) << "Invalid instruction (should not get here)";
744 }
745
746 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
747}
748
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100749void RTPVisitor::VisitInvoke(HInvoke* instr) {
750 if (instr->GetType() != Primitive::kPrimNot) {
751 return;
752 }
753
754 ScopedObjectAccess soa(Thread::Current());
755 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700756 mirror::DexCache* dex_cache = cl->FindDexCache(soa.Self(), instr->GetDexFile());
Vladimir Marko05792b92015-08-03 11:56:49 +0100757 size_t pointer_size = cl->GetImagePointerSize();
758 ArtMethod* method = dex_cache->GetResolvedMethod(instr->GetDexMethodIndex(), pointer_size);
759 mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false, pointer_size);
Calin Juravle2e768302015-07-28 14:41:11 +0000760 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100761}
762
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100763void RTPVisitor::VisitArrayGet(HArrayGet* instr) {
764 if (instr->GetType() != Primitive::kPrimNot) {
765 return;
766 }
David Brazdilfe860702015-12-02 09:06:57 +0000767
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100768 ScopedObjectAccess soa(Thread::Current());
Calin Juravle2e768302015-07-28 14:41:11 +0000769 UpdateArrayGet(instr, handles_, object_class_handle_);
770 if (!instr->GetReferenceTypeInfo().IsValid()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100771 worklist_->push_back(instr);
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100772 }
773}
774
Calin Juravleb1498f62015-02-16 13:13:29 +0000775void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
776 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle2e768302015-07-28 14:41:11 +0000777 if (!new_rti.IsValid()) {
778 return; // No new info yet.
779 }
780
781 // Make sure that we don't go over the bounded type.
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000782 ReferenceTypeInfo upper_bound_rti = instr->GetUpperBound();
783 if (!upper_bound_rti.IsSupertypeOf(new_rti)) {
784 new_rti = upper_bound_rti;
Calin Juravleb1498f62015-02-16 13:13:29 +0000785 }
786 instr->SetReferenceTypeInfo(new_rti);
787}
788
Calin Juravle617bd922015-11-11 14:59:46 +0000789// NullConstant inputs are ignored during merging as they do not provide any useful information.
790// If all the inputs are NullConstants then the type of the phi will be set to Object.
Calin Juravleb1498f62015-02-16 13:13:29 +0000791void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
David Brazdild9510df2015-11-04 23:30:22 +0000792 DCHECK(instr->IsLive());
793
Calin Juravle617bd922015-11-11 14:59:46 +0000794 size_t input_count = instr->InputCount();
795 size_t first_input_index_not_null = 0;
796 while (first_input_index_not_null < input_count &&
797 instr->InputAt(first_input_index_not_null)->IsNullConstant()) {
798 first_input_index_not_null++;
799 }
800 if (first_input_index_not_null == input_count) {
801 // All inputs are NullConstants, set the type to object.
802 // This may happen in the presence of inlining.
803 instr->SetReferenceTypeInfo(
804 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
805 return;
806 }
807
808 ReferenceTypeInfo new_rti = instr->InputAt(first_input_index_not_null)->GetReferenceTypeInfo();
809
Calin Juravle2e768302015-07-28 14:41:11 +0000810 if (new_rti.IsValid() && new_rti.IsObjectClass() && !new_rti.IsExact()) {
811 // Early return if we are Object and inexact.
Calin Juravleb1498f62015-02-16 13:13:29 +0000812 instr->SetReferenceTypeInfo(new_rti);
813 return;
814 }
Calin Juravle617bd922015-11-11 14:59:46 +0000815
816 for (size_t i = first_input_index_not_null + 1; i < input_count; i++) {
817 if (instr->InputAt(i)->IsNullConstant()) {
818 continue;
819 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000820 new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo());
Calin Juravle2e768302015-07-28 14:41:11 +0000821 if (new_rti.IsValid() && new_rti.IsObjectClass()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000822 if (!new_rti.IsExact()) {
823 break;
824 } else {
825 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000826 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000827 }
828 }
David Brazdilfe860702015-12-02 09:06:57 +0000829
830 if (new_rti.IsValid()) {
831 instr->SetReferenceTypeInfo(new_rti);
832 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000833}
834
835// Re-computes and updates the nullability of the instruction. Returns whether or
836// not the nullability was changed.
837bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
David Brazdild9510df2015-11-04 23:30:22 +0000838 DCHECK((instr->IsPhi() && instr->AsPhi()->IsLive())
Calin Juravle2e768302015-07-28 14:41:11 +0000839 || instr->IsBoundType()
840 || instr->IsNullCheck()
841 || instr->IsArrayGet());
842
843 if (!instr->IsPhi() && !instr->IsBoundType()) {
844 return false;
845 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000846
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000847 bool existing_can_be_null = instr->CanBeNull();
848 if (instr->IsPhi()) {
849 HPhi* phi = instr->AsPhi();
850 bool new_can_be_null = false;
851 for (size_t i = 0; i < phi->InputCount(); i++) {
852 if (phi->InputAt(i)->CanBeNull()) {
853 new_can_be_null = true;
854 break;
855 }
856 }
857 phi->SetCanBeNull(new_can_be_null);
858 } else if (instr->IsBoundType()) {
859 HBoundType* bound_type = instr->AsBoundType();
860 bound_type->SetCanBeNull(instr->InputAt(0)->CanBeNull() && bound_type->GetUpperCanBeNull());
Calin Juravleb1498f62015-02-16 13:13:29 +0000861 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000862 return existing_can_be_null != instr->CanBeNull();
Calin Juravle10e244f2015-01-26 18:54:32 +0000863}
864
865void ReferenceTypePropagation::ProcessWorklist() {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100866 while (!worklist_.empty()) {
867 HInstruction* instruction = worklist_.back();
868 worklist_.pop_back();
Calin Juravle12617592015-10-16 16:28:46 +0100869 bool updated_nullability = UpdateNullability(instruction);
870 bool updated_reference_type = UpdateReferenceTypeInfo(instruction);
871 if (updated_nullability || updated_reference_type) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000872 AddDependentInstructionsToWorklist(instruction);
873 }
874 }
875}
876
Calin Juravleb1498f62015-02-16 13:13:29 +0000877void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
Calin Juravle2e768302015-07-28 14:41:11 +0000878 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot)
879 << instruction->DebugName() << ":" << instruction->GetType();
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100880 worklist_.push_back(instruction);
Calin Juravle10e244f2015-01-26 18:54:32 +0000881}
882
Calin Juravleb1498f62015-02-16 13:13:29 +0000883void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000884 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000885 HInstruction* user = it.Current()->GetUser();
David Brazdild9510df2015-11-04 23:30:22 +0000886 if ((user->IsPhi() && user->AsPhi()->IsLive())
Calin Juravle2e768302015-07-28 14:41:11 +0000887 || user->IsBoundType()
888 || user->IsNullCheck()
889 || (user->IsArrayGet() && (user->GetType() == Primitive::kPrimNot))) {
Calin Juravlebeba9302015-07-08 15:57:18 +0000890 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000891 }
892 }
893}
Calin Juravle10e244f2015-01-26 18:54:32 +0000894} // namespace art