blob: 76b8d7eacfe98305b12c6421b8b31a85b51eec4e [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 Juravleb1498f62015-02-16 13:13:29 +000026// TODO: handle: a !=/== null.
Calin Juravleacf735c2015-02-12 15:25:22 +000027
28void ReferenceTypePropagation::Run() {
29 // To properly propagate type info we need to visit in the dominator-based order.
Calin Juravle10e244f2015-01-26 18:54:32 +000030 // Reverse post order guarantees a node's dominators are visited first.
31 // We take advantage of this order in `VisitBasicBlock`.
32 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
33 VisitBasicBlock(it.Current());
34 }
35 ProcessWorklist();
36}
37
Calin Juravleb1498f62015-02-16 13:13:29 +000038void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
39 // TODO: handle other instructions that give type info
40 // (NewArray/Call/Field accesses/array accesses)
Calin Juravle10e244f2015-01-26 18:54:32 +000041
Calin Juravleb1498f62015-02-16 13:13:29 +000042 // Initialize exact types first for faster convergence.
43 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
44 HInstruction* instr = it.Current();
45 if (instr->IsNewInstance()) {
46 VisitNewInstance(instr->AsNewInstance());
47 } else if (instr->IsLoadClass()) {
48 VisitLoadClass(instr->AsLoadClass());
49 }
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.
58 BoundTypeForIfInstanceOf(block);
Calin Juravle10e244f2015-01-26 18:54:32 +000059}
60
Calin Juravleb1498f62015-02-16 13:13:29 +000061// Detects if `block` is the True block for the pattern
62// `if (x instanceof ClassX) { }`
63// If that's the case insert an HBoundType instruction to bound the type of `x`
64// to `ClassX` in the scope of the dominated blocks.
65void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
66 HInstruction* lastInstruction = block->GetLastInstruction();
67 if (!lastInstruction->IsIf()) {
68 return;
69 }
70 HInstruction* ifInput = lastInstruction->InputAt(0);
71 // TODO: Handle more patterns here: HIf(bool) HIf(HNotEqual).
72 if (!ifInput->IsEqual()) {
73 return;
74 }
75 HInstruction* instanceOf = ifInput->InputAt(0);
76 HInstruction* comp_value = ifInput->InputAt(1);
77 if (!instanceOf->IsInstanceOf() || !comp_value->IsIntConstant()) {
78 return;
Calin Juravleacf735c2015-02-12 15:25:22 +000079 }
80
Calin Juravleb1498f62015-02-16 13:13:29 +000081 HInstruction* obj = instanceOf->InputAt(0);
82 HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
Calin Juravleacf735c2015-02-12 15:25:22 +000083
Calin Juravleb1498f62015-02-16 13:13:29 +000084 ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo();
85 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
86 HBoundType* bound_type = new (graph_->GetArena()) HBoundType(obj, class_rti);
Calin Juravleacf735c2015-02-12 15:25:22 +000087
Calin Juravleb1498f62015-02-16 13:13:29 +000088 // Narrow the type as much as possible.
89 {
90 ScopedObjectAccess soa(Thread::Current());
91 if (!load_class->IsResolved() || class_rti.IsSupertypeOf(obj_rti)) {
92 bound_type->SetReferenceTypeInfo(obj_rti);
Calin Juravleacf735c2015-02-12 15:25:22 +000093 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +000094 bound_type->SetReferenceTypeInfo(
95 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
Calin Juravleacf735c2015-02-12 15:25:22 +000096 }
97 }
98
Calin Juravleb1498f62015-02-16 13:13:29 +000099 block->InsertInstructionBefore(bound_type, lastInstruction);
100 // Pick the right successor based on the value we compare against.
101 HIntConstant* comp_value_int = comp_value->AsIntConstant();
102 HBasicBlock* instanceOfTrueBlock = comp_value_int->GetValue() == 0
103 ? lastInstruction->AsIf()->IfFalseSuccessor()
104 : lastInstruction->AsIf()->IfTrueSuccessor();
105
106 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
107 HInstruction* user = it.Current()->GetUser();
108 if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
109 user->ReplaceInput(bound_type, it.Current()->GetIndex());
110 }
111 }
Calin Juravleacf735c2015-02-12 15:25:22 +0000112}
113
114void ReferenceTypePropagation::VisitNewInstance(HNewInstance* instr) {
115 ScopedObjectAccess soa(Thread::Current());
116 mirror::DexCache* dex_cache = dex_compilation_unit_.GetClassLinker()->FindDexCache(dex_file_);
117 // Get type from dex cache assuming it was populated by the verifier.
118 mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
119 if (resolved_class != nullptr) {
120 MutableHandle<mirror::Class> handle = handles_->NewHandle(resolved_class);
Calin Juravleb1498f62015-02-16 13:13:29 +0000121 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, true));
Calin Juravleacf735c2015-02-12 15:25:22 +0000122 }
123}
124
125void ReferenceTypePropagation::VisitLoadClass(HLoadClass* instr) {
126 ScopedObjectAccess soa(Thread::Current());
127 mirror::DexCache* dex_cache = dex_compilation_unit_.GetClassLinker()->FindDexCache(dex_file_);
128 // Get type from dex cache assuming it was populated by the verifier.
129 mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
130 if (resolved_class != nullptr) {
131 Handle<mirror::Class> handle = handles_->NewHandle(resolved_class);
Calin Juravleb1498f62015-02-16 13:13:29 +0000132 instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(handle, /* is_exact */ true));
Calin Juravleacf735c2015-02-12 15:25:22 +0000133 }
134 Handle<mirror::Class> class_handle = handles_->NewHandle(mirror::Class::GetJavaLangClass());
Calin Juravleb1498f62015-02-16 13:13:29 +0000135 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(class_handle, /* is_exact */ true));
Calin Juravleacf735c2015-02-12 15:25:22 +0000136}
Calin Juravle10e244f2015-01-26 18:54:32 +0000137
Calin Juravleb1498f62015-02-16 13:13:29 +0000138void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
139 if (phi->GetType() != Primitive::kPrimNot) {
140 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000141 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000142
143 if (phi->GetBlock()->IsLoopHeader()) {
144 // Set the initial type for the phi. Use the non back edge input for reaching
145 // a fixed point faster.
146 AddToWorklist(phi);
147 phi->SetCanBeNull(phi->InputAt(0)->CanBeNull());
148 phi->SetReferenceTypeInfo(phi->InputAt(0)->GetReferenceTypeInfo());
Calin Juravle10e244f2015-01-26 18:54:32 +0000149 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000150 // Eagerly compute the type of the phi, for quicker convergence. Note
151 // that we don't need to add users to the worklist because we are
152 // doing a reverse post-order visit, therefore either the phi users are
153 // non-loop phi and will be visited later in the visit, or are loop-phis,
154 // and they are already in the work list.
155 UpdateNullability(phi);
156 UpdateReferenceTypeInfo(phi);
157 }
158}
159
160ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
161 const ReferenceTypeInfo& b) {
162 bool is_exact = a.IsExact() && b.IsExact();
163 bool is_top = a.IsTop() || b.IsTop();
164 Handle<mirror::Class> type_handle;
165
166 if (!is_top) {
167 if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
168 type_handle = a.GetTypeHandle();
169 } else if (a.IsSupertypeOf(b)) {
170 type_handle = a.GetTypeHandle();
171 is_exact = false;
172 } else if (b.IsSupertypeOf(a)) {
173 type_handle = b.GetTypeHandle();
174 is_exact = false;
175 } else {
176 // TODO: Find a common super class.
177 is_top = true;
178 is_exact = false;
179 }
180 }
181
182 return is_top
183 ? ReferenceTypeInfo::CreateTop(is_exact)
184 : ReferenceTypeInfo::Create(type_handle, is_exact);
185}
186
187bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
188 ScopedObjectAccess soa(Thread::Current());
189
190 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
191 if (instr->IsBoundType()) {
192 UpdateBoundType(instr->AsBoundType());
193 } else if (instr->IsPhi()) {
194 UpdatePhi(instr->AsPhi());
195 } else {
196 LOG(FATAL) << "Invalid instruction (should not get here)";
197 }
198
199 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
200}
201
202void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
203 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
204 // Be sure that we don't go over the bounded type.
205 ReferenceTypeInfo bound_rti = instr->GetBoundType();
206 if (!bound_rti.IsSupertypeOf(new_rti)) {
207 new_rti = bound_rti;
208 }
209 instr->SetReferenceTypeInfo(new_rti);
210}
211
212void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
213 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
214 if (new_rti.IsTop() && !new_rti.IsExact()) {
215 // Early return if we are Top and inexact.
216 instr->SetReferenceTypeInfo(new_rti);
217 return;
218 }
219 for (size_t i = 1; i < instr->InputCount(); i++) {
220 new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo());
221 if (new_rti.IsTop()) {
222 if (!new_rti.IsExact()) {
223 break;
224 } else {
225 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000226 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000227 }
228 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000229 instr->SetReferenceTypeInfo(new_rti);
230}
231
232// Re-computes and updates the nullability of the instruction. Returns whether or
233// not the nullability was changed.
234bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
235 DCHECK(instr->IsPhi() || instr->IsBoundType());
236
237 if (!instr->IsPhi()) {
238 return false;
239 }
240
241 HPhi* phi = instr->AsPhi();
242 bool existing_can_be_null = phi->CanBeNull();
243 bool new_can_be_null = false;
244 for (size_t i = 0; i < phi->InputCount(); i++) {
245 new_can_be_null |= phi->InputAt(i)->CanBeNull();
246 }
247 phi->SetCanBeNull(new_can_be_null);
248
249 return existing_can_be_null != new_can_be_null;
Calin Juravle10e244f2015-01-26 18:54:32 +0000250}
251
252void ReferenceTypePropagation::ProcessWorklist() {
253 while (!worklist_.IsEmpty()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000254 HInstruction* instruction = worklist_.Pop();
Calin Juravleacf735c2015-02-12 15:25:22 +0000255 if (UpdateNullability(instruction) || UpdateReferenceTypeInfo(instruction)) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000256 AddDependentInstructionsToWorklist(instruction);
257 }
258 }
259}
260
Calin Juravleb1498f62015-02-16 13:13:29 +0000261void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
262 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot) << instruction->GetType();
Calin Juravle10e244f2015-01-26 18:54:32 +0000263 worklist_.Add(instruction);
264}
265
Calin Juravleb1498f62015-02-16 13:13:29 +0000266void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000267 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000268 HInstruction* user = it.Current()->GetUser();
269 if (user->IsPhi() || user->IsBoundType()) {
270 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000271 }
272 }
273}
Calin Juravle10e244f2015-01-26 18:54:32 +0000274} // namespace art