blob: 21d7ee7a6fd0cf903c7f3716221f393284c8b26e [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 Marko456307a2016-04-19 14:12:13 +000026static inline mirror::DexCache* FindDexCacheWithHint(Thread* self,
27 const DexFile& dex_file,
28 Handle<mirror::DexCache> hint_dex_cache)
29 SHARED_REQUIRES(Locks::mutator_lock_) {
30 if (LIKELY(hint_dex_cache->GetDexFile() == &dex_file)) {
31 return hint_dex_cache.Get();
32 } else {
33 return Runtime::Current()->GetClassLinker()->FindDexCache(self, dex_file);
34 }
35}
36
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000037static inline ReferenceTypeInfo::TypeHandle GetRootHandle(StackHandleScopeCollection* handles,
38 ClassLinker::ClassRoot class_root,
39 ReferenceTypeInfo::TypeHandle* cache) {
40 if (!ReferenceTypeInfo::IsValidHandle(*cache)) {
41 // Mutator lock is required for NewHandle.
42 ClassLinker* linker = Runtime::Current()->GetClassLinker();
43 ScopedObjectAccess soa(Thread::Current());
44 *cache = handles->NewHandle(linker->GetClassRoot(class_root));
45 }
46 return *cache;
47}
48
49ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetObjectClassHandle() {
50 return GetRootHandle(handles_, ClassLinker::kJavaLangObject, &object_class_handle_);
51}
52
53ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetClassClassHandle() {
54 return GetRootHandle(handles_, ClassLinker::kJavaLangClass, &class_class_handle_);
55}
56
57ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetStringClassHandle() {
58 return GetRootHandle(handles_, ClassLinker::kJavaLangString, &string_class_handle_);
59}
60
61ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetThrowableClassHandle() {
62 return GetRootHandle(handles_, ClassLinker::kJavaLangThrowable, &throwable_class_handle_);
63}
64
65class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor {
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010066 public:
Calin Juravle2e768302015-07-28 14:41:11 +000067 RTPVisitor(HGraph* graph,
Vladimir Marko456307a2016-04-19 14:12:13 +000068 Handle<mirror::DexCache> hint_dex_cache,
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000069 HandleCache* handle_cache,
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +000070 ArenaVector<HInstruction*>* worklist,
71 bool is_first_run)
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010072 : HGraphDelegateVisitor(graph),
Vladimir Marko456307a2016-04-19 14:12:13 +000073 hint_dex_cache_(hint_dex_cache),
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000074 handle_cache_(handle_cache),
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +000075 worklist_(worklist),
76 is_first_run_(is_first_run) {}
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010077
78 void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
79 void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000080 void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE;
81 void VisitLoadString(HLoadString* instr) OVERRIDE;
David Brazdilbbd733e2015-08-18 17:48:17 +010082 void VisitLoadException(HLoadException* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010083 void VisitNewArray(HNewArray* instr) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000084 void VisitParameterValue(HParameterValue* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010085 void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
86 void SetClassAsTypeInfo(HInstruction* instr, mirror::Class* klass, bool is_exact);
87 void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE;
88 void VisitStaticFieldGet(HStaticFieldGet* instr) OVERRIDE;
Calin Juravlee460d1d2015-09-29 04:52:17 +010089 void VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instr) OVERRIDE;
90 void VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010091 void VisitInvoke(HInvoke* instr) OVERRIDE;
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +010092 void VisitArrayGet(HArrayGet* instr) OVERRIDE;
Calin Juravlea5ae3c32015-07-28 14:40:50 +000093 void VisitCheckCast(HCheckCast* instr) OVERRIDE;
David Brazdilf5552582015-12-27 13:36:12 +000094 void VisitBoundType(HBoundType* instr) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000095 void VisitNullCheck(HNullCheck* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010096 void UpdateReferenceTypeInfo(HInstruction* instr,
97 uint16_t type_idx,
98 const DexFile& dex_file,
99 bool is_exact);
100
101 private:
Vladimir Marko456307a2016-04-19 14:12:13 +0000102 Handle<mirror::DexCache> hint_dex_cache_;
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000103 HandleCache* handle_cache_;
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100104 ArenaVector<HInstruction*>* worklist_;
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000105 const bool is_first_run_;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100106};
107
Calin Juravle2e768302015-07-28 14:41:11 +0000108ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph,
Vladimir Marko456307a2016-04-19 14:12:13 +0000109 Handle<mirror::DexCache> hint_dex_cache,
Calin Juravle2e768302015-07-28 14:41:11 +0000110 StackHandleScopeCollection* handles,
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000111 bool is_first_run,
Calin Juravle2e768302015-07-28 14:41:11 +0000112 const char* name)
113 : HOptimization(graph, name),
Vladimir Marko456307a2016-04-19 14:12:13 +0000114 hint_dex_cache_(hint_dex_cache),
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000115 handle_cache_(handles),
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000116 worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)),
117 is_first_run_(is_first_run) {
Calin Juravle2e768302015-07-28 14:41:11 +0000118}
119
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000120void ReferenceTypePropagation::ValidateTypes() {
121 // TODO: move this to the graph checker.
Calin Juravle2e768302015-07-28 14:41:11 +0000122 if (kIsDebugBuild) {
Calin Juravle2e768302015-07-28 14:41:11 +0000123 ScopedObjectAccess soa(Thread::Current());
124 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
125 HBasicBlock* block = it.Current();
126 for (HInstructionIterator iti(block->GetInstructions()); !iti.Done(); iti.Advance()) {
127 HInstruction* instr = iti.Current();
128 if (instr->GetType() == Primitive::kPrimNot) {
129 DCHECK(instr->GetReferenceTypeInfo().IsValid())
130 << "Invalid RTI for instruction: " << instr->DebugName();
131 if (instr->IsBoundType()) {
132 DCHECK(instr->AsBoundType()->GetUpperBound().IsValid());
133 } else if (instr->IsLoadClass()) {
Calin Juravle98893e12015-10-02 21:05:03 +0100134 HLoadClass* cls = instr->AsLoadClass();
135 DCHECK(cls->GetReferenceTypeInfo().IsExact());
136 DCHECK(!cls->GetLoadedClassRTI().IsValid() || cls->GetLoadedClassRTI().IsExact());
Calin Juravle2e768302015-07-28 14:41:11 +0000137 } else if (instr->IsNullCheck()) {
138 DCHECK(instr->GetReferenceTypeInfo().IsEqual(instr->InputAt(0)->GetReferenceTypeInfo()))
139 << "NullCheck " << instr->GetReferenceTypeInfo()
140 << "Input(0) " << instr->InputAt(0)->GetReferenceTypeInfo();
141 }
142 }
143 }
144 }
145 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000146}
147
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000148void ReferenceTypePropagation::Visit(HInstruction* instruction) {
Vladimir Marko456307a2016-04-19 14:12:13 +0000149 RTPVisitor visitor(graph_, hint_dex_cache_, &handle_cache_, &worklist_, is_first_run_);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000150 instruction->Accept(&visitor);
151}
152
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000153void ReferenceTypePropagation::Run() {
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000154 worklist_.reserve(kDefaultWorklistSize);
155
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000156 // To properly propagate type info we need to visit in the dominator-based order.
157 // Reverse post order guarantees a node's dominators are visited first.
158 // We take advantage of this order in `VisitBasicBlock`.
159 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
160 VisitBasicBlock(it.Current());
161 }
162
163 ProcessWorklist();
164 ValidateTypes();
165}
166
Calin Juravleb1498f62015-02-16 13:13:29 +0000167void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
Vladimir Marko456307a2016-04-19 14:12:13 +0000168 RTPVisitor visitor(graph_, hint_dex_cache_, &handle_cache_, &worklist_, is_first_run_);
Calin Juravle2e768302015-07-28 14:41:11 +0000169 // Handle Phis first as there might be instructions in the same block who depend on them.
170 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
171 VisitPhi(it.Current()->AsPhi());
172 }
Calin Juravlebeba9302015-07-08 15:57:18 +0000173
Calin Juravle2e768302015-07-28 14:41:11 +0000174 // Handle instructions.
Calin Juravleb1498f62015-02-16 13:13:29 +0000175 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
176 HInstruction* instr = it.Current();
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100177 instr->Accept(&visitor);
Calin Juravleb1498f62015-02-16 13:13:29 +0000178 }
179
Calin Juravleb1498f62015-02-16 13:13:29 +0000180 // Add extra nodes to bound types.
Calin Juravle61d544b2015-02-23 16:46:57 +0000181 BoundTypeForIfNotNull(block);
Calin Juravleb1498f62015-02-16 13:13:29 +0000182 BoundTypeForIfInstanceOf(block);
Calin Juravle10e244f2015-01-26 18:54:32 +0000183}
184
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000185// Check if we should create a bound type for the given object at the specified
186// position. Because of inlining and the fact we run RTP more than once and we
187// might have a HBoundType already. If we do, we should not create a new one.
188// In this case we also assert that there are no other uses of the object (except
189// the bound type) dominated by the specified dominator_instr or dominator_block.
190static bool ShouldCreateBoundType(HInstruction* position,
191 HInstruction* obj,
192 ReferenceTypeInfo upper_bound,
193 HInstruction* dominator_instr,
194 HBasicBlock* dominator_block)
195 SHARED_REQUIRES(Locks::mutator_lock_) {
196 // If the position where we should insert the bound type is not already a
197 // a bound type then we need to create one.
198 if (position == nullptr || !position->IsBoundType()) {
199 return true;
200 }
201
202 HBoundType* existing_bound_type = position->AsBoundType();
203 if (existing_bound_type->GetUpperBound().IsSupertypeOf(upper_bound)) {
204 if (kIsDebugBuild) {
205 // Check that the existing HBoundType dominates all the uses.
206 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
207 HInstruction* user = it.Current()->GetUser();
208 if (dominator_instr != nullptr) {
209 DCHECK(!dominator_instr->StrictlyDominates(user)
210 || user == existing_bound_type
211 || existing_bound_type->StrictlyDominates(user));
212 } else if (dominator_block != nullptr) {
213 DCHECK(!dominator_block->Dominates(user->GetBlock())
214 || user == existing_bound_type
215 || existing_bound_type->StrictlyDominates(user));
216 }
217 }
218 }
219 } else {
220 // TODO: if the current bound type is a refinement we could update the
221 // existing_bound_type with the a new upper limit. However, we also need to
222 // update its users and have access to the work list.
223 }
224 return false;
225}
226
Calin Juravle61d544b2015-02-23 16:46:57 +0000227void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100228 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
229 if (ifInstruction == nullptr) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000230 return;
231 }
Calin Juravleb3306642015-04-20 18:30:42 +0100232 HInstruction* ifInput = ifInstruction->InputAt(0);
Calin Juravle61d544b2015-02-23 16:46:57 +0000233 if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) {
234 return;
235 }
236 HInstruction* input0 = ifInput->InputAt(0);
237 HInstruction* input1 = ifInput->InputAt(1);
Calin Juravleedad8ad2015-04-23 14:34:33 +0100238 HInstruction* obj = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000239
Calin Juravleedad8ad2015-04-23 14:34:33 +0100240 if (input1->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000241 obj = input0;
Calin Juravleedad8ad2015-04-23 14:34:33 +0100242 } else if (input0->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000243 obj = input1;
244 } else {
245 return;
246 }
247
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100248 if (!obj->CanBeNull() || obj->IsNullConstant()) {
249 // Null check is dead code and will be removed by DCE.
250 return;
251 }
252 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
253
Calin Juravleb3306642015-04-20 18:30:42 +0100254 // We only need to bound the type if we have uses in the relevant block.
255 // So start with null and create the HBoundType lazily, only if it's needed.
256 HBoundType* bound_type = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000257 HBasicBlock* notNullBlock = ifInput->IsNotEqual()
Calin Juravleb3306642015-04-20 18:30:42 +0100258 ? ifInstruction->IfTrueSuccessor()
259 : ifInstruction->IfFalseSuccessor();
260
Calin Juravle61d544b2015-02-23 16:46:57 +0000261 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
262 HInstruction* user = it.Current()->GetUser();
263 if (notNullBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100264 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000265 ScopedObjectAccess soa(Thread::Current());
266 HInstruction* insert_point = notNullBlock->GetFirstInstruction();
Calin Juravle2e768302015-07-28 14:41:11 +0000267 ReferenceTypeInfo object_rti = ReferenceTypeInfo::Create(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000268 handle_cache_.GetObjectClassHandle(), /* is_exact */ true);
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000269 if (ShouldCreateBoundType(insert_point, obj, object_rti, nullptr, notNullBlock)) {
David Brazdilf5552582015-12-27 13:36:12 +0000270 bound_type = new (graph_->GetArena()) HBoundType(obj);
271 bound_type->SetUpperBound(object_rti, /* bound_can_be_null */ false);
Calin Juravle2e768302015-07-28 14:41:11 +0000272 if (obj->GetReferenceTypeInfo().IsValid()) {
273 bound_type->SetReferenceTypeInfo(obj->GetReferenceTypeInfo());
274 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000275 notNullBlock->InsertInstructionBefore(bound_type, insert_point);
276 } else {
277 // We already have a bound type on the position we would need to insert
278 // the new one. The existing bound type should dominate all the users
279 // (dchecked) so there's no need to continue.
280 break;
281 }
Calin Juravleb3306642015-04-20 18:30:42 +0100282 }
Calin Juravle61d544b2015-02-23 16:46:57 +0000283 user->ReplaceInput(bound_type, it.Current()->GetIndex());
284 }
285 }
286}
287
David Brazdild9510df2015-11-04 23:30:22 +0000288// Returns true if one of the patterns below has been recognized. If so, the
289// InstanceOf instruction together with the true branch of `ifInstruction` will
290// be returned using the out parameters.
291// Recognized patterns:
292// (1) patterns equivalent to `if (obj instanceof X)`
293// (a) InstanceOf -> Equal to 1 -> If
294// (b) InstanceOf -> NotEqual to 0 -> If
295// (c) InstanceOf -> If
296// (2) patterns equivalent to `if (!(obj instanceof X))`
297// (a) InstanceOf -> Equal to 0 -> If
298// (b) InstanceOf -> NotEqual to 1 -> If
299// (c) InstanceOf -> BooleanNot -> If
300static bool MatchIfInstanceOf(HIf* ifInstruction,
301 /* out */ HInstanceOf** instanceOf,
302 /* out */ HBasicBlock** trueBranch) {
303 HInstruction* input = ifInstruction->InputAt(0);
304
305 if (input->IsEqual()) {
306 HInstruction* rhs = input->AsEqual()->GetConstantRight();
307 if (rhs != nullptr) {
308 HInstruction* lhs = input->AsEqual()->GetLeastConstantLeft();
309 if (lhs->IsInstanceOf() && rhs->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +0000310 if (rhs->AsIntConstant()->IsTrue()) {
David Brazdild9510df2015-11-04 23:30:22 +0000311 // Case (1a)
312 *trueBranch = ifInstruction->IfTrueSuccessor();
313 } else {
314 // Case (2a)
Roland Levillain1a653882016-03-18 18:05:57 +0000315 DCHECK(rhs->AsIntConstant()->IsFalse()) << rhs->AsIntConstant()->GetValue();
David Brazdild9510df2015-11-04 23:30:22 +0000316 *trueBranch = ifInstruction->IfFalseSuccessor();
317 }
318 *instanceOf = lhs->AsInstanceOf();
319 return true;
320 }
321 }
322 } else if (input->IsNotEqual()) {
323 HInstruction* rhs = input->AsNotEqual()->GetConstantRight();
324 if (rhs != nullptr) {
325 HInstruction* lhs = input->AsNotEqual()->GetLeastConstantLeft();
326 if (lhs->IsInstanceOf() && rhs->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +0000327 if (rhs->AsIntConstant()->IsFalse()) {
David Brazdild9510df2015-11-04 23:30:22 +0000328 // Case (1b)
329 *trueBranch = ifInstruction->IfTrueSuccessor();
330 } else {
331 // Case (2b)
Roland Levillain1a653882016-03-18 18:05:57 +0000332 DCHECK(rhs->AsIntConstant()->IsTrue()) << rhs->AsIntConstant()->GetValue();
David Brazdild9510df2015-11-04 23:30:22 +0000333 *trueBranch = ifInstruction->IfFalseSuccessor();
334 }
335 *instanceOf = lhs->AsInstanceOf();
336 return true;
337 }
338 }
339 } else if (input->IsInstanceOf()) {
340 // Case (1c)
341 *instanceOf = input->AsInstanceOf();
342 *trueBranch = ifInstruction->IfTrueSuccessor();
343 return true;
344 } else if (input->IsBooleanNot()) {
345 HInstruction* not_input = input->InputAt(0);
346 if (not_input->IsInstanceOf()) {
347 // Case (2c)
348 *instanceOf = not_input->AsInstanceOf();
349 *trueBranch = ifInstruction->IfFalseSuccessor();
350 return true;
351 }
352 }
353
354 return false;
355}
356
Calin Juravleb1498f62015-02-16 13:13:29 +0000357// Detects if `block` is the True block for the pattern
358// `if (x instanceof ClassX) { }`
359// If that's the case insert an HBoundType instruction to bound the type of `x`
360// to `ClassX` in the scope of the dominated blocks.
361void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100362 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
363 if (ifInstruction == nullptr) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000364 return;
365 }
David Brazdil0d13fee2015-04-17 14:52:19 +0100366
David Brazdild9510df2015-11-04 23:30:22 +0000367 // Try to recognize common `if (instanceof)` and `if (!instanceof)` patterns.
368 HInstanceOf* instanceOf = nullptr;
369 HBasicBlock* instanceOfTrueBlock = nullptr;
370 if (!MatchIfInstanceOf(ifInstruction, &instanceOf, &instanceOfTrueBlock)) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000371 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000372 }
373
Calin Juravle98893e12015-10-02 21:05:03 +0100374 HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
375 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
376 {
Calin Juravle98893e12015-10-02 21:05:03 +0100377 if (!class_rti.IsValid()) {
378 // He have loaded an unresolved class. Don't bother bounding the type.
379 return;
380 }
381 }
Calin Juravleb3306642015-04-20 18:30:42 +0100382 // We only need to bound the type if we have uses in the relevant block.
383 // So start with null and create the HBoundType lazily, only if it's needed.
384 HBoundType* bound_type = nullptr;
385
Calin Juravleb1498f62015-02-16 13:13:29 +0000386 HInstruction* obj = instanceOf->InputAt(0);
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100387 if (obj->GetReferenceTypeInfo().IsExact() && !obj->IsPhi()) {
388 // This method is being called while doing a fixed-point calculation
389 // over phis. Non-phis instruction whose type is already known do
390 // not need to be bound to another type.
391 // Not that this also prevents replacing `HLoadClass` with a `HBoundType`.
392 // `HCheckCast` and `HInstanceOf` expect a `HLoadClass` as a second
393 // input.
394 return;
395 }
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100396 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
Calin Juravleb1498f62015-02-16 13:13:29 +0000397 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
398 HInstruction* user = it.Current()->GetUser();
399 if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100400 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000401 ScopedObjectAccess soa(Thread::Current());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000402 HInstruction* insert_point = instanceOfTrueBlock->GetFirstInstruction();
403 if (ShouldCreateBoundType(insert_point, obj, class_rti, nullptr, instanceOfTrueBlock)) {
David Brazdilf5552582015-12-27 13:36:12 +0000404 bound_type = new (graph_->GetArena()) HBoundType(obj);
405 bound_type->SetUpperBound(class_rti, /* InstanceOf fails for null. */ false);
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000406 instanceOfTrueBlock->InsertInstructionBefore(bound_type, insert_point);
407 } else {
408 // We already have a bound type on the position we would need to insert
409 // the new one. The existing bound type should dominate all the users
410 // (dchecked) so there's no need to continue.
411 break;
Calin Juravleb3306642015-04-20 18:30:42 +0100412 }
Calin Juravleb3306642015-04-20 18:30:42 +0100413 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000414 user->ReplaceInput(bound_type, it.Current()->GetIndex());
415 }
416 }
Calin Juravleacf735c2015-02-12 15:25:22 +0000417}
418
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000419void ReferenceTypePropagation::RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
420 mirror::Class* klass,
421 bool is_exact) {
Calin Juravle2e768302015-07-28 14:41:11 +0000422 if (instr->IsInvokeStaticOrDirect() && instr->AsInvokeStaticOrDirect()->IsStringInit()) {
423 // Calls to String.<init> are replaced with a StringFactory.
424 if (kIsDebugBuild) {
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000425 HInvoke* invoke = instr->AsInvoke();
Calin Juravle2e768302015-07-28 14:41:11 +0000426 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000427 ScopedObjectAccess soa(Thread::Current());
428 StackHandleScope<2> hs(soa.Self());
429 Handle<mirror::DexCache> dex_cache(
Vladimir Marko456307a2016-04-19 14:12:13 +0000430 hs.NewHandle(FindDexCacheWithHint(soa.Self(), invoke->GetDexFile(), hint_dex_cache_)));
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000431 // Use a null loader. We should probably use the compiling method's class loader,
432 // but then we would need to pass it to RTPVisitor just for this debug check. Since
433 // the method is from the String class, the null loader is good enough.
434 Handle<mirror::ClassLoader> loader;
Andreas Gampe42ef8ab2015-12-03 17:27:32 -0800435 ArtMethod* method = cl->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000436 invoke->GetDexFile(), invoke->GetDexMethodIndex(), dex_cache, loader, nullptr, kDirect);
Calin Juravle2e768302015-07-28 14:41:11 +0000437 DCHECK(method != nullptr);
438 mirror::Class* declaring_class = method->GetDeclaringClass();
439 DCHECK(declaring_class != nullptr);
440 DCHECK(declaring_class->IsStringClass())
441 << "Expected String class: " << PrettyDescriptor(declaring_class);
442 DCHECK(method->IsConstructor())
443 << "Expected String.<init>: " << PrettyMethod(method);
444 }
445 instr->SetReferenceTypeInfo(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000446 ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000447 } else if (klass != nullptr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100448 ScopedObjectAccess soa(Thread::Current());
Aart Bik8b3f9b22016-04-06 11:22:12 -0700449 if (klass->IsErroneous()) {
450 // Set inexact object type for erroneous types.
451 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
452 } else {
453 ReferenceTypeInfo::TypeHandle handle = handle_cache_->NewHandle(klass);
454 is_exact = is_exact || handle->CannotBeAssignedFromOtherTypes();
455 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
456 }
Calin Juravle2e768302015-07-28 14:41:11 +0000457 } else {
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000458 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100459 }
460}
461
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000462void ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
463 uint16_t type_idx,
464 const DexFile& dex_file,
465 bool is_exact) {
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100466 DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
467
Calin Juravleacf735c2015-02-12 15:25:22 +0000468 ScopedObjectAccess soa(Thread::Current());
Vladimir Marko456307a2016-04-19 14:12:13 +0000469 mirror::DexCache* dex_cache = FindDexCacheWithHint(soa.Self(), dex_file, hint_dex_cache_);
Calin Juravleacf735c2015-02-12 15:25:22 +0000470 // Get type from dex cache assuming it was populated by the verifier.
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100471 SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact);
Calin Juravleacf735c2015-02-12 15:25:22 +0000472}
473
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000474void ReferenceTypePropagation::RTPVisitor::VisitNewInstance(HNewInstance* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100475 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100476}
477
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000478void ReferenceTypePropagation::RTPVisitor::VisitNewArray(HNewArray* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100479 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100480}
481
Vladimir Marko456307a2016-04-19 14:12:13 +0000482static mirror::Class* GetClassFromDexCache(Thread* self,
483 const DexFile& dex_file,
484 uint16_t type_idx,
485 Handle<mirror::DexCache> hint_dex_cache)
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000486 SHARED_REQUIRES(Locks::mutator_lock_) {
Vladimir Marko456307a2016-04-19 14:12:13 +0000487 mirror::DexCache* dex_cache = FindDexCacheWithHint(self, dex_file, hint_dex_cache);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000488 // Get type from dex cache assuming it was populated by the verifier.
489 return dex_cache->GetResolvedType(type_idx);
490}
491
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000492void ReferenceTypePropagation::RTPVisitor::VisitParameterValue(HParameterValue* instr) {
Nicolas Geoffraye418dda2015-08-11 20:03:09 -0700493 // We check if the existing type is valid: the inliner may have set it.
494 if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) {
Vladimir Marko456307a2016-04-19 14:12:13 +0000495 ScopedObjectAccess soa(Thread::Current());
496 mirror::Class* resolved_class = GetClassFromDexCache(soa.Self(),
497 instr->GetDexFile(),
498 instr->GetTypeIndex(),
499 hint_dex_cache_);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000500 SetClassAsTypeInfo(instr, resolved_class, /* is_exact */ false);
Calin Juravle2e768302015-07-28 14:41:11 +0000501 }
502}
503
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000504void ReferenceTypePropagation::RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
505 const FieldInfo& info) {
David Brazdild9510df2015-11-04 23:30:22 +0000506 if (instr->GetType() != Primitive::kPrimNot) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100507 return;
508 }
509
David Brazdild9510df2015-11-04 23:30:22 +0000510 mirror::Class* klass = nullptr;
511
512 // The field index is unknown only during tests.
513 if (info.GetFieldIndex() != kUnknownFieldIndex) {
Vladimir Marko456307a2016-04-19 14:12:13 +0000514 ScopedObjectAccess soa(Thread::Current());
David Brazdild9510df2015-11-04 23:30:22 +0000515 ClassLinker* cl = Runtime::Current()->GetClassLinker();
516 ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), info.GetDexCache().Get());
517 // TODO: There are certain cases where we can't resolve the field.
518 // b/21914925 is open to keep track of a repro case for this issue.
519 if (field != nullptr) {
520 klass = field->GetType<false>();
521 }
522 }
523
Calin Juravle2e768302015-07-28 14:41:11 +0000524 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100525}
526
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000527void ReferenceTypePropagation::RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100528 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
529}
530
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000531void ReferenceTypePropagation::RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100532 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
533}
534
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000535void ReferenceTypePropagation::RTPVisitor::VisitUnresolvedInstanceFieldGet(
536 HUnresolvedInstanceFieldGet* instr) {
Calin Juravlee460d1d2015-09-29 04:52:17 +0100537 // TODO: Use descriptor to get the actual type.
538 if (instr->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000539 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Calin Juravlee460d1d2015-09-29 04:52:17 +0100540 }
541}
542
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000543void ReferenceTypePropagation::RTPVisitor::VisitUnresolvedStaticFieldGet(
544 HUnresolvedStaticFieldGet* instr) {
Calin Juravlee460d1d2015-09-29 04:52:17 +0100545 // TODO: Use descriptor to get the actual type.
546 if (instr->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000547 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Calin Juravlee460d1d2015-09-29 04:52:17 +0100548 }
549}
550
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000551void ReferenceTypePropagation::RTPVisitor::VisitLoadClass(HLoadClass* instr) {
Calin Juravleacf735c2015-02-12 15:25:22 +0000552 ScopedObjectAccess soa(Thread::Current());
Calin Juravleacf735c2015-02-12 15:25:22 +0000553 // Get type from dex cache assuming it was populated by the verifier.
Vladimir Marko456307a2016-04-19 14:12:13 +0000554 mirror::Class* resolved_class = GetClassFromDexCache(soa.Self(),
555 instr->GetDexFile(),
556 instr->GetTypeIndex(),
557 hint_dex_cache_);
Aart Bik8b3f9b22016-04-06 11:22:12 -0700558 if (resolved_class != nullptr && !resolved_class->IsErroneous()) {
Calin Juravle98893e12015-10-02 21:05:03 +0100559 instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000560 handle_cache_->NewHandle(resolved_class), /* is_exact */ true));
Calin Juravle98893e12015-10-02 21:05:03 +0100561 }
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000562 instr->SetReferenceTypeInfo(
563 ReferenceTypeInfo::Create(handle_cache_->GetClassClassHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000564}
565
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000566void ReferenceTypePropagation::RTPVisitor::VisitClinitCheck(HClinitCheck* instr) {
Calin Juravle2e768302015-07-28 14:41:11 +0000567 instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
568}
569
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000570void ReferenceTypePropagation::RTPVisitor::VisitLoadString(HLoadString* instr) {
571 instr->SetReferenceTypeInfo(
572 ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000573}
574
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000575void ReferenceTypePropagation::RTPVisitor::VisitLoadException(HLoadException* instr) {
David Brazdilbbd733e2015-08-18 17:48:17 +0100576 DCHECK(instr->GetBlock()->IsCatchBlock());
577 TryCatchInformation* catch_info = instr->GetBlock()->GetTryCatchInformation();
578
579 if (catch_info->IsCatchAllTypeIndex()) {
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000580 instr->SetReferenceTypeInfo(
581 ReferenceTypeInfo::Create(handle_cache_->GetThrowableClassHandle(), /* is_exact */ false));
David Brazdilbbd733e2015-08-18 17:48:17 +0100582 } else {
583 UpdateReferenceTypeInfo(instr,
584 catch_info->GetCatchTypeIndex(),
585 catch_info->GetCatchDexFile(),
586 /* is_exact */ false);
587 }
588}
589
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000590void ReferenceTypePropagation::RTPVisitor::VisitNullCheck(HNullCheck* instr) {
Calin Juravle2e768302015-07-28 14:41:11 +0000591 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
David Brazdilfe860702015-12-02 09:06:57 +0000592 if (parent_rti.IsValid()) {
593 instr->SetReferenceTypeInfo(parent_rti);
594 }
Calin Juravle2e768302015-07-28 14:41:11 +0000595}
596
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000597void ReferenceTypePropagation::RTPVisitor::VisitBoundType(HBoundType* instr) {
David Brazdilf5552582015-12-27 13:36:12 +0000598 ReferenceTypeInfo class_rti = instr->GetUpperBound();
599 if (class_rti.IsValid()) {
Vladimir Marko456307a2016-04-19 14:12:13 +0000600 ScopedObjectAccess soa(Thread::Current());
David Brazdilf5552582015-12-27 13:36:12 +0000601 // Narrow the type as much as possible.
602 HInstruction* obj = instr->InputAt(0);
603 ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo();
604 if (class_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes()) {
605 instr->SetReferenceTypeInfo(
606 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ true));
David Brazdil744a1c62015-12-28 10:53:34 +0000607 } else if (obj_rti.IsValid()) {
608 if (class_rti.IsSupertypeOf(obj_rti)) {
609 // Object type is more specific.
610 instr->SetReferenceTypeInfo(obj_rti);
611 } else {
612 // Upper bound is more specific.
613 instr->SetReferenceTypeInfo(
614 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
615 }
David Brazdilf5552582015-12-27 13:36:12 +0000616 } else {
David Brazdil744a1c62015-12-28 10:53:34 +0000617 // Object not typed yet. Leave BoundType untyped for now rather than
618 // assign the type conservatively.
David Brazdilf5552582015-12-27 13:36:12 +0000619 }
620 instr->SetCanBeNull(obj->CanBeNull() && instr->GetUpperCanBeNull());
621 } else {
622 // The owner of the BoundType was already visited. If the class is unresolved,
623 // the BoundType should have been removed from the data flow and this method
624 // should remove it from the graph.
625 DCHECK(!instr->HasUses());
626 instr->GetBlock()->RemoveInstruction(instr);
627 }
628}
629
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000630void ReferenceTypePropagation::RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
Calin Juravle98893e12015-10-02 21:05:03 +0100631 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
632 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
David Brazdilf5552582015-12-27 13:36:12 +0000633 HBoundType* bound_type = check_cast->GetNext()->AsBoundType();
634 if (bound_type == nullptr || bound_type->GetUpperBound().IsValid()) {
635 // The next instruction is not an uninitialized BoundType. This must be
636 // an RTP pass after SsaBuilder and we do not need to do anything.
637 return;
Calin Juravle98893e12015-10-02 21:05:03 +0100638 }
David Brazdilf5552582015-12-27 13:36:12 +0000639 DCHECK_EQ(bound_type->InputAt(0), check_cast->InputAt(0));
640
641 if (class_rti.IsValid()) {
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000642 DCHECK(is_first_run_);
David Brazdilf5552582015-12-27 13:36:12 +0000643 // This is the first run of RTP and class is resolved.
644 bound_type->SetUpperBound(class_rti, /* CheckCast succeeds for nulls. */ true);
645 } else {
646 // This is the first run of RTP and class is unresolved. Remove the binding.
647 // The instruction itself is removed in VisitBoundType so as to not
648 // invalidate HInstructionIterator.
649 bound_type->ReplaceWith(bound_type->InputAt(0));
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000650 }
651}
652
Calin Juravleb1498f62015-02-16 13:13:29 +0000653void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
David Brazdild9510df2015-11-04 23:30:22 +0000654 if (phi->IsDead() || phi->GetType() != Primitive::kPrimNot) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000655 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000656 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000657
658 if (phi->GetBlock()->IsLoopHeader()) {
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000659 if (!is_first_run_ && graph_->IsCompilingOsr()) {
660 // Don't update the type of a loop phi when compiling OSR: we may have done
661 // speculative optimizations dominating that phi, that do not hold at the
662 // point the interpreter jumps to that loop header.
663 return;
664 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000665 // Set the initial type for the phi. Use the non back edge input for reaching
666 // a fixed point faster.
David Brazdilfe860702015-12-02 09:06:57 +0000667 HInstruction* first_input = phi->InputAt(0);
668 ReferenceTypeInfo first_input_rti = first_input->GetReferenceTypeInfo();
669 if (first_input_rti.IsValid() && !first_input->IsNullConstant()) {
670 phi->SetCanBeNull(first_input->CanBeNull());
671 phi->SetReferenceTypeInfo(first_input_rti);
672 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000673 AddToWorklist(phi);
Calin Juravle10e244f2015-01-26 18:54:32 +0000674 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000675 // Eagerly compute the type of the phi, for quicker convergence. Note
676 // that we don't need to add users to the worklist because we are
677 // doing a reverse post-order visit, therefore either the phi users are
678 // non-loop phi and will be visited later in the visit, or are loop-phis,
679 // and they are already in the work list.
680 UpdateNullability(phi);
681 UpdateReferenceTypeInfo(phi);
682 }
683}
684
685ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
686 const ReferenceTypeInfo& b) {
Calin Juravle2e768302015-07-28 14:41:11 +0000687 if (!b.IsValid()) {
688 return a;
689 }
690 if (!a.IsValid()) {
691 return b;
Calin Juravle20e60712015-07-01 18:41:04 +0100692 }
693
Calin Juravle2e768302015-07-28 14:41:11 +0000694 bool is_exact = a.IsExact() && b.IsExact();
Calin Juravle52503d82015-11-11 16:58:31 +0000695 ReferenceTypeInfo::TypeHandle result_type_handle;
696 ReferenceTypeInfo::TypeHandle a_type_handle = a.GetTypeHandle();
697 ReferenceTypeInfo::TypeHandle b_type_handle = b.GetTypeHandle();
698 bool a_is_interface = a_type_handle->IsInterface();
699 bool b_is_interface = b_type_handle->IsInterface();
Calin Juravle2e768302015-07-28 14:41:11 +0000700
701 if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
Calin Juravle52503d82015-11-11 16:58:31 +0000702 result_type_handle = a_type_handle;
Calin Juravle2e768302015-07-28 14:41:11 +0000703 } else if (a.IsSupertypeOf(b)) {
Calin Juravle52503d82015-11-11 16:58:31 +0000704 result_type_handle = a_type_handle;
Calin Juravle2e768302015-07-28 14:41:11 +0000705 is_exact = false;
706 } else if (b.IsSupertypeOf(a)) {
Calin Juravle52503d82015-11-11 16:58:31 +0000707 result_type_handle = b_type_handle;
708 is_exact = false;
709 } else if (!a_is_interface && !b_is_interface) {
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000710 result_type_handle =
711 handle_cache_.NewHandle(a_type_handle->GetCommonSuperClass(b_type_handle));
Calin Juravle2e768302015-07-28 14:41:11 +0000712 is_exact = false;
713 } else {
Calin Juravle52503d82015-11-11 16:58:31 +0000714 // This can happen if:
715 // - both types are interfaces. TODO(calin): implement
716 // - one is an interface, the other a class, and the type does not implement the interface
717 // e.g:
718 // void foo(Interface i, boolean cond) {
719 // Object o = cond ? i : new Object();
720 // }
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000721 result_type_handle = handle_cache_.GetObjectClassHandle();
Calin Juravle2e768302015-07-28 14:41:11 +0000722 is_exact = false;
723 }
724
Calin Juravle52503d82015-11-11 16:58:31 +0000725 return ReferenceTypeInfo::Create(result_type_handle, is_exact);
Calin Juravle2e768302015-07-28 14:41:11 +0000726}
727
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000728void ReferenceTypePropagation::UpdateArrayGet(HArrayGet* instr, HandleCache* handle_cache) {
Calin Juravle2e768302015-07-28 14:41:11 +0000729 DCHECK_EQ(Primitive::kPrimNot, instr->GetType());
730
731 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
David Brazdilfe860702015-12-02 09:06:57 +0000732 if (!parent_rti.IsValid()) {
733 return;
734 }
Calin Juravle2e768302015-07-28 14:41:11 +0000735
736 Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
Aart Bik8b3f9b22016-04-06 11:22:12 -0700737 if (handle->IsObjectArrayClass() && !handle->GetComponentType()->IsErroneous()) {
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000738 ReferenceTypeInfo::TypeHandle component_handle =
739 handle_cache->NewHandle(handle->GetComponentType());
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000740 bool is_exact = component_handle->CannotBeAssignedFromOtherTypes();
741 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(component_handle, is_exact));
Calin Juravle2e768302015-07-28 14:41:11 +0000742 } else {
743 // We don't know what the parent actually is, so we fallback to object.
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000744 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Calin Juravle2e768302015-07-28 14:41:11 +0000745 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000746}
747
748bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
749 ScopedObjectAccess soa(Thread::Current());
750
751 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
752 if (instr->IsBoundType()) {
753 UpdateBoundType(instr->AsBoundType());
754 } else if (instr->IsPhi()) {
755 UpdatePhi(instr->AsPhi());
Calin Juravle2e768302015-07-28 14:41:11 +0000756 } else if (instr->IsNullCheck()) {
757 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
758 if (parent_rti.IsValid()) {
759 instr->SetReferenceTypeInfo(parent_rti);
760 }
761 } else if (instr->IsArrayGet()) {
David Brazdilfe860702015-12-02 09:06:57 +0000762 // TODO: consider if it's worth "looking back" and binding the input object
Calin Juravle2e768302015-07-28 14:41:11 +0000763 // to an array type.
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000764 UpdateArrayGet(instr->AsArrayGet(), &handle_cache_);
Calin Juravleb1498f62015-02-16 13:13:29 +0000765 } else {
766 LOG(FATAL) << "Invalid instruction (should not get here)";
767 }
768
769 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
770}
771
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000772void ReferenceTypePropagation::RTPVisitor::VisitInvoke(HInvoke* instr) {
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100773 if (instr->GetType() != Primitive::kPrimNot) {
774 return;
775 }
776
777 ScopedObjectAccess soa(Thread::Current());
778 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Vladimir Marko456307a2016-04-19 14:12:13 +0000779 mirror::DexCache* dex_cache =
780 FindDexCacheWithHint(soa.Self(), instr->GetDexFile(), hint_dex_cache_);
Vladimir Marko05792b92015-08-03 11:56:49 +0100781 size_t pointer_size = cl->GetImagePointerSize();
782 ArtMethod* method = dex_cache->GetResolvedMethod(instr->GetDexMethodIndex(), pointer_size);
783 mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false, pointer_size);
Calin Juravle2e768302015-07-28 14:41:11 +0000784 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100785}
786
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000787void ReferenceTypePropagation::RTPVisitor::VisitArrayGet(HArrayGet* instr) {
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100788 if (instr->GetType() != Primitive::kPrimNot) {
789 return;
790 }
David Brazdilfe860702015-12-02 09:06:57 +0000791
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100792 ScopedObjectAccess soa(Thread::Current());
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000793 UpdateArrayGet(instr, handle_cache_);
Calin Juravle2e768302015-07-28 14:41:11 +0000794 if (!instr->GetReferenceTypeInfo().IsValid()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100795 worklist_->push_back(instr);
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100796 }
797}
798
Calin Juravleb1498f62015-02-16 13:13:29 +0000799void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
800 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle2e768302015-07-28 14:41:11 +0000801 if (!new_rti.IsValid()) {
802 return; // No new info yet.
803 }
804
805 // Make sure that we don't go over the bounded type.
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000806 ReferenceTypeInfo upper_bound_rti = instr->GetUpperBound();
807 if (!upper_bound_rti.IsSupertypeOf(new_rti)) {
808 new_rti = upper_bound_rti;
Calin Juravleb1498f62015-02-16 13:13:29 +0000809 }
810 instr->SetReferenceTypeInfo(new_rti);
811}
812
Calin Juravle617bd922015-11-11 14:59:46 +0000813// NullConstant inputs are ignored during merging as they do not provide any useful information.
814// If all the inputs are NullConstants then the type of the phi will be set to Object.
Calin Juravleb1498f62015-02-16 13:13:29 +0000815void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
David Brazdild9510df2015-11-04 23:30:22 +0000816 DCHECK(instr->IsLive());
817
Calin Juravle617bd922015-11-11 14:59:46 +0000818 size_t input_count = instr->InputCount();
819 size_t first_input_index_not_null = 0;
820 while (first_input_index_not_null < input_count &&
821 instr->InputAt(first_input_index_not_null)->IsNullConstant()) {
822 first_input_index_not_null++;
823 }
824 if (first_input_index_not_null == input_count) {
825 // All inputs are NullConstants, set the type to object.
826 // This may happen in the presence of inlining.
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000827 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Calin Juravle617bd922015-11-11 14:59:46 +0000828 return;
829 }
830
831 ReferenceTypeInfo new_rti = instr->InputAt(first_input_index_not_null)->GetReferenceTypeInfo();
832
Calin Juravle2e768302015-07-28 14:41:11 +0000833 if (new_rti.IsValid() && new_rti.IsObjectClass() && !new_rti.IsExact()) {
834 // Early return if we are Object and inexact.
Calin Juravleb1498f62015-02-16 13:13:29 +0000835 instr->SetReferenceTypeInfo(new_rti);
836 return;
837 }
Calin Juravle617bd922015-11-11 14:59:46 +0000838
839 for (size_t i = first_input_index_not_null + 1; i < input_count; i++) {
840 if (instr->InputAt(i)->IsNullConstant()) {
841 continue;
842 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000843 new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo());
Calin Juravle2e768302015-07-28 14:41:11 +0000844 if (new_rti.IsValid() && new_rti.IsObjectClass()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000845 if (!new_rti.IsExact()) {
846 break;
847 } else {
848 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000849 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000850 }
851 }
David Brazdilfe860702015-12-02 09:06:57 +0000852
853 if (new_rti.IsValid()) {
854 instr->SetReferenceTypeInfo(new_rti);
855 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000856}
857
858// Re-computes and updates the nullability of the instruction. Returns whether or
859// not the nullability was changed.
860bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
David Brazdild9510df2015-11-04 23:30:22 +0000861 DCHECK((instr->IsPhi() && instr->AsPhi()->IsLive())
Calin Juravle2e768302015-07-28 14:41:11 +0000862 || instr->IsBoundType()
863 || instr->IsNullCheck()
864 || instr->IsArrayGet());
865
866 if (!instr->IsPhi() && !instr->IsBoundType()) {
867 return false;
868 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000869
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000870 bool existing_can_be_null = instr->CanBeNull();
871 if (instr->IsPhi()) {
872 HPhi* phi = instr->AsPhi();
873 bool new_can_be_null = false;
874 for (size_t i = 0; i < phi->InputCount(); i++) {
875 if (phi->InputAt(i)->CanBeNull()) {
876 new_can_be_null = true;
877 break;
878 }
879 }
880 phi->SetCanBeNull(new_can_be_null);
881 } else if (instr->IsBoundType()) {
882 HBoundType* bound_type = instr->AsBoundType();
883 bound_type->SetCanBeNull(instr->InputAt(0)->CanBeNull() && bound_type->GetUpperCanBeNull());
Calin Juravleb1498f62015-02-16 13:13:29 +0000884 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000885 return existing_can_be_null != instr->CanBeNull();
Calin Juravle10e244f2015-01-26 18:54:32 +0000886}
887
888void ReferenceTypePropagation::ProcessWorklist() {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100889 while (!worklist_.empty()) {
890 HInstruction* instruction = worklist_.back();
891 worklist_.pop_back();
Calin Juravle12617592015-10-16 16:28:46 +0100892 bool updated_nullability = UpdateNullability(instruction);
893 bool updated_reference_type = UpdateReferenceTypeInfo(instruction);
894 if (updated_nullability || updated_reference_type) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000895 AddDependentInstructionsToWorklist(instruction);
896 }
897 }
898}
899
Calin Juravleb1498f62015-02-16 13:13:29 +0000900void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
Calin Juravle2e768302015-07-28 14:41:11 +0000901 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot)
902 << instruction->DebugName() << ":" << instruction->GetType();
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100903 worklist_.push_back(instruction);
Calin Juravle10e244f2015-01-26 18:54:32 +0000904}
905
Calin Juravleb1498f62015-02-16 13:13:29 +0000906void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000907 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000908 HInstruction* user = it.Current()->GetUser();
David Brazdild9510df2015-11-04 23:30:22 +0000909 if ((user->IsPhi() && user->AsPhi()->IsLive())
Calin Juravle2e768302015-07-28 14:41:11 +0000910 || user->IsBoundType()
911 || user->IsNullCheck()
912 || (user->IsArrayGet() && (user->GetType() == Primitive::kPrimNot))) {
Calin Juravlebeba9302015-07-08 15:57:18 +0000913 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000914 }
915 }
916}
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000917
Calin Juravle10e244f2015-01-26 18:54:32 +0000918} // namespace art