blob: e55061c92a2f2125c1e271ab5cbbd42f1a9cd407 [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));
586 } else if (obj_rti.IsValid() && class_rti.IsSupertypeOf(obj_rti)) {
587 instr->SetReferenceTypeInfo(obj_rti);
588 } else {
589 instr->SetReferenceTypeInfo(
590 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
591 }
592 instr->SetCanBeNull(obj->CanBeNull() && instr->GetUpperCanBeNull());
593 } else {
594 // The owner of the BoundType was already visited. If the class is unresolved,
595 // the BoundType should have been removed from the data flow and this method
596 // should remove it from the graph.
597 DCHECK(!instr->HasUses());
598 instr->GetBlock()->RemoveInstruction(instr);
599 }
600}
601
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000602void RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
David Brazdilf5552582015-12-27 13:36:12 +0000603 ScopedObjectAccess soa(Thread::Current());
604
Calin Juravle98893e12015-10-02 21:05:03 +0100605 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
606 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
David Brazdilf5552582015-12-27 13:36:12 +0000607 HBoundType* bound_type = check_cast->GetNext()->AsBoundType();
608 if (bound_type == nullptr || bound_type->GetUpperBound().IsValid()) {
609 // The next instruction is not an uninitialized BoundType. This must be
610 // an RTP pass after SsaBuilder and we do not need to do anything.
611 return;
Calin Juravle98893e12015-10-02 21:05:03 +0100612 }
David Brazdilf5552582015-12-27 13:36:12 +0000613 DCHECK_EQ(bound_type->InputAt(0), check_cast->InputAt(0));
614
615 if (class_rti.IsValid()) {
616 // This is the first run of RTP and class is resolved.
617 bound_type->SetUpperBound(class_rti, /* CheckCast succeeds for nulls. */ true);
618 } else {
619 // This is the first run of RTP and class is unresolved. Remove the binding.
620 // The instruction itself is removed in VisitBoundType so as to not
621 // invalidate HInstructionIterator.
622 bound_type->ReplaceWith(bound_type->InputAt(0));
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000623 }
624}
625
Calin Juravleb1498f62015-02-16 13:13:29 +0000626void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
David Brazdild9510df2015-11-04 23:30:22 +0000627 if (phi->IsDead() || phi->GetType() != Primitive::kPrimNot) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000628 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000629 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000630
631 if (phi->GetBlock()->IsLoopHeader()) {
David Brazdilfe860702015-12-02 09:06:57 +0000632 ScopedObjectAccess soa(Thread::Current());
Calin Juravleb1498f62015-02-16 13:13:29 +0000633 // Set the initial type for the phi. Use the non back edge input for reaching
634 // a fixed point faster.
David Brazdilfe860702015-12-02 09:06:57 +0000635 HInstruction* first_input = phi->InputAt(0);
636 ReferenceTypeInfo first_input_rti = first_input->GetReferenceTypeInfo();
637 if (first_input_rti.IsValid() && !first_input->IsNullConstant()) {
638 phi->SetCanBeNull(first_input->CanBeNull());
639 phi->SetReferenceTypeInfo(first_input_rti);
640 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000641 AddToWorklist(phi);
Calin Juravle10e244f2015-01-26 18:54:32 +0000642 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000643 // Eagerly compute the type of the phi, for quicker convergence. Note
644 // that we don't need to add users to the worklist because we are
645 // doing a reverse post-order visit, therefore either the phi users are
646 // non-loop phi and will be visited later in the visit, or are loop-phis,
647 // and they are already in the work list.
648 UpdateNullability(phi);
649 UpdateReferenceTypeInfo(phi);
650 }
651}
652
653ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
654 const ReferenceTypeInfo& b) {
Calin Juravle2e768302015-07-28 14:41:11 +0000655 if (!b.IsValid()) {
656 return a;
657 }
658 if (!a.IsValid()) {
659 return b;
Calin Juravle20e60712015-07-01 18:41:04 +0100660 }
661
Calin Juravle2e768302015-07-28 14:41:11 +0000662 bool is_exact = a.IsExact() && b.IsExact();
Calin Juravle52503d82015-11-11 16:58:31 +0000663 ReferenceTypeInfo::TypeHandle result_type_handle;
664 ReferenceTypeInfo::TypeHandle a_type_handle = a.GetTypeHandle();
665 ReferenceTypeInfo::TypeHandle b_type_handle = b.GetTypeHandle();
666 bool a_is_interface = a_type_handle->IsInterface();
667 bool b_is_interface = b_type_handle->IsInterface();
Calin Juravle2e768302015-07-28 14:41:11 +0000668
669 if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
Calin Juravle52503d82015-11-11 16:58:31 +0000670 result_type_handle = a_type_handle;
Calin Juravle2e768302015-07-28 14:41:11 +0000671 } else if (a.IsSupertypeOf(b)) {
Calin Juravle52503d82015-11-11 16:58:31 +0000672 result_type_handle = a_type_handle;
Calin Juravle2e768302015-07-28 14:41:11 +0000673 is_exact = false;
674 } else if (b.IsSupertypeOf(a)) {
Calin Juravle52503d82015-11-11 16:58:31 +0000675 result_type_handle = b_type_handle;
676 is_exact = false;
677 } else if (!a_is_interface && !b_is_interface) {
678 result_type_handle = handles_->NewHandle(a_type_handle->GetCommonSuperClass(b_type_handle));
Calin Juravle2e768302015-07-28 14:41:11 +0000679 is_exact = false;
680 } else {
Calin Juravle52503d82015-11-11 16:58:31 +0000681 // This can happen if:
682 // - both types are interfaces. TODO(calin): implement
683 // - one is an interface, the other a class, and the type does not implement the interface
684 // e.g:
685 // void foo(Interface i, boolean cond) {
686 // Object o = cond ? i : new Object();
687 // }
688 result_type_handle = object_class_handle_;
Calin Juravle2e768302015-07-28 14:41:11 +0000689 is_exact = false;
690 }
691
Calin Juravle52503d82015-11-11 16:58:31 +0000692 return ReferenceTypeInfo::Create(result_type_handle, is_exact);
Calin Juravle2e768302015-07-28 14:41:11 +0000693}
694
695static void UpdateArrayGet(HArrayGet* instr,
696 StackHandleScopeCollection* handles,
697 ReferenceTypeInfo::TypeHandle object_class_handle)
698 SHARED_REQUIRES(Locks::mutator_lock_) {
699 DCHECK_EQ(Primitive::kPrimNot, instr->GetType());
700
701 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
David Brazdilfe860702015-12-02 09:06:57 +0000702 if (!parent_rti.IsValid()) {
703 return;
704 }
Calin Juravle2e768302015-07-28 14:41:11 +0000705
706 Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
707 if (handle->IsObjectArrayClass()) {
708 ReferenceTypeInfo::TypeHandle component_handle = handles->NewHandle(handle->GetComponentType());
709 instr->SetReferenceTypeInfo(
710 ReferenceTypeInfo::Create(component_handle, /* is_exact */ false));
711 } else {
712 // We don't know what the parent actually is, so we fallback to object.
713 instr->SetReferenceTypeInfo(
714 ReferenceTypeInfo::Create(object_class_handle, /* is_exact */ false));
715 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000716}
717
718bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
719 ScopedObjectAccess soa(Thread::Current());
720
721 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
722 if (instr->IsBoundType()) {
723 UpdateBoundType(instr->AsBoundType());
724 } else if (instr->IsPhi()) {
725 UpdatePhi(instr->AsPhi());
Calin Juravle2e768302015-07-28 14:41:11 +0000726 } else if (instr->IsNullCheck()) {
727 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
728 if (parent_rti.IsValid()) {
729 instr->SetReferenceTypeInfo(parent_rti);
730 }
731 } else if (instr->IsArrayGet()) {
David Brazdilfe860702015-12-02 09:06:57 +0000732 // TODO: consider if it's worth "looking back" and binding the input object
Calin Juravle2e768302015-07-28 14:41:11 +0000733 // to an array type.
734 UpdateArrayGet(instr->AsArrayGet(), handles_, object_class_handle_);
Calin Juravleb1498f62015-02-16 13:13:29 +0000735 } else {
736 LOG(FATAL) << "Invalid instruction (should not get here)";
737 }
738
739 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
740}
741
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100742void RTPVisitor::VisitInvoke(HInvoke* instr) {
743 if (instr->GetType() != Primitive::kPrimNot) {
744 return;
745 }
746
747 ScopedObjectAccess soa(Thread::Current());
748 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700749 mirror::DexCache* dex_cache = cl->FindDexCache(soa.Self(), instr->GetDexFile());
Vladimir Marko05792b92015-08-03 11:56:49 +0100750 size_t pointer_size = cl->GetImagePointerSize();
751 ArtMethod* method = dex_cache->GetResolvedMethod(instr->GetDexMethodIndex(), pointer_size);
752 mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false, pointer_size);
Calin Juravle2e768302015-07-28 14:41:11 +0000753 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100754}
755
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100756void RTPVisitor::VisitArrayGet(HArrayGet* instr) {
757 if (instr->GetType() != Primitive::kPrimNot) {
758 return;
759 }
David Brazdilfe860702015-12-02 09:06:57 +0000760
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100761 ScopedObjectAccess soa(Thread::Current());
Calin Juravle2e768302015-07-28 14:41:11 +0000762 UpdateArrayGet(instr, handles_, object_class_handle_);
763 if (!instr->GetReferenceTypeInfo().IsValid()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100764 worklist_->push_back(instr);
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100765 }
766}
767
Calin Juravleb1498f62015-02-16 13:13:29 +0000768void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
769 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle2e768302015-07-28 14:41:11 +0000770 if (!new_rti.IsValid()) {
771 return; // No new info yet.
772 }
773
774 // Make sure that we don't go over the bounded type.
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000775 ReferenceTypeInfo upper_bound_rti = instr->GetUpperBound();
776 if (!upper_bound_rti.IsSupertypeOf(new_rti)) {
777 new_rti = upper_bound_rti;
Calin Juravleb1498f62015-02-16 13:13:29 +0000778 }
779 instr->SetReferenceTypeInfo(new_rti);
780}
781
Calin Juravle617bd922015-11-11 14:59:46 +0000782// NullConstant inputs are ignored during merging as they do not provide any useful information.
783// If all the inputs are NullConstants then the type of the phi will be set to Object.
Calin Juravleb1498f62015-02-16 13:13:29 +0000784void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
David Brazdild9510df2015-11-04 23:30:22 +0000785 DCHECK(instr->IsLive());
786
Calin Juravle617bd922015-11-11 14:59:46 +0000787 size_t input_count = instr->InputCount();
788 size_t first_input_index_not_null = 0;
789 while (first_input_index_not_null < input_count &&
790 instr->InputAt(first_input_index_not_null)->IsNullConstant()) {
791 first_input_index_not_null++;
792 }
793 if (first_input_index_not_null == input_count) {
794 // All inputs are NullConstants, set the type to object.
795 // This may happen in the presence of inlining.
796 instr->SetReferenceTypeInfo(
797 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
798 return;
799 }
800
801 ReferenceTypeInfo new_rti = instr->InputAt(first_input_index_not_null)->GetReferenceTypeInfo();
802
Calin Juravle2e768302015-07-28 14:41:11 +0000803 if (new_rti.IsValid() && new_rti.IsObjectClass() && !new_rti.IsExact()) {
804 // Early return if we are Object and inexact.
Calin Juravleb1498f62015-02-16 13:13:29 +0000805 instr->SetReferenceTypeInfo(new_rti);
806 return;
807 }
Calin Juravle617bd922015-11-11 14:59:46 +0000808
809 for (size_t i = first_input_index_not_null + 1; i < input_count; i++) {
810 if (instr->InputAt(i)->IsNullConstant()) {
811 continue;
812 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000813 new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo());
Calin Juravle2e768302015-07-28 14:41:11 +0000814 if (new_rti.IsValid() && new_rti.IsObjectClass()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000815 if (!new_rti.IsExact()) {
816 break;
817 } else {
818 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000819 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000820 }
821 }
David Brazdilfe860702015-12-02 09:06:57 +0000822
823 if (new_rti.IsValid()) {
824 instr->SetReferenceTypeInfo(new_rti);
825 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000826}
827
828// Re-computes and updates the nullability of the instruction. Returns whether or
829// not the nullability was changed.
830bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
David Brazdild9510df2015-11-04 23:30:22 +0000831 DCHECK((instr->IsPhi() && instr->AsPhi()->IsLive())
Calin Juravle2e768302015-07-28 14:41:11 +0000832 || instr->IsBoundType()
833 || instr->IsNullCheck()
834 || instr->IsArrayGet());
835
836 if (!instr->IsPhi() && !instr->IsBoundType()) {
837 return false;
838 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000839
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000840 bool existing_can_be_null = instr->CanBeNull();
841 if (instr->IsPhi()) {
842 HPhi* phi = instr->AsPhi();
843 bool new_can_be_null = false;
844 for (size_t i = 0; i < phi->InputCount(); i++) {
845 if (phi->InputAt(i)->CanBeNull()) {
846 new_can_be_null = true;
847 break;
848 }
849 }
850 phi->SetCanBeNull(new_can_be_null);
851 } else if (instr->IsBoundType()) {
852 HBoundType* bound_type = instr->AsBoundType();
853 bound_type->SetCanBeNull(instr->InputAt(0)->CanBeNull() && bound_type->GetUpperCanBeNull());
Calin Juravleb1498f62015-02-16 13:13:29 +0000854 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000855 return existing_can_be_null != instr->CanBeNull();
Calin Juravle10e244f2015-01-26 18:54:32 +0000856}
857
858void ReferenceTypePropagation::ProcessWorklist() {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100859 while (!worklist_.empty()) {
860 HInstruction* instruction = worklist_.back();
861 worklist_.pop_back();
Calin Juravle12617592015-10-16 16:28:46 +0100862 bool updated_nullability = UpdateNullability(instruction);
863 bool updated_reference_type = UpdateReferenceTypeInfo(instruction);
864 if (updated_nullability || updated_reference_type) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000865 AddDependentInstructionsToWorklist(instruction);
866 }
867 }
868}
869
Calin Juravleb1498f62015-02-16 13:13:29 +0000870void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
Calin Juravle2e768302015-07-28 14:41:11 +0000871 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot)
872 << instruction->DebugName() << ":" << instruction->GetType();
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100873 worklist_.push_back(instruction);
Calin Juravle10e244f2015-01-26 18:54:32 +0000874}
875
Calin Juravleb1498f62015-02-16 13:13:29 +0000876void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000877 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000878 HInstruction* user = it.Current()->GetUser();
David Brazdild9510df2015-11-04 23:30:22 +0000879 if ((user->IsPhi() && user->AsPhi()->IsLive())
Calin Juravle2e768302015-07-28 14:41:11 +0000880 || user->IsBoundType()
881 || user->IsNullCheck()
882 || (user->IsArrayGet() && (user->GetType() == Primitive::kPrimNot))) {
Calin Juravlebeba9302015-07-08 15:57:18 +0000883 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000884 }
885 }
886}
Calin Juravle10e244f2015-01-26 18:54:32 +0000887} // namespace art