blob: b16c3eaac7167617f4ff78e2dc6e65049dbfd673 [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
Andreas Gampe542451c2016-07-26 09:02:02 -070019#include "base/enums.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070020#include "class_linker-inl.h"
Calin Juravleacf735c2015-02-12 15:25:22 +000021#include "mirror/class-inl.h"
22#include "mirror/dex_cache.h"
Mathieu Chartier0795f232016-09-27 18:43:30 -070023#include "scoped_thread_state_change-inl.h"
Calin Juravleacf735c2015-02-12 15:25:22 +000024
Calin Juravle10e244f2015-01-26 18:54:32 +000025namespace art {
26
Vladimir Marko456307a2016-04-19 14:12:13 +000027static inline mirror::DexCache* FindDexCacheWithHint(Thread* self,
28 const DexFile& dex_file,
29 Handle<mirror::DexCache> hint_dex_cache)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -070030 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko456307a2016-04-19 14:12:13 +000031 if (LIKELY(hint_dex_cache->GetDexFile() == &dex_file)) {
32 return hint_dex_cache.Get();
33 } else {
34 return Runtime::Current()->GetClassLinker()->FindDexCache(self, dex_file);
35 }
36}
37
Mathieu Chartiere8a3c572016-10-11 16:52:17 -070038static inline ReferenceTypeInfo::TypeHandle GetRootHandle(VariableSizedHandleScope* handles,
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000039 ClassLinker::ClassRoot class_root,
40 ReferenceTypeInfo::TypeHandle* cache) {
41 if (!ReferenceTypeInfo::IsValidHandle(*cache)) {
42 // Mutator lock is required for NewHandle.
43 ClassLinker* linker = Runtime::Current()->GetClassLinker();
44 ScopedObjectAccess soa(Thread::Current());
45 *cache = handles->NewHandle(linker->GetClassRoot(class_root));
46 }
47 return *cache;
48}
49
50ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetObjectClassHandle() {
51 return GetRootHandle(handles_, ClassLinker::kJavaLangObject, &object_class_handle_);
52}
53
54ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetClassClassHandle() {
55 return GetRootHandle(handles_, ClassLinker::kJavaLangClass, &class_class_handle_);
56}
57
58ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetStringClassHandle() {
59 return GetRootHandle(handles_, ClassLinker::kJavaLangString, &string_class_handle_);
60}
61
62ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetThrowableClassHandle() {
63 return GetRootHandle(handles_, ClassLinker::kJavaLangThrowable, &throwable_class_handle_);
64}
65
66class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor {
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010067 public:
Calin Juravle2e768302015-07-28 14:41:11 +000068 RTPVisitor(HGraph* graph,
Vladimir Marko456307a2016-04-19 14:12:13 +000069 Handle<mirror::DexCache> hint_dex_cache,
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000070 HandleCache* handle_cache,
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +000071 ArenaVector<HInstruction*>* worklist,
72 bool is_first_run)
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010073 : HGraphDelegateVisitor(graph),
Vladimir Marko456307a2016-04-19 14:12:13 +000074 hint_dex_cache_(hint_dex_cache),
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000075 handle_cache_(handle_cache),
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +000076 worklist_(worklist),
77 is_first_run_(is_first_run) {}
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010078
79 void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
80 void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000081 void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE;
82 void VisitLoadString(HLoadString* instr) OVERRIDE;
David Brazdilbbd733e2015-08-18 17:48:17 +010083 void VisitLoadException(HLoadException* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010084 void VisitNewArray(HNewArray* instr) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000085 void VisitParameterValue(HParameterValue* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010086 void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
Mathieu Chartier3398c782016-09-30 10:27:43 -070087 void SetClassAsTypeInfo(HInstruction* instr, ObjPtr<mirror::Class> klass, bool is_exact)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -070088 REQUIRES_SHARED(Locks::mutator_lock_);
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010089 void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE;
90 void VisitStaticFieldGet(HStaticFieldGet* instr) OVERRIDE;
Calin Juravlee460d1d2015-09-29 04:52:17 +010091 void VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instr) OVERRIDE;
92 void VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010093 void VisitInvoke(HInvoke* instr) OVERRIDE;
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +010094 void VisitArrayGet(HArrayGet* instr) OVERRIDE;
Calin Juravlea5ae3c32015-07-28 14:40:50 +000095 void VisitCheckCast(HCheckCast* instr) OVERRIDE;
David Brazdilf5552582015-12-27 13:36:12 +000096 void VisitBoundType(HBoundType* instr) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000097 void VisitNullCheck(HNullCheck* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010098 void UpdateReferenceTypeInfo(HInstruction* instr,
99 uint16_t type_idx,
100 const DexFile& dex_file,
101 bool is_exact);
102
103 private:
Vladimir Marko456307a2016-04-19 14:12:13 +0000104 Handle<mirror::DexCache> hint_dex_cache_;
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000105 HandleCache* handle_cache_;
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100106 ArenaVector<HInstruction*>* worklist_;
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000107 const bool is_first_run_;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100108};
109
Calin Juravle2e768302015-07-28 14:41:11 +0000110ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph,
Vladimir Marko456307a2016-04-19 14:12:13 +0000111 Handle<mirror::DexCache> hint_dex_cache,
Mathieu Chartiere8a3c572016-10-11 16:52:17 -0700112 VariableSizedHandleScope* handles,
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000113 bool is_first_run,
Calin Juravle2e768302015-07-28 14:41:11 +0000114 const char* name)
115 : HOptimization(graph, name),
Vladimir Marko456307a2016-04-19 14:12:13 +0000116 hint_dex_cache_(hint_dex_cache),
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000117 handle_cache_(handles),
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000118 worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)),
119 is_first_run_(is_first_run) {
Calin Juravle2e768302015-07-28 14:41:11 +0000120}
121
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000122void ReferenceTypePropagation::ValidateTypes() {
123 // TODO: move this to the graph checker.
Calin Juravle2e768302015-07-28 14:41:11 +0000124 if (kIsDebugBuild) {
Calin Juravle2e768302015-07-28 14:41:11 +0000125 ScopedObjectAccess soa(Thread::Current());
126 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
127 HBasicBlock* block = it.Current();
128 for (HInstructionIterator iti(block->GetInstructions()); !iti.Done(); iti.Advance()) {
129 HInstruction* instr = iti.Current();
130 if (instr->GetType() == Primitive::kPrimNot) {
131 DCHECK(instr->GetReferenceTypeInfo().IsValid())
132 << "Invalid RTI for instruction: " << instr->DebugName();
133 if (instr->IsBoundType()) {
134 DCHECK(instr->AsBoundType()->GetUpperBound().IsValid());
135 } else if (instr->IsLoadClass()) {
Calin Juravle98893e12015-10-02 21:05:03 +0100136 HLoadClass* cls = instr->AsLoadClass();
137 DCHECK(cls->GetReferenceTypeInfo().IsExact());
138 DCHECK(!cls->GetLoadedClassRTI().IsValid() || cls->GetLoadedClassRTI().IsExact());
Calin Juravle2e768302015-07-28 14:41:11 +0000139 } else if (instr->IsNullCheck()) {
140 DCHECK(instr->GetReferenceTypeInfo().IsEqual(instr->InputAt(0)->GetReferenceTypeInfo()))
141 << "NullCheck " << instr->GetReferenceTypeInfo()
142 << "Input(0) " << instr->InputAt(0)->GetReferenceTypeInfo();
143 }
144 }
145 }
146 }
147 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000148}
149
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000150void ReferenceTypePropagation::Visit(HInstruction* instruction) {
Vladimir Marko456307a2016-04-19 14:12:13 +0000151 RTPVisitor visitor(graph_, hint_dex_cache_, &handle_cache_, &worklist_, is_first_run_);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000152 instruction->Accept(&visitor);
153}
154
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000155void ReferenceTypePropagation::Run() {
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000156 worklist_.reserve(kDefaultWorklistSize);
157
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000158 // To properly propagate type info we need to visit in the dominator-based order.
159 // Reverse post order guarantees a node's dominators are visited first.
160 // We take advantage of this order in `VisitBasicBlock`.
161 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
162 VisitBasicBlock(it.Current());
163 }
164
165 ProcessWorklist();
166 ValidateTypes();
167}
168
Calin Juravleb1498f62015-02-16 13:13:29 +0000169void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
Vladimir Marko456307a2016-04-19 14:12:13 +0000170 RTPVisitor visitor(graph_, hint_dex_cache_, &handle_cache_, &worklist_, is_first_run_);
Calin Juravle2e768302015-07-28 14:41:11 +0000171 // Handle Phis first as there might be instructions in the same block who depend on them.
172 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
173 VisitPhi(it.Current()->AsPhi());
174 }
Calin Juravlebeba9302015-07-08 15:57:18 +0000175
Calin Juravle2e768302015-07-28 14:41:11 +0000176 // Handle instructions.
Calin Juravleb1498f62015-02-16 13:13:29 +0000177 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
178 HInstruction* instr = it.Current();
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100179 instr->Accept(&visitor);
Calin Juravleb1498f62015-02-16 13:13:29 +0000180 }
181
Calin Juravleb1498f62015-02-16 13:13:29 +0000182 // Add extra nodes to bound types.
Calin Juravle61d544b2015-02-23 16:46:57 +0000183 BoundTypeForIfNotNull(block);
Calin Juravleb1498f62015-02-16 13:13:29 +0000184 BoundTypeForIfInstanceOf(block);
Calin Juravle10e244f2015-01-26 18:54:32 +0000185}
186
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000187// Check if we should create a bound type for the given object at the specified
188// position. Because of inlining and the fact we run RTP more than once and we
189// might have a HBoundType already. If we do, we should not create a new one.
190// In this case we also assert that there are no other uses of the object (except
191// the bound type) dominated by the specified dominator_instr or dominator_block.
192static bool ShouldCreateBoundType(HInstruction* position,
193 HInstruction* obj,
194 ReferenceTypeInfo upper_bound,
195 HInstruction* dominator_instr,
196 HBasicBlock* dominator_block)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700197 REQUIRES_SHARED(Locks::mutator_lock_) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000198 // If the position where we should insert the bound type is not already a
199 // a bound type then we need to create one.
200 if (position == nullptr || !position->IsBoundType()) {
201 return true;
202 }
203
204 HBoundType* existing_bound_type = position->AsBoundType();
205 if (existing_bound_type->GetUpperBound().IsSupertypeOf(upper_bound)) {
206 if (kIsDebugBuild) {
207 // Check that the existing HBoundType dominates all the uses.
Vladimir Marko46817b82016-03-29 12:21:58 +0100208 for (const HUseListNode<HInstruction*>& use : obj->GetUses()) {
209 HInstruction* user = use.GetUser();
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000210 if (dominator_instr != nullptr) {
211 DCHECK(!dominator_instr->StrictlyDominates(user)
212 || user == existing_bound_type
213 || existing_bound_type->StrictlyDominates(user));
214 } else if (dominator_block != nullptr) {
215 DCHECK(!dominator_block->Dominates(user->GetBlock())
216 || user == existing_bound_type
217 || existing_bound_type->StrictlyDominates(user));
218 }
219 }
220 }
221 } else {
222 // TODO: if the current bound type is a refinement we could update the
223 // existing_bound_type with the a new upper limit. However, we also need to
224 // update its users and have access to the work list.
225 }
226 return false;
227}
228
Calin Juravle61d544b2015-02-23 16:46:57 +0000229void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100230 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
231 if (ifInstruction == nullptr) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000232 return;
233 }
Calin Juravleb3306642015-04-20 18:30:42 +0100234 HInstruction* ifInput = ifInstruction->InputAt(0);
Calin Juravle61d544b2015-02-23 16:46:57 +0000235 if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) {
236 return;
237 }
238 HInstruction* input0 = ifInput->InputAt(0);
239 HInstruction* input1 = ifInput->InputAt(1);
Calin Juravleedad8ad2015-04-23 14:34:33 +0100240 HInstruction* obj = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000241
Calin Juravleedad8ad2015-04-23 14:34:33 +0100242 if (input1->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000243 obj = input0;
Calin Juravleedad8ad2015-04-23 14:34:33 +0100244 } else if (input0->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000245 obj = input1;
246 } else {
247 return;
248 }
249
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100250 if (!obj->CanBeNull() || obj->IsNullConstant()) {
251 // Null check is dead code and will be removed by DCE.
252 return;
253 }
254 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
255
Calin Juravleb3306642015-04-20 18:30:42 +0100256 // We only need to bound the type if we have uses in the relevant block.
257 // So start with null and create the HBoundType lazily, only if it's needed.
258 HBoundType* bound_type = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000259 HBasicBlock* notNullBlock = ifInput->IsNotEqual()
Calin Juravleb3306642015-04-20 18:30:42 +0100260 ? ifInstruction->IfTrueSuccessor()
261 : ifInstruction->IfFalseSuccessor();
262
Vladimir Marko46817b82016-03-29 12:21:58 +0100263 const HUseList<HInstruction*>& uses = obj->GetUses();
264 for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
265 HInstruction* user = it->GetUser();
266 size_t index = it->GetIndex();
267 // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput().
268 ++it;
Calin Juravle61d544b2015-02-23 16:46:57 +0000269 if (notNullBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100270 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000271 ScopedObjectAccess soa(Thread::Current());
272 HInstruction* insert_point = notNullBlock->GetFirstInstruction();
Calin Juravle2e768302015-07-28 14:41:11 +0000273 ReferenceTypeInfo object_rti = ReferenceTypeInfo::Create(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000274 handle_cache_.GetObjectClassHandle(), /* is_exact */ true);
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000275 if (ShouldCreateBoundType(insert_point, obj, object_rti, nullptr, notNullBlock)) {
David Brazdilf5552582015-12-27 13:36:12 +0000276 bound_type = new (graph_->GetArena()) HBoundType(obj);
277 bound_type->SetUpperBound(object_rti, /* bound_can_be_null */ false);
Calin Juravle2e768302015-07-28 14:41:11 +0000278 if (obj->GetReferenceTypeInfo().IsValid()) {
279 bound_type->SetReferenceTypeInfo(obj->GetReferenceTypeInfo());
280 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000281 notNullBlock->InsertInstructionBefore(bound_type, insert_point);
282 } else {
283 // We already have a bound type on the position we would need to insert
284 // the new one. The existing bound type should dominate all the users
285 // (dchecked) so there's no need to continue.
286 break;
287 }
Calin Juravleb3306642015-04-20 18:30:42 +0100288 }
Vladimir Marko46817b82016-03-29 12:21:58 +0100289 user->ReplaceInput(bound_type, index);
Calin Juravle61d544b2015-02-23 16:46:57 +0000290 }
291 }
292}
293
David Brazdild9510df2015-11-04 23:30:22 +0000294// Returns true if one of the patterns below has been recognized. If so, the
295// InstanceOf instruction together with the true branch of `ifInstruction` will
296// be returned using the out parameters.
297// Recognized patterns:
298// (1) patterns equivalent to `if (obj instanceof X)`
299// (a) InstanceOf -> Equal to 1 -> If
300// (b) InstanceOf -> NotEqual to 0 -> If
301// (c) InstanceOf -> If
302// (2) patterns equivalent to `if (!(obj instanceof X))`
303// (a) InstanceOf -> Equal to 0 -> If
304// (b) InstanceOf -> NotEqual to 1 -> If
305// (c) InstanceOf -> BooleanNot -> If
306static bool MatchIfInstanceOf(HIf* ifInstruction,
307 /* out */ HInstanceOf** instanceOf,
308 /* out */ HBasicBlock** trueBranch) {
309 HInstruction* input = ifInstruction->InputAt(0);
310
311 if (input->IsEqual()) {
312 HInstruction* rhs = input->AsEqual()->GetConstantRight();
313 if (rhs != nullptr) {
314 HInstruction* lhs = input->AsEqual()->GetLeastConstantLeft();
315 if (lhs->IsInstanceOf() && rhs->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +0000316 if (rhs->AsIntConstant()->IsTrue()) {
David Brazdild9510df2015-11-04 23:30:22 +0000317 // Case (1a)
318 *trueBranch = ifInstruction->IfTrueSuccessor();
319 } else {
320 // Case (2a)
Roland Levillain1a653882016-03-18 18:05:57 +0000321 DCHECK(rhs->AsIntConstant()->IsFalse()) << rhs->AsIntConstant()->GetValue();
David Brazdild9510df2015-11-04 23:30:22 +0000322 *trueBranch = ifInstruction->IfFalseSuccessor();
323 }
324 *instanceOf = lhs->AsInstanceOf();
325 return true;
326 }
327 }
328 } else if (input->IsNotEqual()) {
329 HInstruction* rhs = input->AsNotEqual()->GetConstantRight();
330 if (rhs != nullptr) {
331 HInstruction* lhs = input->AsNotEqual()->GetLeastConstantLeft();
332 if (lhs->IsInstanceOf() && rhs->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +0000333 if (rhs->AsIntConstant()->IsFalse()) {
David Brazdild9510df2015-11-04 23:30:22 +0000334 // Case (1b)
335 *trueBranch = ifInstruction->IfTrueSuccessor();
336 } else {
337 // Case (2b)
Roland Levillain1a653882016-03-18 18:05:57 +0000338 DCHECK(rhs->AsIntConstant()->IsTrue()) << rhs->AsIntConstant()->GetValue();
David Brazdild9510df2015-11-04 23:30:22 +0000339 *trueBranch = ifInstruction->IfFalseSuccessor();
340 }
341 *instanceOf = lhs->AsInstanceOf();
342 return true;
343 }
344 }
345 } else if (input->IsInstanceOf()) {
346 // Case (1c)
347 *instanceOf = input->AsInstanceOf();
348 *trueBranch = ifInstruction->IfTrueSuccessor();
349 return true;
350 } else if (input->IsBooleanNot()) {
351 HInstruction* not_input = input->InputAt(0);
352 if (not_input->IsInstanceOf()) {
353 // Case (2c)
354 *instanceOf = not_input->AsInstanceOf();
355 *trueBranch = ifInstruction->IfFalseSuccessor();
356 return true;
357 }
358 }
359
360 return false;
361}
362
Calin Juravleb1498f62015-02-16 13:13:29 +0000363// Detects if `block` is the True block for the pattern
364// `if (x instanceof ClassX) { }`
365// If that's the case insert an HBoundType instruction to bound the type of `x`
366// to `ClassX` in the scope of the dominated blocks.
367void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100368 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
369 if (ifInstruction == nullptr) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000370 return;
371 }
David Brazdil0d13fee2015-04-17 14:52:19 +0100372
David Brazdild9510df2015-11-04 23:30:22 +0000373 // Try to recognize common `if (instanceof)` and `if (!instanceof)` patterns.
374 HInstanceOf* instanceOf = nullptr;
375 HBasicBlock* instanceOfTrueBlock = nullptr;
376 if (!MatchIfInstanceOf(ifInstruction, &instanceOf, &instanceOfTrueBlock)) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000377 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000378 }
379
Calin Juravle98893e12015-10-02 21:05:03 +0100380 HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
381 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
382 {
Calin Juravle98893e12015-10-02 21:05:03 +0100383 if (!class_rti.IsValid()) {
384 // He have loaded an unresolved class. Don't bother bounding the type.
385 return;
386 }
387 }
Calin Juravleb3306642015-04-20 18:30:42 +0100388 // We only need to bound the type if we have uses in the relevant block.
389 // So start with null and create the HBoundType lazily, only if it's needed.
390 HBoundType* bound_type = nullptr;
391
Calin Juravleb1498f62015-02-16 13:13:29 +0000392 HInstruction* obj = instanceOf->InputAt(0);
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100393 if (obj->GetReferenceTypeInfo().IsExact() && !obj->IsPhi()) {
394 // This method is being called while doing a fixed-point calculation
395 // over phis. Non-phis instruction whose type is already known do
396 // not need to be bound to another type.
397 // Not that this also prevents replacing `HLoadClass` with a `HBoundType`.
398 // `HCheckCast` and `HInstanceOf` expect a `HLoadClass` as a second
399 // input.
400 return;
401 }
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100402 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
Vladimir Marko46817b82016-03-29 12:21:58 +0100403 const HUseList<HInstruction*>& uses = obj->GetUses();
404 for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
405 HInstruction* user = it->GetUser();
406 size_t index = it->GetIndex();
407 // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput().
408 ++it;
Calin Juravleb1498f62015-02-16 13:13:29 +0000409 if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100410 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000411 ScopedObjectAccess soa(Thread::Current());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000412 HInstruction* insert_point = instanceOfTrueBlock->GetFirstInstruction();
413 if (ShouldCreateBoundType(insert_point, obj, class_rti, nullptr, instanceOfTrueBlock)) {
David Brazdilf5552582015-12-27 13:36:12 +0000414 bound_type = new (graph_->GetArena()) HBoundType(obj);
415 bound_type->SetUpperBound(class_rti, /* InstanceOf fails for null. */ false);
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000416 instanceOfTrueBlock->InsertInstructionBefore(bound_type, insert_point);
417 } else {
418 // We already have a bound type on the position we would need to insert
419 // the new one. The existing bound type should dominate all the users
420 // (dchecked) so there's no need to continue.
421 break;
Calin Juravleb3306642015-04-20 18:30:42 +0100422 }
Calin Juravleb3306642015-04-20 18:30:42 +0100423 }
Vladimir Marko46817b82016-03-29 12:21:58 +0100424 user->ReplaceInput(bound_type, index);
Calin Juravleb1498f62015-02-16 13:13:29 +0000425 }
426 }
Calin Juravleacf735c2015-02-12 15:25:22 +0000427}
428
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000429void ReferenceTypePropagation::RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
Mathieu Chartier3398c782016-09-30 10:27:43 -0700430 ObjPtr<mirror::Class> klass,
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000431 bool is_exact) {
Calin Juravle2e768302015-07-28 14:41:11 +0000432 if (instr->IsInvokeStaticOrDirect() && instr->AsInvokeStaticOrDirect()->IsStringInit()) {
433 // Calls to String.<init> are replaced with a StringFactory.
434 if (kIsDebugBuild) {
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000435 HInvoke* invoke = instr->AsInvoke();
Calin Juravle2e768302015-07-28 14:41:11 +0000436 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Vladimir Marko62977ff2016-04-20 15:06:31 +0100437 Thread* self = Thread::Current();
438 StackHandleScope<2> hs(self);
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000439 Handle<mirror::DexCache> dex_cache(
Vladimir Marko62977ff2016-04-20 15:06:31 +0100440 hs.NewHandle(FindDexCacheWithHint(self, invoke->GetDexFile(), hint_dex_cache_)));
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000441 // Use a null loader. We should probably use the compiling method's class loader,
442 // but then we would need to pass it to RTPVisitor just for this debug check. Since
443 // the method is from the String class, the null loader is good enough.
444 Handle<mirror::ClassLoader> loader;
Andreas Gampe42ef8ab2015-12-03 17:27:32 -0800445 ArtMethod* method = cl->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000446 invoke->GetDexFile(), invoke->GetDexMethodIndex(), dex_cache, loader, nullptr, kDirect);
Calin Juravle2e768302015-07-28 14:41:11 +0000447 DCHECK(method != nullptr);
448 mirror::Class* declaring_class = method->GetDeclaringClass();
449 DCHECK(declaring_class != nullptr);
450 DCHECK(declaring_class->IsStringClass())
David Sehr709b0702016-10-13 09:12:37 -0700451 << "Expected String class: " << declaring_class->PrettyDescriptor();
Calin Juravle2e768302015-07-28 14:41:11 +0000452 DCHECK(method->IsConstructor())
David Sehr709b0702016-10-13 09:12:37 -0700453 << "Expected String.<init>: " << method->PrettyMethod();
Calin Juravle2e768302015-07-28 14:41:11 +0000454 }
455 instr->SetReferenceTypeInfo(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000456 ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
Mathieu Chartier1cc62e42016-10-03 18:01:28 -0700457 } else if (IsAdmissible(klass.Ptr())) {
Aart Bikf417ff42016-04-25 12:51:37 -0700458 ReferenceTypeInfo::TypeHandle handle = handle_cache_->NewHandle(klass);
459 is_exact = is_exact || handle->CannotBeAssignedFromOtherTypes();
460 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
Calin Juravle2e768302015-07-28 14:41:11 +0000461 } else {
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000462 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100463 }
464}
465
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000466void ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
467 uint16_t type_idx,
468 const DexFile& dex_file,
469 bool is_exact) {
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100470 DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
471
Calin Juravleacf735c2015-02-12 15:25:22 +0000472 ScopedObjectAccess soa(Thread::Current());
Vladimir Marko456307a2016-04-19 14:12:13 +0000473 mirror::DexCache* dex_cache = FindDexCacheWithHint(soa.Self(), dex_file, hint_dex_cache_);
Calin Juravleacf735c2015-02-12 15:25:22 +0000474 // Get type from dex cache assuming it was populated by the verifier.
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100475 SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact);
Calin Juravleacf735c2015-02-12 15:25:22 +0000476}
477
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000478void ReferenceTypePropagation::RTPVisitor::VisitNewInstance(HNewInstance* 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 Marko7d1fbf32016-01-26 15:01:12 +0000482void ReferenceTypePropagation::RTPVisitor::VisitNewArray(HNewArray* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100483 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100484}
485
Vladimir Marko456307a2016-04-19 14:12:13 +0000486static mirror::Class* GetClassFromDexCache(Thread* self,
487 const DexFile& dex_file,
488 uint16_t type_idx,
489 Handle<mirror::DexCache> hint_dex_cache)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700490 REQUIRES_SHARED(Locks::mutator_lock_) {
Vladimir Marko456307a2016-04-19 14:12:13 +0000491 mirror::DexCache* dex_cache = FindDexCacheWithHint(self, dex_file, hint_dex_cache);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000492 // Get type from dex cache assuming it was populated by the verifier.
493 return dex_cache->GetResolvedType(type_idx);
494}
495
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000496void ReferenceTypePropagation::RTPVisitor::VisitParameterValue(HParameterValue* instr) {
Nicolas Geoffraye418dda2015-08-11 20:03:09 -0700497 // We check if the existing type is valid: the inliner may have set it.
498 if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) {
Vladimir Marko456307a2016-04-19 14:12:13 +0000499 ScopedObjectAccess soa(Thread::Current());
500 mirror::Class* resolved_class = GetClassFromDexCache(soa.Self(),
501 instr->GetDexFile(),
502 instr->GetTypeIndex(),
503 hint_dex_cache_);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000504 SetClassAsTypeInfo(instr, resolved_class, /* is_exact */ false);
Calin Juravle2e768302015-07-28 14:41:11 +0000505 }
506}
507
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000508void ReferenceTypePropagation::RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
509 const FieldInfo& info) {
David Brazdild9510df2015-11-04 23:30:22 +0000510 if (instr->GetType() != Primitive::kPrimNot) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100511 return;
512 }
513
Vladimir Marko62977ff2016-04-20 15:06:31 +0100514 ScopedObjectAccess soa(Thread::Current());
Mathieu Chartier3398c782016-09-30 10:27:43 -0700515 ObjPtr<mirror::Class> klass;
David Brazdild9510df2015-11-04 23:30:22 +0000516
517 // The field index is unknown only during tests.
518 if (info.GetFieldIndex() != kUnknownFieldIndex) {
519 ClassLinker* cl = Runtime::Current()->GetClassLinker();
520 ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), info.GetDexCache().Get());
521 // TODO: There are certain cases where we can't resolve the field.
522 // b/21914925 is open to keep track of a repro case for this issue.
523 if (field != nullptr) {
524 klass = field->GetType<false>();
525 }
526 }
527
Calin Juravle2e768302015-07-28 14:41:11 +0000528 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100529}
530
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000531void ReferenceTypePropagation::RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* 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::VisitStaticFieldGet(HStaticFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100536 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
537}
538
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000539void ReferenceTypePropagation::RTPVisitor::VisitUnresolvedInstanceFieldGet(
540 HUnresolvedInstanceFieldGet* instr) {
Calin Juravlee460d1d2015-09-29 04:52:17 +0100541 // TODO: Use descriptor to get the actual type.
542 if (instr->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000543 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Calin Juravlee460d1d2015-09-29 04:52:17 +0100544 }
545}
546
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000547void ReferenceTypePropagation::RTPVisitor::VisitUnresolvedStaticFieldGet(
548 HUnresolvedStaticFieldGet* instr) {
Calin Juravlee460d1d2015-09-29 04:52:17 +0100549 // TODO: Use descriptor to get the actual type.
550 if (instr->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000551 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Calin Juravlee460d1d2015-09-29 04:52:17 +0100552 }
553}
554
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000555void ReferenceTypePropagation::RTPVisitor::VisitLoadClass(HLoadClass* instr) {
Calin Juravleacf735c2015-02-12 15:25:22 +0000556 ScopedObjectAccess soa(Thread::Current());
Calin Juravleacf735c2015-02-12 15:25:22 +0000557 // Get type from dex cache assuming it was populated by the verifier.
Vladimir Marko456307a2016-04-19 14:12:13 +0000558 mirror::Class* resolved_class = GetClassFromDexCache(soa.Self(),
559 instr->GetDexFile(),
560 instr->GetTypeIndex(),
561 hint_dex_cache_);
Aart Bikf417ff42016-04-25 12:51:37 -0700562 if (IsAdmissible(resolved_class)) {
Calin Juravle98893e12015-10-02 21:05:03 +0100563 instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000564 handle_cache_->NewHandle(resolved_class), /* is_exact */ true));
Calin Juravle98893e12015-10-02 21:05:03 +0100565 }
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000566 instr->SetReferenceTypeInfo(
567 ReferenceTypeInfo::Create(handle_cache_->GetClassClassHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000568}
569
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000570void ReferenceTypePropagation::RTPVisitor::VisitClinitCheck(HClinitCheck* instr) {
Calin Juravle2e768302015-07-28 14:41:11 +0000571 instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
572}
573
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000574void ReferenceTypePropagation::RTPVisitor::VisitLoadString(HLoadString* instr) {
575 instr->SetReferenceTypeInfo(
576 ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000577}
578
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000579void ReferenceTypePropagation::RTPVisitor::VisitLoadException(HLoadException* instr) {
David Brazdilbbd733e2015-08-18 17:48:17 +0100580 DCHECK(instr->GetBlock()->IsCatchBlock());
581 TryCatchInformation* catch_info = instr->GetBlock()->GetTryCatchInformation();
582
583 if (catch_info->IsCatchAllTypeIndex()) {
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000584 instr->SetReferenceTypeInfo(
585 ReferenceTypeInfo::Create(handle_cache_->GetThrowableClassHandle(), /* is_exact */ false));
David Brazdilbbd733e2015-08-18 17:48:17 +0100586 } else {
587 UpdateReferenceTypeInfo(instr,
588 catch_info->GetCatchTypeIndex(),
589 catch_info->GetCatchDexFile(),
590 /* is_exact */ false);
591 }
592}
593
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000594void ReferenceTypePropagation::RTPVisitor::VisitNullCheck(HNullCheck* instr) {
Calin Juravle2e768302015-07-28 14:41:11 +0000595 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
David Brazdilfe860702015-12-02 09:06:57 +0000596 if (parent_rti.IsValid()) {
597 instr->SetReferenceTypeInfo(parent_rti);
598 }
Calin Juravle2e768302015-07-28 14:41:11 +0000599}
600
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000601void ReferenceTypePropagation::RTPVisitor::VisitBoundType(HBoundType* instr) {
David Brazdilf5552582015-12-27 13:36:12 +0000602 ReferenceTypeInfo class_rti = instr->GetUpperBound();
603 if (class_rti.IsValid()) {
Vladimir Marko456307a2016-04-19 14:12:13 +0000604 ScopedObjectAccess soa(Thread::Current());
David Brazdilf5552582015-12-27 13:36:12 +0000605 // Narrow the type as much as possible.
606 HInstruction* obj = instr->InputAt(0);
607 ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo();
608 if (class_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes()) {
609 instr->SetReferenceTypeInfo(
610 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ true));
David Brazdil744a1c62015-12-28 10:53:34 +0000611 } else if (obj_rti.IsValid()) {
612 if (class_rti.IsSupertypeOf(obj_rti)) {
613 // Object type is more specific.
614 instr->SetReferenceTypeInfo(obj_rti);
615 } else {
616 // Upper bound is more specific.
617 instr->SetReferenceTypeInfo(
618 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
619 }
David Brazdilf5552582015-12-27 13:36:12 +0000620 } else {
David Brazdil744a1c62015-12-28 10:53:34 +0000621 // Object not typed yet. Leave BoundType untyped for now rather than
622 // assign the type conservatively.
David Brazdilf5552582015-12-27 13:36:12 +0000623 }
624 instr->SetCanBeNull(obj->CanBeNull() && instr->GetUpperCanBeNull());
625 } else {
626 // The owner of the BoundType was already visited. If the class is unresolved,
627 // the BoundType should have been removed from the data flow and this method
628 // should remove it from the graph.
629 DCHECK(!instr->HasUses());
630 instr->GetBlock()->RemoveInstruction(instr);
631 }
632}
633
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000634void ReferenceTypePropagation::RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
Calin Juravle98893e12015-10-02 21:05:03 +0100635 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
636 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
David Brazdilf5552582015-12-27 13:36:12 +0000637 HBoundType* bound_type = check_cast->GetNext()->AsBoundType();
638 if (bound_type == nullptr || bound_type->GetUpperBound().IsValid()) {
639 // The next instruction is not an uninitialized BoundType. This must be
640 // an RTP pass after SsaBuilder and we do not need to do anything.
641 return;
Calin Juravle98893e12015-10-02 21:05:03 +0100642 }
David Brazdilf5552582015-12-27 13:36:12 +0000643 DCHECK_EQ(bound_type->InputAt(0), check_cast->InputAt(0));
644
645 if (class_rti.IsValid()) {
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000646 DCHECK(is_first_run_);
David Brazdilf5552582015-12-27 13:36:12 +0000647 // This is the first run of RTP and class is resolved.
648 bound_type->SetUpperBound(class_rti, /* CheckCast succeeds for nulls. */ true);
649 } else {
650 // This is the first run of RTP and class is unresolved. Remove the binding.
651 // The instruction itself is removed in VisitBoundType so as to not
652 // invalidate HInstructionIterator.
653 bound_type->ReplaceWith(bound_type->InputAt(0));
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000654 }
655}
656
Calin Juravleb1498f62015-02-16 13:13:29 +0000657void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
David Brazdild9510df2015-11-04 23:30:22 +0000658 if (phi->IsDead() || phi->GetType() != Primitive::kPrimNot) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000659 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000660 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000661
662 if (phi->GetBlock()->IsLoopHeader()) {
663 // Set the initial type for the phi. Use the non back edge input for reaching
664 // a fixed point faster.
David Brazdilfe860702015-12-02 09:06:57 +0000665 HInstruction* first_input = phi->InputAt(0);
666 ReferenceTypeInfo first_input_rti = first_input->GetReferenceTypeInfo();
667 if (first_input_rti.IsValid() && !first_input->IsNullConstant()) {
668 phi->SetCanBeNull(first_input->CanBeNull());
669 phi->SetReferenceTypeInfo(first_input_rti);
670 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000671 AddToWorklist(phi);
Calin Juravle10e244f2015-01-26 18:54:32 +0000672 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000673 // Eagerly compute the type of the phi, for quicker convergence. Note
674 // that we don't need to add users to the worklist because we are
675 // doing a reverse post-order visit, therefore either the phi users are
676 // non-loop phi and will be visited later in the visit, or are loop-phis,
677 // and they are already in the work list.
678 UpdateNullability(phi);
679 UpdateReferenceTypeInfo(phi);
680 }
681}
682
683ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
684 const ReferenceTypeInfo& b) {
Calin Juravle2e768302015-07-28 14:41:11 +0000685 if (!b.IsValid()) {
686 return a;
687 }
688 if (!a.IsValid()) {
689 return b;
Calin Juravle20e60712015-07-01 18:41:04 +0100690 }
691
Calin Juravle2e768302015-07-28 14:41:11 +0000692 bool is_exact = a.IsExact() && b.IsExact();
Calin Juravle52503d82015-11-11 16:58:31 +0000693 ReferenceTypeInfo::TypeHandle result_type_handle;
694 ReferenceTypeInfo::TypeHandle a_type_handle = a.GetTypeHandle();
695 ReferenceTypeInfo::TypeHandle b_type_handle = b.GetTypeHandle();
696 bool a_is_interface = a_type_handle->IsInterface();
697 bool b_is_interface = b_type_handle->IsInterface();
Calin Juravle2e768302015-07-28 14:41:11 +0000698
699 if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
Calin Juravle52503d82015-11-11 16:58:31 +0000700 result_type_handle = a_type_handle;
Calin Juravle2e768302015-07-28 14:41:11 +0000701 } else if (a.IsSupertypeOf(b)) {
Calin Juravle52503d82015-11-11 16:58:31 +0000702 result_type_handle = a_type_handle;
Calin Juravle2e768302015-07-28 14:41:11 +0000703 is_exact = false;
704 } else if (b.IsSupertypeOf(a)) {
Calin Juravle52503d82015-11-11 16:58:31 +0000705 result_type_handle = b_type_handle;
706 is_exact = false;
707 } else if (!a_is_interface && !b_is_interface) {
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000708 result_type_handle =
709 handle_cache_.NewHandle(a_type_handle->GetCommonSuperClass(b_type_handle));
Calin Juravle2e768302015-07-28 14:41:11 +0000710 is_exact = false;
711 } else {
Calin Juravle52503d82015-11-11 16:58:31 +0000712 // This can happen if:
713 // - both types are interfaces. TODO(calin): implement
714 // - one is an interface, the other a class, and the type does not implement the interface
715 // e.g:
716 // void foo(Interface i, boolean cond) {
717 // Object o = cond ? i : new Object();
718 // }
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000719 result_type_handle = handle_cache_.GetObjectClassHandle();
Calin Juravle2e768302015-07-28 14:41:11 +0000720 is_exact = false;
721 }
722
Calin Juravle52503d82015-11-11 16:58:31 +0000723 return ReferenceTypeInfo::Create(result_type_handle, is_exact);
Calin Juravle2e768302015-07-28 14:41:11 +0000724}
725
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000726void ReferenceTypePropagation::UpdateArrayGet(HArrayGet* instr, HandleCache* handle_cache) {
Calin Juravle2e768302015-07-28 14:41:11 +0000727 DCHECK_EQ(Primitive::kPrimNot, instr->GetType());
728
729 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
David Brazdilfe860702015-12-02 09:06:57 +0000730 if (!parent_rti.IsValid()) {
731 return;
732 }
Calin Juravle2e768302015-07-28 14:41:11 +0000733
734 Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
Aart Bikf417ff42016-04-25 12:51:37 -0700735 if (handle->IsObjectArrayClass() && IsAdmissible(handle->GetComponentType())) {
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000736 ReferenceTypeInfo::TypeHandle component_handle =
737 handle_cache->NewHandle(handle->GetComponentType());
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000738 bool is_exact = component_handle->CannotBeAssignedFromOtherTypes();
739 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(component_handle, is_exact));
Calin Juravle2e768302015-07-28 14:41:11 +0000740 } else {
741 // We don't know what the parent actually is, so we fallback to object.
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000742 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Calin Juravle2e768302015-07-28 14:41:11 +0000743 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000744}
745
746bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
747 ScopedObjectAccess soa(Thread::Current());
748
749 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
750 if (instr->IsBoundType()) {
751 UpdateBoundType(instr->AsBoundType());
752 } else if (instr->IsPhi()) {
753 UpdatePhi(instr->AsPhi());
Calin Juravle2e768302015-07-28 14:41:11 +0000754 } else if (instr->IsNullCheck()) {
755 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
756 if (parent_rti.IsValid()) {
757 instr->SetReferenceTypeInfo(parent_rti);
758 }
759 } else if (instr->IsArrayGet()) {
David Brazdilfe860702015-12-02 09:06:57 +0000760 // TODO: consider if it's worth "looking back" and binding the input object
Calin Juravle2e768302015-07-28 14:41:11 +0000761 // to an array type.
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000762 UpdateArrayGet(instr->AsArrayGet(), &handle_cache_);
Calin Juravleb1498f62015-02-16 13:13:29 +0000763 } else {
764 LOG(FATAL) << "Invalid instruction (should not get here)";
765 }
766
767 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
768}
769
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000770void ReferenceTypePropagation::RTPVisitor::VisitInvoke(HInvoke* instr) {
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100771 if (instr->GetType() != Primitive::kPrimNot) {
772 return;
773 }
774
775 ScopedObjectAccess soa(Thread::Current());
776 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Vladimir Marko456307a2016-04-19 14:12:13 +0000777 mirror::DexCache* dex_cache =
778 FindDexCacheWithHint(soa.Self(), instr->GetDexFile(), hint_dex_cache_);
Andreas Gampe542451c2016-07-26 09:02:02 -0700779 PointerSize pointer_size = cl->GetImagePointerSize();
Vladimir Marko05792b92015-08-03 11:56:49 +0100780 ArtMethod* method = dex_cache->GetResolvedMethod(instr->GetDexMethodIndex(), pointer_size);
781 mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false, pointer_size);
Calin Juravle2e768302015-07-28 14:41:11 +0000782 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100783}
784
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000785void ReferenceTypePropagation::RTPVisitor::VisitArrayGet(HArrayGet* instr) {
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100786 if (instr->GetType() != Primitive::kPrimNot) {
787 return;
788 }
David Brazdilfe860702015-12-02 09:06:57 +0000789
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100790 ScopedObjectAccess soa(Thread::Current());
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000791 UpdateArrayGet(instr, handle_cache_);
Calin Juravle2e768302015-07-28 14:41:11 +0000792 if (!instr->GetReferenceTypeInfo().IsValid()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100793 worklist_->push_back(instr);
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100794 }
795}
796
Calin Juravleb1498f62015-02-16 13:13:29 +0000797void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
798 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle2e768302015-07-28 14:41:11 +0000799 if (!new_rti.IsValid()) {
800 return; // No new info yet.
801 }
802
803 // Make sure that we don't go over the bounded type.
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000804 ReferenceTypeInfo upper_bound_rti = instr->GetUpperBound();
805 if (!upper_bound_rti.IsSupertypeOf(new_rti)) {
Nicolas Geoffraya90d4892016-06-01 16:30:20 +0100806 // Note that the input might be exact, in which case we know the branch leading
807 // to the bound type is dead. We play it safe by not marking the bound type as
808 // exact.
809 bool is_exact = upper_bound_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes();
810 new_rti = ReferenceTypeInfo::Create(upper_bound_rti.GetTypeHandle(), is_exact);
Calin Juravleb1498f62015-02-16 13:13:29 +0000811 }
812 instr->SetReferenceTypeInfo(new_rti);
813}
814
Calin Juravle617bd922015-11-11 14:59:46 +0000815// NullConstant inputs are ignored during merging as they do not provide any useful information.
816// If all the inputs are NullConstants then the type of the phi will be set to Object.
Calin Juravleb1498f62015-02-16 13:13:29 +0000817void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
David Brazdild9510df2015-11-04 23:30:22 +0000818 DCHECK(instr->IsLive());
819
Vladimir Markoe9004912016-06-16 16:50:52 +0100820 HInputsRef inputs = instr->GetInputs();
Calin Juravle617bd922015-11-11 14:59:46 +0000821 size_t first_input_index_not_null = 0;
Vladimir Marko372f10e2016-05-17 16:30:10 +0100822 while (first_input_index_not_null < inputs.size() &&
Vladimir Markoe9004912016-06-16 16:50:52 +0100823 inputs[first_input_index_not_null]->IsNullConstant()) {
Calin Juravle617bd922015-11-11 14:59:46 +0000824 first_input_index_not_null++;
825 }
Vladimir Marko372f10e2016-05-17 16:30:10 +0100826 if (first_input_index_not_null == inputs.size()) {
Calin Juravle617bd922015-11-11 14:59:46 +0000827 // All inputs are NullConstants, set the type to object.
828 // This may happen in the presence of inlining.
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000829 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Calin Juravle617bd922015-11-11 14:59:46 +0000830 return;
831 }
832
833 ReferenceTypeInfo new_rti = instr->InputAt(first_input_index_not_null)->GetReferenceTypeInfo();
834
Calin Juravle2e768302015-07-28 14:41:11 +0000835 if (new_rti.IsValid() && new_rti.IsObjectClass() && !new_rti.IsExact()) {
836 // Early return if we are Object and inexact.
Calin Juravleb1498f62015-02-16 13:13:29 +0000837 instr->SetReferenceTypeInfo(new_rti);
838 return;
839 }
Calin Juravle617bd922015-11-11 14:59:46 +0000840
Vladimir Marko372f10e2016-05-17 16:30:10 +0100841 for (size_t i = first_input_index_not_null + 1; i < inputs.size(); i++) {
842 if (inputs[i]->IsNullConstant()) {
Calin Juravle617bd922015-11-11 14:59:46 +0000843 continue;
844 }
Vladimir Marko372f10e2016-05-17 16:30:10 +0100845 new_rti = MergeTypes(new_rti, inputs[i]->GetReferenceTypeInfo());
Calin Juravle2e768302015-07-28 14:41:11 +0000846 if (new_rti.IsValid() && new_rti.IsObjectClass()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000847 if (!new_rti.IsExact()) {
848 break;
849 } else {
850 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000851 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000852 }
853 }
David Brazdilfe860702015-12-02 09:06:57 +0000854
855 if (new_rti.IsValid()) {
856 instr->SetReferenceTypeInfo(new_rti);
857 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000858}
859
860// Re-computes and updates the nullability of the instruction. Returns whether or
861// not the nullability was changed.
862bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
David Brazdild9510df2015-11-04 23:30:22 +0000863 DCHECK((instr->IsPhi() && instr->AsPhi()->IsLive())
Calin Juravle2e768302015-07-28 14:41:11 +0000864 || instr->IsBoundType()
865 || instr->IsNullCheck()
866 || instr->IsArrayGet());
867
868 if (!instr->IsPhi() && !instr->IsBoundType()) {
869 return false;
870 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000871
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000872 bool existing_can_be_null = instr->CanBeNull();
873 if (instr->IsPhi()) {
874 HPhi* phi = instr->AsPhi();
875 bool new_can_be_null = false;
Vladimir Marko372f10e2016-05-17 16:30:10 +0100876 for (HInstruction* input : phi->GetInputs()) {
877 if (input->CanBeNull()) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000878 new_can_be_null = true;
879 break;
880 }
881 }
882 phi->SetCanBeNull(new_can_be_null);
883 } else if (instr->IsBoundType()) {
884 HBoundType* bound_type = instr->AsBoundType();
885 bound_type->SetCanBeNull(instr->InputAt(0)->CanBeNull() && bound_type->GetUpperCanBeNull());
Calin Juravleb1498f62015-02-16 13:13:29 +0000886 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000887 return existing_can_be_null != instr->CanBeNull();
Calin Juravle10e244f2015-01-26 18:54:32 +0000888}
889
890void ReferenceTypePropagation::ProcessWorklist() {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100891 while (!worklist_.empty()) {
892 HInstruction* instruction = worklist_.back();
893 worklist_.pop_back();
Calin Juravle12617592015-10-16 16:28:46 +0100894 bool updated_nullability = UpdateNullability(instruction);
895 bool updated_reference_type = UpdateReferenceTypeInfo(instruction);
896 if (updated_nullability || updated_reference_type) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000897 AddDependentInstructionsToWorklist(instruction);
898 }
899 }
900}
901
Calin Juravleb1498f62015-02-16 13:13:29 +0000902void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
Calin Juravle2e768302015-07-28 14:41:11 +0000903 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot)
904 << instruction->DebugName() << ":" << instruction->GetType();
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100905 worklist_.push_back(instruction);
Calin Juravle10e244f2015-01-26 18:54:32 +0000906}
907
Calin Juravleb1498f62015-02-16 13:13:29 +0000908void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Vladimir Marko46817b82016-03-29 12:21:58 +0100909 for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
910 HInstruction* user = use.GetUser();
David Brazdild9510df2015-11-04 23:30:22 +0000911 if ((user->IsPhi() && user->AsPhi()->IsLive())
Calin Juravle2e768302015-07-28 14:41:11 +0000912 || user->IsBoundType()
913 || user->IsNullCheck()
914 || (user->IsArrayGet() && (user->GetType() == Primitive::kPrimNot))) {
Calin Juravlebeba9302015-07-08 15:57:18 +0000915 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000916 }
917 }
918}
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000919
Calin Juravle10e244f2015-01-26 18:54:32 +0000920} // namespace art