blob: 18c0564b18cfef1602c1562eec3e1c210ee6e235 [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 +000026// TODO: Only do the analysis on reference types. We currently have to handle
27// the `null` constant, that is represented as a `HIntConstant` and therefore
28// has the Primitive::kPrimInt type.
Calin Juravle10e244f2015-01-26 18:54:32 +000029
Calin Juravleacf735c2015-02-12 15:25:22 +000030// TODO: handle:
31// public Main ifNullTest(int count, Main a) {
32// Main m = new Main();
33// if (a == null) {
34// a = m;
35// }
36// return a.g();
37// }
38// public Main ifNotNullTest(Main a) {
39// if (a != null) {
40// return a.g();
41// }
42// return new Main();
43// }
44
45void ReferenceTypePropagation::Run() {
46 // To properly propagate type info we need to visit in the dominator-based order.
Calin Juravle10e244f2015-01-26 18:54:32 +000047 // Reverse post order guarantees a node's dominators are visited first.
48 // We take advantage of this order in `VisitBasicBlock`.
49 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
50 VisitBasicBlock(it.Current());
51 }
52 ProcessWorklist();
53}
54
55// Re-computes and updates the nullability of the instruction. Returns whether or
56// not the nullability was changed.
57bool ReferenceTypePropagation::UpdateNullability(HPhi* phi) {
58 bool existing_can_be_null = phi->CanBeNull();
59 bool new_can_be_null = false;
60 for (size_t i = 0; i < phi->InputCount(); i++) {
61 new_can_be_null |= phi->InputAt(i)->CanBeNull();
62 }
63 phi->SetCanBeNull(new_can_be_null);
64
65 return existing_can_be_null != new_can_be_null;
66}
67
Calin Juravleacf735c2015-02-12 15:25:22 +000068bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HPhi* phi) {
69 ScopedObjectAccess soa(Thread::Current());
70
71 ReferenceTypeInfo existing_rti = phi->GetReferenceTypeInfo();
72 ReferenceTypeInfo new_rti = phi->InputAt(0)->GetReferenceTypeInfo();
73
74 if (new_rti.IsTop() && !new_rti.IsExact()) {
75 // Early return if we are Top and inexact.
76 phi->SetReferenceTypeInfo(new_rti);
77 return !new_rti.IsEqual(existing_rti);;
78 }
79
80 for (size_t i = 1; i < phi->InputCount(); i++) {
81 ReferenceTypeInfo input_rti = phi->InputAt(i)->GetReferenceTypeInfo();
82
83 if (!input_rti.IsExact()) {
84 new_rti.SetInexact();
85 }
86
87 if (input_rti.IsTop()) {
88 new_rti.SetTop();
89 }
90
91 if (new_rti.IsTop()) {
92 if (!new_rti.IsExact()) {
93 break;
94 } else {
95 continue;
96 }
97 }
98
99 if (new_rti.GetTypeHandle().Get() == input_rti.GetTypeHandle().Get()) {
100 // nothing to do if we have the same type
101 } else if (input_rti.IsSupertypeOf(new_rti)) {
102 new_rti.SetTypeHandle(input_rti.GetTypeHandle(), false);
103 } else if (new_rti.IsSupertypeOf(input_rti)) {
104 new_rti.SetInexact();
105 } else {
106 // TODO: Find common parent.
107 new_rti.SetTop();
108 new_rti.SetInexact();
109 }
110 }
111
112 phi->SetReferenceTypeInfo(new_rti);
113 return !new_rti.IsEqual(existing_rti);
114}
115
116void ReferenceTypePropagation::VisitNewInstance(HNewInstance* instr) {
117 ScopedObjectAccess soa(Thread::Current());
118 mirror::DexCache* dex_cache = dex_compilation_unit_.GetClassLinker()->FindDexCache(dex_file_);
119 // Get type from dex cache assuming it was populated by the verifier.
120 mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
121 if (resolved_class != nullptr) {
122 MutableHandle<mirror::Class> handle = handles_->NewHandle(resolved_class);
123 instr->SetReferenceTypeInfo(ReferenceTypeInfo(handle, true));
124 }
125}
126
127void ReferenceTypePropagation::VisitLoadClass(HLoadClass* instr) {
128 ScopedObjectAccess soa(Thread::Current());
129 mirror::DexCache* dex_cache = dex_compilation_unit_.GetClassLinker()->FindDexCache(dex_file_);
130 // Get type from dex cache assuming it was populated by the verifier.
131 mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
132 if (resolved_class != nullptr) {
133 Handle<mirror::Class> handle = handles_->NewHandle(resolved_class);
134 instr->SetLoadedClassRTI(ReferenceTypeInfo(handle, true));
135 }
136 Handle<mirror::Class> class_handle = handles_->NewHandle(mirror::Class::GetJavaLangClass());
137 instr->SetReferenceTypeInfo(ReferenceTypeInfo(class_handle, true));
138}
Calin Juravle10e244f2015-01-26 18:54:32 +0000139
140void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
Calin Juravleacf735c2015-02-12 15:25:22 +0000141 // TODO: handle other instructions that give type info
142 // (NewArray/Call/Field accesses/array accesses)
143 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
144 HInstruction* instr = it.Current();
145 if (instr->IsNewInstance()) {
146 VisitNewInstance(instr->AsNewInstance());
147 } else if (instr->IsLoadClass()) {
148 VisitLoadClass(instr->AsLoadClass());
149 }
150 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000151 if (block->IsLoopHeader()) {
152 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
153 // Set the initial type for the phi. Use the non back edge input for reaching
154 // a fixed point faster.
155 HPhi* phi = it.Current()->AsPhi();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000156 if (phi->GetType() == Primitive::kPrimNot) {
157 AddToWorklist(phi);
158 phi->SetCanBeNull(phi->InputAt(0)->CanBeNull());
Calin Juravleacf735c2015-02-12 15:25:22 +0000159 phi->SetReferenceTypeInfo(phi->InputAt(0)->GetReferenceTypeInfo());
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000160 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000161 }
162 } else {
163 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
164 // Eagerly compute the type of the phi, for quicker convergence. Note
165 // that we don't need to add users to the worklist because we are
166 // doing a reverse post-order visit, therefore either the phi users are
167 // non-loop phi and will be visited later in the visit, or are loop-phis,
168 // and they are already in the work list.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000169 HPhi* phi = it.Current()->AsPhi();
170 if (phi->GetType() == Primitive::kPrimNot) {
171 UpdateNullability(phi);
Calin Juravleacf735c2015-02-12 15:25:22 +0000172 UpdateReferenceTypeInfo(phi);
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000173 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000174 }
175 }
176}
177
178void ReferenceTypePropagation::ProcessWorklist() {
179 while (!worklist_.IsEmpty()) {
180 HPhi* instruction = worklist_.Pop();
Calin Juravleacf735c2015-02-12 15:25:22 +0000181 if (UpdateNullability(instruction) || UpdateReferenceTypeInfo(instruction)) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000182 AddDependentInstructionsToWorklist(instruction);
183 }
184 }
185}
186
187void ReferenceTypePropagation::AddToWorklist(HPhi* instruction) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000188 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot);
Calin Juravle10e244f2015-01-26 18:54:32 +0000189 worklist_.Add(instruction);
190}
191
192void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HPhi* instruction) {
193 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
194 HPhi* phi = it.Current()->GetUser()->AsPhi();
195 if (phi != nullptr) {
196 AddToWorklist(phi);
197 }
198 }
199}
200
201} // namespace art