blob: 91b2e6f9eaf690763e0d893407b63b669d26a45d [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
Calin Juravleacf735c2015-02-12 15:25:22 +000019#include "class_linker.h"
20#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
Calin Juravleacf735c2015-02-12 15:25:22 +000026void ReferenceTypePropagation::Run() {
27 // To properly propagate type info we need to visit in the dominator-based order.
Calin Juravle10e244f2015-01-26 18:54:32 +000028 // Reverse post order guarantees a node's dominators are visited first.
29 // We take advantage of this order in `VisitBasicBlock`.
30 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
31 VisitBasicBlock(it.Current());
32 }
33 ProcessWorklist();
34}
35
Calin Juravleb1498f62015-02-16 13:13:29 +000036void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
37 // TODO: handle other instructions that give type info
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +010038 // (Call/Field accesses/array accesses)
Calin Juravle10e244f2015-01-26 18:54:32 +000039
Calin Juravleb1498f62015-02-16 13:13:29 +000040 // Initialize exact types first for faster convergence.
41 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
42 HInstruction* instr = it.Current();
43 if (instr->IsNewInstance()) {
44 VisitNewInstance(instr->AsNewInstance());
45 } else if (instr->IsLoadClass()) {
46 VisitLoadClass(instr->AsLoadClass());
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +010047 } else if (instr->IsNewArray()) {
48 VisitNewArray(instr->AsNewArray());
Calin Juravleb1498f62015-02-16 13:13:29 +000049 }
50 }
51
52 // Handle Phis.
53 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
54 VisitPhi(it.Current()->AsPhi());
55 }
56
57 // Add extra nodes to bound types.
Calin Juravle61d544b2015-02-23 16:46:57 +000058 BoundTypeForIfNotNull(block);
Calin Juravleb1498f62015-02-16 13:13:29 +000059 BoundTypeForIfInstanceOf(block);
Calin Juravle10e244f2015-01-26 18:54:32 +000060}
61
Calin Juravle61d544b2015-02-23 16:46:57 +000062void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +010063 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
64 if (ifInstruction == nullptr) {
Calin Juravle61d544b2015-02-23 16:46:57 +000065 return;
66 }
Calin Juravleb3306642015-04-20 18:30:42 +010067 HInstruction* ifInput = ifInstruction->InputAt(0);
Calin Juravle61d544b2015-02-23 16:46:57 +000068 if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) {
69 return;
70 }
71 HInstruction* input0 = ifInput->InputAt(0);
72 HInstruction* input1 = ifInput->InputAt(1);
Calin Juravleedad8ad2015-04-23 14:34:33 +010073 HInstruction* obj = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +000074
Calin Juravleedad8ad2015-04-23 14:34:33 +010075 if (input1->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +000076 obj = input0;
Calin Juravleedad8ad2015-04-23 14:34:33 +010077 } else if (input0->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +000078 obj = input1;
79 } else {
80 return;
81 }
82
Calin Juravleb3306642015-04-20 18:30:42 +010083 // We only need to bound the type if we have uses in the relevant block.
84 // So start with null and create the HBoundType lazily, only if it's needed.
85 HBoundType* bound_type = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +000086 HBasicBlock* notNullBlock = ifInput->IsNotEqual()
Calin Juravleb3306642015-04-20 18:30:42 +010087 ? ifInstruction->IfTrueSuccessor()
88 : ifInstruction->IfFalseSuccessor();
89
Calin Juravle61d544b2015-02-23 16:46:57 +000090 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
91 HInstruction* user = it.Current()->GetUser();
92 if (notNullBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +010093 if (bound_type == nullptr) {
94 bound_type = new (graph_->GetArena()) HBoundType(obj, ReferenceTypeInfo::CreateTop(false));
95 notNullBlock->InsertInstructionBefore(bound_type, notNullBlock->GetFirstInstruction());
96 }
Calin Juravle61d544b2015-02-23 16:46:57 +000097 user->ReplaceInput(bound_type, it.Current()->GetIndex());
98 }
99 }
100}
101
Calin Juravleb1498f62015-02-16 13:13:29 +0000102// Detects if `block` is the True block for the pattern
103// `if (x instanceof ClassX) { }`
104// If that's the case insert an HBoundType instruction to bound the type of `x`
105// to `ClassX` in the scope of the dominated blocks.
106void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100107 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
108 if (ifInstruction == nullptr) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000109 return;
110 }
Calin Juravleb3306642015-04-20 18:30:42 +0100111 HInstruction* ifInput = ifInstruction->InputAt(0);
112 HInstruction* instanceOf = nullptr;
113 HBasicBlock* instanceOfTrueBlock = nullptr;
David Brazdil0d13fee2015-04-17 14:52:19 +0100114
Calin Juravleb3306642015-04-20 18:30:42 +0100115 // The instruction simplifier has transformed:
116 // - `if (a instanceof A)` into an HIf with an HInstanceOf input
117 // - `if (!(a instanceof A)` into an HIf with an HBooleanNot input (which in turn
118 // has an HInstanceOf input)
119 // So we should not see the usual HEqual here.
David Brazdil0d13fee2015-04-17 14:52:19 +0100120 if (ifInput->IsInstanceOf()) {
121 instanceOf = ifInput;
Calin Juravleb3306642015-04-20 18:30:42 +0100122 instanceOfTrueBlock = ifInstruction->IfTrueSuccessor();
David Brazdil0d13fee2015-04-17 14:52:19 +0100123 } else if (ifInput->IsBooleanNot() && ifInput->InputAt(0)->IsInstanceOf()) {
124 instanceOf = ifInput->InputAt(0);
Calin Juravleb3306642015-04-20 18:30:42 +0100125 instanceOfTrueBlock = ifInstruction->IfFalseSuccessor();
David Brazdil0d13fee2015-04-17 14:52:19 +0100126 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000127 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000128 }
129
Calin Juravleb3306642015-04-20 18:30:42 +0100130 // We only need to bound the type if we have uses in the relevant block.
131 // So start with null and create the HBoundType lazily, only if it's needed.
132 HBoundType* bound_type = nullptr;
133
Calin Juravleb1498f62015-02-16 13:13:29 +0000134 HInstruction* obj = instanceOf->InputAt(0);
Calin Juravleb1498f62015-02-16 13:13:29 +0000135 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
136 HInstruction* user = it.Current()->GetUser();
137 if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100138 if (bound_type == nullptr) {
139 HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
140
141 ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo();
142 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
143 bound_type = new (graph_->GetArena()) HBoundType(obj, class_rti);
144
145 // Narrow the type as much as possible.
146 {
147 ScopedObjectAccess soa(Thread::Current());
148 if (!load_class->IsResolved() || class_rti.IsSupertypeOf(obj_rti)) {
149 bound_type->SetReferenceTypeInfo(obj_rti);
150 } else {
151 bound_type->SetReferenceTypeInfo(
152 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
153 }
154 }
155
156 instanceOfTrueBlock->InsertInstructionBefore(
157 bound_type, instanceOfTrueBlock->GetFirstInstruction());
158 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000159 user->ReplaceInput(bound_type, it.Current()->GetIndex());
160 }
161 }
Calin Juravleacf735c2015-02-12 15:25:22 +0000162}
163
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100164void ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr,
165 uint16_t type_idx,
166 const DexFile& dex_file) {
167 DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
168
Calin Juravleacf735c2015-02-12 15:25:22 +0000169 ScopedObjectAccess soa(Thread::Current());
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100170 mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
Calin Juravleacf735c2015-02-12 15:25:22 +0000171 // Get type from dex cache assuming it was populated by the verifier.
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100172 mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
Calin Juravleacf735c2015-02-12 15:25:22 +0000173 if (resolved_class != nullptr) {
174 MutableHandle<mirror::Class> handle = handles_->NewHandle(resolved_class);
Calin Juravleb1498f62015-02-16 13:13:29 +0000175 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, true));
Calin Juravleacf735c2015-02-12 15:25:22 +0000176 }
177}
178
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100179void ReferenceTypePropagation::VisitNewInstance(HNewInstance* instr) {
180 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile());
181}
182
183void ReferenceTypePropagation::VisitNewArray(HNewArray* instr) {
184 UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile());
185}
186
Calin Juravleacf735c2015-02-12 15:25:22 +0000187void ReferenceTypePropagation::VisitLoadClass(HLoadClass* instr) {
188 ScopedObjectAccess soa(Thread::Current());
Nicolas Geoffrayd5111bf2015-05-22 15:37:09 +0100189 mirror::DexCache* dex_cache =
190 Runtime::Current()->GetClassLinker()->FindDexCache(instr->GetDexFile());
Calin Juravleacf735c2015-02-12 15:25:22 +0000191 // Get type from dex cache assuming it was populated by the verifier.
192 mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
193 if (resolved_class != nullptr) {
194 Handle<mirror::Class> handle = handles_->NewHandle(resolved_class);
Calin Juravleb1498f62015-02-16 13:13:29 +0000195 instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(handle, /* is_exact */ true));
Calin Juravleacf735c2015-02-12 15:25:22 +0000196 }
197 Handle<mirror::Class> class_handle = handles_->NewHandle(mirror::Class::GetJavaLangClass());
Calin Juravleb1498f62015-02-16 13:13:29 +0000198 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(class_handle, /* is_exact */ true));
Calin Juravleacf735c2015-02-12 15:25:22 +0000199}
Calin Juravle10e244f2015-01-26 18:54:32 +0000200
Calin Juravleb1498f62015-02-16 13:13:29 +0000201void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
202 if (phi->GetType() != Primitive::kPrimNot) {
203 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000204 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000205
206 if (phi->GetBlock()->IsLoopHeader()) {
207 // Set the initial type for the phi. Use the non back edge input for reaching
208 // a fixed point faster.
209 AddToWorklist(phi);
210 phi->SetCanBeNull(phi->InputAt(0)->CanBeNull());
211 phi->SetReferenceTypeInfo(phi->InputAt(0)->GetReferenceTypeInfo());
Calin Juravle10e244f2015-01-26 18:54:32 +0000212 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000213 // Eagerly compute the type of the phi, for quicker convergence. Note
214 // that we don't need to add users to the worklist because we are
215 // doing a reverse post-order visit, therefore either the phi users are
216 // non-loop phi and will be visited later in the visit, or are loop-phis,
217 // and they are already in the work list.
218 UpdateNullability(phi);
219 UpdateReferenceTypeInfo(phi);
220 }
221}
222
223ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
224 const ReferenceTypeInfo& b) {
225 bool is_exact = a.IsExact() && b.IsExact();
226 bool is_top = a.IsTop() || b.IsTop();
227 Handle<mirror::Class> type_handle;
228
229 if (!is_top) {
230 if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
231 type_handle = a.GetTypeHandle();
232 } else if (a.IsSupertypeOf(b)) {
233 type_handle = a.GetTypeHandle();
234 is_exact = false;
235 } else if (b.IsSupertypeOf(a)) {
236 type_handle = b.GetTypeHandle();
237 is_exact = false;
238 } else {
239 // TODO: Find a common super class.
240 is_top = true;
241 is_exact = false;
242 }
243 }
244
245 return is_top
246 ? ReferenceTypeInfo::CreateTop(is_exact)
247 : ReferenceTypeInfo::Create(type_handle, is_exact);
248}
249
250bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
251 ScopedObjectAccess soa(Thread::Current());
252
253 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
254 if (instr->IsBoundType()) {
255 UpdateBoundType(instr->AsBoundType());
256 } else if (instr->IsPhi()) {
257 UpdatePhi(instr->AsPhi());
258 } else {
259 LOG(FATAL) << "Invalid instruction (should not get here)";
260 }
261
262 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
263}
264
265void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
266 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
267 // Be sure that we don't go over the bounded type.
268 ReferenceTypeInfo bound_rti = instr->GetBoundType();
269 if (!bound_rti.IsSupertypeOf(new_rti)) {
270 new_rti = bound_rti;
271 }
272 instr->SetReferenceTypeInfo(new_rti);
273}
274
275void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
276 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
277 if (new_rti.IsTop() && !new_rti.IsExact()) {
278 // Early return if we are Top and inexact.
279 instr->SetReferenceTypeInfo(new_rti);
280 return;
281 }
282 for (size_t i = 1; i < instr->InputCount(); i++) {
283 new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo());
284 if (new_rti.IsTop()) {
285 if (!new_rti.IsExact()) {
286 break;
287 } else {
288 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000289 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000290 }
291 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000292 instr->SetReferenceTypeInfo(new_rti);
293}
294
295// Re-computes and updates the nullability of the instruction. Returns whether or
296// not the nullability was changed.
297bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
298 DCHECK(instr->IsPhi() || instr->IsBoundType());
299
300 if (!instr->IsPhi()) {
301 return false;
302 }
303
304 HPhi* phi = instr->AsPhi();
305 bool existing_can_be_null = phi->CanBeNull();
306 bool new_can_be_null = false;
307 for (size_t i = 0; i < phi->InputCount(); i++) {
308 new_can_be_null |= phi->InputAt(i)->CanBeNull();
309 }
310 phi->SetCanBeNull(new_can_be_null);
311
312 return existing_can_be_null != new_can_be_null;
Calin Juravle10e244f2015-01-26 18:54:32 +0000313}
314
315void ReferenceTypePropagation::ProcessWorklist() {
316 while (!worklist_.IsEmpty()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000317 HInstruction* instruction = worklist_.Pop();
Calin Juravleacf735c2015-02-12 15:25:22 +0000318 if (UpdateNullability(instruction) || UpdateReferenceTypeInfo(instruction)) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000319 AddDependentInstructionsToWorklist(instruction);
320 }
321 }
322}
323
Calin Juravleb1498f62015-02-16 13:13:29 +0000324void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
325 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot) << instruction->GetType();
Calin Juravle10e244f2015-01-26 18:54:32 +0000326 worklist_.Add(instruction);
327}
328
Calin Juravleb1498f62015-02-16 13:13:29 +0000329void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000330 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000331 HInstruction* user = it.Current()->GetUser();
332 if (user->IsPhi() || user->IsBoundType()) {
333 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000334 }
335 }
336}
Calin Juravle10e244f2015-01-26 18:54:32 +0000337} // namespace art