blob: e022d942b4c43b06b4eea3669fde14244a0420b1 [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 Juravle20e60712015-07-01 18:41:04 +010019#include "class_linker.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070020#include "class_linker-inl.h"
Calin Juravleacf735c2015-02-12 15:25:22 +000021#include "mirror/class-inl.h"
22#include "mirror/dex_cache.h"
23#include "scoped_thread_state_change.h"
24
Calin Juravle10e244f2015-01-26 18:54:32 +000025namespace art {
26
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010027class RTPVisitor : public HGraphDelegateVisitor {
28 public:
Calin Juravle20e60712015-07-01 18:41:04 +010029 RTPVisitor(HGraph* graph,
30 StackHandleScopeCollection* handles,
31 GrowableArray<HInstruction*>* worklist,
32 ReferenceTypeInfo::TypeHandle object_class_handle,
33 ReferenceTypeInfo::TypeHandle class_class_handle,
34 ReferenceTypeInfo::TypeHandle string_class_handle)
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010035 : HGraphDelegateVisitor(graph),
Calin Juravle20e60712015-07-01 18:41:04 +010036 handles_(handles),
37 object_class_handle_(object_class_handle),
38 class_class_handle_(class_class_handle),
39 string_class_handle_(string_class_handle),
40 worklist_(worklist) {}
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010041
Calin Juravle20e60712015-07-01 18:41:04 +010042 void VisitNullConstant(HNullConstant* null_constant) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010043 void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
44 void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
Calin Juravle20e60712015-07-01 18:41:04 +010045 void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE;
46 void VisitLoadString(HLoadString* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010047 void VisitNewArray(HNewArray* instr) OVERRIDE;
Calin Juravle20e60712015-07-01 18:41:04 +010048 void VisitParameterValue(HParameterValue* instr) OVERRIDE;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010049 void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
50 void SetClassAsTypeInfo(HInstruction* instr, mirror::Class* klass, bool is_exact);
51 void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE;
52 void VisitStaticFieldGet(HStaticFieldGet* instr) OVERRIDE;
53 void VisitInvoke(HInvoke* instr) OVERRIDE;
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +010054 void VisitArrayGet(HArrayGet* instr) OVERRIDE;
Calin Juravle20e60712015-07-01 18:41:04 +010055 void VisitNullCheck(HNullCheck* instr) OVERRIDE;
56
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010057 void UpdateReferenceTypeInfo(HInstruction* instr,
58 uint16_t type_idx,
59 const DexFile& dex_file,
60 bool is_exact);
61
62 private:
63 StackHandleScopeCollection* handles_;
Calin Juravle20e60712015-07-01 18:41:04 +010064 ReferenceTypeInfo::TypeHandle object_class_handle_;
65 ReferenceTypeInfo::TypeHandle class_class_handle_;
66 ReferenceTypeInfo::TypeHandle string_class_handle_;
67 GrowableArray<HInstruction*>* worklist_;
68
69 static constexpr size_t kDefaultWorklistSize = 8;
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +010070};
71
Calin Juravle20e60712015-07-01 18:41:04 +010072ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph,
73 StackHandleScopeCollection* handles)
74 : HOptimization(graph, kReferenceTypePropagationPassName),
75 handles_(handles),
76 worklist_(graph->GetArena(), kDefaultWorklistSize) {
77 ClassLinker* linker = Runtime::Current()->GetClassLinker();
78 object_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangObject));
79 string_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangString));
80 class_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangClass));
81
82 if (kIsDebugBuild) {
83 ScopedObjectAccess soa(Thread::Current());
84 DCHECK(ReferenceTypeInfo::IsValidHandle(object_class_handle_));
85 DCHECK(ReferenceTypeInfo::IsValidHandle(class_class_handle_));
86 DCHECK(ReferenceTypeInfo::IsValidHandle(string_class_handle_));
87 }
88}
89
Calin Juravleacf735c2015-02-12 15:25:22 +000090void ReferenceTypePropagation::Run() {
91 // To properly propagate type info we need to visit in the dominator-based order.
Calin Juravle10e244f2015-01-26 18:54:32 +000092 // Reverse post order guarantees a node's dominators are visited first.
93 // We take advantage of this order in `VisitBasicBlock`.
Calin Juravle6c0c4f22015-06-12 15:40:42 +000094 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
Calin Juravle10e244f2015-01-26 18:54:32 +000095 VisitBasicBlock(it.Current());
96 }
97 ProcessWorklist();
Calin Juravle20e60712015-07-01 18:41:04 +010098
99 if (kIsDebugBuild) {
100 // TODO: move this to the graph checker.
101 ScopedObjectAccess soa(Thread::Current());
102 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
103 HBasicBlock* block = it.Current();
104 for (HInstructionIterator iti(block->GetInstructions()); !iti.Done(); iti.Advance()) {
105 HInstruction* instr = iti.Current();
106 if (instr->GetType() == Primitive::kPrimNot) {
107 DCHECK(instr->GetReferenceTypeInfo().IsValid())
108 << "Invalid RTI for instruction: " << instr->DebugName();
109 }
110 }
111 }
112 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000113}
114
Calin Juravleb1498f62015-02-16 13:13:29 +0000115void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
Calin Juravle20e60712015-07-01 18:41:04 +0100116 RTPVisitor visitor(graph_,
117 handles_,
118 &worklist_,
119 object_class_handle_,
120 class_class_handle_,
121 string_class_handle_);
Calin Juravleb1498f62015-02-16 13:13:29 +0000122 // Initialize exact types first for faster convergence.
123 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
124 HInstruction* instr = it.Current();
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100125 instr->Accept(&visitor);
Calin Juravleb1498f62015-02-16 13:13:29 +0000126 }
127
128 // Handle Phis.
129 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
130 VisitPhi(it.Current()->AsPhi());
131 }
132
133 // Add extra nodes to bound types.
Calin Juravle61d544b2015-02-23 16:46:57 +0000134 BoundTypeForIfNotNull(block);
Calin Juravleb1498f62015-02-16 13:13:29 +0000135 BoundTypeForIfInstanceOf(block);
Calin Juravle10e244f2015-01-26 18:54:32 +0000136}
137
Calin Juravle61d544b2015-02-23 16:46:57 +0000138void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100139 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
140 if (ifInstruction == nullptr) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000141 return;
142 }
Calin Juravleb3306642015-04-20 18:30:42 +0100143 HInstruction* ifInput = ifInstruction->InputAt(0);
Calin Juravle61d544b2015-02-23 16:46:57 +0000144 if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) {
145 return;
146 }
147 HInstruction* input0 = ifInput->InputAt(0);
148 HInstruction* input1 = ifInput->InputAt(1);
Calin Juravleedad8ad2015-04-23 14:34:33 +0100149 HInstruction* obj = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000150
Calin Juravleedad8ad2015-04-23 14:34:33 +0100151 if (input1->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000152 obj = input0;
Calin Juravleedad8ad2015-04-23 14:34:33 +0100153 } else if (input0->IsNullConstant()) {
Calin Juravle61d544b2015-02-23 16:46:57 +0000154 obj = input1;
155 } else {
156 return;
157 }
158
Calin Juravleb3306642015-04-20 18:30:42 +0100159 // We only need to bound the type if we have uses in the relevant block.
160 // So start with null and create the HBoundType lazily, only if it's needed.
161 HBoundType* bound_type = nullptr;
Calin Juravle61d544b2015-02-23 16:46:57 +0000162 HBasicBlock* notNullBlock = ifInput->IsNotEqual()
Calin Juravleb3306642015-04-20 18:30:42 +0100163 ? ifInstruction->IfTrueSuccessor()
164 : ifInstruction->IfFalseSuccessor();
165
Calin Juravle61d544b2015-02-23 16:46:57 +0000166 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
167 HInstruction* user = it.Current()->GetUser();
168 if (notNullBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100169 if (bound_type == nullptr) {
Calin Juravle20e60712015-07-01 18:41:04 +0100170 bound_type = new (graph_->GetArena()) HBoundType(obj, obj->GetReferenceTypeInfo());
Calin Juravleb3306642015-04-20 18:30:42 +0100171 notNullBlock->InsertInstructionBefore(bound_type, notNullBlock->GetFirstInstruction());
172 }
Calin Juravle61d544b2015-02-23 16:46:57 +0000173 user->ReplaceInput(bound_type, it.Current()->GetIndex());
174 }
175 }
176}
177
Calin Juravleb1498f62015-02-16 13:13:29 +0000178// Detects if `block` is the True block for the pattern
179// `if (x instanceof ClassX) { }`
180// If that's the case insert an HBoundType instruction to bound the type of `x`
181// to `ClassX` in the scope of the dominated blocks.
182void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
Calin Juravleb3306642015-04-20 18:30:42 +0100183 HIf* ifInstruction = block->GetLastInstruction()->AsIf();
184 if (ifInstruction == nullptr) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000185 return;
186 }
Calin Juravleb3306642015-04-20 18:30:42 +0100187 HInstruction* ifInput = ifInstruction->InputAt(0);
188 HInstruction* instanceOf = nullptr;
189 HBasicBlock* instanceOfTrueBlock = nullptr;
David Brazdil0d13fee2015-04-17 14:52:19 +0100190
Calin Juravleb3306642015-04-20 18:30:42 +0100191 // The instruction simplifier has transformed:
192 // - `if (a instanceof A)` into an HIf with an HInstanceOf input
193 // - `if (!(a instanceof A)` into an HIf with an HBooleanNot input (which in turn
194 // has an HInstanceOf input)
195 // So we should not see the usual HEqual here.
David Brazdil0d13fee2015-04-17 14:52:19 +0100196 if (ifInput->IsInstanceOf()) {
197 instanceOf = ifInput;
Calin Juravleb3306642015-04-20 18:30:42 +0100198 instanceOfTrueBlock = ifInstruction->IfTrueSuccessor();
David Brazdil0d13fee2015-04-17 14:52:19 +0100199 } else if (ifInput->IsBooleanNot() && ifInput->InputAt(0)->IsInstanceOf()) {
200 instanceOf = ifInput->InputAt(0);
Calin Juravleb3306642015-04-20 18:30:42 +0100201 instanceOfTrueBlock = ifInstruction->IfFalseSuccessor();
David Brazdil0d13fee2015-04-17 14:52:19 +0100202 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000203 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000204 }
205
Calin Juravleb3306642015-04-20 18:30:42 +0100206 // We only need to bound the type if we have uses in the relevant block.
207 // So start with null and create the HBoundType lazily, only if it's needed.
208 HBoundType* bound_type = nullptr;
209
Calin Juravleb1498f62015-02-16 13:13:29 +0000210 HInstruction* obj = instanceOf->InputAt(0);
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100211 if (obj->GetReferenceTypeInfo().IsExact() && !obj->IsPhi()) {
212 // This method is being called while doing a fixed-point calculation
213 // over phis. Non-phis instruction whose type is already known do
214 // not need to be bound to another type.
215 // Not that this also prevents replacing `HLoadClass` with a `HBoundType`.
216 // `HCheckCast` and `HInstanceOf` expect a `HLoadClass` as a second
217 // input.
218 return;
219 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000220 for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
221 HInstruction* user = it.Current()->GetUser();
222 if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
Calin Juravleb3306642015-04-20 18:30:42 +0100223 if (bound_type == nullptr) {
224 HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
225
226 ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo();
227 ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
Calin Juravle6c0c4f22015-06-12 15:40:42 +0000228 bound_type = new (graph_->GetArena()) HBoundType(obj, class_rti);
Calin Juravleb3306642015-04-20 18:30:42 +0100229
230 // Narrow the type as much as possible.
231 {
232 ScopedObjectAccess soa(Thread::Current());
233 if (!load_class->IsResolved() || class_rti.IsSupertypeOf(obj_rti)) {
234 bound_type->SetReferenceTypeInfo(obj_rti);
235 } else {
236 bound_type->SetReferenceTypeInfo(
237 ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
238 }
239 }
240
241 instanceOfTrueBlock->InsertInstructionBefore(
242 bound_type, instanceOfTrueBlock->GetFirstInstruction());
243 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000244 user->ReplaceInput(bound_type, it.Current()->GetIndex());
245 }
246 }
Calin Juravleacf735c2015-02-12 15:25:22 +0000247}
248
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100249void RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
250 mirror::Class* klass,
251 bool is_exact) {
Calin Juravle20e60712015-07-01 18:41:04 +0100252 if (instr->IsInvokeStaticOrDirect() && instr->AsInvokeStaticOrDirect()->IsStringInit()) {
253 // Calls to String.<init> are replaced with a StringFactory.
254 if (kIsDebugBuild) {
255 ScopedObjectAccess soa(Thread::Current());
256 ClassLinker* cl = Runtime::Current()->GetClassLinker();
257 mirror::DexCache* dex_cache = cl->FindDexCache(instr->AsInvoke()->GetDexFile());
258 ArtMethod* method = dex_cache->GetResolvedMethod(
259 instr->AsInvoke()->GetDexMethodIndex(), cl->GetImagePointerSize());
260 DCHECK(method != nullptr);
261 mirror::Class* declaring_class = method->GetDeclaringClass();
262 DCHECK(declaring_class != nullptr);
263 DCHECK(declaring_class->IsStringClass())
264 << "Expected String class: " << PrettyDescriptor(declaring_class);
265 DCHECK(method->IsConstructor())
266 << "Expected String.<init>: " << PrettyMethod(method);
267 }
268 instr->SetReferenceTypeInfo(
269 ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
270 } else if (klass != nullptr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100271 ScopedObjectAccess soa(Thread::Current());
Calin Juravle20e60712015-07-01 18:41:04 +0100272 ReferenceTypeInfo::TypeHandle handle = handles_->NewHandle(klass);
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100273 is_exact = is_exact || klass->IsFinal();
274 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
Calin Juravle20e60712015-07-01 18:41:04 +0100275 } else {
276 instr->SetReferenceTypeInfo(
277 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100278 }
279}
280
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100281void RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
282 uint16_t type_idx,
283 const DexFile& dex_file,
284 bool is_exact) {
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100285 DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
286
Calin Juravleacf735c2015-02-12 15:25:22 +0000287 ScopedObjectAccess soa(Thread::Current());
Guillaume "Vermeille" Sanchez81d804a2015-05-20 12:42:25 +0100288 mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
Calin Juravleacf735c2015-02-12 15:25:22 +0000289 // Get type from dex cache assuming it was populated by the verifier.
Guillaume Sanchez222862c2015-06-09 18:33:02 +0100290 SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact);
Calin Juravleacf735c2015-02-12 15:25:22 +0000291}
292
Calin Juravle20e60712015-07-01 18:41:04 +0100293void RTPVisitor::VisitNullConstant(HNullConstant* instr) {
294 instr->SetReferenceTypeInfo(
295 ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
296}
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
Calin Juravle20e60712015-07-01 18:41:04 +0100306void RTPVisitor::VisitParameterValue(HParameterValue* instr) {
307 if (instr->GetType() == Primitive::kPrimNot) {
308 // TODO: parse the signature and add precise types for the parameters.
309 SetClassAsTypeInfo(instr, nullptr, /* is_exact */ false);
310 }
311}
312
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100313void RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
314 const FieldInfo& info) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100315 // The field index is unknown only during tests.
316 if (instr->GetType() != Primitive::kPrimNot || info.GetFieldIndex() == kUnknownFieldIndex) {
317 return;
318 }
319
320 ScopedObjectAccess soa(Thread::Current());
321 ClassLinker* cl = Runtime::Current()->GetClassLinker();
322 mirror::DexCache* dex_cache = cl->FindDexCache(info.GetDexFile());
323 ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), dex_cache);
Calin Juravle20e60712015-07-01 18:41:04 +0100324 // TODO: There are certain cases where we can't resolve the field.
325 // b/21914925 is open to keep track of a repro case for this issue.
326 mirror::Class* klass = (field == nullptr) ? nullptr : field->GetType<false>();
327 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100328}
329
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100330void RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100331 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
332}
333
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100334void RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) {
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100335 UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
336}
337
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100338void RTPVisitor::VisitLoadClass(HLoadClass* instr) {
Calin Juravleacf735c2015-02-12 15:25:22 +0000339 ScopedObjectAccess soa(Thread::Current());
Nicolas Geoffrayd5111bf2015-05-22 15:37:09 +0100340 mirror::DexCache* dex_cache =
341 Runtime::Current()->GetClassLinker()->FindDexCache(instr->GetDexFile());
Calin Juravleacf735c2015-02-12 15:25:22 +0000342 // Get type from dex cache assuming it was populated by the verifier.
343 mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
Calin Juravle20e60712015-07-01 18:41:04 +0100344 DCHECK(resolved_class != nullptr);
345 ReferenceTypeInfo::TypeHandle handle = handles_->NewHandle(resolved_class);
346 instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(handle, /* is_exact */ true));
347 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(class_class_handle_, /* is_exact */ true));
348}
349
350void RTPVisitor::VisitClinitCheck(HClinitCheck* instr) {
351 instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
352}
353
354void RTPVisitor::VisitLoadString(HLoadString* instr) {
355 instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
356}
357
358void RTPVisitor::VisitNullCheck(HNullCheck* instr) {
359 ScopedObjectAccess soa(Thread::Current());
360
361 HInstruction* parent = instr->InputAt(0);
362 ReferenceTypeInfo parent_rti = parent->GetReferenceTypeInfo();
363 if (!parent_rti.IsValid()) {
364 // Parent could be a Phi or an ArrayGet and we might not have any valid
365 // information on them at this point.
366 DCHECK(parent->IsPhi() || parent->IsArrayGet()) << parent->DebugName();
367 worklist_->Add(instr);
368 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000369 }
Calin Juravle20e60712015-07-01 18:41:04 +0100370 instr->SetReferenceTypeInfo(parent->GetReferenceTypeInfo());
Calin Juravleacf735c2015-02-12 15:25:22 +0000371}
Calin Juravle10e244f2015-01-26 18:54:32 +0000372
Calin Juravleb1498f62015-02-16 13:13:29 +0000373void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
374 if (phi->GetType() != Primitive::kPrimNot) {
375 return;
Calin Juravleacf735c2015-02-12 15:25:22 +0000376 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000377
378 if (phi->GetBlock()->IsLoopHeader()) {
379 // Set the initial type for the phi. Use the non back edge input for reaching
380 // a fixed point faster.
381 AddToWorklist(phi);
382 phi->SetCanBeNull(phi->InputAt(0)->CanBeNull());
383 phi->SetReferenceTypeInfo(phi->InputAt(0)->GetReferenceTypeInfo());
Calin Juravle10e244f2015-01-26 18:54:32 +0000384 } else {
Calin Juravleb1498f62015-02-16 13:13:29 +0000385 // Eagerly compute the type of the phi, for quicker convergence. Note
386 // that we don't need to add users to the worklist because we are
387 // doing a reverse post-order visit, therefore either the phi users are
388 // non-loop phi and will be visited later in the visit, or are loop-phis,
389 // and they are already in the work list.
390 UpdateNullability(phi);
391 UpdateReferenceTypeInfo(phi);
392 }
393}
394
395ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
396 const ReferenceTypeInfo& b) {
Calin Juravle20e60712015-07-01 18:41:04 +0100397 if (!b.IsValid()) {
398 return a;
399 }
400 if (!a.IsValid()) {
401 return b;
Calin Juravleb1498f62015-02-16 13:13:29 +0000402 }
403
Calin Juravle20e60712015-07-01 18:41:04 +0100404 bool is_exact = a.IsExact() && b.IsExact();
405 Handle<mirror::Class> type_handle;
406
407 if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
408 type_handle = a.GetTypeHandle();
409 } else if (a.IsSupertypeOf(b)) {
410 type_handle = a.GetTypeHandle();
411 is_exact = false;
412 } else if (b.IsSupertypeOf(a)) {
413 type_handle = b.GetTypeHandle();
414 is_exact = false;
415 } else {
416 // TODO: Find the first common super class.
417 type_handle = object_class_handle_;
418 is_exact = false;
419 }
420
421 return ReferenceTypeInfo::Create(type_handle, is_exact);
422}
423
424static void UpdateArrayGet(HArrayGet* instr,
425 StackHandleScopeCollection* handles,
426 ReferenceTypeInfo::TypeHandle object_class_handle)
427 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
428 DCHECK_EQ(Primitive::kPrimNot, instr->GetType());
429
430 HInstruction* array = instr->InputAt(0);
431 ReferenceTypeInfo parent_rti = array->GetReferenceTypeInfo();
432 if (!parent_rti.IsValid()) {
433 DCHECK(array->IsPhi() || array->IsNullCheck() || array->IsArrayGet());
434 // The array could be a Phi/NullCheck/ArrayGet for which we might have not have
435 // valid information at this point.
436 return;
437 }
438
439 Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
440 if (handle->IsObjectArrayClass()) {
441 ReferenceTypeInfo::TypeHandle component_handle = handles->NewHandle(handle->GetComponentType());
442 instr->SetReferenceTypeInfo(
443 ReferenceTypeInfo::Create(component_handle, /* is_exact */ false));
444 } else {
445 // We don't know what the parent actually is, so we fallback to object.
446 instr->SetReferenceTypeInfo(
447 ReferenceTypeInfo::Create(object_class_handle, /* is_exact */ false));
448 }
449
450 return;
Calin Juravleb1498f62015-02-16 13:13:29 +0000451}
452
453bool ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr) {
454 ScopedObjectAccess soa(Thread::Current());
455
456 ReferenceTypeInfo previous_rti = instr->GetReferenceTypeInfo();
457 if (instr->IsBoundType()) {
458 UpdateBoundType(instr->AsBoundType());
459 } else if (instr->IsPhi()) {
460 UpdatePhi(instr->AsPhi());
Calin Juravle20e60712015-07-01 18:41:04 +0100461 } else if (instr->IsNullCheck()) {
462 ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
463 if (parent_rti.IsValid()) {
464 instr->SetReferenceTypeInfo(parent_rti);
465 }
466 } else if (instr->IsArrayGet()) {
467 // TODO: consider if it's worth "looking back" and bounding the input object
468 // to an array type.
469 UpdateArrayGet(instr->AsArrayGet(), handles_, object_class_handle_);
Calin Juravleb1498f62015-02-16 13:13:29 +0000470 } else {
471 LOG(FATAL) << "Invalid instruction (should not get here)";
472 }
473
474 return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
475}
476
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100477void RTPVisitor::VisitInvoke(HInvoke* instr) {
478 if (instr->GetType() != Primitive::kPrimNot) {
479 return;
480 }
481
482 ScopedObjectAccess soa(Thread::Current());
483 ClassLinker* cl = Runtime::Current()->GetClassLinker();
484 mirror::DexCache* dex_cache = cl->FindDexCache(instr->GetDexFile());
485 ArtMethod* method = dex_cache->GetResolvedMethod(
486 instr->GetDexMethodIndex(), cl->GetImagePointerSize());
Calin Juravle20e60712015-07-01 18:41:04 +0100487 mirror::Class* klass = method == nullptr ? nullptr : method->GetReturnType(false);
488 SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
Guillaume "Vermeille" Sanchezae09d2d2015-05-29 10:52:55 +0100489}
490
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100491void RTPVisitor::VisitArrayGet(HArrayGet* instr) {
492 if (instr->GetType() != Primitive::kPrimNot) {
493 return;
494 }
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100495 ScopedObjectAccess soa(Thread::Current());
Calin Juravle20e60712015-07-01 18:41:04 +0100496 UpdateArrayGet(instr, handles_, object_class_handle_);
497 if (!instr->GetReferenceTypeInfo().IsValid()) {
498 // If the RTI is not valid it means it depends on instruction for which we
499 // don't have the final information before the fix point iteration. So we
500 // need to add it to the worklist.
501 worklist_->Add(instr);
Guillaume "Vermeille" Sanchez72a5eb52015-06-02 17:39:45 +0100502 }
503}
504
Calin Juravleb1498f62015-02-16 13:13:29 +0000505void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
506 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
507 // Be sure that we don't go over the bounded type.
508 ReferenceTypeInfo bound_rti = instr->GetBoundType();
509 if (!bound_rti.IsSupertypeOf(new_rti)) {
510 new_rti = bound_rti;
511 }
512 instr->SetReferenceTypeInfo(new_rti);
513}
514
515void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
516 ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
Calin Juravle20e60712015-07-01 18:41:04 +0100517 if (new_rti.IsObjectClass() && !new_rti.IsExact()) {
518 // Early return if we are Object and inexact.
Calin Juravleb1498f62015-02-16 13:13:29 +0000519 instr->SetReferenceTypeInfo(new_rti);
520 return;
521 }
522 for (size_t i = 1; i < instr->InputCount(); i++) {
523 new_rti = MergeTypes(new_rti, instr->InputAt(i)->GetReferenceTypeInfo());
Calin Juravle20e60712015-07-01 18:41:04 +0100524 if (new_rti.IsObjectClass()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000525 if (!new_rti.IsExact()) {
526 break;
527 } else {
528 continue;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000529 }
Calin Juravle10e244f2015-01-26 18:54:32 +0000530 }
531 }
Calin Juravleb1498f62015-02-16 13:13:29 +0000532 instr->SetReferenceTypeInfo(new_rti);
533}
534
535// Re-computes and updates the nullability of the instruction. Returns whether or
536// not the nullability was changed.
537bool ReferenceTypePropagation::UpdateNullability(HInstruction* instr) {
Calin Juravle20e60712015-07-01 18:41:04 +0100538 DCHECK(instr->IsPhi()
539 || instr->IsBoundType()
540 || instr->IsNullCheck()
541 || instr->IsArrayGet());
Calin Juravleb1498f62015-02-16 13:13:29 +0000542
543 if (!instr->IsPhi()) {
544 return false;
545 }
546
547 HPhi* phi = instr->AsPhi();
548 bool existing_can_be_null = phi->CanBeNull();
549 bool new_can_be_null = false;
550 for (size_t i = 0; i < phi->InputCount(); i++) {
551 new_can_be_null |= phi->InputAt(i)->CanBeNull();
552 }
553 phi->SetCanBeNull(new_can_be_null);
554
555 return existing_can_be_null != new_can_be_null;
Calin Juravle10e244f2015-01-26 18:54:32 +0000556}
557
558void ReferenceTypePropagation::ProcessWorklist() {
559 while (!worklist_.IsEmpty()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000560 HInstruction* instruction = worklist_.Pop();
Calin Juravleacf735c2015-02-12 15:25:22 +0000561 if (UpdateNullability(instruction) || UpdateReferenceTypeInfo(instruction)) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000562 AddDependentInstructionsToWorklist(instruction);
563 }
564 }
565}
566
Calin Juravleb1498f62015-02-16 13:13:29 +0000567void ReferenceTypePropagation::AddToWorklist(HInstruction* instruction) {
Calin Juravle20e60712015-07-01 18:41:04 +0100568 DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot)
569 << instruction->DebugName() << ":" << instruction->GetType();
Calin Juravle10e244f2015-01-26 18:54:32 +0000570 worklist_.Add(instruction);
571}
572
Calin Juravleb1498f62015-02-16 13:13:29 +0000573void ReferenceTypePropagation::AddDependentInstructionsToWorklist(HInstruction* instruction) {
Calin Juravle10e244f2015-01-26 18:54:32 +0000574 for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
Calin Juravleb1498f62015-02-16 13:13:29 +0000575 HInstruction* user = it.Current()->GetUser();
Calin Juravle20e60712015-07-01 18:41:04 +0100576 if (user->IsPhi()
577 || user->IsBoundType()
578 || user->IsNullCheck()
579 || (user->IsArrayGet() && (user->GetType() == Primitive::kPrimNot))) {
580 AddToWorklist(user);
Calin Juravle10e244f2015-01-26 18:54:32 +0000581 }
582 }
583}
Calin Juravle10e244f2015-01-26 18:54:32 +0000584} // namespace art