blob: 9d0d412f2895bc0c7fe210f46b1a5b88b9ec9b6a [file] [log] [blame]
Calin Juravle10e244f2015-01-26 18:54:32 +00001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "reference_type_propagation.h"
18
Mathieu Chartiere401d142015-04-22 13:56:20 -070019#include "class_linker-inl.h"
Calin Juravleacf735c2015-02-12 15:25:22 +000020#include "mirror/class-inl.h"
21#include "mirror/dex_cache.h"
22#include "scoped_thread_state_change.h"
23
Calin Juravle10e244f2015-01-26 18:54:32 +000024namespace art {
25
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010026class RTPVisitor : public HGraphDelegateVisitor {
27 public:
Calin Juravlebeba9302015-07-08 15:57:18 +000028 RTPVisitor(HGraph* graph, StackHandleScopeCollection* handles)
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010029 : HGraphDelegateVisitor(graph),
Calin Juravlebeba9302015-07-08 15:57:18 +000030 handles_(handles) {}
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010031
32 void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
33 void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
34 void VisitNewArray(HNewArray* instr) OVERRIDE;
35 void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
36 void SetClassAsTypeInfo(HInstruction* instr, mirror::Class* klass, bool is_exact);
37 void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE;
38 void VisitStaticFieldGet(HStaticFieldGet* instr) OVERRIDE;
39 void VisitInvoke(HInvoke* instr) OVERRIDE;
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +010040 void VisitArrayGet(HArrayGet* instr) OVERRIDE;
Calin Juravlea5ae3c32015-07-28 14:40:50 +000041 void VisitCheckCast(HCheckCast* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010042 void UpdateReferenceTypeInfo(HInstruction* instr,
43 uint16_t type_idx,
44 const DexFile& dex_file,
45 bool is_exact);
46
47 private:
48 StackHandleScopeCollection* handles_;
49};
50
Calin Juravleacf735c2015-02-12 15:25:22 +000051void ReferenceTypePropagation::Run() {
52 // To properly propagate type info we need to visit in the dominator-based order.
Calin Juravle10e244f2015-01-26 18:54:32 +000053 // Reverse post order guarantees a node's dominators are visited first.
54 // We take advantage of this order in `VisitBasicBlock`.
Calin Juravle6c0c4f22015-06-12 15:40:42 +000055 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
Calin Juravle10e244f2015-01-26 18:54:32 +000056 VisitBasicBlock(it.Current());
57 }
58 ProcessWorklist();
59}
60
Calin Juravleb1498f62015-02-16 13:13:29 +000061void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
Calin Juravlebeba9302015-07-08 15:57:18 +000062 // TODO: handle other instructions that give type info
63 // (array accesses)
64
65 RTPVisitor visitor(graph_, handles_);
Calin Juravleb1498f62015-02-16 13:13:29 +000066 // Initialize exact types first for faster convergence.
67 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
68 HInstruction* instr = it.Current();
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010069 instr->Accept(&visitor);
Calin Juravleb1498f62015-02-16 13:13:29 +000070 }
71
72 // Handle Phis.
73 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
74 VisitPhi(it.Current()->AsPhi());
75 }
76
77 // Add extra nodes to bound types.
Calin Juravle61d544b2015-02-23 16:46:57 +000078 BoundTypeForIfNotNull(block);
Calin Juravleb1498f62015-02-16 13:13:29 +000079 BoundTypeForIfInstanceOf(block);
Calin Juravle10e244f2015-01-26 18:54:32 +000080}
81
Calin Juravlea5ae3c32015-07-28 14:40:50 +000082// Create a bound type for the given object narrowing the type as much as possible.
83// The BoundType upper values for the super type and can_be_null will be taken from
84// load_class.GetLoadedClassRTI() and upper_can_be_null.
85static HBoundType* CreateBoundType(ArenaAllocator* arena,
86 HInstruction* obj,
87 HLoadClass* load_class,
88 bool upper_can_be_null)
89 SHARED_REQUIRES(Locks::mutator_lock_) {
90 ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo();
91 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
92 HBoundType* bound_type = new (arena) HBoundType(obj, class_rti, upper_can_be_null);
93 // Narrow the type as much as possible.
94 if (load_class->IsResolved() && class_rti.GetTypeHandle()->IsFinal()) {
95 bound_type->SetReferenceTypeInfo(
96 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ true));
97 } else if (!load_class->IsResolved() || class_rti.IsSupertypeOf(obj_rti)) {
98 bound_type->SetReferenceTypeInfo(obj_rti);
99 } else {
100 bound_type->SetReferenceTypeInfo(
101 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
102 }
103 return bound_type;
104}
105
106// Check if we should create a bound type for the given object at the specified
107// position. Because of inlining and the fact we run RTP more than once and we
108// might have a HBoundType already. If we do, we should not create a new one.
109// In this case we also assert that there are no other uses of the object (except
110// the bound type) dominated by the specified dominator_instr or dominator_block.
111static bool ShouldCreateBoundType(HInstruction* position,
112 HInstruction* obj,
113 ReferenceTypeInfo upper_bound,
114 HInstruction* dominator_instr,
115 HBasicBlock* dominator_block)
116 SHARED_REQUIRES(Locks::mutator_lock_) {
117 // If the position where we should insert the bound type is not already a
118 // a bound type then we need to create one.
119 if (position == nullptr || !position->IsBoundType()) {
120 return true;
121 }
122
123 HBoundType* existing_bound_type = position->AsBoundType();
124 if (existing_bound_type->GetUpperBound().IsSupertypeOf(upper_bound)) {
125 if (kIsDebugBuild) {
126 // Check that the existing HBoundType dominates all the uses.
127 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
128 HInstruction* user = it.Current()->GetUser();
129 if (dominator_instr != nullptr) {
130 DCHECK(!dominator_instr->StrictlyDominates(user)
131 || user == existing_bound_type
132 || existing_bound_type->StrictlyDominates(user));
133 } else if (dominator_block != nullptr) {
134 DCHECK(!dominator_block->Dominates(user->GetBlock())
135 || user == existing_bound_type
136 || existing_bound_type->StrictlyDominates(user));
137 }
138 }
139 }
140 } else {
141 // TODO: if the current bound type is a refinement we could update the
142 // existing_bound_type with the a new upper limit. However, we also need to
143 // update its users and have access to the work list.
144 }
145 return false;
146}
147
Calin Juravle61d544b2015-02-23 16:46:57 +0000148void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100149 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
150 if (ifInstruction == nullptr) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000151 return;
152 }
Calin Juravleb3306642015-04-20 18:30:42 +0100153 HInstruction* ifInput = ifInstruction->InputAt(0);
Calin Juravle61d544b2015-02-23 16:46:57 +0000154 if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) {
155 return;
156 }
157 HInstruction* input0 = ifInput->InputAt(0);
158 HInstruction* input1 = ifInput->InputAt(1);
Calin Juravleedad8ad2015-04-23 14:34:33 +0100159 HInstruction* obj = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000160
Calin Juravleedad8ad2015-04-23 14:34:33 +0100161 if (input1->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000162 obj = input0;
Calin Juravleedad8ad2015-04-23 14:34:33 +0100163 } else if (input0->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000164 obj = input1;
165 } else {
166 return;
167 }
168
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100169 if (!obj->CanBeNull() || obj->IsNullConstant()) {
170 // Null check is dead code and will be removed by DCE.
171 return;
172 }
173 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
174
Calin Juravleb3306642015-04-20 18:30:42 +0100175 // We only need to bound the type if we have uses in the relevant block.
176 // So start with null and create the HBoundType lazily, only if it's needed.
177 HBoundType* bound_type = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000178 HBasicBlock* notNullBlock = ifInput->IsNotEqual()
Calin Juravleb3306642015-04-20 18:30:42 +0100179 ? ifInstruction->IfTrueSuccessor()
180 : ifInstruction->IfFalseSuccessor();
181
Calin Juravle61d544b2015-02-23 16:46:57 +0000182 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
183 HInstruction* user = it.Current()->GetUser();
184 if (notNullBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100185 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000186 ScopedObjectAccess soa(Thread::Current());
187 HInstruction* insert_point = notNullBlock->GetFirstInstruction();
188 ReferenceTypeInfo object_rti = ReferenceTypeInfo::CreateTop(false);
189 if (ShouldCreateBoundType(insert_point, obj, object_rti, nullptr, notNullBlock)) {
190 bound_type = new (graph_->GetArena()) HBoundType(
191 obj, object_rti, /* bound_can_be_null */ false);
192 notNullBlock->InsertInstructionBefore(bound_type, insert_point);
193 } else {
194 // We already have a bound type on the position we would need to insert
195 // the new one. The existing bound type should dominate all the users
196 // (dchecked) so there's no need to continue.
197 break;
198 }
Calin Juravleb3306642015-04-20 18:30:42 +0100199 }
Calin Juravle61d544b2015-02-23 16:46:57 +0000200 user->ReplaceInput(bound_type, it.Current()->GetIndex());
201 }
202 }
203}
204
Calin Juravleb1498f62015-02-16 13:13:29 +0000205// Detects if `block` is the True block for the pattern
206// `if (x instanceof ClassX) { }`
207// If that's the case insert an HBoundType instruction to bound the type of `x`
208// to `ClassX` in the scope of the dominated blocks.
209void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100210 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
211 if (ifInstruction == nullptr) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000212 return;
213 }
Calin Juravleb3306642015-04-20 18:30:42 +0100214 HInstruction* ifInput = ifInstruction->InputAt(0);
215 HInstruction* instanceOf = nullptr;
216 HBasicBlock* instanceOfTrueBlock = nullptr;
David Brazdil0d13fee2015-04-17 14:52:19 +0100217
Calin Juravleb3306642015-04-20 18:30:42 +0100218 // The instruction simplifier has transformed:
219 // - `if (a instanceof A)` into an HIf with an HInstanceOf input
220 // - `if (!(a instanceof A)` into an HIf with an HBooleanNot input (which in turn
221 // has an HInstanceOf input)
222 // So we should not see the usual HEqual here.
David Brazdil0d13fee2015-04-17 14:52:19 +0100223 if (ifInput->IsInstanceOf()) {
224 instanceOf = ifInput;
Calin Juravleb3306642015-04-20 18:30:42 +0100225 instanceOfTrueBlock = ifInstruction->IfTrueSuccessor();
David Brazdil0d13fee2015-04-17 14:52:19 +0100226 } else if (ifInput->IsBooleanNot() && ifInput->InputAt(0)->IsInstanceOf()) {
227 instanceOf = ifInput->InputAt(0);
Calin Juravleb3306642015-04-20 18:30:42 +0100228 instanceOfTrueBlock = ifInstruction->IfFalseSuccessor();
David Brazdil0d13fee2015-04-17 14:52:19 +0100229 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000230 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000231 }
232
Calin Juravleb3306642015-04-20 18:30:42 +0100233 // We only need to bound the type if we have uses in the relevant block.
234 // So start with null and create the HBoundType lazily, only if it's needed.
235 HBoundType* bound_type = nullptr;
236
Calin Juravleb1498f62015-02-16 13:13:29 +0000237 HInstruction* obj = instanceOf->InputAt(0);
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100238 if (obj->GetReferenceTypeInfo().IsExact() && !obj->IsPhi()) {
239 // This method is being called while doing a fixed-point calculation
240 // over phis. Non-phis instruction whose type is already known do
241 // not need to be bound to another type.
242 // Not that this also prevents replacing `HLoadClass` with a `HBoundType`.
243 // `HCheckCast` and `HInstanceOf` expect a `HLoadClass` as a second
244 // input.
245 return;
246 }
Nicolas Geoffray7d5ea032015-07-02 15:48:27 +0100247 DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
Calin Juravleb1498f62015-02-16 13:13:29 +0000248 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
249 HInstruction* user = it.Current()->GetUser();
250 if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100251 if (bound_type == nullptr) {
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000252 ScopedObjectAccess soa(Thread::Current());
Calin Juravleb3306642015-04-20 18:30:42 +0100253 HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
Calin Juravleb3306642015-04-20 18:30:42 +0100254 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000255 HInstruction* insert_point = instanceOfTrueBlock->GetFirstInstruction();
256 if (ShouldCreateBoundType(insert_point, obj, class_rti, nullptr, instanceOfTrueBlock)) {
257 bound_type = CreateBoundType(
258 graph_->GetArena(),
259 obj,
260 load_class,
261 false /* InstanceOf ensures the object is not null. */);
262 instanceOfTrueBlock->InsertInstructionBefore(bound_type, insert_point);
263 } else {
264 // We already have a bound type on the position we would need to insert
265 // the new one. The existing bound type should dominate all the users
266 // (dchecked) so there's no need to continue.
267 break;
Calin Juravleb3306642015-04-20 18:30:42 +0100268 }
Calin Juravleb3306642015-04-20 18:30:42 +0100269 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000270 user->ReplaceInput(bound_type, it.Current()->GetIndex());
271 }
272 }
Calin Juravleacf735c2015-02-12 15:25:22 +0000273}
274
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100275void RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
276 mirror::Class* klass,
277 bool is_exact) {
Calin Juravlebeba9302015-07-08 15:57:18 +0000278 if (klass != nullptr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100279 ScopedObjectAccess soa(Thread::Current());
Calin Juravlebeba9302015-07-08 15:57:18 +0000280 MutableHandle<mirror::Class> handle = handles_->NewHandle(klass);
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100281 is_exact = is_exact || klass->IsFinal();
282 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100283 }
284}
285
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100286void RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
287 uint16_t type_idx,
288 const DexFile& dex_file,
289 bool is_exact) {
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100290 DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
291
Calin Juravleacf735c2015-02-12 15:25:22 +0000292 ScopedObjectAccess soa(Thread::Current());
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100293 mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
Calin Juravleacf735c2015-02-12 15:25:22 +0000294 // Get type from dex cache assuming it was populated by the verifier.
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100295 SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact);
Calin Juravleacf735c2015-02-12 15:25:22 +0000296}
297
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100298void RTPVisitor::VisitNewInstance(HNewInstance* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100299 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100300}
301
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100302void RTPVisitor::VisitNewArray(HNewArray* instr) {
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100303 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100304}
305
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100306void RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
307 const FieldInfo& info) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100308 // The field index is unknown only during tests.
309 if (instr->GetType() != Primitive::kPrimNot || info.GetFieldIndex() == kUnknownFieldIndex) {
310 return;
311 }
312
313 ScopedObjectAccess soa(Thread::Current());
314 ClassLinker* cl = Runtime::Current()->GetClassLinker();
315 mirror::DexCache* dex_cache = cl->FindDexCache(info.GetDexFile());
316 ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), dex_cache);
Calin Juravlebeba9302015-07-08 15:57:18 +0000317 if (field != nullptr) {
318 mirror::Class* klass = field->GetType<false>();
319 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
320 }
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100321}
322
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100323void RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100324 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
325}
326
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100327void RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100328 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
329}
330
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100331void RTPVisitor::VisitLoadClass(HLoadClass* instr) {
Calin Juravleacf735c2015-02-12 15:25:22 +0000332 ScopedObjectAccess soa(Thread::Current());
Nicolas Geoffrayd5111bf2015-05-22 15:37:09 +0100333 mirror::DexCache* dex_cache =
334 Runtime::Current()->GetClassLinker()->FindDexCache(instr->GetDexFile());
Calin Juravleacf735c2015-02-12 15:25:22 +0000335 // Get type from dex cache assuming it was populated by the verifier.
336 mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
Calin Juravlebeba9302015-07-08 15:57:18 +0000337 if (resolved_class != nullptr) {
338 Handle<mirror::Class> handle = handles_->NewHandle(resolved_class);
339 instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(handle, /* is_exact */ true));
Calin Juravleacf735c2015-02-12 15:25:22 +0000340 }
Calin Juravlebeba9302015-07-08 15:57:18 +0000341 Handle<mirror::Class> class_handle = handles_->NewHandle(mirror::Class::GetJavaLangClass());
342 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(class_handle, /* is_exact */ true));
Calin Juravleacf735c2015-02-12 15:25:22 +0000343}
Calin Juravle10e244f2015-01-26 18:54:32 +0000344
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000345void RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
346 HInstruction* obj = check_cast->InputAt(0);
347 HBoundType* bound_type = nullptr;
348 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
349 HInstruction* user = it.Current()->GetUser();
350 if (check_cast->StrictlyDominates(user)) {
351 if (bound_type == nullptr) {
352 ScopedObjectAccess soa(Thread::Current());
353 HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
354 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
355 if (ShouldCreateBoundType(check_cast->GetNext(), obj, class_rti, check_cast, nullptr)) {
356 bound_type = CreateBoundType(
357 GetGraph()->GetArena(),
358 obj,
359 load_class,
360 true /* CheckCast succeeds for nulls. */);
361 check_cast->GetBlock()->InsertInstructionAfter(bound_type, check_cast);
362 } else {
363 // We already have a bound type on the position we would need to insert
364 // the new one. The existing bound type should dominate all the users
365 // (dchecked) so there's no need to continue.
366 break;
367 }
368 }
369 user->ReplaceInput(bound_type, it.Current()->GetIndex());
370 }
371 }
372}
373
Calin Juravleb1498f62015-02-16 13:13:29 +0000374void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
375 if (phi->GetType() != Primitive::kPrimNot) {
376 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000377 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000378
379 if (phi->GetBlock()->IsLoopHeader()) {
380 // Set the initial type for the phi. Use the non back edge input for reaching
381 // a fixed point faster.
382 AddToWorklist(phi);
383 phi->SetCanBeNull(phi->InputAt(0)->CanBeNull());
384 phi->SetReferenceTypeInfo(phi->InputAt(0)->GetReferenceTypeInfo());
Calin Juravle10e244f2015-01-26 18:54:32 +0000385 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000386 // Eagerly compute the type of the phi, for quicker convergence. Note
387 // that we don't need to add users to the worklist because we are
388 // doing a reverse post-order visit, therefore either the phi users are
389 // non-loop phi and will be visited later in the visit, or are loop-phis,
390 // and they are already in the work list.
391 UpdateNullability(phi);
392 UpdateReferenceTypeInfo(phi);
393 }
394}
395
396ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
397 const ReferenceTypeInfo& b) {
Calin Juravle20e60712015-07-01 18:41:04 +0100398 bool is_exact = a.IsExact() && b.IsExact();
Calin Juravlebeba9302015-07-08 15:57:18 +0000399 bool is_top = a.IsTop() || b.IsTop();
Calin Juravle20e60712015-07-01 18:41:04 +0100400 Handle<mirror::Class> type_handle;
401
Calin Juravlebeba9302015-07-08 15:57:18 +0000402 if (!is_top) {
403 if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
404 type_handle = a.GetTypeHandle();
405 } else if (a.IsSupertypeOf(b)) {
406 type_handle = a.GetTypeHandle();
407 is_exact = false;
408 } else if (b.IsSupertypeOf(a)) {
409 type_handle = b.GetTypeHandle();
410 is_exact = false;
411 } else {
412 // TODO: Find a common super class.
413 is_top = true;
414 is_exact = false;
415 }
Calin Juravle20e60712015-07-01 18:41:04 +0100416 }
417
Calin Juravlebeba9302015-07-08 15:57:18 +0000418 return is_top
419 ? ReferenceTypeInfo::CreateTop(is_exact)
420 : ReferenceTypeInfo::Create(type_handle, is_exact);
Calin Juravleb1498f62015-02-16 13:13:29 +0000421}
422
423bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
424 ScopedObjectAccess soa(Thread::Current());
425
426 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
427 if (instr->IsBoundType()) {
428 UpdateBoundType(instr->AsBoundType());
429 } else if (instr->IsPhi()) {
430 UpdatePhi(instr->AsPhi());
431 } else {
432 LOG(FATAL) << "Invalid instruction (should not get here)";
433 }
434
435 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
436}
437
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100438void RTPVisitor::VisitInvoke(HInvoke* instr) {
439 if (instr->GetType() != Primitive::kPrimNot) {
440 return;
441 }
442
443 ScopedObjectAccess soa(Thread::Current());
444 ClassLinker* cl = Runtime::Current()->GetClassLinker();
445 mirror::DexCache* dex_cache = cl->FindDexCache(instr->GetDexFile());
446 ArtMethod* method = dex_cache->GetResolvedMethod(
447 instr->GetDexMethodIndex(), cl->GetImagePointerSize());
Calin Juravlebeba9302015-07-08 15:57:18 +0000448 if (method != nullptr) {
449 mirror::Class* klass = method->GetReturnType(false);
450 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
451 }
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100452}
453
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100454void RTPVisitor::VisitArrayGet(HArrayGet* instr) {
455 if (instr->GetType() != Primitive::kPrimNot) {
456 return;
457 }
Calin Juravlebeba9302015-07-08 15:57:18 +0000458
459 HInstruction* parent = instr->InputAt(0);
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100460 ScopedObjectAccess soa(Thread::Current());
Calin Juravlebeba9302015-07-08 15:57:18 +0000461 Handle<mirror::Class> handle = parent->GetReferenceTypeInfo().GetTypeHandle();
462 if (handle.GetReference() != nullptr && handle->IsObjectArrayClass()) {
463 SetClassAsTypeInfo(instr, handle->GetComponentType(), /* is_exact */ false);
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100464 }
465}
466
Calin Juravleb1498f62015-02-16 13:13:29 +0000467void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
468 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
469 // Be sure that we don't go over the bounded type.
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000470 ReferenceTypeInfo upper_bound_rti = instr->GetUpperBound();
471 if (!upper_bound_rti.IsSupertypeOf(new_rti)) {
472 new_rti = upper_bound_rti;
Calin Juravleb1498f62015-02-16 13:13:29 +0000473 }
474 instr->SetReferenceTypeInfo(new_rti);
475}
476
477void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
478 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravlebeba9302015-07-08 15:57:18 +0000479 if (new_rti.IsTop() && !new_rti.IsExact()) {
480 // Early return if we are Top and inexact.
Calin Juravleb1498f62015-02-16 13:13:29 +0000481 instr->SetReferenceTypeInfo(new_rti);
482 return;
483 }
484 for (size_t i = 1; i < instr->InputCount(); i++) {
485 new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo());
Calin Juravlebeba9302015-07-08 15:57:18 +0000486 if (new_rti.IsTop()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000487 if (!new_rti.IsExact()) {
488 break;
489 } else {
490 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000491 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000492 }
493 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000494 instr->SetReferenceTypeInfo(new_rti);
495}
496
497// Re-computes and updates the nullability of the instruction. Returns whether or
498// not the nullability was changed.
499bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
Calin Juravlebeba9302015-07-08 15:57:18 +0000500 DCHECK(instr->IsPhi() || instr->IsBoundType());
Calin Juravleb1498f62015-02-16 13:13:29 +0000501
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000502 bool existing_can_be_null = instr->CanBeNull();
503 if (instr->IsPhi()) {
504 HPhi* phi = instr->AsPhi();
505 bool new_can_be_null = false;
506 for (size_t i = 0; i < phi->InputCount(); i++) {
507 if (phi->InputAt(i)->CanBeNull()) {
508 new_can_be_null = true;
509 break;
510 }
511 }
512 phi->SetCanBeNull(new_can_be_null);
513 } else if (instr->IsBoundType()) {
514 HBoundType* bound_type = instr->AsBoundType();
515 bound_type->SetCanBeNull(instr->InputAt(0)->CanBeNull() && bound_type->GetUpperCanBeNull());
Calin Juravleb1498f62015-02-16 13:13:29 +0000516 }
Calin Juravlea5ae3c32015-07-28 14:40:50 +0000517 return existing_can_be_null != instr->CanBeNull();
Calin Juravle10e244f2015-01-26 18:54:32 +0000518}
519
520void ReferenceTypePropagation::ProcessWorklist() {
521 while (!worklist_.IsEmpty()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000522 HInstruction* instruction = worklist_.Pop();
Calin Juravleacf735c2015-02-12 15:25:22 +0000523 if (UpdateNullability(instruction) || UpdateReferenceTypeInfo(instruction)) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000524 AddDependentInstructionsToWorklist(instruction);
525 }
526 }
527}
528
Calin Juravleb1498f62015-02-16 13:13:29 +0000529void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
Calin Juravlebeba9302015-07-08 15:57:18 +0000530 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot) << instruction->GetType();
Calin Juravle10e244f2015-01-26 18:54:32 +0000531 worklist_.Add(instruction);
532}
533
Calin Juravleb1498f62015-02-16 13:13:29 +0000534void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000535 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000536 HInstruction* user = it.Current()->GetUser();
Calin Juravlebeba9302015-07-08 15:57:18 +0000537 if (user->IsPhi() || user->IsBoundType()) {
538 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000539 }
540 }
541}
Calin Juravle10e244f2015-01-26 18:54:32 +0000542} // namespace art