blob: 75356c848b65758ee1b4102833fd9a6db4d7a8d7 [file] [log] [blame]
Calin Juravle10e244f2015-01-26 18:54:32 +00001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "reference_type_propagation.h"
18
Mathieu Chartiere401d142015-04-22 13:56:20 -070019#include "class_linker-inl.h"
Calin Juravleacf735c2015-02-12 15:25:22 +000020#include "mirror/class-inl.h"
21#include "mirror/dex_cache.h"
22#include "scoped_thread_state_change.h"
23
Calin Juravle10e244f2015-01-26 18:54:32 +000024namespace art {
25
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000026static inline ReferenceTypeInfo::TypeHandle GetRootHandle(StackHandleScopeCollection* handles,
27 ClassLinker::ClassRoot class_root,
28 ReferenceTypeInfo::TypeHandle* cache) {
29 if (!ReferenceTypeInfo::IsValidHandle(*cache)) {
30 // Mutator lock is required for NewHandle.
31 ClassLinker* linker = Runtime::Current()->GetClassLinker();
32 ScopedObjectAccess soa(Thread::Current());
33 *cache = handles->NewHandle(linker->GetClassRoot(class_root));
34 }
35 return *cache;
36}
37
38ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetObjectClassHandle() {
39 return GetRootHandle(handles_, ClassLinker::kJavaLangObject, &object_class_handle_);
40}
41
42ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetClassClassHandle() {
43 return GetRootHandle(handles_, ClassLinker::kJavaLangClass, &class_class_handle_);
44}
45
46ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetStringClassHandle() {
47 return GetRootHandle(handles_, ClassLinker::kJavaLangString, &string_class_handle_);
48}
49
50ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetThrowableClassHandle() {
51 return GetRootHandle(handles_, ClassLinker::kJavaLangThrowable, &throwable_class_handle_);
52}
53
54class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor {
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010055 public:
Calin Juravle2e768302015-07-28 14:41:11 +000056 RTPVisitor(HGraph* graph,
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000057 HandleCache* handle_cache,
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +000058 ArenaVector<HInstruction*>* worklist,
59 bool is_first_run)
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010060 : HGraphDelegateVisitor(graph),
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000061 handle_cache_(handle_cache),
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +000062 worklist_(worklist),
63 is_first_run_(is_first_run) {}
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010064
65 void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
66 void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000067 void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE;
68 void VisitLoadString(HLoadString* instr) OVERRIDE;
David Brazdilbbd733e2015-08-18 17:48:17 +010069 void VisitLoadException(HLoadException* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010070 void VisitNewArray(HNewArray* instr) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000071 void VisitParameterValue(HParameterValue* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010072 void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
73 void SetClassAsTypeInfo(HInstruction* instr, mirror::Class* klass, bool is_exact);
74 void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE;
75 void VisitStaticFieldGet(HStaticFieldGet* instr) OVERRIDE;
Calin Juravlee460d1d2015-09-29 04:52:17 +010076 void VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instr) OVERRIDE;
77 void VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010078 void VisitInvoke(HInvoke* instr) OVERRIDE;
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +010079 void VisitArrayGet(HArrayGet* instr) OVERRIDE;
Calin Juravlea5ae3c32015-07-28 14:40:50 +000080 void VisitCheckCast(HCheckCast* instr) OVERRIDE;
David Brazdilf5552582015-12-27 13:36:12 +000081 void VisitBoundType(HBoundType* instr) OVERRIDE;
Calin Juravle2e768302015-07-28 14:41:11 +000082 void VisitNullCheck(HNullCheck* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010083 void UpdateReferenceTypeInfo(HInstruction* instr,
84 uint16_t type_idx,
85 const DexFile& dex_file,
86 bool is_exact);
87
88 private:
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000089 HandleCache* handle_cache_;
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010090 ArenaVector<HInstruction*>* worklist_;
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +000091 const bool is_first_run_;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010092};
93
Calin Juravle2e768302015-07-28 14:41:11 +000094ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph,
95 StackHandleScopeCollection* handles,
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +000096 bool is_first_run,
Calin Juravle2e768302015-07-28 14:41:11 +000097 const char* name)
98 : HOptimization(graph, name),
Vladimir Marko7d1fbf32016-01-26 15:01:12 +000099 handle_cache_(handles),
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000100 worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)),
101 is_first_run_(is_first_run) {
Calin Juravle2e768302015-07-28 14:41:11 +0000102}
103
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000104void ReferenceTypePropagation::ValidateTypes() {
105 // TODO: move this to the graph checker.
Calin Juravle2e768302015-07-28 14:41:11 +0000106 if (kIsDebugBuild) {
Calin Juravle2e768302015-07-28 14:41:11 +0000107 ScopedObjectAccess soa(Thread::Current());
108 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
109 HBasicBlock* block = it.Current();
110 for (HInstructionIterator iti(block->GetInstructions()); !iti.Done(); iti.Advance()) {
111 HInstruction* instr = iti.Current();
112 if (instr->GetType() == Primitive::kPrimNot) {
113 DCHECK(instr->GetReferenceTypeInfo().IsValid())
114 << "Invalid RTI for instruction: " << instr->DebugName();
115 if (instr->IsBoundType()) {
116 DCHECK(instr->AsBoundType()->GetUpperBound().IsValid());
117 } else if (instr->IsLoadClass()) {
Calin Juravle98893e12015-10-02 21:05:03 +0100118 HLoadClass* cls = instr->AsLoadClass();
119 DCHECK(cls->GetReferenceTypeInfo().IsExact());
120 DCHECK(!cls->GetLoadedClassRTI().IsValid() || cls->GetLoadedClassRTI().IsExact());
Calin Juravle2e768302015-07-28 14:41:11 +0000121 } else if (instr->IsNullCheck()) {
122 DCHECK(instr->GetReferenceTypeInfo().IsEqual(instr->InputAt(0)->GetReferenceTypeInfo()))
123 << "NullCheck " << instr->GetReferenceTypeInfo()
124 << "Input(0) " << instr->InputAt(0)->GetReferenceTypeInfo();
125 }
126 }
127 }
128 }
129 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000130}
131
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000132void ReferenceTypePropagation::Visit(HInstruction* instruction) {
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000133 RTPVisitor visitor(graph_, &handle_cache_, &worklist_, is_first_run_);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000134 instruction->Accept(&visitor);
135}
136
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000137void ReferenceTypePropagation::Run() {
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000138 worklist_.reserve(kDefaultWorklistSize);
139
Calin Juravlecdfed3d2015-10-26 14:05:01 +0000140 // To properly propagate type info we need to visit in the dominator-based order.
141 // Reverse post order guarantees a node's dominators are visited first.
142 // We take advantage of this order in `VisitBasicBlock`.
143 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
144 VisitBasicBlock(it.Current());
145 }
146
147 ProcessWorklist();
148 ValidateTypes();
149}
150
Calin Juravleb1498f62015-02-16 13:13:29 +0000151void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000152 RTPVisitor visitor(graph_, &handle_cache_, &worklist_, is_first_run_);
Calin Juravle2e768302015-07-28 14:41:11 +0000153 // Handle Phis first as there might be instructions in the same block who depend on them.
154 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
155 VisitPhi(it.Current()->AsPhi());
156 }
Calin Juravlebeba9302015-07-08 15:57:18 +0000157
Calin Juravle2e768302015-07-28 14:41:11 +0000158 // Handle instructions.
Calin Juravleb1498f62015-02-16 13:13:29 +0000159 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
160 HInstruction* instr = it.Current();
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100161 instr->Accept(&visitor);
Calin Juravleb1498f62015-02-16 13:13:29 +0000162 }
163
Calin Juravleb1498f62015-02-16 13:13:29 +0000164 // Add extra nodes to bound types.
Calin Juravle61d544b2015-02-23 16:46:57 +0000165 BoundTypeForIfNotNull(block);
Calin Juravleb1498f62015-02-16 13:13:29 +0000166 BoundTypeForIfInstanceOf(block);
Calin Juravle10e244f2015-01-26 18:54:32 +0000167}
168
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000169// Check if we should create a bound type for the given object at the specified
170// position. Because of inlining and the fact we run RTP more than once and we
171// might have a HBoundType already. If we do, we should not create a new one.
172// In this case we also assert that there are no other uses of the object (except
173// the bound type) dominated by the specified dominator_instr or dominator_block.
174static bool ShouldCreateBoundType(HInstruction* position,
175 HInstruction* obj,
176 ReferenceTypeInfo upper_bound,
177 HInstruction* dominator_instr,
178 HBasicBlock* dominator_block)
179 SHARED_REQUIRES(Locks::mutator_lock_) {
180 // If the position where we should insert the bound type is not already a
181 // a bound type then we need to create one.
182 if (position == nullptr || !position->IsBoundType()) {
183 return true;
184 }
185
186 HBoundType* existing_bound_type = position->AsBoundType();
187 if (existing_bound_type->GetUpperBound().IsSupertypeOf(upper_bound)) {
188 if (kIsDebugBuild) {
189 // Check that the existing HBoundType dominates all the uses.
190 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
191 HInstruction* user = it.Current()->GetUser();
192 if (dominator_instr != nullptr) {
193 DCHECK(!dominator_instr->StrictlyDominates(user)
194 || user == existing_bound_type
195 || existing_bound_type->StrictlyDominates(user));
196 } else if (dominator_block != nullptr) {
197 DCHECK(!dominator_block->Dominates(user->GetBlock())
198 || user == existing_bound_type
199 || existing_bound_type->StrictlyDominates(user));
200 }
201 }
202 }
203 } else {
204 // TODO: if the current bound type is a refinement we could update the
205 // existing_bound_type with the a new upper limit. However, we also need to
206 // update its users and have access to the work list.
207 }
208 return false;
209}
210
Calin Juravle61d544b2015-02-23 16:46:57 +0000211void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100212 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
213 if (ifInstruction == nullptr) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000214 return;
215 }
Calin Juravleb3306642015-04-20 18:30:42 +0100216 HInstruction* ifInput = ifInstruction->InputAt(0);
Calin Juravle61d544b2015-02-23 16:46:57 +0000217 if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) {
218 return;
219 }
220 HInstruction* input0 = ifInput->InputAt(0);
221 HInstruction* input1 = ifInput->InputAt(1);
Calin Juravleedad8ad2015-04-23 14:34:33 +0100222 HInstruction* obj = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000223
Calin Juravleedad8ad2015-04-23 14:34:33 +0100224 if (input1->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000225 obj = input0;
Calin Juravleedad8ad2015-04-23 14:34:33 +0100226 } else if (input0->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000227 obj = input1;
228 } else {
229 return;
230 }
231
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100232 if (!obj->CanBeNull() || obj->IsNullConstant()) {
233 // Null check is dead code and will be removed by DCE.
234 return;
235 }
236 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
237
Calin Juravleb3306642015-04-20 18:30:42 +0100238 // We only need to bound the type if we have uses in the relevant block.
239 // So start with null and create the HBoundType lazily, only if it's needed.
240 HBoundType* bound_type = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000241 HBasicBlock* notNullBlock = ifInput->IsNotEqual()
Calin Juravleb3306642015-04-20 18:30:42 +0100242 ? ifInstruction->IfTrueSuccessor()
243 : ifInstruction->IfFalseSuccessor();
244
Calin Juravle61d544b2015-02-23 16:46:57 +0000245 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
246 HInstruction* user = it.Current()->GetUser();
247 if (notNullBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100248 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000249 ScopedObjectAccess soa(Thread::Current());
250 HInstruction* insert_point = notNullBlock->GetFirstInstruction();
Calin Juravle2e768302015-07-28 14:41:11 +0000251 ReferenceTypeInfo object_rti = ReferenceTypeInfo::Create(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000252 handle_cache_.GetObjectClassHandle(), /* is_exact */ true);
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000253 if (ShouldCreateBoundType(insert_point, obj, object_rti, nullptr, notNullBlock)) {
David Brazdilf5552582015-12-27 13:36:12 +0000254 bound_type = new (graph_->GetArena()) HBoundType(obj);
255 bound_type->SetUpperBound(object_rti, /* bound_can_be_null */ false);
Calin Juravle2e768302015-07-28 14:41:11 +0000256 if (obj->GetReferenceTypeInfo().IsValid()) {
257 bound_type->SetReferenceTypeInfo(obj->GetReferenceTypeInfo());
258 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000259 notNullBlock->InsertInstructionBefore(bound_type, insert_point);
260 } else {
261 // We already have a bound type on the position we would need to insert
262 // the new one. The existing bound type should dominate all the users
263 // (dchecked) so there's no need to continue.
264 break;
265 }
Calin Juravleb3306642015-04-20 18:30:42 +0100266 }
Calin Juravle61d544b2015-02-23 16:46:57 +0000267 user->ReplaceInput(bound_type, it.Current()->GetIndex());
268 }
269 }
270}
271
David Brazdild9510df2015-11-04 23:30:22 +0000272// Returns true if one of the patterns below has been recognized. If so, the
273// InstanceOf instruction together with the true branch of `ifInstruction` will
274// be returned using the out parameters.
275// Recognized patterns:
276// (1) patterns equivalent to `if (obj instanceof X)`
277// (a) InstanceOf -> Equal to 1 -> If
278// (b) InstanceOf -> NotEqual to 0 -> If
279// (c) InstanceOf -> If
280// (2) patterns equivalent to `if (!(obj instanceof X))`
281// (a) InstanceOf -> Equal to 0 -> If
282// (b) InstanceOf -> NotEqual to 1 -> If
283// (c) InstanceOf -> BooleanNot -> If
284static bool MatchIfInstanceOf(HIf* ifInstruction,
285 /* out */ HInstanceOf** instanceOf,
286 /* out */ HBasicBlock** trueBranch) {
287 HInstruction* input = ifInstruction->InputAt(0);
288
289 if (input->IsEqual()) {
290 HInstruction* rhs = input->AsEqual()->GetConstantRight();
291 if (rhs != nullptr) {
292 HInstruction* lhs = input->AsEqual()->GetLeastConstantLeft();
293 if (lhs->IsInstanceOf() && rhs->IsIntConstant()) {
294 if (rhs->AsIntConstant()->IsOne()) {
295 // Case (1a)
296 *trueBranch = ifInstruction->IfTrueSuccessor();
297 } else {
298 // Case (2a)
299 DCHECK(rhs->AsIntConstant()->IsZero());
300 *trueBranch = ifInstruction->IfFalseSuccessor();
301 }
302 *instanceOf = lhs->AsInstanceOf();
303 return true;
304 }
305 }
306 } else if (input->IsNotEqual()) {
307 HInstruction* rhs = input->AsNotEqual()->GetConstantRight();
308 if (rhs != nullptr) {
309 HInstruction* lhs = input->AsNotEqual()->GetLeastConstantLeft();
310 if (lhs->IsInstanceOf() && rhs->IsIntConstant()) {
311 if (rhs->AsIntConstant()->IsZero()) {
312 // Case (1b)
313 *trueBranch = ifInstruction->IfTrueSuccessor();
314 } else {
315 // Case (2b)
316 DCHECK(rhs->AsIntConstant()->IsOne());
317 *trueBranch = ifInstruction->IfFalseSuccessor();
318 }
319 *instanceOf = lhs->AsInstanceOf();
320 return true;
321 }
322 }
323 } else if (input->IsInstanceOf()) {
324 // Case (1c)
325 *instanceOf = input->AsInstanceOf();
326 *trueBranch = ifInstruction->IfTrueSuccessor();
327 return true;
328 } else if (input->IsBooleanNot()) {
329 HInstruction* not_input = input->InputAt(0);
330 if (not_input->IsInstanceOf()) {
331 // Case (2c)
332 *instanceOf = not_input->AsInstanceOf();
333 *trueBranch = ifInstruction->IfFalseSuccessor();
334 return true;
335 }
336 }
337
338 return false;
339}
340
Calin Juravleb1498f62015-02-16 13:13:29 +0000341// Detects if `block` is the True block for the pattern
342// `if (x instanceof ClassX) { }`
343// If that's the case insert an HBoundType instruction to bound the type of `x`
344// to `ClassX` in the scope of the dominated blocks.
345void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100346 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
347 if (ifInstruction == nullptr) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000348 return;
349 }
David Brazdil0d13fee2015-04-17 14:52:19 +0100350
David Brazdild9510df2015-11-04 23:30:22 +0000351 // Try to recognize common `if (instanceof)` and `if (!instanceof)` patterns.
352 HInstanceOf* instanceOf = nullptr;
353 HBasicBlock* instanceOfTrueBlock = nullptr;
354 if (!MatchIfInstanceOf(ifInstruction, &instanceOf, &instanceOfTrueBlock)) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000355 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000356 }
357
Calin Juravle98893e12015-10-02 21:05:03 +0100358 HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
359 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
360 {
361 ScopedObjectAccess soa(Thread::Current());
362 if (!class_rti.IsValid()) {
363 // He have loaded an unresolved class. Don't bother bounding the type.
364 return;
365 }
366 }
Calin Juravleb3306642015-04-20 18:30:42 +0100367 // We only need to bound the type if we have uses in the relevant block.
368 // So start with null and create the HBoundType lazily, only if it's needed.
369 HBoundType* bound_type = nullptr;
370
Calin Juravleb1498f62015-02-16 13:13:29 +0000371 HInstruction* obj = instanceOf->InputAt(0);
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100372 if (obj->GetReferenceTypeInfo().IsExact() && !obj->IsPhi()) {
373 // This method is being called while doing a fixed-point calculation
374 // over phis. Non-phis instruction whose type is already known do
375 // not need to be bound to another type.
376 // Not that this also prevents replacing `HLoadClass` with a `HBoundType`.
377 // `HCheckCast` and `HInstanceOf` expect a `HLoadClass` as a second
378 // input.
379 return;
380 }
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100381 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
Calin Juravleb1498f62015-02-16 13:13:29 +0000382 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
383 HInstruction* user = it.Current()->GetUser();
384 if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100385 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000386 ScopedObjectAccess soa(Thread::Current());
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000387 HInstruction* insert_point = instanceOfTrueBlock->GetFirstInstruction();
388 if (ShouldCreateBoundType(insert_point, obj, class_rti, nullptr, instanceOfTrueBlock)) {
David Brazdilf5552582015-12-27 13:36:12 +0000389 bound_type = new (graph_->GetArena()) HBoundType(obj);
390 bound_type->SetUpperBound(class_rti, /* InstanceOf fails for null. */ false);
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000391 instanceOfTrueBlock->InsertInstructionBefore(bound_type, insert_point);
392 } else {
393 // We already have a bound type on the position we would need to insert
394 // the new one. The existing bound type should dominate all the users
395 // (dchecked) so there's no need to continue.
396 break;
Calin Juravleb3306642015-04-20 18:30:42 +0100397 }
Calin Juravleb3306642015-04-20 18:30:42 +0100398 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000399 user->ReplaceInput(bound_type, it.Current()->GetIndex());
400 }
401 }
Calin Juravleacf735c2015-02-12 15:25:22 +0000402}
403
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000404void ReferenceTypePropagation::RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
405 mirror::Class* klass,
406 bool is_exact) {
Calin Juravle2e768302015-07-28 14:41:11 +0000407 if (instr->IsInvokeStaticOrDirect() && instr->AsInvokeStaticOrDirect()->IsStringInit()) {
408 // Calls to String.<init> are replaced with a StringFactory.
409 if (kIsDebugBuild) {
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000410 HInvoke* invoke = instr->AsInvoke();
Calin Juravle2e768302015-07-28 14:41:11 +0000411 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000412 ScopedObjectAccess soa(Thread::Current());
413 StackHandleScope<2> hs(soa.Self());
414 Handle<mirror::DexCache> dex_cache(
415 hs.NewHandle(cl->FindDexCache(soa.Self(), invoke->GetDexFile(), false)));
416 // Use a null loader. We should probably use the compiling method's class loader,
417 // but then we would need to pass it to RTPVisitor just for this debug check. Since
418 // the method is from the String class, the null loader is good enough.
419 Handle<mirror::ClassLoader> loader;
Andreas Gampe42ef8ab2015-12-03 17:27:32 -0800420 ArtMethod* method = cl->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
Nicolas Geoffrayc89715c2015-10-28 12:06:25 +0000421 invoke->GetDexFile(), invoke->GetDexMethodIndex(), dex_cache, loader, nullptr, kDirect);
Calin Juravle2e768302015-07-28 14:41:11 +0000422 DCHECK(method != nullptr);
423 mirror::Class* declaring_class = method->GetDeclaringClass();
424 DCHECK(declaring_class != nullptr);
425 DCHECK(declaring_class->IsStringClass())
426 << "Expected String class: " << PrettyDescriptor(declaring_class);
427 DCHECK(method->IsConstructor())
428 << "Expected String.<init>: " << PrettyMethod(method);
429 }
430 instr->SetReferenceTypeInfo(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000431 ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000432 } else if (klass != nullptr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100433 ScopedObjectAccess soa(Thread::Current());
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000434 ReferenceTypeInfo::TypeHandle handle = handle_cache_->NewHandle(klass);
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000435 is_exact = is_exact || handle->CannotBeAssignedFromOtherTypes();
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100436 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
Calin Juravle2e768302015-07-28 14:41:11 +0000437 } else {
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000438 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100439 }
440}
441
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000442void ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
443 uint16_t type_idx,
444 const DexFile& dex_file,
445 bool is_exact) {
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100446 DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
447
Calin Juravleacf735c2015-02-12 15:25:22 +0000448 ScopedObjectAccess soa(Thread::Current());
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700449 mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(
450 soa.Self(), dex_file, false);
Calin Juravleacf735c2015-02-12 15:25:22 +0000451 // Get type from dex cache assuming it was populated by the verifier.
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100452 SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact);
Calin Juravleacf735c2015-02-12 15:25:22 +0000453}
454
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000455void ReferenceTypePropagation::RTPVisitor::VisitNewInstance(HNewInstance* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100456 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100457}
458
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000459void ReferenceTypePropagation::RTPVisitor::VisitNewArray(HNewArray* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100460 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100461}
462
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000463static mirror::Class* GetClassFromDexCache(Thread* self, const DexFile& dex_file, uint16_t type_idx)
464 SHARED_REQUIRES(Locks::mutator_lock_) {
465 mirror::DexCache* dex_cache =
David Brazdild9510df2015-11-04 23:30:22 +0000466 Runtime::Current()->GetClassLinker()->FindDexCache(self, dex_file, /* allow_failure */ true);
467 if (dex_cache == nullptr) {
468 // Dex cache could not be found. This should only happen during gtests.
469 return nullptr;
470 }
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000471 // Get type from dex cache assuming it was populated by the verifier.
472 return dex_cache->GetResolvedType(type_idx);
473}
474
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000475void ReferenceTypePropagation::RTPVisitor::VisitParameterValue(HParameterValue* instr) {
Nicolas Geoffraye418dda2015-08-11 20:03:09 -0700476 ScopedObjectAccess soa(Thread::Current());
477 // We check if the existing type is valid: the inliner may have set it.
478 if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) {
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000479 mirror::Class* resolved_class =
480 GetClassFromDexCache(soa.Self(), instr->GetDexFile(), instr->GetTypeIndex());
481 SetClassAsTypeInfo(instr, resolved_class, /* is_exact */ false);
Calin Juravle2e768302015-07-28 14:41:11 +0000482 }
483}
484
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000485void ReferenceTypePropagation::RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
486 const FieldInfo& info) {
David Brazdild9510df2015-11-04 23:30:22 +0000487 if (instr->GetType() != Primitive::kPrimNot) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100488 return;
489 }
490
491 ScopedObjectAccess soa(Thread::Current());
David Brazdild9510df2015-11-04 23:30:22 +0000492 mirror::Class* klass = nullptr;
493
494 // The field index is unknown only during tests.
495 if (info.GetFieldIndex() != kUnknownFieldIndex) {
496 ClassLinker* cl = Runtime::Current()->GetClassLinker();
497 ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), info.GetDexCache().Get());
498 // TODO: There are certain cases where we can't resolve the field.
499 // b/21914925 is open to keep track of a repro case for this issue.
500 if (field != nullptr) {
501 klass = field->GetType<false>();
502 }
503 }
504
Calin Juravle2e768302015-07-28 14:41:11 +0000505 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100506}
507
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000508void ReferenceTypePropagation::RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100509 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
510}
511
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000512void ReferenceTypePropagation::RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100513 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
514}
515
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000516void ReferenceTypePropagation::RTPVisitor::VisitUnresolvedInstanceFieldGet(
517 HUnresolvedInstanceFieldGet* instr) {
Calin Juravlee460d1d2015-09-29 04:52:17 +0100518 // TODO: Use descriptor to get the actual type.
519 if (instr->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000520 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Calin Juravlee460d1d2015-09-29 04:52:17 +0100521 }
522}
523
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000524void ReferenceTypePropagation::RTPVisitor::VisitUnresolvedStaticFieldGet(
525 HUnresolvedStaticFieldGet* instr) {
Calin Juravlee460d1d2015-09-29 04:52:17 +0100526 // TODO: Use descriptor to get the actual type.
527 if (instr->GetFieldType() == Primitive::kPrimNot) {
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000528 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Calin Juravlee460d1d2015-09-29 04:52:17 +0100529 }
530}
531
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000532void ReferenceTypePropagation::RTPVisitor::VisitLoadClass(HLoadClass* instr) {
Calin Juravleacf735c2015-02-12 15:25:22 +0000533 ScopedObjectAccess soa(Thread::Current());
Calin Juravleacf735c2015-02-12 15:25:22 +0000534 // Get type from dex cache assuming it was populated by the verifier.
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000535 mirror::Class* resolved_class =
536 GetClassFromDexCache(soa.Self(), instr->GetDexFile(), instr->GetTypeIndex());
Calin Juravle98893e12015-10-02 21:05:03 +0100537 if (resolved_class != nullptr) {
538 instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000539 handle_cache_->NewHandle(resolved_class), /* is_exact */ true));
Calin Juravle98893e12015-10-02 21:05:03 +0100540 }
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000541 instr->SetReferenceTypeInfo(
542 ReferenceTypeInfo::Create(handle_cache_->GetClassClassHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000543}
544
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000545void ReferenceTypePropagation::RTPVisitor::VisitClinitCheck(HClinitCheck* instr) {
Calin Juravle2e768302015-07-28 14:41:11 +0000546 instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
547}
548
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000549void ReferenceTypePropagation::RTPVisitor::VisitLoadString(HLoadString* instr) {
550 instr->SetReferenceTypeInfo(
551 ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
Calin Juravle2e768302015-07-28 14:41:11 +0000552}
553
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000554void ReferenceTypePropagation::RTPVisitor::VisitLoadException(HLoadException* instr) {
David Brazdilbbd733e2015-08-18 17:48:17 +0100555 DCHECK(instr->GetBlock()->IsCatchBlock());
556 TryCatchInformation* catch_info = instr->GetBlock()->GetTryCatchInformation();
557
558 if (catch_info->IsCatchAllTypeIndex()) {
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000559 instr->SetReferenceTypeInfo(
560 ReferenceTypeInfo::Create(handle_cache_->GetThrowableClassHandle(), /* is_exact */ false));
David Brazdilbbd733e2015-08-18 17:48:17 +0100561 } else {
562 UpdateReferenceTypeInfo(instr,
563 catch_info->GetCatchTypeIndex(),
564 catch_info->GetCatchDexFile(),
565 /* is_exact */ false);
566 }
567}
568
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000569void ReferenceTypePropagation::RTPVisitor::VisitNullCheck(HNullCheck* instr) {
Calin Juravle2e768302015-07-28 14:41:11 +0000570 ScopedObjectAccess soa(Thread::Current());
571 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
David Brazdilfe860702015-12-02 09:06:57 +0000572 if (parent_rti.IsValid()) {
573 instr->SetReferenceTypeInfo(parent_rti);
574 }
Calin Juravle2e768302015-07-28 14:41:11 +0000575}
576
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000577void ReferenceTypePropagation::RTPVisitor::VisitBoundType(HBoundType* instr) {
David Brazdilf5552582015-12-27 13:36:12 +0000578 ScopedObjectAccess soa(Thread::Current());
579
580 ReferenceTypeInfo class_rti = instr->GetUpperBound();
581 if (class_rti.IsValid()) {
582 // Narrow the type as much as possible.
583 HInstruction* obj = instr->InputAt(0);
584 ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo();
585 if (class_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes()) {
586 instr->SetReferenceTypeInfo(
587 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ true));
David Brazdil744a1c62015-12-28 10:53:34 +0000588 } else if (obj_rti.IsValid()) {
589 if (class_rti.IsSupertypeOf(obj_rti)) {
590 // Object type is more specific.
591 instr->SetReferenceTypeInfo(obj_rti);
592 } else {
593 // Upper bound is more specific.
594 instr->SetReferenceTypeInfo(
595 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
596 }
David Brazdilf5552582015-12-27 13:36:12 +0000597 } else {
David Brazdil744a1c62015-12-28 10:53:34 +0000598 // Object not typed yet. Leave BoundType untyped for now rather than
599 // assign the type conservatively.
David Brazdilf5552582015-12-27 13:36:12 +0000600 }
601 instr->SetCanBeNull(obj->CanBeNull() && instr->GetUpperCanBeNull());
602 } else {
603 // The owner of the BoundType was already visited. If the class is unresolved,
604 // the BoundType should have been removed from the data flow and this method
605 // should remove it from the graph.
606 DCHECK(!instr->HasUses());
607 instr->GetBlock()->RemoveInstruction(instr);
608 }
609}
610
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000611void ReferenceTypePropagation::RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
David Brazdilf5552582015-12-27 13:36:12 +0000612 ScopedObjectAccess soa(Thread::Current());
613
Calin Juravle98893e12015-10-02 21:05:03 +0100614 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
615 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
David Brazdilf5552582015-12-27 13:36:12 +0000616 HBoundType* bound_type = check_cast->GetNext()->AsBoundType();
617 if (bound_type == nullptr || bound_type->GetUpperBound().IsValid()) {
618 // The next instruction is not an uninitialized BoundType. This must be
619 // an RTP pass after SsaBuilder and we do not need to do anything.
620 return;
Calin Juravle98893e12015-10-02 21:05:03 +0100621 }
David Brazdilf5552582015-12-27 13:36:12 +0000622 DCHECK_EQ(bound_type->InputAt(0), check_cast->InputAt(0));
623
624 if (class_rti.IsValid()) {
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000625 DCHECK(is_first_run_);
David Brazdilf5552582015-12-27 13:36:12 +0000626 // This is the first run of RTP and class is resolved.
627 bound_type->SetUpperBound(class_rti, /* CheckCast succeeds for nulls. */ true);
628 } else {
629 // This is the first run of RTP and class is unresolved. Remove the binding.
630 // The instruction itself is removed in VisitBoundType so as to not
631 // invalidate HInstructionIterator.
632 bound_type->ReplaceWith(bound_type->InputAt(0));
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000633 }
634}
635
Calin Juravleb1498f62015-02-16 13:13:29 +0000636void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
David Brazdild9510df2015-11-04 23:30:22 +0000637 if (phi->IsDead() || phi->GetType() != Primitive::kPrimNot) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000638 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000639 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000640
641 if (phi->GetBlock()->IsLoopHeader()) {
Nicolas Geoffrayd9994f02016-02-11 17:35:55 +0000642 if (!is_first_run_ && graph_->IsCompilingOsr()) {
643 // Don't update the type of a loop phi when compiling OSR: we may have done
644 // speculative optimizations dominating that phi, that do not hold at the
645 // point the interpreter jumps to that loop header.
646 return;
647 }
David Brazdilfe860702015-12-02 09:06:57 +0000648 ScopedObjectAccess soa(Thread::Current());
Calin Juravleb1498f62015-02-16 13:13:29 +0000649 // Set the initial type for the phi. Use the non back edge input for reaching
650 // a fixed point faster.
David Brazdilfe860702015-12-02 09:06:57 +0000651 HInstruction* first_input = phi->InputAt(0);
652 ReferenceTypeInfo first_input_rti = first_input->GetReferenceTypeInfo();
653 if (first_input_rti.IsValid() && !first_input->IsNullConstant()) {
654 phi->SetCanBeNull(first_input->CanBeNull());
655 phi->SetReferenceTypeInfo(first_input_rti);
656 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000657 AddToWorklist(phi);
Calin Juravle10e244f2015-01-26 18:54:32 +0000658 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000659 // Eagerly compute the type of the phi, for quicker convergence. Note
660 // that we don't need to add users to the worklist because we are
661 // doing a reverse post-order visit, therefore either the phi users are
662 // non-loop phi and will be visited later in the visit, or are loop-phis,
663 // and they are already in the work list.
664 UpdateNullability(phi);
665 UpdateReferenceTypeInfo(phi);
666 }
667}
668
669ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
670 const ReferenceTypeInfo& b) {
Calin Juravle2e768302015-07-28 14:41:11 +0000671 if (!b.IsValid()) {
672 return a;
673 }
674 if (!a.IsValid()) {
675 return b;
Calin Juravle20e60712015-07-01 18:41:04 +0100676 }
677
Calin Juravle2e768302015-07-28 14:41:11 +0000678 bool is_exact = a.IsExact() && b.IsExact();
Calin Juravle52503d82015-11-11 16:58:31 +0000679 ReferenceTypeInfo::TypeHandle result_type_handle;
680 ReferenceTypeInfo::TypeHandle a_type_handle = a.GetTypeHandle();
681 ReferenceTypeInfo::TypeHandle b_type_handle = b.GetTypeHandle();
682 bool a_is_interface = a_type_handle->IsInterface();
683 bool b_is_interface = b_type_handle->IsInterface();
Calin Juravle2e768302015-07-28 14:41:11 +0000684
685 if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
Calin Juravle52503d82015-11-11 16:58:31 +0000686 result_type_handle = a_type_handle;
Calin Juravle2e768302015-07-28 14:41:11 +0000687 } else if (a.IsSupertypeOf(b)) {
Calin Juravle52503d82015-11-11 16:58:31 +0000688 result_type_handle = a_type_handle;
Calin Juravle2e768302015-07-28 14:41:11 +0000689 is_exact = false;
690 } else if (b.IsSupertypeOf(a)) {
Calin Juravle52503d82015-11-11 16:58:31 +0000691 result_type_handle = b_type_handle;
692 is_exact = false;
693 } else if (!a_is_interface && !b_is_interface) {
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000694 result_type_handle =
695 handle_cache_.NewHandle(a_type_handle->GetCommonSuperClass(b_type_handle));
Calin Juravle2e768302015-07-28 14:41:11 +0000696 is_exact = false;
697 } else {
Calin Juravle52503d82015-11-11 16:58:31 +0000698 // This can happen if:
699 // - both types are interfaces. TODO(calin): implement
700 // - one is an interface, the other a class, and the type does not implement the interface
701 // e.g:
702 // void foo(Interface i, boolean cond) {
703 // Object o = cond ? i : new Object();
704 // }
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000705 result_type_handle = handle_cache_.GetObjectClassHandle();
Calin Juravle2e768302015-07-28 14:41:11 +0000706 is_exact = false;
707 }
708
Calin Juravle52503d82015-11-11 16:58:31 +0000709 return ReferenceTypeInfo::Create(result_type_handle, is_exact);
Calin Juravle2e768302015-07-28 14:41:11 +0000710}
711
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000712void ReferenceTypePropagation::UpdateArrayGet(HArrayGet* instr, HandleCache* handle_cache) {
Calin Juravle2e768302015-07-28 14:41:11 +0000713 DCHECK_EQ(Primitive::kPrimNot, instr->GetType());
714
715 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
David Brazdilfe860702015-12-02 09:06:57 +0000716 if (!parent_rti.IsValid()) {
717 return;
718 }
Calin Juravle2e768302015-07-28 14:41:11 +0000719
720 Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
721 if (handle->IsObjectArrayClass()) {
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000722 ReferenceTypeInfo::TypeHandle component_handle =
723 handle_cache->NewHandle(handle->GetComponentType());
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000724 bool is_exact = component_handle->CannotBeAssignedFromOtherTypes();
725 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(component_handle, is_exact));
Calin Juravle2e768302015-07-28 14:41:11 +0000726 } else {
727 // We don't know what the parent actually is, so we fallback to object.
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000728 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Calin Juravle2e768302015-07-28 14:41:11 +0000729 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000730}
731
732bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
733 ScopedObjectAccess soa(Thread::Current());
734
735 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
736 if (instr->IsBoundType()) {
737 UpdateBoundType(instr->AsBoundType());
738 } else if (instr->IsPhi()) {
739 UpdatePhi(instr->AsPhi());
Calin Juravle2e768302015-07-28 14:41:11 +0000740 } else if (instr->IsNullCheck()) {
741 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
742 if (parent_rti.IsValid()) {
743 instr->SetReferenceTypeInfo(parent_rti);
744 }
745 } else if (instr->IsArrayGet()) {
David Brazdilfe860702015-12-02 09:06:57 +0000746 // TODO: consider if it's worth "looking back" and binding the input object
Calin Juravle2e768302015-07-28 14:41:11 +0000747 // to an array type.
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000748 UpdateArrayGet(instr->AsArrayGet(), &handle_cache_);
Calin Juravleb1498f62015-02-16 13:13:29 +0000749 } else {
750 LOG(FATAL) << "Invalid instruction (should not get here)";
751 }
752
753 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
754}
755
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000756void ReferenceTypePropagation::RTPVisitor::VisitInvoke(HInvoke* instr) {
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100757 if (instr->GetType() != Primitive::kPrimNot) {
758 return;
759 }
760
761 ScopedObjectAccess soa(Thread::Current());
762 ClassLinker* cl = Runtime::Current()->GetClassLinker();
Mathieu Chartier673ed3d2015-08-28 14:56:43 -0700763 mirror::DexCache* dex_cache = cl->FindDexCache(soa.Self(), instr->GetDexFile());
Vladimir Marko05792b92015-08-03 11:56:49 +0100764 size_t pointer_size = cl->GetImagePointerSize();
765 ArtMethod* method = dex_cache->GetResolvedMethod(instr->GetDexMethodIndex(), pointer_size);
766 mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false, pointer_size);
Calin Juravle2e768302015-07-28 14:41:11 +0000767 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100768}
769
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000770void ReferenceTypePropagation::RTPVisitor::VisitArrayGet(HArrayGet* instr) {
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100771 if (instr->GetType() != Primitive::kPrimNot) {
772 return;
773 }
David Brazdilfe860702015-12-02 09:06:57 +0000774
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100775 ScopedObjectAccess soa(Thread::Current());
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000776 UpdateArrayGet(instr, handle_cache_);
Calin Juravle2e768302015-07-28 14:41:11 +0000777 if (!instr->GetReferenceTypeInfo().IsValid()) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100778 worklist_->push_back(instr);
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100779 }
780}
781
Calin Juravleb1498f62015-02-16 13:13:29 +0000782void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
783 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle2e768302015-07-28 14:41:11 +0000784 if (!new_rti.IsValid()) {
785 return; // No new info yet.
786 }
787
788 // Make sure that we don't go over the bounded type.
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000789 ReferenceTypeInfo upper_bound_rti = instr->GetUpperBound();
790 if (!upper_bound_rti.IsSupertypeOf(new_rti)) {
791 new_rti = upper_bound_rti;
Calin Juravleb1498f62015-02-16 13:13:29 +0000792 }
793 instr->SetReferenceTypeInfo(new_rti);
794}
795
Calin Juravle617bd922015-11-11 14:59:46 +0000796// NullConstant inputs are ignored during merging as they do not provide any useful information.
797// If all the inputs are NullConstants then the type of the phi will be set to Object.
Calin Juravleb1498f62015-02-16 13:13:29 +0000798void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
David Brazdild9510df2015-11-04 23:30:22 +0000799 DCHECK(instr->IsLive());
800
Calin Juravle617bd922015-11-11 14:59:46 +0000801 size_t input_count = instr->InputCount();
802 size_t first_input_index_not_null = 0;
803 while (first_input_index_not_null < input_count &&
804 instr->InputAt(first_input_index_not_null)->IsNullConstant()) {
805 first_input_index_not_null++;
806 }
807 if (first_input_index_not_null == input_count) {
808 // All inputs are NullConstants, set the type to object.
809 // This may happen in the presence of inlining.
Nicolas Geoffray18401b72016-03-11 13:35:51 +0000810 instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
Calin Juravle617bd922015-11-11 14:59:46 +0000811 return;
812 }
813
814 ReferenceTypeInfo new_rti = instr->InputAt(first_input_index_not_null)->GetReferenceTypeInfo();
815
Calin Juravle2e768302015-07-28 14:41:11 +0000816 if (new_rti.IsValid() && new_rti.IsObjectClass() && !new_rti.IsExact()) {
817 // Early return if we are Object and inexact.
Calin Juravleb1498f62015-02-16 13:13:29 +0000818 instr->SetReferenceTypeInfo(new_rti);
819 return;
820 }
Calin Juravle617bd922015-11-11 14:59:46 +0000821
822 for (size_t i = first_input_index_not_null + 1; i < input_count; i++) {
823 if (instr->InputAt(i)->IsNullConstant()) {
824 continue;
825 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000826 new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo());
Calin Juravle2e768302015-07-28 14:41:11 +0000827 if (new_rti.IsValid() && new_rti.IsObjectClass()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000828 if (!new_rti.IsExact()) {
829 break;
830 } else {
831 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000832 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000833 }
834 }
David Brazdilfe860702015-12-02 09:06:57 +0000835
836 if (new_rti.IsValid()) {
837 instr->SetReferenceTypeInfo(new_rti);
838 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000839}
840
841// Re-computes and updates the nullability of the instruction. Returns whether or
842// not the nullability was changed.
843bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
David Brazdild9510df2015-11-04 23:30:22 +0000844 DCHECK((instr->IsPhi() && instr->AsPhi()->IsLive())
Calin Juravle2e768302015-07-28 14:41:11 +0000845 || instr->IsBoundType()
846 || instr->IsNullCheck()
847 || instr->IsArrayGet());
848
849 if (!instr->IsPhi() && !instr->IsBoundType()) {
850 return false;
851 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000852
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000853 bool existing_can_be_null = instr->CanBeNull();
854 if (instr->IsPhi()) {
855 HPhi* phi = instr->AsPhi();
856 bool new_can_be_null = false;
857 for (size_t i = 0; i < phi->InputCount(); i++) {
858 if (phi->InputAt(i)->CanBeNull()) {
859 new_can_be_null = true;
860 break;
861 }
862 }
863 phi->SetCanBeNull(new_can_be_null);
864 } else if (instr->IsBoundType()) {
865 HBoundType* bound_type = instr->AsBoundType();
866 bound_type->SetCanBeNull(instr->InputAt(0)->CanBeNull() && bound_type->GetUpperCanBeNull());
Calin Juravleb1498f62015-02-16 13:13:29 +0000867 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000868 return existing_can_be_null != instr->CanBeNull();
Calin Juravle10e244f2015-01-26 18:54:32 +0000869}
870
871void ReferenceTypePropagation::ProcessWorklist() {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100872 while (!worklist_.empty()) {
873 HInstruction* instruction = worklist_.back();
874 worklist_.pop_back();
Calin Juravle12617592015-10-16 16:28:46 +0100875 bool updated_nullability = UpdateNullability(instruction);
876 bool updated_reference_type = UpdateReferenceTypeInfo(instruction);
877 if (updated_nullability || updated_reference_type) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000878 AddDependentInstructionsToWorklist(instruction);
879 }
880 }
881}
882
Calin Juravleb1498f62015-02-16 13:13:29 +0000883void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
Calin Juravle2e768302015-07-28 14:41:11 +0000884 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot)
885 << instruction->DebugName() << ":" << instruction->GetType();
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100886 worklist_.push_back(instruction);
Calin Juravle10e244f2015-01-26 18:54:32 +0000887}
888
Calin Juravleb1498f62015-02-16 13:13:29 +0000889void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000890 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000891 HInstruction* user = it.Current()->GetUser();
David Brazdild9510df2015-11-04 23:30:22 +0000892 if ((user->IsPhi() && user->AsPhi()->IsLive())
Calin Juravle2e768302015-07-28 14:41:11 +0000893 || user->IsBoundType()
894 || user->IsNullCheck()
895 || (user->IsArrayGet() && (user->GetType() == Primitive::kPrimNot))) {
Calin Juravlebeba9302015-07-08 15:57:18 +0000896 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000897 }
898 }
899}
Vladimir Marko7d1fbf32016-01-26 15:01:12 +0000900
Calin Juravle10e244f2015-01-26 18:54:32 +0000901} // namespace art