blob: 1224a48fa077b42eb8e23f87ea36985811c97db7 [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
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000026static inline ReferenceTypeInfo::TypeHandle GetRootHandle(StackHandleScopeCollection* handles,
27 ClassLinker::ClassRoot class_root,
28 ReferenceTypeInfo::TypeHandle* cache) {
29 if (!ReferenceTypeInfo::IsValidHandle(*cache)) {
30 // Mutator lock is required for NewHandle.
31 ClassLinker* linker = Runtime::Current()->GetClassLinker();
32 ScopedObjectAccess soa(Thread::Current());
33 *cache = handles->NewHandle(linker->GetClassRoot(class_root));
34 }
35 return *cache;
36}
37
38ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetObjectClassHandle() {
39 return GetRootHandle(handles_, ClassLinker::kJavaLangObject, &object_class_handle_);
40}
41
42ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetClassClassHandle() {
43 return GetRootHandle(handles_, ClassLinker::kJavaLangClass, &class_class_handle_);
44}
45
46ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetStringClassHandle() {
47 return GetRootHandle(handles_, ClassLinker::kJavaLangString, &string_class_handle_);
48}
49
50ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetThrowableClassHandle() {
51 return GetRootHandle(handles_, ClassLinker::kJavaLangThrowable, &throwable_class_handle_);
52}
53
54class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor {
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010055 public:
Calin Juravle2e768302015-07-28 14:41:11 +000056 RTPVisitor(HGraph* graph,
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000057 HandleCache* handle_cache,
58 ArenaVector<HInstruction*>* worklist)
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010059 : HGraphDelegateVisitor(graph),
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000060 handle_cache_(handle_cache),
Calin Juravle2e768302015-07-28 14:41:11 +000061 worklist_(worklist) {}
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010062
63 void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
64 void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000065 void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE;
66 void VisitLoadString(HLoadString* instr) OVERRIDE;
David Brazdilbbd733e2015-08-18 17:48:17 +010067 void VisitLoadException(HLoadException* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010068 void VisitNewArray(HNewArray* instr) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000069 void VisitParameterValue(HParameterValue* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010070 void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
71 void SetClassAsTypeInfo(HInstruction* instr, mirror::Class* klass, bool is_exact);
72 void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE;
73 void VisitStaticFieldGet(HStaticFieldGet* instr) OVERRIDE;
Calin Juravlee460d1d2015-09-29 04:52:17 +010074 void VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instr) OVERRIDE;
75 void VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010076 void VisitInvoke(HInvoke* instr) OVERRIDE;
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +010077 void VisitArrayGet(HArrayGet* instr) OVERRIDE;
Calin Juravlea5ae3c32015-07-28 14:40:50 +000078 void VisitCheckCast(HCheckCast* instr) OVERRIDE;
David Brazdilf5552582015-12-27 13:36:12 +000079 void VisitBoundType(HBoundType* instr) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000080 void VisitNullCheck(HNullCheck* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010081 void UpdateReferenceTypeInfo(HInstruction* instr,
82 uint16_t type_idx,
83 const DexFile& dex_file,
84 bool is_exact);
85
86 private:
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000087 HandleCache* handle_cache_;
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010088 ArenaVector<HInstruction*>* worklist_;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010089};
90
Calin Juravle2e768302015-07-28 14:41:11 +000091ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph,
92 StackHandleScopeCollection* handles,
93 const char* name)
94 : HOptimization(graph, name),
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000095 handle_cache_(handles),
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010096 worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)) {
Calin Juravle2e768302015-07-28 14:41:11 +000097}
98
Calin Juravlecdfed3d2015-10-26 14:05:01 +000099void ReferenceTypePropagation::ValidateTypes() {
100 // TODO: move this to the graph checker.
Calin Juravle2e768302015-07-28 14:41:11 +0000101 if (kIsDebugBuild) {
Calin Juravle2e768302015-07-28 14:41:11 +0000102 ScopedObjectAccess soa(Thread::Current());
103 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
104 HBasicBlock* block = it.Current();
105 for (HInstructionIterator iti(block->GetInstructions()); !iti.Done(); iti.Advance()) {
106 HInstruction* instr = iti.Current();
107 if (instr->GetType() == Primitive::kPrimNot) {
108 DCHECK(instr->GetReferenceTypeInfo().IsValid())
109 << "Invalid RTI for instruction: " << instr->DebugName();
110 if (instr->IsBoundType()) {
111 DCHECK(instr->AsBoundType()->GetUpperBound().IsValid());
112 } else if (instr->IsLoadClass()) {
Calin Juravle98893e12015-10-02 21:05:03 +0100113 HLoadClass* cls = instr->AsLoadClass();
114 DCHECK(cls->GetReferenceTypeInfo().IsExact());
115 DCHECK(!cls->GetLoadedClassRTI().IsValid() || cls->GetLoadedClassRTI().IsExact());
Calin Juravle2e768302015-07-28 14:41:11 +0000116 } else if (instr->IsNullCheck()) {
117 DCHECK(instr->GetReferenceTypeInfo().IsEqual(instr->InputAt(0)->GetReferenceTypeInfo()))
118 << "NullCheck " << instr->GetReferenceTypeInfo()
119 << "Input(0) " << instr->InputAt(0)->GetReferenceTypeInfo();
120 }
121 }
122 }
123 }
124 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000125}
126
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000127void ReferenceTypePropagation::Visit(HInstruction* instruction) {
128 RTPVisitor visitor(graph_, &handle_cache_, &worklist_);
129 instruction->Accept(&visitor);
130}
131
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000132void ReferenceTypePropagation::Run() {
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000133 worklist_.reserve(kDefaultWorklistSize);
134
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000135 // To properly propagate type info we need to visit in the dominator-based order.
136 // Reverse post order guarantees a node's dominators are visited first.
137 // We take advantage of this order in `VisitBasicBlock`.
138 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
139 VisitBasicBlock(it.Current());
140 }
141
142 ProcessWorklist();
143 ValidateTypes();
144}
145
Calin Juravleb1498f62015-02-16 13:13:29 +0000146void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000147 RTPVisitor visitor(graph_, &handle_cache_, &worklist_);
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(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000247 handle_cache_.GetObjectClassHandle(), /* 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
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000399void ReferenceTypePropagation::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(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000426 ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000427 } else if (klass != nullptr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100428 ScopedObjectAccess soa(Thread::Current());
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000429 ReferenceTypeInfo::TypeHandle handle = handle_cache_->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(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000434 ReferenceTypeInfo::Create(handle_cache_->GetObjectClassHandle(), /* is_exact */ false));
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100435 }
436}
437
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000438void ReferenceTypePropagation::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
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000451void ReferenceTypePropagation::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
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000455void ReferenceTypePropagation::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
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000471void ReferenceTypePropagation::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
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000481void ReferenceTypePropagation::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
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000504void ReferenceTypePropagation::RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100505 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
506}
507
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000508void ReferenceTypePropagation::RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100509 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
510}
511
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000512void ReferenceTypePropagation::RTPVisitor::VisitUnresolvedInstanceFieldGet(
513 HUnresolvedInstanceFieldGet* instr) {
Calin Juravlee460d1d2015-09-29 04:52:17 +0100514 // TODO: Use descriptor to get the actual type.
515 if (instr->GetFieldType() == Primitive::kPrimNot) {
516 instr->SetReferenceTypeInfo(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000517 ReferenceTypeInfo::Create(handle_cache_->GetObjectClassHandle(), /* is_exact */ false));
Calin Juravlee460d1d2015-09-29 04:52:17 +0100518 }
519}
520
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000521void ReferenceTypePropagation::RTPVisitor::VisitUnresolvedStaticFieldGet(
522 HUnresolvedStaticFieldGet* instr) {
Calin Juravlee460d1d2015-09-29 04:52:17 +0100523 // TODO: Use descriptor to get the actual type.
524 if (instr->GetFieldType() == Primitive::kPrimNot) {
525 instr->SetReferenceTypeInfo(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000526 ReferenceTypeInfo::Create(handle_cache_->GetObjectClassHandle(), /* is_exact */ false));
Calin Juravlee460d1d2015-09-29 04:52:17 +0100527 }
528}
529
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000530void ReferenceTypePropagation::RTPVisitor::VisitLoadClass(HLoadClass* instr) {
Calin Juravleacf735c2015-02-12 15:25:22 +0000531 ScopedObjectAccess soa(Thread::Current());
Calin Juravleacf735c2015-02-12 15:25:22 +0000532 // Get type from dex cache assuming it was populated by the verifier.
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000533 mirror::Class* resolved_class =
534 GetClassFromDexCache(soa.Self(), instr->GetDexFile(), instr->GetTypeIndex());
Calin Juravle98893e12015-10-02 21:05:03 +0100535 if (resolved_class != nullptr) {
536 instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000537 handle_cache_->NewHandle(resolved_class), /* is_exact */ true));
Calin Juravle98893e12015-10-02 21:05:03 +0100538 }
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000539 instr->SetReferenceTypeInfo(
540 ReferenceTypeInfo::Create(handle_cache_->GetClassClassHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000541}
542
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000543void ReferenceTypePropagation::RTPVisitor::VisitClinitCheck(HClinitCheck* instr) {
Calin Juravle2e768302015-07-28 14:41:11 +0000544 instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
545}
546
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000547void ReferenceTypePropagation::RTPVisitor::VisitLoadString(HLoadString* instr) {
548 instr->SetReferenceTypeInfo(
549 ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000550}
551
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000552void ReferenceTypePropagation::RTPVisitor::VisitLoadException(HLoadException* instr) {
David Brazdilbbd733e2015-08-18 17:48:17 +0100553 DCHECK(instr->GetBlock()->IsCatchBlock());
554 TryCatchInformation* catch_info = instr->GetBlock()->GetTryCatchInformation();
555
556 if (catch_info->IsCatchAllTypeIndex()) {
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000557 instr->SetReferenceTypeInfo(
558 ReferenceTypeInfo::Create(handle_cache_->GetThrowableClassHandle(), /* is_exact */ false));
David Brazdilbbd733e2015-08-18 17:48:17 +0100559 } else {
560 UpdateReferenceTypeInfo(instr,
561 catch_info->GetCatchTypeIndex(),
562 catch_info->GetCatchDexFile(),
563 /* is_exact */ false);
564 }
565}
566
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000567void ReferenceTypePropagation::RTPVisitor::VisitNullCheck(HNullCheck* instr) {
Calin Juravle2e768302015-07-28 14:41:11 +0000568 ScopedObjectAccess soa(Thread::Current());
569 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
David Brazdilfe860702015-12-02 09:06:57 +0000570 if (parent_rti.IsValid()) {
571 instr->SetReferenceTypeInfo(parent_rti);
572 }
Calin Juravle2e768302015-07-28 14:41:11 +0000573}
574
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000575void ReferenceTypePropagation::RTPVisitor::VisitBoundType(HBoundType* instr) {
David Brazdilf5552582015-12-27 13:36:12 +0000576 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
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000609void ReferenceTypePropagation::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) {
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000685 result_type_handle =
686 handle_cache_.NewHandle(a_type_handle->GetCommonSuperClass(b_type_handle));
Calin Juravle2e768302015-07-28 14:41:11 +0000687 is_exact = false;
688 } else {
Calin Juravle52503d82015-11-11 16:58:31 +0000689 // This can happen if:
690 // - both types are interfaces. TODO(calin): implement
691 // - one is an interface, the other a class, and the type does not implement the interface
692 // e.g:
693 // void foo(Interface i, boolean cond) {
694 // Object o = cond ? i : new Object();
695 // }
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000696 result_type_handle = handle_cache_.GetObjectClassHandle();
Calin Juravle2e768302015-07-28 14:41:11 +0000697 is_exact = false;
698 }
699
Calin Juravle52503d82015-11-11 16:58:31 +0000700 return ReferenceTypeInfo::Create(result_type_handle, is_exact);
Calin Juravle2e768302015-07-28 14:41:11 +0000701}
702
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000703void ReferenceTypePropagation::UpdateArrayGet(HArrayGet* instr, HandleCache* handle_cache) {
Calin Juravle2e768302015-07-28 14:41:11 +0000704 DCHECK_EQ(Primitive::kPrimNot, instr->GetType());
705
706 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
David Brazdilfe860702015-12-02 09:06:57 +0000707 if (!parent_rti.IsValid()) {
708 return;
709 }
Calin Juravle2e768302015-07-28 14:41:11 +0000710
711 Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
712 if (handle->IsObjectArrayClass()) {
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000713 ReferenceTypeInfo::TypeHandle component_handle =
714 handle_cache->NewHandle(handle->GetComponentType());
Calin Juravle2e768302015-07-28 14:41:11 +0000715 instr->SetReferenceTypeInfo(
716 ReferenceTypeInfo::Create(component_handle, /* is_exact */ false));
717 } else {
718 // We don't know what the parent actually is, so we fallback to object.
719 instr->SetReferenceTypeInfo(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000720 ReferenceTypeInfo::Create(handle_cache->GetObjectClassHandle(), /* is_exact */ false));
Calin Juravle2e768302015-07-28 14:41:11 +0000721 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000722}
723
724bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
725 ScopedObjectAccess soa(Thread::Current());
726
727 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
728 if (instr->IsBoundType()) {
729 UpdateBoundType(instr->AsBoundType());
730 } else if (instr->IsPhi()) {
731 UpdatePhi(instr->AsPhi());
Calin Juravle2e768302015-07-28 14:41:11 +0000732 } else if (instr->IsNullCheck()) {
733 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
734 if (parent_rti.IsValid()) {
735 instr->SetReferenceTypeInfo(parent_rti);
736 }
737 } else if (instr->IsArrayGet()) {
David Brazdilfe860702015-12-02 09:06:57 +0000738 // TODO: consider if it's worth "looking back" and binding the input object
Calin Juravle2e768302015-07-28 14:41:11 +0000739 // to an array type.
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000740 UpdateArrayGet(instr->AsArrayGet(), &handle_cache_);
Calin Juravleb1498f62015-02-16 13:13:29 +0000741 } else {
742 LOG(FATAL) << "Invalid instruction (should not get here)";
743 }
744
745 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
746}
747
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000748void ReferenceTypePropagation::RTPVisitor::VisitInvoke(HInvoke* instr) {
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100749 if (instr->GetType() != Primitive::kPrimNot) {
750 return;
751 }
752
753 ScopedObjectAccess soa(Thread::Current());
754 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700755 mirror::DexCache* dex_cache = cl->FindDexCache(soa.Self(), instr->GetDexFile());
Vladimir Marko05792b92015-08-03 11:56:49 +0100756 size_t pointer_size = cl->GetImagePointerSize();
757 ArtMethod* method = dex_cache->GetResolvedMethod(instr->GetDexMethodIndex(), pointer_size);
758 mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false, pointer_size);
Calin Juravle2e768302015-07-28 14:41:11 +0000759 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100760}
761
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000762void ReferenceTypePropagation::RTPVisitor::VisitArrayGet(HArrayGet* instr) {
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100763 if (instr->GetType() != Primitive::kPrimNot) {
764 return;
765 }
David Brazdilfe860702015-12-02 09:06:57 +0000766
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100767 ScopedObjectAccess soa(Thread::Current());
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000768 UpdateArrayGet(instr, handle_cache_);
Calin Juravle2e768302015-07-28 14:41:11 +0000769 if (!instr->GetReferenceTypeInfo().IsValid()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100770 worklist_->push_back(instr);
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100771 }
772}
773
Calin Juravleb1498f62015-02-16 13:13:29 +0000774void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
775 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle2e768302015-07-28 14:41:11 +0000776 if (!new_rti.IsValid()) {
777 return; // No new info yet.
778 }
779
780 // Make sure that we don't go over the bounded type.
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000781 ReferenceTypeInfo upper_bound_rti = instr->GetUpperBound();
782 if (!upper_bound_rti.IsSupertypeOf(new_rti)) {
783 new_rti = upper_bound_rti;
Calin Juravleb1498f62015-02-16 13:13:29 +0000784 }
785 instr->SetReferenceTypeInfo(new_rti);
786}
787
Calin Juravle617bd922015-11-11 14:59:46 +0000788// NullConstant inputs are ignored during merging as they do not provide any useful information.
789// If all the inputs are NullConstants then the type of the phi will be set to Object.
Calin Juravleb1498f62015-02-16 13:13:29 +0000790void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
David Brazdild9510df2015-11-04 23:30:22 +0000791 DCHECK(instr->IsLive());
792
Calin Juravle617bd922015-11-11 14:59:46 +0000793 size_t input_count = instr->InputCount();
794 size_t first_input_index_not_null = 0;
795 while (first_input_index_not_null < input_count &&
796 instr->InputAt(first_input_index_not_null)->IsNullConstant()) {
797 first_input_index_not_null++;
798 }
799 if (first_input_index_not_null == input_count) {
800 // All inputs are NullConstants, set the type to object.
801 // This may happen in the presence of inlining.
802 instr->SetReferenceTypeInfo(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000803 ReferenceTypeInfo::Create(handle_cache_.GetObjectClassHandle(), /* is_exact */ false));
Calin Juravle617bd922015-11-11 14:59:46 +0000804 return;
805 }
806
807 ReferenceTypeInfo new_rti = instr->InputAt(first_input_index_not_null)->GetReferenceTypeInfo();
808
Calin Juravle2e768302015-07-28 14:41:11 +0000809 if (new_rti.IsValid() && new_rti.IsObjectClass() && !new_rti.IsExact()) {
810 // Early return if we are Object and inexact.
Calin Juravleb1498f62015-02-16 13:13:29 +0000811 instr->SetReferenceTypeInfo(new_rti);
812 return;
813 }
Calin Juravle617bd922015-11-11 14:59:46 +0000814
815 for (size_t i = first_input_index_not_null + 1; i < input_count; i++) {
816 if (instr->InputAt(i)->IsNullConstant()) {
817 continue;
818 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000819 new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo());
Calin Juravle2e768302015-07-28 14:41:11 +0000820 if (new_rti.IsValid() && new_rti.IsObjectClass()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000821 if (!new_rti.IsExact()) {
822 break;
823 } else {
824 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000825 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000826 }
827 }
David Brazdilfe860702015-12-02 09:06:57 +0000828
829 if (new_rti.IsValid()) {
830 instr->SetReferenceTypeInfo(new_rti);
831 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000832}
833
834// Re-computes and updates the nullability of the instruction. Returns whether or
835// not the nullability was changed.
836bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
David Brazdild9510df2015-11-04 23:30:22 +0000837 DCHECK((instr->IsPhi() && instr->AsPhi()->IsLive())
Calin Juravle2e768302015-07-28 14:41:11 +0000838 || instr->IsBoundType()
839 || instr->IsNullCheck()
840 || instr->IsArrayGet());
841
842 if (!instr->IsPhi() && !instr->IsBoundType()) {
843 return false;
844 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000845
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000846 bool existing_can_be_null = instr->CanBeNull();
847 if (instr->IsPhi()) {
848 HPhi* phi = instr->AsPhi();
849 bool new_can_be_null = false;
850 for (size_t i = 0; i < phi->InputCount(); i++) {
851 if (phi->InputAt(i)->CanBeNull()) {
852 new_can_be_null = true;
853 break;
854 }
855 }
856 phi->SetCanBeNull(new_can_be_null);
857 } else if (instr->IsBoundType()) {
858 HBoundType* bound_type = instr->AsBoundType();
859 bound_type->SetCanBeNull(instr->InputAt(0)->CanBeNull() && bound_type->GetUpperCanBeNull());
Calin Juravleb1498f62015-02-16 13:13:29 +0000860 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000861 return existing_can_be_null != instr->CanBeNull();
Calin Juravle10e244f2015-01-26 18:54:32 +0000862}
863
864void ReferenceTypePropagation::ProcessWorklist() {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100865 while (!worklist_.empty()) {
866 HInstruction* instruction = worklist_.back();
867 worklist_.pop_back();
Calin Juravle12617592015-10-16 16:28:46 +0100868 bool updated_nullability = UpdateNullability(instruction);
869 bool updated_reference_type = UpdateReferenceTypeInfo(instruction);
870 if (updated_nullability || updated_reference_type) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000871 AddDependentInstructionsToWorklist(instruction);
872 }
873 }
874}
875
Calin Juravleb1498f62015-02-16 13:13:29 +0000876void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
Calin Juravle2e768302015-07-28 14:41:11 +0000877 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot)
878 << instruction->DebugName() << ":" << instruction->GetType();
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100879 worklist_.push_back(instruction);
Calin Juravle10e244f2015-01-26 18:54:32 +0000880}
881
Calin Juravleb1498f62015-02-16 13:13:29 +0000882void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000883 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000884 HInstruction* user = it.Current()->GetUser();
David Brazdild9510df2015-11-04 23:30:22 +0000885 if ((user->IsPhi() && user->AsPhi()->IsLive())
Calin Juravle2e768302015-07-28 14:41:11 +0000886 || user->IsBoundType()
887 || user->IsNullCheck()
888 || (user->IsArrayGet() && (user->GetType() == Primitive::kPrimNot))) {
Calin Juravlebeba9302015-07-08 15:57:18 +0000889 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000890 }
891 }
892}
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000893
Calin Juravle10e244f2015-01-26 18:54:32 +0000894} // namespace art